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