3Copyright (C) 2005, 2006, 2007, 2008, 2009 Mohamed Kamoun
4Copyright (C) 2009 Jaroslav Hajek
6This file is part of Octave.
8Octave is free software; you can redistribute it and/or modify it
9under the terms of the GNU General Public License as published by the
10Free Software Foundation; either version 3 of the License, or (at your
11option) any later version.
13Octave is distributed in the hope that it will be useful, but WITHOUT
14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18You should have received a copy of the GNU General Public License
19along with Octave; see the file COPYING. If not, see
20<http://www.gnu.org/licenses/>.
33#include "lo-mappers.h"
34#include "oct-locbuf.h"
42#include "unwind-prot.h"
48#include "ov-complex.h"
49#include "ov-flt-complex.h"
61// The octave_base_value::subsasgn method carries too much overhead for
62// per-element assignment strategy.
63// This class will optimize the most optimistic and most likely case
64// when the output really is scalar by defining a hierarchy of virtual
65// collectors specialized for some scalar types.
67class scalar_col_helper
70 virtual bool collect (octave_idx_type i, const octave_value& val) = 0;
71 virtual octave_value result (void) = 0;
72 virtual ~scalar_col_helper (void) { }
75// The default collector represents what was previously done in the main loop.
76// This reuses the existing assignment machinery via octave_value::subsasgn,
77// which can perform all sorts of conversions, but is relatively slow.
79class scalar_col_helper_def : public scalar_col_helper
81 std::list<octave_value_list> idx_list;
84 scalar_col_helper_def (const octave_value& val, const dim_vector& dims)
85 : idx_list (1), resval (val)
87 idx_list.front ().resize (1);
88 if (resval.dims () != dims)
91 ~scalar_col_helper_def (void) { }
93 bool collect (octave_idx_type i, const octave_value& val)
95 if (val.numel () == 1)
97 idx_list.front ()(0) = static_cast<double> (i + 1);
98 resval = resval.subsasgn ("(", idx_list, val);
101 error ("cellfun: expecting all values to be scalars for UniformOutput = true");
105 octave_value result (void)
112static bool can_extract (const octave_value& val)
115#define DEF_CAN_EXTRACT(T, CLASS) \
117bool can_extract<T> (const octave_value& val) \
118{ return val.type_id () == octave_ ## CLASS::static_type_id (); }
120DEF_CAN_EXTRACT (double, scalar);
121DEF_CAN_EXTRACT (float, float_scalar);
122DEF_CAN_EXTRACT (bool, bool);
123DEF_CAN_EXTRACT (octave_int8, int8_scalar);
124DEF_CAN_EXTRACT (octave_int16, int16_scalar);
125DEF_CAN_EXTRACT (octave_int32, int32_scalar);
126DEF_CAN_EXTRACT (octave_int64, int64_scalar);
127DEF_CAN_EXTRACT (octave_uint8, uint8_scalar);
128DEF_CAN_EXTRACT (octave_uint16, uint16_scalar);
129DEF_CAN_EXTRACT (octave_uint32, uint32_scalar);
130DEF_CAN_EXTRACT (octave_uint64, uint64_scalar);
133bool can_extract<Complex> (const octave_value& val)
135 int t = val.type_id ();
136 return (t == octave_complex::static_type_id ()
137 || t == octave_scalar::static_type_id ());
141bool can_extract<FloatComplex> (const octave_value& val)
143 int t = val.type_id ();
144 return (t == octave_float_complex::static_type_id ()
145 || t == octave_float_scalar::static_type_id ());
148// This specializes for collecting elements of a single type, by accessing
149// an array directly. If the scalar is not valid, it returns false.
152class scalar_col_helper_nda : public scalar_col_helper
155 typedef typename NDA::element_type T;
157 scalar_col_helper_nda (const octave_value& val, const dim_vector& dims)
160 arrayval(0) = octave_value_extract<T> (val);
162 ~scalar_col_helper_nda (void) { }
164 bool collect (octave_idx_type i, const octave_value& val)
166 bool retval = can_extract<T> (val);
168 arrayval(i) = octave_value_extract<T> (val);
171 octave_value result (void)
177template class scalar_col_helper_nda<NDArray>;
178template class scalar_col_helper_nda<FloatNDArray>;
179template class scalar_col_helper_nda<ComplexNDArray>;
180template class scalar_col_helper_nda<FloatComplexNDArray>;
181template class scalar_col_helper_nda<boolNDArray>;
182template class scalar_col_helper_nda<int8NDArray>;
183template class scalar_col_helper_nda<int16NDArray>;
184template class scalar_col_helper_nda<int32NDArray>;
185template class scalar_col_helper_nda<int64NDArray>;
186template class scalar_col_helper_nda<uint8NDArray>;
187template class scalar_col_helper_nda<uint16NDArray>;
188template class scalar_col_helper_nda<uint32NDArray>;
189template class scalar_col_helper_nda<uint64NDArray>;
191// the virtual constructor.
193make_col_helper (const octave_value& val, const dim_vector& dims)
195 scalar_col_helper *retval;
197 // No need to check numel() here.
198 switch (val.builtin_type ())
200#define ARRAYCASE(BTYP, ARRAY) \
202 retval = new scalar_col_helper_nda<ARRAY> (val, dims); \
205 ARRAYCASE (btyp_double, NDArray);
206 ARRAYCASE (btyp_float, FloatNDArray);
207 ARRAYCASE (btyp_complex, ComplexNDArray);
208 ARRAYCASE (btyp_float_complex, FloatComplexNDArray);
209 ARRAYCASE (btyp_bool, boolNDArray);
210 ARRAYCASE (btyp_int8, int8NDArray);
211 ARRAYCASE (btyp_int16, int16NDArray);
212 ARRAYCASE (btyp_int32, int32NDArray);
213 ARRAYCASE (btyp_int64, int64NDArray);
214 ARRAYCASE (btyp_uint8, uint8NDArray);
215 ARRAYCASE (btyp_uint16, uint16NDArray);
216 ARRAYCASE (btyp_uint32, uint32NDArray);
217 ARRAYCASE (btyp_uint64, uint64NDArray);
219 retval = new scalar_col_helper_def (val, dims);
226static octave_value_list
227get_output_list (octave_idx_type count, octave_idx_type nargout,
228 const octave_value_list& inputlist,
230 octave_value& error_handler)
232 octave_value_list tmp = func.do_multi_index_op (nargout, inputlist);
236 if (error_handler.is_defined ())
239 msg.assign ("identifier", last_error_id ());
240 msg.assign ("message", last_error_message ());
241 msg.assign ("index", octave_value(double (count + static_cast<octave_idx_type>(1))));
242 octave_value_list errlist = inputlist;
243 errlist.prepend (msg);
244 buffer_error_messages--;
246 tmp = error_handler.do_multi_index_op (nargout, errlist);
247 buffer_error_messages++;
259DEFUN_DLD (cellfun, args, nargout,
261@deftypefn {Loadable Function} {} cellfun (@var{name}, @var{c})\n\
262@deftypefnx {Loadable Function} {} cellfun (\"size\", @var{c}, @var{k})\n\
263@deftypefnx {Loadable Function} {} cellfun (\"isclass\", @var{c}, @var{class})\n\
264@deftypefnx {Loadable Function} {} cellfun (@var{func}, @var{c})\n\
265@deftypefnx {Loadable Function} {} cellfun (@var{func}, @var{c}, @var{d})\n\
266@deftypefnx {Loadable Function} {[@var{a}, @dots{}] =} cellfun (@dots{})\n\
267@deftypefnx {Loadable Function} {} cellfun (@dots{}, 'ErrorHandler', @var{errfunc})\n\
268@deftypefnx {Loadable Function} {} cellfun (@dots{}, 'UniformOutput', @var{val})\n\
270Evaluate the function named @var{name} on the elements of the cell array\n\
271@var{c}. Elements in @var{c} are passed on to the named function\n\
272individually. The function @var{name} can be one of the functions\n\
276Return 1 for empty elements.\n\
278Return 1 for logical elements.\n\
280Return 1 for real elements.\n\
282Return a vector of the lengths of cell elements.\n\
284Return the number of dimensions of each element.\n\
286Return the product of dimensions of each element.\n\
288Return the size along the @var{k}-th dimension.\n\
290Return 1 for elements of @var{class}.\n\
293Additionally, @code{cellfun} accepts an arbitrary function @var{func}\n\
294in the form of an inline function, function handle, or the name of a\n\
295function (in a character string). In the case of a character string\n\
296argument, the function must accept a single argument named @var{x}, and\n\
297it must return a string value. The function can take one or more arguments,\n\
298with the inputs args given by @var{c}, @var{d}, etc. Equally the function\n\
299can return one or more output arguments. For example\n\
303cellfun (@@atan2, @{1, 0@}, @{0, 1@})\n\
304 @result{}ans = [1.57080 0.00000]\n\
308The number of output arguments of @code{cellfun} matches the number of output\n\
309arguments of the function. The outputs of the function will be collected into the\n\
310output arguments of @code{cellfun} like this:\n\
314function [a, b] = twoouts (x)\n\
318[aa, bb] = cellfun(@@twoouts, @{1, 2, 3@})\n\
326Note that per default the output argument(s) are arrays of the same size as the\n\
328Input arguments that are singleton (1x1) cells will be automatically expanded\n\
329to the size of the other arguments.\n\
331If the parameter 'UniformOutput' is set to true (the default), then the function\n\
332must return scalars which will be concatenated into the\n\
333return array(s). If 'UniformOutput' is false, the outputs are concatenated into\n\
334a cell array (or cell arrays). For example\n\
338cellfun (\"tolower(x)\", @{\"Foo\", \"Bar\", \"FooBar\"@},\n\
339 \"UniformOutput\",false)\n\
340@result{} ans = @{\"foo\", \"bar\", \"foobar\"@}\n\
344Given the parameter 'ErrorHandler', then @var{errfunc} defines a function to\n\
345call in case @var{func} generates an error. The form of the function is\n\
348function [@dots{}] = errfunc (@var{s}, @dots{})\n\
351where there is an additional input argument to @var{errfunc} relative to\n\
352@var{func}, given by @var{s}. This is a structure with the elements\n\
353'identifier', 'message' and 'index', giving respectively the error\n\
354identifier, the error message, and the index into the input arguments\n\
355of the element that caused the error. For example\n\
359function y = foo (s, x), y = NaN; endfunction\n\
360cellfun (@@factorial, @{-1,2@},'ErrorHandler',@@foo)\n\
361@result{} ans = [NaN 2]\n\
365@seealso{isempty, islogical, isreal, length, ndims, numel, size}\n\
368 octave_value_list retval;
369 int nargin = args.length ();
370 int nargout1 = (nargout < 1 ? 1 : nargout);
374 error ("cellfun: you must supply at least 2 arguments");
379 octave_value func = args(0);
381 if (! args(1).is_cell ())
383 error ("cellfun: second argument must be a cell array");
388 if (func.is_string ())
390 const Cell f_args = args(1).cell_value ();
392 octave_idx_type k = f_args.numel ();
394 std::string name = func.string_value ();
396 if (name == "isempty")
398 boolNDArray result (f_args.dims ());
399 for (octave_idx_type count = 0; count < k ; count++)
400 result(count) = f_args.elem(count).is_empty ();
403 else if (name == "islogical")
405 boolNDArray result (f_args.dims ());
406 for (octave_idx_type count= 0; count < k ; count++)
407 result(count) = f_args.elem(count).is_bool_type ();
410 else if (name == "isreal")
412 boolNDArray result (f_args.dims ());
413 for (octave_idx_type count= 0; count < k ; count++)
414 result(count) = f_args.elem(count).is_real_type ();
417 else if (name == "length")
419 NDArray result (f_args.dims ());
420 for (octave_idx_type count= 0; count < k ; count++)
421 result(count) = static_cast<double> (f_args.elem(count).length ());
424 else if (name == "ndims")
426 NDArray result (f_args.dims ());
427 for (octave_idx_type count = 0; count < k ; count++)
428 result(count) = static_cast<double> (f_args.elem(count).ndims ());
431 else if (name == "prodofsize" || name == "numel")
433 NDArray result (f_args.dims ());
434 for (octave_idx_type count = 0; count < k ; count++)
435 result(count) = static_cast<double> (f_args.elem(count).numel ());
438 else if (name == "size")
442 int d = args(2).nint_value () - 1;
445 error ("cellfun: third argument must be a positive integer");
449 NDArray result (f_args.dims ());
450 for (octave_idx_type count = 0; count < k ; count++)
452 dim_vector dv = f_args.elem(count).dims ();
453 if (d < dv.length ())
454 result(count) = static_cast<double> (dv(d));
462 error ("not enough arguments for `size'");
464 else if (name == "isclass")
468 std::string class_name = args(2).string_value();
469 boolNDArray result (f_args.dims ());
470 for (octave_idx_type count = 0; count < k ; count++)
471 result(count) = (f_args.elem(count).class_name() == class_name);
476 error ("not enough arguments for `isclass'");
478 else if (name == "subsref" && nargin == 5 && nargout == 1
479 && args(2).numel () == 1 && args(2).is_cell ()
480 && args(3).is_string ()
481 && args(3).xtolower ().string_value () == "uniformoutput"
482 && ! args(4).bool_value () && ! error_state)
484 // This optimizes the case of applying the same index expression to
485 // multiple values. We decode the subscript just once. uniformoutput must
488 const Cell tmpc = args(2).cell_value ();
489 octave_value subs = tmpc(0);
492 std::list<octave_value_list> idx;
493 decode_subscripts ("subsref", subs, type, idx);
497 Cell result (f_args.dims ());
498 for (octave_idx_type count = 0; count < k && ! error_state; count++)
500 octave_value tmp = f_args.elem (count);
501 result(count) = tmp.subsref (type, idx);
509 if (! valid_identifier (name))
512 std::string fcn_name = unique_symbol_name ("__cellfun_fcn_");
513 std::string fname = "function y = ";
514 fname.append (fcn_name);
515 fname.append ("(x) y = ");
516 octave_function *ptr_func = extract_function (args(0), "cellfun",
517 fcn_name, fname, "; endfunction");
518 if (ptr_func && ! error_state)
519 func = octave_value (ptr_func, true);
522 func = symbol_table::find_function (name);
523 if (func.is_undefined ())
524 error ("cellfun: invalid function name: %s", name.c_str ());
528 if (error_state || ! retval.empty ())
531 if (func.is_function_handle () || func.is_inline_function ()
532 || func.is_function ())
534 unwind_protect frame;
535 frame.protect_var (buffer_error_messages);
537 bool uniform_output = true;
538 octave_value error_handler;
540 while (nargin > 3 && args(nargin-2).is_string())
542 std::string arg = args(nargin-2).string_value();
544 std::transform (arg.begin (), arg.end (),
545 arg.begin (), tolower);
547 if (arg == "uniformoutput")
548 uniform_output = args(nargin-1).bool_value();
549 else if (arg == "errorhandler")
551 if (args(nargin-1).is_function_handle () ||
552 args(nargin-1).is_inline_function ())
554 error_handler = args(nargin-1);
556 else if (args(nargin-1).is_string ())
558 std::string err_name = args(nargin-1).string_value ();
559 error_handler = symbol_table::find_function (err_name);
560 if (error_handler.is_undefined ())
562 error ("cellfun: invalid function name: %s", err_name.c_str ());
568 error ("invalid errorhandler value");
574 error ("cellfun: unrecognized parameter %s",
584 octave_value_list inputlist (nargin, octave_value ());
586 OCTAVE_LOCAL_BUFFER (Cell, inputs, nargin);
587 OCTAVE_LOCAL_BUFFER (bool, mask, nargin);
589 // This is to prevent copy-on-write.
590 const Cell *cinputs = inputs;
592 octave_idx_type k = 1;
594 dim_vector fdims (1, 1);
597 return octave_value_list ();
599 for (int j = 0; j < nargin; j++)
601 if (! args(j+1).is_cell ())
603 error ("cellfun: arguments must be cells");
604 return octave_value_list ();
607 inputs[j] = args(j+1).cell_value ();
608 mask[j] = inputs[j].numel () != 1;
610 inputlist(j) = cinputs[j](0);
613 for (int j = 0; j < nargin; j++)
617 fdims = inputs[j].dims ();
618 k = inputs[j].numel ();
619 for (int i = j+1; i < nargin; i++)
621 if (mask[i] && inputs[i].dims () != fdims)
623 error ("cellfun: Dimensions mismatch.");
624 return octave_value_list ();
631 if (error_handler.is_defined ())
632 buffer_error_messages++;
636 OCTAVE_LOCAL_BUFFER (std::auto_ptr<scalar_col_helper>, retptr, nargout1);
638 for (octave_idx_type count = 0; count < k ; count++)
640 for (int j = 0; j < nargin; j++)
643 inputlist.xelem (j) = cinputs[j](count);
646 const octave_value_list tmp = get_output_list (count, nargout, inputlist,
647 func, error_handler);
652 if (tmp.length () < nargout1)
654 if (tmp.length () < nargout)
656 error ("cellfun: too many output arguments");
657 return octave_value_list ();
665 for (int j = 0; j < nargout1; j++)
667 octave_value val = tmp(j);
669 if (val.numel () == 1)
670 retptr[j].reset (make_col_helper (val, fdims));
673 error ("cellfun: expecting all values to be scalars for UniformOutput = true");
680 for (int j = 0; j < nargout1; j++)
682 octave_value val = tmp(j);
684 if (! retptr[j]->collect (count, val))
686 // FIXME: A more elaborate structure would allow again a virtual
688 retptr[j].reset (new scalar_col_helper_def (retptr[j]->result (),
690 retptr[j]->collect (count, val);
699 retval.resize (nargout1);
700 for (int j = 0; j < nargout1; j++)
702 if (retptr[j].get ())
703 retval(j) = retptr[j]->result ();
705 retval(j) = Matrix ();
710 OCTAVE_LOCAL_BUFFER (Cell, results, nargout1);
711 for (int j = 0; j < nargout1; j++)
712 results[j].resize (fdims);
714 for (octave_idx_type count = 0; count < k ; count++)
716 for (int j = 0; j < nargin; j++)
719 inputlist.xelem (j) = cinputs[j](count);
722 const octave_value_list tmp = get_output_list (count, nargout, inputlist,
723 func, error_handler);
728 if (tmp.length () < nargout1)
730 if (tmp.length () < nargout)
732 error ("cellfun: too many output arguments");
733 return octave_value_list ();
740 for (int j = 0; j < nargout1; j++)
741 results[j](count) = tmp(j);
744 retval.resize(nargout1);
745 for (int j = 0; j < nargout1; j++)
746 retval(j) = results[j];
750 error ("cellfun: first argument must be a string or function handle");
757%% Test function to check the "Errorhandler" option
758%!function [z] = cellfunerror (S, varargin)
762%% First input argument can be a string, an inline function,
763%% a function_handle or an anonymous function
765%! A = cellfun ("islogical", {true, 0.1, false, i*2});
766%! assert (A, [true, false, true, false]);
768%! A = cellfun (inline ("islogical (x)", "x"), {true, 0.1, false, i*2});
769%! assert (A, [true, false, true, false]);
771%! A = cellfun (@islogical, {true, 0.1, false, i*2});
772%! assert (A, [true, false, true, false]);
774%! A = cellfun (@(x) islogical(x), {true, 0.1, false, i*2});
775%! assert (A, [true, false, true, false]);
777%% First input argument can be the special string "isreal",
778%% "isempty", "islogical", "length", "ndims" or "prodofsize"
780%! A = cellfun ("isreal", {true, 0.1, false, i*2, [], "abc"});
781%! assert (A, [true, true, true, false, true, false]);
783%! A = cellfun ("isempty", {true, 0.1, false, i*2, [], "abc"});
784%! assert (A, [false, false, false, false, true, false]);
786%! A = cellfun ("islogical", {true, 0.1, false, i*2, [], "abc"});
787%! assert (A, [true, false, true, false, false, false]);
789%! A = cellfun ("length", {true, 0.1, false, i*2, [], "abc"});
790%! assert (A, [1, 1, 1, 1, 0, 3]);
792%! A = cellfun ("ndims", {[1, 2; 3, 4]; (cell (1,2,3,4))});
793%! assert (A, [2; 4]);
795%! A = cellfun ("prodofsize", {[1, 2; 3, 4], (cell (1,2,3,4))});
796%! assert (A, [4, 24]);
798%% Number of input and output arguments may not be limited to one
800%! A = cellfun (@(x,y,z) x + y + z, {1, 1, 1}, {2, 2, 2}, {3, 4, 5});
801%! assert (A, [6, 7, 8]);
803%! A = cellfun (@(x,y,z) x + y + z, {1, 1, 1}, {2, 2, 2}, {3, 4, 5}, \
804%! "UniformOutput", false);
805%! assert (A, {6, 7, 8});
806%!test %% Two input arguments of different types
807%! A = cellfun (@(x,y) islogical (x) && ischar (y), {false, true}, {"a", 3});
808%! assert (A, [true, false]);
809%!test %% Pass another variable to the anonymous function
810%! y = true; A = cellfun (@(x) islogical (x) && y, {false, 0.3});
811%! assert (A, [true, false]);
812%!test %% Three ouptut arguments of different type
813%! [A, B, C] = cellfun (@find, {10, 11; 0, 12}, "UniformOutput", false);
814%! assert (isequal (A, {true, true; [], true}));
815%! assert (isequal (B, {true, true; [], true}));
816%! assert (isequal (C, {10, 11; [], 12}));
818%% Input arguments can be of type cell array of logical
820%! A = cellfun (@(x,y) x == y, {false, true}, {true, true});
821%! assert (A, [false, true]);
823%! A = cellfun (@(x,y) x == y, {false; true}, {true; true}, \
824%! "UniformOutput", true);
825%! assert (A, [false; true]);
827%! A = cellfun (@(x) x, {false, true; false, true}, "UniformOutput", false);
828%! assert (A, {false, true; false, true});
829%!test %% Three ouptut arguments of same type
830%! [A, B, C] = cellfun (@find, {true, false; false, true}, \
831%! "UniformOutput", false);
832%! assert (isequal (A, {true, []; [], true}));
833%! assert (isequal (B, {true, []; [], true}));
834%! assert (isequal (C, {true, []; [], true}));
836%! A = cellfun (@(x,y) cell2str (x,y), {true}, {true}, \
837%! "ErrorHandler", @cellfunerror);
838%! assert (isfield (A, "identifier"), true);
839%! assert (isfield (A, "message"), true);
840%! assert (isfield (A, "index"), true);
841%! assert (isempty (A.message), false);
842%! assert (A.index, 1);
843%!test %% Overwriting setting of "UniformOutput" true
844%! A = cellfun (@(x,y) cell2str (x,y), {true}, {true}, \
845%! "UniformOutput", true, "ErrorHandler", @cellfunerror);
846%! assert (isfield (A, "identifier"), true);
847%! assert (isfield (A, "message"), true);
848%! assert (isfield (A, "index"), true);
849%! assert (isempty (A.message), false);
850%! assert (A.index, 1);
852%% Input arguments can be of type cell array of numeric
854%! A = cellfun (@(x,y) x>y, {1.1, 4.2}, {3.1, 2+3*i});
855%! assert (A, [false, true]);
857%! A = cellfun (@(x,y) x>y, {1.1, 4.2; 2, 4}, {3.1, 2; 2, 4+2*i}, \
858%! "UniformOutput", true);
859%! assert (A, [false, true; false, false]);
861%! A = cellfun (@(x,y) x:y, {1.1, 4}, {3.1, 6}, "UniformOutput", false);
862%! assert (isequal (A{1}, [1.1, 2.1, 3.1]));
863%! assert (isequal (A{2}, [4, 5, 6]));
864%!test %% Three ouptut arguments of different type
865%! [A, B, C] = cellfun (@find, {10, 11; 0, 12}, "UniformOutput", false);
866%! assert (isequal (A, {true, true; [], true}));
867%! assert (isequal (B, {true, true; [], true}));
868%! assert (isequal (C, {10, 11; [], 12}));
870%! A = cellfun (@(x,y) cell2str(x,y), {1.1, 4}, {3.1, 6}, \
871%! "ErrorHandler", @cellfunerror);
872%! B = isfield (A(1), "message") && isfield (A(1), "index");
873%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]);
874%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]);
875%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]);
876%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]);
877%! assert ([A(1).index, A(2).index], [1, 2]);
878%!test %% Overwriting setting of "UniformOutput" true
879%! A = cellfun (@(x,y) cell2str(x,y), {1.1, 4}, {3.1, 6}, \
880%! "UniformOutput", true, "ErrorHandler", @cellfunerror);
881%! B = isfield (A(1), "message") && isfield (A(1), "index");
882%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]);
883%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]);
884%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]);
885%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]);
886%! assert ([A(1).index, A(2).index], [1, 2]);
888%% Input arguments can be of type cell arrays of character or strings
889%!error %% "UniformOutput" false should be used
890%! A = cellfun (@(x,y) x>y, {"ad", "c", "ghi"}, {"cc", "d", "fgh"});
892%! A = cellfun (@(x,y) x>y, {"a"; "f"}, {"c"; "d"}, "UniformOutput", true);
893%! assert (A, [false; true]);
895%! A = cellfun (@(x,y) x:y, {"a", "d"}, {"c", "f"}, "UniformOutput", false);
896%! assert (A, {"abc", "def"});
898%! A = cellfun (@(x,y) cell2str(x,y), {"a", "d"}, {"c", "f"}, \
899%! "ErrorHandler", @cellfunerror);
900%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]);
901%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]);
902%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]);
903%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]);
904%! assert ([A(1).index, A(2).index], [1, 2]);
905%!test %% Overwriting setting of "UniformOutput" true
906%! A = cellfun (@(x,y) cell2str(x,y), {"a", "d"}, {"c", "f"}, \
907%! "UniformOutput", true, "ErrorHandler", @cellfunerror);
908%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]);
909%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]);
910%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]);
911%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]);
912%! assert ([A(1).index, A(2).index], [1, 2]);
914%% Structures cannot be handled by cellfun
916%! vst1.a = 1.1; vst1.b = 4.2; vst2.a = 3.1; vst2.b = 2;
917%! A = cellfun (@(x,y) (x.a < y.a) && (x.b > y.b), vst1, vst2);
919%% Input arguments can be of type cell array of cell arrays
921%! A = cellfun (@(x,y) x{1} < y{1}, {{1.1}, {4.2}}, {{3.1}, {2}});
922%! assert (A, [1, 0], 1e-16);
924%! A = cellfun (@(x,y) x{1} < y{1}, {{1.1}; {4.2}}, {{3.1}; {2}}, \
925%! "UniformOutput", true);
926%! assert (A, [1; 0], 1e-16);
928%! A = cellfun (@(x,y) x{1} < y{1}, {{1.1}, {4.2}}, {{3.1}, {2}}, \
929%! "UniformOutput", false);
930%! assert (A, {true, false});
932%! A = cellfun (@(x,y) mat2str(x,y), {{1.1}, {4.2}}, {{3.1}, {2}}, \
933%! "ErrorHandler", @cellfunerror);
934%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]);
935%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]);
936%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]);
937%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]);
938%! assert ([A(1).index, A(2).index], [1, 2]);
939%!test %% Overwriting setting of "UniformOutput" true
940%! A = cellfun (@(x,y) mat2str(x,y), {{1.1}, {4.2}}, {{3.1}, {2}}, \
941%! "UniformOutput", true, "ErrorHandler", @cellfunerror);
942%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]);
943%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]);
944%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]);
945%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]);
946%! assert ([A(1).index, A(2).index], [1, 2]);
948%% Input arguments can be of type cell array of structure arrays
950%! a = struct ("a", 1, "b", 2); b = struct ("a", 1, "b", 3);
951%! A = cellfun (@(x,y) (x.a == y.a) && (x.b < y.b), {a}, {b});
954%! a = struct ("a", 1, "b", 2); b = struct ("a", 1, "b", 3);
955%! A = cellfun (@(x,y) (x.a == y.a) && (x.b < y.b) , {a}, {b}, \
956%! "UniformOutput", true);
959%! a = struct ("a", 1, "b", 2); b = struct ("a", 1, "b", 3);
960%! A = cellfun (@(x,y) (x.a == y.a) && (x.b < y.b) , {a}, {b}, \
961%! "UniformOutput", false);
962%! assert (A, {true});
964%! a = struct ("a", 1, "b", 2); b = struct ("a", 1, "b", 3);
965%! A = cellfun (@(x,y) cell2str (x.a, y.a), {a}, {b}, \
966%! "ErrorHandler", @cellfunerror);
967%! assert (isfield (A, "identifier"), true);
968%! assert (isfield (A, "message"), true);
969%! assert (isfield (A, "index"), true);
970%! assert (isempty (A.message), false);
971%! assert (A.index, 1);
972%!test %% Overwriting setting of "UniformOutput" true
973%! a = struct ("a", 1, "b", 2); b = struct ("a", 1, "b", 3);
974%! A = cellfun (@(x,y) cell2str (x.a, y.a), {a}, {b}, \
975%! "UniformOutput", true, "ErrorHandler", @cellfunerror);
976%! assert (isfield (A, "identifier"), true);
977%! assert (isfield (A, "message"), true);
978%! assert (isfield (A, "index"), true);
979%! assert (isempty (A.message), false);
980%! assert (A.index, 1);
982%% A lot of other tests
984%!error(cellfun('isclass',1))
985%!error(cellfun('size',1))
986%!error(cellfun(@sin,{[]},'BadParam',false))
987%!error(cellfun(@sin,{[]},'UniformOuput'))
988%!error(cellfun(@sin,{[]},'ErrorHandler'))
989%!assert(cellfun(@sin,{0,1}),sin([0,1]))
990%!assert(cellfun(inline('sin(x)'),{0,1}),sin([0,1]))
991%!assert(cellfun('sin',{0,1}),sin([0,1]))
992%!assert(cellfun('isempty',{1,[]}),[false,true])
993%!assert(cellfun('islogical',{false,pi}),[true,false])
994%!assert(cellfun('isreal',{1i,1}),[false,true])
995%!assert(cellfun('length',{zeros(2,2),1}),[2,1])
996%!assert(cellfun('prodofsize',{zeros(2,2),1}),[4,1])
997%!assert(cellfun('ndims',{zeros([2,2,2]),1}),[3,2])
998%!assert(cellfun('isclass',{zeros([2,2,2]),'test'},'double'),[true,false])
999%!assert(cellfun('size',{zeros([1,2,3]),1},1),[1,1])
1000%!assert(cellfun('size',{zeros([1,2,3]),1},2),[2,1])
1001%!assert(cellfun('size',{zeros([1,2,3]),1},3),[3,1])
1002%!assert(cellfun(@atan2,{1,1},{1,2}),[atan2(1,1),atan2(1,2)])
1003%!assert(cellfun(@atan2,{1,1},{1,2},'UniformOutput',false),{atan2(1,1),atan2(1,2)})
1004%!assert(cellfun(@sin,{1,2;3,4}),sin([1,2;3,4]))
1005%!assert(cellfun(@atan2,{1,1;1,1},{1,2;1,2}),atan2([1,1;1,1],[1,2;1,2]))
1006%!error(cellfun(@factorial,{-1,3}))
1007%!assert(cellfun(@factorial,{-1,3},'ErrorHandler',@(x,y) NaN),[NaN,6])
1009%! [a,b,c]=cellfun(@fileparts,{fullfile("a","b","c.d"),fullfile("e","f","g.h")},'UniformOutput',false);
1010%! assert(a,{fullfile("a","b"),fullfile("e","f")})
1011%! assert(b,{'c','g'})
1012%! assert(c,{'.d','.h'})
1017do_num2cell_helper (const dim_vector& dv,
1018 const Array<int>& dimv,
1019 dim_vector& celldv, dim_vector& arraydv,
1022 int dvl = dimv.length ();
1023 int maxd = dv.length ();
1025 for (int i = 0; i < dvl; i++)
1026 maxd = std::max (maxd, dimv(i));
1027 if (maxd > dv.length ())
1028 celldv.resize (maxd, 1);
1031 OCTAVE_LOCAL_BUFFER_INIT (bool, sing, maxd, false);
1034 for (int i = 0; i < dvl; i++)
1036 int k = dimv(i) - 1;
1039 error ("num2cell: dimension indices must be positive");
1042 else if (i > 0 && k < dimv(i-1) - 1)
1044 error ("num2cell: dimension indices must be strictly increasing");
1052 for (int k = 0, i = dvl; k < maxd; k++)
1056 for (int i = 0; i < maxd; i++)
1065do_num2cell (const NDA& array, const Array<int>& dimv)
1067 if (dimv.is_empty ())
1069 Cell retval (array.dims ());
1070 octave_idx_type nel = array.numel ();
1071 for (octave_idx_type i = 0; i < nel; i++)
1072 retval.xelem (i) = array(i);
1078 dim_vector celldv, arraydv;
1080 do_num2cell_helper (array.dims (), dimv, celldv, arraydv, perm);
1084 NDA parray = array.permute (perm);
1086 octave_idx_type nela = arraydv.numel (), nelc = celldv.numel ();
1087 parray = parray.reshape (dim_vector (nela, nelc));
1089 Cell retval (celldv);
1090 for (octave_idx_type i = 0; i < nelc; i++)
1092 retval.xelem (i) = NDA (parray.column (i).reshape (arraydv));
1100DEFUN_DLD (num2cell, args, ,
1102@deftypefn {Loadable Function} {@var{c} =} num2cell (@var{m})\n\
1103@deftypefnx {Loadable Function} {@var{c} =} num2cell (@var{m}, @var{dim})\n\
1104Convert the matrix @var{m} to a cell array. If @var{dim} is defined, the\n\
1105value @var{c} is of dimension 1 in this dimension and the elements of\n\
1106@var{m} are placed into @var{c} in slices. For example:\n\
1110num2cell([1,2;3,4])\n\
1118num2cell([1,2;3,4],1)\n\
1131@seealso{mat2cell}\n\
1134 int nargin = args.length();
1135 octave_value retval;
1137 if (nargin < 1 || nargin > 2)
1141 octave_value array = args(0);
1144 dimv = args (1).int_vector_value (true);
1148 else if (array.is_bool_type ())
1149 retval = do_num2cell (array.bool_array_value (), dimv);
1150 else if (array.is_char_matrix ())
1151 retval = do_num2cell (array.char_array_value (), dimv);
1152 else if (array.is_numeric_type ())
1154 if (array.is_integer_type ())
1156 if (array.is_int8_type ())
1157 retval = do_num2cell (array.int8_array_value (), dimv);
1158 else if (array.is_int16_type ())
1159 retval = do_num2cell (array.int16_array_value (), dimv);
1160 else if (array.is_int32_type ())
1161 retval = do_num2cell (array.int32_array_value (), dimv);
1162 else if (array.is_int64_type ())
1163 retval = do_num2cell (array.int64_array_value (), dimv);
1164 else if (array.is_uint8_type ())
1165 retval = do_num2cell (array.uint8_array_value (), dimv);
1166 else if (array.is_uint16_type ())
1167 retval = do_num2cell (array.uint16_array_value (), dimv);
1168 else if (array.is_uint32_type ())
1169 retval = do_num2cell (array.uint32_array_value (), dimv);
1170 else if (array.is_uint64_type ())
1171 retval = do_num2cell (array.uint64_array_value (), dimv);
1173 else if (array.is_complex_type ())
1175 if (array.is_single_type ())
1176 retval = do_num2cell (array.float_complex_array_value (), dimv);
1178 retval = do_num2cell (array.complex_array_value (), dimv);
1182 if (array.is_single_type ())
1183 retval = do_num2cell (array.float_array_value (), dimv);
1185 retval = do_num2cell (array.array_value (), dimv);
1188 else if (array.is_cell () || array.is_map ())
1190 dim_vector celldv, arraydv;
1192 do_num2cell_helper (array.dims (), dimv, celldv, arraydv, perm);
1196 // FIXME: this operation may be rather inefficient.
1197 octave_value parray = array.permute (perm);
1199 octave_idx_type nela = arraydv.numel (), nelc = celldv.numel ();
1200 parray = parray.reshape (dim_vector (nela, nelc));
1202 Cell retcell (celldv);
1203 octave_value_list idx (2);
1204 idx(0) = octave_value::magic_colon_t;
1206 for (octave_idx_type i = 0; i < nelc; i++)
1209 octave_value tmp = parray.do_index_op (idx);
1210 retcell(i) = tmp.reshape (arraydv);
1217 gripe_wrong_type_arg ("num2cell", array);
1225%!assert(num2cell([1,2;3,4]),{1,2;3,4})
1226%!assert(num2cell([1,2;3,4],1),{[1;3],[2;4]})
1227%!assert(num2cell([1,2;3,4],2),{[1,2];[3,4]})
1231DEFUN_DLD (mat2cell, args, ,
1233@deftypefn {Loadable Function} {@var{b} =} mat2cell (@var{a}, @var{m}, @var{n})\n\
1234@deftypefnx {Loadable Function} {@var{b} =} mat2cell (@var{a}, @var{d1}, @var{d2}, @dots{})\n\
1235@deftypefnx {Loadable Function} {@var{b} =} mat2cell (@var{a}, @var{r})\n\
1236Convert the matrix @var{a} to a cell array. If @var{a} is 2-D, then\n\
1237it is required that @code{sum (@var{m}) == size (@var{a}, 1)} and\n\
1238@code{sum (@var{n}) == size (@var{a}, 2)}. Similarly, if @var{a} is\n\
1239a multi-dimensional and the number of dimensional arguments is equal\n\
1240to the dimensions of @var{a}, then it is required that @code{sum (@var{di})\n\
1241== size (@var{a}, i)}.\n\
1243Given a single dimensional argument @var{r}, the other dimensional\n\
1244arguments are assumed to equal @code{size (@var{a},@var{i})}.\n\
1246An example of the use of mat2cell is\n\
1249mat2cell (reshape(1:16,4,4),[3,1],[3,1])\n\
1270@seealso{num2cell, cell2mat}\n\
1273 int nargin = args.length();
1274 octave_value retval;
1280 dim_vector dv = args(0).dims();
1282 new_dv.resize(dv.length());
1286 octave_idx_type nmax = -1;
1288 if (nargin - 1 != dv.length())
1289 error ("mat2cell: Incorrect number of dimensions");
1292 for (octave_idx_type j = 0; j < dv.length(); j++)
1294 ColumnVector d = ColumnVector (args(j+1).vector_value
1299 error ("mat2cell: dimension can not be empty");
1304 if (nmax < d.length())
1307 for (octave_idx_type i = 1; i < d.length(); i++)
1315 error ("mat2cell: invalid dimensional argument");
1321 error ("mat2cell: invalid dimensional argument");
1323 if (d(d.length() - 1) != dv(j))
1324 error ("mat2cell: inconsistent dimensions");
1329 new_dv(j) = d.length();
1336 // Construct a matrix with the index values
1337 Matrix dimargs(nmax, new_dv.length());
1338 for (octave_idx_type j = 0; j < new_dv.length(); j++)
1342 ColumnVector d = ColumnVector (args(j+1).vector_value
1345 dimargs(0,j) = d(0);
1346 for (octave_idx_type i = 1; i < d.length(); i++)
1347 dimargs(i,j) = dimargs(i-1,j) + d(i);
1351 octave_value_list lst (new_dv.length(), octave_value());
1353 octave_idx_type nel = new_dv.numel();
1354 octave_idx_type ntot = 1;
1356 for (int j = 0; j < new_dv.length()-1; j++)
1359 for (octave_idx_type i = 0; i < nel; i++)
1361 octave_idx_type n = ntot;
1362 octave_idx_type ii = i;
1363 for (octave_idx_type j = new_dv.length() - 1; j >= 0; j--)
1367 octave_idx_type idx = ii / n;
1368 lst (j) = Range((idx == 0 ? 1. : dimargs(idx-1,j)+1.),
1374 ret(i) = octave_value(args(0)).do_index_op(lst, 0);
1385 ColumnVector d = ColumnVector (args(1).vector_value
1389 for (octave_idx_type i = 0; i < d.length(); i++)
1397 error ("mat2cell: invalid dimensional argument");
1403 error ("mat2cell: inconsistent dimensions");
1405 new_dv(0) = d.length();
1406 for (octave_idx_type i = 1; i < dv.length(); i++)
1411 octave_value_list lst (new_dv.length(), octave_value());
1414 for (octave_idx_type i = 1; i < new_dv.length(); i++)
1415 lst (i) = Range (1., static_cast<double>(dv(i)));
1418 for (octave_idx_type i = 0; i < new_dv(0); i++)
1422 lst(0) = Range(idx + 1., idx + d(i));
1423 ret(i) = octave_value(args(0)).do_index_op(lst, 0);
1441%! x = reshape(1:20,5,4);
1442%! c = mat2cell(x,[3,2],[3,1]);
1443%! assert(c,{[1,6,11;2,7,12;3,8,13],[16;17;18];[4,9,14;5,10,15],[19;20]})
1447%! c = mat2cell(x,1,[0,4,2,0,4,0]);
1448%! empty1by0str = resize('',1,0);
1449%! assert(c,{empty1by0str,'abcd','ef',empty1by0str,'ghij',empty1by0str})
1453// FIXME: it would be nice to allow ranges being handled without a conversion.
1456do_cellslices_nda (const NDA& array,
1457 const Array<octave_idx_type>& lb,
1458 const Array<octave_idx_type>& ub,
1461 octave_idx_type n = lb.length ();
1463 if (array.is_vector () && (dim == -1
1464 || (dim == 0 && array.columns () == 1)
1465 || (dim == 1 && array.rows () == 1)))
1467 for (octave_idx_type i = 0; i < n && ! error_state; i++)
1468 retval(i) = array.index (idx_vector (lb(i) - 1, ub(i)));
1472 const dim_vector dv = array.dims ();
1473 int ndims = dv.length ();
1475 dim = dv.first_non_singleton ();
1476 ndims = std::max (ndims, dim + 1);
1478 Array<idx_vector> idx (ndims, idx_vector::colon);
1480 for (octave_idx_type i = 0; i < n && ! error_state; i++)
1482 idx(dim) = idx_vector (lb(i) - 1, ub(i));
1483 retval(i) = array.index (idx);
1490DEFUN_DLD (cellslices, args, ,
1492@deftypefn {Loadable Function} {@var{sl} =} cellslices (@var{x}, @var{lb}, @var{ub}, @var{dim})\n\
1493Given an array @var{x}, this function produces a cell array of slices from the array\n\
1494determined by the index vectors @var{lb}, @var{ub}, for lower and upper bounds, respectively.\n\
1495In other words, it is equivalent to the following code:\n\
1501for i = 1:length (lb)\n\
1502 sl@{i@} = x(:,@dots{},lb(i):ub(i),@dots{},:);\n\
1507The position of the index is determined by @var{dim}. If not specified, slicing\n\
1508is done along the first non-singleton dimension.\n\
1511 octave_value retval;
1512 int nargin = args.length ();
1513 if (nargin == 3 || nargin == 4)
1515 octave_value x = args(0);
1516 Array<octave_idx_type> lb = args(1).octave_idx_type_vector_value ();
1517 Array<octave_idx_type> ub = args(2).octave_idx_type_vector_value ();
1521 dim = args(3).int_value () - 1;
1523 error ("cellslices: dim must be a valid dimension");
1528 if (lb.length () != ub.length ())
1529 error ("cellslices: the lengths of lb and ub must match");
1533 if (! x.is_sparse_type () && x.is_matrix_type ())
1535 // specialize for some dense arrays.
1536 if (x.is_bool_type ())
1537 retcell = do_cellslices_nda (x.bool_array_value (), lb, ub, dim);
1538 else if (x.is_char_matrix ())
1539 retcell = do_cellslices_nda (x.char_array_value (), lb, ub, dim);
1540 else if (x.is_integer_type ())
1542 if (x.is_int8_type ())
1543 retcell = do_cellslices_nda (x.int8_array_value (), lb, ub, dim);
1544 else if (x.is_int16_type ())
1545 retcell = do_cellslices_nda (x.int16_array_value (), lb, ub, dim);
1546 else if (x.is_int32_type ())
1547 retcell = do_cellslices_nda (x.int32_array_value (), lb, ub, dim);
1548 else if (x.is_int64_type ())
1549 retcell = do_cellslices_nda (x.int64_array_value (), lb, ub, dim);
1550 else if (x.is_uint8_type ())
1551 retcell = do_cellslices_nda (x.uint8_array_value (), lb, ub, dim);
1552 else if (x.is_uint16_type ())
1553 retcell = do_cellslices_nda (x.uint16_array_value (), lb, ub, dim);
1554 else if (x.is_uint32_type ())
1555 retcell = do_cellslices_nda (x.uint32_array_value (), lb, ub, dim);
1556 else if (x.is_uint64_type ())
1557 retcell = do_cellslices_nda (x.uint64_array_value (), lb, ub, dim);
1559 else if (x.is_complex_type ())
1561 if (x.is_single_type ())
1562 retcell = do_cellslices_nda (x.float_complex_array_value (), lb, ub, dim);
1564 retcell = do_cellslices_nda (x.complex_array_value (), lb, ub, dim);
1568 if (x.is_single_type ())
1569 retcell = do_cellslices_nda (x.float_array_value (), lb, ub, dim);
1571 retcell = do_cellslices_nda (x.array_value (), lb, ub, dim);
1577 octave_idx_type n = lb.length ();
1578 retcell = Cell (1, n);
1579 const dim_vector dv = x.dims ();
1580 int ndims = dv.length ();
1582 dim = dv.first_non_singleton ();
1583 ndims = std::max (ndims, dim + 1);
1584 octave_value_list idx (ndims, octave_value::magic_colon_t);
1585 for (octave_idx_type i = 0; i < n && ! error_state; i++)
1587 idx(dim) = Range (lb(i), ub(i));
1588 retcell(i) = x.do_index_op (idx);
1604%! m = [1, 2, 3, 4; 5, 6, 7, 8; 9, 10, 11, 12];
1605%! c = cellslices (m, [1, 2], [2, 3], 2);
1606%! assert (c, {[1, 2; 5, 6; 9, 10], [2, 3; 6, 7; 10, 11]});