yonzmeer
yonzmeer

Reputation: 362

Create a "pyramid" matrix

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.

Upvotes: 13

Views: 2628

Answers (3)

Luis Mendo
Luis Mendo

Reputation: 112769

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

Upvotes: 5

Divakar
Divakar

Reputation: 221754

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

Upvotes: 8

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.

Upvotes: 9

Related Questions