How can I generate the following Matrices in Matlab - fast method? - matlab

I have two input variables:
N=10;
M=4;
Using Matlab, I want to generate the following matrices - without using for loops, for any M and N:
%N = 1 2 3 4 5 6 7 8 9
Mat1 = [2, 3, 4, 5, 6, 7, 8, 9, 10; %M=1 -> Mat1(1, i) = N(i)+1
3, 6, 9, 12, 15, 18, 21, 27, 30; %M=2 -> Mat1(2, i) = N(i)+N(i)*2
4, 8, 12, 16, 20, 24, 28, 32, 36; %M=3 -> Mat1(2, i) = N(i)+N(i)*3
5, 10, 15, 20, 25, 30, 35, 40, 45] %M=4 -> Mat1(2, i) = N(i)+N(i)*4
%N = 1 2 3 4 5 6 7 8 9
Mat2 = [1, 2, 3, 4, 5, 6, 7, 8, 9; %M=1 -> Mat2(2, i) = N(i)
1, 4, 7, 10, 13, 16, 19, 25, 28; %M=2 -> Mat2(2, i) = N(i)+N(i)*2-2
1, 5, 9, 13, 17, 21, 25, 29, 33; %M=3 -> Mat2(2, i) = N(i)+N(i)*3-3
1, 6, 11, 16, 21, 26, 31, 36, 41] %M=4 -> Mat2(2, i) = N(i)+N(i)*4-4
General description:
% i=1:N
%Mat1(M, i) = N(i)+N(i)*M , if M>1
% N(i)+1 , if M=1
%Mat2(M, i) = N(i)+N(i)*M-M , if M>1
% N(i) , if M=1
I wrote a code with two for loops, but I would like to ask if there is any method to get these results, without using loops. I tried with bsxfun and arrayfun, but I did not manage to get the right result:
clear Mat1 Mat2
N=10;
M=9;
Mat1 = ones(M, N);
Mat2 = ones(M, N);
for i=1:M
for j=1:N
if i==1
Mat1(i, j) = j+1;
Mat2(i, j) = j;
elseif j ==1
Mat1(i, j) = j+j*i;
elseif i~=1 && j~=1
Mat1(i, j) = j+j*i;
Mat2(i, j) = j+j*i-i;
end
end
end
Thank you

