Julia: find row in matrix - matrix

Using Julia, I'd like to determine if a row is located in a matrix and (if applicable) where in the matrix the row is located. For example, in Matlab this can done with ismember:
a = [1 2 3];
B = [3 1 2; 2 1 3; 1 2 3; 2 3 1]
B =
3 1 2
2 1 3
1 2 3
2 3 1
ismember(B, a, 'rows')
ans =
0
0
1
0
From this, we can see a is located in row 3 of B. Is there a similar function to accomplish this in Julia?

You can also make use of array broadcasting by simply testing for equality (.==) without the use of comprehensions:
all(B .== a, dims=2)
Which gives you:
4x1 BitMatrix:
0
0
1
0
You can then use findall on this array:
findall(all(B .== a, 2))
However, this gives you a vector of CartesianIndex objects:
1-element Vector{CartesianIndex{2}}:
CartesianIndex(3, 1)
So if you expect to find multiple rows with the value defined in a you can either:
simplify this Vector by taking only the row index from each CartesianIndex:
[cart_idx[1] for cart_idx in findall(all(B .== a, 2))]
or pass one dimensional BitMatrix to findall (as suggested by Shep Bryan in the comment):
findall(all(B .== a, dims=2)[:, 1])
Either way you get an integer vector of column indices:
1-element Vector{Int64}:
3

Another pattern is using array comprehension:
julia> Bool[ a == B[i,:] for i=1:size(B,1) ]
4-element Array{Bool,1}:
false
false
true
false
julia> Int[ a == B[i,:] for i=1:size(B,1) ]
4-element Array{Int64,1}:
0
0
1
0

how about:
matchrow(a,B) = findfirst(i->all(j->a[j] == B[i,j],1:size(B,2)),1:size(B,1))
returns 0 when no matching row, or first row number when there is one.
matchrow(a,B)
3
should be as "fast as possible" and pretty simple too.

Though Julia doesn't have a built-in function, its easy enough as a one-liner.
a = [1 2 3];
B = [3 1 2; 2 1 3; 1 2 3; 2 3 1]
ismember(mat, x, dims) = mapslices(elem -> elem == vec(x), mat, dims)
ismember(B, a, 2) # Returns booleans instead of ints

Related

Omitting zeroes from matrix calculation in Octave

I'm performing input-output calculations in Octave. I have several matrices/vectors in the formula:
F = f' * (I-A)^-1 * Y
All vectors probably contain zeroes. I would like to omit them from the calculation and just return 0 instead. Any help would be greatly appreciated!
Miranda
What do you mean when you say "omit them"?
If you want to remove zeros from a vector you can do this:
octave:1> x=[1,2,0,3,4,0,5];
octave:2> x(find(x==0))=[]
x =
1 2 3 4 5
The logic is: x==0 will test each element of x (in this case the test is if it equals zero) and will return a vector of 0's and 1's (0 if the test is false for that element and 1 otherwise)
So:
octave:1> x=[1,2,0,3,4,0,5];
octave:2> x==0
ans =
0 0 1 0 0 1 0
The find() function will return the index value of any non-zero element of it's argument, hence:
octave:3> find(x==0)
ans =
3 6
And then you are just indexing and removing when you do something like:
octave:5> x([3, 6]) = []
x =
1 2 3 4 5
But instead you do it with the output of the find() function (which is the vector [3,6] in this case)
You can do the same for matrices:
octave:7> A = [1,2,0;4,5,0]
A =
1 2 0
4 5 0
octave:8> A(find(A==0))=[]
A =
1
4
2
5
Then use the reshape() function to turn it back into a matrix.

julia find in matrix with (row,col) instead of index

