I'm not sure it's possible to do exactly what you've indicated, but I think you should be able to get something along those lines as follows. There might be a better way to do this, but one way that I think should work is to use persistent variables to store x and fval across calls of objfunc done by each individual parallel worker, and then retrieve them all at the end using an spmd command.
So your objfunc.m function should look something like:
function [fv,x2,fv2] = objfunc(x)
persistent xstore fvstore
fval = ExternalProgramFunction(x);
xstore = [xstore; x];
fvstore = [fvstore; fval];
if nargout > 1
x2 = xstore;
if nargout > 2
fv2 = fvstore;
end
end
end
Note that xstore and fvstore here are variables that will be shared by successive calls to objfunc by a particular worker, but not across different workers. So if you have 8 workers, then at the end of your optimization you'll have 8 different versions of xstore and fvstore. You can then retrieve them using spmd via
spmd
[~,x2,fv2] = objfunc(x);
end
clear objfunc
Here, x2 and fv2 will be composite variables with dimension equal to the number of parallel workers you have, and where x2{j} and fv2{j} returning the values of xstore and fvstore on worker j. Thus, the i-th rows of xj=x2{j} and fvj=fv2{j} will give the values of x and fval for the ith call of objfunc made by the j-th worker.
Note that the last line above ("clear objfunc") clears the persistent variables from memory. If you don't do that, then next time objfunc is called you'll continue to add rows to the stored variables, which you may not want. In general, it's a good idea to run this clear statement right after you've retrieved your data in order to avoid unexpected results later on.
Note also that it's not possible to group the calls made by the different workers by the corresponding genetic algorithm "generation". If that's what you're after, I'm not sure how to do that.
One final note. The above code, as well as the method you linked to for serial execution, involve expanding the size of the stored arrays at every iteration, which is a costly step to execute and should be avoided if possible. If you have some idea of what the maximum number of function calls will be, you can potentially speed things up by pre-allocating the xstore and fvstore arrays as follows:
function [fv,x2,fv2] = objfunc(x)
persistent xstore fvstore iter
if isempty(iter)
maxcalls = 1000;
nx = 10;
xstore = zeros(maxcalls,nx);
fvstore = zeros(maxcalls,1);
iter = 1;
else
iter = iter+1
end
fval = ExternalProgramFunction(x);
xstore(iter,:) = x;
fvstore(iter) = fval;
if nargout > 1
x2 = xstore;
if nargout > 2
fv2 = fvstore;
end
end
end
Best Answer