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?
Comments
Post a Comment