Convert adjacency matrix to specific edge list in MATLAB - matlab

If I have the matrix
1 0 0
0 0 1
0 0 0
and I want this form in MATLAB
1 2 3 1 2 3 1 2 3
1 1 1 2 2 2 3 3 3
1 0 0 0 0 0 0 1 0
also I want the values of third row in result. i.e. ans= [1 0 0 0 0 0 0 1 0]

Here you go -
[X,Y] = ndgrid(1:size(A,1),1:size(A,2));
out = [X(:).' ; Y(:).' ; A(:).']
For the last part of your question, use the last row of out : out(end,:) or A(:).'.
Sample run -
>> A
A =
1 0 0
0 0 1
0 0 0
>> [X,Y] = ndgrid(1:size(A,1),1:size(A,2));
>> out = [X(:).' ; Y(:).' ; A(:).']
out =
1 2 3 1 2 3 1 2 3
1 1 1 2 2 2 3 3 3
1 0 0 0 0 0 0 1 0

Related

solving binary linear equation in matlab

Consider a binary linear equation of form x*A = b. I want to solve for x, the efficiency way is by avoiding using x = b*inv(A) and instead using x= b/A.But with this command results are not in binary form. I tried the command x = mod(b/A ,2)but still result was not in binary. How to fix this?
example
`
x = 1 0 1 1 0 0 0 1 1 0`
and matrix A is
`0 1 0 1 0 0 1 1 1 1
0 1 1 1 1 1 1 1 0 1
0 0 1 0 1 1 0 1 1 1
1 0 0 1 1 1 1 1 1 1
1 1 0 0 1 1 0 0 0 0
0 1 1 1 0 1 1 0 1 0
0 0 1 1 0 0 0 1 0 0
1 1 1 1 0 1 0 1 1 1
1 0 1 0 1 1 1 0 1 1
1 1 1 0 0 0 1 1 0 0`
which is full rank.
then
>> b = mod (x*A,2)
b =
1 0 1 1 1 0 1 0 1 1
To find x, am getting
>> k = b / A
k =
Columns 1 through 6
1.3750 -0.5000 -0.7500 -0.7500 0.8750 -0.5000
Columns 7 through 10
1.8750 -0.5000 2.1250 -0.7500
or if am using modulus 2, the result is
>> k = mod (b / A,2)
k =
Columns 1 through 6
1.3750 1.5000 1.2500 1.2500 0.8750 1.5000
Columns 7 through 10
1.8750 1.5000 0.1250 1.2500
So ,how can I get x in the same binary form? and by the way matrices are all in class double not galois field
This example at Mathworks shows how to perform boolean matrix inversion with MATLAB and I believe answers your question.
I have not quite gotten it working perfectly, but I believe you need to use a combination of mod() and logical() for example:
A=logical(A);
b=(mod(x*A,2));
inverseA= ~A;
k=mod(b*inverseA,2)
this gives
k=[1 1 0 0 1 1 0 1 0 0]
which is not x, but i think if you play around with the logical function and logical operations in conjunction with mod() you should be able to get it to work
To solvexin binary form, matrix A should be in galois field.
consider the following example;
>> x = randi ([0 1],1,10)
x =
1 1 0 1 1 1 0 1 1 1
>> A = gf (randi([0 1],10,10))
A = GF(2) array.
Array elements =
Columns 1 through 6
1 1 1 0 0 1
1 0 1 0 1 0
1 0 1 1 0 1
0 0 0 0 0 1
1 1 1 0 1 1
0 1 0 1 0 1
0 0 0 1 1 1
0 1 0 0 1 0
0 0 1 0 1 0
0 0 1 0 0 1
Columns 7 through 10
1 1 0 0
1 0 1 1
1 1 0 0
0 0 1 0
1 1 1 1
0 1 1 1
1 0 1 0
1 1 1 0
1 0 0 0
1 1 1 0
then,
>> b = x*A
b = GF(2) array.
Array elements =
Columns 1 through 6
1 0 1 1 0 1
Columns 7 through 10
0 1 0 1
>> x_solved = b*inv (A)
x_solved = GF(2) array.
Array elements =
Columns 1 through 6
1 1 0 1 1 1
Columns 7 through 10
0 1 1 1
As you can see x_solved is the same as the original x. Therefore you should convert matrix A to galois field by just running a codeA = gf(A).

Linear span of a vector in MATLAB

I'm looking for a way to generate the spans of a given vector in MATLAB.
For example:
if a = [ 0 1 0 1] I need all vectors of the form [0 x 0 y], 1 <= x <= max1, 1 <= y <= max2,.
or if
a = [ 0 1 0 1 1 0] I need all vectors of the form [0 x 0 y z 0], 1 <= x <= max1, 1 <= y <= max2, 1<= z <= max3.
Note that the vector can have a variable number of 1's.
My first impression is that I would need a variable number of for loops, though I don't know if that is doable in MATLAB. Also any other ideas are welcome!
You don't need multiple for loops for this. The code below generates all required vectors as rows of a tall matrix. It actually creates the columns of the matrix one at a time. Each column will have numbers 1:m(i) arranged in the pattern where
each term repeats the number of times equal to the product of all m-numbers after m(i)
the whole pattern repeats the number of times equal to the product of all m-numbers before m(i)
This is what repmat(kron(1:m(i),ones(1,after)),1,before)' does. (Starting with R2015a you can use repelem to simplify this by replacing the kron command, but I don't have that release yet.)
a = [0 1 0 1 1 0];
m = [2 4 3]; // the numbers max1, max2, max3
A = zeros(prod(m), length(a));
i = 1; // runs through elements of m
for j=1:length(a) // runs through elements of a
if (a(j)>0)
before = prod(m(1:i-1));
after = prod(m(i+1:end));
A(:,j) = repmat(kron(1:m(i),ones(1,after)),1,before)';
i = i+1;
end
end
Output:
0 1 0 1 1 0
0 1 0 1 2 0
0 1 0 1 3 0
0 1 0 2 1 0
0 1 0 2 2 0
0 1 0 2 3 0
0 1 0 3 1 0
0 1 0 3 2 0
0 1 0 3 3 0
0 1 0 4 1 0
0 1 0 4 2 0
0 1 0 4 3 0
0 2 0 1 1 0
0 2 0 1 2 0
0 2 0 1 3 0
0 2 0 2 1 0
0 2 0 2 2 0
0 2 0 2 3 0
0 2 0 3 1 0
0 2 0 3 2 0
0 2 0 3 3 0
0 2 0 4 1 0
0 2 0 4 2 0
0 2 0 4 3 0

Assign values w/ multiple conditions

Let's have a M = [10 x 4 x 12] matrix. As example I take the M(:,:,4):
val(:,:,4) =
0 0 1 0
0 1 1 1
0 0 0 1
1 1 1 1
1 1 0 1
0 1 1 1
1 1 1 1
1 1 1 1
0 0 1 1
0 0 1 1
How can I obtain this:
val(:,:,4) =
0 0 3 0
0 2 2 2
0 0 0 4
1 1 1 1
1 1 0 1
0 2 2 2
1 1 1 1
1 1 1 1
0 0 3 3
0 0 3 3
If I have 1 in the first column then all the subsequent 1's should be 1.
If I have 0 in the first column but 1 in the second, all the subsequent 1's should be 2.
If I have 0 in the first and second column but 1 in the third then all the subsequent 1's should be 3.
If I have 0 in the first 3 columns but 1 in the forth then this one should be four.
Note: The logical matrix M is constructed:
Tab = [reshape(Avg_1step.',10,1,[]) reshape(Avg_2step.',10,1,[]) ...
reshape(Avg_4step.',10,1,[]) reshape(Avg_6step.',10,1,[])];
M = Tab>=repmat([20 40 60 80],10,1,size(Tab,3));
This is a very simple approach that works for both 2D and 3D matrices.
%// Find the column index of the first element in each "slice".
[~, idx] = max(val,[],2);
%// Multiply the column index with each row of the initial matrix
bsxfun(#times, val, idx);
This could be one approach -
%// Concatenate input array along dim3 to create a 2D array for easy work ahead
M2d = reshape(permute(M,[1 3 2]),size(M,1)*size(M,3),[]);
%// Find matches for each case, index into each matching row and
%// elementwise multiply all elements with the corresponding multiplying
%// factor of 2 or 3 or 4 and thus obtain the desired output but as 2D array
%// NOTE: Case 1 would not change any value, so it was skipped.
case2m = all(bsxfun(#eq,M2d(:,1:2),[0 1]),2);
M2d(case2m,:) = bsxfun(#times,M2d(case2m,:),2);
case3m = all(bsxfun(#eq,M2d(:,1:3),[0 0 1]),2);
M2d(case3m,:) = bsxfun(#times,M2d(case3m,:),3);
case4m = all(bsxfun(#eq,M2d(:,1:4),[0 0 0 1]),2);
M2d(case4m,:) = bsxfun(#times,M2d(case4m,:),4);
%// Cut the 2D array thus obtained at every size(a,1) to give us back a 3D
%// array version of the expected values
Mout = permute(reshape(M2d,size(M,1),size(M,3),[]),[1 3 2])
Code run with a random 6 x 4 x 2 sized input array -
M(:,:,1) =
1 1 0 1
1 0 1 1
1 0 0 1
0 0 1 1
1 0 0 0
1 0 1 1
M(:,:,2) =
0 1 0 1
1 1 0 0
1 1 0 0
0 0 1 1
0 0 0 1
0 0 1 0
Mout(:,:,1) =
1 1 0 1
1 0 1 1
1 0 0 1
0 0 3 3
1 0 0 0
1 0 1 1
Mout(:,:,2) =
0 2 0 2
1 1 0 0
1 1 0 0
0 0 3 3
0 0 0 4
0 0 3 0

Identify sequences of the same number in a matrix

I have matrix A
A= [0 0 2 2 2 2 0 0 1 1 1 0 3 3;
2 2 2 2 0 0 1 1 1 0 0 3 3 0;
As you can see, there are consecutive numbers in it; notice for example the 2 2 2 2 on the first and second row.
For each number occuring in this matrix (or at least for every number from 1 to the maximum number in my matrix) I want to have an output matrix that indicates sequences of this number and this number only in the original matrix.
So for example, for 1: there are three consecutive numbers on the first row and three on the second row: I want to indicate this in the first output matrix as follows:
Matrix 1 = [ 0 0 0 0 0 0 0 0 1 2 3 0 0 0;
0 0 0 0 0 0 0 1 2 3 0 0 0 0]
Same for number 2:
Matrix 2 = [ 0 0 1 2 3 4 0 0 0 0 0 0 0 0;
1 2 3 4 0 0 0 0 0 0 0 0 0 0]
and 3:
Matrix 3 = [ 0 0 0 0 0 0 0 0 0 0 0 0 1 2;
0 0 0 0 0 0 0 0 0 0 0 1 2 0]
As you can see, each output matrix shows counting forward for the consecutive occurrences of a number.
So in this case, I have 3 output matrices because matrix A has 3 as the biggest value there.
You can try this:
A= [0 0 2 2 2 2 0 0 1 1 1 0 3 3;
2 2 2 2 0 0 1 1 1 0 0 3 3 0];
result = arrayfun(#(b) (A == b).*cumsum((A == b),2),nonzeros(unique(A)), 'UniformOutput', false);
For this example, there will be 3 submatrices in the variable result.
result =
[2x14 double]
[2x14 double]
[2x14 double]
To access them, use the following syntax:
result{1}
result{2}
result{3}
Then you get:
ans =
0 0 0 0 0 0 0 0 1 2 3 0 0 0
0 0 0 0 0 0 1 2 3 0 0 0 0 0
ans =
0 0 1 2 3 4 0 0 0 0 0 0 0 0
1 2 3 4 0 0 0 0 0 0 0 0 0 0
ans =
0 0 0 0 0 0 0 0 0 0 0 0 1 2
0 0 0 0 0 0 0 0 0 0 0 1 2 0
~edit~
If, as asked in the comments, A is a 3D matrix, this code works just the same, but the structure of result is a bit different:
result =
[2x14x2 double]
[2x14x2 double]
[2x14x2 double]
To access these matrices, use for instance
result{1}(:,:,1) % for the results of comparing A(:,:,1) with value 1
result{1}(:,:,2) % for the results of comparing A(:,:,2) with value 1
Edited because the question changed
This is nowhere near to optimal but will do what you want
V = 1;
C = A' == V;
D = cumsum(C).*C
E = D'
now E will be Matrix1 in your example. Change V to 2 and 3 to obtain Matrix2 and Matrix3. If you have something like
A = [2 2 2 0 0 0 0 0 2 2 2]
then you will get
[1 2 3 0 0 0 0 0 4 5 6]
so it may not be what you want. It is not clear from your question if this is the case or not, but if not tell me and I will delete the answer
This is a loop-based solution to get you started:
A = [
0 0 2 2 2 2 0 0 1 1 1 0 3 3;
2 2 2 2 0 0 1 1 1 0 0 3 3 0
];
mx = max(A(:));
AA = cell(mx,1);
for num=1:mx
AA{num} = zeros(size(A));
for r=1:size(A,1)
idx = ( A(r,:) == num );
AA{num}(r,idx) = sum(idx):-1:1;
end
end
The result:
>> AA{1}
ans =
0 0 0 0 0 0 0 0 3 2 1 0 0 0
0 0 0 0 0 0 3 2 1 0 0 0 0 0
>> AA{2}
ans =
0 0 4 3 2 1 0 0 0 0 0 0 0 0
4 3 2 1 0 0 0 0 0 0 0 0 0 0
>> AA{3}
ans =
0 0 0 0 0 0 0 0 0 0 0 0 2 1
0 0 0 0 0 0 0 0 0 0 0 2 1 0
EDIT:
Updated code to work on matrix with three dimensions:
A = zeros(2,7,2);
A(:,:,1) = [2 2 2 0 0 1 1 ; 0 0 2 2 2 1 1];
A(:,:,2) = [1 1 2 2 2 0 0 ; 0 1 1 0 2 2 2];
mx = max(A(:));
AA = cell(mx,1);
for num=1:mx
AA{num} = zeros(size(A));
for p=1:size(A,3)
for r=1:size(A,1)
idx = ( A(r,:,p) == num );
AA{num}(r,idx,p) = 1:sum(idx);
end
end
end
The result:
%# contains consecutive numbers corresponding to number 1 in all slices
>> AA{1}
ans(:,:,1) =
0 0 0 0 0 1 2
0 0 0 0 0 1 2
ans(:,:,2) =
1 2 0 0 0 0 0
0 1 2 0 0 0 0
%# contains consecutive numbers corresponding to number 2 in all slices
>> AA{2}
ans(:,:,1) =
1 2 3 0 0 0 0
0 0 1 2 3 0 0
ans(:,:,2) =
0 0 1 2 3 0 0
0 0 0 0 1 2 3

How to account number of each column value in a matrix

I have Matrix A:
A= [ 1 1 0 2 2 2 2 0 0 3 3 0 0;
0 1 1 0 0 2 2 2 2 3 3 0 0 ];
and I want to make another matrix B, so that this matrix contains the number of value occurences of the original matrix A: ie each iith row of B contains how many times ii occurs in the corresponding columns of A. The number 0 may be ignored.
For example: in the 2nd column of A, only the number 1 occurs, to be specific two times --> hence B(1,2) = 2 and B(other,2) = 0.
For my example matrix A, the output should be
Res = [ 1 2 1 0 0 0 0 0 0 0 0 0 0;
0 0 0 1 1 2 2 1 1 0 0 0 0;
0 0 0 0 0 0 0 0 0 2 2 0 0 ];
This also is an opportunity for the (under-appreciated) accumarray
A= [ 1 1 0 2 2 2 2 0 0 3 3 0 0;
0 1 1 0 0 2 2 2 2 3 3 0 0 ];
N = size(A,2);
result = zeros(max(A(:)),N);
for ii=1:N
s = accumarray(nonzeros(A(:,ii)),1);
result(1:numel(s),ii) = s;
end
too bad only that accumarray can't do it all in one call :(
EDIT
Got it all in one accumarray call: :p
A= [ 1 1 0 2 2 2 2 0 0 3 3 0 0;
0 1 1 0 0 2 2 2 2 3 3 0 0 ];
N = size(A);
C = repmat(1:N(2),N(1),1);
result = accumarray([A(:)+1 C(:)], 1);
result = result(2:end,:)
EDIT2
If you have a 3 dimensional input matrix, it's easiest to first transform it into a 2 dimensional matrix and then process it using the above. The following code does this transform:
% example data:
A3d = repmat(A,[1 1 2])
A2d = reshape(permute(A3d,[1 3 2]),[],size(A3d,2))
Result:
A3d(:,:,1) =
1 1 0 2 2 2 2 0 0 3 3 0 0
0 1 1 0 0 2 2 2 2 3 3 0 0
A3d(:,:,2) =
1 1 0 2 2 2 2 0 0 3 3 0 0
0 1 1 0 0 2 2 2 2 3 3 0 0
A2d =
1 1 0 2 2 2 2 0 0 3 3 0 0
0 1 1 0 0 2 2 2 2 3 3 0 0
1 1 0 2 2 2 2 0 0 3 3 0 0
0 1 1 0 0 2 2 2 2 3 3 0 0
You can use
A= [ 1 1 0 2 2 2 2 0 0 3 3 0 0;
0 1 1 0 0 2 2 2 2 3 3 0 0 ];
cell2mat(arrayfun(#(b) sum(A == b),nonzeros(unique(A)), 'UniformOutput', false))
This results in
ans =
1 2 1 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 2 2 1 1 0 0 0 0
0 0 0 0 0 0 0 0 0 2 2 0 0
If, as asked in the comments, the matrix a has three dimensions, you need to sum the result along the third dimension:
sum(cell2mat(arrayfun(#(b) sum(A == b,1),nonzeros(unique(A)), 'UniformOutput', false)),3)
You could do this is one function call:
Res = histc(A, 1:3);
result as expected:
Res =
1 2 1 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 2 2 1 1 0 0 0 0
0 0 0 0 0 0 0 0 0 2 2 0 0
Another alternative using the SPARSE function (similar to #GuntherStruyf's second solution using ACCUMARRAY)
c = repmat(1:size(A,2), [size(A,1) 1]);
M = full(sparse(A(:)+1, c(:), 1));
M = M(2:end,:);
The result:
M =
1 2 1 0 0 0 0 0 0 0 0 0 0
0 0 0 1 1 2 2 1 1 0 0 0 0
0 0 0 0 0 0 0 0 0 2 2 0 0