In Julia you can find the coordinates of elements in a matrix via:
julia> find( x -> x == 2, [ 1 2 3; 2 3 4; 1 0 2] )
3-element Array{Int64,1}:
2
4
9
These values are correct but I would prefer that I would get the (row,col) tuples instead.
(1,2)
(2,1)
(3,3)
What is the easiest way to achieve this in Julia?
I don't believe there is an inbuilt way to do it, but here is a function to do it
function findmat(f, A::AbstractMatrix)
m,n = size(A)
out = (Int,Int)[]
for i in 1:m, j in 1:n
f(A[i,j]) && push!(out,(i,j))
end
out
end
e.g.
julia> findmat(x->x==2, [ 1 2 3; 2 3 4; 1 0 2] )
3-element Array{(Int64,Int64),1}:
(1,2)
(2,1)
(3,3)
If a large number of items satisfy the condition it might be more efficient to do it in two passes, but I doubt it.
Edit:
For newer versions of Julia replace
out = (Int,Int)[]
with
out = Tuple{Int, Int}[]
In case anyone else finds this you can now use:
ind2sub(a, index)
It returns a tuple of subscripts into array a corresponding to the linear index index
The closest thing that I can find in the Julia standard library is findn :
julia> A = [1 2 3; 2 3 4; 1 0 2]
3x3 Array{Int64,2}:
1 2 3
2 3 4
1 0 2
julia> findn(A .== 2)
([2,1,3],[1,2,3])
This gives a tuple of vectors instead of a vector of tuples, though.
Another thing to note is that the match at (2,1) is reported before the one at (1,2). This is because arrays in Julia are stored in column major order, so scanning the array A in storage order will look at the position (2,1) before (1,2).
if you wish to avoid defining "new" functions, perhaps:
collect(zip(ind2sub((3,3),find( x -> x == 2, [ 1 2 3; 2 3 4; 1 0 2] ))...))
is what you are looking for. the (3,3) is implicit in the size of the matrix. if the matrix was given by a variable it would look more natural with a size(M)
on julia 1.7, find does not exist (it was deprecated on julia 1.0), findall is the equivalent that gives the same result as the original question.
On matrices, findall will return CartesianIndex locations:
julia> idx = findall( x -> x == 2, [ 1 2 3; 2 3 4; 1 0 2])
3-element Vector{CartesianIndex{2}}:
CartesianIndex(2, 1)
CartesianIndex(1, 2)
CartesianIndex(3, 3)
julia> ans[1][1]
2

Tiling or repeating n-dimensional arrays in Julia

I am looking for a general function to tile or repeat matrices along an arbitrary number of dimensions an arbitrary number of times. Python and Matlab have these features in NumPy's tile and Matlab's repmat functions. Julia's repmat function only seems to support up to 2-dimensional arrays.
The function should look like repmatnd(a, (n1,n2,...,nk)). a is an array of arbitrary dimension. And the second argument is a tuple specifying the number of times the array is repeated for each dimension k.
Any idea how to tile a Julia array on greater than 2 dimensions? In Python I would use np.tile and in matlab repmat, but the repmat function in Julia only supports 2 dimensions.
For instance,
x = [1 2 3]
repmatnd(x, 3, 1, 3)
Would result in:
1 2 3
1 2 3
1 2 3
1 2 3
1 2 3
1 2 3
1 2 3
1 2 3
1 2 3
And for
x = [1 2 3; 1 2 3; 1 2 3]
repmatnd(x, (1, 1, 3))
would result in the same thing as before. I imagine the Julia developers will implement something like this in the standard library, but until then, it would be nice to have a fix.
Use repeat:
julia> X = [1 2 3]
1x3 Array{Int64,2}:
1 2 3
julia> repeat(X, outer = [3, 1, 3])
3x3x3 Array{Int64,3}:
[:, :, 1] =
1 2 3
1 2 3
1 2 3
[:, :, 2] =
1 2 3
1 2 3
1 2 3
[:, :, 3] =
1 2 3
1 2 3
1 2 3

Counting subrows in each row of a matrix in Matlab?

