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