How can I generate the following matrix in MATLAB? - matlab

I want to generate a matrix that is "stairsteppy" from a vector.
Example input vector: [8 12 17]
Example output matrix:
[1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0]
[0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0]
[0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1]
Is there an easier (or built-in) way to do this than the following?:
function M = stairstep(v)
M = zeros(length(v),max(v));
v2 = [0 v];
for i = 1:length(v)
M(i,(v2(i)+1):v2(i+1)) = 1;
end

You can do this via indexing.
A = eye(3);
B = A(:,[zeros(1,8)+1, zeros(1,4)+2, zeros(1,5)+3])

Here's a solution without explicit loops:
function M = stairstep(v)
L = length(v); % M will be
V = max(v); % an L x V matrix
M = zeros(L, V);
% create indices to set to one
idx = zeros(1, V);
idx(v + 1) = 1;
idx = cumsum(idx) + 1;
idx = sub2ind(size(M), idx(1:V), 1:V);
% update the output matrix
M(idx) = 1;
EDIT: fixed bug :p

There's no built-in function I know of to do this, but here's one vectorized solution:
v = [8 12 17];
N = numel(v);
M = zeros(N,max(v));
M([0 v(1:N-1)]*N+(1:N)) = 1;
M(v(1:N-1)*N+(1:N-1)) = -1;
M = cumsum(M,2);
EDIT: I like the idea that Jonas had to use BLKDIAG. I couldn't help playing with the idea a bit until I shortened it further (using MAT2CELL instead of ARRAYFUN):
C = mat2cell(ones(1,max(v)),1,diff([0 v]));
M = blkdiag(C{:});

A very short version of a vectorized solution
function out = stairstep(v)
% create lists of ones
oneCell = arrayfun(#(x)ones(1,x),diff([0,v]),'UniformOutput',false);
% create output
out = blkdiag(oneCell{:});

You can use ones to define the places where you have 1's:
http://www.mathworks.com/help/techdoc/ref/ones.html

Related

Create a special diagonal matrix

I want to create a special diagonal matrix in MATLAB that
uses [1 1] or any other array as main diagonal elements.
Something like the following:
[1 1 0 0 0 0
0 0 1 1 0 0
0 0 0 0 1 1]
How can I do that without using any loop structures?
Let
v = [1 1];
n = 3;
Using kron:
result = kron(eye(n), v);
Using blkdiag:
vv = repmat({v}, 1, n);
result = blkdiag(vv{:});

Make a one simple code from several similar code

Hello everybody I have a very simple problem, I have too many data y, p and r. So I want to calculate it in a single code.
This an example of my code if I breakdown into separate code
y1=45
y2=56
y3=67
p1=34
p2=45
p3=56
r1=23
r2=34
r3=45
Ryaw1=[cosd(y1) -sind(y1) 0;
sind(y1) cosd(y1) 0;
0 0 1]
Rpitch1=[cosd(p1) 0 sind(p1);
0 1 0;
-sind(p1) 0 cos(p1)]
Rroll1=[1 0 0;
0 cosd(r1) -sind(r1);
0 sind(r1) cosd(r1)]
R1=Ryaw1*Rpitch1*Rroll1
Coordinate1=R1*X0
Ryaw2=[cosd(y2) -sind(y2) 0;
sind(y2) cosd(y2) 0;
0 0 1]
Rpitch2=[cosd(p2) 0 sind(p2);
0 1 0;
-sind(p2) 0 cos(p2)]
Rroll2=[1 0 0;
0 cosd(r2) -sind(r2);
0 sind(r2) cosd(r2)]
R2=Ryaw2*Rpitch2*Rroll2
Coordinate2=R2*X0
Ryaw3=[cosd(y3) -sind(y3) 0;
sind(y3) cosd(y3) 0;
0 0 1]
Rpitch3=[cosd(p3) 0 sind(p3);
0 1 0;
-sind(p3) 0 cos(p3)]
Rroll3=[1 0 0;
0 cosd(r3) -sind(r3);
0 sind(r3) cosd(r3)]
R3=Ryaw3*Rpitch3*Rroll3
Coordinate3=R3*X0
Coordinate=[Cooedinate1 Coordinate2 Coordinate3]
The goals is to find "Coordinate" (in matrix - combined from Coordinate1, Coordinate2, Coordinate3, .... ,Coordinate..) from every y, p and r data with the same "X0" as a single primary data for calculation.
Sorry for my bad english,
Thanks :)
Use vectors and matrices instead of individual scalars. These are indexed in almost the same way as you had before, i.e. y1 becomes y(1).
Then you can easily loop over the code 3 times and save the repetition.
See my commented code below.
% Define some X0. This should be a column vector.
X0 = [1; 2; 3];
% Make y,p,r into 3 element vectors
y = [45 56 67];
p = [34 45 56];
r = [23 34 45];
% Make R, Ryaw, Rpitch and Rroll 3x3x3 matrices
R = zeros(3,3,3);
Ryaw = zeros(3,3,3);
Rpitch = zeros(3,3,3);
Rroll = zeros(3,3,3);
% Make Coordinate a 3x3 matrix
Coordinate = zeros(3,3);
% Loop k from 1 to 3
% For each 3x3x3 matrix, the kth 3x3 matrix is equivalent to your Ryawk, Rpitchk, Rrollk, Rk
for k = 1:3
Ryaw(:,:,k) = [cosd(y(k)) -sind(y(k)) 0
sind(y(k)) cosd(y(k)) 0
0 0 1];
Rpitch(:,:,k)= [cosd(p(k)) 0 sind(p(k))
0 1 0
-sind(p(k)) 0 cos(p(k))];
Rroll(:,:,k) = [1 0 0
0 cosd(r(k)) -sind(r(k))
0 sind(r(k)) cosd(r(k))];
R(:,:,k) = Ryaw(:,:,k)*Rpitch(:,:,k)*Rroll(:,:,k);
Coordinate(:,k) = R(:,:,k)*X0;
end
disp(Coordinate)

