changelog shortlog tags changeset files revisions annotate raw

src/DLD-FUNCTIONS/cellfun.cc

changeset 9846: 1d90fc211872
parent:7b9cbaad68d6
author: John W. Eaton <jwe@octave.org>
date: Sat Nov 21 21:44:51 2009 -0500 (33 hours ago)
permissions: -rw-r--r--
description: configure.ac: report freetype, fontconfig, and fltk cflags and libs info
1/*
2
3Copyright (C) 2005, 2006, 2007, 2008, 2009 Mohamed Kamoun
4Copyright (C) 2009 Jaroslav Hajek
5
6This file is part of Octave.
7
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.
12
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
16for more details.
17
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/>.
21
22*/
23
24#ifdef HAVE_CONFIG_H
25#include <config.h>
26#endif
27
28#include <string>
29#include <vector>
30#include <list>
31#include <memory>
32
33#include "lo-mappers.h"
34#include "oct-locbuf.h"
35
36#include "Cell.h"
37#include "oct-map.h"
38#include "defun-dld.h"
39#include "parse.h"
40#include "variables.h"
41#include "ov-colon.h"
42#include "unwind-prot.h"
43#include "gripes.h"
44#include "utils.h"
45
46// Rationale:
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.
52
53class scalar_col_helper
54{
55public:
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) { }
59};
60
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.
64
65class scalar_col_helper_def : public scalar_col_helper
66{
67 std::list<octave_value_list> idx_list;
68 octave_value resval;
69public:
70 scalar_col_helper_def (const octave_value& val, const dim_vector& dims)
71 : idx_list (1), resval (val)
72 {
73 idx_list.front ().resize (1);
74 if (resval.dims () != dims)
75 resval.resize (dims);
76 }
77 ~scalar_col_helper_def (void) { }
78
79 bool collect (octave_idx_type i, const octave_value& val)
80 {
81 if (val.numel () == 1)
82 {
83 idx_list.front ()(0) = static_cast<double> (i + 1);
84 resval = resval.subsasgn ("(", idx_list, val);
85 }
86 else
87 error ("cellfun: expecting all values to be scalars for UniformOutput = true");
88
89 return true;
90 }
91 octave_value result (void)
92 {
93 return resval;
94 }
95};
96
97template <class T>
98struct scalar_query_helper { };
99
100#define DEF_QUERY_HELPER(T, TEST, QUERY) \
101template <> \
102struct scalar_query_helper<T> \
103{ \
104 static bool has_value (const octave_value& val) \
105 { return TEST; } \
106 static T get_value (const octave_value& val) \
107 { return QUERY; } \
108}
109
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 ());
117// FIXME: More?
118
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.
121
122template <class NDA>
123class scalar_col_helper_nda : public scalar_col_helper
124{
125 NDA arrayval;
126 typedef typename NDA::element_type T;
127public:
128 scalar_col_helper_nda (const octave_value& val, const dim_vector& dims)
129 : arrayval (dims)
130 {
131 arrayval(0) = scalar_query_helper<T>::get_value (val);
132 }
133 ~scalar_col_helper_nda (void) { }
134
135 bool collect (octave_idx_type i, const octave_value& val)
136 {
137 bool retval = scalar_query_helper<T>::has_value (val);
138 if (retval)
139 arrayval(i) = scalar_query_helper<T>::get_value (val);
140 return retval;
141 }
142 octave_value result (void)
143 {
144 return arrayval;
145 }
146};
147
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>;
153
154// the virtual constructor.
155scalar_col_helper *
156make_col_helper (const octave_value& val, const dim_vector& dims)
157{
158 scalar_col_helper *retval;
159
160 if (val.is_bool_scalar ())
161 retval = new scalar_col_helper_nda<boolNDArray> (val, dims);
162 else if (val.is_complex_scalar ())
163 {
164 if (val.is_single_type ())
165 retval = new scalar_col_helper_nda<FloatComplexNDArray> (val, dims);
166 else
167 retval = new scalar_col_helper_nda<ComplexNDArray> (val, dims);
168 }
169 else if (val.is_real_scalar ())
170 {
171 if (val.is_single_type ())
172 retval = new scalar_col_helper_nda<FloatNDArray> (val, dims);
173 else
174 retval = new scalar_col_helper_nda<NDArray> (val, dims);
175 }
176 else
177 retval = new scalar_col_helper_def (val, dims);
178
179 return retval;
180}
181
182DEFUN_DLD (cellfun, args, nargout,
183 "-*- texinfo -*-\n\
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\
192\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\
196\n\
197@table @code\n\
198@item isempty\n\
199Return 1 for empty elements.\n\
200@item islogical\n\
201Return 1 for logical elements.\n\
202@item isreal\n\
203Return 1 for real elements.\n\
204@item length\n\
205Return a vector of the lengths of cell elements.\n\
206@item ndims\n\
207Return the number of dimensions of each element.\n\
208@item prodofsize\n\
209Return the product of dimensions of each element.\n\
210@item size\n\
211Return the size along the @var{k}-th dimension.\n\
212@item isclass\n\
213Return 1 for elements of @var{class}.\n\
214@end table\n\
215\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\
223\n\
224@example\n\
225@group\n\
226cellfun (@@atan2, @{1, 0@}, @{0, 1@})\n\
227@result{}ans = [1.57080 0.00000]\n\
228@end group\n\
229@end example\n\
230\n\
231Note that the default output argument is an array of the same size as the\n\
232input arguments.\n\
233Input arguments that are singleton (1x1) cells will be automatically expanded\n\
234to the size of the other arguments.\n\
235\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\
240\n\
241@example\n\
242@group\n\
243cellfun (\"tolower(x)\", @{\"Foo\", \"Bar\", \"FooBar\"@},\n\
244 \"UniformOutput\",false)\n\
245@result{} ans = @{\"foo\", \"bar\", \"foobar\"@}\n\
246@end group\n\
247@end example\n\
248\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\
251\n\
252@example\n\
253function [@dots{}] = errfunc (@var{s}, @dots{})\n\
254@end example\n\
255\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\
261\n\
262@example\n\
263@group\n\
264function y = foo (s, x), y = NaN; endfunction\n\
265cellfun (@@factorial, @{-1,2@},'ErrorHandler',@@foo)\n\
266@result{} ans = [NaN 2]\n\
267@end group\n\
268@end example\n\
269\n\
270@seealso{isempty, islogical, isreal, length, ndims, numel, size}\n\
271@end deftypefn")
272{
273 octave_value_list retval;
274 int nargin = args.length ();
275 nargout = (nargout < 1 ? 1 : nargout);
276
277 if (nargin < 2)
278 {
279 error ("cellfun: you must supply at least 2 arguments");
280 print_usage ();
281 return retval;
282 }
283
284 octave_value func = args(0);
285
286 if (! args(1).is_cell ())
287 {
288 error ("cellfun: second argument must be a cell array");
289
290 return retval;
291 }
292
293 if (func.is_string ())
294 {
295 const Cell f_args = args(1).cell_value ();
296
297 octave_idx_type k = f_args.numel ();
298
299 std::string name = func.string_value ();
300
301 if (name == "isempty")
302 {
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 ();
306 retval(0) = result;
307 }
308 else if (name == "islogical")
309 {
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 ();
313 retval(0) = result;
314 }
315 else if (name == "isreal")
316 {
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 ();
320 retval(0) = result;
321 }
322 else if (name == "length")
323 {
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 ());
327 retval(0) = result;
328 }
329 else if (name == "ndims")
330 {
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 ());
334 retval(0) = result;
335 }
336 else if (name == "prodofsize" || name == "numel")
337 {
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 ());
341 retval(0) = result;
342 }
343 else if (name == "size")
344 {
345 if (nargin == 3)
346 {
347 int d = args(2).nint_value () - 1;
348
349 if (d < 0)
350 error ("cellfun: third argument must be a positive integer");
351
352 if (! error_state)
353 {
354 NDArray result (f_args.dims ());
355 for (octave_idx_type count = 0; count < k ; count++)
356 {
357 dim_vector dv = f_args.elem(count).dims ();
358 if (d < dv.length ())
359 result(count) = static_cast<double> (dv(d));
360 else
361 result(count) = 1.0;
362 }
363 retval(0) = result;
364 }
365 }
366 else
367 error ("not enough arguments for `size'");
368 }
369 else if (name == "isclass")
370 {
371 if (nargin == 3)
372 {
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);
377
378 retval(0) = result;
379 }
380 else
381 error ("not enough arguments for `isclass'");
382 }
383 else
384 {
385 if (! valid_identifier (name))
386 {
387
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);
396 }
397
398 func = symbol_table::find_function (name);
399 if (func.is_undefined ())
400 error ("cellfun: invalid function name: %s", name.c_str ());
401 }
402 }
403
404 if (error_state || ! retval.empty ())
405 return retval;
406
407 if (func.is_function_handle () || func.is_inline_function ()
408 || func.is_function ())
409 {
410 unwind_protect::frame_id_t uwp_frame = unwind_protect::begin_frame ();
411 unwind_protect::protect_var (buffer_error_messages);
412
413 bool uniform_output = true;
414 octave_value error_handler;
415
416 while (nargin > 3 && args(nargin-2).is_string())
417 {
418 std::string arg = args(nargin-2).string_value();
419
420 std::transform (arg.begin (), arg.end (),
421 arg.begin (), tolower);
422
423 if (arg == "uniformoutput")
424 uniform_output = args(nargin-1).bool_value();
425 else if (arg == "errorhandler")
426 {
427 if (args(nargin-1).is_function_handle () ||
428 args(nargin-1).is_inline_function ())
429 {
430 error_handler = args(nargin-1);
431 }
432 else if (args(nargin-1).is_string ())
433 {
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 ())
437 {
438 error ("cellfun: invalid function name: %s", err_name.c_str ());
439 break;
440 }
441 }
442 else
443 {
444 error ("invalid errorhandler value");
445 break;
446 }
447 }
448 else
449 {
450 error ("cellfun: unrecognized parameter %s",
451 arg.c_str());
452 break;
453 }
454
455 nargin -= 2;
456 }
457
458 nargin -= 1;
459
460 octave_value_list inputlist (nargin, octave_value ());
461
462 OCTAVE_LOCAL_BUFFER (Cell, inputs, nargin);
463 OCTAVE_LOCAL_BUFFER (bool, mask, nargin);
464
465 // This is to prevent copy-on-write.
466 const Cell *cinputs = inputs;
467
468 octave_idx_type k = 1;
469
470 dim_vector fdims (1, 1);
471
472 if (error_state)
473 goto cellfun_err;
474
475 for (int j = 0; j < nargin; j++)
476 {
477 if (! args(j+1).is_cell ())
478 {
479 error ("cellfun: arguments must be cells");
480 goto cellfun_err;
481 }
482
483 inputs[j] = args(j+1).cell_value ();
484 mask[j] = inputs[j].numel () != 1;
485 if (! mask[j])
486 inputlist(j) = cinputs[j](0);
487 }
488
489 for (int j = 0; j < nargin; j++)
490 {
491 if (mask[j])
492 {
493 fdims = inputs[j].dims ();
494 k = inputs[j].numel ();
495 for (int i = j+1; i < nargin; i++)
496 {
497 if (mask[i] && inputs[i].dims () != fdims)
498 {
499 error ("cellfun: Dimensions mismatch.");
500 goto cellfun_err;
501 }
502 }
503 break;
504 }
505 }
506
507 if (error_handler.is_defined ())
508 buffer_error_messages++;
509
510 if (uniform_output)
511 {
512 OCTAVE_LOCAL_BUFFER (std::auto_ptr<scalar_col_helper>, retptr, nargout);
513
514 for (octave_idx_type count = 0; count < k ; count++)
515 {
516 for (int j = 0; j < nargin; j++)
517 {
518 if (mask[j])
519 inputlist(j) = cinputs[j](count);
520 }
521
522 octave_value_list tmp = func.do_multi_index_op (nargout, inputlist);
523
524 if (error_state && error_handler.is_defined ())
525 {
526 Octave_map msg;
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--;
533 error_state = 0;
534 tmp = error_handler.do_multi_index_op (nargout, errlist);
535 buffer_error_messages++;
536
537 if (error_state)
538 goto cellfun_err;
539 }
540
541 if (error_state)
542 goto cellfun_err;
543
544 if (tmp.length() < nargout)
545 {
546 error ("cellfun: too many output arguments");
547 goto cellfun_err;
548 }
549
550 if (count == 0)
551 {
552 for (int j = 0; j < nargout; j++)
553 {
554 octave_value val = tmp(j);
555
556 if (val.numel () == 1)
557 retptr[j].reset (make_col_helper (val, fdims));
558 else
559 {
560 error ("cellfun: expecting all values to be scalars for UniformOutput = true");
561 break;
562 }
563 }
564 }
565 else
566 {
567 for (int j = 0; j < nargout; j++)
568 {
569 octave_value val = tmp(j);
570
571 if (! retptr[j]->collect (count, val))
572 {
573 // FIXME: A more elaborate structure would allow again a virtual
574 // constructor here.
575 retptr[j].reset (new scalar_col_helper_def (retptr[j]->result (),
576 fdims));
577 retptr[j]->collect (count, val);
578 }
579 }
580 }
581
582 if (error_state)
583 break;
584 }
585
586 retval.resize (nargout);
587 for (int j = 0; j < nargout; j++)
588 {
589 if (retptr[j].get ())
590 retval(j) = retptr[j]->result ();
591 else
592 retval(j) = Matrix ();
593 }
594 }
595 else
596 {
597 OCTAVE_LOCAL_BUFFER (Cell, results, nargout);
598 for (int j = 0; j < nargout; j++)
599 results[j].resize (fdims);
600
601 for (octave_idx_type count = 0; count < k ; count++)
602 {
603 for (int j = 0; j < nargin; j++)
604 {
605 if (mask[j])
606 inputlist(j) = cinputs[j](count);
607 }
608
609 octave_value_list tmp = func.do_multi_index_op (nargout, inputlist);
610
611 if (error_state && error_handler.is_defined ())
612 {
613 Octave_map msg;
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--;
620 error_state = 0;
621 tmp = error_handler.do_multi_index_op (nargout, errlist);
622 buffer_error_messages++;
623
624 if (error_state)
625 goto cellfun_err;
626 }
627
628 if (error_state)
629 goto cellfun_err;
630
631 if (tmp.length() < nargout)
632 {
633 error ("cellfun: too many output arguments");
634 goto cellfun_err;
635 }
636
637
638 for (int j = 0; j < nargout; j++)
639 results[j](count) = tmp(j);
640 }
641
642 retval.resize(nargout);
643 for (int j = 0; j < nargout; j++)
644 retval(j) = results[j];
645 }
646
647cellfun_err:
648 if (error_state)
649 retval = octave_value_list();
650
651 unwind_protect::run_frame (uwp_frame);
652 }
653 else
654 error ("cellfun: first argument must be a string or function handle");
655
656 return retval;
657}
658
659/*
660
661%% Test function to check the "Errorhandler" option
662%!function [z] = cellfunerror (S, varargin)
663%! z = S;
664%! endfunction
665
666%% First input argument can be a string, an inline function,
667%% a function_handle or an anonymous function
668%!test
669%! A = cellfun ("islogical", {true, 0.1, false, i*2});
670%! assert (A, [true, false, true, false]);
671%!test
672%! A = cellfun (inline ("islogical (x)", "x"), {true, 0.1, false, i*2});
673%! assert (A, [true, false, true, false]);
674%!test
675%! A = cellfun (@islogical, {true, 0.1, false, i*2});
676%! assert (A, [true, false, true, false]);
677%!test
678%! A = cellfun (@(x) islogical(x), {true, 0.1, false, i*2});
679%! assert (A, [true, false, true, false]);
680
681%% First input argument can be the special string "isreal",
682%% "isempty", "islogical", "length", "ndims" or "prodofsize"
683%!test
684%! A = cellfun ("isreal", {true, 0.1, false, i*2, [], "abc"});
685%! assert (A, [true, true, true, false, true, false]);
686%!test
687%! A = cellfun ("isempty", {true, 0.1, false, i*2, [], "abc"});
688%! assert (A, [false, false, false, false, true, false]);
689%!test
690%! A = cellfun ("islogical", {true, 0.1, false, i*2, [], "abc"});
691%! assert (A, [true, false, true, false, false, false]);
692%!test
693%! A = cellfun ("length", {true, 0.1, false, i*2, [], "abc"});
694%! assert (A, [1, 1, 1, 1, 0, 3]);
695%!test
696%! A = cellfun ("ndims", {[1, 2; 3, 4]; (cell (1,2,3,4))});
697%! assert (A, [2; 4]);
698%!test
699%! A = cellfun ("prodofsize", {[1, 2; 3, 4], (cell (1,2,3,4))});
700%! assert (A, [4, 24]);
701
702%% Number of input and output arguments may not be limited to one
703%!test
704%! A = cellfun (@(x,y,z) x + y + z, {1, 1, 1}, {2, 2, 2}, {3, 4, 5});
705%! assert (A, [6, 7, 8]);
706%!test
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}));
721
722%% Input arguments can be of type cell array of logical
723%!test
724%! A = cellfun (@(x,y) x == y, {false, true}, {true, true});
725%! assert (A, [false, true]);
726%!test
727%! A = cellfun (@(x,y) x == y, {false; true}, {true; true}, \
728%! "UniformOutput", true);
729%! assert (A, [false; true]);
730%!test
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}));
739%!test
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);
755
756%% Input arguments can be of type cell array of numeric
757%!test
758%! A = cellfun (@(x,y) x>y, {1.1, 4.2}, {3.1, 2+3*i});
759%! assert (A, [false, true]);
760%!test
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]);
764%!test
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}));
773%!test
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]);
791
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"});
795%!test
796%! A = cellfun (@(x,y) x>y, {"a"; "f"}, {"c"; "d"}, "UniformOutput", true);
797%! assert (A, [false; true]);
798%!test
799%! A = cellfun (@(x,y) x:y, {"a", "d"}, {"c", "f"}, "UniformOutput", false);
800%! assert (A, {"abc", "def"});
801%!test
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]);
817
818%% Structures cannot be handled by cellfun
819%!error
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);
822
823%% Input arguments can be of type cell array of cell arrays
824%!test
825%! A = cellfun (@(x,y) x{1} < y{1}, {{1.1}, {4.2}}, {{3.1}, {2}});
826%! assert (A, [1, 0], 1e-16);
827%!test
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);
831%!test
832%! A = cellfun (@(x,y) x{1} < y{1}, {{1.1}, {4.2}}, {{3.1}, {2}}, \
833%! "UniformOutput", false);
834%! assert (A, {true, false});
835%!test
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]);
851
852%% Input arguments can be of type cell array of structure arrays
853%!test
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});
856%! assert (A, true);
857%!test
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);
861%! assert (A, true);
862%!test
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});
867%!test
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);
885
886%% A lot of other tests
887%!error(cellfun(1))
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])
912%!test
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'})
917
918*/
919
920static void
921do_num2cell_helper (const dim_vector& dv,
922 const Array<int>& dimv,
923 dim_vector& celldv, dim_vector& arraydv,
924 Array<int>& perm)
925{
926 int dvl = dimv.length ();
927 int maxd = dv.length ();
928 celldv = dv;
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);
933 arraydv = celldv;
934
935 OCTAVE_LOCAL_BUFFER_INIT (bool, sing, maxd, false);
936
937 perm.clear (maxd);
938 for (int i = 0; i < dvl; i++)
939 {
940 int k = dimv(i) - 1;
941 if (k < 0)
942 {
943 error ("num2cell: dimension indices must be positive");
944 return;
945 }
946 else if (i > 0 && k < dimv(i-1) - 1)
947 {
948 error ("num2cell: dimension indices must be strictly increasing");
949 return;
950 }
951
952 sing[k] = true;
953 perm(i) = k;
954 }
955
956 for (int k = 0, i = dvl; k < maxd; k++)
957 if (! sing[k])
958 perm(i++) = k;
959
960 for (int i = 0; i < maxd; i++)
961 if (sing[i])
962 celldv(i) = 1;
963 else
964 arraydv(i) = 1;
965}
966
967template<class NDA>
968static Cell
969do_num2cell (const NDA& array, const Array<int>& dimv)
970{
971 if (dimv.is_empty ())
972 {
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);
977
978 return retval;
979 }
980 else
981 {
982 dim_vector celldv, arraydv;
983 Array<int> perm;
984 do_num2cell_helper (array.dims (), dimv, celldv, arraydv, perm);
985 if (error_state)
986 return Cell ();
987
988 NDA parray = array.permute (perm);
989
990 octave_idx_type nela = arraydv.numel (), nelc = celldv.numel ();
991 parray = parray.reshape (dim_vector (nela, nelc));
992
993 Cell retval (celldv);
994 for (octave_idx_type i = 0; i < nelc; i++)
995 {
996 retval.xelem (i) = NDA (parray.column (i).reshape (arraydv));
997 }
998
999 return retval;
1000 }
1001}
1002
1003
1004DEFUN_DLD (num2cell, args, ,
1005 "-*- texinfo -*-\n\
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\
1012@end deftypefn")
1013{
1014 int nargin = args.length();
1015 octave_value retval;
1016
1017 if (nargin < 1 || nargin > 2)
1018 print_usage ();
1019 else
1020 {
1021 octave_value array = args(0);
1022 Array<int> dimv;
1023 if (nargin > 1)
1024 dimv = args (1).int_vector_value (true);
1025
1026 if (error_state)
1027 ;
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 ())
1033 {
1034 if (array.is_integer_type ())
1035 {
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);
1052 }
1053 else if (array.is_complex_type ())
1054 {
1055 if (array.is_single_type ())
1056 retval = do_num2cell (array.float_complex_array_value (), dimv);
1057 else
1058 retval = do_num2cell (array.complex_array_value (), dimv);
1059 }
1060 else
1061 {
1062 if (array.is_single_type ())
1063 retval = do_num2cell (array.float_array_value (), dimv);
1064 else
1065 retval = do_num2cell (array.array_value (), dimv);
1066 }
1067 }
1068 else if (array.is_cell () || array.is_map ())
1069 {
1070 dim_vector celldv, arraydv;
1071 Array<int> perm;
1072 do_num2cell_helper (array.dims (), dimv, celldv, arraydv, perm);
1073
1074 if (! error_state)
1075 {
1076 // FIXME: this operation may be rather inefficient.
1077 octave_value parray = array.permute (perm);
1078
1079 octave_idx_type nela = arraydv.numel (), nelc = celldv.numel ();
1080 parray = parray.reshape (dim_vector (nela, nelc));
1081
1082 Cell retcell (celldv);
1083 octave_value_list idx (2);
1084 idx(0) = octave_value::magic_colon_t;
1085
1086 for (octave_idx_type i = 0; i < nelc; i++)
1087 {
1088 idx(1) = i + 1;
1089 octave_value tmp = parray.do_index_op (idx);
1090 retcell(i) = tmp.reshape (arraydv);
1091 }
1092
1093 retval = retcell;
1094 }
1095 }
1096 else
1097 gripe_wrong_type_arg ("num2cell", array);
1098 }
1099
1100 return retval;
1101}
1102
1103/*
1104
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]})
1108
1109*/
1110
1111DEFUN_DLD (mat2cell, args, ,
1112 "-*- texinfo -*-\n\
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\
1122\n\
1123Given a single dimensional argument @var{r}, the other dimensional\n\
1124arguments are assumed to equal @code{size (@var{a},@var{i})}.\n\
1125\n\
1126An example of the use of mat2cell is\n\
1127\n\
1128@example\n\
1129mat2cell (reshape(1:16,4,4),[3,1],[3,1])\n\
1130@result{} @{\n\
1131 [1,1] =\n\
1132\n\
1133 1 5 9\n\
1134 2 6 10\n\
1135 3 7 11\n\
1136\n\
1137 [2,1] =\n\
1138\n\
1139 4 8 12\n\
1140\n\
1141 [1,2] =\n\
1142\n\
1143 13\n\
1144 14\n\
1145 15\n\
1146\n\
1147 [2,2] = 16\n\
1148@}\n\
1149@end example\n\
1150@seealso{num2cell, cell2mat}\n\
1151@end deftypefn")
1152{
1153 int nargin = args.length();
1154 octave_value retval;
1155
1156 if (nargin < 2)
1157 print_usage ();
1158 else
1159 {
1160 dim_vector dv = args(0).dims();
1161 dim_vector new_dv;
1162 new_dv.resize(dv.length());
1163
1164 if (nargin > 2)
1165 {
1166 octave_idx_type nmax = -1;
1167
1168 if (nargin - 1 != dv.length())
1169 error ("mat2cell: Incorrect number of dimensions");
1170 else
1171 {
1172 for (octave_idx_type j = 0; j < dv.length(); j++)
1173 {
1174 ColumnVector d = ColumnVector (args(j+1).vector_value
1175 (false, true));
1176
1177 if (d.length() < 1)
1178 {
1179 error ("mat2cell: dimension can not be empty");
1180 break;
1181 }
1182 else
1183 {
1184 if (nmax < d.length())
1185 nmax = d.length();
1186
1187 for (octave_idx_type i = 1; i < d.length(); i++)
1188 {
1189 OCTAVE_QUIT;
1190
1191 if (d(i) >= 0)
1192 d(i) += d(i-1);
1193 else
1194 {
1195 error ("mat2cell: invalid dimensional argument");
1196 break;
1197 }
1198 }
1199
1200 if (d(0) < 0)
1201 error ("mat2cell: invalid dimensional argument");
1202
1203 if (d(d.length() - 1) != dv(j))
1204 error ("mat2cell: inconsistent dimensions");
1205
1206 if (error_state)
1207 break;
1208
1209 new_dv(j) = d.length();
1210 }
1211 }
1212 }
1213
1214 if (! error_state)
1215 {
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++)
1219 {
1220 OCTAVE_QUIT;
1221
1222 ColumnVector d = ColumnVector (args(j+1).vector_value
1223 (false, true));
1224
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);
1228 }
1229
1230
1231 octave_value_list lst (new_dv.length(), octave_value());
1232 Cell ret (new_dv);
1233 octave_idx_type nel = new_dv.numel();
1234 octave_idx_type ntot = 1;
1235
1236 for (int j = 0; j < new_dv.length()-1; j++)
1237 ntot *= new_dv(j);
1238
1239 for (octave_idx_type i = 0; i < nel; i++)
1240 {
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--)
1244 {
1245 OCTAVE_QUIT;
1246
1247 octave_idx_type idx = ii / n;
1248 lst (j) = Range((idx == 0 ? 1. : dimargs(idx-1,j)+1.),
1249 dimargs(idx,j));
1250 ii = ii % n;
1251 if (j != 0)
1252 n /= new_dv(j-1);
1253 }
1254 ret(i) = args(0).do_index_op(lst, 0);
1255 if (error_state)
1256 break;
1257 }
1258
1259 if (!error_state)
1260 retval = ret;
1261 }
1262 }
1263 else
1264 {
1265 ColumnVector d = ColumnVector (args(1).vector_value
1266 (false, true));
1267
1268 double sumd = 0.;
1269 for (octave_idx_type i = 0; i < d.length(); i++)
1270 {
1271 OCTAVE_QUIT;
1272
1273 if (d(i) >= 0)
1274 sumd += d(i);
1275 else
1276 {
1277 error ("mat2cell: invalid dimensional argument");
1278 break;
1279 }
1280 }
1281
1282 if (sumd != dv(0))
1283 error ("mat2cell: inconsistent dimensions");
1284
1285 new_dv(0) = d.length();
1286 for (octave_idx_type i = 1; i < dv.length(); i++)
1287 new_dv(i) = 1;
1288
1289 if (! error_state)
1290 {
1291 octave_value_list lst (new_dv.length(), octave_value());
1292 Cell ret (new_dv);
1293
1294 for (octave_idx_type i = 1; i < new_dv.length(); i++)
1295 lst (i) = Range (1., static_cast<double>(dv(i)));
1296
1297 double idx = 0.;
1298 for (octave_idx_type i = 0; i < new_dv(0); i++)
1299 {
1300 OCTAVE_QUIT;
1301
1302 lst(0) = Range(idx + 1., idx + d(i));
1303 ret(i) = args(0).do_index_op(lst, 0);
1304 idx += d(i);
1305 if (error_state)
1306 break;
1307 }
1308
1309 if (!error_state)
1310 retval = ret;
1311 }
1312 }
1313 }
1314
1315 return retval;
1316}
1317
1318/*
1319
1320%!test
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]})
1324
1325%!test
1326%! x = 'abcdefghij';
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})
1330
1331*/
1332
1333// FIXME: it would be nice to allow ranges being handled without a conversion.
1334template <class NDA>
1335static Cell
1336do_cellslices_nda (const NDA& array,
1337 const Array<octave_idx_type>& lb,
1338 const Array<octave_idx_type>& ub)
1339{
1340 octave_idx_type n = lb.length ();
1341 Cell retval (1, n);
1342 if (array.is_vector ())
1343 {
1344 for (octave_idx_type i = 0; i < n && ! error_state; i++)
1345 retval(i) = array.index (idx_vector (lb(i) - 1, ub(i)));
1346 }
1347 else
1348 {
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++)
1353 {
1354 // Do it with a single index to speed things up.
1355 dv = array.dims ();
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);
1359 }
1360 }
1361
1362 return retval;
1363}
1364
1365DEFUN_DLD (cellslices, args, ,
1366 "-*- texinfo -*-\n\
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\
1371\n\
1372@example\n\
1373@group\n\
1374n = length (lb);\n\
1375sl = cell (1, n);\n\
1376for i = 1:length (lb)\n\
1377 sl@{i@} = x(lb(i):ub(i));\n\
1378endfor\n\
1379@end group\n\
1380@end example\n\
1381\n\
1382If @var{X} is a matrix or array, indexing is done along the last dimension.\n\
1383@seealso{mat2cell}\n\
1384@end deftypefn")
1385{
1386 octave_value retval;
1387 int nargin = args.length ();
1388 if (nargin == 3)
1389 {
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 ();
1393 if (! error_state)
1394 {
1395 if (lb.length () != ub.length ())
1396 error ("cellslices: the lengths of lb and ub must match");
1397 else
1398 {
1399 Cell retcell;
1400 if (! x.is_sparse_type () && x.is_matrix_type ())
1401 {
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 ())
1408 {
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);
1425 }
1426 else if (x.is_complex_type ())
1427 {
1428 if (x.is_single_type ())
1429 retcell = do_cellslices_nda (x.float_complex_array_value (), lb, ub);
1430 else
1431 retcell = do_cellslices_nda (x.complex_array_value (), lb, ub);
1432 }
1433 else
1434 {
1435 if (x.is_single_type ())
1436 retcell = do_cellslices_nda (x.float_array_value (), lb, ub);
1437 else
1438 retcell = do_cellslices_nda (x.array_value (), lb, ub);
1439 }
1440 }
1441 else
1442 {
1443 // generic code.
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++)
1449 {
1450 idx(nind-1) = Range (lb(i), ub(i));
1451 retcell(i) = x.do_index_op (idx);
1452 }
1453 }
1454 if (! error_state)
1455 retval = retcell;
1456 }
1457 }
1458 }
1459 else
1460 print_usage ();
1461
1462 return retval;
1463}
1464
1465/*
1466;;; Local Variables: ***
1467;;; mode: C++ ***
1468;;; End: ***
1469*/