Bug Summary

File:libinterp/corefcn/cellfun.cc
Location:line 2160, column 9
Description:Forming reference to null pointer

Annotated Source Code

1/*
2
3Copyright (C) 2005-2013 Mohamed Kamoun
4Copyright (C) 2006-2013 Bill Denney
5Copyright (C) 2009 Jaroslav Hajek
6Copyright (C) 2010 VZLU Prague
7
8This file is part of Octave.
9
10Octave is free software; you can redistribute it and/or modify it
11under the terms of the GNU General Public License as published by the
12Free Software Foundation; either version 3 of the License, or (at your
13option) any later version.
14
15Octave is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18for more details.
19
20You should have received a copy of the GNU General Public License
21along with Octave; see the file COPYING. If not, see
22<http://www.gnu.org/licenses/>.
23
24*/
25
26#ifdef HAVE_CONFIG_H1
27#include <config.h>
28#endif
29
30#include <string>
31#include <vector>
32#include <list>
33#include <memory>
34
35#include "caseless-str.h"
36#include "lo-mappers.h"
37#include "oct-locbuf.h"
38
39#include "Cell.h"
40#include "oct-map.h"
41#include "defun.h"
42#include "parse.h"
43#include "variables.h"
44#include "ov-colon.h"
45#include "unwind-prot.h"
46#include "gripes.h"
47#include "utils.h"
48
49#include "ov-class.h"
50#include "ov-scalar.h"
51#include "ov-float.h"
52#include "ov-complex.h"
53#include "ov-flt-complex.h"
54#include "ov-bool.h"
55#include "ov-int8.h"
56#include "ov-int16.h"
57#include "ov-int32.h"
58#include "ov-int64.h"
59#include "ov-uint8.h"
60#include "ov-uint16.h"
61#include "ov-uint32.h"
62#include "ov-uint64.h"
63
64#include "ov-fcn-handle.h"
65
66static octave_value_list
67get_output_list (octave_idx_type count, octave_idx_type nargout,
68 const octave_value_list& inputlist,
69 octave_value& func,
70 octave_value& error_handler)
71{
72 octave_value_list tmp;
73 try
74 {
75 tmp = func.do_multi_index_op (nargout, inputlist);
76 }
77 catch (octave_execution_exception)
78 {
79 if (error_handler.is_defined ())
80 error_state = 1;
81 }
82
83 if (error_state)
84 {
85 if (error_handler.is_defined ())
86 {
87 octave_scalar_map msg;
88 msg.assign ("identifier", last_error_id ());
89 msg.assign ("message", last_error_message ());
90 msg.assign ("index",
91 static_cast<double> (count
92 + static_cast<octave_idx_type>(1)));
93
94 octave_value_list errlist = inputlist;
95 errlist.prepend (msg);
96
97 buffer_error_messages--;
98
99 error_state = 0;
100
101 tmp = error_handler.do_multi_index_op (nargout, errlist);
102
103 buffer_error_messages++;
104
105 if (error_state)
106 tmp.clear ();
107 }
108 else
109 tmp.clear ();
110 }
111
112 return tmp;
113}
114
115static octave_value_list
116try_cellfun_internal_ops (const octave_value_list& args, int nargin)
117{
118 octave_value_list retval;
119
120 std::string name = args(0).string_value ();
121
122 const Cell f_args = args(1).cell_value ();
123
124 octave_idx_type k = f_args.numel ();
125
126 if (name == "isempty")
127 {
128 boolNDArray result (f_args.dims ());
129 for (octave_idx_type count = 0; count < k; count++)
130 result(count) = f_args.elem (count).is_empty ();
131 retval(0) = result;
132 }
133 else if (name == "islogical")
134 {
135 boolNDArray result (f_args.dims ());
136 for (octave_idx_type count= 0; count < k; count++)
137 result(count) = f_args.elem (count).is_bool_type ();
138 retval(0) = result;
139 }
140 else if (name == "isnumeric")
141 {
142 boolNDArray result (f_args.dims ());
143 for (octave_idx_type count= 0; count < k; count++)
144 result(count) = f_args.elem (count).is_numeric_type ();
145 retval(0) = result;
146 }
147 else if (name == "isreal")
148 {
149 boolNDArray result (f_args.dims ());
150 for (octave_idx_type count= 0; count < k; count++)
151 result(count) = f_args.elem (count).is_real_type ();
152 retval(0) = result;
153 }
154 else if (name == "length")
155 {
156 NDArray result (f_args.dims ());
157 for (octave_idx_type count= 0; count < k; count++)
158 result(count) = static_cast<double> (f_args.elem (count).length ());
159 retval(0) = result;
160 }
161 else if (name == "ndims")
162 {
163 NDArray result (f_args.dims ());
164 for (octave_idx_type count = 0; count < k; count++)
165 result(count) = static_cast<double> (f_args.elem (count).ndims ());
166 retval(0) = result;
167 }
168 else if (name == "numel" || name == "prodofsize")
169 {
170 NDArray result (f_args.dims ());
171 for (octave_idx_type count = 0; count < k; count++)
172 result(count) = static_cast<double> (f_args.elem (count).numel ());
173 retval(0) = result;
174 }
175 else if (name == "size")
176 {
177 if (nargin == 3)
178 {
179 int d = args(2).nint_value () - 1;
180
181 if (d < 0)
182 error ("cellfun: K must be a positive integer");
183
184 if (! error_state)
185 {
186 NDArray result (f_args.dims ());
187 for (octave_idx_type count = 0; count < k; count++)
188 {
189 dim_vector dv = f_args.elem (count).dims ();
190 if (d < dv.length ())
191 result(count) = static_cast<double> (dv(d));
192 else
193 result(count) = 1.0;
194 }
195 retval(0) = result;
196 }
197 }
198 else
199 error ("cellfun: not enough arguments for \"size\"");
200 }
201 else if (name == "isclass")
202 {
203 if (nargin == 3)
204 {
205 std::string class_name = args(2).string_value ();
206 boolNDArray result (f_args.dims ());
207 for (octave_idx_type count = 0; count < k; count++)
208 result(count) = (f_args.elem (count).class_name () == class_name);
209
210 retval(0) = result;
211 }
212 else
213 error ("cellfun: not enough arguments for \"isclass\"");
214 }
215
216 return retval;
217}
218
219static void
220get_mapper_fun_options (const octave_value_list& args, int& nargin,
221 bool& uniform_output, octave_value& error_handler)
222{
223 while (nargin > 3 && args(nargin-2).is_string ())
224 {
225 caseless_str arg = args(nargin-2).string_value ();
226
227 size_t compare_len = std::max (arg.length (), static_cast<size_t> (2));
228
229 if (arg.compare ("uniformoutput", compare_len))
230 uniform_output = args(nargin-1).bool_value ();
231 else if (arg.compare ("errorhandler", compare_len))
232 {
233 if (args(nargin-1).is_function_handle ()
234 || args(nargin-1).is_inline_function ())
235 {
236 error_handler = args(nargin-1);
237 }
238 else if (args(nargin-1).is_string ())
239 {
240 std::string err_name = args(nargin-1).string_value ();
241
242 error_handler = symbol_table::find_function (err_name);
243
244 if (error_handler.is_undefined ())
245 {
246 error ("cellfun: invalid function NAME: %s",
247 err_name.c_str ());
248 break;
249 }
250 }
251 else
252 {
253 error ("cellfun: invalid value for 'ErrorHandler' function");
254 break;
255 }
256 }
257 else
258 {
259 error ("cellfun: unrecognized parameter %s",
260 arg.c_str ());
261 break;
262 }
263
264 nargin -= 2;
265 }
266
267 nargin -= 1;
268}
269
270DEFUN (cellfun, args, nargout,octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
271 "-*- texinfo -*-\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
272@deftypefn {Built-in Function} {} cellfun (@var{name}, @var{C})\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
273@deftypefnx {Built-in Function} {} cellfun (\"size\", @var{C}, @var{k})\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
274@deftypefnx {Built-in Function} {} cellfun (\"isclass\", @var{C}, @var{class})\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
275@deftypefnx {Built-in Function} {} cellfun (@var{func}, @var{C})\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
276@deftypefnx {Built-in Function} {} cellfun (@var{func}, @var{C}, @var{D})\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
277@deftypefnx {Built-in Function} {[@var{a}, @dots{}] =} cellfun (@dots{})\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
278@deftypefnx {Built-in Function} {} cellfun (@dots{}, \"ErrorHandler\", @var{errfunc})\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
279@deftypefnx {Built-in Function} {} cellfun (@dots{}, \"UniformOutput\", @var{val})\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
280\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
281Evaluate the function named @var{name} on the elements of the cell array\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
282@var{C}. Elements in @var{C} are passed on to the named function\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
283individually. The function @var{name} can be one of the functions\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
284\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
285@table @code\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
286@item isempty\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
287Return 1 for empty elements.\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
288\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
289@item islogical\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
290Return 1 for logical elements.\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
291\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
292@item isnumeric\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
293Return 1 for numeric elements.\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
294\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
295@item isreal\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
296Return 1 for real elements.\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
297\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
298@item length\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
299Return a vector of the lengths of cell elements.\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
300\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
301@item ndims\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
302Return the number of dimensions of each element.\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
303\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
304@item numel\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
305@itemx prodofsize\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
306Return the number of elements contained within each cell element. The\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
307number is the product of the dimensions of the object at each cell element.\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
308\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
309@item size\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
310Return the size along the @var{k}-th dimension.\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
311\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
312@item isclass\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
313Return 1 for elements of @var{class}.\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
314@end table\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
315\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
316Additionally, @code{cellfun} accepts an arbitrary function @var{func}\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
317in the form of an inline function, function handle, or the name of a\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
318function (in a character string). In the case of a character string\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
319argument, the function must accept a single argument named @var{x}, and\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
320it must return a string value. The function can take one or more arguments,\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
321with the inputs arguments given by @var{C}, @var{D}, etc. Equally the\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
322function can return one or more output arguments. For example:\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
323\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
324@example\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
325@group\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
326cellfun (\"atan2\", @{1, 0@}, @{0, 1@})\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
327 @result{} [ 1.57080 0.00000 ]\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
328@end group\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
329@end example\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
330\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
331The number of output arguments of @code{cellfun} matches the number of output\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
332arguments of the function. The outputs of the function will be collected\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
333into the output arguments of @code{cellfun} like this:\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
334\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
335@example\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
336@group\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
337function [a, b] = twoouts (x)\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
338 a = x;\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
339 b = x*x;\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
340endfunction\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
341[aa, bb] = cellfun (@@twoouts, @{1, 2, 3@})\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
342 @result{}\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
343 aa =\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
344 1 2 3\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
345 bb =\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
346 1 4 9\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
347@end group\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
348@end example\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
349\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
350Note that per default the output argument(s) are arrays of the same size as\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
351the input arguments. Input arguments that are singleton (1x1) cells will be\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
352automatically expanded to the size of the other arguments.\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
353\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
354If the parameter @qcode{\"UniformOutput\"} is set to true (the default),\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
355then the function must return scalars which will be concatenated into the\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
356return array(s). If @qcode{\"UniformOutput\"} is false, the outputs are\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
357concatenated into a cell array (or cell arrays). For example:\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
358\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
359@example\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
360@group\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
361cellfun (\"tolower\", @{\"Foo\", \"Bar\", \"FooBar\"@},\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
362 \"UniformOutput\", false)\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
363@result{} @{\"foo\", \"bar\", \"foobar\"@}\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
364@end group\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
365@end example\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
366\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
367Given the parameter @qcode{\"ErrorHandler\"}, then @var{errfunc} defines a\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
368function to call in case @var{func} generates an error. The form of the\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
369function is\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
370\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
371@example\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
372function [@dots{}] = errfunc (@var{s}, @dots{})\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
373@end example\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
374\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
375@noindent\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
376where there is an additional input argument to @var{errfunc} relative to\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
377@var{func}, given by @var{s}. This is a structure with the elements\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
378@qcode{\"identifier\"}, @qcode{\"message\"} and @qcode{\"index\"}, giving\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
379respectively the error identifier, the error message, and the index into the\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
380input arguments of the element that caused the error. For example:\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
381\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
382@example\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
383@group\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
384function y = foo (s, x), y = NaN; endfunction\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
385cellfun (\"factorial\", @{-1,2@}, \"ErrorHandler\", @@foo)\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
386@result{} [NaN 2]\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
387@end group\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
388@end example\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
389\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
390Use @code{cellfun} intelligently. The @code{cellfun} function is a\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
391useful tool for avoiding loops. It is often used with anonymous\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
392function handles; however, calling an anonymous function involves an\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
393overhead quite comparable to the overhead of an m-file function.\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
394Passing a handle to a built-in function is faster, because the\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
395interpreter is not involved in the internal loop. For example:\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
396\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
397@example\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
398@group\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
399a = @{@dots{}@}\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
400v = cellfun (@@(x) det (x), a); # compute determinants\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
401v = cellfun (@@det, a); # faster\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
402@end group\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
403@end example\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
404\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
405@seealso{arrayfun, structfun, spfun}\n\octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
406@end deftypefn")octave_value_list Fcellfun (const octave_value_list& args
, int nargout)
407{
408 octave_value_list retval;
409 int nargin = args.length ();
410 int nargout1 = (nargout < 1 ? 1 : nargout);
411
412 if (nargin < 2)
413 {
414 error ("cellfun: function requires at least 2 arguments");
415 print_usage ();
416 return retval;
417 }
418
419 octave_value func = args(0);
420
421 if (! args(1).is_cell ())
422 {
423 error ("cellfun: C must be a cell array");
424
425 return retval;
426 }
427
428 if (func.is_string ())
429 {
430 retval = try_cellfun_internal_ops (args, nargin);
431
432 if (error_state || ! retval.empty ())
433 return retval;
434
435 // See if we can convert the string into a function.
436
437 std::string name = args(0).string_value ();
438
439 if (! valid_identifier (name))
440 {
441 std::string fcn_name = unique_symbol_name ("__cellfun_fcn_");
442 std::string fname = "function y = " + fcn_name + "(x) y = ";
443
444 octave_function *ptr_func
445 = extract_function (args(0), "cellfun", fcn_name,
446 fname, "; endfunction");
447
448 if (ptr_func && ! error_state)
449 func = octave_value (ptr_func, true);
450 }
451 else
452 {
453 func = symbol_table::find_function (name);
454
455 if (func.is_undefined ())
456 error ("cellfun: invalid function NAME: %s", name.c_str ());
457 }
458
459 if (error_state || ! retval.empty ())
460 return retval;
461 }
462
463 if (func.is_function_handle () || func.is_inline_function ()
464 || func.is_function ())
465 {
466
467 // The following is an optimisation because the symbol table can
468 // give a more specific function class, so this can result in
469 // fewer polymorphic function calls as the function gets called
470 // for each value of the array.
471 {
472 if (func.is_function_handle ())
473 {
474 octave_fcn_handle* f = func.fcn_handle_value ();
475
476 // Overloaded function handles need to check the type of the
477 // arguments for each element of the array, so they cannot
478 // be optimised this way.
479 if (f -> is_overloaded ())
480 goto nevermind;
481 }
482
483 std::string name = func.function_value () -> name ();
484 octave_value f = symbol_table::find_function (name);
485
486 if (f.is_defined ())
487 {
488 //Except for these two which are special cases...
489 if (name != "size" && name != "class")
490 {
491 //Try first the optimised code path for built-in functions
492 octave_value_list tmp_args = args;
493 tmp_args(0) = name;
494 retval = try_cellfun_internal_ops (tmp_args, nargin);
495 if (error_state || ! retval.empty ())
496 return retval;
497 }
498
499 //Okay, we tried, doesn't work, let's do the best we can
500 //instead and avoid polymorphic calls for each element of
501 //the array.
502 func = f;
503 }
504 }
505 nevermind:
506
507 bool uniform_output = true;
508 octave_value error_handler;
509
510 get_mapper_fun_options (args, nargin, uniform_output, error_handler);
511
512 if (error_state)
513 return octave_value_list ();
514
515 // Extract cell arguments.
516
517 octave_value_list inputlist (nargin, octave_value ());
518
519 OCTAVE_LOCAL_BUFFER (Cell, inputs, nargin)octave_local_buffer<Cell> _buffer_inputs (nargin); Cell
*inputs = _buffer_inputs
;
520 OCTAVE_LOCAL_BUFFER (bool, mask, nargin)octave_local_buffer<bool> _buffer_mask (nargin); bool *
mask = _buffer_mask
;
521
522 // This is to prevent copy-on-write.
523 const Cell *cinputs = inputs;
524
525 octave_idx_type k = 1;
526
527 dim_vector fdims (1, 1);
528
529 // Collect arguments. Pre-fill scalar elements of inputlist
530 // array.
531
532 for (int j = 0; j < nargin; j++)
533 {
534 if (! args(j+1).is_cell ())
535 {
536 error ("cellfun: arguments must be cells");
537 return octave_value_list ();
538 }
539
540 inputs[j] = args(j+1).cell_value ();
541 mask[j] = inputs[j].numel () != 1;
542 if (! mask[j])
543 inputlist(j) = cinputs[j](0);
544 }
545
546 for (int j = 0; j < nargin; j++)
547 {
548 if (mask[j])
549 {
550 fdims = inputs[j].dims ();
551 k = inputs[j].numel ();
552 for (int i = j+1; i < nargin; i++)
553 {
554 if (mask[i] && inputs[i].dims () != fdims)
555 {
556 error ("cellfun: dimensions mismatch");
557 return octave_value_list ();
558 }
559 }
560 break;
561 }
562 }
563
564 unwind_protect frame;
565 frame.protect_var (buffer_error_messages);
566
567 if (error_handler.is_defined ())
568 buffer_error_messages++;
569
570 // Apply functions.
571
572 if (uniform_output)
573 {
574 std::list<octave_value_list> idx_list (1);
575 idx_list.front ().resize (1);
576 std::string idx_type = "(";
577
578 OCTAVE_LOCAL_BUFFER (octave_value, retv, nargout1)octave_local_buffer<octave_value> _buffer_retv (nargout1
); octave_value *retv = _buffer_retv
;
579
580 for (octave_idx_type count = 0; count < k; count++)
581 {
582 for (int j = 0; j < nargin; j++)
583 {
584 if (mask[j])
585 inputlist.xelem (j) = cinputs[j](count);
586 }
587
588 const octave_value_list tmp
589 = get_output_list (count, nargout, inputlist, func,
590 error_handler);
591
592 if (error_state)
593 return retval;
594
595 if (nargout > 0 && tmp.length () < nargout)
596 {
597 error ("cellfun: function returned fewer than nargout values");
598 return retval;
599 }
600
601 if (nargout > 0
602 || (nargout == 0
603 && tmp.length () > 0 && tmp(0).is_defined ()))
604 {
605 int num_to_copy = tmp.length ();
606
607 if (num_to_copy > nargout1)
608 num_to_copy = nargout1;
609
610 if (count == 0)
611 {
612 for (int j = 0; j < num_to_copy; j++)
613 {
614 if (tmp(j).is_defined ())
615 {
616 octave_value val = tmp(j);
617
618 if (val.numel () == 1)
619 retv[j] = val.resize (fdims);
620 else
621 {
622 error ("cellfun: all values must be scalars when UniformOutput = true");
623 break;
624 }
625 }
626 }
627 }
628 else
629 {
630 for (int j = 0; j < num_to_copy; j++)
631 {
632 if (tmp(j).is_defined ())
633 {
634 octave_value val = tmp(j);
635
636 if (! retv[j].fast_elem_insert (count, val))
637 {
638 if (val.numel () == 1)
639 {
640 idx_list.front ()(0) = count + 1.0;
641 retv[j].assign (octave_value::op_asn_eq,
642 idx_type, idx_list, val);
643
644 if (error_state)
645 break;
646 }
647 else
648 {
649 error ("cellfun: all values must be scalars when UniformOutput = true");
650 break;
651 }
652 }
653 }
654 }
655 }
656 }
657
658 if (error_state)
659 break;
660 }
661
662 retval.resize (nargout1);
663
664 for (int j = 0; j < nargout1; j++)
665 {
666 if (nargout > 0 && retv[j].is_undefined ())
667 retval(j) = NDArray (fdims);
668 else
669 retval(j) = retv[j];
670 }
671 }
672 else
673 {
674 OCTAVE_LOCAL_BUFFER (Cell, results, nargout1)octave_local_buffer<Cell> _buffer_results (nargout1); Cell
*results = _buffer_results
;
675
676 for (int j = 0; j < nargout1; j++)
677 results[j].resize (fdims, Matrix ());
678
679 bool have_some_output = false;
680
681 for (octave_idx_type count = 0; count < k; count++)
682 {
683 for (int j = 0; j < nargin; j++)
684 {
685 if (mask[j])
686 inputlist.xelem (j) = cinputs[j](count);
687 }
688
689 const octave_value_list tmp
690 = get_output_list (count, nargout, inputlist, func,
691 error_handler);
692
693 if (error_state)
694 return retval;
695
696 if (nargout > 0 && tmp.length () < nargout)
697 {
698 error ("cellfun: function returned fewer than nargout values");
699 return retval;
700 }
701
702 if (nargout > 0
703 || (nargout == 0
704 && tmp.length () > 0 && tmp(0).is_defined ()))
705 {
706 int num_to_copy = tmp.length ();
707
708 if (num_to_copy > nargout1)
709 num_to_copy = nargout1;
710
711 if (num_to_copy > 0)
712 have_some_output = true;
713
714 for (int j = 0; j < num_to_copy; j++)
715 results[j](count) = tmp(j);
716 }
717 }
718
719 if (have_some_output || fdims.any_zero ())
720 {
721 retval.resize (nargout1);
722
723 for (int j = 0; j < nargout1; j++)
724 retval(j) = results[j];
725 }
726 }
727 }
728 else
729 error ("cellfun: argument NAME must be a string or function handle");
730
731 return retval;
732}
733
734/*
735
736%!function r = __f11 (x)
737%! global __cellfun_test_num_outputs__;
738%! __cellfun_test_num_outputs__ = nargout;
739%! r = x;
740%!endfunction
741
742%!function __f01 (x)
743%! global __cellfun_test_num_outputs__;
744%! __cellfun_test_num_outputs__ = nargout;
745%!endfunction
746
747%!test
748%! global __cellfun_test_num_outputs__;
749%! cellfun (@__f11, {1});
750%! assert (__cellfun_test_num_outputs__, 0);
751%! x = cellfun (@__f11, {1});
752%! assert (__cellfun_test_num_outputs__, 1);
753
754%!test
755%! global __cellfun_test_num_outputs__;
756%! cellfun (@__f01, {1});
757%! assert (__cellfun_test_num_outputs__, 0);
758
759%!error x = cellfun (@__f01, {1, 2});
760
761%!test
762%! assert (cellfun (@__f11, {1, 2}), [1, 2]);
763%! assert (cellfun (@__f11, {1, 2}, 'uniformoutput', false), {1, 2});
764
765%!test
766%! [a,b] = cellfun (@(x) x, cell (2, 0));
767%! assert (a, zeros (2, 0));
768%! assert (b, zeros (2, 0));
769
770%!test
771%! [a,b] = cellfun (@(x) x, cell (2, 0), "uniformoutput", false);
772%! assert (a, cell (2, 0));
773%! assert (b, cell (2, 0));
774
775%% Test function to check the "Errorhandler" option
776%!function z = __cellfunerror (S, varargin)
777%! z = S;
778%!endfunction
779
780%% First input argument can be a string, an inline function,
781%% a function_handle or an anonymous function
782%!test
783%! A = cellfun ("islogical", {true, 0.1, false, i*2});
784%! assert (A, [true, false, true, false]);
785%!test
786%! A = cellfun (inline ("islogical (x)", "x"), {true, 0.1, false, i*2});
787%! assert (A, [true, false, true, false]);
788%!test
789%! A = cellfun (@islogical, {true, 0.1, false, i*2});
790%! assert (A, [true, false, true, false]);
791%!test
792%! A = cellfun (@(x) islogical (x), {true, 0.1, false, i*2});
793%! assert (A, [true, false, true, false]);
794
795%% First input argument can be the special string "isreal",
796%% "isempty", "islogical", "isnumeric", "length", "ndims" or "prodofsize"
797%!test
798%! A = cellfun ("isreal", {true, 0.1, {}, i*2, [], "abc"});
799%! assert (A, [true, true, false, false, true, true]);
800%!test
801%! A = cellfun ("isempty", {true, 0.1, false, i*2, [], "abc"});
802%! assert (A, [false, false, false, false, true, false]);
803%!test
804%! A = cellfun ("islogical", {true, 0.1, false, i*2, [], "abc"});
805%! assert (A, [true, false, true, false, false, false]);
806%!test
807%! A = cellfun ("isnumeric", {true, 0.1, false, i*2, [], "abc"});
808%! assert (A, [false, true, false, true, true, false]);
809%!test
810%! A = cellfun ("length", {true, 0.1, false, i*2, [], "abc"});
811%! assert (A, [1, 1, 1, 1, 0, 3]);
812%!test
813%! A = cellfun ("ndims", {[1, 2; 3, 4]; (cell (1,2,3,4))});
814%! assert (A, [2; 4]);
815%!test
816%! A = cellfun ("prodofsize", {[1, 2; 3, 4], (cell (1,2,3,4))});
817%! assert (A, [4, 24]);
818
819%% Number of input and output arguments may not be limited to one
820%!test
821%! A = cellfun (@(x,y,z) x + y + z, {1, 1, 1}, {2, 2, 2}, {3, 4, 5});
822%! assert (A, [6, 7, 8]);
823%!test
824%! A = cellfun (@(x,y,z) x + y + z, {1, 1, 1}, {2, 2, 2}, {3, 4, 5}, ...
825%! "UniformOutput", false);
826%! assert (A, {6, 7, 8});
827%!test %% Two input arguments of different types
828%! A = cellfun (@(x,y) islogical (x) && ischar (y), {false, true}, {"a", 3});
829%! assert (A, [true, false]);
830%!test %% Pass another variable to the anonymous function
831%! y = true;
832%! A = cellfun (@(x) islogical (x) && y, {false, 0.3});
833%! assert (A, [true, false]);
834%!test %% Three ouptut arguments of different type
835%! [A, B, C] = cellfun (@find, {10, 11; 0, 12}, "UniformOutput", false);
836%! assert (isequal (A, {true, true; [], true}));
837%! assert (isequal (B, {true, true; [], true}));
838%! assert (isequal (C, {10, 11; [], 12}));
839
840%% Input arguments can be of type cell array of logical
841%!test
842%! A = cellfun (@(x,y) x == y, {false, true}, {true, true});
843%! assert (A, [false, true]);
844%!test
845%! A = cellfun (@(x,y) x == y, {false; true}, {true; true}, ...
846%! "UniformOutput", true);
847%! assert (A, [false; true]);
848%!test
849%! A = cellfun (@(x) x, {false, true; false, true}, "UniformOutput", false);
850%! assert (A, {false, true; false, true});
851%!test %% Three ouptut arguments of same type
852%! [A, B, C] = cellfun (@find, {true, false; false, true}, ...
853%! "UniformOutput", false);
854%! assert (isequal (A, {true, []; [], true}));
855%! assert (isequal (B, {true, []; [], true}));
856%! assert (isequal (C, {true, []; [], true}));
857%!test
858%! A = cellfun (@(x,y) cell2str (x,y), {true}, {true}, ...
859%! "ErrorHandler", @__cellfunerror);
860%! assert (isfield (A, "identifier"), true);
861%! assert (isfield (A, "message"), true);
862%! assert (isfield (A, "index"), true);
863%! assert (isempty (A.message), false);
864%! assert (A.index, 1);
865%!test %% Overwriting setting of "UniformOutput" true
866%! A = cellfun (@(x,y) cell2str (x,y), {true}, {true}, ...
867%! "UniformOutput", true, "ErrorHandler", @__cellfunerror);
868%! assert (isfield (A, "identifier"), true);
869%! assert (isfield (A, "message"), true);
870%! assert (isfield (A, "index"), true);
871%! assert (isempty (A.message), false);
872%! assert (A.index, 1);
873
874%% Input arguments can be of type cell array of numeric
875%!test
876%! A = cellfun (@(x,y) x>y, {1.1, 4.2}, {3.1, 2+3*i});
877%! assert (A, [false, true]);
878%!test
879%! A = cellfun (@(x,y) x>y, {1.1, 4.2; 2, 4}, {3.1, 2; 2, 4+2*i}, ...
880%! "UniformOutput", true);
881%! assert (A, [false, true; false, false]);
882%!test
883%! A = cellfun (@(x,y) x:y, {1.1, 4}, {3.1, 6}, "UniformOutput", false);
884%! assert (isequal (A{1}, [1.1, 2.1, 3.1]));
885%! assert (isequal (A{2}, [4, 5, 6]));
886%!test %% Three ouptut arguments of different type
887%! [A, B, C] = cellfun (@find, {10, 11; 0, 12}, "UniformOutput", false);
888%! assert (isequal (A, {true, true; [], true}));
889%! assert (isequal (B, {true, true; [], true}));
890%! assert (isequal (C, {10, 11; [], 12}));
891%!test
892%! A = cellfun (@(x,y) cell2str (x,y), {1.1, 4}, {3.1, 6}, ...
893%! "ErrorHandler", @__cellfunerror);
894%! B = isfield (A(1), "message") && isfield (A(1), "index");
895%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]);
896%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]);
897%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]);
898%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]);
899%! assert ([A(1).index, A(2).index], [1, 2]);
900%!test %% Overwriting setting of "UniformOutput" true
901%! A = cellfun (@(x,y) cell2str (x,y), {1.1, 4}, {3.1, 6}, ...
902%! "UniformOutput", true, "ErrorHandler", @__cellfunerror);
903%! B = isfield (A(1), "message") && isfield (A(1), "index");
904%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]);
905%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]);
906%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]);
907%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]);
908%! assert ([A(1).index, A(2).index], [1, 2]);
909
910%% Input arguments can be of type cell arrays of character or strings
911%!error %% "UniformOutput" false should be used
912%! A = cellfun (@(x,y) x>y, {"ad", "c", "ghi"}, {"cc", "d", "fgh"});
913%!test
914%! A = cellfun (@(x,y) x>y, {"a"; "f"}, {"c"; "d"}, "UniformOutput", true);
915%! assert (A, [false; true]);
916%!test
917%! A = cellfun (@(x,y) x:y, {"a", "d"}, {"c", "f"}, "UniformOutput", false);
918%! assert (A, {"abc", "def"});
919%!test
920%! A = cellfun (@(x,y) cell2str (x,y), {"a", "d"}, {"c", "f"}, ...
921%! "ErrorHandler", @__cellfunerror);
922%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]);
923%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]);
924%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]);
925%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]);
926%! assert ([A(1).index, A(2).index], [1, 2]);
927%!test %% Overwriting setting of "UniformOutput" true
928%! A = cellfun (@(x,y) cell2str (x,y), {"a", "d"}, {"c", "f"}, ...
929%! "UniformOutput", true, "ErrorHandler", @__cellfunerror);
930%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]);
931%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]);
932%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]);
933%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]);
934%! assert ([A(1).index, A(2).index], [1, 2]);
935
936%% Structures cannot be handled by cellfun
937%!error
938%! vst1.a = 1.1; vst1.b = 4.2; vst2.a = 3.1; vst2.b = 2;
939%! A = cellfun (@(x,y) (x.a < y.a) && (x.b > y.b), vst1, vst2);
940
941%% Input arguments can be of type cell array of cell arrays
942%!test
943%! A = cellfun (@(x,y) x{1} < y{1}, {{1.1}, {4.2}}, {{3.1}, {2}});
944%! assert (A, [1, 0], 1e-16);
945%!test
946%! A = cellfun (@(x,y) x{1} < y{1}, {{1.1}; {4.2}}, {{3.1}; {2}}, ...
947%! "UniformOutput", true);
948%! assert (A, [1; 0], 1e-16);
949%!test
950%! A = cellfun (@(x,y) x{1} < y{1}, {{1.1}, {4.2}}, {{3.1}, {2}}, ...
951%! "UniformOutput", false);
952%! assert (A, {true, false});
953%!test
954%! A = cellfun (@(x,y) mat2str (x,y), {{1.1}, {4.2}}, {{3.1}, {2}}, ...
955%! "ErrorHandler", @__cellfunerror);
956%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]);
957%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]);
958%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]);
959%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]);
960%! assert ([A(1).index, A(2).index], [1, 2]);
961%!test %% Overwriting setting of "UniformOutput" true
962%! A = cellfun (@(x,y) mat2str (x,y), {{1.1}, {4.2}}, {{3.1}, {2}}, ...
963%! "UniformOutput", true, "ErrorHandler", @__cellfunerror);
964%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]);
965%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]);
966%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]);
967%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]);
968%! assert ([A(1).index, A(2).index], [1, 2]);
969
970%% Input arguments can be of type cell array of structure arrays
971%!test
972%! a = struct ("a", 1, "b", 2); b = struct ("a", 1, "b", 3);
973%! A = cellfun (@(x,y) (x.a == y.a) && (x.b < y.b), {a}, {b});
974%! assert (A, true);
975%!test
976%! a = struct ("a", 1, "b", 2); b = struct ("a", 1, "b", 3);
977%! A = cellfun (@(x,y) (x.a == y.a) && (x.b < y.b) , {a}, {b}, ...
978%! "UniformOutput", true);
979%! assert (A, true);
980%!test
981%! a = struct ("a", 1, "b", 2); b = struct ("a", 1, "b", 3);
982%! A = cellfun (@(x,y) (x.a == y.a) && (x.b < y.b) , {a}, {b}, ...
983%! "UniformOutput", false);
984%! assert (A, {true});
985%!test
986%! a = struct ("a", 1, "b", 2); b = struct ("a", 1, "b", 3);
987%! A = cellfun (@(x,y) cell2str (x.a, y.a), {a}, {b}, ...
988%! "ErrorHandler", @__cellfunerror);
989%! assert (isfield (A, "identifier"), true);
990%! assert (isfield (A, "message"), true);
991%! assert (isfield (A, "index"), true);
992%! assert (isempty (A.message), false);
993%! assert (A.index, 1);
994%!test %% Overwriting setting of "UniformOutput" true
995%! a = struct ("a", 1, "b", 2); b = struct ("a", 1, "b", 3);
996%! A = cellfun (@(x,y) cell2str (x.a, y.a), {a}, {b}, ...
997%! "UniformOutput", true, "ErrorHandler", @__cellfunerror);
998%! assert (isfield (A, "identifier"), true);
999%! assert (isfield (A, "message"), true);
1000%! assert (isfield (A, "index"), true);
1001%! assert (isempty (A.message), false);
1002%! assert (A.index, 1);
1003
1004%% A lot of other tests
1005%!assert (cellfun (@sin, {0,1}), sin ([0,1]))
1006%!assert (cellfun (inline ("sin (x)"), {0,1}), sin ([0,1]))
1007%!assert (cellfun ("sin", {0,1}), sin ([0,1]))
1008%!assert (cellfun ("isempty", {1,[]}), [false,true])
1009%!assert (cellfun ("islogical", {false,pi}), [true,false])
1010%!assert (cellfun ("isnumeric", {false,pi,struct()}), [false,true,false])
1011%!assert (cellfun ("isreal", {1i,1}), [false,true])
1012%!assert (cellfun ("length", {zeros(2,2),1}), [2,1])
1013%!assert (cellfun ("prodofsize", {zeros(2,2),1}), [4,1])
1014%!assert (cellfun ("ndims", {zeros([2,2,2]),1}), [3,2])
1015%!assert (cellfun ("isclass", {zeros([2,2,2]),"test"}, "double"), [true,false])
1016%!assert (cellfun ("size", {zeros([1,2,3]),1}, 1), [1,1])
1017%!assert (cellfun ("size", {zeros([1,2,3]),1}, 2), [2,1])
1018%!assert (cellfun ("size", {zeros([1,2,3]),1}, 3), [3,1])
1019%!assert (cellfun (@atan2, {1,1}, {1,2}), [atan2(1,1), atan2(1,2)])
1020%!assert (cellfun (@atan2, {1,1}, {1,2},"UniformOutput", false), {atan2(1,1), atan2(1,2)})
1021%!assert (cellfun (@sin, {1,2;3,4}), sin ([1,2;3,4]))
1022%!assert (cellfun (@atan2, {1,1;1,1}, {1,2;1,2}), atan2 ([1,1;1,1],[1,2;1,2]))
1023%!error cellfun (@factorial, {-1,3})
1024%!assert (cellfun (@factorial,{-1,3},"ErrorHandler",@(x,y) NaN), [NaN,6])
1025%!assert (cellfun (@(x) x(2),{[1],[1,2]},"ErrorHandler",@(x,y) NaN), [NaN,2])
1026%!test
1027%! [a,b,c] = cellfun (@fileparts, {fullfile("a","b","c.d"), fullfile("e","f","g.h")}, "UniformOutput", false);
1028%! assert (a, {fullfile("a","b"), fullfile("e","f")});
1029%! assert (b, {"c", "g"});
1030%! assert (c, {".d", ".h"});
1031
1032%!error cellfun (1)
1033%!error cellfun ("isclass", 1)
1034%!error cellfun ("size", 1)
1035%!error cellfun (@sin, {[]}, "BadParam", false)
1036%!error cellfun (@sin, {[]}, "UniformOuput")
1037%!error cellfun (@sin, {[]}, "ErrorHandler")
1038*/
1039
1040// Arrayfun was originally a .m file written by Bill Denney and Jaroslav
1041// Hajek. It was converted to C++ by jwe so that it could properly
1042// handle the nargout = 0 case.
1043
1044DEFUN (arrayfun, args, nargout,octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1045 "-*- texinfo -*-\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1046@deftypefn {Function File} {} arrayfun (@var{func}, @var{A})\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1047@deftypefnx {Function File} {@var{x} =} arrayfun (@var{func}, @var{A})\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1048@deftypefnx {Function File} {@var{x} =} arrayfun (@var{func}, @var{A}, @var{b}, @dots{})\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1049@deftypefnx {Function File} {[@var{x}, @var{y}, @dots{}] =} arrayfun (@var{func}, @var{A}, @dots{})\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1050@deftypefnx {Function File} {} arrayfun (@dots{}, \"UniformOutput\", @var{val})\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1051@deftypefnx {Function File} {} arrayfun (@dots{}, \"ErrorHandler\", @var{errfunc})\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1052\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1053Execute a function on each element of an array. This is useful for\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1054functions that do not accept array arguments. If the function does\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1055accept array arguments it is better to call the function directly.\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1056\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1057The first input argument @var{func} can be a string, a function\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1058handle, an inline function, or an anonymous function. The input\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1059argument @var{A} can be a logic array, a numeric array, a string\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1060array, a structure array, or a cell array. By a call of the function\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1061@command{arrayfun} all elements of @var{A} are passed on to the named\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1062function @var{func} individually.\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1063\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1064The named function can also take more than two input arguments, with\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1065the input arguments given as third input argument @var{b}, fourth\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1066input argument @var{c}, @dots{} If given more than one array input\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1067argument then all input arguments must have the same sizes, for\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1068example:\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1069\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1070@example\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1071@group\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1072arrayfun (@@atan2, [1, 0], [0, 1])\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1073 @result{} [ 1.5708 0.0000 ]\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1074@end group\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1075@end example\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1076\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1077If the parameter @var{val} after a further string input argument\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1078@qcode{\"UniformOutput\"} is set @code{true} (the default), then the named\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1079function @var{func} must return a single element which then will be\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1080concatenated into the return value and is of type matrix. Otherwise,\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1081if that parameter is set to @code{false}, then the outputs are\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1082concatenated in a cell array. For example:\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1083\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1084@example\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1085@group\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1086arrayfun (@@(x,y) x:y, \"abc\", \"def\", \"UniformOutput\", false)\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1087@result{}\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1088 @{\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1089 [1,1] = abcd\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1090 [1,2] = bcde\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1091 [1,3] = cdef\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1092 @}\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1093@end group\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1094@end example\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1095\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1096If more than one output arguments are given then the named function\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1097must return the number of return values that also are expected, for\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1098example:\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1099\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1100@example\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1101@group\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1102[A, B, C] = arrayfun (@@find, [10; 0], \"UniformOutput\", false)\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1103@result{}\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1104A =\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1105@{\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1106 [1,1] = 1\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1107 [2,1] = [](0x0)\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1108@}\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1109B =\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1110@{\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1111 [1,1] = 1\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1112 [2,1] = [](0x0)\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1113@}\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1114C =\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1115@{\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1116 [1,1] = 10\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1117 [2,1] = [](0x0)\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1118@}\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1119@end group\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1120@end example\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1121\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1122If the parameter @var{errfunc} after a further string input argument\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1123@qcode{\"ErrorHandler\"} is another string, a function handle, an inline\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1124function, or an anonymous function, then @var{errfunc} defines a\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1125function to call in the case that @var{func} generates an error.\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1126The definition of the function must be of the form\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1127\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1128@example\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1129function [@dots{}] = errfunc (@var{s}, @dots{})\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1130@end example\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1131\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1132@noindent\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1133where there is an additional input argument to @var{errfunc}\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1134relative to @var{func}, given by @var{s}. This is a structure with\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1135the elements @qcode{\"identifier\"}, @qcode{\"message\"}, and\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1136@qcode{\"index\"} giving, respectively, the error identifier, the error\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1137message, and the index of the array elements that caused the error. The\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1138size of the output argument of @var{errfunc} must have the same size as the\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1139output argument of @var{func}, otherwise a real error is thrown. For\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1140example:\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1141\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1142@example\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1143@group\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1144function y = ferr (s, x), y = \"MyString\"; endfunction\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1145arrayfun (@@str2num, [1234],\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1146 \"UniformOutput\", false, \"ErrorHandler\", @@ferr)\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1147@result{}\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1148 @{\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1149 [1,1] = MyString\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1150 @}\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1151@end group\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1152@end example\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1153\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1154@seealso{spfun, cellfun, structfun}\n\octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1155@end deftypefn")octave_value_list Farrayfun (const octave_value_list& args
, int nargout)
1156{
1157 octave_value_list retval;
1158 int nargin = args.length ();
1159 int nargout1 = (nargout < 1 ? 1 : nargout);
1160
1161 if (nargin < 2)
1162 {
1163 error_with_id ("Octave:invalid-fun-call",
1164 "arrayfun: function requires at least 2 arguments");
1165 print_usage ();
1166 return retval;
1167 }
1168
1169 octave_value func = args(0);
1170 bool symbol_table_lookup = false;
1171
1172 if (func.is_string ())
1173 {
1174 // See if we can convert the string into a function.
1175
1176 std::string name = args(0).string_value ();
1177
1178 if (! valid_identifier (name))
1179 {
1180 std::string fcn_name = unique_symbol_name ("__arrayfun_fcn_");
1181 std::string fname = "function y = " + fcn_name + "(x) y = ";
1182
1183 octave_function *ptr_func
1184 = extract_function (args(0), "arrayfun", fcn_name,
1185 fname, "; endfunction");
1186
1187 if (ptr_func && ! error_state)
1188 func = octave_value (ptr_func, true);
1189 }
1190 else
1191 {
1192 func = symbol_table::find_function (name);
1193
1194 if (func.is_undefined ())
1195 error_with_id ("Octave:invalid-input-arg",
1196 "arrayfun: invalid function NAME: %s",
1197 name.c_str ());
1198
1199 symbol_table_lookup = true;
1200 }
1201
1202 if (error_state)
1203 return retval;
1204 }
1205
1206 if (func.is_function_handle () || func.is_inline_function ()
1207 || func.is_function ())
1208 {
1209 // The following is an optimisation because the symbol table can
1210 // give a more specific function class, so this can result in
1211 // fewer polymorphic function calls as the function gets called
1212 // for each value of the array.
1213
1214 if (! symbol_table_lookup )
1215 {
1216 if (func.is_function_handle ())
1217 {
1218 octave_fcn_handle* f = func.fcn_handle_value ();
1219
1220 // Overloaded function handles need to check the type of
1221 // the arguments for each element of the array, so they
1222 // cannot be optimised this way.
1223
1224 if (f -> is_overloaded ())
1225 goto nevermind;
1226 }
1227 octave_value f = symbol_table::find_function (func.function_value ()
1228 -> name ());
1229 if (f.is_defined ())
1230 func = f;
1231 }
1232
1233 nevermind:
1234
1235 bool uniform_output = true;
1236 octave_value error_handler;
1237
1238 get_mapper_fun_options (args, nargin, uniform_output, error_handler);
1239
1240 if (error_state)
1241 return octave_value_list ();
1242
1243 octave_value_list inputlist (nargin, octave_value ());
1244
1245 OCTAVE_LOCAL_BUFFER (octave_value, inputs, nargin)octave_local_buffer<octave_value> _buffer_inputs (nargin
); octave_value *inputs = _buffer_inputs
;
1246 OCTAVE_LOCAL_BUFFER (bool, mask, nargin)octave_local_buffer<bool> _buffer_mask (nargin); bool *
mask = _buffer_mask
;
1247
1248 octave_idx_type k = 1;
1249
1250 dim_vector fdims (1, 1);
1251
1252 // Collect arguments. Pre-fill scalar elements of inputlist
1253 // array.
1254
1255 for (int j = 0; j < nargin; j++)
1256 {
1257 inputs[j] = args(j+1);
1258 mask[j] = inputs[j].numel () != 1;
1259
1260 if (! mask[j])
1261 inputlist(j) = inputs[j];
1262 }
1263
1264 for (int j = 0; j < nargin; j++)
1265 {
1266 if (mask[j])
1267 {
1268 fdims = inputs[j].dims ();
1269 k = inputs[j].numel ();
1270
1271 for (int i = j+1; i < nargin; i++)
1272 {
1273 if (mask[i] && inputs[i].dims () != fdims)
1274 {
1275 error_with_id ("Octave:invalid-input-arg",
1276 "arrayfun: dimensions mismatch");
1277 return retval;
1278 }
1279 }
1280 break;
1281 }
1282 }
1283
1284
1285 unwind_protect frame;
1286 frame.protect_var (buffer_error_messages);
1287
1288 if (error_handler.is_defined ())
1289 buffer_error_messages++;
1290
1291 // Apply functions.
1292
1293 if (uniform_output)
1294 {
1295 std::list<octave_value_list> idx_list (1);
1296 idx_list.front ().resize (1);
1297 std::string idx_type = "(";
1298
1299 OCTAVE_LOCAL_BUFFER (octave_value, retv, nargout1)octave_local_buffer<octave_value> _buffer_retv (nargout1
); octave_value *retv = _buffer_retv
;
1300
1301 for (octave_idx_type count = 0; count < k; count++)
1302 {
1303 idx_list.front ()(0) = count + 1.0;
1304
1305 for (int j = 0; j < nargin; j++)
1306 {
1307 if (mask[j])
1308 inputlist.xelem (j) = inputs[j].do_index_op (idx_list);
1309
1310 if (error_state)
1311 return retval;
1312 }
1313
1314 const octave_value_list tmp
1315 = get_output_list (count, nargout, inputlist, func,
1316 error_handler);
1317
1318 if (error_state)
1319 return retval;
1320
1321 if (nargout > 0 && tmp.length () < nargout)
1322 {
1323 error_with_id ("Octave:invalid-fun-call",
1324 "arrayfun: function returned fewer than nargout values");
1325 return retval;
1326 }
1327
1328 if (nargout > 0
1329 || (nargout == 0
1330 && tmp.length () > 0 && tmp(0).is_defined ()))
1331 {
1332 int num_to_copy = tmp.length ();
1333
1334 if (num_to_copy > nargout1)
1335 num_to_copy = nargout1;
1336
1337 if (count == 0)
1338 {
1339 for (int j = 0; j < num_to_copy; j++)
1340 {
1341 if (tmp(j).is_defined ())
1342 {
1343 octave_value val = tmp(j);
1344
1345 if (val.numel () == 1)
1346 retv[j] = val.resize (fdims);
1347 else
1348 {
1349 error_with_id ("Octave:invalid-fun-call",
1350 "arrayfun: all values must be scalars when UniformOutput = true");
1351 break;
1352 }
1353 }
1354 }
1355 }
1356 else
1357 {
1358 for (int j = 0; j < num_to_copy; j++)
1359 {
1360 if (tmp(j).is_defined ())
1361 {
1362 octave_value val = tmp(j);
1363
1364 if (! retv[j].fast_elem_insert (count, val))
1365 {
1366 if (val.numel () == 1)
1367 {
1368 idx_list.front ()(0) = count + 1.0;
1369 retv[j].assign (octave_value::op_asn_eq,
1370 idx_type, idx_list, val);
1371
1372 if (error_state)
1373 break;
1374 }
1375 else
1376 {
1377 error_with_id ("Octave:invalid-fun-call",
1378 "arrayfun: all values must be scalars when UniformOutput = true");
1379 break;
1380 }
1381 }
1382 }
1383 }
1384 }
1385 }
1386
1387 if (error_state)
1388 break;
1389 }
1390
1391 retval.resize (nargout1);
1392
1393 for (int j = 0; j < nargout1; j++)
1394 {
1395 if (nargout > 0 && retv[j].is_undefined ())
1396 retval(j) = NDArray (fdims);
1397 else
1398 retval(j) = retv[j];
1399 }
1400 }
1401 else
1402 {
1403 std::list<octave_value_list> idx_list (1);
1404 idx_list.front ().resize (1);
1405 std::string idx_type = "(";
1406
1407 OCTAVE_LOCAL_BUFFER (Cell, results, nargout1)octave_local_buffer<Cell> _buffer_results (nargout1); Cell
*results = _buffer_results
;
1408
1409 for (int j = 0; j < nargout1; j++)
1410 results[j].resize (fdims, Matrix ());
1411
1412 bool have_some_output = false;
1413
1414 for (octave_idx_type count = 0; count < k; count++)
1415 {
1416 idx_list.front ()(0) = count + 1.0;
1417
1418 for (int j = 0; j < nargin; j++)
1419 {
1420 if (mask[j])
1421 inputlist.xelem (j) = inputs[j].do_index_op (idx_list);
1422
1423 if (error_state)
1424 return retval;
1425 }
1426
1427 const octave_value_list tmp
1428 = get_output_list (count, nargout, inputlist, func,
1429 error_handler);
1430
1431 if (error_state)
1432 return retval;
1433
1434 if (nargout > 0 && tmp.length () < nargout)
1435 {
1436 error_with_id ("Octave:invalid-fun-call",
1437 "arrayfun: function returned fewer than nargout values");
1438 return retval;
1439 }
1440
1441 if (nargout > 0
1442 || (nargout == 0
1443 && tmp.length () > 0 && tmp(0).is_defined ()))
1444 {
1445 int num_to_copy = tmp.length ();
1446
1447 if (num_to_copy > nargout1)
1448 num_to_copy = nargout1;
1449
1450 if (num_to_copy > 0)
1451 have_some_output = true;
1452
1453 for (int j = 0; j < num_to_copy; j++)
1454 results[j](count) = tmp(j);
1455 }
1456 }
1457
1458 if (have_some_output || fdims.any_zero ())
1459 {
1460 retval.resize (nargout1);
1461
1462 for (int j = 0; j < nargout1; j++)
1463 retval(j) = results[j];
1464 }
1465 }
1466 }
1467 else
1468 error_with_id ("Octave:invalid-fun-call",
1469 "arrayfun: argument NAME must be a string or function handle");
1470
1471 return retval;
1472}
1473
1474/*
1475%!function r = __f11 (x)
1476%! global __arrayfun_test_num_outputs__;
1477%! __arrayfun_test_num_outputs__ = nargout;
1478%! r = x;
1479%!endfunction
1480
1481%!function __f01 (x)
1482%! global __arrayfun_test_num_outputs__;
1483%! __arrayfun_test_num_outputs__ = nargout;
1484%!endfunction
1485
1486%!test
1487%! global __arrayfun_test_num_outputs__;
1488%! arrayfun (@__f11, {1});
1489%! assert (__arrayfun_test_num_outputs__, 0);
1490%! x = arrayfun (@__f11, {1});
1491%! assert (__arrayfun_test_num_outputs__, 1);
1492
1493%!test
1494%! global __arrayfun_test_num_outputs__;
1495%! arrayfun (@__f01, {1});
1496%! assert (__arrayfun_test_num_outputs__, 0);
1497
1498%!error x = arrayfun (@__f01, [1, 2]);
1499
1500%!test
1501%! assert (arrayfun (@__f11, [1, 2]), [1, 2]);
1502%! assert (arrayfun (@__f11, [1, 2], "uniformoutput", false), {1, 2});
1503%! assert (arrayfun (@__f11, {1, 2}), {1, 2});
1504%! assert (arrayfun (@__f11, {1, 2}, "uniformoutput", false), {{1}, {2}});
1505
1506%!assert (arrayfun (@ones, 1, [2,3], "uniformoutput", false), {[1,1], [1,1,1]})
1507
1508%% Test function to check the "Errorhandler" option
1509%!function z = __arrayfunerror (S, varargin)
1510%! z = S;
1511%!endfunction
1512%% First input argument can be a string, an inline function, a
1513%% function_handle or an anonymous function
1514%!test
1515%! arrayfun (@isequal, [false, true], [true, true]); %% No output argument
1516%!error
1517%! arrayfun (@isequal); %% One or less input arguments
1518%!test
1519%! A = arrayfun ("isequal", [false, true], [true, true]);
1520%! assert (A, [false, true]);
1521%!test
1522%! A = arrayfun (inline ("(x == y)", "x", "y"), [false, true], [true, true]);
1523%! assert (A, [false, true]);
1524%!test
1525%! A = arrayfun (@isequal, [false, true], [true, true]);
1526%! assert (A, [false, true]);
1527%!test
1528%! A = arrayfun (@(x,y) isequal (x,y), [false, true], [true, true]);
1529%! assert (A, [false, true]);
1530
1531%% Number of input and output arguments may be greater than one
1532%#!test
1533%! A = arrayfun (@(x) islogical (x), false);
1534%! assert (A, true);
1535%!test
1536%! A = arrayfun (@(x,y,z) x + y + z, [1, 1, 1], [2, 2, 2], [3, 4, 5]);
1537%! assert (A, [6, 7, 8], 1e-16);
1538%!test %% Two input arguments of different types
1539%! A = arrayfun (@(x,y) islogical (x) && ischar (y), false, "a");
1540%! assert (A, true);
1541%!test %% Pass another variable to the anonymous function
1542%! y = true;
1543%! A = arrayfun (@(x) islogical (x && y), false);
1544%! assert (A, true);
1545%!test %% Three ouptut arguments of different type
1546%! [A, B, C] = arrayfun (@find, [10, 11; 0, 12], "UniformOutput", false);
1547%! assert (isequal (A, {true, true; [], true}));
1548%! assert (isequal (B, {true, true; [], true}));
1549%! assert (isequal (C, {10, 11; [], 12}));
1550
1551%% Input arguments can be of type logical
1552%!test
1553%! A = arrayfun (@(x,y) x == y, [false, true], [true, true]);
1554%! assert (A, [false, true]);
1555%!test
1556%! A = arrayfun (@(x,y) x == y, [false; true], [true; true], "UniformOutput", true);
1557%! assert (A, [false; true]);
1558%!test
1559%! A = arrayfun (@(x) x, [false, true, false, true], "UniformOutput", false);
1560%! assert (A, {false, true, false, true});
1561%!test %% Three ouptut arguments of same type
1562%! [A, B, C] = arrayfun (@find, [true, false; false, true], "UniformOutput", false);
1563%! assert (isequal (A, {true, []; [], true}));
1564%! assert (isequal (B, {true, []; [], true}));
1565%! assert (isequal (C, {true, []; [], true}));
1566%!test
1567%! A = arrayfun (@(x,y) array2str (x,y), true, true, ...
1568%! "ErrorHandler", @__arrayfunerror);
1569%! assert (isfield (A, "identifier"), true);
1570%! assert (isfield (A, "message"), true);
1571%! assert (isfield (A, "index"), true);
1572%! assert (isempty (A.message), false);
1573%! assert (A.index, 1);
1574%!test %% Overwriting setting of "UniformOutput" true
1575%! A = arrayfun (@(x,y) array2str (x,y), true, true, "UniformOutput", true, ...
1576%! "ErrorHandler", @__arrayfunerror);
1577%! assert (isfield (A, "identifier"), true);
1578%! assert (isfield (A, "message"), true);
1579%! assert (isfield (A, "index"), true);
1580%! assert (isempty (A.message), false);
1581%! assert (A.index, 1);
1582
1583%% Input arguments can be of type numeric
1584%!test
1585%! A = arrayfun (@(x,y) x>y, [1.1, 4.2], [3.1, 2+3*i]);
1586%! assert (A, [false, true]);
1587%!test
1588%! A = arrayfun (@(x,y) x>y, [1.1, 4.2; 2, 4], [3.1, 2; 2, 4+2*i], "UniformOutput", true);
1589%! assert (A, [false, true; false, false]);
1590%!test
1591%! A = arrayfun (@(x,y) x:y, [1.1, 4], [3.1, 6], "UniformOutput", false);
1592%! assert (isequal (A{1}, [1.1, 2.1, 3.1]));
1593%! assert (isequal (A{2}, [4, 5, 6]));
1594%!test %% Three ouptut arguments of different type
1595%! [A, B, C] = arrayfun (@find, [10, 11; 0, 12], "UniformOutput", false);
1596%! assert (isequal (A, {true, true; [], true}));
1597%! assert (isequal (B, {true, true; [], true}));
1598%! assert (isequal (C, {10, 11; [], 12}));
1599%!test
1600%! A = arrayfun (@(x,y) array2str (x,y), {1.1, 4}, {3.1, 6}, ...
1601%! "ErrorHandler", @__arrayfunerror);
1602%! B = isfield (A(1), "message") && isfield (A(1), "index");
1603%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]);
1604%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]);
1605%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]);
1606%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]);
1607%! assert ([A(1).index, A(2).index], [1, 2]);
1608%!test %% Overwriting setting of "UniformOutput" true
1609%! A = arrayfun (@(x,y) array2str (x,y), {1.1, 4}, {3.1, 6}, ...
1610%! "UniformOutput", true, "ErrorHandler", @__arrayfunerror);
1611%! B = isfield (A(1), "message") && isfield (A(1), "index");
1612%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]);
1613%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]);
1614%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]);
1615%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]);
1616%! assert ([A(1).index, A(2).index], [1, 2]);
1617
1618%% Input arguments can be of type character or strings
1619%!test
1620%! A = arrayfun (@(x,y) x>y, ["ad", "c", "ghi"], ["cc", "d", "fgh"]);
1621%! assert (A, [false, true, false, true, true, true]);
1622%!test
1623%! A = arrayfun (@(x,y) x>y, ["a"; "f"], ["c"; "d"], "UniformOutput", true);
1624%! assert (A, [false; true]);
1625%!test
1626%! A = arrayfun (@(x,y) x:y, ["a", "d"], ["c", "f"], "UniformOutput", false);
1627%! assert (A, {"abc", "def"});
1628%!test
1629%! A = arrayfun (@(x,y) cell2str (x,y), ["a", "d"], ["c", "f"], ...
1630%! "ErrorHandler", @__arrayfunerror);
1631%! B = isfield (A(1), "identifier") && isfield (A(1), "message") && isfield (A(1), "index");
1632%! assert (B, true);
1633
1634%% Input arguments can be of type structure
1635%!test
1636%! a = struct ("a", 1.1, "b", 4.2); b = struct ("a", 3.1, "b", 2);
1637%! A = arrayfun (@(x,y) (x.a < y.a) && (x.b > y.b), a, b);
1638%! assert (A, true);
1639%!test
1640%! a = struct ("a", 1.1, "b", 4.2); b = struct ("a", 3.1, "b", 2);
1641%! A = arrayfun (@(x,y) (x.a < y.a) && (x.b > y.b), a, b, "UniformOutput", true);
1642%! assert (A, true);
1643%!test
1644%! a = struct ("a", 1.1, "b", 4.2); b = struct ("a", 3.1, "b", 2);
1645%! A = arrayfun (@(x,y) x.a:y.a, a, b, "UniformOutput", false);
1646%! assert (isequal (A, {[1.1, 2.1, 3.1]}));
1647%!test
1648%! A = arrayfun (@(x) mat2str(x), "a", "ErrorHandler", @__arrayfunerror);
1649%! assert (isfield (A, "identifier"), true);
1650%! assert (isfield (A, "message"), true);
1651%! assert (isfield (A, "index"), true);
1652%! assert (isempty (A.message), false);
1653%! assert (A.index, 1);
1654%!test %% Overwriting setting of "UniformOutput" true
1655%! A = arrayfun (@(x) mat2str(x), "a", "UniformOutput", true, ...
1656%! "ErrorHandler", @__arrayfunerror);
1657%! assert (isfield (A, "identifier"), true);
1658%! assert (isfield (A, "message"), true);
1659%! assert (isfield (A, "index"), true);
1660%! assert (isempty (A.message), false);
1661%! assert (A.index, 1);
1662
1663%% Input arguments can be of type cell array
1664%!test
1665%! A = arrayfun (@(x,y) x{1} < y{1}, {1.1, 4.2}, {3.1, 2});
1666%! assert (A, [true, false]);
1667%!test
1668%! A = arrayfun (@(x,y) x{1} < y{1}, {1.1; 4.2}, {3.1; 2}, "UniformOutput", true);
1669%! assert (A, [true; false]);
1670%!test
1671%! A = arrayfun (@(x,y) x{1} < y{1}, {1.1, 4.2}, {3.1, 2}, "UniformOutput", false);
1672%! assert (A, {true, false});
1673%!test
1674%! A = arrayfun (@(x,y) num2str(x,y), {1.1, 4.2}, {3.1, 2}, "ErrorHandler", @__arrayfunerror);
1675%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]);
1676%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]);
1677%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]);
1678%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]);
1679%! assert ([A(1).index, A(2).index], [1, 2]);
1680%!test
1681%! A = arrayfun (@(x,y) num2str (x,y), {1.1, 4.2}, {3.1, 2}, ...
1682%! "UniformOutput", true, "ErrorHandler", @__arrayfunerror);
1683%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]);
1684%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]);
1685%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]);
1686%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]);
1687%! assert ([A(1).index, A(2).index], [1, 2]);
1688*/
1689
1690static void
1691do_num2cell_helper (const dim_vector& dv,
1692 const Array<int>& dimv,
1693 dim_vector& celldv, dim_vector& arraydv,
1694 Array<int>& perm)
1695{
1696 int dvl = dimv.length ();
1697 int maxd = dv.length ();
1698 celldv = dv;
1699 for (int i = 0; i < dvl; i++)
1700 maxd = std::max (maxd, dimv(i));
1701 if (maxd > dv.length ())
1702 celldv.resize (maxd, 1);
1703 arraydv = celldv;
1704
1705 OCTAVE_LOCAL_BUFFER_INIT (bool, sing, maxd, false)octave_local_buffer<bool> _buffer_sing (maxd); bool *sing
= _buffer_sing; for (size_t _buf_iter = 0, _buf_size = maxd;
_buf_iter < _buf_size; _buf_iter++) sing[_buf_iter] = false
;
1706
1707 perm.clear (maxd, 1);
1708 for (int i = 0; i < dvl; i++)
1709 {
1710 int k = dimv(i) - 1;
1711 if (k < 0)
1712 {
1713 error ("num2cell: dimension indices must be positive");
1714 return;
1715 }
1716 else if (i > 0 && k < dimv(i-1) - 1)
1717 {
1718 error ("num2cell: dimension indices must be strictly increasing");
1719 return;
1720 }
1721
1722 sing[k] = true;
1723 perm(i) = k;
1724 }
1725
1726 for (int k = 0, i = dvl; k < maxd; k++)
1727 if (! sing[k])
1728 perm(i++) = k;
1729
1730 for (int i = 0; i < maxd; i++)
1731 if (sing[i])
1732 celldv(i) = 1;
1733 else
1734 arraydv(i) = 1;
1735}
1736
1737template<class NDA>
1738static inline typename NDA::element_type
1739do_num2cell_elem (const NDA& array, octave_idx_type i)
1740{ return array(i); }
1741
1742static inline Cell
1743do_num2cell_elem (const Cell& array, octave_idx_type i)
1744{ return Cell (array(i)); }
1745
1746
1747template<class NDA>
1748static Cell
1749do_num2cell (const NDA& array, const Array<int>& dimv)
1750{
1751 if (dimv.is_empty ())
1752 {
1753 Cell retval (array.dims ());
1754 octave_idx_type nel = array.numel ();
1755 for (octave_idx_type i = 0; i < nel; i++)
1756 retval.xelem (i) = do_num2cell_elem (array, i);
1757
1758 return retval;
1759 }
1760 else
1761 {
1762 dim_vector celldv, arraydv;
1763 Array<int> perm;
1764 do_num2cell_helper (array.dims (), dimv, celldv, arraydv, perm);
1765 if (error_state)
1766 return Cell ();
1767
1768 NDA parray = array.permute (perm);
1769
1770 octave_idx_type nela = arraydv.numel (), nelc = celldv.numel ();
1771 parray = parray.reshape (dim_vector (nela, nelc));
1772
1773 Cell retval (celldv);
1774 for (octave_idx_type i = 0; i < nelc; i++)
1775 {
1776 retval.xelem (i) = NDA (parray.column (i).reshape (arraydv));
1777 }
1778
1779 return retval;
1780 }
1781}
1782
1783// FIXME: this is a mess, but if a size method for the object exists,
1784// we have to call it to get the size of the object instead of using the
1785// internal dims method.
1786
1787static dim_vector
1788get_object_dims (octave_value& obj)
1789{
1790 dim_vector retval;
1791
1792 Matrix m = obj.size ();
1793
1794 int n = m.numel ();
1795
1796 retval.resize (n);
1797
1798 for (int i = 0; i < n; i++)
1799 retval(i) = m(i);
1800
1801 return retval;
1802}
1803
1804static Cell
1805do_object2cell (const octave_value& obj, const Array<int>& dimv)
1806{
1807 Cell retval;
1808
1809 // FIXME: this copy is only needed because the octave_value::size
1810 // method is not const.
1811 octave_value array = obj;
1812
1813 if (dimv.is_empty ())
1814 {
1815 dim_vector dv = get_object_dims (array);
1816
1817 if (! error_state)
1818 {
1819 retval.resize (dv);
1820
1821 octave_value_list idx (1);
1822
1823 for (octave_idx_type i = 0; i < dv.numel (); i++)
1824 {
1825 octave_quit ();
1826
1827 idx(0) = double (i+1);
1828
1829 retval.xelem (i) = array.single_subsref ("(", idx);
1830
1831 if (error_state)
1832 break;
1833 }
1834 }
1835 }
1836 else
1837 {
1838 error ("num2cell (A, dim) not implemented for class objects");
1839 }
1840
1841 return retval;
1842}
1843
1844DEFUN (num2cell, args, ,octave_value_list Fnum2cell (const octave_value_list& args
, int )
1845 "-*- texinfo -*-\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1846@deftypefn {Built-in Function} {@var{C} =} num2cell (@var{A})\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1847@deftypefnx {Built-in Function} {@var{C} =} num2cell (@var{A}, @var{dim})\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1848Convert the numeric matrix @var{A} to a cell array. If @var{dim} is\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1849defined, the value @var{C} is of dimension 1 in this dimension and the\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1850elements of @var{A} are placed into @var{C} in slices. For example:\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1851\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1852@example\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1853@group\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1854num2cell ([1,2;3,4])\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1855 @result{}\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1856 @{\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1857 [1,1] = 1\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1858 [2,1] = 3\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1859 [1,2] = 2\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1860 [2,2] = 4\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1861 @}\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1862num2cell ([1,2;3,4],1)\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1863 @result{}\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1864 @{\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1865 [1,1] =\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1866 1\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1867 3\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1868 [1,2] =\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1869 2\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1870 4\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1871 @}\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1872@end group\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1873@end example\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1874\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1875@seealso{mat2cell}\n\octave_value_list Fnum2cell (const octave_value_list& args
, int )
1876@end deftypefn")octave_value_list Fnum2cell (const octave_value_list& args
, int )
1877{
1878 int nargin = args.length ();
1879 octave_value retval;
1880
1881 if (nargin < 1 || nargin > 2)
1882 print_usage ();
1883 else
1884 {
1885 octave_value array = args(0);
1886 Array<int> dimv;
1887 if (nargin > 1)
1888 dimv = args (1).int_vector_value (true);
1889
1890 if (error_state)
1891 ;
1892 else if (array.is_bool_type ())
1893 retval = do_num2cell (array.bool_array_value (), dimv);
1894 else if (array.is_char_matrix ())
1895 retval = do_num2cell (array.char_array_value (), dimv);
1896 else if (array.is_numeric_type ())
1897 {
1898 if (array.is_integer_type ())
1899 {
1900 if (array.is_int8_type ())
1901 retval = do_num2cell (array.int8_array_value (), dimv);
1902 else if (array.is_int16_type ())
1903 retval = do_num2cell (array.int16_array_value (), dimv);
1904 else if (array.is_int32_type ())
1905 retval = do_num2cell (array.int32_array_value (), dimv);
1906 else if (array.is_int64_type ())
1907 retval = do_num2cell (array.int64_array_value (), dimv);
1908 else if (array.is_uint8_type ())
1909 retval = do_num2cell (array.uint8_array_value (), dimv);
1910 else if (array.is_uint16_type ())
1911 retval = do_num2cell (array.uint16_array_value (), dimv);
1912 else if (array.is_uint32_type ())
1913 retval = do_num2cell (array.uint32_array_value (), dimv);
1914 else if (array.is_uint64_type ())
1915 retval = do_num2cell (array.uint64_array_value (), dimv);
1916 }
1917 else if (array.is_complex_type ())
1918 {
1919 if (array.is_single_type ())
1920 retval = do_num2cell (array.float_complex_array_value (), dimv);
1921 else
1922 retval = do_num2cell (array.complex_array_value (), dimv);
1923 }
1924 else
1925 {
1926 if (array.is_single_type ())
1927 retval = do_num2cell (array.float_array_value (), dimv);
1928 else
1929 retval = do_num2cell (array.array_value (), dimv);
1930 }
1931 }
1932 else if (array.is_object ())
1933 retval = do_object2cell (array, dimv);
1934 else if (array.is_map ())
1935 retval = do_num2cell (array.map_value (), dimv);
1936 else if (array.is_cell ())
1937 retval = do_num2cell (array.cell_value (), dimv);
1938 else if (array.is_object ())
1939 retval = do_num2cell (array.cell_value (), dimv);
1940 else
1941 gripe_wrong_type_arg ("num2cell", array);
1942 }
1943
1944 return retval;
1945}
1946
1947/*
1948%!assert (num2cell ([1,2;3,4]), {1,2;3,4})
1949%!assert (num2cell ([1,2;3,4], 1), {[1;3],[2;4]})
1950%!assert (num2cell ([1,2;3,4], 2), {[1,2];[3,4]})
1951*/
1952
1953static bool
1954mat2cell_mismatch (const dim_vector& dv,
1955 const Array<octave_idx_type> *d, int nd)
1956{
1957 for (int i = 0; i < nd; i++)
1958 {
1959 octave_idx_type s = 0;
1960 for (octave_idx_type j = 0; j < d[i].length (); j++)
1961 s += d[i](j);
1962
1963 octave_idx_type r = i < dv.length () ? dv(i) : 1;
1964
1965 if (s != r)
1966 {
1967 error ("mat2cell: mismatch on %d-th dimension (%d != %d)",
1968 i+1, r, s);
1969 return true;
1970 }
1971 }
1972
1973 return false;
1974}
1975
1976template<class container>
1977static void
1978prepare_idx (container *idx, int idim, int nd,
1979 const Array<octave_idx_type>* d)
1980{
1981 octave_idx_type nidx = idim < nd ? d[idim].numel () : 1;
1982 if (nidx == 1)
1983 idx[0] = idx_vector::colon;
1984 else
1985 {
1986 octave_idx_type l = 0;
1987 for (octave_idx_type i = 0; i < nidx; i++)
1988 {
1989 octave_idx_type u = l + d[idim](i);
1990 idx[i] = idx_vector (l, u);
1991 l = u;
1992 }
1993 }
1994}
1995
1996// 2D specialization, works for Array, Sparse and octave_map.
1997// Uses 1D or 2D indexing.
1998
1999template <class Array2D>
2000static Cell
2001do_mat2cell_2d (const Array2D& a, const Array<octave_idx_type> *d, int nd)
2002{
2003 NoAlias<Cell> retval;
2004 assert (nd == 1 || nd == 2)((nd == 1 || nd == 2) ? static_cast<void> (0) : __assert_fail
("nd == 1 || nd == 2", "corefcn/cellfun.cc", 2004, __PRETTY_FUNCTION__
))
;
2005 assert (a.ndims () == 2)((a.ndims () == 2) ? static_cast<void> (0) : __assert_fail
("a.ndims () == 2", "corefcn/cellfun.cc", 2005, __PRETTY_FUNCTION__
))
;
2006
2007 if (mat2cell_mismatch (a.dims (), d, nd))
2008 return retval;
2009
2010 octave_idx_type nridx = d[0].length ();
2011 octave_idx_type ncidx = nd == 1 ? 1 : d[1].length ();
2012 retval.clear (nridx, ncidx);
2013
2014 int ivec = -1;
2015 if (a.rows () > 1 && a.cols () == 1 && ncidx == 1)
2016 ivec = 0;
2017 else if (a.rows () == 1 && nridx == 1 && nd == 2)
2018 ivec = 1;
2019
2020 if (ivec >= 0)
2021 {
2022 // Vector split. Use 1D indexing.
2023 octave_idx_type l = 0, nidx = (ivec == 0 ? nridx : ncidx);
2024 for (octave_idx_type i = 0; i < nidx; i++)
2025 {
2026 octave_idx_type u = l + d[ivec](i);
2027 retval(i) = a.index (idx_vector (l, u));
2028 l = u;
2029 }
2030 }
2031 else
2032 {
2033 // General 2D case. Use 2D indexing.
2034 OCTAVE_LOCAL_BUFFER (idx_vector, ridx, nridx)octave_local_buffer<idx_vector> _buffer_ridx (nridx); idx_vector
*ridx = _buffer_ridx
;
2035 prepare_idx (ridx, 0, nd, d);
2036
2037 OCTAVE_LOCAL_BUFFER (idx_vector, cidx, ncidx)octave_local_buffer<idx_vector> _buffer_cidx (ncidx); idx_vector
*cidx = _buffer_cidx
;
2038 prepare_idx (cidx, 1, nd, d);
2039
2040 for (octave_idx_type j = 0; j < ncidx; j++)
2041 for (octave_idx_type i = 0; i < nridx; i++)
2042 {
2043 octave_quit ();
2044
2045 retval(i,j) = a.index (ridx[i], cidx[j]);
2046 }
2047 }
2048
2049 return retval;
2050}
2051
2052// Nd case. Works for Arrays and octave_map.
2053// Uses Nd indexing.
2054
2055template <class ArrayND>
2056Cell
2057do_mat2cell_nd (const ArrayND& a, const Array<octave_idx_type> *d, int nd)
2058{
2059 NoAlias<Cell> retval;
2060 assert (nd >= 1)((nd >= 1) ? static_cast<void> (0) : __assert_fail (
"nd >= 1", "corefcn/cellfun.cc", 2060, __PRETTY_FUNCTION__
))
;
2061
2062 if (mat2cell_mismatch (a.dims (), d, nd))
2063 return retval;
2064
2065 dim_vector rdv = dim_vector::alloc (nd);
2066 OCTAVE_LOCAL_BUFFER (octave_idx_type, nidx, nd)octave_local_buffer<octave_idx_type> _buffer_nidx (nd);
octave_idx_type *nidx = _buffer_nidx
;
2067 octave_idx_type idxtot = 0;
2068 for (int i = 0; i < nd; i++)
2069 {
2070 rdv(i) = nidx[i] = d[i].length ();
2071 idxtot += nidx[i];
2072 }
2073
2074 retval.clear (rdv);
2075
2076 OCTAVE_LOCAL_BUFFER (idx_vector, xidx, idxtot)octave_local_buffer<idx_vector> _buffer_xidx (idxtot); idx_vector
*xidx = _buffer_xidx
;
2077 OCTAVE_LOCAL_BUFFER (idx_vector *, idx, nd)octave_local_buffer<idx_vector *> _buffer_idx (nd); idx_vector
* *idx = _buffer_idx
;
2078
2079 idxtot = 0;
2080 for (int i = 0; i < nd; i++)
2081 {
2082 idx[i] = xidx + idxtot;
2083 prepare_idx (idx[i], i, nd, d);
2084 idxtot += nidx[i];
2085 }
2086
2087 OCTAVE_LOCAL_BUFFER_INIT (octave_idx_type, ridx, nd, 0)octave_local_buffer<octave_idx_type> _buffer_ridx (nd);
octave_idx_type *ridx = _buffer_ridx; for (size_t _buf_iter =
0, _buf_size = nd; _buf_iter < _buf_size; _buf_iter++) ridx
[_buf_iter] = 0
;
2088 NoAlias< Array<idx_vector> > ra_idx
2089 (dim_vector (1, std::max (nd, a.ndims ())), idx_vector::colon);
2090
2091 for (octave_idx_type j = 0; j < retval.numel (); j++)
2092 {
2093 octave_quit ();
2094
2095 for (int i = 0; i < nd; i++)
2096 ra_idx(i) = idx[i][ridx[i]];
2097
2098 retval(j) = a.index (ra_idx);
2099
2100 rdv.increment_index (ridx);
2101 }
2102
2103 return retval;
2104}
2105
2106// Dispatcher.
2107template <class ArrayND>
2108Cell
2109do_mat2cell (const ArrayND& a, const Array<octave_idx_type> *d, int nd)
2110{
2111 if (a.ndims () == 2 && nd <= 2)
2112 return do_mat2cell_2d (a, d, nd);
2113 else
2114 return do_mat2cell_nd (a, d, nd);
2115}
2116
2117// General case. Works for any class supporting do_index_op.
2118// Uses Nd indexing.
2119
2120Cell
2121do_mat2cell (octave_value& a, const Array<octave_idx_type> *d, int nd)
2122{
2123 NoAlias<Cell> retval;
2124 assert (nd >= 1)((nd >= 1) ? static_cast<void> (0) : __assert_fail (
"nd >= 1", "corefcn/cellfun.cc", 2124, __PRETTY_FUNCTION__
))
;
2125
2126 if (mat2cell_mismatch (a.dims (), d, nd))
10
Taking false branch
2127 return retval;
2128
2129 dim_vector rdv = dim_vector::alloc (nd);
2130 OCTAVE_LOCAL_BUFFER (octave_idx_type, nidx, nd)octave_local_buffer<octave_idx_type> _buffer_nidx (nd);
octave_idx_type *nidx = _buffer_nidx
;
2131 octave_idx_type idxtot = 0;
2132 for (int i = 0; i < nd; i++)
11
Loop condition is true. Entering loop body
12
Loop condition is false. Execution continues on line 2138
2133 {
2134 rdv(i) = nidx[i] = d[i].length ();
2135 idxtot += nidx[i];
2136 }
2137
2138 retval.clear (rdv);
2139
2140 OCTAVE_LOCAL_BUFFER (octave_value, xidx, idxtot)octave_local_buffer<octave_value> _buffer_xidx (idxtot)
; octave_value *xidx = _buffer_xidx
;
2141 OCTAVE_LOCAL_BUFFER (octave_value *, idx, nd)octave_local_buffer<octave_value *> _buffer_idx (nd); octave_value
* *idx = _buffer_idx
;
2142
2143 idxtot = 0;
2144 for (int i = 0; i < nd; i++)
13
Loop condition is true. Entering loop body
14
Loop condition is false. Execution continues on line 2151
2145 {
2146 idx[i] = xidx + idxtot;
2147 prepare_idx (idx[i], i, nd, d);
2148 idxtot += nidx[i];
2149 }
2150
2151 OCTAVE_LOCAL_BUFFER_INIT (octave_idx_type, ridx, nd, 0)octave_local_buffer<octave_idx_type> _buffer_ridx (nd);
octave_idx_type *ridx = _buffer_ridx; for (size_t _buf_iter =
0, _buf_size = nd; _buf_iter < _buf_size; _buf_iter++) ridx
[_buf_iter] = 0
;
2152 octave_value_list ra_idx (std::max (nd, a.ndims ()),
2153 octave_value::magic_colon_t);
2154
2155 for (octave_idx_type j = 0; j < retval.numel (); j++)
15
Loop condition is true. Entering loop body
2156 {
2157 octave_quit ();
2158
2159 for (int i = 0; i < nd; i++)
16
Loop condition is true. Entering loop body
2160 ra_idx(i) = idx[i][ridx[i]];
17
Forming reference to null pointer
2161
2162 retval(j) = a.do_index_op (ra_idx);
2163
2164 if (error_state)
2165 break;
2166
2167 rdv.increment_index (ridx);
2168 }
2169
2170 return retval;
2171}
2172
2173DEFUN (mat2cell, args, ,octave_value_list Fmat2cell (const octave_value_list& args
, int )
2174 "-*- texinfo -*-\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2175@deftypefn {Built-in Function} {@var{C} =} mat2cell (@var{A}, @var{m}, @var{n})\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2176@deftypefnx {Built-in Function} {@var{C} =} mat2cell (@var{A}, @var{d1}, @var{d2}, @dots{})\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2177@deftypefnx {Built-in Function} {@var{C} =} mat2cell (@var{A}, @var{r})\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2178Convert the matrix @var{A} to a cell array. If @var{A} is 2-D, then\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2179it is required that @code{sum (@var{m}) == size (@var{A}, 1)} and\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2180@code{sum (@var{n}) == size (@var{A}, 2)}. Similarly, if @var{A} is\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2181multi-dimensional and the number of dimensional arguments is equal\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2182to the dimensions of @var{A}, then it is required that @code{sum (@var{di})\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2183== size (@var{A}, i)}.\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2184\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2185Given a single dimensional argument @var{r}, the other dimensional\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2186arguments are assumed to equal @code{size (@var{A},@var{i})}.\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2187\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2188An example of the use of mat2cell is\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2189\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2190@example\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2191mat2cell (reshape (1:16,4,4), [3,1], [3,1])\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2192@result{}\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2193@{\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2194 [1,1] =\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2195\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2196 1 5 9\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2197 2 6 10\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2198 3 7 11\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2199\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2200 [2,1] =\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2201\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2202 4 8 12\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2203\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2204 [1,2] =\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2205\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2206 13\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2207 14\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2208 15\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2209\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2210 [2,2] = 16\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2211@}\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2212@end example\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2213@seealso{num2cell, cell2mat}\n\octave_value_list Fmat2cell (const octave_value_list& args
, int )
2214@end deftypefn")octave_value_list Fmat2cell (const octave_value_list& args
, int )
2215{
2216 int nargin = args.length ();
2217 octave_value retval;
2218
2219 if (nargin < 2)
1
Assuming 'nargin' is >= 2
2
Taking false branch
2220 print_usage ();
2221 else
2222 {
2223 // Prepare indices.
2224 OCTAVE_LOCAL_BUFFER (Array<octave_idx_type>, d, nargin-1)octave_local_buffer<Array<octave_idx_type> > _buffer_d
(nargin-1); Array<octave_idx_type> *d = _buffer_d
;
2225
2226 for (int i = 1; i < nargin; i++)
3
Loop condition is true. Entering loop body
6
Assuming 'i' is >= 'nargin'
7
Loop condition is false. Execution continues on line 2233
2227 {
2228 d[i-1] = args(i).octave_idx_type_vector_value (true);
2229 if (error_state)
4
Assuming 'error_state' is 0
5
Taking false branch
2230 return retval;
2231 }
2232
2233 octave_value a = args(0);
2234 bool sparse = a.is_sparse_type ();
2235 if (sparse && nargin > 3)
2236 {
2237 error ("mat2cell: sparse arguments only support 2-D indexing");
2238 return retval;
2239 }
2240
2241 switch (a.builtin_type ())
8
Control jumps to the 'default' case at line 2286
2242 {
2243 case btyp_double:
2244 {
2245 if (sparse)
2246 retval = do_mat2cell_2d (a.sparse_matrix_value (), d, nargin-1);
2247 else
2248 retval = do_mat2cell (a.array_value (), d, nargin - 1);
2249 break;
2250 }
2251 case btyp_complex:
2252 {
2253 if (sparse)
2254 retval = do_mat2cell_2d (a.sparse_complex_matrix_value (), d,
2255 nargin-1);
2256 else
2257 retval = do_mat2cell (a.complex_array_value (), d, nargin - 1);
2258 break;
2259 }
2260#define BTYP_BRANCH(X,Y) \
2261 case btyp_ ## X: \
2262 retval = do_mat2cell (a.Y ## _value (), d, nargin - 1); \
2263 break
2264
2265 BTYP_BRANCH (float, float_array);
2266 BTYP_BRANCH (float_complex, float_complex_array);
2267 BTYP_BRANCH (bool, bool_array);
2268 BTYP_BRANCH (char, char_array);
2269
2270 BTYP_BRANCH (int8, int8_array);
2271 BTYP_BRANCH (int16, int16_array);
2272 BTYP_BRANCH (int32, int32_array);
2273 BTYP_BRANCH (int64, int64_array);
2274 BTYP_BRANCH (uint8, uint8_array);
2275 BTYP_BRANCH (uint16, uint16_array);
2276 BTYP_BRANCH (uint32, uint32_array);
2277 BTYP_BRANCH (uint64, uint64_array);
2278
2279 BTYP_BRANCH (cell, cell);
2280 BTYP_BRANCH (struct, map);
2281#undef BTYP_BRANCH
2282
2283 case btyp_func_handle:
2284 gripe_wrong_type_arg ("mat2cell", a);
2285 break;
2286 default:
2287 retval = do_mat2cell (a, d, nargin-1);
9
Calling 'do_mat2cell'
2288 }
2289 }
2290
2291 return retval;
2292}
2293
2294/*
2295%!test
2296%! x = reshape (1:20, 5, 4);
2297%! c = mat2cell (x, [3,2], [3,1]);
2298%! assert (c, {[1,6,11;2,7,12;3,8,13],[16;17;18];[4,9,14;5,10,15],[19;20]});
2299
2300%!test
2301%! x = "abcdefghij";
2302%! c = mat2cell (x, 1, [0,4,2,0,4,0]);
2303%! empty1by0str = resize ("", 1, 0);
2304%! assert (c, {empty1by0str,"abcd","ef",empty1by0str,"ghij",empty1by0str});
2305*/
2306
2307// FIXME: it would be nice to allow ranges being handled without a conversion.
2308template <class NDA>
2309static Cell
2310do_cellslices_nda (const NDA& array,
2311 const Array<octave_idx_type>& lb,
2312 const Array<octave_idx_type>& ub,
2313 int dim = -1)
2314{
2315 octave_idx_type n = lb.length ();
2316 Cell retval (1, n);
2317 if (array.is_vector () && (dim == -1
2318 || (dim == 0 && array.columns () == 1)
2319 || (dim == 1 && array.rows () == 1)))
2320 {
2321 for (octave_idx_type i = 0; i < n && ! error_state; i++)
2322 retval(i) = array.index (idx_vector (lb(i) - 1, ub(i)));
2323 }
2324 else
2325 {
2326 const dim_vector dv = array.dims ();
2327 int ndims = dv.length ();
2328 if (dim < 0)
2329 dim = dv.first_non_singleton ();
2330 ndims = std::max (ndims, dim + 1);
2331
2332 Array<idx_vector> idx (dim_vector (ndims, 1), idx_vector::colon);
2333
2334 for (octave_idx_type i = 0; i < n && ! error_state; i++)
2335 {
2336 idx(dim) = idx_vector (lb(i) - 1, ub(i));
2337 retval(i) = array.index (idx);
2338 }
2339 }
2340
2341 return retval;
2342}
2343
2344DEFUN (cellslices, args, ,octave_value_list Fcellslices (const octave_value_list& args
, int )
2345 "-*- texinfo -*-\n\octave_value_list Fcellslices (const octave_value_list& args
, int )
2346@deftypefn {Built-in Function} {@var{sl} =} cellslices (@var{x}, @var{lb}, @var{ub}, @var{dim})\n\octave_value_list Fcellslices (const octave_value_list& args
, int )
2347Given an array @var{x}, this function produces a cell array of slices from\n\octave_value_list Fcellslices (const octave_value_list& args
, int )
2348the array determined by the index vectors @var{lb}, @var{ub}, for lower and\n\octave_value_list Fcellslices (const octave_value_list& args
, int )
2349upper bounds, respectively. In other words, it is equivalent to the\n\octave_value_list Fcellslices (const octave_value_list& args
, int )
2350following code:\n\octave_value_list Fcellslices (const octave_value_list& args
, int )
2351\n\octave_value_list Fcellslices (const octave_value_list& args
, int )
2352@example\n\octave_value_list Fcellslices (const octave_value_list& args
, int )
2353@group\n\octave_value_list Fcellslices (const octave_value_list& args
, int )
2354n = length (lb);\n\octave_value_list Fcellslices (const octave_value_list& args
, int )
2355sl = cell (1, n);\n\octave_value_list Fcellslices (const octave_value_list& args
, int )
2356for i = 1:length (lb)\n\octave_value_list Fcellslices (const octave_value_list& args
, int )
2357 sl@{i@} = x(:,@dots{},lb(i):ub(i),@dots{},:);\n\octave_value_list Fcellslices (const octave_value_list& args
, int )
2358endfor\n\octave_value_list Fcellslices (const octave_value_list& args
, int )
2359@end group\n\octave_value_list Fcellslices (const octave_value_list& args
, int )
2360@end example\n\octave_value_list Fcellslices (const octave_value_list& args
, int )
2361\n\octave_value_list Fcellslices (const octave_value_list& args
, int )
2362The position of the index is determined by @var{dim}. If not specified,\n\octave_value_list Fcellslices (const octave_value_list& args
, int )
2363slicing is done along the first non-singleton dimension.\n\octave_value_list Fcellslices (const octave_value_list& args
, int )
2364@seealso{cell2mat, cellindexmat, cellfun}\n\octave_value_list Fcellslices (const octave_value_list& args
, int )
2365@end deftypefn")octave_value_list Fcellslices (const octave_value_list& args
, int )
2366{
2367 octave_value retval;
2368 int nargin = args.length ();
2369 if (nargin == 3 || nargin == 4)
2370 {
2371 octave_value x = args(0);
2372 Array<octave_idx_type> lb = args(1).octave_idx_type_vector_value ();
2373 Array<octave_idx_type> ub = args(2).octave_idx_type_vector_value ();
2374 int dim = -1;
2375 if (nargin == 4)
2376 {
2377 dim = args(3).int_value () - 1;
2378 if (dim < 0)
2379 error ("cellslices: DIM must be a valid dimension");
2380 }
2381
2382 if (! error_state)
2383 {
2384 if (lb.length () != ub.length ())
2385 error ("cellslices: the lengths of LB and UB must match");
2386 else
2387 {
2388 Cell retcell;
2389 if (! x.is_sparse_type () && x.is_matrix_type ())
2390 {
2391 // specialize for some dense arrays.
2392 if (x.is_bool_type ())
2393 retcell = do_cellslices_nda (x.bool_array_value (),
2394 lb, ub, dim);
2395 else if (x.is_char_matrix ())
2396 retcell = do_cellslices_nda (x.char_array_value (),
2397 lb, ub, dim);
2398 else if (x.is_integer_type ())
2399 {
2400 if (x.is_int8_type ())
2401 retcell = do_cellslices_nda (x.int8_array_value (),
2402 lb, ub, dim);
2403 else if (x.is_int16_type ())
2404 retcell = do_cellslices_nda (x.int16_array_value (),
2405 lb, ub, dim);
2406 else if (x.is_int32_type ())
2407 retcell = do_cellslices_nda (x.int32_array_value (),
2408 lb, ub, dim);
2409 else if (x.is_int64_type ())
2410 retcell = do_cellslices_nda (x.int64_array_value (),
2411 lb, ub, dim);
2412 else if (x.is_uint8_type ())
2413 retcell = do_cellslices_nda (x.uint8_array_value (),
2414 lb, ub, dim);
2415 else if (x.is_uint16_type ())
2416 retcell = do_cellslices_nda (x.uint16_array_value (),
2417 lb, ub, dim);
2418 else if (x.is_uint32_type ())
2419 retcell = do_cellslices_nda (x.uint32_array_value (),
2420 lb, ub, dim);
2421 else if (x.is_uint64_type ())
2422 retcell = do_cellslices_nda (x.uint64_array_value (),
2423 lb, ub, dim);
2424 }
2425 else if (x.is_complex_type ())
2426 {
2427 if (x.is_single_type ())
2428 retcell = do_cellslices_nda (x.float_complex_array_value (),
2429 lb, ub, dim);
2430 else
2431 retcell = do_cellslices_nda (x.complex_array_value (),
2432 lb, ub, dim);
2433 }
2434 else
2435 {
2436 if (x.is_single_type ())
2437 retcell = do_cellslices_nda (x.float_array_value (),
2438 lb, ub, dim);
2439 else
2440 retcell = do_cellslices_nda (x.array_value (),
2441 lb, ub, dim);
2442 }
2443 }
2444 else
2445 {
2446 // generic code.
2447 octave_idx_type n = lb.length ();
2448 retcell = Cell (1, n);
2449 const dim_vector dv = x.dims ();
2450 int ndims = dv.length ();
2451 if (dim < 0)
2452 dim = dv.first_non_singleton ();
2453 ndims = std::max (ndims, dim + 1);
2454 octave_value_list idx (ndims, octave_value::magic_colon_t);
2455 for (octave_idx_type i = 0; i < n && ! error_state; i++)
2456 {
2457 idx(dim) = Range (lb(i), ub(i));
2458 retcell(i) = x.do_index_op (idx);
2459 }
2460 }
2461 if (! error_state)
2462 retval = retcell;
2463 }
2464 }
2465 }
2466 else
2467 print_usage ();
2468
2469 return retval;
2470}
2471
2472/*
2473%!test
2474%! m = [1, 2, 3, 4; 5, 6, 7, 8; 9, 10, 11, 12];
2475%! c = cellslices (m, [1, 2], [2, 3], 2);
2476%! assert (c, {[1, 2; 5, 6; 9, 10], [2, 3; 6, 7; 10, 11]});
2477*/
2478
2479DEFUN (cellindexmat, args, ,octave_value_list Fcellindexmat (const octave_value_list&
args, int )
2480 "-*- texinfo -*-\n\octave_value_list Fcellindexmat (const octave_value_list&
args, int )
2481@deftypefn {Built-in Function} {@var{y} =} cellindexmat (@var{x}, @var{varargin})\n\octave_value_list Fcellindexmat (const octave_value_list&
args, int )
2482Given a cell array of matrices @var{x}, this function computes\n\octave_value_list Fcellindexmat (const octave_value_list&
args, int )
2483\n\octave_value_list Fcellindexmat (const octave_value_list&
args, int )
2484@example\n\octave_value_list Fcellindexmat (const octave_value_list&
args, int )
2485@group\n\octave_value_list Fcellindexmat (const octave_value_list&
args, int )
2486Y = cell (size (X));\n\octave_value_list Fcellindexmat (const octave_value_list&
args, int )
2487for i = 1:numel (X)\n\octave_value_list Fcellindexmat (const octave_value_list&
args, int )
2488 Y@{i@} = X@{i@}(varargin@{:@});\n\octave_value_list Fcellindexmat (const octave_value_list&
args, int )
2489endfor\n\octave_value_list Fcellindexmat (const octave_value_list&
args, int )
2490@end group\n\octave_value_list Fcellindexmat (const octave_value_list&
args, int )
2491@end example\n\octave_value_list Fcellindexmat (const octave_value_list&
args, int )
2492@seealso{cellslices, cellfun}\n\octave_value_list Fcellindexmat (const octave_value_list&
args, int )
2493@end deftypefn")octave_value_list Fcellindexmat (const octave_value_list&
args, int )
2494{
2495 octave_value retval;
2496 if (args.length () >= 1)
2497 {
2498 if (args(0).is_cell ())
2499 {
2500 const Cell x = args(0).cell_value ();
2501 NoAlias<Cell> y(x.dims ());
2502 octave_idx_type nel = x.numel ();
2503 octave_value_list idx = args.slice (1, args.length () - 1);
2504
2505 for (octave_idx_type i = 0; i < nel; i++)
2506 {
2507 octave_quit ();
2508 octave_value tmp = x(i);
2509 y(i) = tmp.do_index_op (idx);
2510 if (error_state)
2511 break;
2512 }
2513
2514 retval = y;
2515 }
2516 else
2517 error ("cellindexmat: X must be a cell");
2518 }
2519 else
2520 print_usage ();
2521
2522 return retval;
2523}