5

I have come up with the following functions, and I need to calculate a value, in order to have a condition valid. In my problem, all data are given, and I need to calculate variable l. I am using findroot, and I give an initial value of 25 (plausible assumption) in order to get what I need. Although my calculation is correct, it is really time consuming (I am using an i7 -3720 qm) and it takes almost 8-9 seconds. My question is, how can I speed up evaluation speed.

f1[x_, y_] := 
  PDF[NormalDistribution[l, 3.975], x]*
   PDF[NormalDistribution[53.559 - l, 3.975], y];
p = (1 - Sum[f1[i, i], {i, 0, 50}])/(1 - 
     Sum[f1[i, i], {i, 0, 50}]*1.4317884120211488); 



f2[x_, y_] := If[x == y, f1[x, y]*1.4317884120211488`,
   f1[x, y]/p];

A = SessionTime[];
sexpNEW = 
 FindRoot[Sum[f2[i, j], {i, 0, 50}, {j, 0, i - 6.5}] == 
   0.4605263157894738, {l, 25}]
B = SessionTime[];

My results:

{l->29.8104}

{ speed:,8.6508650,seconds}

consider the following example, which is based on my previous, but this time some variables are unknown, lets call them u1, u2, u3

f1[x_,y_]:=PDF[NormalDistribution[u1,2.1],x]*PDF[NormalDistribution[u2,2.05],y];

p=(1-Sum[f1[i,i],{i,0,20}])/(1-Sum[f1[i,i],{i,0,50}]*u3);

f2[x_,y_]:=If[x==y,f1[x,y]*u3,f1[x,y]/p];

   limit1=20.5;



 FindRoot[
  Sum[f2[i, j], {i, 0, limit1}, {j, 0, limit1 - i}] == 
    0.4285714285714286`
   && Sum[f2[i, j], {i, 1, 20}, {j, 0, i - 1}] == 0.47417677642980943`
   && Sum[f2[i, j], {j, 1, 20}, {i, 0, j - 1}] == 
    0.2558058925476603`, {u1, 12}, {u2, 12}, {u3, 
   1}] // AbsoluteTiming

{8.18311, {u1 -> 11.0489, u2 -> 10.0626, u3 -> 2.10168}}

How would I use compile as you did @xzczd, in order to use findroot for a 3*3 system?


edit: (26/2/2016)

I am studying compile and I have a question regarding its applications. Could I use it in recursive functions too? I am using memoization, but even though I gain in speed, I was thinking that compile could improve my speeds further. My question is, how could I define the following function with compile? I tried to do so, but when I call my function, it keeps running forever.

This is my original function

f[t_, d_] := 
 f[t, d] = 
  If[t > 80, 0, 
   If[d == A && t == B, 1, 
    p7h*f[t + 1, d - 7] + p5h*f[t + 1, d - 5] + 
     p3h*f[t + 1, d - 3] + p7a*f[t + 1, d + 7] + 
     p5a*f[t + 1, d + 5] + p3a*f[t + 1, d + 3] + 
     pns*f[t + 1, d]]]

and this is how i tried to rewrite it using Compile

fC=
 Compile[{t, d},
  If[t > 80, 0,
   If[d == A && t == B, 1, 
    p7h*fC[t + 1, d - 7] + p5h*fC[t + 1, d - 5] + 
     p3h*fC[t + 1, d - 3] + p7a*fC[t + 1, d + 7] + 
     p5a*fC[t + 1, d + 5] + p3a*fC[t + 1, d + 3] + 
     pns*fC[t + 1, d]]]
  ]

t,d are intenger variables, and so are A and B. Thank you in advance.

