-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathiss_arrayfun_parfor.m
133 lines (109 loc) · 3.46 KB
/
iss_arrayfun_parfor.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
%% ISS_ARRAYFUN_PARFOR An implementation of ARRAYFUN that uses PARFOR
%
% SYNOPSIS
% This s a MATLAB equivalent of pararrayfun for GNU Octave. It is
% used instead of parfor in order to a single functional
% interface for both MATLAB and Octave. You should not need to
% use it stand-alone.
%
% This function automatically starts and stops workers in order to perform
% computation, so you shouldn't do this yourself.
%
% USAGE
% % Run with two processors -- call fn(x, y, z) on each combination of
% % elements from x, y, z, and give their return values in the matrix, v.
% v = vk_cellfun_parfor(2, fn, x, y, z);
%
% % If fn2 returns a non-scalar, then use the "UniformOutput" option. In this
% % case, v will be a cell.
% v = vk_cellfun_parfor(2, fn2, x, y, z, 'UniformOutput', false);
%
% See also: arrayfun, pararrayfun, parfor
%%
% Copyright 2015 Jacek B. Krawczyk and Alastair Pharo
%
% Licensed under the Apache License, Version 2.0 (the "License");
% you may not use this file except in compliance with the License.
% You may obtain a copy of the License at
%
% http://www.apache.org/licenses/LICENSE-2.0
%
% Unless required by applicable law or agreed to in writing, software
% distributed under the License is distributed on an "AS IS" BASIS,
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
% See the License for the specific language governing permissions and
% limitations under the License.
function varargout = iss_arrayfun_parfor(numprocs, fun, varargin)
%% nret gives the number of return values to work with.
if (nargout(fun) >= 1)
nret = nargout(fun);
elseif nargout >= 1
nret = nargout;
else
nret = 1;
end
%% Work out what inputs are cell arrays.
% Unless we discover otherwise, all inputs are arrays.
array_count = numel(varargin);
for i = 1:array_count
if ~isnumeric(varargin{i})
array_count = i-1;
break;
end
end
if array_count < 1
error('There must be at least one array as input');
end
%% Any remaining inputs should be name:value pairs.
% We need to know the 'uniform output' setting, but nothing else.
if (array_count < numel(varargin))
options = struct(varargin{array_count+1:end});
uniform_output = isfield(options, 'UniformOutput') && options.UniformOutput;
else
options = struct();
uniform_output = true;
end
%% Work out the dimensions of each array
array_size = size(varargin{1});
array_numel = numel(varargin{1});
%% Start the pool, unless its already started
handle_pool = iss_pool_start(numprocs);
%% Construct return cell
% We have to return the result of each parfor run, and the break
% it up afterwards.
rets = cell(array_size);
%% Make the function calls in parallel.
try
parfor i = 1:array_numel
rets{i} = cell(1, nret);
args = cell(1, array_count);
for j = 1:array_count
args{j} = varargin{j}(i);
end
[rets{i}{:}] = fun(args{:});
end
catch exception
iss_pool_stop(handle_pool);
rethrow(exception);
end
%% Close the pool
iss_pool_stop(handle_pool);
%% Construct the output cell arrays
varargout = cell(1, nret);
for i = 1:nret
if uniform_output
varargout{i} = zeros(array_size);
else
varargout{i} = cell(array_size);
end
end
for i = 1:array_numel
for j = 1:nret
if uniform_output
varargout{j}(i) = rets{i}{j};
else
varargout{j}(i) = rets{i}(j);
end
end
end
end