Create a horizontically stretched upper triangular matrix - matlab

I'd like to create a 4x12 matrix which is very similar to a upper triangle matrix, it looks like this:
1 1 1 1 1 1 1 1 1 1 1 1
0 0 0 1 1 1 1 1 1 1 1 1
0 0 0 0 0 0 1 1 1 1 1 1
0 0 0 0 0 0 0 0 0 1 1 1
So my question is. What is the most efficient way to create it? no loops, no cellfun. Thanks.

One vectorized approach -
nrows = 4;
ncols = 12;
row_idx = repmat(1:nrows,ncols/nrows,1)
out = bsxfun(#le,[1:nrows]',row_idx(:).')

The Matlab R2015a and later approach using the newly introduced repelem:
n = 4;
m = 3;
out = repelem(triu(ones(n)),1,m);
out =
1 1 1 1 1 1 1 1 1 1 1 1
0 0 0 1 1 1 1 1 1 1 1 1
0 0 0 0 0 0 1 1 1 1 1 1
0 0 0 0 0 0 0 0 0 1 1 1
It even seems faster than the bsxfun approach, though I can't believe this ;)
Benchmark
Unfortunately I couldn't consider andrew's solution as it is not complete and I didn't got it totally.
function [t] = bench()
n = 4;
m = 12;
t = zeros(3,15);
for ii = 1:15
fcns = {
#() thewaywewalk(ii*n,ii*m);
#() Divakar(ii*n,ii*m);
#() LuisMendo(ii*n,ii*m);
};
% timeit
for jj = 1:100;
t(:,ii) = t(:,ii) + cellfun(#timeit, fcns);
end
end
plot(1:15,t(1,:)); hold on;
plot(1:15,t(2,:)); hold on;
plot(1:15,t(3,:)); hold on;
xlabel('Matrix size: n = x*4, m = x*12')
ylabel('timing')
legend({'thewaywewalk','Divakar','Luis Mendo'},'location','northwest')
end
function Z = thewaywewalk(n,m)
Z = repelem(triu(ones(n)),1,m/n);
end
function Z = Divakar(n,m)
row_idx = repmat(1:n,m/n,1);
Z = bsxfun(#le,[1:n]',row_idx(:).');
end
function Z = LuisMendo(n,m)
Z = reshape(repmat(permute(triu(ones(n,n)), [1 3 2]), [1 m/n 1]), [n m]);
end
First bottomline - small matrices:
The new repelem does a very good job, but also the reshape(repmat(permute... does not disappoint. The bsxfun approach stays a little behind for some medium-sized matrices, before it becomes the leader for large matrices:
Second bottomline - big matrices:
As predicted by Divakar, bsxfun is the fastest for larger matrices, actually as expected as bsxfun is always the fastest! Interesting that the other two align perfectly, on could guess they almost work the same internally.

Create an upper triangular matrix of ones, permute second and third dimensions, repeat along second dimension, and reshape into desired shape:
m = 4;
n = 12;
result = reshape(repmat(permute(triu(ones(m,m)), [1 3 2]), [1 n/m 1]), [m n]);

depending on your matlab version
m = 4;
n = 12;
dec2bin(bitshift(num,-1*[0:n/m:n-1])) %this prints out a string
these should be logical arrays (i don't have either of these so I cant test it)
decimalToBinaryVector(bitshift(num,-1*[0:n/m:n-1]))
de2bi(bitshift(num,-1*[0:n/m:n-1]))

Related

How to permute elements of a vector by another vector to obtain a matrix of permutations

I want to obtain all the possible permutations of one vector elements by another vector elements. For example one vector is A=[0 0 0 0] and another is B=[1 1]. I want to replace the elements of A by B to obtain all the permutations in a matrix like this [1 1 0 0; 1 0 1 0; 1 0 0 1; 0 1 1 0; 0 1 0 1; 0 0 1 1]. The length of real A is big and I should be able to choose the length of B_max and to obtain all the permutations of A with B=[1], [1 1], [1 1 1],..., B_max.
Thanks a lot
Actually, since A and B are always defined, respectively, as a vector of zeros and a vector of ones, this computation is much easier than you may think. The only constraints you should respect concerns B, which shoud not be empty and it's elements cannot be greater than or equal to the number of elements in A... because after that threshold A will become a vector of ones and calculating its permutations will be just a waste of CPU cycles.
Here is the core function of the script, which undertakes the creation of the unique permutations of 0 and 1 given the target vector X:
function p = uperms(X)
n = numel(X);
k = sum(X);
c = nchoosek(1:n,k);
m = size(c,1);
p = zeros(m,n);
p(repmat((1-m:0)',1,k) + m*c) = 1;
end
And here is the full code:
clear();
clc();
% Define the main parameter: the number of elements in A...
A_len = 4;
% Compute the elements of B accordingly...
B_len = A_len - 1;
B_seq = 1:B_len;
% Compute the possible mixtures of A and B...
X = tril(ones(A_len));
X = X(B_seq,:);
% Compute the unique permutations...
p = [];
for i = B_seq
p = [p; uperms(X(i,:).')];
end
Output for A_len = 4:
p =
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
1 1 0 0
1 0 1 0
1 0 0 1
0 1 1 0
0 1 0 1
0 0 1 1
1 1 1 0
1 1 0 1
1 0 1 1
0 1 1 1

How to generate a customized checker board matrix as fast as possible?

I need a function that creates a checker board matrix with M rows and N columns of P*Q rectangles. I modified the third solution from here to get that:
function [I] = mycheckerboard(M, N, P, Q)
nr = M*P;
nc = N*Q;
i = floor(mod((0:(nc-1))/Q, 2));
j = floor(mod((0:(nr-1))/P, 2))';
r = repmat(i, [nr 1]);
c = repmat(j, [1 nc]);
I = xor(r, c);
it works with no problem:
I=mycheckerboard(2, 3, 4, 3)
I =
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 1 1 1 0 0 0
1 1 1 0 0 0 1 1 1
1 1 1 0 0 0 1 1 1
1 1 1 0 0 0 1 1 1
1 1 1 0 0 0 1 1 1
But it's not fast enough since there are lots of calls of this function in a single run. Is there a faster way to get the result? How can I remove floating point divisions and/or calls of the floor function?
Your code is fairly fast for small matrices, but becomes less so as the dimensions get larger. Here's a one-liner using bsxfun and imresize (requires Image Processing toolbox that most have):
m = 2;
n = 3;
p = 4;
q = 3;
I = imresize(bsxfun(#xor, mod(1:m, 2).', mod(1:n, 2)), [p*m q*n], 'nearest')
Or, inspired by #AndrasDeak's use of kron, this is faster with R2015b:
I = kron(bsxfun(#xor, mod(1:m, 2).', mod(1:n, 2)), ones(p, q))
For a small bit more speed, the underlying code for kron can be simplified by taking advantage of the structure of the problem:
A = bsxfun(#xor, mod(1:m, 2).', mod(1:n, 2));
A = permute(A, [3 1 4 2]);
B = ones(q, 1, p);
I = reshape(bsxfun(#times, A, B), [m*n p*q]);
or as one (long) line:
I = reshape(bsxfun(#times, permute(bsxfun(#xor, mod(1:m, 2).', mod(1:n, 2)), [3 1 4 2]), ones(q, 1, p)), [m*n p*q]);
I suggest first creating a binary matrix for the checkerboard's fields, then using the built-in kron to blow it up to the necessary size:
M = 2;
N = 3;
P = 4;
Q = 3;
[iM,iN] = meshgrid(1:M,1:N);
A = zeros(M,N);
A(mod(iM.'+iN.',2)==1) = 1;
board = kron(A,ones(P,Q))

Conditionally replace neighbouring cells

Lets say I have a matrix A:
A =
0 1 0 0
0 0 0 0
0 0 0 1
0 0 0 0
And I want to create a new matrix B of the same dimension where all ones and accompanying neighbours are replaced by the following matrix:
X =
1 1 1
1 2 1
1 1 1
The 2 in matrix X should be placed 'on top' of the 1 values as to get:
B =
1 2 1 0
1 1 2 1
0 0 1 2
0 0 1 1
Values should be added up where elements overlap and matrix X should be 'cut off' in places where it extends the dimensions of matrix A/B The idea is to eventually replace X by a 2d gaussian distribution and matrix A will be large containing many more ones. So it's essential that the code is efficient and fast. This is the code i came up with:
A = [0 1 0 0;0 0 0 0;0 0 0 1;0 0 0 0]
X = [1 1 1;1 2 1;1 1 1]
B = zeros(4,4);
t=1;
indA = find(A==1);
indX = find(X==2);
all = find(X>0);
[iall jall] = ind2sub(size(X),all);
[ia ja] = ind2sub(size(A),indA)
[ix jx] = ind2sub(size(X),indX)
iv = ia-ix
jv = ja-jx
for t=1:numel(iv),
ib = iall+iv(t);
jb = jall+jv(t);
ibjb = [ib(:), jb(:)]
c1 = (ibjb(:,1)>4)|(ibjb(:,1)<1); c2 = (ibjb(:,2)>4)|(ibjb(:,1)<1);
ibjb((c1|c2),:)=[]
isel = ibjb(:,1)-iv(t)
jsel = ibjb(:,2)-jv(t)
B(ibjb(:,1), ibjb(:,2)) = B(ibjb(:,1), ibjb(:,2))+ X(isel, jsel)
t=t+1;
end
Is there a more efficient/faster way (minimizing the loops) to code this function?
What you want is a (2D) convolution. So use conv2:
B = conv2(A, X, 'same');

Inserting variable number of zeros between non-zero elements in a vector in MATLAB

I have a vector like:
a = [1,2,3,4,5,6...,n]
and I would like to obtain a new vector like this:
a_new = [1,0,0,2,0,0,3,0,0,4,0,0,5,0,0,6,...,0,0,n]
where a fixed number of zeros (2 in the above example) are inserted between the non-zero elements. If I choose zero_p=3, the new vector would be:
a_new = [1,0,0,0,2,0,0,0,3,0,0,0,4,0,0,0,5,0,0,0,6,...,0,0,0,n]
etc.
How can I do this?
Try this:
zero_p=3;
a_new=zeros(1, (zero_p+1)*length(a)-zero_p);
a_new(1:(zero_p+1):end)=a;
(Untested, but should hopefully work.)
There's a few ways I can think of:
Kronecker product
The kronecker product is excellently suited for this.
In Matlab, kron is what you're looking for:
a = 1:4;
a = kron(a, [1 0 0])
ans =
1 0 0 2 0 0 3 0 0 4 0 0
or, generalized,
a = 1:4;
zero_p = 3;
b = [1 zeros(1,zero_p-1)];
a = kron(a, b)
ans =
1 0 0 2 0 0 3 0 0 4 0 0
If you want to have it end with a non-zero element, you have to do one additional step:
a = a(1:end-zero_p);
Or, if you like one-liners, the whole thing can be done like this:
a = 1:4;
zero_p = 3;
a = [kron(a(1:end-1), [1 zeros(1,zero_p-1)]), a(end)]
ans =
1 0 0 2 0 0 3 0 0 4
Zero padding
Probably the simplest method and best performance:
a = 1:4;
zero_p = 3;
a = [a; zeros(zero_p, size(a, 2))];
a = a(1:end-zero_p);
Matrix multiplication
Also simple, readable and great performance, although it might be overkill for many situations other than this particular scenario:
a = 1:4;
b = [1; zeros(zero_p, 1)];
a = b*a;
a = a(1:end-zero_p);
x = [1 2 3 4 5];
upsample(x,3)
o/p: 1 0 0 2 0 0 3 0 0 4 0 0 5 0 0
Cheers!!

Matlab indexing into 2D array using

I have a 2D matrix, say M=zeros(10,10);
I have another column matrix, V=[1;2;3;4;5;6;5;4;3;2];
I would like to be able to set M(i,j) = 1 for all j >= V(i)
I know I can do this in a loop
for i=1:10
M(i,V(i):10) = 1;
end
but it seems that it would be possible to use some form of Matlab indexing to avoid using a loop. For example something like :
M(:,V:10)=1;
or
M(:,V(:):10)=1;
but neither of these produces the expected result.
Is there some syntactic sugar I can use to achieve this or should I revert to looping?
Since you're looking for syntactic sugar, here's a sort of esoteric way of doing it. :)
Assuming the length of V is the size of both dimensions in the desired matrix M, first create an identity matrix of the same size, then index appropriately and take cumsum:
V = [1;2;3;4;5;6;5;4;3;2]; #% 10x1 vector
E = eye(length(V), length(V)); #%10x10 identity matrix
M = cumsum(E(V,:),2)
M =
1 1 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1 1
0 0 1 1 1 1 1 1 1 1
0 0 0 1 1 1 1 1 1 1
0 0 0 0 1 1 1 1 1 1
0 0 0 0 0 1 1 1 1 1
0 0 0 0 1 1 1 1 1 1
0 0 0 1 1 1 1 1 1 1
0 0 1 1 1 1 1 1 1 1
0 1 1 1 1 1 1 1 1 1
Ok, now: less fun, but (on my machine) faster than any of the other options that have been tested so far:
n=10000;
V = randi(n-1, 1, n); #% as in #KevinRatelle's answer (but not transposed)
tic;
Vlinear = reshape(V + (0:n-1)*n, 1, []); #% find linear indices of first "ones"
M = zeros(n);
M(Vlinear)=1;
M=cumsum(M);
toc
Its hardly subtle and not really better than a loop I don't think but:
[J,I] = meshgrid(1:10,1:10);
V = [1;2;3;4;5;6;5;4;3;2];
M = J>V(I);
Enjoy.
I tried the loop method, and the 'meshgrid' method. I was wondering about the time to compute for large matrices (since the issue with loops in matlab is usually the time).
First, I optimised the code to look like this :
V = V*ones(1,n);
N = ones(1,n)'*(1:n);
M = N>=V;
Actually, N is a meshgrid, but it seems way faster to do it this way...
I tried this :
n = 10000;
V = randi(n-1,1,n)';
tic;
M = zeros(n);
for i=1:n
M(i,V(i):n) = 1;
end
toc
tic;
[J,I] = meshgrid(1:n,1:n);
M = J>=V(I);
toc
tic;
V = V*ones(1,n);
N = ones(1,n)'*(1:n);
M = N>=V;
toc
And results were :
Elapsed time is 1.726872 seconds.
Elapsed time is 5.206657 seconds.
Elapsed time is 1.548600 seconds.
But methods using matrices instead of loops are memory consuming for large n. I would personnaly stick to the loop.
try this:
v = [1;2;3;4;5;6;5;4;3;2];
n = 10;
M = repmat((1:n)', 1, numel(v)) > repmat(v', n, 1);