2

What is the reason that ParallelDo works with singly-indexed iterators, but not doubly- or more-indexed iterators? For example, the code

Print[1]
ParallelDo[Pause[1], {x, 8}]
Print[2]
ParallelDo[Pause[1], {x[1], 0, 8}]
Print[3]
ParallelDo[Pause[1], {x[1][1], 0, 8}]
Print[4]
ParallelDo[Pause[1], {x[1][1][1], 0, 8}]

will run the first two cases in parallel, but will say the last two cases cannot be parallelized. Is there a way to get these latter two cases to run in parallel?

EDIT: I've edited my original post to add actual indices to the variables, where previously I had omitted them for simplicity. The behavior I'm referring to appears to be independent of what the actually indices are, and occurs in the same way even with "empty" indices. The fundamental issue is that the Do function seems to be happy to accept arbitrarily-indexed variables as iterators, while ParallelDo is unhappy with anything that has two or more sets of indices.

EDIT 2: In regard to the comments discussion with @HenrikSchumacher, it appears that the many calls to Set do cause a huge slow down. The code below demonstrates this:

sow[x_] := (foo = {foo, x};)

With[{n = 7},
 Print[First@AbsoluteTiming[Reap[Do[
      Sow[x[1]],
      Evaluate[Sequence @@ Table[{x[i], 10}, {i, n}]]]]]];
 Print[First@AbsoluteTiming[Block[{foo},
     ParallelEvaluate[foo = {}];
     ParallelDo[
      sow[x[1]],
      Evaluate[Sequence @@ Table[{x[i], 10}, {i, n}]]];
     Join @@ ParallelEvaluate[Flatten@foo]]]];
 Print[First@AbsoluteTiming[Block[{foo},
     ParallelEvaluate[foo = {}];
     ParallelDo[
      Block[{x},
       sow[x[1] /. Table[x[i] -> z[i], {i, n}]]
       ],
      Evaluate[Sequence @@ Table[{z[i], 10}, {i, n}]]];
     Join @@ ParallelEvaluate[Flatten@foo]]]];
 Print[First@AbsoluteTiming[Block[{foo},
     ParallelEvaluate[foo = {}];
     ParallelDo[
      Block[{x},
       Do[x[i] = z[i], {i, n}];
       sow[x[1]]
       ],
      Evaluate[Sequence @@ Table[{z[i], 10}, {i, n}]]];
     Join @@ ParallelEvaluate[Flatten@foo]]]];
]

The output on my machine is:

18.2045
8.19745
28.5532
34.8674

This is using the advice given here for the parallelized cases, as opposed to a ParallelSow type approach which is very slow. Note that in this code I haven't replicated the multi-index notation that originally caused this question to arise, I've just tried implementing some potential solutions for it.

The first case is using a non-parallel Do loop, and just Sowing a value at every step and Reaping them all at the end. The second case is doing the exact same thing, but with a ParallelDo, for comparison, and is a fair bit faster.

The third and fourth cases are of the forms suggested in the comments by @HenrikSchumacher to solve my problem, with the third replacing variables using /. and the fourth using Set to replace variables. Both of these solve the original problem, but are significantly slower than the ParallelDo with no replacement, and are even slower than the serial case.

  • I even don't get the point why you want to use x[] as an iterator. I am even surprised that Mathematica does not complain about x[] not being a symbol. Maybe you are looking for something like ParallelDo[Print[$KernelID -> {x, y}], {x, 0, 8}, {y, 0, 8}]? – Henrik Schumacher May 01 '18 at 06:47
  • @HenrikSchumacher This is just a minimal working (or non-working, I guess) example. In actuality, I'm trying to solve a system of equations that has a number of variables set by input, and so I'm indexing the variables to allow for that. The most convenient way to label them all is with doubly-indexed variables, since there are two distinct sets of parameters that label the variables. I could change the entire setup I've used to this point, but I'd rather find out how to make this work if possible. – Andrew Patrick Turner May 01 '18 at 07:20
  • Usually, x[][] doesn't index anything. I am quite certain that you try to do something reasonable in the wrong way. Would you be so kind and give a simple example in code that highlights why you would like to use x[][]? – Henrik Schumacher May 01 '18 at 07:25
  • @HenrikSchumacher I'm sorry for the confusion, I omitted actual indices in my post for simplicity because it exhibited the same behavior I was seeing in my actual use case, which is notationally more cumbersome. In the actual use, I would have something like ParallelDo[Solve[...],{x[1,2][{3,{2,1}}],0,10},...] with more variables indexed in a similar form. – Andrew Patrick Turner May 01 '18 at 07:29
  • Ah, now I see. Would ParallelTable[ Block[{x}, x[1][1][1] = i; $KernelID -> {x[1][1][1]} ], {i, 0, 8}] work for you? – Henrik Schumacher May 01 '18 at 07:40
  • I had wondered about doing something similar to this, but my worry was that doing so would increase the run time enough to counteract the parallelization because of the explicit Set that I have to do. I have no idea how costly Set is, but in my actual use case, I have many (hundreds or more) variables I need to iterate over, and so I would have as many calls to Set at each step of the Do/Table. Do you know if this would seriously hinder the run time? – Andrew Patrick Turner May 01 '18 at 07:46
  • No I don't know, just give it a try with a sufficiently large example. You can also try ParallelTable[ $KernelID -> {x[1][1][1] /. x[1][1][1] -> i}, {i, 0, 8}] but I would guess that using Set is fast. – Henrik Schumacher May 01 '18 at 07:49
  • Thank you for your help. I'll give this a go and maybe update the question if it doesn't work out for some reason. Cheers! – Andrew Patrick Turner May 01 '18 at 07:51

0 Answers0