gsardarian
gsardarian

Reputation: 53

Create matrix of row-wise increasing differences based on vector

I have a column vector in MATLAB and am trying to construct a matrix of differences with row-wise varying size of difference.

It is hard to explain in words, so I will illustrate with an example:

lets say my data is:

data = [ 1 2 3 4 5 6 ];

what i am trying to do, is make a matrix that takes the differences as such (each column difference size changes [increasing by one]):

diff = 
[(2 - 1) ...
 (3 - 2) (3 - 1) ...
 (4 - 3) (4 - 2) (4 - 1) ...
 (5 - 4) (5 - 3) (5 - 2) (5 - 1) ...
 (6 - 5) (6 - 4) (6 - 3) (6- 2) (6 - 1)]

My best guess of doing this was to make a triangle matrix with nested loops. My MATLAB code looks like this:

differences = zeros(length(data) - 1, length(data) - 1);
step = 0;  

for j = 1:1:size(data) - 1; 
    for i = 1:size(logquarterly) - 1 - step;

        if j <= i;
        differences(i,j) = data(i + 1 + step , 1) - data(i,1);
        step = step + 1;
        end

    end
end

What I am trying to do is calculate the first column of differences with distance 1, then calculate the second column of differences with distance 2 and so on... To accommodate the necessary row values I need, I am using the "step" variable which is set to zero for calculating column one, I then want it to increase by 1 when calculating column 2 to have the correct dimensions. But I can not make it work. If I take the "step" out and use this:

differences = zeros(length(data) - 1, length(data) - 1);


for j = 1:1:size(data) - 1; 
    for i = 1:size(logquarterly) - 1;

        if j <= i;
        differences(i,j) = data(i + 1 , 1) - data(i,1);
        end

    end
end

everything works, but each column has the same distance of differences and it does not increase by one. Any ideas guys?

Upvotes: 3

Views: 407

Answers (2)

knedlsepp
knedlsepp

Reputation: 6084

The problem with your solution is that it will only work with column vectors, because of the loop j = 1:1:size(data)-1. The call of size will return [1,6]; then the -1 is applied yielding [0,5]. Then only the first value of this vector is taken and in turn the for loop will only run from 1 to 1-1==0, i.e. NOT. Use numel or size(.,1)/size(.,2) instead. (Also don't use semicola ; after the loop initialization). (Try out the MATLAB debugger!)

Here is my take on how to repair your approach:

differences = zeros(length(data)-1, length(data)-1);
for j = 1:size(differences,2) 
    for i = j:size(differences,1)
        differences(i,j) = data(i+1) - data(i-j+1);
    end
end

I like the use of gallery('circul',n:-1:1), in thewaywewalk's answer, I do however find the rest a bit too complicated.

Here is my take reusing his idea:

n = numel(data);
L = ndgrid(2:n,2:n);           % // Generate indices for Left side of operator
R = gallery('circul',1:n-1).'; %'// Generate indices for Right side of operator
out = tril(data(L) - data(R))  % // Do subtraction of corresponding indices

Upvotes: 1

Robert Seifert
Robert Seifert

Reputation: 25232

If I understand right, you want to do that:

data = [ 1 2 3 4 5 6 ];
n = numel(data);

%// calculate differences
diffs = bsxfun(@minus, data(end:-1:1), data(end:-1:1).')  

%'
%// get linear indices from circulant sub-indices for rows and 
%// linear indices for columns
idx = sub2ind([n n], gallery('circul',n:-1:1), ndgrid(1:n,1:n))

%// mask output and get lower triangular matrix
output = tril(diffs(idx(n-1:-1:1,n-1:-1:1)))

so the output is:

output =

     1     0     0     0     0
     1     2     0     0     0
     1     2     3     0     0
     1     2     3     4     0
     1     2     3     4     5

Upvotes: 4

Related Questions