0
$\begingroup$

I've read through the documentation on tuning and debugging but feel like I am missing some important concepts. Many of the examples given presume the programmer is explicitly generating ranges of values for a symbolic variable. For example, on the Reap documentation page, we have this canonical example:

Reap[Sum[Sow[i^2] + 1, {i, 10}]]

Here, the Sow and Reap functions work together to collect intermediate states of the calculation i*i, where i is set to iterate from 1-10. No problems here, as the variable is a symbol (i) and its iteration bounds are set in the expression.

However, there are other approaches to writing expressions, including recursive definitions where a single value will be passed in to a variable and it may be useful to monitor that variable as it is transformed throughout the recursive calculation.

For example, given a homemade gcd function based on the Euclidean approach:

gcd[x_, y_] := If [Equal[y, 0], x, gcd[y, Mod[x, y]]]

We can trace this function as follows:

Output of Trace

However, that output is a bit verbose and cannot be immediately graphed (as far as I know). I've tried Reap/Sow, Monitor, and others, however, as noted above, the example assume mostly a symbolic variable that is given a range rather than a recursive function with a value passed in. It is not clear to me how to use these tools for the case of a recursive function such as the gcd example above where a value is passed into the function and the desired behaviour is to monitor / accumulate transformations of a function variable.

What would be the correct way to:

  1. Accumulate a list of intermediate values for variable x in gcd[x, y] as this variable is updated through successive recursive calls;
  2. Plot these intermediate values of x to visualise how the function iterates towards a final solution?
$\endgroup$
2
  • $\begingroup$ What's the problem with gcd[x_, y_] := (Sow@x; If[Equal[y, 0], x, gcd[y, Mod[x, y]]]), Reap@gcd[4, 16]? $\endgroup$
    – Lukas Lang
    Commented Jan 1, 2019 at 15:12
  • $\begingroup$ Thanks @LukasLang. I get a syntax error with this statement: Syntax::tsntxi: "gcd[x_,y_]:=(Sow@x;If[Equal[y,0],x,gcd[y,Mod[x,y]]]),Reap@gcd[4,16]" is incomplete; more input is needed. Also, I was not looking to embed the monitoring in the function itself. Rather, I was looking for a way to wrap the function and call specific values to be able to produce a list of intermediate values for x. $\endgroup$ Commented Jan 1, 2019 at 22:04

1 Answer 1

0
$\begingroup$

Here is one approach:

Cases[Trace[gcd[4, 16]], gcd[x_, _] :> x, All]
(* {4, 16, 4} *)

This should work in most simple cases. It extracts the relevant parameters from the calls listed in the output of Trace. For very long traces with a lot of irrelevant stuff, this might not be very efficient however. We can improve this by supplying a filter to Trace:

Cases[Trace[gcd[4, 16], gcd], gcd[x_, _] :> x, All]
(* {4, 16, 4} *)
$\endgroup$
1
  • $\begingroup$ Many thanks, I did not know about the Cases function - this is exactly what I was looking for. Thank you very much. $\endgroup$ Commented Jan 3, 2019 at 12:15

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.