MATLAB: Create a block diagonal matrix - matlab

I have a formula for creating a system of equations in matrix form.and wrote it like below:
for i=1:n+1
for j=1:n+1
t(i)=(1/2)*(1+cos(((2*(n-i)+3)*pi)/(2*(n+1))));
y(i,j)=t(i)^(j-1);
end
end
now what I have to do is creating a block diagonal matrix with rows of y separately in each block. i mean each row of y that contain powers of just t(i) should repeat three times in each block, then next row be the next block with three rows. like this:
T=[y(t1) 0 0;0 y(t1) 0;0 0 y(t1); ... ;y(t n+1) 0 0;0 y(tn+1) 0;0 0 y(tn+1)]

So since I can't comment in formated mode I try to interprete your question the following way:
So if
y =
1 2
3 4
Interpretation possibility a) is
T =
1 2 0 0 0 0 3 4 0 0 0 0
0 0 1 2 0 0 0 0 3 4 0 0
0 0 0 0 1 2 0 0 0 0 3 4
or this b)
T =
1 2 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 0 1 2 0 0 0 0 0 0
0 0 0 0 0 0 3 4 0 0 0 0
0 0 0 0 0 0 0 0 3 4 0 0
0 0 0 0 0 0 0 0 0 0 3 4
Solution
You first create one block i.e.
1 2 0 0 0 0
0 0 1 2 0 0
0 0 0 0 1 2
by calculating temp{1} = kron(I, y(1,:)), where I = eye(3). You then do the same operation for the second row: temp{2} = kron(I,y(2,:)) and so on. This procedure can be done easily in a for-loop:
I = eye(3);
temp = cell(1,size(y,1));
for i = 1:size(y,1)
temp{i} = kron(I, y(i,:));
end
Option a)
The result is now just: [temp{:}].
Option b)
Here the result is: blkdiag(temp{:})

you know, I had a problem for making a system of linear equations.maybe what I wrote above in calculating the y(i) just make it difficult for me.
for the example you said, I have this:
n=3
form equation above:
t1=0.0381
t2=0.3087
t3=0.6913
t4=0.9619
now,
y(t)=[1 t t^2 t^3 t^4]
I mean
y(t1)=[1.0000 0.0381 0.0014 0.0001]
y(t2)=[1.0000 0.3087 0.0953 0.0294]
y(t3)=[1.0000 0.6913 0.4780 0.3304]
y(t4)=[1.0000 0.9619 0.9253 0.8901]
but, since I couldn't calculate every y(i) seperately, wrote it in this form
y=[1.0000 0.0381 0.0014 0.0001
1.0000 0.3087 0.0953 0.0294
1.0000 0.6913 0.4780 0.3304
1.0000 0.9619 0.9253 0.8901]
now, should have two matrices. one:
s=[y(t) 0 0;0 y(t) 0;0 0 y(t)]
r=[s(t1) ... 0; ... ;0 ... s(tn+1)]
second:
d=[ 1 -1 1 -1
0 2 -8 18
0 0 8 -48
0 0 0 32]
k=y*d
u=[0 0 0;0 k 0;0 0 0]
a=[u(t1) ... 0; ... ;0 ... u(tn+1)]
and these matrices, r and a, should have 3(n+1) columns (in this example 12 columns).
I hope it could help

Related

perimeter of periodic binary matrix (in matlab)

