Search code examples
matlabfor-loopmatrixvectordimensions

Matlab: arithmetic operation on columns inside a for loop (simple yet devious!)


I'm trying to represent a simple matrix m*n (let's assume it has only one row!) such that m1n1 = m1n1^1, m1n2 = m1n1^2, m1n3 = m1n1^3, m1n3 = m1n1^4, ... m1ni = m1n1^i. In other words, I am trying to iterate over a matrix columns n times to add a new vector(column) at the end such that each of the indices has the same value as the the first vector but raised to the power of its column number n.

This is the original vector:

v =
    1.2421
    2.3348
    0.1326
    2.3470
    6.7389
and this is v after the third iteration:

v = 
    1.2421    1.5429    1.9165
    2.3348    5.4513   12.7277
    0.1326    0.0176    0.0023
    2.3470    5.5084   12.9282
    6.7389   45.4128  306.0329
now given that I'm a total noob in Matlab, I really underestimated the difficulty of such a seemingly easy task, that took my almost a day of debugging and surfing the web to find any clue. Here's what I have come up with:

rows = 5;
columns = 3;
v = x(1:rows,1);
k = v;
Ncol = ones(rows,1);
extraK = ones(rows,1);

disp(v)

for c = 1:columns
    Ncol = k(:,length(k(1,:))).^c; % a verbose way of selecting the last column only.
    extraK = cat(2,extraK,Ncol);
end

k = cat(2,k,extraK);
disp(extraK(:,2:columns+1)) % to cut off the first column

now this code (for some weird reason) work only if rows = 6 or less, and columns = 3 or less.

when rows = 7, this is the output:

v = 1.0e+03 *

0.0012    0.0015    0.0019
0.0023    0.0055    0.0127
0.0001    0.0000    0.0000
0.0023    0.0055    0.0129
0.0067    0.0454    0.3060
0.0037    0.0138    0.0510
0.0119    0.1405    1.6654

How could I get it to run on any number of rows and columns?

Thanks!


Solution

  • I have found a couple of things wrong with your code:

    1. I'm not sure as to why you are defining d = 3;. This is just nitpicking, but you can remove that from your code safely.
    2. You are not doing the power operation properly. Specifically, look at this statement:

      Ncol = k(:,length(k(1,:))).^c; % a verbose way of selecting the last column only.
      

      You are selectively choosing the last column, which is great, but you are not applying the power operation properly. If I understand your statement, you wish to take the original vector, and perform a power operation to the power of n, where n is the current iteration. Therefore, you really just need to do this:

      Ncol = k.^c;
      

      Once you replace Ncol with the above line, the code should now work. I also noticed that you crop out the first column of your result. The reason why you are getting duplicate columns is because your for loop starts from c = 1. Since you have already computed v.^1 = v, you can just start your loop at c = 2. Change your loop starting point to c = 2, and you can get rid of the removal of the first column.


    However, I'm going to do this in an alternative way in one line of code. Before we do this, let's go through the theory of what you're trying to do.

    Given a vector v that is m elements long stored in a m x 1 vector, what you want is to have a matrix of size m x n, where n is the desired number of columns, and for each column starting from left to right, you wish to take v to the nth power.

    Therefore, given your example from your third "iteration", the first column represents v, the second column represents v.^2, and the third column represents v.^3.


    I'm going to introduce you to the power of bsxfun. bsxfun stands for Binary Singleton EXpansion function. What bsxfun does is that if you have two inputs where either or both inputs has a singleton dimension, or if either of both inputs has only one dimension which has value of 1, each input is replicated in their singleton dimensions to match the size of the other input, and then an element-wise operation is applied to these inputs together to produce your output.

    For example, if we had two vectors like so:

    A = [1 2 3]
    
    B = [1
         2
         3]
    

    Note that one of them is a row vector, and the other is a column vector. bsxfun would see that A and B both have singleton dimensions, where A has a singleton dimension being the number of rows being 1, and B having a singleton dimension which is the number of columns being 1. Therefore, we would duplicate B as many columns as there are in A and duplicate A for as many rows as there are in B, and we actually get:

    A = [1 2 3
         1 2 3
         1 2 3]
    
    B = [1 1 1
         2 2 2
         3 3 3]
    

    Once we have these two matrices, you can apply any element wise operations to these matrices to get your output. For example, you could add, subtract, take the power or do an element wise multiplication or division.


    Now, how this scenario applies to your problem is the following. What you are doing is you have a vector v, and you will have a matrix of powers like so:

    M = [1 2 3 ... n
         1 2 3 ... n
         ...........
         ...........
         1 2 3 ... n]
    

    Essentially, we will have a column of 1s, followed by a column of 2s, up to as many columns as you want n. We would apply bsxfun on the vector v which is a column vector, and another vector that is only a single row of values from 1 up to n. You would apply the power operation to achieve your result. Therefore, you can conveniently calculate your output by doing:

    columns = 3;
    out = bsxfun(@power, v, 1:columns);
    

    Let's try a few examples given your vector v:

    >> v = [1.2421; 2.3348; 0.1326; 2.3470; 6.7389];
    >> columns = 3;
    >> out = bsxfun(@power, v, 1:columns)
    
    out =
    
        1.2421    1.5428    1.9163
        2.3348    5.4513   12.7277
        0.1326    0.0176    0.0023
        2.3470    5.5084   12.9282
        6.7389   45.4128  306.0321
    
    >> columns = 7;
    >> format bank
    >> out = bsxfun(@power, v, 1:columns)
    
    out =
    
      Columns 1 through 5
    
              1.24          1.54          1.92          2.38          2.96
              2.33          5.45         12.73         29.72         69.38
              0.13          0.02          0.00          0.00          0.00
              2.35          5.51         12.93         30.34         71.21
              6.74         45.41        306.03       2062.32      13897.77
    
      Columns 6 through 7
    
              3.67          4.56
            161.99        378.22
              0.00          0.00
            167.14        392.28
          93655.67     631136.19
    

    Note that for setting the columns to 3, we get what we see in your post. For pushing the columns up to 7, I had to change the way the numbers were presented so you can see the numbers clearly. Not doing this would put this into exponential form, and there were a lot of zeroes that followed the significant digits.


    Good luck!