2
$\begingroup$

I want parallelize one task, but got some stupid error. I don't know why i got it and how to fix it. I have 2 examples. One works:

Do[s[a] = 
  NDSolve[{y'[x] == y[x] Cos[a x + y[x]], y[0] == 1}, 
   y, {x, 0, 5}], {a, 1, 10, .3}]
ListPlot[Table[{a, NIntegrate[y'[x]^2 /. s[a][[1]], {x, 0, 5}]}, {a, 
   1, 10, .3}], PlotRange -> All]

This fails:

Do[s[a] = 
  NDSolve[{y'[x] == y[x] Cos[a x + y[x]], y[0] == 1}, 
   y, {x, 0, 5}], {a, 1, 10, .3}]
ListPlot[ParallelTable[{a, 
   N[Integrate[y'[x]^2 /. s[a][[1]], {x, 0, 5}]]}, {a, 1, 10, .3}], 
 PlotRange -> All]

Why? How can i fi it? enter image description here But if i change increment 0.3 to 0.5:

Do[s[a] = 
  NDSolve[{y'[x] == y[x] Cos[a x + y[x]], y[0] == 1}, 
   y, {x, 0, 5}], {a, 1, 10, .5}]
ListPlot[Table[{a, NIntegrate[y'[x]^2 /. s[a][[1]], {x, 0, 5}]}, {a, 
   1, 10, .5}], PlotRange -> All]

Do[s[a] = 
  NDSolve[{y'[x] == y[x] Cos[a x + y[x]], y[0] == 1}, 
   y, {x, 0, 5}], {a, 1, 10, .5}]
ListPlot[ParallelTable[{a, 
   N[Integrate[y'[x]^2 /. s[a][[1]], {x, 0, 5}]]}, {a, 1, 10, .5}], 
 PlotRange -> All]

Both examples works fine. I can't understand this. Can i fix it?

$\endgroup$
  • $\begingroup$ First rule of debugging (or asking for debugging help here): reduce your code to the absolute smallest example that still exhibits the problem. $\endgroup$ – Szabolcs Jun 15 '16 at 15:28
  • $\begingroup$ OK, I found the reason. Will write an answer shortly. $\endgroup$ – Szabolcs Jun 15 '16 at 15:35
2
$\begingroup$

The reason for this behaviour is that Table and ParallelTable generate the range from 1 to 10 by steps of 0.3 in slightly different ways. You are working with inexact (floating point) numbers. This means that even the slightest change in the order of arithmetic operations may change the result. (a+b) + c may give a different result from a + (b+c).

Obligatory reference:

Normally, Mathematica protects against this by allowing for a tolerance in ==-comparisons. But there is zero tolerance in pattern matching. Only two exactly equal expressions will be treated the same by MatchQ.

For this reason it is not a very good idea to define s[someNumber] = ... like this. Even without talking about precision, consider:

ff[1] = "a";
ff[1.] = "b";
ff[1.`10] = "c";

enter image description here

We have three different definitions for the three different kinds of numbers. Mathematically they are equal. But they are otherwise distinct expressions.

Thus,

1 == 1. == 1.`10
(* True *)

With SameQ there is already a difference, but it considers some of them to be the same:

{1 === 1., 1. === 1.`10, 1 === 1.`10}
(* {False, True, False} *)

For pattern matching, they're all different:

{MatchQ[1, 1.], MatchQ[1., 1.`10], MatchQ[1, 1.`10]}
(* {False, False, False} *)

Demonstration on your case:

s /@ ParallelTable[a, {a, 1, 10, 0.3}]

(* s[2.8] fails to match on my system *)

s /@ Range[1,10,0.3]

(* there's a match for every value on my system *)

alist = {}
a = 1.;
While[a <= 10,
 AppendTo[alist, a];
 a += 0.3;
 ]
s /@ alist

(* s fails to match for 1.9 on my system *)

Workaround 1:

rules = Table[
   a -> First@
     NDSolve[{y'[x] == y[x] Cos[a x + y[x]], y[0] == 1}, 
      y, {x, 0, 5}], {a, 1, 10, .3}];

nf = Nearest[rules]

nf[1.] now gives the match for 1.. This is a bit dangerous because it also gives the same match for 1.1 since 1.1 is nearest to 1. out of the given points.

Workaround 2:

Use Round on a every time you set s or read s. Choose the desired precision. For example,

Do[s[Round[a, 0.001]] = 
   NDSolve[{y'[x] == y[x] Cos[a x + y[x]], y[0] == 1}, 
    y, {x, 0, 5}], {a, 1, 10, .3}];

Then, use s[Round[a,0.001]] when you read s too.

$\endgroup$

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.