0
$\begingroup$

I was trying to execute the following code:

form[n_, m_, r_] := (
   {large, small} = Sort[{n, m}, Greater]; diff = Abs[large - small];
   output = 
    Exp[-r^2/4]*Sqrt[Factorial[small]/Factorial[large]]*(r/Sqrt[2])^
     diff*LaguerreL[small, diff, r^2/2];
   Return[output];
   );
num = 50;
fnm[r_] := Table[form[n, m, r], {n, 0, num}, {m, 0, num}];
list = Table[Random[Complex], {i, 0, num}, {j, 0, num}];
table1[r_] := 
  Table[Conjugate[list[[n1, m1]]]*fnm[r][[n1, m1]]*
    list[[n2, (n2 - n1) + m1]]*fnm[r][[n2, (n2 - n1) + m1]], {n1, 1, 
    num + 1}, {m1, 1, num + 1}, {n2, Max[n1 - m1 + 1, 1], 
    Min[num + 1, n1 - m1 + num + 1]}];
sum[r_] := Total[Flatten[table1[r]]];
result = NIntegrate[sum[r], {r, 0, ∞}];

This code is extremely slow in constructing table1[r], and it takes more than two seconds to construct each element in table1[r]. However, if I remove the function definition, and simply use

form[n_, m_, r_] := (
   {large, small} = Sort[{n, m}, Greater]; diff = Abs[large - small];
   output = 
    Exp[-r^2/4]*Sqrt[Factorial[small]/Factorial[large]]*(r/Sqrt[2])^
     diff*LaguerreL[small, diff, r^2/2];
   Return[output];
   );
num = 50;
fnm = Table[form[n, m, r], {n, 0, num}, {m, 0, num}];
list = Table[Random[Complex], {i, 0, num}, {j, 0, num}];
table1 = 
  Table[Conjugate[list[[n1, m1]]]*fnm[[n1, m1]]*
    list[[n2, (n2 - n1) + m1]]*fnm[[n2, (n2 - n1) + m1]], {n1, 1, 
    num + 1}, {m1, 1, num + 1}, {n2, Max[n1 - m1 + 1, 1], 
    Min[num + 1, n1 - m1 + num + 1]}];
sum = Total[Flatten[table1]];
result = NIntegrate[sum, {r, 0, ∞}];

the table1 variable is constructed almost instantly. So my question is:

  1. Why is there such a big difference by removing the functional definition?
  2. In general when should one use the functional definition, when should not?

By the way, I was trying to redefine fnm[r_] as fnm[r_?NumberQ], but in this case the table of fnm was not even generated, because of the NumberQ constraint. Did I use NumberQ incorrectly?

$\endgroup$
  • $\begingroup$ Changing output = Exp[-r^2/4]* Sqrt[Factorial[small]/ Factorial[large]]* (r/Sqrt[2])^diff* LaguerreL[small, diff, r^2/2]; Return[output]; to just output = Exp[-r^2/4]* Sqrt[Factorial[small]/ Factorial[large]]* (r/Sqrt[2])^diff* LaguerreL[small, diff, r^2/2] without a trailing ; would probably be better. Return has a history of odd behavior and is often not needed. $\endgroup$ – Bill Jan 18 '16 at 6:48
4
$\begingroup$

(1) The time difference comes from the way fnm is evaluated differently. In the first code block, you evaluate fnm at every step in the Table in table1, and then you take parts of it, but you only need to evaluate it once as it does not depend on any of the iteration variables n1,m1,n2. This is what you do in the second code block: you calculate the fnm table once, and then you just access it in the table1 Table. A way to do this while keeping the := definitions is

fnm[r_] := Table[form[n, m, r], {n, 0, num}, {m, 0, num}];
table1[r_] := With[{fnmr = fnm[r]}, body]

but I would just do what you did in the second code block.

The second question is too broad to be answerable IMO... But at least you can learn from this that you should think about what you actually need to calculate at each step in your code; if an expression doesn't depend on the iterators of some loop/table, just calculate the expression outside the loop/table!

$\endgroup$
  • $\begingroup$ Thanks for the answer. Very helpful! So basically in the first example I was constructing the table fnm each time but only take one element from it. This is indeed too much a waste:) $\endgroup$ – Xiao Jan 18 '16 at 8:36

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.