3

I'm finding that precision of variables updated outside ParallelTable don't update inside of it the way I'd hope. Here's the minimal code that demonstrates my point:

a1 = SetPrecision[1.0, 20];
Precision[a1]
ParallelTable[
  Print[Precision[a1]];
  , {j, 1}];
a1 = SetPrecision[1.0, 30];
a2 = a1;
Precision /@ {a1, a2}
ParallelTable[
  Print[Precision /@ {a1, a2}];
  , {j, 1}];

which outputs

20.
20.
{30., 30.}
{20.,30.}

The key problem is that output lines 3 and 4 aren't the same. a1 is defined differently inside and outside ParallelTable. Why is this and how can I make sure a1 is properly updated?

For contrast, note the problem does not occur if a1 has its value updated instead of its precision:

a1 = 1.0;
a1
ParallelTable[
  Print[a1];
  , {j, 1}];
a1 = 2.0;
a2 = a1;
{a1, a2}
ParallelTable[
  Print[{a1, a2}];
  , {j, 1}];

output:

1.
1.
{2., 2.}
{2.,2.}

Some possibly related questions:

ParallelTable and Precision

-- This seems to answer a related but different question?

ParallelTable and Table do not give same result

-- I couldn't quite grasp this one to figure out if it was answering my question. A more straightforward answer would be very helpful.

Max
  • 1,050
  • 6
  • 14
  • 1
    Insert SetSharedVariable[a1, a2]; after the assignment a2=a1. This will fix it. Not completely sure what's going on though... – Lukas Jun 06 '16 at 08:19
  • What you are doing updates the precision on the master kernel, but not on the slave kernels. Alternatively to what @Lukas said (if you don't want to make the variables shared variables) you can also use ParallelEvaluate to update the precision. – sebhofer Jun 06 '16 at 11:30
  • @sebhofer Also thought so... But why is then the precision for a2 correct on the slave? That disturbed me – Lukas Jun 06 '16 at 11:38
  • @Lukas Without having checked the details, there is one obvious difference between a1 and a2: a1 already exists in the context of the slave kernels, while a2 does not. ParallelTable automatically distributes the definition of a2, but apparently does not update a1 (which seems to be reasonable behaviour to me). Again, I didn't check this in detail, just a guess. – sebhofer Jun 06 '16 at 11:46
  • @sebhofer Right, that makes sense. I overlooked that only a1 existed before the first ParallelTable. I guess you're right – Lukas Jun 06 '16 at 11:48
  • @sebhofer What makes you say this is reasonable behavior? If you do something similar where a1 changes its value (say to 2.0) instead of its precision the slave kernels get the update immediately. So why should an update not happen when the precision is changed but not the value? I'll add code for this to my question. – Max Jun 06 '16 at 16:24
  • Max, I agree this seems like strange behavior. I can't tell you why this is implemented the way it is, but see my answer for a partial explanation. – sebhofer Jun 06 '16 at 17:37

1 Answers1

4

What you are seeing can be traced back to the behavior of DistributeDefinitions which is used internally by ParallelTable. DistributeDefinitions seems to have some way to determine which of its argument should in fact be distributed [1]. If the value of a variable is unchanged, it will do nothing. Consider the following snippet, for example:

a1 = SetPrecision[1.0, 20];
DistributeDefinitions[a1]
(*{a1}*)
DistributeDefinitions[a1]
(*{}*)

The empty braces indicate that nothing was distributed. Now, a change of precision will not trigger such an update, as can be seen when evaluating

a1 = SetPrecision[2.0, 20];
DistributeDefinitions[a1]
(*{a1}*)
a1 = SetPrecision[2.0, 30];
DistributeDefinitions[a1]
(*{}*)

I can't tell you why this is the case, maybe someone else can shed light on this. As to how to work around this, we already mentioned several possible ways in the comments:

  • Using shared variables (note that this of course has additional side-effects you may or may not want)

    SetSharedVariable[a1]
    a1 = SetPrecision[2.0, 20]
    
  • Manually setting the precision on all kernels

    ParallelEvaluate[a1 = SetPrecision[2.0, 20]]
    

[1] As an aside I want to mention that the documentation seems incorrect, or confusing at the least. It states: "DistributeDefinitions in effect applies ParallelEvaluate to all assignments for values and attributes with the symbols [...], including not only ownvalues but also downvalues, upvalues, and other types of values."

sebhofer
  • 2,741
  • 18
  • 25