Matlab: How to matrix calculation with cell matrix? - matlab

I need to calculation R*S*R'.
R is an ordinary matrix.
But S is composed of values. The element of S is the value of F(w), and is calculated by
[PressureSpecAuto,F] = periodogram(....);
S{i,j} = PressureSpecAuto;
which means each element is a set of data.
The problem is that, Matlab cannot multiply cell matrix with matrix, then How can I solve this problem?
Notice: The element of S should not be treated as an vector. It's just the value set of function F(w).
UPDATE1:
Element in S(the value set of a function)
Essentially, element in S is a function's value, e.g. f(x). When multiplying, it is still R(1,:)*S(:,1). That is, R(1,1) * S(1,1) + R(1,2) * S(2,1) ...
UPDATE2:
R:
1 0 0 0 0 0
0 0 0 0 0 0
1 0 0 0 0 0
0 0 0 0 0 0
1 0 0 0 0 0
0 0 0 0 0 0
1 0 0 0 0 0
0 0 0 0 0 0
0 1 0 0 0 0
0 0 0 0 0 0
0 1 0 0 0 0
0 0 0 0 0 0
0 1 0 0 0 0
0 0 0 0 0 0
0 1 0 0 0 0
0 0 0 0 0 0
0 0 0 0 0 0
0 0 0 1 0 0
0 0 0 0 0 0
0 0 1 0 0 0
0 0 0 0 0 0
0 0 0 1 0 0
0 0 0 0 0 0
0 0 0 0 1 0
0 0 0 0 0 0
0 0 0 0 0 1
Element in S( e.g. S(1,1) ):
2.11586339015690e-23
6548.06822760155
10933.4416318101
67974.4878764171
1640.90694018577
22254.1105594943
54583.8668300499
25426.8190829386
4646.70203854458
19224.2485418923
17292.0278726986
928.765041030392
14728.5614115324
113385.034815149
30274.0332077125
22697.8886043178
61916.4030808219
38648.2740539840
127.547928632502
24452.0499691112
12311.1687443994
6627.23433956309
11264.7956369618
7232.97125504007
4120.08127891675
1546.69594235781
22795.2322822644
627.572461904325
9237.43533412019
3433.67898348596