Fierce82
  • 543
  • 1
  • 4
  • 14
  • Your last edit should be asked as a new question instead of being appended to this question, since it seems to be an entirely different issue. – J. M.'s missing motivation Feb 26 '16 at 14:16
  • sorry, I was thinking that it was relevant due to compile and speed gain. – Fierce82 Feb 26 '16 at 14:32
  • While it's better to post your last edit as a new question, I'm afraid the answer will disappoint you. Check these posts: http://mathematica.stackexchange.com/q/78768/1871 http://mathematica.stackexchange.com/q/31171/1871 http://mathematica.stackexchange.com/q/55206/1871 – xzczd Feb 26 '16 at 15:28
  • Anybody know why FullSimplify[f1[x, y]] (the first f1 ) gives zero? – george2079 Feb 29 '16 at 21:22
  • @george2079 That's …very interesting! You should post this as a separate question! – xzczd Mar 01 '16 at 02:36
  • Could we apply this method to this case to increase performance?http://blog.wolfram.com/2013/07/09/using-mathematica-to-simulate-and-visualize-fluid-flow-in-a-box/comment-page-1/#comment-120213 Looks like it super slow because it is not precompile... It takes more than 110s to run a 20x20 inversion... – Carmoufle Feb 29 '16 at 18:26
  • see here re: the FullSimplify issue http://mathematica.stackexchange.com/q/82765/2079 – george2079 Mar 01 '16 at 16:04

1 Answers1

12

You need Compile, with option "EvaluateSymbolically" -> False:

cf = Compile[{l}, #, RuntimeOptions -> "EvaluateSymbolically" -> False] &@
   Sum[f2[i, j], {i, 0, 50}, {j, 0, i - 6.5}];

FindRoot[cf@l == 0.4605263157894738, {l, 25}] // AbsoluteTiming
{0.015624, {l -> 29.8104}}

Update:

The method I showed above is fully applicable to the new added sample:

cfgenerator = 
  Compile[{u1, u2, u3}, #, RuntimeOptions -> "EvaluateSymbolically" -> False] &;

{cf1, cf2, cf3} = cfgenerator /@ {Sum[f2[i, j], {i, 0, limit1}, {j, 0, limit1 - i}],
     Sum[f2[i, j], {i, 1, 20}, {j, 0, i - 1}],
     Sum[f2[i, j], {j, 1, 20}, {i, 0, j - 1}]}; 

FindRoot[cf1[u1, u2, u3] == 0.4285714285714286` && 
   cf2[u1, u2, u3] == 0.47417677642980943` && 
   cf3[u1, u2, u3] == 0.2558058925476603`, {u1, 12}, {u2, 12}, {u3, 1}] // AbsoluteTiming
{0.052929, {u1 -> 11.0489, u2 -> 10.0626, u3 -> 2.10168}}

Then I'd like to talk a little about why this method works. Simply speaking, your original code is slow because those Sums are very big, and Compile is a way to speed up the evaluation of big expressions that are formed by relatively low level functions.

Well, to be honest, before answering, I hesitate for a while, because Compile isn't really a easy-to-use function (see here for more information) and personaly I don't recommond not-that-experienced Mathematica user jumping into the world of compiling. However, your Sums can (luckily) evaluate to compilable algebraic expressions and are so suitable for Compile that I can't help posting this answer. If you want to learn more about Compile (as mentioned above, currently I don't recommend you to! ) , you can consider starting from here.

xzczd
  • 65,995
  • 9
  • 163
  • 468
  • I cannot thank you enough, this is amazing. I really appreciate your help. – Fierce82 Feb 23 '16 at 12:32
  • May I ask something more general, since this method is really convenient. Suppose that someone has 3 equations and 3 unknown variables. So they use findroot to calculate these 3 variables. So in our case lets say that f2 is more complex with 3 conditions similar to Sum[f2[i, j], {i, 0, 50}, {j, 0, i - 6.5}] == 0.4605263157894738. How could I use compile with 3 functions (like cf) and then use findroot ? I can provide with an example if it is not clear. – Fierce82 Feb 23 '16 at 15:14
  • @Vasilis Just add the example into the question :) (Perhaps I won't be able to answer your new question until tomorrow though, it's midnight here) – xzczd Feb 23 '16 at 15:21
  • sorry i cannot post code as comment, i will provide it below @xzczd – Fierce82 Feb 23 '16 at 16:25
  • @Vasilis Check my edit. – xzczd Feb 24 '16 at 03:59
  • your clarifications and suggestions are really helpful. I will try to follow them, I appreciate your assistance. Compile indeed seems really powerful, but every time I tried using in the past I just could tell the difference, probably because of misusing it. – Fierce82 Feb 24 '16 at 09:05