13
votes

Say I'm given a symmetric row vector with an odd length where each element is smaller than the next one in the first half of the vector and each element is bigger than the next one in the second half and the middle element is the biggest. (e.g [1 2 3 2 1] or [10 20 50 20 10]).

I want to create a square matrix where this row vector is its middle row and the equivalent column vector (v') is its middle column and each other row or column is a reduced version of the given vector according to the middle element in this row or column. And when there are no more "original elements" we put 0.

Examples:

if v = [1 2 3 2 1] we get

0 0 1 0 0  
0 1 2 1 0  
1 2 3 2 1  
0 1 2 1 0  
0 0 1 0 0

if v = [3 5 3] we get

0 3 0  
3 5 3  
0 3 0  

What I did so far: I managed to create a matrix with v as the middle row and v' as the middle column with this code I wrote:

s = length(vector);
matrix= zeros(s);
matrix(round(s/2),:) = vector;
matrix(:, round(s/2)) = vector';

but got stuck with assigning the other values.

3

3 Answers

9
votes

A more hands-on approach is to produce your matrix as a mosaic, starting from a hankel matrix. For performance comparison, here's a version using the same format as @Divakar's solution:

function out=pyramid_hankel(v)

%I suggest checking v here
%it should be odd in length and a palindrome    

i0=ceil(length(v)/2);
v2=v(i0:end);

Mtmp=hankel(v2);
out=zeros(length(v));
out(i0:end,i0:end)=Mtmp;
out(1:i0-1,i0:end)=flipud(Mtmp(2:end,:));
out(:,1:i0-1)=fliplr(out(:,i0+1:end));
>> pyramid_hankel([1 2 3 2 1])

ans =

     0     0     1     0     0
     0     1     2     1     0
     1     2     3     2     1
     0     1     2     1     0
     0     0     1     0     0

For v=[1 2 3 2 1] the starting block is hankel([3 2 1]), which is

ans =

     3     2     1
     2     1     0
     1     0     0

From here it should be clear what's happening.

8
votes

Here's one approach -

function out = pyramid(v)

hlen = (numel(v)+1)/2;
updown_vec = [1:(numel(v)+1)/2 (numel(v)-1)/2:-1:1];
upper_part = cumsum(bsxfun(@le,(hlen:-1:1)',updown_vec));  %//'
out = [upper_part ; flipud(upper_part(1:end-1,:))];
out = changem(out,v,updown_vec);

Here's another approach, sort of simpler maybe -

function out = pyramid_v2(v)

hlen = (numel(v)+1)/2;
updown_vec = [1:(numel(v)+1)/2 (numel(v)-1)/2:-1:1];
mask = bsxfun(@le,([hlen:-1:1 2:hlen])',updown_vec); %//'
M = double(mask);
M(hlen+1:end,:) = -1;
out = changem(cumsum(M).*mask,v,updown_vec);

Sample runs -

>> v = [1 2 3 2 1];
>> pyramid(v)
ans =
     0     0     1     0     0
     0     1     2     1     0
     1     2     3     2     1
     0     1     2     1     0
     0     0     1     0     0
>> v = [3 5 3];
>> pyramid(v)
ans =
     0     3     0
     3     5     3
     0     3     0

>> v = [99,3,78,55,78,3,99];
>> pyramid(v)
ans =
     0     0     0    99     0     0     0
     0     0    99     3    99     0     0
     0    99     3    78     3    99     0
    99     3    78    55    78     3    99
     0    99     3    78     3    99     0
     0     0    99     3    99     0     0
     0     0     0    99     0     0     0
5
votes

Here's another approach:

v = [1 2 3 2 1]; %// symmetric, odd size
m = (numel(v)-1)/2;
w = [0 v(1:m+1)];
t = abs(-m:m);
result = w(max(m+2-bsxfun(@plus, t, t.'),1));