tags:

views:

179

answers:

5

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
A: 

You can use ones to define the places where you have 1's:

http://www.mathworks.com/access/helpdesk/help/techdoc/ref/ones.html

John at CashCommons
hmm, I don't think that'll work... isn't ones just a function that returns a matrix of all 1's?
Jason S
Right but I think you can set a submatrix of your matrix to that all-1s vector. Might be cleaner than setting 1 explicitly to each element. Anyway YMMV.
John at CashCommons
+1  A: 

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{:});
gnovice
clever! -------
Jason S
+2  A: 

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

catchmeifyoutry
+1: Very clever performing the CUMSUM on the index (as opposed to the final matrix), although for the sake of clarity `idx` should be initialized as `zeros(1,V+1)` to show that it actually ends up that size due to the subsequent line.
gnovice
+3  A: 

You can do this via indexing.

A = eye(3);
B  = A(:,[zeros(1,8)+1, zeros(1,4)+2, zeros(1,5)+3])
Loren
weird... will have to study this one.
Jason S
+1  A: 

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{:});
Jonas
Clever use of BLKDIAG, but you need to use something like `diff([0 v])` instead of `v` in the call to ARRAYFUN.
gnovice
Thanks for spotting this, gnovice. I really should have had a closer look at the question.
Jonas

related questions