Finding no. of edges in a graph - matlab

I want to find how many edges are there in C1 and C2? I have stored their adjacency matrix like this :
1 2 3 4 5
1 0 1 1 0 0
2 1 0 0 0 1
3 0 0 0 1 0
4 0 0 0 0 1
5 0 0 0 1 0
If I give an input in an array as [1,3,4] O/P should be : 2

You can use your array to select the appropriate rows and columns from your adjacency matrix and then count the number of non-zeros in the result by using nnz
nnz(A([1 3 4], [1 3 4]))

Related

MATLAB - Inserting zero rows and columns into matrix

I have written some code that compresses a matrix to remove zero columns and rows, but I can't work out how to reconstruct the original matrix.
Say I have a matrix:
A = [ 0 3 0 2 1 0 6
3 0 0 4 8 0 5
0 0 0 0 0 0 0
2 4 0 0 2 0 1
1 8 0 2 0 0 7
0 0 0 0 0 0 0
6 5 0 1 7 0 0 ]
Here rows/columns 3 and 6 are empty, so my compression function will give the output:
A_dash = [ 0 3 2 1 6
3 0 4 8 5
2 4 0 2 1
1 8 2 0 7
6 5 1 7 0 ]
A_map = [ 1 2 4 5 7]
Where A_map is a vector mapping the indicies of the rows/columns of A_dash to A. This means that if A_map(3) = 4, then row/column 4 of A is the same as row/column 3 of A_dash - ie. a row/column of zeroes must be inserted between columns/rows 2 and 3 in A_dash
What is the easiest way people can suggest for me to recreate matrix A from A_dash, using the information in A_map?
Here is what I have got so far:
% orig_size is original number of columns/rows
c_count = size(A_dash,1);
A = zeros(c_count, orig_size); % c_count rows to avoid dimension mismatch
for ii = 1:c_count
A(:,A_map(ii)) == A_dash(:,ii);
end
This gives me the right result column-wise:
A = [ 0 3 0 2 1 0 6
3 0 0 4 8 0 5
2 4 0 0 2 0 1
1 8 0 2 0 0 7
6 5 0 1 7 0 0 ]
However, I'm not sure how i should go about inserting the rows, i suppose i could copy the first 1:i rows into one matrix, i:end rows to a second matrix and concatenate those with a zero row in between, but that feels like a bit of a
clunky solution, and probably not very efficient for large sized matrices..
Otherwise, is there a better way that people can suggest I store the map information? I was thinking instead of storing the mapping between column/row indices, that I just store the indices of the zero columns/rows and then insert columns/rows of zeros where appropriate. Would this be a better way?
You've got the indices of the valid rows/columns. Now all you've got to do is put them in a new matrix of zeros the same size as A:
B=zeros(size(A));
B(A_map,A_map)=A_dash
B =
0 3 0 2 1 0 6
3 0 0 4 8 0 5
0 0 0 0 0 0 0
2 4 0 0 2 0 1
1 8 0 2 0 0 7
0 0 0 0 0 0 0
6 5 0 1 7 0 0
Just to check...
>> A==B
ans =
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
A and B are equal everywhere, so we've reconstructed A.

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

is there a better way of assigning values to a matrix

say i have a matrix
A=zeros(10,3);
and a vector
ll=[1 1 1 2 2 2 3 1 3 2]';
and i want to assign the value in each row corresponding to the value in ll for that row to be 1
i.e output would be
A= 1 0 0
1 0 0
1 0 0
0 1 0
0 1 0
0 1 0
0 0 1
1 0 0
0 0 1
0 1 0
how i do it is using a for loop
for ii=1:length(ll)
A(ii,ll(ii)=1;
end
This should do the trick:
ll=[1 1 1 2 2 2 3 1 3 2]';
A=bsxfun(#eq,ll,1:max(ll))
I'm using bsxfun to check when the entry of ll is equal to an element of the row vector [1 2 3] (in this case). If the entry of ll is 1, it will be equal to the entry in the first column of the [1 2 3] vector and will give a 1 in the first column of A and zeros in the rest of the columns of that row.
Just convert to a linear index:
A((ll-1)*size(A,1) + (1:size(A,1)).') = 1;

MATLAB Add 1's to matrix elements around a specific element

Using MATLAB, I have a matrix such as:
1 1 0
1 0 1
1 1 1
The aim is to represent the zero's as a mine in a minesweeper program and the values around the 0's should reflect how many mines are adjacent to it.
Therefore creating a vector like this:
1 2 0
1 0 2
1 1 1
I have thought to take elements around the zero as a sub matrix and then add 1, but then it will turn 0's into 1's.
How would I program such a task?
I think this can be achieved by simple convolution plus some post-processing on the resultant matrix as follows:
% Defining a 6x6 matrix of zeros and ones
mineMat=randi(2,6,6)-1;
numberOfMines=conv2(double(~mineMat),ones(3,3),'same').*mineMat;
% Result:
mineMat=
1 0 1 1 0 0
0 0 0 1 0 0
1 1 1 1 1 0
1 1 1 1 0 1
0 1 0 0 0 0
0 1 1 0 0 0
numberOfMines=
3 0 3 3 0 0
0 0 0 3 0 0
2 3 2 3 4 0
1 2 2 4 0 4
0 3 0 0 0 0
0 3 3 0 0 0
Parag's answer would be my first option. Another approach is to use blockproc (Image Processing Toolbox):
blockproc(~M, [1 1], #(x)sum(x.data(:)), 'Bordersize', [1 1], 'TrimBorder', 0).*M
Sounds like you are looking to apply a (two dimensional) filter:
M = [1 1 0; 1 0 1; 1 1 1]==0;
F = filter2(ones(3),M);
F(M)=0
The middle line basically does the work (applying the filter) to create the count. The last line ensures that the mines stay at value 0.

Copying part of a matrix to another empty matrix with the same indices

I'm trying to copy part of a matrix (matrix 1) in matlab to another empty matrix of zeros (matrix 2) so that the section I copy from matrix 1 has the same indices in matrix 2, e.g.
Matrix 1 (mat1):
0 3 0 0 2 4 1 2 6
1 3 4 2 0 0 0 2 0
0 2 6 1 3 6 6 1 1
0 0 0 2 1 3 3 1 0
1 4 5 2 3 3 0 0 1
Matrix 2 (mat2) desired output:
0 0 0 0 0 0 0 0 0
0 0 4 2 0 0 0 0 0
0 0 6 1 3 6 6 0 0
0 0 0 2 1 3 3 0 0
0 0 0 0 0 0 0 0 0
I've tried something like
mat2([2:4],[3:7]) = mat1([2:4],[3:7])
but of course it doesn't work... any ideas of an efficient way to do this? I couldn't find another thread to help with this problem.
Thanks!
It does work. You just need to create mat2 first:
mat2 = zeros(size(mat1));
mat2(2:4, 3:7) = mat1(2:4, 3:7);
Note that you don't need the square brackets on those ranges.
Do this:
mat2 = zeros(size(mat1));
Before copying over.