Can someone help with implementing pararrayfun in my program?

Problem description

I am trying to implement pararrayfun in my program (see the attached codes). But I am not sure I am implementing it correctly. I receive the following error message upon executing the program:

>> simulate_function

execution error
error: __parcellfun_get_next_result__: could not receive result
error: called from
    parcellfun at line 201 column 16
    pararrayfun at line 85 column 28
    simulate_function at line 9 column 23

logistic_map.m (226 Bytes)
simulate_function.m (236 Bytes)

My system

  • OS: Windows 10 Enterprise SP0 - 64 bit
  • Octave version: Version 6.2.0

firstly i see that you are using variable ni in simulate function at line 9 before it was declared previously, try solve it and check again.

The ni is defined as follows: ni=1:nmax.

Now I have made some additional changes in my program. The revised program is given below. Nevertheless, I still receive the same error message. I give it below the codes.

pkg load parallel
nmax=100;
y=cell(nmax,1);
function y = myFun(i)
  n=10000; a=3.9; x0=0.1;
  y = logistic_map(n,a,x0);
end
tic
ni=1:nmax; y=pararrayfun(4,@(i)myFun(i),ni);
toc

The logistic_map is defined as follows:

function data = logistic_map( Total_time, a, x )
  data=cell(1,1);
  y=size(Total_time,1);
  y(1,1)=x;
  for i=2:Total_time
    y(i,1)=y(i-1,1)*a*(1-y(i-1));
  end  
  data{1,1}=y;    
end

The error message:

>> simulate_function
execution error
error: __parcellfun_get_next_result__: could not receive result
error: called from
    parcellfun at line 201 column 16
    pararrayfun at line 85 column 28
    simulate_function at line 10 column 13

The program runs without an error when run using for-loop. One can easily check that.

I will greatly appreciate any suggestion to fix this issue. Thanks in advance.

The way the “parallel” package works in Octave is that it spawns various “independent” instances of Octave and runs the given code in all of those.
For this to work correctly, all necessary functions must be accessible in all of those instances. If I understand your code correctly, you define myFun inline. That way it will only be defined in the “main” instance.
Move that function to a dedicated file and store it in a place that is in the load path of all instances. (Maybe use .octaverc to add it to your default load path.)

Hi @mmuetzel,
Thanks for the suggestion. I was able to successfully run the following program (taken from here):

% test_parrarrayfun_2_1.m
# Square root of the number of points where the function is calculated.
npo = 51;
# Dimensions of the integration domain
L = 10; xa = -L; xb = L; ya = -L; yb = L;
# Fist method, using two for loops, defining the function to calculate
# within the double loop.
INTENSITY_1=zeros(npo,npo);
tic
for m = 1:npo
  xo = L*0.8*((2*(m-1)/(npo-1))-1);
  for l = 1:npo
    yo = L*0.8*((2*(l-1)/(npo-1))-1);
    INTENSITY_1(m,l) = dblquad(@(x,y) integrando(x,y,xo,yo,L),xa,xb,ya,yb);
  endfor
endfor
fprintf(1,'Hello!\n');
t1 = toc
# Second method, using pararrayfun to call Int_Num
pkg load parallel
range = linspace(-L*0.8,L*0.8,npo);
[xo,yo] = meshgrid(range);
tic 
INTENSITY_2 = pararrayfun(4,@(xo,yo) Int_Num(xo,yo,L,xa,xb,ya,yb),xo,yo);
t2 = toc
fprintf(1,'Hello!!\n');
pkg unload parallel

The two functions, integrando and Int_Num, are saved separately in the working directory in which the test_parrarrayfun_2_1 sits.

# Function integrand definition
function intg = integrando(x,y,xo,yo,L)
  intg = cos(((x-xo).^2 + (y-yo).^2)/L).^2;
endfunction
# Numerical integration definition
function res = Int_Num(xo,yo,L,xa,xb,ya,yb);
  res = dblquad(@(x,y) integrando(x,y,xo,yo,L), xa, xb, ya, yb);
endfunction

The outputs printed on my computer screen looks like as follows:

>> test_parrarrayfun_2_1

Hello!
t1 = 2575.6
t2 = 1056.7
Hello!!

After this success, I tried running my own toy program, given below.

% simulate_function_2_1
pkg load parallel
% Main starts here
nmax=100;
tic
y=cell(nmax,1);
for ni=1:nmax
  y{ni,1}=myFun(ni);
