Assignement in matrixes using double indexes - julia

I can't figure out how to obtain this behavior:
From this matrix:
julia> a = [1 1 1; 1 1 1; 1 1 2]
3×3 Array{Int64,2}:
1 1 1
1 1 1
1 1 2
I want to change all the 1s to 5s but only in the last row.
What I did is a[3, :][a[3, :] .== 1] .= 5 but the value of a isn't changed.
I've noticed that with:
foo[foo .== 1] .= 5
a[3, :] = foo
It works, but I'm trying to reduce allocations and this should be removed.
Thanks in advance

You can use #view and replace!:
julia> a = [1 1 1
1 1 1
1 1 2]
3×3 Array{Int64,2}:
1 1 1
1 1 1
1 1 2
julia> replace!(#view(a[end, :]), 1 => 5)
3-element view(::Array{Int64,2}, 3, :) with eltype Int64:
5
5
2
julia> a
3×3 Array{Int64,2}:
1 1 1
1 1 1
5 5 2

The problem is
a[3, :][a[3, :] .== 1] .= 5
is the same as getindex(a, 3, :)[a[3, :] .== 1] .=5
getindex returns a copy of that part of a
You are mutating the copy, not the original a
You want to use a view
view(a, 3, :)[a[3, :] .== 1] .=5
You can also do this with the #view or #views macro.

Related

Efficient way to copy a matrix except for one column

Consider a matrix where you don't need the third column:
X = zeros(Int64, (4, 3));
X[:, 1] = [0, 0, 1, 1];
X[:, 2] = [1, 2, 1, 2];
julia> X
4×3 Matrix{Int64}:
0 1 0
0 2 0
1 1 0
1 2 0
So you want to select (copy) everything except column 3:
4×2 Matrix{Int64}:
0 1
0 2
1 1
1 2
Is there a shorthand way to express this?
These work, but feel impractical when you have a large number of columns:
X[:, [1, 2]]
X[:, sort(collect(setdiff(Set([1, 2, 3]), Set([3]))))]
There are plenty of ways to do this. Below is a solution in which you express which ranges of column numbers to include:
X = zeros(Int64, (8, 3));
X[:, 1] = [0, 0, 0, 0, 1, 1, 1, 1];
X[:, 2] = [1, 1, 2, 2, 1, 1, 2, 2];
return X[:,1:2] #Columns 1 through 2 are being directly included.
Alternatively, you could express which you would like to exclude, which is perhaps a more widely useful version of the code:
return X[:, 1:end .!= 3] #column number 3 is being directly excluded.
Both of which would return:
8×2 Matrix{Int64}:
0 1
0 1
0 2
0 2
1 1
1 1
1 2
1 2
If it is some column in the middle you can get perhaps get most elegant code by using InvertedIndices. (This also gets loaded by other packages such as DataFrames).:
julia> A = collect(reshape(1:16,4,4))
4×4 Matrix{Int64}:
1 5 9 13
2 6 10 14
3 7 11 15
4 8 12 16
julia> A[:, Not(3)]
4×3 Matrix{Int64}:
1 5 13
2 6 14
3 7 15
4 8 16

Generate all combinations of items with two values in Julia?

I have m items. Each item is a pair of two values. For example, for m=4, I have the matrix:
julia> valid_pairs = [0 1;
1 2;
1 2;
2 3];
I would like to generate all combinations of the four items where each item i can take only the values in valid_pairs[i, :]. Based on the previous example, I would like to have:
julia> all_combs
4x16 Array{Int,2}
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
1 1 1 1 2 2 2 2 1 1 1 1 2 2 2 2
1 1 2 2 1 1 2 2 1 1 2 2 1 1 2 2
2 3 2 3 2 3 2 3 2 3 2 3 2 3 2 3
I feel like this can be done easily using Combinatorics.jl.
Though I used Combinatorics.jl, what I did was the following:
using Combinatorics
m = 4
combs = combinations(1:m) |> collect
L = length(combs)
all_combs = zeros(Int, m, L+1)
for j in 1:L
for i in 1:m
if !in(i, combs[j])
all_combs[i, j] = valid_pairs[i, 1]
else
all_combs[i, j] = valid_pairs[i, 2]
end
end
end
all_combs[:, end] = valid_pairs[:, 1]
Not the same order, but
julia> [collect(x) for x in Iterators.product(eachrow(valid_pairs)...)]
2×2×2×2 Array{Array{Int64,1},4}:
[:, :, 1, 1] =
[0, 1, 1, 2] [0, 2, 1, 2]
[1, 1, 1, 2] [1, 2, 1, 2]
[:, :, 2, 1] =
[0, 1, 2, 2] [0, 2, 2, 2]
[1, 1, 2, 2] [1, 2, 2, 2]
[:, :, 1, 2] =
[0, 1, 1, 3] [0, 2, 1, 3]
[1, 1, 1, 3] [1, 2, 1, 3]
[:, :, 2, 2] =
[0, 1, 2, 3] [0, 2, 2, 3]
[1, 1, 2, 3] [1, 2, 2, 3]
should do. If you really want a matrix (2D array), then you can hcat the previous answer, or directly do
julia> reduce(hcat, collect(x) for x in Iterators.product(eachrow(valid_pairs)...))
4×16 Array{Int64,2}:
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 1 2 2 1 1 2 2 1 1 2 2 1 1 2 2
1 1 1 1 2 2 2 2 1 1 1 1 2 2 2 2
2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3
EDIT: side note, I would define the pairs as tuples to clarify what's happening, so something like
valid_pairs = [(0,1), (1,2), (1,2), (2,3)]
and I would not create the 2D (or 4D, or m-D) array, but, instead, do
comb_pairs = Iterators.product(valid_pairs...)
which then gives you a lazy version of all the pair combinations, so that you can iterate on it without actually creating it first, which should be more efficient (and looks cleaner) I think.

Create a mask array, where `1` are at max value index of given array

Given a matrix A = [1 5 3; 4 2 6]. How to create a new mask matrix where 1 values are at column-wise maximum value index mask = [0 1 0; 1 0 1]. How to do this in julia without mutating any created arrays.
With mutation I'm doing it the following way.
maxval, maxind = findmax(A, dims=1)
mask = zeros(size(A))
mask[maxind] .= 1
There's really nothing wrong with what you have (although I'd probably use falses instead of zeros). You could alternatively use broadcast, but I'd expect it to have similar performance:
julia> A = [1 5 3; 4 2 6]
2×3 Array{Int64,2}:
1 5 3
4 2 6
julia> A .== maximum(A, dims=1)
2×3 BitArray{2}:
0 1 0
1 0 1
(Note that unlike Python, we differentiate between matrices and vectors of vectors; you wrote them like the latter)

