6
$\begingroup$

I'm trying to do some operations to a matrix in a loop, and then I want to graph the results. The results are pair of numbers.

Can I store the results of each iteration on "something" and the use that to graph it? Or can I convert this loop in some kind of function that I an use for instance in

Plot[myfunction, {x, 0, 10}]

For[i = 2, i < 50, i++,
 iM = {{0.3, 0, 0.5, 0.2}, {0, 0.4, 0.3, 0.3}, {0.3, 0.2, 0, 
    0.5}, {0.4, 0.1, 0, 0.5}};
 staDis = {0.300400534045394, 0.12683578104138837, 
   0.18825100133511352, 0.38451268357810403};
 iMP = MatrixPower[iM, i];
 iMPV = iMP[[4]];
 y = Norm[iMPV - staDis, 1]/2;
 Print["i ", i];
 Print["y ",  y ];
 Print[" "];
 ]
$\endgroup$
0

2 Answers 2

14
$\begingroup$

b.gatessucks's answer shows you what to do and is worthy of the accept. However, it does not explain why your previous approach wasn't going to work.

First, a point on efficiency. In your For loop, you were redefining iM and staDis each iteration of the loop, even though the values didn't change. This is unnecessary. Similarly, you didn't really need both iMP and iMPV. You could have saved a little memory by going straight to MatrixPower[im,i][[4]], or even incorporating the next line with the Norm function, much as b.gatessucks did with his answer. In the problem posed in your question, the speedup and memory saving will be trivial, but it is worth bearing these sort of tips in mind as you move on to bigger problems with larger matrices etc.

The reason you weren't getting the desired result out of your loop is that Do, For and other Fortran-style looping constructs in Mathematica do not actually return any values. You have to set up side effects inside the loop, defining other variables as you did in the code in your question. List-based operations, like the Table command b.gatessucks used, directly return a result so you can define a variable name to take that result, as he did in his answer. It is much more direct, and in my view a more transparent style of code.

I'd also note that if you just want to plot the result in a ListPlot or similar, you don't actually need the sequential index as part of the result. In other words, a vector would do, rather than the two-column matrix you seemed to be building up and b.gatessucks used in his answer.

There are many different ways to build up lists from intermediate calculations. For example, the following give the exact same results as the Table version, but use functional programming (Slot # notation).

You can Map the required function to a vector created with Range

result2 = 
 Norm[MatrixPower[iM, #][[4]] - staDis, 1]/2 & /@ Range[2, 50];
ListLogPlot[result2]  

log plot of mapping to a Range

Or you can use Array. Here I've used the little-known third argument to specify a 49-element array where the index starts at 2, not the default of 1.

Array[Norm[MatrixPower[iM, #][[4]] - staDis, 1]/2 &, {49}, {2}]

Which approach you use out of Table, Array and a functional construct like Map depends on the nature of your problem and particularly what you are iterating over. I'd also suggest you have a good look at NestList and FoldList in the documentation. Those functions simplify many operations that programmers familiar with other languages tend to try to use loops for.

$\endgroup$
1
  • $\begingroup$ very well explained! Thanks a lot! $\endgroup$
    – whynot
    Oct 5, 2012 at 22:52
6
$\begingroup$

I think using Table is more convenient in your case :

result = Table[{i, Norm[MatrixPower[iM, i][[4]] - staDis, 1]/2}, {i, 2, 50}]

You can then plot the results in different ways, for instance :

ListLogPlot[result]

plot

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.