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 }