How to find the index of the column of the minimum nonzero element across rows in Julia?

I have an nxm Array{Int64,2} in Julia. I would like to find for each row, the index of the column of the minimum element that is not zero. If the row is zero then return 0.
For example, for n=10 and m=2 and
julia> A
10×2 Array{Int64,2}:
2 0
1 1
8 7
0 0
3 8
0 0
0 0
2 4
5 1
6 0
I would like to return
julia> B
10-element Array{Int64,1}:
1
1
2
1
1
1
1
1
2
1
What I did is this:
B = zeros(Int64, n);
for i in 1:n
B[i] = findmin(A[i, :])[2];
end
but this does not work when there is a zero in some row...
You can also use mapslices and specify your function that works for a single row.
First, set up a matrix:
julia> A = [2 1; 1 2; -1 -2; 0 0; 0 5; 10 0]
6×2 Array{Int64,2}:
2 1
1 2
-1 -2
0 0
0 5
10 0
Create a function that finds the index of the minimal non-zero elements per row:
function findmincol(row)
# handle the special case when all elements are 0
if all(row .== 0)
return 0
end
# check the number of zero elements
length_zero = sum(row .== 0)
# find the min among non-zero elements
filter!(x -> x != 0, row)
return findmin(row)[2] + length_zero
end
Then you can use mapslices to map the the findmincol function to each row of A:
mapslices(findmincol, A, dims=2)
This gives you (what I think is) the correct solution:
6×1 Array{Int64,2}:
2
1
2
0
2
1
Most functions (sum, minimum, find, findmin, etc) take a dims keyword argument to specify the axis along which to do said operation:
Ex
findmin(rand(3, 4), dims=1)
([0.15952 0.0289172 0.409214 0.195433], CartesianIndex{2}[CartesianIndex(3, 1)
CartesianIndex(2, 2) CartesianIndex(3, 3) CartesianIndex(3, 4)])
returns the actual minima and the locations, as Cartesian Indices, as two separate arrays
So:
v, i = findmin(randn(10, 2), dims=2)
i = map(t -> t[2], i)
i[v .== 0] .= 0
The Cartesian Index is a little weird, but apparently used frequently for multi-dimensional indexing

How to define a matrix using if and for loops in sagemath?

I am using sagemath for my computations.
Now, from R I have the codes to generate a matrix of size $2r\times 2r$ from the following codes..
n=10
k=10
r=5
x=matrix(data=NA, nrow=n, ncol=k)
for(j in 1:k){
for(i in 1:n){
if (i==j){x[i,j]=0}
if ((i<=r)&(i<j)&(j<=r)) {x[i,j]=2}
if ((i<=r)&(i>j)&(j<=r)) {x[i,j]=2}
if ((i<=r)&(j>r)){x[i,j]=1}
if ((i>r)&(j<=r)) {x[i,j]=1}
if ((i>r)&(j>r)){x[i,j]=0}
if ((i>r)& (i<j) &(j>r)){x[i,j]=2}
if ((i>r)& (i>j) &(j>r)){x[i,j]=2}
}
}
x
How can I do the same in SageMath?
When constructing a matrix in Sagemath, you can pass in a function that computes its entries, which eliminates the need for explicit (and generally inefficient) loops. This function is defined below as xentries: I used the same conditionals as in your post, but grouped them for readability.
def xentries(i, j, r):
if i == j or (i > r and j > r):
return 0
if (i <= r and j > r) or (i > r and j <= r):
return 1
return 2
n = 10
k = 10
r = 5
x = matrix(ZZ, n, k, lambda i, j: xentries(i, j, r))
Here, ZZ means the integers, and is used to indicate that the matrix has integer entries. It could be rational QQ or real RR. The other arguments are the size of the matrix, and the function that constructs its entries. The matrix x is now the following:
[0 2 2 2 2 2 1 1 1 1]
[2 0 2 2 2 2 1 1 1 1]
[2 2 0 2 2 2 1 1 1 1]
[2 2 2 0 2 2 1 1 1 1]
[2 2 2 2 0 2 1 1 1 1]
[2 2 2 2 2 0 1 1 1 1]
[1 1 1 1 1 1 0 0 0 0]
[1 1 1 1 1 1 0 0 0 0]
[1 1 1 1 1 1 0 0 0 0]
[1 1 1 1 1 1 0 0 0 0]

Resources