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