I have a periodic binary matrix which includes a block of ones. I need to find the boundary between zeros and ones in the matrix. Here is an example:
A=[0,1,1,1,0,0,0,1,1;
0,0,0,0,1,1,1,1,0;
0,0,0,0,1,1,1,1,0;
0,0,0,0,1,1,1,1,0;
0,1,1,1,1,1,1,0,0;
0,1,1,1,1,1,1,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]
If the matrix was not periodic, I could use
perim=bwperim(A);
to find the perimeter. But this does not work perfectly for periodic matrices. I appreciate it if someone can help me with this problem.
EDIT:
a periodic matrix is a matrix that its boundary elements are connected to the boundary elements on the other side of the matrix.
You can pad the image on each side with the column/row that it's connected to. For example, the left edge will be padded with the rightmost column. Then use bwperim, and trim one row/column from each side of the result.
A = [0 1 1 1 0 0 0 1 1;
0 0 0 0 1 1 1 1 0;
0 0 0 0 1 1 1 1 0;
0 0 0 0 1 1 1 1 0;
0 1 1 1 1 1 1 0 0;
0 1 1 1 1 1 1 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];
padded_A = [0 A(end,:) 0;
A(:,end) A A(:,1);
0 A(1,:) 0];
padded_perim = bwperim(padded_A);
perim = padded_perim(2:end-1,2:end-1);
Result:
perim =
0 1 1 1 0 0 0 1 1
0 0 0 0 1 1 1 1 0
0 0 0 0 1 0 0 1 0
0 0 0 0 1 0 0 1 0
0 1 1 1 0 0 1 0 0
0 1 0 0 1 1 1 0 0
0 1 0 1 0 0 0 0 0
0 1 0 1 0 0 0 0 0
0 1 0 1 0 0 0 0 0
You can use conv2 and padarray to find the perimeter:
4-connected:
perim = A & conv2(padarray(A, [1 1], 'circular'), [0 1 0;1 0 1;0 1 0], 'valid') < 4;
8-connected:
perim = A & conv2(padarray(A, [1 1], 'circular'), [1 1 1;1 0 1;1 1 1], 'valid') < 8;
Using the definition of the perimeter:
A pixel is part of the perimeter if it is nonzero and it is connected to at least one zero-valued pixel.
Use A & ... to ensure that the pixel is nonzero. The boundary pixels are replicated using padarray with option 'circular'. The padded array is convolved with the connectivity mask. use conv2 with option 'valid' to trim the replicated boundary pixels. If it is less than 4 or 8 it means that it is connected to at least one zero-valued pixel.

How do I create random matrix where each column is all zeroes except for one random row?

