0

I need help for the following simple matrix manipulation.

My inputs are:

A =

    9.8627   14.6475
   65.7510   97.6500
  -48.9131  -72.6431
   65.7510   97.6500


B =

   60.3806   39.3176   39.3176   22.1663   16.1483
         0         0         0         0         0
  123.8806   80.6665   80.6665   45.4778   33.1309
         0         0         0         0         0


C =

  279.2250  275.4000  183.6000  202.7250   84.1500
         0         0         0         0         0
  518.7707  511.6642  341.1095  376.6417  156.3418
         0         0         0         0         0

Then my matlab code:

x_3 = size(A);
x_4 = size(B);


  for m_1 = 1:x_3(1,2);
      for n_1 = 1:x_4(1,2);


         G = A(:,m_1)+ B(:,n_1)+C(:,n_1)

      end
  end

The result for this code:

G =

  349.4682
   65.7510
  593.7382
   65.7510


G =

  324.5802
   65.7510
  543.4176
   65.7510


G =

  232.7803
   65.7510
  372.8629
   65.7510


G =

  234.7540
   65.7510
  373.2064
   65.7510


G =

  110.1610
   65.7510
  140.5597
   65.7510


G =

  354.2531
   97.6500
  570.0081
   97.6500


G =

  329.3651
   97.6500
  519.6875
   97.6500


G =

  237.5651
   97.6500
  349.1328
   97.6500


G =

  239.5388
   97.6500
  349.4763
   97.6500


G =

  114.9458
   97.6500
  116.8296
   97.6500

but my desired output is just one matrix G that has all the ten matrices shown above (as columns). so basically it's gonna look like this:

G =  
     349.4682   324.5802    BLAH...
     65.7510    65.7510     BLAH...
     593.7382   543.3176    BLAH...
     65.7510    65.7510     BLAH...

