1
$\begingroup$

I wrote two versions of this code which have similar performances. I'd like to know if it is possible to further optimize this code:

g = 0.01;
alfa[n_, t_] := g*t*Sqrt[n + 1];
beta[n_, t_, pe_] :=pe*Cos[alfa[n, t]]^2 + (1 - pe)*Cos[alfa[n - 1, t]]^2;

vettore3[t_, pe_, N_] := 
Module[{pg, vec0, vec1, alfan, betan, sinalfan1, sinalfan2, cosalfan},
pg = 1 - pe;
alfan = Prepend[ParallelTable[alfa[n, t], {n, 0, N}], 0];
sinalfan1 = Drop[Sin[alfan]^2, 1];
sinalfan2 = Drop[Sin[alfan]^2, -1];
cosalfan = Cos[alfan]^2;
betan = pe*Drop[cosalfan, 1] + (1 - pe)*Drop[cosalfan, -1];
vec0 = Prepend[ConstantArray[0, N],1];
Monitor[For[i = 0, i < N, i++,
vec1 = betan*vec0 + Prepend[Drop[pe*sinalfan1*vec0, -1], 0] + 
Drop[Append[pg*sinalfan2*vec0, 0], 1];
vec0 = vec1;], Framed[i]]; Return[vec1]]

vettore4[t_, pe_, N_] := 
Module[{pg, vec, alfan, betan, sinalfan1, sinalfan2, cosalfan},
$RecursionLimit = Infinity;
pg = 1 - pe;
alfan = Prepend[ParallelTable[alfa[n, t], {n, 0, N}], 0];
sinalfan1 = Drop[Sin[alfan]^2, 1];
sinalfan2 = Drop[Sin[alfan]^2, -1];
cosalfan = Cos[alfan]^2;
betan = pe*Drop[cosalfan, 1] + (1 - pe)*Drop[cosalfan, -1];
vec[0] = Prepend[ConstantArray[0, N], 1];
Monitor[vec[n_] := vec[n] = betan*vec[n - 1]+
Prepend[Drop[pe*sinalfan1*vec[n - 1], -1], 0] + 
Drop[Append[pg*sinalfan2*vec[n - 1], 0], 1], n];
Return[vec[N]]]

Both vettore3 and vettore4 perform in a similar way. Thanks for the help!

$\endgroup$
  • 3
    $\begingroup$ It would help a lot I you could describe what the code does. Also, without a few example test cases are necessary to give relevant suggestions. $\endgroup$ – Lukas Lang Aug 20 '18 at 16:40
  • $\begingroup$ I wrould recommend avoiding reshaping arrays and instead of recursion and for loops try using built in vector operation. $\endgroup$ – Johu Aug 20 '18 at 16:41
5
$\begingroup$
  • Avoid recursion. It is slow in Mathematica. Better use Do or Fold.

In particular, it is not meaningful to use the memoization construnction for vec in vettore4: For computing vec[n] you need only to now vec[n-1] and afterwards, you can forget entirely about vec[n-1] afterwards. So, this memoization may need much more memory than needed to solve the problem; allocation and deallocation of memory -- even if done automatically by Mathematica -- needs is time.

  • Avoid Monitor. It slows down execution.

  • N is a built-in symbol. Just don't use it as variable.

  • Use packed arrays as much a possible. In particular, make sure that all entries of an array are floating point numbers if in the end the array will contain at least one floating point number.

  • Use vectorization of arithmetic operations as much as possible.

  • Use operations that change the size of an array (e.g. Append and Drop etc.) as few as possible.

  • Safe a lot of scalar-vector multiplications by precomputing quantities that can be reused (e.g. pesinalfan and pgsinalfan below).

Here is a version of vettore3a that is faster by a factor of 20.

vettore3a[t_, pe_, nn_] := 
 Module[{pg, vec0, vec1, alfan, betan, cosalfan, pesinalfan, pgsinalfan},
  pg = 1. - pe;
  alfan = alfa[Range[-1., nn], N[t]];
  cosalfan = Cos[alfan]^2;
  With[{sinalfan = Subtract[1., cosalfan[[2 ;; -2]]]},
   pesinalfan = pe sinalfan;
   pgsinalfan = pg sinalfan;
   ];
  betan = pe Rest[cosalfan] + (1. - pe) Most[cosalfan];
  vec0 = ConstantArray[0., nn + 1];
  vec0[[1]] = 1.;
  Do[
   vec1 = betan vec0;
   vec1[[2 ;;]] += pesinalfan vec0[[;; -2]];
   vec1[[;; -2]] += pgsinalfan vec0[[2 ;;]];
   vec0 = vec1;
   , {nn}];
  vec0
  ]
| improve this answer | |
$\endgroup$
  • $\begingroup$ Thank you very much! $\endgroup$ – Knomes Aug 21 '18 at 8:09
  • $\begingroup$ You're welcome. $\endgroup$ – Henrik Schumacher Aug 21 '18 at 8:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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