4
$\begingroup$

How do you run the same function multiple times and at the same time, but with different parameters?

I have had a look at ParallelEvaluate[] but it is meant to run the same function multiple times but with the same parameters.

For instance: I have the following function: f[x_]: = a*x+b*x Now I would like to run this function on multiple kernels at the same time with different parameters for a and b...

pseudocode:

(*Define function in current notebook with default kernel*)    
f[x_]: = a*x+b*x

RunParallel[{ (*pseudocode*)
{a=1,b=1,f[1]}, (*send to kernel1*)
{a=2,b=2,f[1]}, (*send to kernel2*)
{a=3,b=3,f[1]}, (*send to kernel3*)
{a=4,b=4,f[1]}  (*send to kernel4*)
}]
$\endgroup$
  • $\begingroup$ How about including the parameters to the arguments of the function? This way, the definitions would localized. Much more robust and debuggable coding style. $\endgroup$ – Henrik Schumacher Apr 14 '18 at 18:21
  • $\begingroup$ Alternatively, you may use something like Block[{a=1,b=1},f[x]]... $\endgroup$ – Henrik Schumacher Apr 14 '18 at 18:23
  • $\begingroup$ @Henrik Schumacher The syntax of ParallelEvaluate doesn't permit to call in parallel the same function with different agruments (say f[1] and f[2] in parallel).I think the only way to launch the same function with different parameters withParallelEvaluate is to use a shared variable (or some Random.. in the kernels). $\endgroup$ – andre314 Apr 14 '18 at 18:31
  • $\begingroup$ @andre thanks for the comment. Would you mind to explain in more details how to do it? I am just beginning to get to know parallel evaluation. $\endgroup$ – james Apr 14 '18 at 18:36
  • $\begingroup$ @HenrikSchumacher I agree, but I cannot change the function's input parameter, unfortunately. $\endgroup$ – james Apr 14 '18 at 18:37
6
$\begingroup$

One may use lists of parameters for each kernel in conjunction with $KernelID. On each kernel, $KernelID simply evaluates on a number of the kernel. So all we have to do is to design the code in a way that it depends on $KernelID. In this case, we use $KernelID in order to index into the lists of parameters (indexing with [[ ]], the short form of Part).

alist = {9, 8, 7, 6};
blist = {10, 20, 30, 40};
f[x_] := a x + b x

ParallelEvaluate[
 Block[{a = alist[[$KernelID]], b = blist[[$KernelID]]},
  f[1]
  ]
 ]

{19, 28, 37, 46}

The drawback of this method is that the outcome depends on the number of kernels...

A better approach might be to use, e.g., ParallelTable. Here an example that hopefully illuminates what is going on:

f = {x, a, b} \[Function] a x + b x;
alist = {9, 8, 7, 6};
blist = {10, 20, 30, 40};

ParallelTable[
 Row[{"Kernel ", $KernelID, " computes ", i -> f[1, alist[[i]], alist[[i]]], "."}],
 {i, 1, Length[alist]}
 ]

{Row[{"Kernel ", 4, " computes ", 1 -> 18, "."}], Row[{"Kernel ", 3, " computes ", 2 -> 16, "."}], Row[{"Kernel ", 2, " computes ", 3 -> 14, "."}], Row[{"Kernel ", 1, " computes ", 4 -> 12, "."}]}

A further, more functional oriented way could be ParallelMap:

ParallelMap[
 abpair \[Function] Row[{"Kernel ", $KernelID, " computes ",  f[1, abpair[[1]], abpair[[2]]], "."}],
 Transpose[{alist, blist}]
 ]

{Row[{"Kernel ", 4, " computes ", 19, "."}], Row[{"Kernel ", 3, " computes ", 28, "."}], Row[{"Kernel ", 2, " computes ", 37, "."}], Row[{"Kernel ", 1, " computes ", 46, "."}]}

|improve this answer|||||
$\endgroup$
  • $\begingroup$ Thank you very much. I get: {2, 4} as a result? Would you mind to comment your code? I don't understand the [[$KernelID]] part... how do you assign the function with different parameters to new kernels ? Thanks! $\endgroup$ – james Apr 14 '18 at 18:42
  • $\begingroup$ You obtain {2,4} because you have two kernels running (a processor with two cores), and $KernelID is the identification of each kernel... $\endgroup$ – José Antonio Díaz Navas Apr 14 '18 at 18:45
  • $\begingroup$ @JoséAntonioDíazNavas I cannot go beyond that with my computer then ? ... I am asking because I can define a multitude of new kernels using "Evaluation" -> "Kernel Configuration Options" $\endgroup$ – james Apr 14 '18 at 18:49
  • $\begingroup$ I think not, although I am not an expert. As far I know, you can define the machine in which you can run your NoteBook. Then, for that machine you could use as many cores as it has. However, I am afraid no beyond...I mean, I think we cannot run the same NoteBook in many machines (each one with many cores)...Therefore, I cannot run my calculation at my home computer and at the same time in the one at my office... $\endgroup$ – José Antonio Díaz Navas Apr 14 '18 at 18:53
  • $\begingroup$ @HenrikSchumacher Thank you very much for your answer and your annotation. This is really helpful! :) $\endgroup$ – james Apr 14 '18 at 18:56
5
$\begingroup$

I guess that you begin to discover parallel computing with Mathematica by reading the tutorial
ParallelTools/tutorial/ParallelEvaluation.

That's the way I discovered it.

The problem is that the first instruction that this tutorial introduces is ParallelEvaluate.

It's misleading : ParallelEvaluate is seldom used and, when reading the tutorial, it takes time
to understand that it is not destinated to evaluate the same function with different parameters in parallel.

Fortunely there are many other instructions to do what you want.

Here are two solutions :

Solution without risks, robust, conform to functional programming (recommended)

f[{x_,a_,b_}]=a x + b x;
ParallelMap[f,{{1,1,1},{1,2,2},{1,3,3},{1,4,4}}]  

{2, 4, 6, 8}

It's prudent to verify that the computing was really done in parallel (as opposed to a premature evaluation of the whole expression in the main kernel) :

f[{x_,a_,b_}]=a x + b x;
ParallelMap["Kernel "<>ToString[$KernelID]<>" : "<>ToString[f[#]]&,
     {{1,1,1},{1,2,2},{1,3,3},{1,4,4}}]

{"Kernel 4 : 2", "Kernel 3 : 4", "Kernel 2 : 6", "Kernel 1 : 8"}

Other solution, more close to your code

f[x_]=a x + b x;
DistributeDefinitions[a,b,f];
sub00=Table[ParallelSubmit[{params},(a=params[[1]];b=params[[2]];f[1])],
       {params,{{1,1},{2,2},{3,3},{4,4}}}]  

enter image description here

WaitAll[sub00]

enter image description here

{2, 4, 6, 8}

|improve this answer|||||
$\endgroup$
  • $\begingroup$ Thank you very much for your comment. Would you mind pointing me or any other newbie to an instruction that will do the job? Maybe with a small example? That would be very helpful for anyone trying to learn how to do it. Thank you very much. $\endgroup$ – james Apr 14 '18 at 18:53
  • $\begingroup$ Thanks a lot! Looking forward seeing it. $\endgroup$ – james Apr 14 '18 at 19:06
  • $\begingroup$ Thank you very much for your detailed and nicely visualized answer ! +1 Can you tell me: 1. Why the first solution is better than the second ? 2. What does WaitAll do ? Thank you very much ! $\endgroup$ – james Apr 15 '18 at 9:24
  • $\begingroup$ great answer +1 $\endgroup$ – henry Apr 15 '18 at 9:25

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.