4
$\begingroup$
  • A function can be defined with SetDelayed while storing its value with Set, eg:

    f[x_] := f[x] = x
    

    Now, if the function is to have an optional argument with say default value 0,

    f[x_,y_:0] := f[x,y] = x+y
    

    so f[a] equals a and f[a,b] equals a+b.

  • Now we take it one step further and use Options instead of y_:0. So

    Options[g]={option1 -> 0}
    g[x_,OptionsPattern[]] := x + OptionValue[option1]
    

    works similarly to f, so f[x,y] equals g[x, option1->y] and f[x] equals g[x]

  • But now comes the problem: how to use Set to store values of g, just like what was done for f?

    g[x_,OptionsPattern[]] := g[x, OptionsPattern[]] = x + OptionValue[option1]
    

    doesn't work, since it will store the first run of g, say g[a, option1->b] as a+b, but then g[a] will return a+b, as will g[a, option1->c].

It makes sense. So how can this be done?

$\endgroup$
  • $\begingroup$ As you can see it is way more natural to memoize based on arguments rather than options. So why not stick to that? $\endgroup$ – Kuba Apr 24 '17 at 19:19
  • $\begingroup$ I agree. But in this particular case, the goal is to make a larger function that calls other (many) functions, passing some options to those functions, but also allowing optional switches for saving output, etc. I can't store values in intermediate functions, as that would quickly run Mathematica out of memory (the computation takes several hours to run). So the point is to just store the final result in memory. $\endgroup$ – Gaius Apr 24 '17 at 19:41
4
$\begingroup$

I believe the following works as you intend:

Clear[g];
Options[g] = {option1 -> 0};
g[x_, opts : OptionsPattern[]] := 
 g[x, opts] = x + OptionValue[option1]

by assigning the options pattern an explicit name, we can use Set to produce an DownValue of g with that exact option pattern.

$\endgroup$
2
$\begingroup$

I think you can make this work by introducing a function with a different name to do the memoization. To be tidy, I'll limit the scope of the new name gcache

Options[g] = {option1 -> 0};
Module[{gcache},
 g[x_, OptionsPattern[]] := gcache[x, OptionValue[option1]];
 gcache[x_, a_] := gcache[x, a] = (Print["Evaluating"]; x + a)]

We only evaluate on the first call...

g[x, option1 -> b]
(* "Evaluating" *) 
(* b + x *)

...not the second...

g[x, option1 -> b]
(* b + x *)

... and option1 is not cached...

g[a, option1 -> c]
(* "Evaluating" *)
(* a + c *)

g[a, option1 -> c]
(* a + c *)
$\endgroup$
  • $\begingroup$ Ended up accepting the other answer, as that was what I used. But I also benefited from yours. Thank you. $\endgroup$ – Gaius Apr 26 '17 at 15:11

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