Please someone help.... :(

I would appreciate it THANKS!

Sebastien C.
  • 4,649
  • 1
  • 21
  • 32

5 Answers5

1

You're overwriting the value of G on each iteration of the loop:

G = A(:,m_1)+ B(:,n_1)+C(:,n_1)

You need to append the newly-calculated rows to the existing rows of G:

G = [G, A(:,m_1)+ B(:,n_1)+C(:,n_1)]
beaker
  • 16,331
  • 3
  • 32
  • 49
1

The following should work (but only for size(B,2)=5 and size(A,2) = 2):

 G = [repmat(A(:,1),1,5) repmat(A(:,2),1,5)]+ repmat(B+C,1,2);

The output is

G =

  Columns 1 through 9 

  349.4683  324.5803  232.7803  234.7540  110.1610  354.2531  329.3651  237.5651  239.5388
   65.7510   65.7510   65.7510   65.7510   65.7510   97.6500   97.6500   97.6500   97.6500
  593.7382  543.4176  372.8629  373.2064  140.5596  570.0082  519.6876  349.1329  349.4764
   65.7510   65.7510   65.7510   65.7510   65.7510   97.6500   97.6500   97.6500   97.6500

  Column 10 

  114.9458
   97.6500
  116.8296
   97.6500

If the order of the columns is not so important a brief general solution is possible:

   nA = size(A,2);
   nB = size(B,2);
   G = repmat(A,1,nB) + repmat(B+C,1,nA);

but then the order of the columns alternates (first A(:,1) then A(:,2) ...):

G =

  Columns 1 through 9 

  349.4683  329.3651  232.7803  239.5388  110.1610  354.2531  324.5803  237.5651  234.7540
   65.7510   97.6500   65.7510   97.6500   65.7510   97.6500   65.7510   97.6500   65.7510
  593.7382  519.6876  372.8629  349.4764  140.5596  570.0082  543.4176  349.1329  373.2064
   65.7510   97.6500   65.7510   97.6500   65.7510   97.6500   65.7510   97.6500   65.7510

  Column 10 

  114.9458
   97.6500
  116.8296
   97.6500

Given the varied answers I took them on a speed test, 10000 iterations on my pokey laptop:

@LuisMendo Elapsed time is 1.906000 seconds.

@TryHard Elapsed time is 1.625000 seconds. (edited!)

@MohsenNosratinia Elapsed time is 3.985000 seconds.

Buck Thorn
  • 5,024
  • 2
  • 17
  • 27
  • 1
    You could turn your more compact solution into the "correct" solution by performing a simple re-arranging of the columns: `index = reshape(1:nA*nB, nA, nB)'; G = G(:, index(:));` . Upvoting for the timing benchmarks! – Floris Aug 04 '13 at 21:36
  • @Floris good lead on the indexing, it turns out the required values are `index = [1 7 3 9 5 6 2 8 4 10]`, that is swap 2 and 7, 4 and 9 etc... – Buck Thorn Aug 04 '13 at 22:05
1

The following code does what you want. Since you didn't specify about sizes, I've made it quite general: A and B can have any number of columns. It is assumed that B and C have the same size, and of course A, B, C need to have the same number of rows.

D = B+C;
numA = size(A,2);
numB = size(B,2);

sol = reshape(repmat(A,numB,1),size(A,1),size(A,2)*numB) + repmat(D,1,numA)
Luis Mendo
  • 110,752
  • 13
  • 76
  • 147
1

You can ask kron function to do all the repetitions for you

G = kron(A, ones(1,size(B,2)))+kron(ones(1,size(A,2)),B+C);
Mohsen Nosratinia
  • 9,844
  • 1
  • 27
  • 52
1

Staying close to your original code (which isn't very efficient, but that's not what you were asking about): you just need to make sure that every loop takes you to a new column in G:

gcol = 0;
for m_1 = 1:x_3(1,2);
  for n_1 = 1:x_4(1,2);

    gcol = gcol + 1;
    G(:, gcol) = A(:,m_1) + B(:,n_1) + C(:,n_1)

  end
end

This puts each successive result in its own column.

It would be preferable to allocate the size of G before you start - that is a good habit and gets more important as the size of matrices grows (it prevents lots of copying of data "to make space for the new size"). For this you would use

G = zeros(x_3(1), x_3(1,2) * x_4(1,2));

before the nested loops.

Note - the advantage of this formulation is that you can see quite clearly what the code is doing. In my experience, 9 times out of 10 "clear code" trumps "efficient but hard to follow" code. Six months from now you would like to remember what your code does. In cases where speed really matters I will often put the "slow but clear" code in a comment, and execute the "fast but obscure" - with a test case to make sure they do in fact produce identical answers. Seems like a hassle, but it is worth the extra time. One day you will thank me...

EDIT another somewhat elegant technique would use bsxfun - as follows:

G = reshape( bsxfun(@add, reshape(A, size(A,1),1,[]), B+C), size(A,1), []);

This works because bsxfun will automatically perform the operation (add) on every dimension where one array has a singleton dimension while the other array has a non-singleton dimension - in effect performing the for loops without needing a for loop. And because no "larger" copy of the array is made, it should be marginally faster. This is probably more noticeable when A and B,C are large arrays - for the current size most of the time will go into the function overhead.

I didn't run a timing benchmark, but usually bsxfun is faster than repmat... See for example https://stackoverflow.com/a/12955706/1967396

Community
  • 1
  • 1
Floris
  • 45,857
  • 6
  • 70
  • 122
  • I fully agree with you that clear code is important, but I think that loops do not necessarily make reading code any clearer, on the contrary I would say in this case. Code using repmat is in my opinion simpler to read, it just takes getting used to the meaning of repmat, which is no more difficult than learning the meaning of indexing into an array. – Buck Thorn Aug 04 '13 at 18:20
  • 2
    @TryHard - use of repmat is clear enough in general, but the `[repmat(A(:,1),1,5) repmat(A(:,2),1,5)]` isn't very readable - and only works because you are hard-coding for A being a `2x5` array. If it wasn't, your code would break immediately - and the fact that the original code is using the size of `A` (rather than the number `2`) suggests that OP wants the solution to be more flexible... at least that's my interpretation. – Floris Aug 04 '13 at 21:07
  • Granted, in that regard Luis Mendo's answer is better, despite being somewhat slower and definitely less readable. With logical indexing or a permutation operation my answer might be amended, but that would nullify my clarity counterargument. – Buck Thorn Aug 04 '13 at 21:19
  • Thanks for the comment, I amended my answer accordingly. – Buck Thorn Aug 04 '13 at 21:25
  • @TryHard: I'd be interested in seeing the timing of my latest solution (bscfun) compared with yours... I don't have access to a Matlab license right now so can't do the test. Can you? Would be good to confirm it actually works... – Floris Aug 04 '13 at 21:30
  • I'd love to but It'll have to wait until I upgrade to a newer version of Matlab :>[ – Buck Thorn Aug 04 '13 at 21:36
  • @TryHard - I see. I will try this tomorrow then and let you know. – Floris Aug 04 '13 at 21:37
  • @Floris, thank you for your help this is very related to what I wanted to achieved!! – Jordan David Aug 04 '13 at 23:40
  • @Floris, One more question.. it works but I am quite confused about the logic of it... for gcol = gcol + 1 then G(:, gcol), isn't this just re-writing the value each run? i.e. when gcol = 0 + 1 = 1 then G(:,1) = blah blah then another loop again which follows the same step so each run will always be gcol = 0 + 1? or does it move like gcol = 0 + 1, gcol = 1+1 .... ? – Jordan David Aug 04 '13 at 23:44
  • 1
    `gcol` is set to zero _before_ the loops - so when you start looping it keeps being incremented ; if you left the semicolon off the end of the statement so the result echoes to the console you would see `1,2,3,4...` in each successive iteration. – Floris Aug 05 '13 at 11:02