I want to create a matrix of size m-by-n where all elements in a column are 0 except one element which is 1. That one element must be at a random position.
eg.
[0 1 0 0 0
0 0 1 0 0
1 0 0 1 0
0 0 0 0 0
0 0 0 0 1]
To add some variety, here's another approach:
m = 4;
n = 5;
[~, result] = sort(rand(m,n));
result = double(result==1);
This gives, for example,
result =
0 0 0 0 1
0 1 0 0 0
1 0 0 1 0
0 0 1 0 0
You can also use rand and max to do the job:
m=4;
n=5;
R=rand(m,n);
result = bsxfun(#eq, R, max(R,[],1))
On my machine it gave:
1 1 0 0 0
0 0 0 0 0
0 0 1 0 1
0 0 0 1 0
How it works: Generating a random matrix, R, and then setting to 1 the entry corresponding to the maximal element at each column. No need for sorting.
Regarding the original answer of Divakar, since it uses randperm it is restricted to square matrix only, and it will only produce random permutation matrices.
One possible way to correct his solution is to use randi instead of randperm:
result = bsxfun( #eq, (1:m)', randi(m, 1, n ) )
May give this output:
1 0 1 0 0
0 0 0 0 0
0 0 0 0 0
0 1 0 1 1
As for the answer of bla, using accumarry can save the use of zeros and sub2ind:
m=5; n=10;
R=randi(m,n,1);
A = accumarray( {R, (1:n)' }, 1, [m n] )
May give this output:
0 0 0 0 1 0 0 1 0 0
0 1 0 0 0 0 1 0 1 0
1 0 0 1 0 0 0 0 0 1
0 0 0 0 0 1 0 0 0 0
0 0 1 0 0 0 0 0 0 0
Another idea I have is to create the identity matrix of size m x m, then use randi with a range from 1 up to m to create a vector of n elements long. After, you'd use this vector to access the columns of the identity matrix to complete the random matrix you desire:
m = 5; n = 5; %// Given your example
M = eye(m);
out = M(:,randi(m, n, 1));
Here's one possible run of the above code:
out =
1 0 0 0 0
0 0 0 0 0
0 0 0 1 0
0 0 0 0 0
0 1 1 0 1
here's an example using randi:
m=5; n=10;
A=zeros(m,n);
R=randi(m,n,1);
A(sub2ind(size(A),R',1:n))=1
A =
0 0 0 0 0 0 0 1 0 1
0 0 1 0 0 0 0 0 0 0
0 1 0 1 0 1 0 0 0 0
0 0 0 0 1 0 0 0 0 0
1 0 0 0 0 0 1 0 1 0
You can use sparse with randi for a one-liner, like so -
full(sparse(randi(m,1,n),1:n,1,m,n))
Sample run -
>> m = 5; n = 6;
>> full(sparse(randi(m,1,n),1:n,1,m,n))
ans =
0 1 0 0 0 1
0 0 1 1 0 0
0 0 0 0 0 0
1 0 0 0 1 0
0 0 0 0 0 0

what do the commas in (cl,:,k) in MATLAB do, when building a matrix

I know how to build a matrix within MATLAB but the example I am working on has is defined as
a(cl,:,k)=x*ang;
cl, k, x and ang are already defined. I just wondered what the (cl,:,k) does, in particular the role of the commas?
Also, if I were to replicate this within Excel then how would I do so?
The comma , in a(cl,:,k) is to separate different dimensions of the matrix a.
The colon : in a(cl,:,k) is to select all elements along this dimension (restricted by other dimensions), which is shorthand notation for 1:end. In other words, all elements a(cl, 1:end, k) are selected, where end is the size of the second dimension of a.
For example:
a = zeros(2, 3); // 2x3 matrix with all elements are 0
a(1, :) = [1 2 3]; // <=> a(1,1:3)=[1 2 3]; assign all elements to the first row
then, a will be
1 2 3
0 0 0
The commas separate the indices along different axes of the elements of the multi dimensional array you want to access
: means 1:end - here end will become the largest index possible along that axis
>> a = zeros(3,3,3)
a(:,:,1) =
0 0 0
0 0 0
0 0 0
a(:,:,2) =
0 0 0
0 0 0
0 0 0
a(:,:,3) =
0 0 0
0 0 0
0 0 0
>> a(1,:,1) = 1
a(:,:,1) =
1 1 1
0 0 0
0 0 0
a(:,:,2) =
0 0 0
0 0 0
0 0 0
a(:,:,3) =
0 0 0
0 0 0
0 0 0
>> a(2,1:end,2) = 2
a(:,:,1) =
1 1 1
0 0 0
0 0 0
a(:,:,2) =
0 0 0
2 2 2
0 0 0
a(:,:,3) =
0 0 0
0 0 0
0 0 0
>> a(1,1,:) = 5
a(:,:,1) =
5 1 1
0 0 0
0 0 0
a(:,:,2) =
5 0 0
2 2 2
0 0 0
a(:,:,3) =
5 0 0
0 0 0
0 0 0

Transform vector with repeating values into a matrix in Matlab

I have a vector of n size, which I would like to transform into the Boolean matrix of nxm, where m is a number of unique values in that vector.
a = repmat(1:5:20,1,3)
a =
1 6 11 16 1 6 11 16 1 6 11 16
The result I would like to have is the matrix 12x4:
1 0 0 0
0 1 0 0
0 0 1 0
...
0 0 0 1
Any ideas how to do that without for loop?
You can try this:
a = repmat(1:5:20,1,3);
b = unique(a);
bsxfun(#eq, a', b)
The result would be:
ans =
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
a = repmat(1:5:20,1,3)
b=unique(a);
c = repmat(a',1,numel(b))== repmat(b,numel(a),1);
but in general a loop will be faster, repmat is to be avoided.
So, now with a loop:
a = repmat(1:5:20,1,3)
b=unique(a);
c=false(numel(a),numel(b));
for ii=1:numel(a)
c(ii,:) = a(ii)==b;
end

Please help me to test my hypothesis with the neighbor elements in the matrix

I could not figure out the last part of my research so if anyone could help me I would be really appreciated for the help.. :)
Say that my original matrix is,
X =
0 0 0 0 0
0 0 12 9 0
0 4 9 15 0
0 11 19 0 0
0 2 4 8 0
0 4 5 8 0
0 0 0 0 0
and after finding the average of the non-zeros I will get something like below:
new_x =
0 0 0 0 0
0 0 **9.0000** 9.0000 0
0 4.0000 9.0000 **9.0000** 0
0 **8.3333** **8.0000** 0 0
0 2.0000 4.0000 8.0000 0
0 4.0000 5.0000 8.0000 0
0 0 0 0 0
Note that any elements that are greater than 10 are the 'center' and we want to find the average of the non-zeros with the radius of say 1 m. where 1 meter = 1 element away from the center.
** ** means the center.
For this part I have used the following (from gnovice):
X=[0 0 0 0 0; 0 0 12 9 0; 0 4 9 15 0; 0 11 19 0 0;
0 2 4 8 0; 0 4 5 8 0; 0 0 0 0 0];
kernel=[0 1 0; 1 0 1; 0 1 0];
sumx=conv2(X,kernel,'same');
nx=conv2(double(X>0),kernel,'same');
index=(X>10);
new_x=X;
new_x(index)=sumx(index)./max(nx(index),1);
So my question is that I want to compare the neighbor elements with its center whether they are equal, lesser, or greater. If it is greater or equal then '1' or else '0'.Also whatever elements that are outside the radius can be ignored and replaced with '0'.
For example, the 9 in the middle is within the radius of 12, 15, and 19 centers, so take the minimum center of those `min[9.000, 9.000, 8.000] = 8.000.
In this case 4 will not take into the consideration as it is not called the 'center' as well as [ 8 4 5 and 8 ] in the last two rows.
So I want something like below:
Test_x =
0 0 0 0 0
0 0 1 1 0
0 0 1 1 0
0 1 1 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
I have put this first part in the forum before and I am really appreciated for every suggestion earlier.
Please give me some ideas to start with. I have tried using a loop but it didnt seem to work very well. Any MATLAB function that can do the job for me..
Thank you so much for the help.
Beginner at MATLAB
I think I found the solution for this question by using Jonas techniques. Thank you for the help Jonas and gnovie:)
X=[0 0 0 0 0; 0 0 12 9 0; 0 4 9 15 0; 0 11 19 0 0; 0 2 4 8 0; 0 4 5 8 0; 0 0 0 0 0];
kernel=[0 1 0; 1 0 1; 0 1 0];
sumx=conv2(X,kernel,'same');
nx=conv2(double(X>0),kernel,'same');
avg_x=X;
avg_x(avg_x<10)=0;
index=(avg_x>10);
avg_x(index)=sumx(index)./max(nx(index),1);
avg_x =
0 0 0 0 0
0 0 9.0000 0 0
0 0 0 9.0000 0
0 8.3333 8.0000 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
tmp_x=avg_x;
maxVal=max(avg_x(:))+1;
tmp_x(tmp_x==0)=maxVal;
tmp_x=imerode(tmp_x,kernel);
Test_x=X>=tmp_x;
I think what you want to do is create a new array based on new_x that replaces every element by the minimum of its 4-connected neighbours. Then you can compare the new array to new_x.
Here's a way to do this (requires the image processing toolbox)
tmp_x = new_x;
maxVal = max(new_x(:))+1;
tmp_x(tmp_x == 0) = maxVal; %# replace all the zeros in tmp_x with something large
tmp_x = imerode(tmp_x,kernel); %# kernel is the same as in the OP
Test_x = new_x >= tmp_x; %# put ones wherever the value is
%# greater or equal the neighbour's minimum
%# only keep 1's that are next to 'centers'
Test_x = Test_x .* imdilate(X>10,strel('disk',1))
Test_x =
0 0 0 0 0
0 0 1 1 0
0 0 1 1 0
0 1 1 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 0
Note that I get one more ones with this logic than you do.