end
t1=toc
tic
ni=1:nmax; y=pararrayfun(4,@(i)myFun(i),ni);
t2=toc

As before, the two functions, myFun and logistic_map, are stored as separate m-files in the working directory.

function y = myFun(i)
  n=10000; a=3.9; x0=0.1;
  y{i,1} = logistic_map(n,a,x0);
end
function data = logistic_map( Total_time, a, x )
  y=size(Total_time,1);
  y(1,1)=x;
  for i=2:Total_time
    y(i,1)=y(i-1,1)*a*(1-y(i-1));
  end  
  data{1,1}=y;
end

The outputs from the running of my toy program simulate_function_2_1 printed on my computer screen looks like as follows:

>> simulate_function_2_1

t1 = 8.3731
error: reshape: can't reshape 5050x1 array to 1x100 array
error: called from
    parcellfun at line 261 column 21
    pararrayfun at line 85 column 28
    simulate_function_2_1 at line 12 column 13

What am I doing incorrectly?

Thanks for your help, as always.

Without having looked at your example in much detail:
Do your functions return scalars for each (independent) parallel execution step?
If not, have you tried with ..., "UniformOutput", false)?

It’s hard to guess from looking at your example what you’d like to do.
As rule of thumb: If your problem doesn’t execute with arrayfun, it probably won’t with pararrayfun either.
It might be easier to first try and get it working with arrayfun. If it works with that function, try and replace arrayfun with pararrayfun.

Hi @mmuetzel,

The output from a single simulation is a cell datatype. It stores a set of Total_time doubles. See the logistic_map below.

function data = logistic_map( Total_time, a, x )
  y=size(Total_time,1);
  y(1,1)=x;
  for i=2:Total_time
    y(i,1)=y(i-1,1)*a*(1-y(i-1));
  end  
  data{1,1}=y;
end

Thus, a set of 100 runs (for nmax=100 in the main toy program) would create (as I had hoped) an output of a cell array. In this cell array, each element is a cell datatype. Am I making sense?

I tried your suggestion of using the "UniformOutput",false option. See below my modified program.

% simulate_function_2_1
% Main starts here
nmax=100;
tic
y=cell(nmax,1);
for ni=1:nmax
  y{ni,1}=myFun(ni);
end
t1=toc
pkg load parallel
tic
ni=1:nmax; y=pararrayfun(4,@(i)myFun(i),ni,"UniformOutput",false);
t2=toc
pkg unload parallel

It gave different error messages:

>> simulate_function_2_1

t1 = 11.687
error: '__parcellfun_set_nproc_used__' undefined near line 117, column 117
error: called from
    parcellfun at line 117 column 9
    pararrayfun at line 85 column 28
    simulate_function_2_1 at line 12 column 13

What did I do wrong?

Thanks.

Does it work when you are using arrayfun?

Thank you, @mmuetzel. I think my toy program, with one modification and your suggestion of using the "UniformOutput",false option, works well. Below I provide the main program, simulate_function_2_2 and two functions, myFun and logistic_map for the sake of completeness.

% simulate_function_2_2
% Main starts here
nmax=1000;
tic
y=cell(1,nmax);
for ni=1:nmax
  y{1,ni}=myFun(ni);
end
t1=toc
tic
ni=1:nmax; y2=arrayfun("myFun",ni,"UniformOutput",false);
t2=toc
%
pkg load parallel
tic
ni=1:nmax; y3=pararrayfun(4,@(i)myFun(i),ni,"UniformOutput",false);
t3=toc
pkg unload parallel

The myFun function:

function y = myFun(i)
  n=10000; a=3.9; x0=rand;
  y = logistic_map(n,a,x0);
end

The logistic_map function:

function y = logistic_map( Total_time, a, x )
  y=size(Total_time,1);
  y(1,1)=x;
  for i=2:Total_time
    y(i,1)=y(i-1,1)*a*(1-y(i-1));
  end  
end

As one can see, the one modification needed was to make the output, return by the function logistic_map, a column array of doubles. In the previous version, the output was being returned as single element of a cell. Also, I use the "UniformOutput",false option in arrayfun as well as in pararrayfun.

Below I provide the output printed on my computer screen.

>> simulate_function_2_2

    t1 = 101.47
    t2 = 111.28
    t3 = 40.106
could not terminate child process
could not terminate child process
could not terminate child process
could not terminate child process

One thing I don’t understand. Why am I receiving the message, could not terminate child process? Any thoughts? I think it is not be a big deal.