Could you use a loop? Maybe this would work then...
Just use a loop and loop through the indices of S to extract each matrix. Then do the multiplication.
In essence:
for n=1:numel(S)
R*S{n}*R'
end
or using cellfun where #(x) is an anonymous function.
cellfun(#(x) R*x*R', S, 'UniformOutput',false)

Related

How to draw 2 merging trees using an adjacency matrix in Matlab

I have an adjacency matrix describing two trees that merges in the middle. An exemple for 10 nodes:
The corresponding adjacency matrix is a 10x10 matrix where the first row correspond to the first node (start of the first tree, node #1) and the last row to the root of the second tree (end of the second tree, node #10).
Here is the adjacency matrix corresponding to a larger example with 22 nodes:
0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 1
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0
I'm trying to plot this adjacency matrix as the picture showed above using Matlab. Matlab as some tools for plotting trees, for example the code given in:
https://blogs.mathworks.com/cleve/2017/03/20/morse-code-binary-trees-and-graphs/
However, using the previous matrix (let's label it 'A') and the following code:
G = digraph(A);
Gp = plot(G);
does not produce a tree, but a graph (not ordered as a tree).
Thus, how to produce a picture of a tree (as showed above) using 'A' in Matlab?
Please note that I also have matrices describing trees where the degree between the children nodes are 3 (or more) rather than 2.
Zero-out half of your adjacency matrix to make the connection one-way.
By default, MATLAB tries to decide the layout of graphs automatically, based on the structure of your graph. There are a few different graph layouts you can choose from.
The option you wanted is the 'Layered' layout; but I tested it with your example, and it definitely still doesn't look like a tree. The reason being that your adjacency matrix is symmetrical, and the connection is two-way. This confuses MATLAB when placing the nodes, and it doesn't think it's a tree.
The easy fix, is you can zero-out the lower triangular half of your adjacency matrix. I used the function tril for this.
% Create a lower triangular matrix with the dimension of A,
idx = tril(ones(size(A)));
% Make it a logical array to select matrix elements with
idx = logical(idx);
% Select the defined lower triangular part, and set that to zero
A(idx) = 0;
% Generate-Plot graph as you did
G = digraph(A);
plot(G)
Result

How to correctly use the col2im function?

This function is confusing to use, and it always gives me an error:
To RESHAPE the number of elements must not change.
That's my code:
im=im2col(zeros(300,300),[3 3]);
im(:,9)=ones(9,1);
im=col2im(im,[3 3],[300 300]);
Basically, this code just gets the block at index 6, replaces it with ones, and reassembles it back into the original image. What's wrong with this code?
It seems you want to create distinct blocks from your input array, change single blocks, and rearrange them. (Your target size is the same as your input array size.) So, you must use the distinct parameter in both, im2col as well as col2im:
blk_size = [3, 3];
im = zeros(9, 9)
temp = im2col(im, blk_size, 'distinct');
temp(:, 3) = ones(prod(blk_size), 1);
im2 = col2im(temp, [3 3], size(im), 'distinct')
Output:
im =
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
im2 =
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0
1 1 1 0 0 0 0 0 0
1 1 1 0 0 0 0 0 0
1 1 1 0 0 0 0 0 0
When using im2col with the sliding parameter, which is also the default, if no parameter is set at all, there'll be a lot more columns in the result than can be rearranged to the input array size, cf. the Tips section on im2col.
Hope that helps!

"""Diagonal""" -1/+1 Matrix

I need to construct the tech cycle constraint matrix Aa and the right side ba. The aim is building the technology cycle matrices in order to solve the scheduling linear problem constrained by Ax<=b. In this case -1 and +1 in A refers to the coefficients of the constraints of the problem such as starting times and precedences
TC = [1,2,3,4,6,7;1,2,5,4,6,7;2,5,6,7,0,0]; % Technology cycle
CT = [100,60,200,160,80,120;100,60,150,120,60,150;50,120,40,30,0,0]; % Cycle time
n_jb = size(TC,1); % number of jobs
n_op = sum(TC~=0,2); % number of operations for each job
N_op = sum(n_op); % total number of operations
c=1; % indice for constraints in Aa
Op=1; % counter for overall operation
n_tf = N_op - n_jb- sum(n_op==1); % number of job transfer between machines (also number of tech cycle constraint numbers)
Aa = zeros(n_tf,N_op); % Constraint matrx for tech cycle
ba = zeros(n_tf,1); % The right vector of the constraint function: Aa*x<=ba
for j=1:n_jb
if n_op(j)>1
for op=1:n_op(j)-1
Aa(c,Op)=-1;
Aa(c,Op+1)=1;
ba(c,1)=CT(j,op);
c=c+1;
Op=Op+1;
end
else
Op=Op+1;
end
Op=Op+1;
end
The output, like Aa is 3 """diagonal""" -1/+1 matrices:
-1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 -1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 -1 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 -1 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 -1 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 -1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 -1 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 -1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 -1 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 -1 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 -1 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1
In order to be more precise in the following there is an image: showing the 3 different part of the matrix Aa. My question is: Is there a way to build the same this avoiding loops since A is not a 3x1 but will definitely become 30-50x1?
You can use diag to create the positive and negative ones. The second input to diag is to shift the diagonal to the side. In this case, 1 to the right.
Use cumsum to find the rows you want to remove. For n = [6, 6, 4], you want to remove the 6th, 12th and 16th row.
n = [6, 6, 4];
cols = sum(n);
A = -eye(cols) + diag(ones(cols-1,1), 1);
A(cumsum(n),:) = []
A =
-1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 -1 1 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 -1 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 -1 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 -1 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 -1 1 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 -1 1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 -1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 -1 1 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 -1 1 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 -1 1 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 -1 1

Find out first circle in an image on Matlab (wrt. y-axis)

I'm using Matlab. I have a 2-D Binary image/array. like this
0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 1 1 1 0 0 1 0 0
0 0 1 1 0 0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 1 1 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0
I want to find out center of very first white block/Circle with respect to y-axis
Answer of the above image will be.
0 1 0
1 1 1
0 1 0
Anyone who have have a simplest solution for this.
If you are looking for exact matches of the template, you can use a moving filter, one example is:
H=[0 0 0 0 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 1 0 0 0 0 0 0;
0 0 0 0 0 1 1 1 0 0 1 0 0;
0 0 1 1 0 0 1 0 0 0 0 0 0;
0 0 0 1 0 0 0 0 0 0 0 0 0;
0 0 0 0 0 0 1 0 0 0 0 0 0;
0 0 0 0 0 0 1 1 0 0 0 0 0;
0 0 0 0 0 0 1 0 0 0 0 0 0];
b=[0 1 0;
1 1 1;
0 1 0];
C=filter2(b,H, 'same');
[x,y]=find(C==max(max(C)));
x and y are the locations of your template in the order that it appears from the top left corner of your array.
Edit: if you have the Image Processing Toolbox and are looking for a less strict way of finding objects that have a roughly circular shape you can use regionprops with the 'Centroid' and 'Eccentricity' arguments with the bwconncomp function.
ObjectStats=regionprops(bwconncomp(H,4), 'Centroid', 'Eccentricity');
Objects with an 'Eccentricity' of 0 (or close to 0) will be the circles.
idx=find(cell2mat({ObjectStats.Eccentricity})==0); % Change ==0 to <0.2 or something to make it less strict.
ctrs={ObjectStats.Centroid};
>> ctrs{1,idx(1)}
ans =
7 3
Note that in your case, a lone pixel is an object with an eccentricity of 0, it is the smallest 'circle' that you can find. If you need to define a minimum size, use the 'Area' property of regionprops
You can do this with a simple 2 dimensional convolution. It will "overlay" the filter along a larger matrix and multiply the filter by the values it is overlaying. If the product is equal to the sum of the filter, then you know you found a match.
Here is some simple code.
mat = [0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 1 1 1 0 0 1 0 0
0 0 1 1 0 0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 1 1 0 0 0 0 0
0 0 0 0 0 0 1 0 0 0 0 0 0];
filt = [0 1 0
1 1 1
0 1 0];
[row,col] = find(conv2(mat,filt,'same') == sum(filt(:)))

How to replace elements of a matrix by an another matrix in MATLAB?

How to replace elements of a matrix by an another matrix in MATLAB?
Ex: let say if we have a matrix A, where
A=[1 0 0; 0 1 0; 1 0 1]
I want to replace all ones by
J=[1 0 0; 0 1 0; 0 0 1]
and zeros by
K=[0 0 0; 0 0 0; 0 0 0]
So that I can get 9x9 matrix. So how we will code it in MATLAB
Thanks
Sounds like you might want to take a look at the kronecker tensor product. This is not a general case but the idea should work for what you want
>> kron(A==1,J)+kron(A==0,K)
ans =
1 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0 0
1 0 0 0 0 0 1 0 0
0 1 0 0 0 0 0 1 0
0 0 1 0 0 0 0 0 1
which, for the example case, would simplify to a simpler command:
>> kron(A,J)
ans =
1 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0
0 0 0 1 0 0 0 0 0
0 0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0 0
1 0 0 0 0 0 1 0 0
0 1 0 0 0 0 0 1 0
0 0 1 0 0 0 0 0 1
You can do:
A2=imresize(A,size(A).*size(J),'nearest');
J2=repmat(J,size(A));
K2=repmat(K,size(A));
A2(A2==1)=J2(A2==1);
A2(A2==0)=K2(A2==0)