My try:
N=10;
M=4;
mat1 = bsxfun(#(x,y) x*(y.*(y>1)+1)+(y==1), 1:N,(1:M)')
mat2 = bsxfun(#(x,y) x*(y.*(y>1)+1)-(y>1).*y, 1:N,(1:M)')

I think this might do what you are looking for:
First matrix:
Mat1 = (2:N+1)'*(1:N);
Mat1 = Mat1(1:M,:);
Mat1(1,:) = 2:N+1;
This gives (N=10, M=4):
Mat1 =
2 3 4 5 6 7 8 9 10 11
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
Second matrix:
tmp = (0:N-2)'*(1:N-1);
Mat2 = repmat((4:3:3*N),M-1,1) + tmp(1:M-1,:);
Mat2 = [ones(M,1), [2:N; Mat2]];
Which gives:
Mat2 =
1 2 3 4 5 6 7 8 9 10
1 4 7 10 13 16 19 22 25 28
1 5 9 13 17 21 25 29 33 37
1 6 11 16 21 26 31 36 41 46
It was a bit of a puzzle, as it is not all too clear what exactly are the rules to build these matrices. But if it is just these matrices you want, this should be a fast way to get them.
For all N and M these lines of code produce the same matrices as you code with for loops does.

Meanwhile I learned how to use bsxfun and repmat. I got a compact code for both Mat1 and Mat2 generators:
N=10;
M=4;
Mat1 = bsxfun(#times, (1:M)', (1:N)) +...
[ones(1, N) ; horzcat( ones(M-1,1) , repmat(2:N,M-1,1) ) ];
Mat2 = [ones(M,1), [(2:N); bsxfun(#plus, (2:M)',(2:N)) +...
horzcat( zeros(M-1,1), bsxfun(#times, (2:M)',(1:N-2)) ) ] ];
Mat1 =
2 3 4 5 6 7 8 9 10 11
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
Mat2 =
1 2 3 4 5 6 7 8 9 10
1 4 7 10 13 16 19 22 25 28
1 5 9 13 17 21 25 29 33 37
1 6 11 16 21 26 31 36 41 46

I haven't tried these for every test case so I am not sure if it's totally general. I think you should be able to investigate what I used to do this and arrive at a solution for the first matrix as well. I think you might have some typos in your sample matrices above, hopefully this will get you on the right track
M=4;
N=10;
Mat2=repmat([1:N],M,1);
Mat2(2:M,:)=Mat2(2:M,:)+bsxfun(#times, Mat2(2:M,:), [2:M]');
Mat2(2:M,:)=bsxfun(#minus, Mat2(2:M,:), [2:M]');
gives us:
Mat2 =
1 2 3 4 5 6 7 8 9 10
1 4 7 10 13 16 19 22 25 28
1 5 9 13 17 21 25 29 33 37
1 6 11 16 21 26 31 36 41 46
with M=5 and N=10
Mat2 =
1 2 3 4 5 6 7 8 9 10
1 4 7 10 13 16 19 22 25 28
1 5 9 13 17 21 25 29 33 37
1 6 11 16 21 26 31 36 41 46
1 7 13 19 25 31 37 43 49 55
and I think this is Mat1:
Mat1=repmat([1:N],M,1);
Mat1(2:M,:)=Mat1(2:M,:)+bsxfun(#times, Mat1(2:M,:), [2:M]');
Mat1(1,:)=Mat1(1,:)+1;
Mat1 =
2 3 4 5 6 7 8 9 10 11
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50

Related

Fastest code to merge two matrices of different dimension in Matlab

I have two matrices in Matlab A and B respectively of dimension MxN and GxN.
M can be greater or smaller than G.
A and B do not contain identical rows.
I want to construct a matrix C of dimension Hx(N+2) in the following way
C=[];
for i=1:size(A,1)
%if A(i,1:end-1) coincides with a row in B(:,1:end-1) (it can coincide with only one row at most)
%then C=[C;A(i,1:end) B(j,end)]; %where j is the index of the identical row in B
%otherwise impose C=[C;A(i,1:end) 0]
end
for i=1:size(B,1)
%if B(i,1:end-1) does not coincide with any row in A(:,1:end-1)
%then impose C=[C; B(i,1:end-1) 0 B(i,end)];
end
For example:
A=[1 2 3 4 5 100; 6 7 8 9 10 101; 11 12 13 14 15 102];
B=[6 7 8 9 10 103; 15 16 17 18 19 104]
C=[1 2 3 4 5 100 0; 6 7 8 9 10 101 103; 11 12 13 14 16 102 0; 15 16 17 18 19 0 104]
As M and G can be very high, I am looking for the fastest way to perform this.
You can use ismember + indexing to do your task:
[idx1,idx2] = ismember(A(:,1:end-1), B(:,1:end-1), 'rows');
idx3 = ~ismember(B(:,1:end-1), A(:,1:end-1), 'rows');
C(idx1,:) = [A(idx1,:) B(idx2(idx1),end)];
C(~idx1,:) = [A(~idx1,:) zeros(sum(~idx1),1)];
C=[C;B(idx3,1:end-1) zeros(sum(idx3),1) B(idx3,end)];
You could also use intersect with a bit of preallocation to speed up the assignment (if M or G gets really large).
A=[1 2 3 4 5 100; 6 7 8 9 10 101; 11 12 13 14 15 102];
B=[6 7 8 9 10 103; 15 16 17 18 19 104];
C=[1 2 3 4 5 100 0; 6 7 8 9 10 101 103; 11 12 13 14 16 102 0; 15 16 17 18 19 0 104];
[M,N] = size(A);
G = size(B,1);
[tmp, idxA, idxB] = intersect(A(:,1:end-1),B(:,1:end-1),'rows')
idxBnotA = setdiff([1:G],idxB);
H = M + G - length(idxA);
C1 = zeros(H,N+1);
C1(1:M,1:N) = A;
C1(idxA,end) = B(idxB,end);
C1(M+1:end,1:end-2) = B(idxBnotA,1:end-1);
C1(M+1:end,end) = B(idxBnotA,end)

How can I select rows with specific column values from a matrix?

I have a matrix train3.
1 2 3 4 5 6 7
2 12 13 14 15 16 17
3 62 53 44 35 26 17
4 52 13 24 15 26 37
I want to select only those rows of whose 1st columns contain specific values (in my case 1 and 2).
I have tried the following,
>> train3
train3 =
1 2 3 4 5 6 7
2 12 13 14 15 16 17
3 62 53 44 35 26 17
4 52 13 24 15 26 37
>> ind1 = train3(:,1) == 1
ind1 =
1
0
0
0
>> ind2 = train3(:,1) == 2
ind2 =
0
1
0
0
>> mat1 = train3(ind1, :)
mat1 =
1 2 3 4 5 6 7
>> mat2 = train3(ind2, :)
mat2 =
2 12 13 14 15 16 17
>> mat3 = [mat1 ; mat2]
mat3 =
1 2 3 4 5 6 7
2 12 13 14 15 16 17
>>
Is there any better way to do this?
Presumably you are trying to get mat3 in a single step which you can do with:
mat3 = train3(train3(:,1)==1 | train3(:,1)==2,:)
A more general way to do this would be to use ismember to get all of the rows that match the values in a list:
train3 =[
1 2 3 4 5 6 7
2 12 13 14 15 16 17
3 62 53 44 35 26 17
4 52 13 24 15 26 37];
chooseList = [1 2];
colIndex = ismember(train3(:, 1), chooseList);
subset = train3(colIndex, :);
subset =
1 2 3 4 5 6 7
2 12 13 14 15 16 17

Matlab: Cut Vector at missing values and create new vectors

I want to write a Matlab script.
In my example I have a vector A=[1 3 4 5 7 8 9 10 11 13 14 15 16 17 19 20 21]
Now I want to cut the vector automatically at the points where a number is missing(here the numbers 2, 6, 12, 18 are missing).
As a result I want to have the vectors [1] and [3 4 5] and [7 8 9 10 11] and [13 14 15 16 17] and [19 20 21]. So as you can see the new vectors have different lenghts.
I thought about using a for loop, but I am not sure how to write these new vectors.
Thank you for your help :)
One liner with diff, cumsum & accumarray -
out = accumarray(cumsum([0 ; diff(A(:))~=1])+1,A(:),[],#(x) {x})
Sample run -
>> A
A =
1 3 4 5 7 8 9 10 ...
11 13 14 15 16 17 19 20 21
>> celldisp(out)
out{1} =
1
out{2} =
3
4
5
out{3} =
7
8
9
10
11
out{4} =
13
14
15
16
17
out{5} =
19
20
21
This is one approach:
s = [find(diff(A(:).')>1) numel(A)]; %'// detect where consecutive difference exceeds 1
s = [s(1) diff(s)]; %// sizes of groups
result = mat2cell(A(:).', 1, s); %'// split into cells according to those sizes
In your example, this gives
>> celldisp(result)
result{1} =
1
result{2} =
3 4 5
result{3} =
7 8 9 10 11
result{4} =
13 14 15 16 17
result{5} =
19 20 21
Another approach (computes group sizes differently):
s = diff([0 sum(bsxfun(#lt, A(:), setdiff(1:max(A(:).'), A(:).')), 1) numel(A)]);
result = mat2cell(A(:).', 1, s);

corresponding indices from two different matrices in matlab

In an algorithm, in each level, I have two corresponding matrices in a way one of them has 4 times more element than the other. like children and parent, but i need to have the corresponding elements. consider the two following indices as an example for a level
1 5 9 13
2 6 10 14 and 1 3
3 7 11 15 2 4
4 8 12 16
so for example, I want to receive the element by the index of 1 from the second matrix when i have each of 1,2,5,6 element indices from the first matrix or 2 when i have 3,4,7,8 or 3 for 9,10,16,14 and so on. how can i do that?
as an another example for another level:
1 9 17 25 33 41 49 57
2 10 18 26 34 42 50 58
3 11 19 27 35 43 51 59 and 1 5 9 13
4 12 20 28 36 44 52 60 2 6 10 14
5 13 21 29 37 45 53 61 3 7 11 15
6 14 22 30 38 46 54 62 4 8 12 16
7 15 23 31 39 47 55 63
8 16 24 32 40 48 56 64
Here is one way of doing that:
% Size of matrix A (8x8)
sizeA = 8;
% Size of matrix B (4x4)
sizeB = 4;
% Index of element on matrix A
idxA = 43;
% That is how you can get the corresponding index on matrix B
[r, c] = ind2sub([sizeA sizeA], idxA);
idxB = sub2ind([sizeB sizeB], ceil(r / 2), ceil(c / 2))
It will give you idxB = 10.
It is possible that reshape could be helpful for you.
Consider
A = [1 5 9 13;
2 6 10 14;
3 7 11 15;
4 8 12 16];
B = reshape(permute(reshape(A, [2 2 2 2]), [2 4 1 3]), [4 4]);
B
1 2 5 6
3 4 7 8
9 10 13 14
11 12 15 16
Now you have a nice mapping of the indices from one level to the next.
B(1,:) corresponds to all the indices that map to element 1 in your second array, etc.
When the matrix gets larger (2n x 2n), the operation becomes
B = reshape(permute(reshape(A, [2 n 2 n]), [2 4 1 3]), [n*n 4]);
If you know the 2D indices for the first matrix, then you just divide each by 2 to get the second pair indices:
r = 3;
c = 2;
% Then A(r,c) corresponds to B(floor(r/2), floor(c/2))
If you DON'T know the indices, but instead have the element value itself, you have to find the 2D index first:
val = 7; % test value
[r c] = find(A==val);
other_val = B(floor(r/2), floor(c/2));

Matrix division & permutation to achieve Baker map

I'm trying to implement the Baker map.
Is there a function that would allow one to divide a 8 x 8 matrix by providing, for example, a sequence of divisors 2, 4, 2 and rearranging pixels in the order as shown in the matrices below?
X = reshape(1:64,8,8);
After applying divisors 2,4,2 to the matrix X one should get a matrix like A shown below.
A=[31 23 15 7 32 24 16 8;
63 55 47 39 64 56 48 40;
11 3 12 4 13 5 14 6;
27 19 28 20 29 21 30 22;
43 35 44 36 45 37 46 38;
59 51 60 52 61 53 62 54;
25 17 9 1 26 18 10 2;
57 49 41 33 58 50 42 34]
The link to the document which I am working on is:
http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.39.5132&rep=rep1&type=pdf
This is what I want to achieve:
Edit: a little more generic solution:
%function Z = bakermap(X,divisors)
function Z = bakermap()
X = reshape(1:64,8,8)'
divisors = [ 2 4 2 ];
[x,y] = size(X);
offsets = sum(divisors)-fliplr(cumsum(fliplr(divisors)));
if any(mod(y,divisors)) && ~(sum(divisors) == y)
disp('invalid divisor vector')
return
end
blocks = #(div) cell2mat( cellfun(#mtimes, repmat({ones(x/div,div)},div,1),...
num2cell(1:div)',...
'UniformOutput',false) );
%create index matrix
I = [];
for ii = 1:numel(divisors);
I = [I, blocks(divisors(ii))+offsets(ii)];
end
%create Baker map
Y = flipud(X);
Z = [];
for jj=1:I(end)
Z = [Z; Y(I==jj)'];
end
Z = flipud(Z);
end
returns:
index matrix:
I =
1 1 3 3 3 3 7 7
1 1 3 3 3 3 7 7
1 1 4 4 4 4 7 7
1 1 4 4 4 4 7 7
2 2 5 5 5 5 8 8
2 2 5 5 5 5 8 8
2 2 6 6 6 6 8 8
2 2 6 6 6 6 8 8
Baker map:
Z =
31 23 15 7 32 24 16 8
63 55 47 39 64 56 48 40
11 3 12 4 13 5 14 6
27 19 28 20 29 21 30 22
43 35 44 36 45 37 46 38
59 51 60 52 61 53 62 54
25 17 9 1 26 18 10 2
57 49 41 33 58 50 42 34
But have a look at the if-condition, it's just possible for these cases. I don't know if that's enough. I also tried something like divisors = [ 1 4 1 2 ] - and it worked. As long as the sum of all divisors is equal the row-length and the modulus as well, there shouldn't be problems.
Explanation:
% definition of anonymous function with input parameter: div: divisor vector
blocks = #(div) cell2mat( ... % converts final result into matrix
cellfun(#mtimes, ... % multiplies the next two inputs A,B
repmat(... % A...
{ones(x/div,div)},... % cell with a matrix of ones in size
of one subblock, e.g. [1,1,1,1;1,1,1,1]
div,1),... % which is replicated div-times according
to actual by cellfun processed divisor
num2cell(1:div)',... % creates a vector [1,2,3,4...] according
to the number of divisors, so so finally
every Block A gets an increasing factor
'UniformOutput',false...% necessary additional property of cellfun
));
Have also a look at this revision to have a simpler insight in what is happening. You requested a generic solution, thats the one above, the one linked was with more manual inputs.