2

I'll try to make a basic example of my problem with $n$ being an array of elements, ex. $\{1,2,2,3,3,3\}$:

If i have a sum which needs a computed value i would like to compute it beforehand and store it in a variable (ex. $k$). When calculating the sum, $k$ is not $i_{max}$ but $\{i_1,i_2,...\}$:

f[{_}] = 2.;
f[n_] := f[n] = (
   k = Union[Select[n, # > 1 &]];
   f[Drop[n, 1]]
     + If[k == {}, 0., 
        Sum[Count[n, i]
         *f[Join[DeleteCases[n, i, 1, 1], i - 1]], {i, k}]])

f[{1, 2, 2, 3, 3, 3}]
Out=1368.

But this output is not what i intended to generate and i assume it's because a recursive step is computed every time it is encountered, overwriting $k$ every time.

The correct computation would be:

g[{_}] = 2.;
g[n_] := g[n] = (
   g[Drop[n, 1]]
     + If[Union[Select[n, # > 1 &]] == {}, 0., 
        Sum[Count[n, i]
         *g[Join[DeleteCases[n, i, 1, 1], i - 1]], {i, Union[Select[n, # > 1 &]]}]])

g[{1, 2, 2, 3, 3, 3}]
Out=2640.

The computation of the function $f$ is however much faster then $g$, so i'm wondering if it's possible to first gather all recursions needed before computing them, so computing $k$ once in each recursion would be enough.

Edit: I decided to upload my original code as it is not too complex. The goal is to compute a theoretical distribution for Runs-up-and-down:

edit[r_, del_, add_] := edit[r, del, add] = 
  If[Min[Count[r, #1] - #2 & @@@ Tally[del]] < 0, {}, 
    Sort[Join[Fold[DeleteCases[##, 1, 1] &, r, del], add]]]

h[{}] = 0.;
h[{_}] = 2.;
h[r_] := h[r] = (
   2*h[edit[r, {1}, {}]]
    + If[Union[Select[r, # > 1 &]] == {}, 0., 
     Sum[(Count[r, i - 1] + 1)*h[edit[r, {i}, {i - 1}]], {i, 
       Union[Select[r, # > 1 &]]}]]
    + Sum[(Count[r, i + j] + 1)*h[edit[r, {1, i, j}, {i + j}]], {i, 
      Union[r]}, {j, Union[r]}])

n = 31; 
dist = Flatten[
List /@ Plus @@@ 
  Map[h, GatherBy[Sort /@ IntegerPartitions[n - 1], 
    Length], {2}]]/n! // AbsoluteTiming

The computation takes about 25 seconds on my (slow) Notebook. By storing Union[Select[r, # > 1 &]] and Union[r] into variables, the computation only took 17 seconds but delivered wrong results.

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
kon
  • 263
  • 1
  • 6

1 Answers1

2

Use With to replace only explicit appearances of k in the right-hand-side, preventing the changing values of k from contaminating the stack.

f[{_}] = 2.;

f[n_] := f[n] =
  With[
   {k = Union[Select[n, # > 1 &]]},
   f[Drop[n, 1]] + 
    If[k == {}, 0., Sum[Count[n, i]*f[Join[DeleteCases[n, i, 1, 1], i - 1]], {i, k}]]
  ]

f[{1, 2, 2, 3, 3, 3}]
2640.
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • I tried using with but the computation speed seems similar in my original code. As an example it took about 17 seconds by changing the code to something like my (wrong) function f, about 25 seconds with function g and about 24 seconds using with. Maybe i should post my original code as it isn't too complicated. – kon Mar 25 '15 at 11:58
  • @kon I'll take a look at it. – Mr.Wizard Mar 25 '15 at 13:30
  • @kon It would appear that the vast majority of the time is spent on edit, so optimizing h is unlikely to be of much help unless it can be made to call edit less. Since you got the wrong output I suggest that the apparent improvement you saw was not due to greater efficiency but simply fewer calls to edit. I shall continue to play with this but I shall focus on edit. – Mr.Wizard Mar 25 '15 at 13:45
  • the edit function is a result of the help i got here – kon Mar 25 '15 at 13:49
  • @kon Unless I misread it that question appears to be a duplicate. There are faster ways to approach this. I'll get back to you after some moderator custodial work. – Mr.Wizard Mar 25 '15 at 13:53
  • @kon It does indeed seem to be a duplicate as written so I closed it as such. See the link inserted at the top for several methods that should be faster than what you were using. The complication of returning {0} on a malformed removal will take some additional thought but since it was added as an afterthought in a comment I feel the [duplicate] is appropriate. – Mr.Wizard Mar 25 '15 at 13:58
  • @kon I have been attempting to adapt Leonid's unsortedComplement to handle the malformed removal without losing speed but I haven't achieved it yet. Incidentally are you using Mathematica 10? – Mr.Wizard Mar 25 '15 at 14:20
  • i'm using Mathematica 8.0 (why does @ Mr.Wizard not work?) – kon Mar 25 '15 at 14:25
  • @kon the author of the post under which a comment is made is automatically notified, therefore using the @ notification for that person is redundant and the system automatically removes it. I'll try to return to this problem later but I've got other things to work on now. – Mr.Wizard Mar 25 '15 at 15:03