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"
47// The octave_base_value::subsasgn method carries too much overhead for
48// per-element assignment strategy.
49// This class will optimize the most optimistic and most likely case
50// when the output really is scalar by defining a hierarchy of virtual
51// collectors specialized for some scalar types.
53class scalar_col_helper
56 virtual bool collect (octave_idx_type i, const octave_value& val) = 0;
57 virtual octave_value result (void) = 0;
58 virtual ~scalar_col_helper (void) { }
61// The default collector represents what was previously done in the main loop.
62// This reuses the existing assignment machinery via octave_value::subsasgn,
63// which can perform all sorts of conversions, but is relatively slow.
65class scalar_col_helper_def : public scalar_col_helper
67 std::list<octave_value_list> idx_list;
70 scalar_col_helper_def (const octave_value& val, const dim_vector& dims)
71 : idx_list (1), resval (val)
73 idx_list.front ().resize (1);
74 if (resval.dims () != dims)
77 ~scalar_col_helper_def (void) { }
79 bool collect (octave_idx_type i, const octave_value& val)
81 if (val.numel () == 1)
83 idx_list.front ()(0) = static_cast<double> (i + 1);
84 resval = resval.subsasgn ("(", idx_list, val);
87 error ("cellfun: expecting all values to be scalars for UniformOutput = true");
91 octave_value result (void)
98struct scalar_query_helper { };
100#define DEF_QUERY_HELPER(T, TEST, QUERY) \
102struct scalar_query_helper<T> \
104 static bool has_value (const octave_value& val) \
106 static T get_value (const octave_value& val) \
110DEF_QUERY_HELPER (double, val.is_real_scalar (), val.scalar_value ());
111DEF_QUERY_HELPER (Complex, val.is_complex_scalar (), val.complex_value ());
112DEF_QUERY_HELPER (float, val.is_single_type () && val.is_real_scalar (),
113 val.float_scalar_value ());
114DEF_QUERY_HELPER (FloatComplex, val.is_single_type () && val.is_complex_scalar (),
115 val.float_complex_value ());
116DEF_QUERY_HELPER (bool, val.is_bool_scalar (), val.bool_value ());
119// This specializes for collecting elements of a single type, by accessing
120// an array directly. If the scalar is not valid, it returns false.
123class scalar_col_helper_nda : public scalar_col_helper
126 typedef typename NDA::element_type T;
128 scalar_col_helper_nda (const octave_value& val, const dim_vector& dims)
131 arrayval(0) = scalar_query_helper<T>::get_value (val);
133 ~scalar_col_helper_nda (void) { }
135 bool collect (octave_idx_type i, const octave_value& val)
137 bool retval = scalar_query_helper<T>::has_value (val);
139 arrayval(i) = scalar_query_helper<T>::get_value (val);
142 octave_value result (void)
148template class scalar_col_helper_nda<NDArray>;
149template class scalar_col_helper_nda<FloatNDArray>;
150template class scalar_col_helper_nda<ComplexNDArray>;
151template class scalar_col_helper_nda<FloatComplexNDArray>;
152template class scalar_col_helper_nda<boolNDArray>;
154// the virtual constructor.
156make_col_helper (const octave_value& val, const dim_vector& dims)
158 scalar_col_helper *retval;
160 if (val.is_bool_scalar ())
161 retval = new scalar_col_helper_nda<boolNDArray> (val, dims);
162 else if (val.is_complex_scalar ())
164 if (val.is_single_type ())
165 retval = new scalar_col_helper_nda<FloatComplexNDArray> (val, dims);
167 retval = new scalar_col_helper_nda<ComplexNDArray> (val, dims);
169 else if (val.is_real_scalar ())
171 if (val.is_single_type ())
172 retval = new scalar_col_helper_nda<FloatNDArray> (val, dims);
174 retval = new scalar_col_helper_nda<NDArray> (val, dims);
177 retval = new scalar_col_helper_def (val, dims);
182DEFUN_DLD (cellfun, args, nargout,
184@deftypefn {Loadable Function} {} cellfun (@var{name}, @var{c})\n\
185@deftypefnx {Loadable Function} {} cellfun (\"size\", @var{c}, @var{k})\n\
186@deftypefnx {Loadable Function} {} cellfun (\"isclass\", @var{c}, @var{class})\n\
187@deftypefnx {Loadable Function} {} cellfun (@var{func}, @var{c})\n\
188@deftypefnx {Loadable Function} {} cellfun (@var{func}, @var{c}, @var{d})\n\
189@deftypefnx {Loadable Function} {[@var{a}, @var{b}] =} cellfun (@dots{})\n\
190@deftypefnx {Loadable Function} {} cellfun (@dots{}, 'ErrorHandler', @var{errfunc})\n\
191@deftypefnx {Loadable Function} {} cellfun (@dots{}, 'UniformOutput', @var{val})\n\
193Evaluate the function named @var{name} on the elements of the cell array\n\
194@var{c}. Elements in @var{c} are passed on to the named function\n\
195individually. The function @var{name} can be one of the functions\n\
199Return 1 for empty elements.\n\
201Return 1 for logical elements.\n\
203Return 1 for real elements.\n\
205Return a vector of the lengths of cell elements.\n\
207Return the number of dimensions of each element.\n\
209Return the product of dimensions of each element.\n\
211Return the size along the @var{k}-th dimension.\n\
213Return 1 for elements of @var{class}.\n\
216Additionally, @code{cellfun} accepts an arbitrary function @var{func}\n\
217in the form of an inline function, function handle, or the name of a\n\
218function (in a character string). In the case of a character string\n\
219argument, the function must accept a single argument named @var{x}, and\n\
220it must return a string value. The function can take one or more arguments,\n\
221with the inputs args given by @var{c}, @var{d}, etc. Equally the function\n\
222can return one or more output arguments. For example\n\
226cellfun (@@atan2, @{1, 0@}, @{0, 1@})\n\
227@result{}ans = [1.57080 0.00000]\n\
231Note that the default output argument is an array of the same size as the\n\
233Input arguments that are singleton (1x1) cells will be automatically expanded\n\
234to the size of the other arguments.\n\
236If the parameter 'UniformOutput' is set to true (the default), then the function\n\
237must return a single element which will be concatenated into the\n\
238return value. If 'UniformOutput' is false, the outputs are concatenated in\n\
239a cell array. For example\n\
243cellfun (\"tolower(x)\", @{\"Foo\", \"Bar\", \"FooBar\"@},\n\
244 \"UniformOutput\",false)\n\
245@result{} ans = @{\"foo\", \"bar\", \"foobar\"@}\n\
249Given the parameter 'ErrorHandler', then @var{errfunc} defines a function to\n\
250call in case @var{func} generates an error. The form of the function is\n\
253function [@dots{}] = errfunc (@var{s}, @dots{})\n\
256where there is an additional input argument to @var{errfunc} relative to\n\
257@var{func}, given by @var{s}. This is a structure with the elements\n\
258'identifier', 'message' and 'index', giving respectively the error\n\
259identifier, the error message, and the index into the input arguments\n\
260of the element that caused the error. For example\n\
264function y = foo (s, x), y = NaN; endfunction\n\
265cellfun (@@factorial, @{-1,2@},'ErrorHandler',@@foo)\n\
266@result{} ans = [NaN 2]\n\
270@seealso{isempty, islogical, isreal, length, ndims, numel, size}\n\
273 octave_value_list retval;
274 int nargin = args.length ();
275 nargout = (nargout < 1 ? 1 : nargout);
279 error ("cellfun: you must supply at least 2 arguments");
284 octave_value func = args(0);
286 if (! args(1).is_cell ())
288 error ("cellfun: second argument must be a cell array");
293 if (func.is_string ())
295 const Cell f_args = args(1).cell_value ();
297 octave_idx_type k = f_args.numel ();
299 std::string name = func.string_value ();
301 if (name == "isempty")
303 boolNDArray result (f_args.dims ());
304 for (octave_idx_type count = 0; count < k ; count++)
305 result(count) = f_args.elem(count).is_empty ();
308 else if (name == "islogical")
310 boolNDArray result (f_args.dims ());
311 for (octave_idx_type count= 0; count < k ; count++)
312 result(count) = f_args.elem(count).is_bool_type ();
315 else if (name == "isreal")
317 boolNDArray result (f_args.dims ());
318 for (octave_idx_type count= 0; count < k ; count++)
319 result(count) = f_args.elem(count).is_real_type ();
322 else if (name == "length")
324 NDArray result (f_args.dims ());
325 for (octave_idx_type count= 0; count < k ; count++)
326 result(count) = static_cast<double> (f_args.elem(count).length ());
329 else if (name == "ndims")
331 NDArray result (f_args.dims ());
332 for (octave_idx_type count = 0; count < k ; count++)
333 result(count) = static_cast<double> (f_args.elem(count).ndims ());
336 else if (name == "prodofsize" || name == "numel")
338 NDArray result (f_args.dims ());
339 for (octave_idx_type count = 0; count < k ; count++)
340 result(count) = static_cast<double> (f_args.elem(count).numel ());
343 else if (name == "size")
347 int d = args(2).nint_value () - 1;
350 error ("cellfun: third argument must be a positive integer");
354 NDArray result (f_args.dims ());
355 for (octave_idx_type count = 0; count < k ; count++)
357 dim_vector dv = f_args.elem(count).dims ();
358 if (d < dv.length ())
359 result(count) = static_cast<double> (dv(d));
367 error ("not enough arguments for `size'");
369 else if (name == "isclass")
373 std::string class_name = args(2).string_value();
374 boolNDArray result (f_args.dims ());
375 for (octave_idx_type count = 0; count < k ; count++)
376 result(count) = (f_args.elem(count).class_name() == class_name);
381 error ("not enough arguments for `isclass'");
385 if (! valid_identifier (name))
388 std::string fcn_name = unique_symbol_name ("__cellfun_fcn_");
389 std::string fname = "function y = ";
390 fname.append (fcn_name);
391 fname.append ("(x) y = ");
392 octave_function *ptr_func = extract_function (args(0), "cellfun",
393 fcn_name, fname, "; endfunction");
394 if (ptr_func && ! error_state)
395 func = octave_value (ptr_func, true);
398 func = symbol_table::find_function (name);
399 if (func.is_undefined ())
400 error ("cellfun: invalid function name: %s", name.c_str ());
404 if (error_state || ! retval.empty ())
407 if (func.is_function_handle () || func.is_inline_function ()
408 || func.is_function ())
410 unwind_protect::frame_id_t uwp_frame = unwind_protect::begin_frame ();
411 unwind_protect::protect_var (buffer_error_messages);
413 bool uniform_output = true;
414 octave_value error_handler;
416 while (nargin > 3 && args(nargin-2).is_string())
418 std::string arg = args(nargin-2).string_value();
420 std::transform (arg.begin (), arg.end (),
421 arg.begin (), tolower);
423 if (arg == "uniformoutput")
424 uniform_output = args(nargin-1).bool_value();
425 else if (arg == "errorhandler")
427 if (args(nargin-1).is_function_handle () ||
428 args(nargin-1).is_inline_function ())
430 error_handler = args(nargin-1);
432 else if (args(nargin-1).is_string ())
434 std::string err_name = args(nargin-1).string_value ();
435 error_handler = symbol_table::find_function (err_name);
436 if (error_handler.is_undefined ())
438 error ("cellfun: invalid function name: %s", err_name.c_str ());
444 error ("invalid errorhandler value");
450 error ("cellfun: unrecognized parameter %s",
460 octave_value_list inputlist (nargin, octave_value ());
462 OCTAVE_LOCAL_BUFFER (Cell, inputs, nargin);
463 OCTAVE_LOCAL_BUFFER (bool, mask, nargin);
465 // This is to prevent copy-on-write.
466 const Cell *cinputs = inputs;
468 octave_idx_type k = 1;
470 dim_vector fdims (1, 1);
475 for (int j = 0; j < nargin; j++)
477 if (! args(j+1).is_cell ())
479 error ("cellfun: arguments must be cells");
483 inputs[j] = args(j+1).cell_value ();
484 mask[j] = inputs[j].numel () != 1;
486 inputlist(j) = cinputs[j](0);
489 for (int j = 0; j < nargin; j++)
493 fdims = inputs[j].dims ();
494 k = inputs[j].numel ();
495 for (int i = j+1; i < nargin; i++)
497 if (mask[i] && inputs[i].dims () != fdims)
499 error ("cellfun: Dimensions mismatch.");
507 if (error_handler.is_defined ())
508 buffer_error_messages++;
512 OCTAVE_LOCAL_BUFFER (std::auto_ptr<scalar_col_helper>, retptr, nargout);
514 for (octave_idx_type count = 0; count < k ; count++)
516 for (int j = 0; j < nargin; j++)
519 inputlist(j) = cinputs[j](count);
522 octave_value_list tmp = func.do_multi_index_op (nargout, inputlist);
524 if (error_state && error_handler.is_defined ())
527 msg.assign ("identifier", last_error_id ());
528 msg.assign ("message", last_error_message ());
529 msg.assign ("index", octave_value(double (count + static_cast<octave_idx_type>(1))));
530 octave_value_list errlist = inputlist;
531 errlist.prepend (msg);
532 buffer_error_messages--;
534 tmp = error_handler.do_multi_index_op (nargout, errlist);
535 buffer_error_messages++;
544 if (tmp.length() < nargout)
546 error ("cellfun: too many output arguments");
552 for (int j = 0; j < nargout; j++)
554 octave_value val = tmp(j);
556 if (val.numel () == 1)
557 retptr[j].reset (make_col_helper (val, fdims));
560 error ("cellfun: expecting all values to be scalars for UniformOutput = true");
567 for (int j = 0; j < nargout; j++)
569 octave_value val = tmp(j);
571 if (! retptr[j]->collect (count, val))
573 // FIXME: A more elaborate structure would allow again a virtual
575 retptr[j].reset (new scalar_col_helper_def (retptr[j]->result (),
577 retptr[j]->collect (count, val);
586 retval.resize (nargout);
587 for (int j = 0; j < nargout; j++)
589 if (retptr[j].get ())
590 retval(j) = retptr[j]->result ();
592 retval(j) = Matrix ();
597 OCTAVE_LOCAL_BUFFER (Cell, results, nargout);
598 for (int j = 0; j < nargout; j++)
599 results[j].resize (fdims);
601 for (octave_idx_type count = 0; count < k ; count++)
603 for (int j = 0; j < nargin; j++)
606 inputlist(j) = cinputs[j](count);
609 octave_value_list tmp = func.do_multi_index_op (nargout, inputlist);
611 if (error_state && error_handler.is_defined ())
614 msg.assign ("identifier", last_error_id ());
615 msg.assign ("message", last_error_message ());
616 msg.assign ("index", octave_value(double (count + static_cast<octave_idx_type>(1))));
617 octave_value_list errlist = inputlist;
618 errlist.prepend (msg);
619 buffer_error_messages--;
621 tmp = error_handler.do_multi_index_op (nargout, errlist);
622 buffer_error_messages++;
631 if (tmp.length() < nargout)
633 error ("cellfun: too many output arguments");
638 for (int j = 0; j < nargout; j++)
639 results[j](count) = tmp(j);
642 retval.resize(nargout);
643 for (int j = 0; j < nargout; j++)
644 retval(j) = results[j];
649 retval = octave_value_list();
651 unwind_protect::run_frame (uwp_frame);
654 error ("cellfun: first argument must be a string or function handle");
661%% Test function to check the "Errorhandler" option
662%!function [z] = cellfunerror (S, varargin)
666%% First input argument can be a string, an inline function,
667%% a function_handle or an anonymous function
669%! A = cellfun ("islogical", {true, 0.1, false, i*2});
670%! assert (A, [true, false, true, false]);
672%! A = cellfun (inline ("islogical (x)", "x"), {true, 0.1, false, i*2});
673%! assert (A, [true, false, true, false]);
675%! A = cellfun (@islogical, {true, 0.1, false, i*2});
676%! assert (A, [true, false, true, false]);
678%! A = cellfun (@(x) islogical(x), {true, 0.1, false, i*2});
679%! assert (A, [true, false, true, false]);
681%% First input argument can be the special string "isreal",
682%% "isempty", "islogical", "length", "ndims" or "prodofsize"
684%! A = cellfun ("isreal", {true, 0.1, false, i*2, [], "abc"});
685%! assert (A, [true, true, true, false, true, false]);
687%! A = cellfun ("isempty", {true, 0.1, false, i*2, [], "abc"});
688%! assert (A, [false, false, false, false, true, false]);
690%! A = cellfun ("islogical", {true, 0.1, false, i*2, [], "abc"});
691%! assert (A, [true, false, true, false, false, false]);
693%! A = cellfun ("length", {true, 0.1, false, i*2, [], "abc"});
694%! assert (A, [1, 1, 1, 1, 0, 3]);
696%! A = cellfun ("ndims", {[1, 2; 3, 4]; (cell (1,2,3,4))});
697%! assert (A, [2; 4]);
699%! A = cellfun ("prodofsize", {[1, 2; 3, 4], (cell (1,2,3,4))});
700%! assert (A, [4, 24]);
702%% Number of input and output arguments may not be limited to one
704%! A = cellfun (@(x,y,z) x + y + z, {1, 1, 1}, {2, 2, 2}, {3, 4, 5});
705%! assert (A, [6, 7, 8]);
707%! A = cellfun (@(x,y,z) x + y + z, {1, 1, 1}, {2, 2, 2}, {3, 4, 5}, \
708%! "UniformOutput", false);
709%! assert (A, {6, 7, 8});
710%!test %% Two input arguments of different types
711%! A = cellfun (@(x,y) islogical (x) && ischar (y), {false, true}, {"a", 3});
712%! assert (A, [true, false]);
713%!test %% Pass another variable to the anonymous function
714%! y = true; A = cellfun (@(x) islogical (x) && y, {false, 0.3});
715%! assert (A, [true, false]);
716%!test %% Three ouptut arguments of different type
717%! [A, B, C] = cellfun (@find, {10, 11; 0, 12}, "UniformOutput", false);
718%! assert (isequal (A, {true, true; [], true}));
719%! assert (isequal (B, {true, true; [], true}));
720%! assert (isequal (C, {10, 11; [], 12}));
722%% Input arguments can be of type cell array of logical
724%! A = cellfun (@(x,y) x == y, {false, true}, {true, true});
725%! assert (A, [false, true]);
727%! A = cellfun (@(x,y) x == y, {false; true}, {true; true}, \
728%! "UniformOutput", true);
729%! assert (A, [false; true]);
731%! A = cellfun (@(x) x, {false, true; false, true}, "UniformOutput", false);
732%! assert (A, {false, true; false, true});
733%!test %% Three ouptut arguments of same type
734%! [A, B, C] = cellfun (@find, {true, false; false, true}, \
735%! "UniformOutput", false);
736%! assert (isequal (A, {true, []; [], true}));
737%! assert (isequal (B, {true, []; [], true}));
738%! assert (isequal (C, {true, []; [], true}));
740%! A = cellfun (@(x,y) cell2str (x,y), {true}, {true}, \
741%! "ErrorHandler", @cellfunerror);
742%! assert (isfield (A, "identifier"), true);
743%! assert (isfield (A, "message"), true);
744%! assert (isfield (A, "index"), true);
745%! assert (isempty (A.message), false);
746%! assert (A.index, 1);
747%!test %% Overwriting setting of "UniformOutput" true
748%! A = cellfun (@(x,y) cell2str (x,y), {true}, {true}, \
749%! "UniformOutput", true, "ErrorHandler", @cellfunerror);
750%! assert (isfield (A, "identifier"), true);
751%! assert (isfield (A, "message"), true);
752%! assert (isfield (A, "index"), true);
753%! assert (isempty (A.message), false);
754%! assert (A.index, 1);
756%% Input arguments can be of type cell array of numeric
758%! A = cellfun (@(x,y) x>y, {1.1, 4.2}, {3.1, 2+3*i});
759%! assert (A, [false, true]);
761%! A = cellfun (@(x,y) x>y, {1.1, 4.2; 2, 4}, {3.1, 2; 2, 4+2*i}, \
762%! "UniformOutput", true);
763%! assert (A, [false, true; false, false]);
765%! A = cellfun (@(x,y) x:y, {1.1, 4}, {3.1, 6}, "UniformOutput", false);
766%! assert (isequal (A{1}, [1.1, 2.1, 3.1]));
767%! assert (isequal (A{2}, [4, 5, 6]));
768%!test %% Three ouptut arguments of different type
769%! [A, B, C] = cellfun (@find, {10, 11; 0, 12}, "UniformOutput", false);
770%! assert (isequal (A, {true, true; [], true}));
771%! assert (isequal (B, {true, true; [], true}));
772%! assert (isequal (C, {10, 11; [], 12}));
774%! A = cellfun (@(x,y) cell2str(x,y), {1.1, 4}, {3.1, 6}, \
775%! "ErrorHandler", @cellfunerror);
776%! B = isfield (A(1), "message") && isfield (A(1), "index");
777%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]);
778%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]);
779%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]);
780%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]);
781%! assert ([A(1).index, A(2).index], [1, 2]);
782%!test %% Overwriting setting of "UniformOutput" true
783%! A = cellfun (@(x,y) cell2str(x,y), {1.1, 4}, {3.1, 6}, \
784%! "UniformOutput", true, "ErrorHandler", @cellfunerror);
785%! B = isfield (A(1), "message") && isfield (A(1), "index");
786%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]);
787%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]);
788%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]);
789%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]);
790%! assert ([A(1).index, A(2).index], [1, 2]);
792%% Input arguments can be of type cell arrays of character or strings
793%!error %% "UniformOutput" false should be used
794%! A = cellfun (@(x,y) x>y, {"ad", "c", "ghi"}, {"cc", "d", "fgh"});
796%! A = cellfun (@(x,y) x>y, {"a"; "f"}, {"c"; "d"}, "UniformOutput", true);
797%! assert (A, [false; true]);
799%! A = cellfun (@(x,y) x:y, {"a", "d"}, {"c", "f"}, "UniformOutput", false);
800%! assert (A, {"abc", "def"});
802%! A = cellfun (@(x,y) cell2str(x,y), {"a", "d"}, {"c", "f"}, \
803%! "ErrorHandler", @cellfunerror);
804%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]);
805%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]);
806%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]);
807%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]);
808%! assert ([A(1).index, A(2).index], [1, 2]);
809%!test %% Overwriting setting of "UniformOutput" true
810%! A = cellfun (@(x,y) cell2str(x,y), {"a", "d"}, {"c", "f"}, \
811%! "UniformOutput", true, "ErrorHandler", @cellfunerror);
812%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]);
813%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]);
814%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]);
815%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]);
816%! assert ([A(1).index, A(2).index], [1, 2]);
818%% Structures cannot be handled by cellfun
820%! vst1.a = 1.1; vst1.b = 4.2; vst2.a = 3.1; vst2.b = 2;
821%! A = cellfun (@(x,y) (x.a < y.a) && (x.b > y.b), vst1, vst2);
823%% Input arguments can be of type cell array of cell arrays
825%! A = cellfun (@(x,y) x{1} < y{1}, {{1.1}, {4.2}}, {{3.1}, {2}});
826%! assert (A, [1, 0], 1e-16);
828%! A = cellfun (@(x,y) x{1} < y{1}, {{1.1}; {4.2}}, {{3.1}; {2}}, \
829%! "UniformOutput", true);
830%! assert (A, [1; 0], 1e-16);
832%! A = cellfun (@(x,y) x{1} < y{1}, {{1.1}, {4.2}}, {{3.1}, {2}}, \
833%! "UniformOutput", false);
834%! assert (A, {true, false});
836%! A = cellfun (@(x,y) mat2str(x,y), {{1.1}, {4.2}}, {{3.1}, {2}}, \
837%! "ErrorHandler", @cellfunerror);
838%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]);
839%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]);
840%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]);
841%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]);
842%! assert ([A(1).index, A(2).index], [1, 2]);
843%!test %% Overwriting setting of "UniformOutput" true
844%! A = cellfun (@(x,y) mat2str(x,y), {{1.1}, {4.2}}, {{3.1}, {2}}, \
845%! "UniformOutput", true, "ErrorHandler", @cellfunerror);
846%! assert ([(isfield (A(1), "identifier")), (isfield (A(2), "identifier"))], [true, true]);
847%! assert ([(isfield (A(1), "message")), (isfield (A(2), "message"))], [true, true]);
848%! assert ([(isfield (A(1), "index")), (isfield (A(2), "index"))], [true, true]);
849%! assert ([(isempty (A(1).message)), (isempty (A(2).message))], [false, false]);
850%! assert ([A(1).index, A(2).index], [1, 2]);
852%% Input arguments can be of type cell array of structure arrays
854%! a = struct ("a", 1, "b", 2); b = struct ("a", 1, "b", 3);
855%! A = cellfun (@(x,y) (x.a == y.a) && (x.b < y.b), {a}, {b});
858%! a = struct ("a", 1, "b", 2); b = struct ("a", 1, "b", 3);
859%! A = cellfun (@(x,y) (x.a == y.a) && (x.b < y.b) , {a}, {b}, \
860%! "UniformOutput", true);
863%! a = struct ("a", 1, "b", 2); b = struct ("a", 1, "b", 3);
864%! A = cellfun (@(x,y) (x.a == y.a) && (x.b < y.b) , {a}, {b}, \
865%! "UniformOutput", false);
866%! assert (A, {true});
868%! a = struct ("a", 1, "b", 2); b = struct ("a", 1, "b", 3);
869%! A = cellfun (@(x,y) cell2str (x.a, y.a), {a}, {b}, \
870%! "ErrorHandler", @cellfunerror);
871%! assert (isfield (A, "identifier"), true);
872%! assert (isfield (A, "message"), true);
873%! assert (isfield (A, "index"), true);
874%! assert (isempty (A.message), false);
875%! assert (A.index, 1);
876%!test %% Overwriting setting of "UniformOutput" true
877%! a = struct ("a", 1, "b", 2); b = struct ("a", 1, "b", 3);
878%! A = cellfun (@(x,y) cell2str (x.a, y.a), {a}, {b}, \
879%! "UniformOutput", true, "ErrorHandler", @cellfunerror);
880%! assert (isfield (A, "identifier"), true);
881%! assert (isfield (A, "message"), true);
882%! assert (isfield (A, "index"), true);
883%! assert (isempty (A.message), false);
884%! assert (A.index, 1);
886%% A lot of other tests
888%!error(cellfun('isclass',1))
889%!error(cellfun('size',1))
890%!error(cellfun(@sin,{[]},'BadParam',false))
891%!error(cellfun(@sin,{[]},'UniformOuput'))
892%!error(cellfun(@sin,{[]},'ErrorHandler'))
893%!assert(cellfun(@sin,{0,1}),sin([0,1]))
894%!assert(cellfun(inline('sin(x)'),{0,1}),sin([0,1]))
895%!assert(cellfun('sin',{0,1}),sin([0,1]))
896%!assert(cellfun('isempty',{1,[]}),[false,true])
897%!assert(cellfun('islogical',{false,pi}),[true,false])
898%!assert(cellfun('isreal',{1i,1}),[false,true])
899%!assert(cellfun('length',{zeros(2,2),1}),[2,1])
900%!assert(cellfun('prodofsize',{zeros(2,2),1}),[4,1])
901%!assert(cellfun('ndims',{zeros([2,2,2]),1}),[3,2])
902%!assert(cellfun('isclass',{zeros([2,2,2]),'test'},'double'),[true,false])
903%!assert(cellfun('size',{zeros([1,2,3]),1},1),[1,1])
904%!assert(cellfun('size',{zeros([1,2,3]),1},2),[2,1])
905%!assert(cellfun('size',{zeros([1,2,3]),1},3),[3,1])
906%!assert(cellfun(@atan2,{1,1},{1,2}),[atan2(1,1),atan2(1,2)])
907%!assert(cellfun(@atan2,{1,1},{1,2},'UniformOutput',false),{atan2(1,1),atan2(1,2)})
908%!assert(cellfun(@sin,{1,2;3,4}),sin([1,2;3,4]))
909%!assert(cellfun(@atan2,{1,1;1,1},{1,2;1,2}),atan2([1,1;1,1],[1,2;1,2]))
910%!error(cellfun(@factorial,{-1,3}))
911%!assert(cellfun(@factorial,{-1,3},'ErrorHandler',@(x,y) NaN),[NaN,6])
913%! [a,b,c]=cellfun(@fileparts,{fullfile("a","b","c.d"),fullfile("e","f","g.h")},'UniformOutput',false);
914%! assert(a,{fullfile("a","b"),fullfile("e","f")})
915%! assert(b,{'c','g'})
916%! assert(c,{'.d','.h'})
921do_num2cell_helper (const dim_vector& dv,
922 const Array<int>& dimv,
923 dim_vector& celldv, dim_vector& arraydv,
926 int dvl = dimv.length ();
927 int maxd = dv.length ();
929 for (int i = 0; i < dvl; i++)
930 maxd = std::max (maxd, dimv(i));
931 if (maxd > dv.length ())
932 celldv.resize (maxd, 1);
935 OCTAVE_LOCAL_BUFFER_INIT (bool, sing, maxd, false);
938 for (int i = 0; i < dvl; i++)
943 error ("num2cell: dimension indices must be positive");
946 else if (i > 0 && k < dimv(i-1) - 1)
948 error ("num2cell: dimension indices must be strictly increasing");
956 for (int k = 0, i = dvl; k < maxd; k++)
960 for (int i = 0; i < maxd; i++)
969do_num2cell (const NDA& array, const Array<int>& dimv)
971 if (dimv.is_empty ())
973 Cell retval (array.dims ());
974 octave_idx_type nel = array.numel ();
975 for (octave_idx_type i = 0; i < nel; i++)
976 retval.xelem (i) = array(i);
982 dim_vector celldv, arraydv;
984 do_num2cell_helper (array.dims (), dimv, celldv, arraydv, perm);
988 NDA parray = array.permute (perm);
990 octave_idx_type nela = arraydv.numel (), nelc = celldv.numel ();
991 parray = parray.reshape (dim_vector (nela, nelc));
993 Cell retval (celldv);
994 for (octave_idx_type i = 0; i < nelc; i++)
996 retval.xelem (i) = NDA (parray.column (i).reshape (arraydv));
1004DEFUN_DLD (num2cell, args, ,
1006@deftypefn {Loadable Function} {@var{c} =} num2cell (@var{m})\n\
1007@deftypefnx {Loadable Function} {@var{c} =} num2cell (@var{m}, @var{dim})\n\
1008Convert the matrix @var{m} to a cell array. If @var{dim} is defined, the\n\
1009value @var{c} is of dimension 1 in this dimension and the elements of\n\
1010@var{m} are placed in slices in @var{c}.\n\
1011@seealso{mat2cell}\n\
1014 int nargin = args.length();
1015 octave_value retval;
1017 if (nargin < 1 || nargin > 2)
1021 octave_value array = args(0);
1024 dimv = args (1).int_vector_value (true);
1028 else if (array.is_bool_type ())
1029 retval = do_num2cell (array.bool_array_value (), dimv);
1030 else if (array.is_char_matrix ())
1031 retval = do_num2cell (array.char_array_value (), dimv);
1032 else if (array.is_numeric_type ())
1034 if (array.is_integer_type ())
1036 if (array.is_int8_type ())
1037 retval = do_num2cell (array.int8_array_value (), dimv);
1038 else if (array.is_int16_type ())
1039 retval = do_num2cell (array.int16_array_value (), dimv);
1040 else if (array.is_int32_type ())
1041 retval = do_num2cell (array.int32_array_value (), dimv);
1042 else if (array.is_int64_type ())
1043 retval = do_num2cell (array.int64_array_value (), dimv);
1044 else if (array.is_uint8_type ())
1045 retval = do_num2cell (array.uint8_array_value (), dimv);
1046 else if (array.is_uint16_type ())
1047 retval = do_num2cell (array.uint16_array_value (), dimv);
1048 else if (array.is_uint32_type ())
1049 retval = do_num2cell (array.uint32_array_value (), dimv);
1050 else if (array.is_uint64_type ())
1051 retval = do_num2cell (array.uint64_array_value (), dimv);
1053 else if (array.is_complex_type ())
1055 if (array.is_single_type ())
1056 retval = do_num2cell (array.float_complex_array_value (), dimv);
1058 retval = do_num2cell (array.complex_array_value (), dimv);
1062 if (array.is_single_type ())
1063 retval = do_num2cell (array.float_array_value (), dimv);
1065 retval = do_num2cell (array.array_value (), dimv);
1068 else if (array.is_cell () || array.is_map ())
1070 dim_vector celldv, arraydv;
1072 do_num2cell_helper (array.dims (), dimv, celldv, arraydv, perm);
1076 // FIXME: this operation may be rather inefficient.
1077 octave_value parray = array.permute (perm);
1079 octave_idx_type nela = arraydv.numel (), nelc = celldv.numel ();
1080 parray = parray.reshape (dim_vector (nela, nelc));
1082 Cell retcell (celldv);
1083 octave_value_list idx (2);
1084 idx(0) = octave_value::magic_colon_t;
1086 for (octave_idx_type i = 0; i < nelc; i++)
1089 octave_value tmp = parray.do_index_op (idx);
1090 retcell(i) = tmp.reshape (arraydv);
1097 gripe_wrong_type_arg ("num2cell", array);
1105%!assert(num2cell([1,2;3,4]),{1,2;3,4})
1106%!assert(num2cell([1,2;3,4],1),{[1;3],[2;4]})
1107%!assert(num2cell([1,2;3,4],2),{[1,2];[3,4]})
1111DEFUN_DLD (mat2cell, args, ,
1113@deftypefn {Loadable Function} {@var{b} =} mat2cell (@var{a}, @var{m}, @var{n})\n\
1114@deftypefnx {Loadable Function} {@var{b} =} mat2cell (@var{a}, @var{d1}, @var{d2}, @dots{})\n\
1115@deftypefnx {Loadable Function} {@var{b} =} mat2cell (@var{a}, @var{r})\n\
1116Convert the matrix @var{a} to a cell array. If @var{a} is 2-D, then\n\
1117it is required that @code{sum (@var{m}) == size (@var{a}, 1)} and\n\
1118@code{sum (@var{n}) == size (@var{a}, 2)}. Similarly, if @var{a} is\n\
1119a multi-dimensional and the number of dimensional arguments is equal\n\
1120to the dimensions of @var{a}, then it is required that @code{sum (@var{di})\n\
1121== size (@var{a}, i)}.\n\
1123Given a single dimensional argument @var{r}, the other dimensional\n\
1124arguments are assumed to equal @code{size (@var{a},@var{i})}.\n\
1126An example of the use of mat2cell is\n\
1129mat2cell (reshape(1:16,4,4),[3,1],[3,1])\n\
1150@seealso{num2cell, cell2mat}\n\
1153 int nargin = args.length();
1154 octave_value retval;
1160 dim_vector dv = args(0).dims();
1162 new_dv.resize(dv.length());
1166 octave_idx_type nmax = -1;
1168 if (nargin - 1 != dv.length())
1169 error ("mat2cell: Incorrect number of dimensions");
1172 for (octave_idx_type j = 0; j < dv.length(); j++)
1174 ColumnVector d = ColumnVector (args(j+1).vector_value
1179 error ("mat2cell: dimension can not be empty");
1184 if (nmax < d.length())
1187 for (octave_idx_type i = 1; i < d.length(); i++)
1195 error ("mat2cell: invalid dimensional argument");
1201 error ("mat2cell: invalid dimensional argument");
1203 if (d(d.length() - 1) != dv(j))
1204 error ("mat2cell: inconsistent dimensions");
1209 new_dv(j) = d.length();
1216 // Construct a matrix with the index values
1217 Matrix dimargs(nmax, new_dv.length());
1218 for (octave_idx_type j = 0; j < new_dv.length(); j++)
1222 ColumnVector d = ColumnVector (args(j+1).vector_value
1225 dimargs(0,j) = d(0);
1226 for (octave_idx_type i = 1; i < d.length(); i++)
1227 dimargs(i,j) = dimargs(i-1,j) + d(i);
1231 octave_value_list lst (new_dv.length(), octave_value());
1233 octave_idx_type nel = new_dv.numel();
1234 octave_idx_type ntot = 1;
1236 for (int j = 0; j < new_dv.length()-1; j++)
1239 for (octave_idx_type i = 0; i < nel; i++)
1241 octave_idx_type n = ntot;
1242 octave_idx_type ii = i;
1243 for (octave_idx_type j = new_dv.length() - 1; j >= 0; j--)
1247 octave_idx_type idx = ii / n;
1248 lst (j) = Range((idx == 0 ? 1. : dimargs(idx-1,j)+1.),
1254 ret(i) = args(0).do_index_op(lst, 0);
1265 ColumnVector d = ColumnVector (args(1).vector_value
1269 for (octave_idx_type i = 0; i < d.length(); i++)
1277 error ("mat2cell: invalid dimensional argument");
1283 error ("mat2cell: inconsistent dimensions");
1285 new_dv(0) = d.length();
1286 for (octave_idx_type i = 1; i < dv.length(); i++)
1291 octave_value_list lst (new_dv.length(), octave_value());
1294 for (octave_idx_type i = 1; i < new_dv.length(); i++)
1295 lst (i) = Range (1., static_cast<double>(dv(i)));
1298 for (octave_idx_type i = 0; i < new_dv(0); i++)
1302 lst(0) = Range(idx + 1., idx + d(i));
1303 ret(i) = args(0).do_index_op(lst, 0);
1321%! x = reshape(1:20,5,4);
1322%! c = mat2cell(x,[3,2],[3,1]);
1323%! assert(c,{[1,6,11;2,7,12;3,8,13],[16;17;18];[4,9,14;5,10,15],[19;20]})
1327%! c = mat2cell(x,1,[0,4,2,0,4,0]);
1328%! empty1by0str = resize('',1,0);
1329%! assert(c,{empty1by0str,'abcd','ef',empty1by0str,'ghij',empty1by0str})
1333// FIXME: it would be nice to allow ranges being handled without a conversion.
1336do_cellslices_nda (const NDA& array,
1337 const Array<octave_idx_type>& lb,
1338 const Array<octave_idx_type>& ub)
1340 octave_idx_type n = lb.length ();
1342 if (array.is_vector ())
1344 for (octave_idx_type i = 0; i < n && ! error_state; i++)
1345 retval(i) = array.index (idx_vector (lb(i) - 1, ub(i)));
1349 dim_vector dv = array.dims ();
1350 octave_idx_type nl = 1;
1351 for (int i = 0; i < dv.length () - 1; i++) nl *= dv(i);
1352 for (octave_idx_type i = 0; i < n && ! error_state; i++)
1354 // Do it with a single index to speed things up.
1356 dv(dv.length () - 1) = ub(i) + 1 - lb(i);
1357 dv.chop_trailing_singletons ();
1358 retval(i) = array.index (idx_vector (nl*(lb(i) - 1), nl*ub(i))).reshape (dv);
1365DEFUN_DLD (cellslices, args, ,
1367@deftypefn {Loadable Function} {@var{sl} =} cellslices (@var{x}, @var{lb}, @var{ub})\n\
1368Given a vector @var{x}, this function produces a cell array of slices from the vector\n\
1369determined by the index vectors @var{lb}, @var{ub}, for lower and upper bounds, respectively.\n\
1370In other words, it is equivalent to the following code:\n\
1376for i = 1:length (lb)\n\
1377 sl@{i@} = x(lb(i):ub(i));\n\
1382If @var{X} is a matrix or array, indexing is done along the last dimension.\n\
1383@seealso{mat2cell}\n\
1386 octave_value retval;
1387 int nargin = args.length ();
1390 octave_value x = args(0);
1391 Array<octave_idx_type> lb = args(1).octave_idx_type_vector_value ();
1392 Array<octave_idx_type> ub = args(2).octave_idx_type_vector_value ();
1395 if (lb.length () != ub.length ())
1396 error ("cellslices: the lengths of lb and ub must match");
1400 if (! x.is_sparse_type () && x.is_matrix_type ())
1402 // specialize for some dense arrays.
1403 if (x.is_bool_type ())
1404 retcell = do_cellslices_nda (x.bool_array_value (), lb, ub);
1405 else if (x.is_char_matrix ())
1406 retcell = do_cellslices_nda (x.char_array_value (), lb, ub);
1407 else if (x.is_integer_type ())
1409 if (x.is_int8_type ())
1410 retcell = do_cellslices_nda (x.int8_array_value (), lb, ub);
1411 else if (x.is_int16_type ())
1412 retcell = do_cellslices_nda (x.int16_array_value (), lb, ub);
1413 else if (x.is_int32_type ())
1414 retcell = do_cellslices_nda (x.int32_array_value (), lb, ub);
1415 else if (x.is_int64_type ())
1416 retcell = do_cellslices_nda (x.int64_array_value (), lb, ub);
1417 else if (x.is_uint8_type ())
1418 retcell = do_cellslices_nda (x.uint8_array_value (), lb, ub);
1419 else if (x.is_uint16_type ())
1420 retcell = do_cellslices_nda (x.uint16_array_value (), lb, ub);
1421 else if (x.is_uint32_type ())
1422 retcell = do_cellslices_nda (x.uint32_array_value (), lb, ub);
1423 else if (x.is_uint64_type ())
1424 retcell = do_cellslices_nda (x.uint64_array_value (), lb, ub);
1426 else if (x.is_complex_type ())
1428 if (x.is_single_type ())
1429 retcell = do_cellslices_nda (x.float_complex_array_value (), lb, ub);
1431 retcell = do_cellslices_nda (x.complex_array_value (), lb, ub);
1435 if (x.is_single_type ())
1436 retcell = do_cellslices_nda (x.float_array_value (), lb, ub);
1438 retcell = do_cellslices_nda (x.array_value (), lb, ub);
1444 octave_idx_type n = lb.length ();
1445 retcell = Cell (1, n);
1446 octave_idx_type nind = x.dims ().is_vector () ? 1 : x.ndims ();
1447 octave_value_list idx (nind, octave_value::magic_colon_t);
1448 for (octave_idx_type i = 0; i < n && ! error_state; i++)
1450 idx(nind-1) = Range (lb(i), ub(i));
1451 retcell(i) = x.do_index_op (idx);
1466;;; Local Variables: ***