I need an algorithm in Matlab which counts how many adjacent and non-overlapping (1,1) I have in each row of a matrix A mx(n*2) without using loops. E.g.
A=[1 1 1 0 1 1 0 0 0 1; 1 0 1 1 1 1 0 0 1 1] %m=2, n=5
Then I want
B=[2;3] %mx1
Specific case
Assuming A to have ones and zeros only, this could be one way -
B = sum(reshape(sum(reshape(A',2,[]))==2,size(A,2)/2,[]))
General case
If you are looking for a general approach that must work for all integers and a case where you can specify the pattern of numbers, you may use this -
patt = [0 1] %%// pattern to be found out
B = sum(reshape(ismember(reshape(A',2,[])',patt,'rows'),[],2))
Output
With patt = [1 1], B = [2 3]
With patt = [0 1], B = [1 0]
you can use transpose then reshape so each consecutive values will now be in a row, then compare the top and bottom row (boolean compare or compare the sum of each row to 2), then sum the result of the comparison and reshape the result to your liking.
in code, it would look like:
A=[1 1 1 0 1 1 0 0 0 1; 1 0 1 1 1 1 0 0 1 1] ;
m = size(A,1) ;
n = size(A,2)/2 ;
Atemp = reshape(A.' , 2 , [] , m ) ;
B = squeeze(sum(sum(Atemp)==2))
You could pack everything in one line of code if you want, but several lines is usually easier for comprehension. For clarity, the Atemp matrix looks like that:
Atemp(:,:,1) =
1 1 1 0 0
1 0 1 0 1
Atemp(:,:,2) =
1 1 1 0 1
0 1 1 0 1
You'll notice that each row of the original A matrix has been broken down in 2 rows element-wise. The second line will simply compare the sum of each row with 2, then sum the valid result of the comparisons.
The squeeze command is only to remove the singleton dimensions not necessary anymore.
you can use imresize , for example
imresize(A,[size(A,1),size(A,2)/2])>0.8
ans =
1 0 1 0 0
0 1 1 0 1
this places 1 where you have [1 1] pairs... then you can just use sum
For any pair type [x y] you can :
x=0; y=1;
R(size(A,1),size(A,2)/2)=0; % prealocarting memory
for n=1:size(A,1)
b=[A(n,1:2:end)' A(n,2:2:end)']
try
R(n,find(b(:,1)==x & b(:,2)==y))=1;
end
end
R =
0 0 0 0 1
0 0 0 0 0
With diff (to detect start and end of each run of ones) and accumarray (to group runs of the same row; each run contributes half its length rounded down):
B = diff([zeros(1,size(A,1)); A.'; zeros(1,size(A,1))]); %'// columnwise is easier
[is js] = find(B==1); %// rows and columns of starts of runs of ones
[ie je] = find(B==-1); %// rows and columns of ends of runs of ones
result = accumarray(js, floor((ie-is)/2)); %// sum values for each row of A

How to get this matrix

I have this matrix:
S.No. A B
1 5268020 1756
2 15106230 5241
3 24298744 9591
4 23197375 9129
I want to get a matrix which will have two columns [X,Y]. X will take values from S.No. and Y will can be either 1 or 0. For example, for 1 5268020 1756 there should be total 5268020 (1,0) i.e, (X,Y) pairs and 1756 (1,1) pairs.
How can I get this matrix in Octave ??
If I understand your question correctly, you want to fill a matrix with repeated entries (x,0) and (x,1), where x=1...4, where repetition is determined by values found in column A and B. Given the values you supplied that's going to be a huge matrix (67,896,086 rows). So, you could try something like this (replace m below, which has less elements for illustrative purpose):
m = [1, 2, 1;
2, 3, 2;
3, 2, 1;
4, 2, 2];
res = [];
for k = 1:4
res = [res ; [k*ones(m(k, 2), 1), zeros(m(k, 2), 1);
k*ones(m(k, 3), 1), ones(m(k, 3), 1)]];
endfor
which yields
res =
1 0
1 0
1 1
2 0
2 0
2 0
2 1
2 1
3 0
3 0
3 1
4 0
4 0
4 1
4 1
Out of curiosity, is there any reason not to consider a matrix like
1 0 n
1 1 m
2 0 p
2 1 q
...
where n, m, p, q, are values found in columns A and B. This would probably be easier to handle , no?

Resources