# How can I memoize the result of o[i] and at the same time force u to be incremented whenever o[i] is called?

I am working on the following code:

f[1] = Cos[t];
f[2] = Sin[t];
f[3] = 1.2 Cos[1.2 Pi t];
f[4] = 1.2 Sin[1.2 Pi t];
f[5] = 1.7 Cos[1.7 Pi t];
f[6] = 1.7 Sin[1.7 Pi t];
u = 0;
s = 0.1;

o[n_] := (o[n] = Table[{f[2 n - 1], f[2 n]}, {t, 0, 2 Pi, s }]; u++)

o[1];
o[2];
o[3];
u


If I run it, it outputs $$u=3$$ correctly. But if I run it again, it outputs $$u=0$$. What is going on here? I understand that $$u$$ is defined as $$0$$ in the beginning of the code, but shouldn't re-running it increment $$u$$ three times again and $$u$$ should be $$3$$?

How can I force $$u$$ to be incremented when calling o[1] after o[1] has been defined? I know I could use $$\text{Clear["Global*"]}$$ in the beginning of the code, but it would be nice to use the memoization in there too.

• Because the code for o[1], o[2], o[3] is different after memoization. You can check with ? o or Downvalues[o]. Dec 5 '21 at 20:44
• @MichaelE2 Can't I force o[i] it to increment everytime, even when it is declared? I am trying o[n_] := (o[n] = (u++; Table[{f[2 n - 1], f[2 n]}, {t, 0, 2 Pi, s }])) but this is also not working. Dec 5 '21 at 20:53
• Update your question to be how to do that. I think it's ok to change it at this point, since no one has answered (and the answer to the current one is rather simple). How to do it is a more interesting question, anyway. Dec 5 '21 at 20:56
• @MichaelE2 Done. I wasn't too sure about what to ask so I guess this is could come up with. Dec 5 '21 at 20:59
• I thought you would add "How can I memoize the result of o[i] and at the same time force u to be incremented whenever o[i] is called?" (Unless I've misunderstood what your question is.) Dec 5 '21 at 21:02

Introducing a new memoized variable,om, allows it to be done like this

u = 0;
Clear[o, om]
om[n_] := (Pause[1];
om[n] = Table[{f[2 n - 1], f[2 n]}, {t, 0, 2 Pi, s}])
o[n_] := (u++; om[n])

First@*AbsoluteTiming@*o  /@ {1, 2, 1, 2}  (* {1.00142, 1.56995, 3.*10^-6, 2.*10^-6} *)
u  (* 4 *)


The Pause is there only to make the first evaluation expensive. AbsoluteTiming shows the expensive evaluation is performed the first time and the memoized value is returned thereafter. And the counter works.

Memoization, as I understand it (I'm not broadly versed in programming concepts), usually redefines the specific function call to be the computed output value. In Mathematica, we can make any definition we like, including adding side effects to a memoized call:

mem : o[n_] :=
With[{res = Table[{f[2 n - 1], f[2 n]}, {t, 0, 2 Pi, s}]},
mem := ( (* define the memoized actions *)
u++;
(* other code if desired; *)
res); (* return value last *)
mem
];


Notes: mem represents the call, for instance o[1]. We have to use SetDelayed to make the new definition for mem (or o[1] etc.). Also, the side effect u++ should occur on the first call, so the return value of o[n_] comes from calling mem after it has be defined.

Example:

u = 0;
o[1];
o[2];
o[3];
u
(* 3  *)

o[1];
u
(*  4  *)
`