Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I would like to be able to get the current iteration count, the one that if exceeds $IterationLimit makes the evaluation stop.

After not finding a magical variable that stores this value, or a magical built-in that retrieves it, I thought about TraceScan.

According to the documentation of $IterationLimit,

$IterationLimit gives an upper limit on the length of any list that can be generated by Trace

However, a quick test shows that this is not so simple. Let's define

ClearAll[f]
f[i_] := f[i - 1]
f[0] := "Yeah"

Now,

Block[{$IterationLimit = 20},
 Trace[f[18]] // Length//Print;
 Trace[f[18], TraceDepth -> 1] // Length//Print;
 f[18]
 ]

prints 56 and 38 respectively, while f[18]'s evaluation finishes successfully.

Looking at the output of the last trace, we see that the before and after argument evaluation are being traced. So,

Trace[f[3], TraceDepth -> 1]   
(* {f[3],f[3-1],f[2],f[2-1],f[1],f[1-1],f[0],Yeah} *)

Notice that the "two outputs per iteration" rule doesn't hold if we add a definition like f[3]=f[1], in which case

Trace[f[5], TraceDepth -> 1]
(* {f[5],f[5-1],f[4],f[4-1],f[3],f[1],f[1-1],f[0],Yeah} *)

If this happened, a hacky workround could exist along the lines of

SetAttributes[trackIterations, HoldFirst];
trackIterations[code_] := Block[{iterationCounter = 0},
  TraceScan[iterationCounter += 1/2, code, TraceDepth -> 1]
  ]

Question

How can I get that counter, or alternatively, how can I make Trace only trace once each iteration?

share|improve this question
    
I wanted to be the one to answer this but I'm stumped. –  Mr.Wizard Jan 25 '13 at 0:39
1  
Take a look at verbeia.com/mathematica/tips/HTMLLinks/Tricks_Misc_3.html. He says "I don't discuss how counting iterarions and recursions fit into the evaluation process because I have never seen an explanation of when that happens." –  belisarius Jan 25 '13 at 0:44
1  
@belisarius (She says...) verbeia.com/mathematica/bios.html –  Daniel Lichtblau Jan 25 '13 at 1:13
    
@DanielLichtblau I thought it was Ted's –  belisarius Jan 25 '13 at 1:18
    
@belisarius Sorry, you are probably correct. I thought you were referring to Verbeia and did not check to see specifically who wrote what. –  Daniel Lichtblau Jan 25 '13 at 1:23
show 2 more comments

1 Answer 1

I'm not sure whether you can generalize this or how stable this approach is, but it seems if you use Trace to look how often the exactly the form f is evaluated then that does the trick.

ClearAll[f]
f[i_] := f[i - 1]
f[0] := "Yeah"

Block[{$IterationLimit = 20},
 Cases[Trace[f[100], f, TraceOriginal -> True], HoldForm[f], Infinity] // Length // Print;
 f[100]]

The idea behind this is as follows: I was reading Rojos question and inspecting the trace of depth 1

(* {f[5],f[5-1],f[4],f[4-1],f[3],f[3-1],f[2],f[2-1],f[1],f[1-1],f[0],Yeah} *)

The problem was that although f was called fewer times, every evaluation step is shown and the length of the above list cannot be used. Therefore, I though about a way to count how often the Head of the expression, i.e. the symbol f itself was evaluated. Usually, the evaluation of the Head is not shown, since its form does not change.

This can be turned on using TraceOriginal

Trace[f[3],f,TraceOriginal->True]
(* {f[3],{f},f[3],f[3-1],{f},f[2],f[2-1],{f},f[1],f[1-1],{f},f[0],Yeah} *)

Now we can count each single instance of f which occurs in the output. In my first example I used Cases because I was just adapting Rojos examples with its //Length//Print. Of course, and as suggested by Mr.Wizard Count is the better alternative here

Block[{$IterationLimit = 20}, 
 Count[Trace[f[100], f, TraceOriginal -> True], {HoldForm[f]}]
]

While I was writing this, another idea came to my mind. When the problem is, that the head does not change and it therefore does not appear in the usual output, why not fixing this? Therefore, here an alternative approach which adjusts the function to be evaluated and makes a use of options to Trace unnecessary:

ClearAll[f, g]
g = f;
f[i_] := g[i - 1]
f[0] := "Yeah"

Block[{$IterationLimit = 25},
 Count[Flatten[Trace[g[100]]], HoldForm[g]]
]
share|improve this answer
    
Interesting. I suggest you change Cases to Count for brevity. Also, do you need Infinity or would scanning at level 1 be sufficient? –  Mr.Wizard Mar 18 '13 at 6:01
    
@Mr.Wizard likely the Infinity is required otherwise it won't scan deep enough. –  rcollyer Mar 18 '13 at 13:49
    
NiiiiIIiIIiiIIIiiiiice. A ThreadDepth->2 might help it be more efficient –  Rojo Mar 18 '13 at 19:58
    
@Mr.Wizard I explained that Count is better now. I just wanted to wait, whether it helps Rojo at all. You might be interested in the last part I added. –  halirutan Mar 18 '13 at 21:21
    
I can't think of a way to generalize the last approach, I prefer the first :) –  Rojo Mar 18 '13 at 22:53
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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