Create a horizontically stretched upper triangular matrix

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]))

MATLAB Expanding A Matrix with Zeros

I need a matrix of nxn, where the first pxp of it contains ones and rest are zeros. I can do it with traversing the cells, so I'm not asking a way to do it. I'm looking for "the MATLAB way" to do it, using built-in functions and avoiding loops etc.
To be more clear;
let n=4 and p=2,
then the expected result is:
1 1 0 0
1 1 0 0
0 0 0 0
0 0 0 0
There are possibly more than one elegant solution to do it, so I will accept the answer with the shortest and most readable one.
P.S. The question title looks a bit irrelevant: I put that title because my initial approach would be creating a pxp matrix with ones, then expanding it to nxn with zeros.
The answer is creating a matrix of zeroes, and then setting part of it to 1 using indexing:
For example:
n = 4;
p = 2;
x = zeros(n,n);
x(1:p,1:p) = 1;
If you insist on expanding, you can use:
padarray( zeros(p,p)+1 , [n-p n-p], 0, 'post')
Another way to expand the matrix with zeros:
>> p = 2; n = 4;
>> M = ones(p,p)
M =
1 1
1 1
>> M(n,n) = 0
M =
1 1 0 0
1 1 0 0
0 0 0 0
0 0 0 0
You can create the matrix easily by concatenating horizontally and vertically:
n = 4;
p = 2;
MyMatrix = [ ones(p), zeros(p, n-p); zeros(n-p, n) ];
>> p = 2; n = 4;
>> a = [ones(p, 1); zeros(n - p, 1)]
a =
1
1
0
0
>> A = a * a'
A =
1 1 0 0
1 1 0 0
0 0 0 0
0 0 0 0

Generate boolean matrix by predicate on row and column

I have the following vector:
y = [1; 3; 2; 3; 1];
All its values are between 1 and n (in this case, 3) and denote different options.
I want to create a matrix of size size(y, 1) x n whose rows correpond to y values:
1 0 0 % because y(1) = 1
0 0 1 % because y(2) = 3
0 1 0 % because y(3) = 2
0 0 1
1 0 0
One way to do this would be
Y = zeros(size(y, 1), num_labels);
for i = 1:m
Y(i, y(i)) = 1;
end
Is there a better way to do this, maybe in a single expression?
Basically, what I need is to generate a matrix with boolean predicate (i, j) => j == y(i).
You can try this if a is a column vector
a = [1; 3; 2; 3; 1];
bsxfun(#eq, a, [1:max(a)])
and this if it is a row vector
a = [1; 3; 2; 3; 1]';
bsxfun(#eq, a', [1:max(a)])
If you have access to Statistics Toolbox, the command dummyvar does exactly what you need.
>> y = [1; 3; 2; 3; 1];
>> dummyvar(y)
ans =
1 0 0
0 0 1
0 1 0
0 0 1
1 0 0
You can use sub2ind after initializing the matrix as follows:
y = [1; 3; 2; 3; 1];
m = length(y);
n = max(y);
Y = zeros(m, n);
Y(sub2ind(size(Y), 1:m, y')) = 1
Y =
1 0 0
0 0 1
0 1 0
0 0 1
1 0 0
The trick here is to know that the corresponding rows of y go from 1 to m one by one.
accumarray([(1:length(y)).' y], 1)
As suggested by Dmitri Bouianov on Coursera discussion forum, this also works:
Y = eye(num_labels)(y, :);
This solution uses elements of y to as indices to select rows from an identity matrix.
In Octave (at least as of 3.6.3, not sure when it was introduced), you can use broadcasting to do this extremely easily. It works like this:
Y = y==1:3
(if y is a row matrix, you need to transpose it first - if you want to have Y transposed instead, use y==(1:3)')