Could you please tell me why this MATLAB code is wrong? I don't understand why. Thank you so much in advance.
function [mst, cost] = prim(A)
[n,n] = size(A);
A, n, pause,
if norm(A-A','fro') ~= 0 ,
disp(' Error: Adjacency matrix must be symmetric ')
return,
end;
intree = [1]; number_in_tree = 1;
number_of_edges = 0;
notintree = [2:n]'; number_notin_tree= n-1;
in = intree(1:number_in_tree),
out = notintree(1:number_notin_tree),
pause,
while number_in_tree < n,
mincost = Inf;
for i=1:number_in_tree,
for j=1:number_notin_tree,
ii = intree(i); jj =
notintree(j);
if A(ii,jj) < mincost,
mincost = A(ii,jj); jsave = j;
iisave = ii; jjsave = jj;
end;
end;
end;
number_of_edges = number_of_edges +1;
mst(number_of_edges,1) = iisave;
mst(number_of_edges,2) = jjsave;
costs(number_of_edges,1) = mincost;
number_in_tree = number_in_tree + 1;
intree = [intree; jjsave];
for j=jsave+1:number_notin_tree,
notintree(j-1) = notintree(j);
end;
number_notin_tree = number_notin_tree - 1;
in = intree(1:number_in_tree),
out = notintree(1:number_notin_tree),
pause,
end;
disp(' Edges in minimum spanning tree and their costs: ')
[mst costs]
cost = sum(costs)
When I click the run button says:
Not enough input arguments.
Error in prim (line 10)
[n,n] = size(A);
% The matrix is n by n, where n = # nodes.
However when I call the function in the Command window with
s=[1 1 2 2 2 3 3 4 4 4 5 5 6 7];
t=[2 3 4 5 3 5 6 5 7 8 6 8 7 8];
w=[3 5 4 7 4 9 8 3 11 8 3 9 8 7];
G = graph(s,t,w);
A = adjacency(G);
prim(A)
The code works 'correctly'
As a final answer returns
mst =
cost=
All zero sparse: 1-by-1
It should have returned
mst=
1 2
2 3
2 4
4 5
5 6
6 7
7 8
costs=32
Why did not returned that?
Whilst running the program went from 1 to 4 though it should have gone to 2. Then from 4 to 5, that was correct but I don't know why skipped 2 and 3 and went directly to 4,5,6,7,8.
Help me please.
If there is an alternative code that you know please provide it, perhaps an easier one.
The main problem with your function is that when you check to see if the current edge has lower cost than mincost, you don't verify that there's actually an edge there. If there's no edge, then the cost will be 0, which is naturally lower than any positive cost value. You need to change the line:
if A(ii,jj) < mincost,
to
if (A(ii,jj) > 0) && (A(ii,jj) < mincost), % A(ii,jj) is edge and lower cost than mincost
Adjacency matrix used as input:
A =
0 3 5 0 0 0 0 0
3 0 4 4 7 0 0 0
5 4 0 0 9 8 0 0
0 4 0 0 3 0 11 8
0 7 9 3 0 3 0 9
0 0 8 0 3 0 8 0
0 0 0 11 0 8 0 7
0 0 0 8 9 0 7 0
The output after this change is:
mst =
1 2
2 3
2 4
4 5
5 6
4 8
8 7
cost = 32
Related
To find the output of the following formula in Matlab, I need to get all elements of a matrix (PDA in the following code) except its first element without using any loop.
Formula(Goal): % EVec = (A11-B11).^2 - (A12-B12).^2 - .. - (Aij-Bij).^2
Ex:
A(:,:,1) = [1 2 3 4; 4 5 6 1];
A(:,:,2) = [0 5 4 3; 2 7 6 0];
A(:,:,3) = [1 2 3 9; 0 6 7 0];
B(:,:,1) = [4 0 3 4; 4 8 0 1];
B(:,:,2) = [0 5 6 1; 0 9 4 3];
B(:,:,3) = [2 0 3 5; 8 6 7 2];
PDA = (A-B).^2;
EVec = PDA(1,1,:) - sum(PDA(?, ?, :)); % The problem is sum(PDA(?, ?,:)).
The result of PDA is:
PDA(:,:,1) =
9 4 0 0
0 9 36 0
% All of them except Val(1,1) = 9.
PDA(:,:,2) =
0 0 4 4
4 4 4 9
% All of them except Val(1,1) = 0.
PDA(:,:,3) =
1 4 0 16
64 0 0 4
% All of them except Val(1,1) = 1.
And my problem is in the output of PDA(1,1,:) - sum(PDA(?, ?, :)) that should be:9-(4+0+0+0+0+9+36+0), 0-(0+4+4+4+4+4+9), 1-(4+0+16+64+0+0+4) = [-40, -29, -87]..Unfortunately it doesn't.
How to get all elements of a matrix except its first element in Matlab?
The first element minus the sum of the remaining elements is just twice the first element minus the sum of all elements, so
>> squeeze(2*PDA(1,1,:) - sum(sum(PDA,1),2))
ans =
-40
-29
-87
Or in newer releases
>> squeeze(2*PDA(1,1,:) - sum(PDA,[1,2]))
ans =
-40
-29
-87
I have 10 bins, and each bin contains a specific number of observations, e.g.:
a = [0,0,1,0,0,2,0,0,0,2]
I'd like to subsequently tally how many times any given pair of (non-zero) bins co-occur - based on the number of observations.
Given the above example, bin#3 = 1, bin#6 = 2 and bin#10 = 2.
This means that bin 3 and 6 co-occurred once, bin 3 and 10 co-occurred once, and bin 6 and 10 co-occurred twice (the minimum value of the pair is taken).
My desired output is a full matrix, listing every possible bin combination (columns 1-2) and the tally of what was observed (column 3):
1 2 0
1 3 0
1 4 0
1 5 0
1 6 0
1 7 0
1 8 0
1 9 0
1 10 0
2 3 0
2 4 0
2 5 0
2 6 0
2 7 0
2 8 0
2 9 0
2 10 0
3 4 0
3 5 0
3 6 1
3 7 0
3 8 0
3 9 0
3 10 1
4 5 0
4 6 0
4 7 0
4 8 0
4 9 0
4 10 0
5 6 0
5 7 0
5 8 0
5 9 0
5 10 0
6 7 0
6 8 0
6 9 0
6 10 2
7 8 0
7 9 0
7 10 0
8 9 0
8 10 0
9 10 0
Is there a short and/or fast way of doing this?
You can get all combinations of the bin numbers in many ways. I'll use combvec for ease.
Then it's relatively simple to vectorise this using min...
a = [0,0,1,0,0,2,0,0,0,2];
n = 1:numel(a);
% Use unique and sort to get rid of duplicate pairs when order doesn't matter
M = unique( sort( combvec( n, n ).', 2 ), 'rows' );
% Get rid of rows where columns 1 and 2 are equal
M( M(:,1) == M(:,2), : ) = [];
% Get the overlap count for bins
M( :, 3 ) = min( a(M), [], 2 );
Try this.
bin_output = [....];
bin_matrix = [0,0,1,0,0,2,0,0,0,2];
bin_nonzero = find(bin_matrix);
for j = 1:length(bin_nonzero);
if isequal(j,length(bin_nonzero))
break;
end
for k = (j+1):(length(bin_nonzero))
for m = 1:length(bin_output)
if isequal(bin_output(m,1),j) && isequal(bin_output(m,2),k)
bin_output(m,3) = bin_output(m,3) + min([bin_matrix(1,bin_nonzero(1,j)),bin_matrix(1,bin_nonzero(1,k))]);
end
end
end
end
Let's say I have a 3 x 3 matrix (A), and I want to make it a 5 x 5 matrix (B), but the Matrix A has the following content:
1 2 3
4 5 6
7 8 9
And the resulting bigger matrix B, needs to have the following content:
1 0 2 0 3
0 0 0 0 0
4 0 5 0 6
0 0 0 0 0
7 0 8 0 9
I know this can be done with some "Fors" following a sequence like:
%% We get the dimensions of our matrix.
[xLength, yLength] = size(InMat);
%% We create a matrix of the double size.
NewInMat = zeros(xLength * 2, yLength * 2);
%% We prepare the counters to fill the new matrix.
XLenN = (xLength * 2) -1;
YLenN = (yLength * 2) - 1;
for i = 1 : XLenN
for j = 1 : YLenN
if mod(i, 2) ~= 0
if mod(j, 2) ~= 0
NewInMat(i, j) = InMat(i, j);
else
NewInMat(i,j) = mean([InMat(i, j - 1), InMat(i, j + 2)]);
end
end
end
end
But I would like to know if there is an easier way, or if Matlab has a tool for doing this task. Many thanks in advance!
You can use indexing:
InMat = [...
1 2 3
4 5 6
7 8 9];
s = size(InMat)*2-1;
NewInMat(1:2:s(1), 1:2:s(2)) = InMat;
Here NewInMat is allocated and filled at the same time.
I have a square symmetric matrix A of dimension n in Matlab and I want to reorder the elements in each row in ascending order but preserving the symmetry and without touching the diagonal elements.
E.g.
n=4;
A=[10 9 8 7; 9 6 5 4; 8 5 3 2; 7 4 2 1];
%reorder A in order to obtain
B=[10 7 8 9; 7 6 4 5; 8 4 3 2; 9 5 2 1];
Could you provide some help?
you can use triu to sort only the upper triangle and then add the transpose to keep the symmetry. finally just set the diagonal as in the original matrix:
n=4;
A=[10 9 8 7; 9 6 5 4; 8 5 3 2; 7 4 2 1];
% upper triangle indexes
UI = triu(true(size(A)),1);
% upper triangle of A
B = triu(A,1);
% assign inf to diagonal and below - important if there are any negative values in A
B(~UI) = -inf;
% sort rows descending order
B = sort(B,2,'ascend');
% set infs to 0
B(isinf(B)) = 0;
% add lower triangle matrix
B = B + B.';
% set diagonal as original A
B(1:n+1:n^2) = diag(A)
A = [10 9 8 7;
9 6 5 4;
8 5 3 2;
7 4 2 1];
B = sort(triu(A,1),2) + diag(diag(A)) + sort(triu(A,1),2)';
Explain
triu(A,1) gets the upper triangular matrix above the main diagonal, that is
ans0 =
0 9 8 7
0 0 5 4
0 0 0 2
0 0 0 0
sort(triu(A,1),2) sorts the elements in each row of the above result in an ascending order, that is
ans1 =
0 7 8 9
0 0 4 5
0 0 0 2
0 0 0 0
diag(diag(A)) gets the diagonal of A, that is
ans2 =
10 0 0 0
0 6 0 0
0 0 3 0
0 0 0 1
sort(triu(A,1),2)' gets the transpose of the sorted upper triangular matrix, that is
ans =
0 0 0 0
7 0 0 0
8 4 0 0
9 5 2 0
Add ans1, ans2 and ans3 up, you will get B.
I have divied an Image into number of subimages. Now I want to compare the average intensity of each subimage with its 8 neighbors. But in some points there would be less than 8 neighbors. For example for the first block(i=1,J=1), the upperleft block(i-1,j-1) does not exist. How can I check this and skip to the next valid one?
file='myimg.bmp';
I=imread(file);
blockSizeR = 128; % Rows in block.
blockSizeC = 128; % Columns in block.
wholeBlockRows = floor(rows / blockSizeR);
blockVectorR = [blockSizeR * ones(1, wholeBlockRows), rem(rows, blockSizeR)];
wholeBlockCols = floor(columns / blockSizeC);
blockVectorC = [blockSizeC * ones(1, wholeBlockCols), rem(columns, blockSizeC)];
ca = mat2cell(I, blockVectorR, blockVectorC);
%get the mean value of each cell
meanValues = cellfun(#(x) mean(x(:)),ca);
for j=1:size(ca(2))
for i=1:size(ca(1))
currentSlice = ca(i,j);
MeanOfCurrentSlice = cellfun(#(x) mean(x(:)),currentSlice);
%here I want to minus the 8 neighbors average grayscale intensity from the currentSlice average grayscale inensity and take the absolute sum
end
end
A solution that give you the index of the nearest neighbor for each element:
%creation of the index matrix (here a 3x3 matrix)
M = reshape([1:9],3,3);
%subdivide the matrix into 3x3 array
IND = nlfilter(M,[3 3],#(x){x(:)});
%elimination of the value where IND == 0 or IND == index value of the element
for ii = 1:size(M,1)
for jj = 1:size(M,2)
IND{ii,jj}(IND{ii,jj}==0|IND{ii,jj}==sub2ind(size(M),ii,jj)) = [];
end
end
PS: nlfilteris part of the image processing toolbox, but it's easy to create your own similar function.
STEP 1:
M =
1 4 7
2 5 8
3 6 9
STEP 2:
IND =
{
[1,1] =
0 0 0 0 1 2 0 4 5
[2,1] =
0 0 0 1 2 3 4 5 6
[3,1] =
0 0 0 2 3 0 5 6 0
[1,2] =
0 1 2 0 4 5 0 7 8
[2,2] =
1 2 3 4 5 6 7 8 9
[3,2] =
2 3 0 5 6 0 8 9 0
[1,3] =
0 4 5 0 7 8 0 0 0
[2,3] =
4 5 6 7 8 9 0 0 0
[3,3] =
5 6 0 8 9 0 0 0 0
}
STEP 3:
IND =
{
[1,1] = %neighbors of the value M[1,1]
2 4 5
[2,1] =
1 3 4 5 6
[3,1] =
2 5 6
[1,2] =
1 2 5 7 8
[2,2] =
1 2 3 4 6 7 8 9
[3,2] =
2 3 5 8 9
[1,3] =
4 5 8
[2,3] =
4 5 6 7 9
[3,3] =
5 6 8
}