# How to take matrix elements as input to another matrix or loop?

Say I have matrix tmp1 of size 1000 x 5 (shown is just a small section for illustration purpose), consisting of real numbers and 0:

How can I iteratively take every non-zero real number elements and use it as input for another 'For' loop argument limit to calculate another set of matrix values? For example, taking second row, first column value of 4.956 I would like to use it to calculate a 'For' loop like

r=0.4;

For[i = 0, i < 4.956, i = i + 0.2,

calculate P = Exp[-r i]*i

P += P

And place this cumulated P result into tmp2 output matrix at same corresponding location as where 4.956 was taken from. Then repeat for the next non-zero element of tmp1, so for row 2, column 2 value of 1.234:

For[i = 0, i < 1.234, i = i + 0.2,

calculate P = Exp[-r i]*i

P += P

and result into tmp2 location row 2, column 2. Any zero elements found in tmp1 will simply be mapped to tmp2 of same location. Thanks.

-
Did you consider the answers from this question mathematica.stackexchange.com/questions/14262/…? –  image_doctor Nov 14 '12 at 8:00
@sebastian.cheung could you please consider accepting answers? –  chris Nov 14 '12 at 20:01
Hi @chris how do you accept answers? Sorry a bit new to this. –  sebastian c. Nov 15 '12 at 0:05
For any question you ask, below the voting arrows is a checkmark. If you find an answer the most useful of the one's you received, click on the check mark. It then turns green, like on this answer to one of your questions. Note, your selection is not set in stone, if another answer comes along that is better, you can change it. –  rcollyer Nov 15 '12 at 3:37

You could use a bit of functional programming. Here I'm fixing r to be 3 for readability.

With[{r = 3},
Map[(#.Exp[-r*#]) &[Range[0, #, .2]] &, tmp1, {2}]
]

(*{{0., 0., 0.}, {0.539181, 0.484569, 0.534811}, {0.484569, 0.,
0.539174}, {0., 0., 0.484569}}*)


This is likely quite a bit faster than anything you are going to get with For loops unless you use Compile. Here's a benchmark.

tmp = RandomChoice[{0, 1}, {10^5, 10}]*RandomReal[{0, 5}, {10^5, 10}];

With[{r = 3},
Map[(#.Exp[-r*#]) &[Range[0, #, .2]] &,
tmp, {2}]]; // AbsoluteTiming

(*{1.160002, Null}*)


Edit:

In response to the comments. Here is one way to do this using ReplaceAll. Note that it is about 10 times slower than using Map.

With[{r = 3},
SetAttributes[fn, Listable];
fn[m_] := (#.Exp[-r*#]) &[Range[0, m, .2]];
tmp /. m_ :> fn[m]
]; // AbsoluteTiming

(*{10.6900150, Null}*)


Finally, if you really want a more procedural approach you can use Compile with loops. I've pulled out all the stops here to make it fast. If you have a C compiler installed you could additionally try setting the CompilationTarget to "C".

f = Compile[{{r, _Real}, {tmp, _Real, 2}},
Block[{g, rng, u, v, out = InternalBag[], res},
{v, u} = Dimensions[tmp];
Do[
rng = Range[0., CompileGetElement[tmp, i, j], .2];
res = rng.Exp[-r*rng];
InternalStuffBag[out, res]
, {i, v}, {j, u}
];
Partition[InternalBagPart[out, All], u]
], RuntimeOptions -> "Speed"];


Note that this didn't make things much faster and the functional approach is in my opinion much cleaner.

f[3., tmp]; // AbsoluteTiming

(*{0.9984018, Null}*)

-
Hi @Andy Ross, the last {2} is the levelspec? Not sure how that affects the results? –  sebastian c. Nov 14 '12 at 15:23
Thank @Andy Ross works well, not sure if I want to use Replacement rule instead of Map when working with large data set later. –  sebastian c. Nov 14 '12 at 16:07
Yes, the {2} is the levelspec. I recommend using Map[f, Array[Subscript[x, ##] &, {5, 5}], lspec] with different lspecs to see what this does. –  Andy Ross Nov 14 '12 at 17:42
Hi @Andy Ross, so how to modify your solution to use Replacement instead of Map? Performance seems faster using it as image_doctor pointed out. :) –  sebastian c. Nov 15 '12 at 0:14

Here are 3 approaches to appling a function to a 2D list ( matrix ) of scalar values.

myFunc[x_] := x^2

matrix = RandomInteger[Range@2, {4, 5}];


Listable Function Attribute

SetAttributes[myFunc, Listable]

myFunc@matrix


Map

As Andy Ross has illustrated you can use Map.

Map[myFunc, matrix, {2}]


Replacement Rule(s)

Clear@m
matrix /. m_ -> myFunc[m]


Speed

Define a larger matrix of 10^7 elements, apply the function and measure the AbsoluteTiming.

matrix = RandomInteger[Range@2, {1000, 10000}];
Grid[{{"Map", "Listable", "Replacement"},
{ Map[myFunc, matrix, {2}]; // AbsoluteTiming,
Clear@m; myFunc@matrix; // AbsoluteTiming,
matrix /. m_ -> myFunc[m]; // AbsoluteTiming}
[[All, 1]]
}, Dividers -> All]


-
Hi @image_doctor could you share the code for coding the last part of AbsoluteTiming? Thanks –  sebastian c. Nov 14 '12 at 13:40
@sebastiancheung Yes of course, on re-running it I noticed a small error which changes the results so that Listable and Replacement are now much closer in performance. –  image_doctor Nov 14 '12 at 16:03
Your choice of x^2 for myFunc makes these timings a little misleading. You should try a function that isn't already listable like, for example, myFunc[x_] := Total[Range[x]]. It is worth looking at TracePrint of your Replacement example to see why this matters. –  Andy Ross Nov 14 '12 at 18:01
@AndyRoss Perhaps it makes more sense to call the 3rd option Replacement + Listable. –  image_doctor Nov 14 '12 at 18:11