00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #ifdef HAVE_CONFIG_H
00027 #include <config.h>
00028 #endif
00029
00030 #include <string>
00031 #include <vector>
00032 #include <list>
00033 #include <memory>
00034
00035 #include "caseless-str.h"
00036 #include "lo-mappers.h"
00037 #include "oct-locbuf.h"
00038
00039 #include "Cell.h"
00040 #include "oct-map.h"
00041 #include "defun-dld.h"
00042 #include "parse.h"
00043 #include "variables.h"
00044 #include "ov-colon.h"
00045 #include "unwind-prot.h"
00046 #include "gripes.h"
00047 #include "utils.h"
00048
00049 #include "ov-class.h"
00050 #include "ov-scalar.h"
00051 #include "ov-float.h"
00052 #include "ov-complex.h"
00053 #include "ov-flt-complex.h"
00054 #include "ov-bool.h"
00055 #include "ov-int8.h"
00056 #include "ov-int16.h"
00057 #include "ov-int32.h"
00058 #include "ov-int64.h"
00059 #include "ov-uint8.h"
00060 #include "ov-uint16.h"
00061 #include "ov-uint32.h"
00062 #include "ov-uint64.h"
00063
00064 #include "ov-fcn-handle.h"
00065
00066 static octave_value_list
00067 get_output_list (octave_idx_type count, octave_idx_type nargout,
00068 const octave_value_list& inputlist,
00069 octave_value& func,
00070 octave_value& error_handler)
00071 {
00072 octave_value_list tmp;
00073 try {
00074 tmp = func.do_multi_index_op (nargout, inputlist);
00075 }
00076 catch (octave_execution_exception) {
00077 if (error_handler.is_defined ())
00078 error_state = 1;
00079 }
00080
00081 if (error_state)
00082 {
00083 if (error_handler.is_defined ())
00084 {
00085 octave_scalar_map msg;
00086 msg.assign ("identifier", last_error_id ());
00087 msg.assign ("message", last_error_message ());
00088 msg.assign ("index", static_cast<double> (count + static_cast<octave_idx_type>(1)));
00089
00090 octave_value_list errlist = inputlist;
00091 errlist.prepend (msg);
00092
00093 buffer_error_messages--;
00094
00095 error_state = 0;
00096
00097 tmp = error_handler.do_multi_index_op (nargout, errlist);
00098
00099 buffer_error_messages++;
00100
00101 if (error_state)
00102 tmp.clear ();
00103 }
00104 else
00105 tmp.clear ();
00106 }
00107
00108 return tmp;
00109 }
00110
00111 static octave_value_list
00112 try_cellfun_internal_ops (const octave_value_list& args, int nargin)
00113 {
00114 octave_value_list retval;
00115
00116 std::string name = args(0).string_value ();
00117
00118 const Cell f_args = args(1).cell_value ();
00119
00120 octave_idx_type k = f_args.numel ();
00121
00122 if (name == "isempty")
00123 {
00124 boolNDArray result (f_args.dims ());
00125 for (octave_idx_type count = 0; count < k; count++)
00126 result(count) = f_args.elem(count).is_empty ();
00127 retval(0) = result;
00128 }
00129 else if (name == "islogical")
00130 {
00131 boolNDArray result (f_args.dims ());
00132 for (octave_idx_type count= 0; count < k; count++)
00133 result(count) = f_args.elem(count).is_bool_type ();
00134 retval(0) = result;
00135 }
00136 else if (name == "isreal")
00137 {
00138 boolNDArray result (f_args.dims ());
00139 for (octave_idx_type count= 0; count < k; count++)
00140 result(count) = f_args.elem(count).is_real_type ();
00141 retval(0) = result;
00142 }
00143 else if (name == "length")
00144 {
00145 NDArray result (f_args.dims ());
00146 for (octave_idx_type count= 0; count < k; count++)
00147 result(count) = static_cast<double> (f_args.elem(count).length ());
00148 retval(0) = result;
00149 }
00150 else if (name == "ndims")
00151 {
00152 NDArray result (f_args.dims ());
00153 for (octave_idx_type count = 0; count < k; count++)
00154 result(count) = static_cast<double> (f_args.elem(count).ndims ());
00155 retval(0) = result;
00156 }
00157 else if (name == "prodofsize" || name == "numel")
00158 {
00159 NDArray result (f_args.dims ());
00160 for (octave_idx_type count = 0; count < k; count++)
00161 result(count) = static_cast<double> (f_args.elem(count).numel ());
00162 retval(0) = result;
00163 }
00164 else if (name == "size")
00165 {
00166 if (nargin == 3)
00167 {
00168 int d = args(2).nint_value () - 1;
00169
00170 if (d < 0)
00171 error ("cellfun: K must be a positive integer");
00172
00173 if (! error_state)
00174 {
00175 NDArray result (f_args.dims ());
00176 for (octave_idx_type count = 0; count < k; count++)
00177 {
00178 dim_vector dv = f_args.elem(count).dims ();
00179 if (d < dv.length ())
00180 result(count) = static_cast<double> (dv(d));
00181 else
00182 result(count) = 1.0;
00183 }
00184 retval(0) = result;
00185 }
00186 }
00187 else
00188 error ("cellfun: not enough arguments for \"size\"");
00189 }
00190 else if (name == "isclass")
00191 {
00192 if (nargin == 3)
00193 {
00194 std::string class_name = args(2).string_value();
00195 boolNDArray result (f_args.dims ());
00196 for (octave_idx_type count = 0; count < k; count++)
00197 result(count) = (f_args.elem(count).class_name() == class_name);
00198
00199 retval(0) = result;
00200 }
00201 else
00202 error ("cellfun: not enough arguments for \"isclass\"");
00203 }
00204
00205 return retval;
00206 }
00207
00208 static void
00209 get_mapper_fun_options (const octave_value_list& args, int& nargin,
00210 bool& uniform_output, octave_value& error_handler)
00211 {
00212 while (nargin > 3 && args(nargin-2).is_string ())
00213 {
00214 caseless_str arg = args(nargin-2).string_value ();
00215
00216 size_t compare_len = std::max (arg.length (), static_cast<size_t> (2));
00217
00218 if (arg.compare ("uniformoutput", compare_len))
00219 uniform_output = args(nargin-1).bool_value();
00220 else if (arg.compare ("errorhandler", compare_len))
00221 {
00222 if (args(nargin-1).is_function_handle ()
00223 || args(nargin-1).is_inline_function ())
00224 {
00225 error_handler = args(nargin-1);
00226 }
00227 else if (args(nargin-1).is_string ())
00228 {
00229 std::string err_name = args(nargin-1).string_value ();
00230
00231 error_handler = symbol_table::find_function (err_name);
00232
00233 if (error_handler.is_undefined ())
00234 {
00235 error ("cellfun: invalid function NAME: %s",
00236 err_name.c_str ());
00237 break;
00238 }
00239 }
00240 else
00241 {
00242 error ("cellfun: invalid value for 'ErrorHandler' function");
00243 break;
00244 }
00245 }
00246 else
00247 {
00248 error ("cellfun: unrecognized parameter %s",
00249 arg.c_str());
00250 break;
00251 }
00252
00253 nargin -= 2;
00254 }
00255
00256 nargin -= 1;
00257 }
00258
00259 DEFUN_DLD (cellfun, args, nargout,
00260 "-*- texinfo -*-\n\
00261 @deftypefn {Loadable Function} {} cellfun (@var{name}, @var{C})\n\
00262 @deftypefnx {Loadable Function} {} cellfun (\"size\", @var{C}, @var{k})\n\
00263 @deftypefnx {Loadable Function} {} cellfun (\"isclass\", @var{C}, @var{class})\n\
00264 @deftypefnx {Loadable Function} {} cellfun (@var{func}, @var{C})\n\
00265 @deftypefnx {Loadable Function} {} cellfun (@var{func}, @var{C}, @var{D})\n\
00266 @deftypefnx {Loadable Function} {[@var{a}, @dots{}] =} cellfun (@dots{})\n\
00267 @deftypefnx {Loadable Function} {} cellfun (@dots{}, 'ErrorHandler', @var{errfunc})\n\
00268 @deftypefnx {Loadable Function} {} cellfun (@dots{}, 'UniformOutput', @var{val})\n\
00269 \n\
00270 Evaluate the function named @var{name} on the elements of the cell array\n\
00271 @var{C}. Elements in @var{C} are passed on to the named function\n\
00272 individually. The function @var{name} can be one of the functions\n\
00273 \n\
00274 @table @code\n\
00275 @item isempty\n\
00276 Return 1 for empty elements.\n\
00277 \n\
00278 @item islogical\n\
00279 Return 1 for logical elements.\n\
00280 \n\
00281 @item isreal\n\
00282 Return 1 for real elements.\n\
00283 \n\
00284 @item length\n\
00285 Return a vector of the lengths of cell elements.\n\
00286 \n\
00287 @item ndims\n\
00288 Return the number of dimensions of each element.\n\
00289 \n\
00290 @item numel\n\
00291 @itemx prodofsize\n\
00292 Return the number of elements contained within each cell element. The\n\
00293 number is the product of the dimensions of the object at each cell element.\n\
00294 \n\
00295 @item size\n\
00296 Return the size along the @var{k}-th dimension.\n\
00297 \n\
00298 @item isclass\n\
00299 Return 1 for elements of @var{class}.\n\
00300 @end table\n\
00301 \n\
00302 Additionally, @code{cellfun} accepts an arbitrary function @var{func}\n\
00303 in the form of an inline function, function handle, or the name of a\n\
00304 function (in a character string). In the case of a character string\n\
00305 argument, the function must accept a single argument named @var{x}, and\n\
00306 it must return a string value. The function can take one or more arguments,\n\
00307 with the inputs arguments given by @var{C}, @var{D}, etc. Equally the\n\
00308 function can return one or more output arguments. For example:\n\
00309 \n\
00310 @example\n\
00311 @group\n\
00312 cellfun (\"atan2\", @{1, 0@}, @{0, 1@})\n\
00313 @result{}ans = [1.57080 0.00000]\n\
00314 @end group\n\
00315 @end example\n\
00316 \n\
00317 The number of output arguments of @code{cellfun} matches the number of output\n\
00318 arguments of the function. The outputs of the function will be collected\n\
00319 into the output arguments of @code{cellfun} like this:\n\
00320 \n\
00321 @example\n\
00322 @group\n\
00323 function [a, b] = twoouts (x)\n\
00324 a = x;\n\
00325 b = x*x;\n\
00326 endfunction\n\
00327 [aa, bb] = cellfun(@@twoouts, @{1, 2, 3@})\n\
00328 @result{}\n\
00329 aa =\n\
00330 1 2 3\n\
00331 bb =\n\
00332 1 4 9\n\
00333 @end group\n\
00334 @end example\n\
00335 \n\
00336 Note that per default the output argument(s) are arrays of the same size as\n\
00337 the input arguments. Input arguments that are singleton (1x1) cells will be\n\
00338 automatically expanded to the size of the other arguments.\n\
00339 \n\
00340 If the parameter 'UniformOutput' is set to true (the default), then the\n\
00341 function must return scalars which will be concatenated into the return\n\
00342 array(s). If 'UniformOutput' is false, the outputs are concatenated into a\n\
00343 cell array (or cell arrays). For example:\n\
00344 \n\
00345 @example\n\
00346 @group\n\
00347 cellfun (\"tolower\", @{\"Foo\", \"Bar\", \"FooBar\"@},\n\
00348 \"UniformOutput\",false)\n\
00349 @result{} ans = @{\"foo\", \"bar\", \"foobar\"@}\n\
00350 @end group\n\
00351 @end example\n\
00352 \n\
00353 Given the parameter 'ErrorHandler', then @var{errfunc} defines a function to\n\
00354 call in case @var{func} generates an error. The form of the function is\n\
00355 \n\
00356 @example\n\
00357 function [@dots{}] = errfunc (@var{s}, @dots{})\n\
00358 @end example\n\
00359 \n\
00360 @noindent\n\
00361 where there is an additional input argument to @var{errfunc} relative to\n\
00362 @var{func}, given by @var{s}. This is a structure with the elements\n\
00363 'identifier', 'message' and 'index', giving respectively the error\n\
00364 identifier, the error message, and the index into the input arguments\n\
00365 of the element that caused the error. For example:\n\
00366 \n\
00367 @example\n\
00368 @group\n\
00369 function y = foo (s, x), y = NaN; endfunction\n\
00370 cellfun (\"factorial\", @{-1,2@}, 'ErrorHandler', @@foo)\n\
00371 @result{} ans = [NaN 2]\n\
00372 @end group\n\
00373 @end example\n\
00374 \n\
00375 Use @code{cellfun} intelligently. The @code{cellfun} function is a\n\
00376 useful tool for avoiding loops. It is often used with anonymous\n\
00377 function handles; however, calling an anonymous function involves an\n\
00378 overhead quite comparable to the overhead of an m-file function.\n\
00379 Passing a handle to a built-in function is faster, because the\n\
00380 interpreter is not involved in the internal loop. For example:\n\
00381 \n\
00382 @example\n\
00383 @group\n\
00384 a = @{@dots{}@}\n\
00385 v = cellfun (@@(x) det(x), a); # compute determinants\n\
00386 v = cellfun (@@det, a); # faster\n\
00387 @end group\n\
00388 @end example\n\
00389 \n\
00390 @seealso{arrayfun, structfun, spfun}\n\
00391 @end deftypefn")
00392 {
00393 octave_value_list retval;
00394 int nargin = args.length ();
00395 int nargout1 = (nargout < 1 ? 1 : nargout);
00396
00397 if (nargin < 2)
00398 {
00399 error ("cellfun: function requires at least 2 arguments");
00400 print_usage ();
00401 return retval;
00402 }
00403
00404 octave_value func = args(0);
00405
00406 if (! args(1).is_cell ())
00407 {
00408 error ("cellfun: C must be a cell array");
00409
00410 return retval;
00411 }
00412
00413 if (func.is_string ())
00414 {
00415 retval = try_cellfun_internal_ops (args, nargin);
00416
00417 if (error_state || ! retval.empty ())
00418 return retval;
00419
00420
00421
00422 std::string name = args(0).string_value ();
00423
00424 if (! valid_identifier (name))
00425 {
00426 std::string fcn_name = unique_symbol_name ("__cellfun_fcn_");
00427 std::string fname = "function y = " + fcn_name + "(x) y = ";
00428
00429 octave_function *ptr_func
00430 = extract_function (args(0), "cellfun", fcn_name,
00431 fname, "; endfunction");
00432
00433 if (ptr_func && ! error_state)
00434 func = octave_value (ptr_func, true);
00435 }
00436 else
00437 {
00438 func = symbol_table::find_function (name);
00439
00440 if (func.is_undefined ())
00441 error ("cellfun: invalid function NAME: %s", name.c_str ());
00442 }
00443
00444 if (error_state || ! retval.empty ())
00445 return retval;
00446 }
00447
00448 if (func.is_function_handle () || func.is_inline_function ()
00449 || func.is_function ())
00450 {
00451
00452
00453
00454
00455
00456 {
00457 if (func.is_function_handle ())
00458 {
00459 octave_fcn_handle* f = func.fcn_handle_value ();
00460
00461
00462
00463
00464 if (f -> is_overloaded ())
00465 goto nevermind;
00466 }
00467
00468 std::string name = func.function_value () -> name ();
00469 octave_value f = symbol_table::find_function (name);
00470
00471 if (f.is_defined ())
00472 {
00473
00474 if (name != "size" && name != "class")
00475 {
00476
00477 octave_value_list tmp_args = args;
00478 tmp_args(0) = name;
00479 retval = try_cellfun_internal_ops (tmp_args, nargin);
00480 if (error_state || ! retval.empty ())
00481 return retval;
00482 }
00483
00484
00485
00486
00487 func = f;
00488 }
00489 }
00490 nevermind:
00491
00492 bool uniform_output = true;
00493 octave_value error_handler;
00494
00495 get_mapper_fun_options (args, nargin, uniform_output, error_handler);
00496
00497 if (error_state)
00498 return octave_value_list ();
00499
00500
00501
00502 octave_value_list inputlist (nargin, octave_value ());
00503
00504 OCTAVE_LOCAL_BUFFER (Cell, inputs, nargin);
00505 OCTAVE_LOCAL_BUFFER (bool, mask, nargin);
00506
00507
00508 const Cell *cinputs = inputs;
00509
00510 octave_idx_type k = 1;
00511
00512 dim_vector fdims (1, 1);
00513
00514
00515
00516
00517 for (int j = 0; j < nargin; j++)
00518 {
00519 if (! args(j+1).is_cell ())
00520 {
00521 error ("cellfun: arguments must be cells");
00522 return octave_value_list ();
00523 }
00524
00525 inputs[j] = args(j+1).cell_value ();
00526 mask[j] = inputs[j].numel () != 1;
00527 if (! mask[j])
00528 inputlist(j) = cinputs[j](0);
00529 }
00530
00531 for (int j = 0; j < nargin; j++)
00532 {
00533 if (mask[j])
00534 {
00535 fdims = inputs[j].dims ();
00536 k = inputs[j].numel ();
00537 for (int i = j+1; i < nargin; i++)
00538 {
00539 if (mask[i] && inputs[i].dims () != fdims)
00540 {
00541 error ("cellfun: dimensions mismatch");
00542 return octave_value_list ();
00543 }
00544 }
00545 break;
00546 }
00547 }
00548
00549 unwind_protect frame;
00550 frame.protect_var (buffer_error_messages);
00551
00552 if (error_handler.is_defined ())
00553 buffer_error_messages++;
00554
00555
00556
00557 if (uniform_output)
00558 {
00559 std::list<octave_value_list> idx_list (1);
00560 idx_list.front ().resize (1);
00561 std::string idx_type = "(";
00562
00563 OCTAVE_LOCAL_BUFFER (octave_value, retv, nargout1);
00564
00565 for (octave_idx_type count = 0; count < k; count++)
00566 {
00567 for (int j = 0; j < nargin; j++)
00568 {
00569 if (mask[j])
00570 inputlist.xelem (j) = cinputs[j](count);
00571 }
00572
00573 const octave_value_list tmp
00574 = get_output_list (count, nargout, inputlist, func,
00575 error_handler);
00576
00577 if (error_state)
00578 return retval;
00579
00580 if (nargout > 0 && tmp.length () < nargout)
00581 {
00582 error ("cellfun: function returned fewer than nargout values");
00583 return retval;
00584 }
00585
00586 if (nargout > 0
00587 || (nargout == 0
00588 && tmp.length () > 0 && tmp(0).is_defined ()))
00589 {
00590 int num_to_copy = tmp.length ();
00591
00592 if (num_to_copy > nargout1)
00593 num_to_copy = nargout1;
00594
00595 if (count == 0)
00596 {
00597 for (int j = 0; j < num_to_copy; j++)
00598 {
00599 if (tmp(j).is_defined ())
00600 {
00601 octave_value val = tmp(j);
00602
00603 if (val.numel () == 1)
00604 retv[j] = val.resize (fdims);
00605 else
00606 {
00607 error ("cellfun: all values must be scalars when UniformOutput = true");
00608 break;
00609 }
00610 }
00611 }
00612 }
00613 else
00614 {
00615 for (int j = 0; j < num_to_copy; j++)
00616 {
00617 if (tmp(j).is_defined ())
00618 {
00619 octave_value val = tmp(j);
00620
00621 if (! retv[j].fast_elem_insert (count, val))
00622 {
00623 if (val.numel () == 1)
00624 {
00625 idx_list.front ()(0) = count + 1.0;
00626 retv[j].assign (octave_value::op_asn_eq,
00627 idx_type, idx_list, val);
00628
00629 if (error_state)
00630 break;
00631 }
00632 else
00633 {
00634 error ("cellfun: all values must be scalars when UniformOutput = true");
00635 break;
00636 }
00637 }
00638 }
00639 }
00640 }
00641 }
00642
00643 if (error_state)
00644 break;
00645 }
00646
00647 retval.resize (nargout1);
00648
00649 for (int j = 0; j < nargout1; j++)
00650 {
00651 if (nargout > 0 && retv[j].is_undefined ())
00652 retval(j) = NDArray (fdims);
00653 else
00654 retval(j) = retv[j];
00655 }
00656 }
00657 else
00658 {
00659 OCTAVE_LOCAL_BUFFER (Cell, results, nargout1);
00660
00661 for (int j = 0; j < nargout1; j++)
00662 results[j].resize (fdims, Matrix ());
00663
00664 bool have_some_output = false;
00665
00666 for (octave_idx_type count = 0; count < k; count++)
00667 {
00668 for (int j = 0; j < nargin; j++)
00669 {
00670 if (mask[j])
00671 inputlist.xelem (j) = cinputs[j](count);
00672 }
00673
00674 const octave_value_list tmp
00675 = get_output_list (count, nargout, inputlist, func,
00676 error_handler);
00677
00678 if (error_state)
00679 return retval;
00680
00681 if (nargout > 0 && tmp.length () < nargout)
00682 {
00683 error ("cellfun: function returned fewer than nargout values");
00684 return retval;
00685 }
00686
00687 if (nargout > 0
00688 || (nargout == 0
00689 && tmp.length () > 0 && tmp(0).is_defined ()))
00690 {
00691 int num_to_copy = tmp.length ();
00692
00693 if (num_to_copy > nargout1)
00694 num_to_copy = nargout1;
00695
00696 if (num_to_copy > 0)
00697 have_some_output = true;
00698
00699 for (int j = 0; j < num_to_copy; j++)
00700 results[j](count) = tmp(j);
00701 }
00702 }
00703
00704 if (have_some_output || fdims.any_zero ())
00705 {
00706 retval.resize (nargout1);
00707
00708 for (int j = 0; j < nargout1; j++)
00709 retval(j) = results[j];
00710 }
00711 }
00712 }
00713 else
00714 error ("cellfun: argument NAME must be a string or function handle");
00715
00716 return retval;
00717 }
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024 DEFUN_DLD (arrayfun, args, nargout,
01025 "-*- texinfo -*-\n\
01026 @deftypefn {Function File} {} arrayfun (@var{func}, @var{A})\n\
01027 @deftypefnx {Function File} {@var{x} =} arrayfun (@var{func}, @var{A})\n\
01028 @deftypefnx {Function File} {@var{x} =} arrayfun (@var{func}, @var{A}, @var{b}, @dots{})\n\
01029 @deftypefnx {Function File} {[@var{x}, @var{y}, @dots{}] =} arrayfun (@var{func}, @var{A}, @dots{})\n\
01030 @deftypefnx {Function File} {} arrayfun (@dots{}, \"UniformOutput\", @var{val})\n\
01031 @deftypefnx {Function File} {} arrayfun (@dots{}, \"ErrorHandler\", @var{errfunc})\n\
01032 \n\
01033 Execute a function on each element of an array. This is useful for\n\
01034 functions that do not accept array arguments. If the function does\n\
01035 accept array arguments it is better to call the function directly.\n\
01036 \n\
01037 The first input argument @var{func} can be a string, a function\n\
01038 handle, an inline function, or an anonymous function. The input\n\
01039 argument @var{A} can be a logic array, a numeric array, a string\n\
01040 array, a structure array, or a cell array. By a call of the function\n\
01041 @command{arrayfun} all elements of @var{A} are passed on to the named\n\
01042 function @var{func} individually.\n\
01043 \n\
01044 The named function can also take more than two input arguments, with\n\
01045 the input arguments given as third input argument @var{b}, fourth\n\
01046 input argument @var{c}, @dots{} If given more than one array input\n\
01047 argument then all input arguments must have the same sizes, for\n\
01048 example:\n\
01049 \n\
01050 @example\n\
01051 @group\n\
01052 arrayfun (@@atan2, [1, 0], [0, 1])\n\
01053 @result{} ans = [1.5708 0.0000]\n\
01054 @end group\n\
01055 @end example\n\
01056 \n\
01057 If the parameter @var{val} after a further string input argument\n\
01058 \"UniformOutput\" is set @code{true} (the default), then the named\n\
01059 function @var{func} must return a single element which then will be\n\
01060 concatenated into the return value and is of type matrix. Otherwise,\n\
01061 if that parameter is set to @code{false}, then the outputs are\n\
01062 concatenated in a cell array. For example:\n\
01063 \n\
01064 @example\n\
01065 @group\n\
01066 arrayfun (@@(x,y) x:y, \"abc\", \"def\", \"UniformOutput\", false)\n\
01067 @result{} ans =\n\
01068 @{\n\
01069 [1,1] = abcd\n\
01070 [1,2] = bcde\n\
01071 [1,3] = cdef\n\
01072 @}\n\
01073 @end group\n\
01074 @end example\n\
01075 \n\
01076 If more than one output arguments are given then the named function\n\
01077 must return the number of return values that also are expected, for\n\
01078 example:\n\
01079 \n\
01080 @example\n\
01081 @group\n\
01082 [A, B, C] = arrayfun (@@find, [10; 0], \"UniformOutput\", false)\n\
01083 @result{}\n\
01084 A =\n\
01085 @{\n\
01086 [1,1] = 1\n\
01087 [2,1] = [](0x0)\n\
01088 @}\n\
01089 B =\n\
01090 @{\n\
01091 [1,1] = 1\n\
01092 [2,1] = [](0x0)\n\
01093 @}\n\
01094 C =\n\
01095 @{\n\
01096 [1,1] = 10\n\
01097 [2,1] = [](0x0)\n\
01098 @}\n\
01099 @end group\n\
01100 @end example\n\
01101 \n\
01102 If the parameter @var{errfunc} after a further string input argument\n\
01103 \"ErrorHandler\" is another string, a function handle, an inline\n\
01104 function, or an anonymous function, then @var{errfunc} defines a\n\
01105 function to call in the case that @var{func} generates an error.\n\
01106 The definition of the function must be of the form\n\
01107 \n\
01108 @example\n\
01109 function [@dots{}] = errfunc (@var{s}, @dots{})\n\
01110 @end example\n\
01111 \n\
01112 @noindent\n\
01113 where there is an additional input argument to @var{errfunc}\n\
01114 relative to @var{func}, given by @var{s}. This is a structure with\n\
01115 the elements \"identifier\", \"message\", and \"index\" giving,\n\
01116 respectively, the error identifier, the error message, and the index of\n\
01117 the array elements that caused the error. The size of the output\n\
01118 argument of @var{errfunc} must have the same size as the output\n\
01119 argument of @var{func}, otherwise a real error is thrown. For\n\
01120 example:\n\
01121 \n\
01122 @example\n\
01123 @group\n\
01124 function y = ferr (s, x), y = \"MyString\"; endfunction\n\
01125 arrayfun (@@str2num, [1234],\n\
01126 \"UniformOutput\", false, \"ErrorHandler\", @@ferr)\n\
01127 @result{} ans =\n\
01128 @{\n\
01129 [1,1] = MyString\n\
01130 @}\n\
01131 @end group\n\
01132 @end example\n\
01133 \n\
01134 @seealso{spfun, cellfun, structfun}\n\
01135 @end deftypefn")
01136 {
01137 octave_value_list retval;
01138 int nargin = args.length ();
01139 int nargout1 = (nargout < 1 ? 1 : nargout);
01140
01141 if (nargin < 2)
01142 {
01143 error ("arrayfun: function requires at least 2 arguments");
01144 print_usage ();
01145 return retval;
01146 }
01147
01148 octave_value func = args(0);
01149 bool symbol_table_lookup = false;
01150
01151 if (func.is_string ())
01152 {
01153
01154
01155 std::string name = args(0).string_value ();
01156
01157 if (! valid_identifier (name))
01158 {
01159 std::string fcn_name = unique_symbol_name ("__arrayfun_fcn_");
01160 std::string fname = "function y = " + fcn_name + "(x) y = ";
01161
01162 octave_function *ptr_func
01163 = extract_function (args(0), "arrayfun", fcn_name,
01164 fname, "; endfunction");
01165
01166 if (ptr_func && ! error_state)
01167 func = octave_value (ptr_func, true);
01168 }
01169 else
01170 {
01171 func = symbol_table::find_function (name);
01172
01173 if (func.is_undefined ())
01174 error ("arrayfun: invalid function NAME: %s", name.c_str ());
01175
01176 symbol_table_lookup = true;
01177 }
01178
01179 if (error_state)
01180 return retval;
01181 }
01182
01183 if (func.is_function_handle () || func.is_inline_function ()
01184 || func.is_function ())
01185 {
01186
01187
01188
01189
01190
01191 if (! symbol_table_lookup )
01192 {
01193 if (func.is_function_handle ())
01194 {
01195 octave_fcn_handle* f = func.fcn_handle_value ();
01196
01197
01198
01199
01200
01201 if (f -> is_overloaded ())
01202 goto nevermind;
01203 }
01204 octave_value f = symbol_table::find_function (func.function_value ()
01205 -> name ());
01206 if (f.is_defined ())
01207 func = f;
01208 }
01209
01210 nevermind:
01211
01212 bool uniform_output = true;
01213 octave_value error_handler;
01214
01215 get_mapper_fun_options (args, nargin, uniform_output, error_handler);
01216
01217 if (error_state)
01218 return octave_value_list ();
01219
01220 octave_value_list inputlist (nargin, octave_value ());
01221
01222 OCTAVE_LOCAL_BUFFER (octave_value, inputs, nargin);
01223 OCTAVE_LOCAL_BUFFER (bool, mask, nargin);
01224
01225 octave_idx_type k = 1;
01226
01227 dim_vector fdims (1, 1);
01228
01229
01230
01231
01232 for (int j = 0; j < nargin; j++)
01233 {
01234 inputs[j] = args(j+1);
01235 mask[j] = inputs[j].numel () != 1;
01236
01237 if (! mask[j])
01238 inputlist(j) = inputs[j];
01239 }
01240
01241 for (int j = 0; j < nargin; j++)
01242 {
01243 if (mask[j])
01244 {
01245 fdims = inputs[j].dims ();
01246 k = inputs[j].numel ();
01247
01248 for (int i = j+1; i < nargin; i++)
01249 {
01250 if (mask[i] && inputs[i].dims () != fdims)
01251 {
01252 error ("arrayfun: dimensions mismatch");
01253 return retval;
01254 }
01255 }
01256 break;
01257 }
01258 }
01259
01260
01261 unwind_protect frame;
01262 frame.protect_var (buffer_error_messages);
01263
01264 if (error_handler.is_defined ())
01265 buffer_error_messages++;
01266
01267
01268
01269 if (uniform_output)
01270 {
01271 std::list<octave_value_list> idx_list (1);
01272 idx_list.front ().resize (1);
01273 std::string idx_type = "(";
01274
01275 OCTAVE_LOCAL_BUFFER (octave_value, retv, nargout1);
01276
01277 for (octave_idx_type count = 0; count < k; count++)
01278 {
01279 idx_list.front ()(0) = count + 1.0;
01280
01281 for (int j = 0; j < nargin; j++)
01282 {
01283 if (mask[j])
01284 inputlist.xelem (j) = inputs[j].do_index_op (idx_list);
01285
01286 if (error_state)
01287 return retval;
01288 }
01289
01290 const octave_value_list tmp
01291 = get_output_list (count, nargout, inputlist, func,
01292 error_handler);
01293
01294 if (error_state)
01295 return retval;
01296
01297 if (nargout > 0 && tmp.length () < nargout)
01298 {
01299 error ("arrayfun: function returned fewer than nargout values");
01300 return retval;
01301 }
01302
01303 if (nargout > 0
01304 || (nargout == 0
01305 && tmp.length () > 0 && tmp(0).is_defined ()))
01306 {
01307 int num_to_copy = tmp.length ();
01308
01309 if (num_to_copy > nargout1)
01310 num_to_copy = nargout1;
01311
01312 if (count == 0)
01313 {
01314 for (int j = 0; j < num_to_copy; j++)
01315 {
01316 if (tmp(j).is_defined ())
01317 {
01318 octave_value val = tmp(j);
01319
01320 if (val.numel () == 1)
01321 retv[j] = val.resize (fdims);
01322 else
01323 {
01324 error ("arrayfun: all values must be scalars when UniformOutput = true");
01325 break;
01326 }
01327 }
01328 }
01329 }
01330 else
01331 {
01332 for (int j = 0; j < num_to_copy; j++)
01333 {
01334 if (tmp(j).is_defined ())
01335 {
01336 octave_value val = tmp(j);
01337
01338 if (! retv[j].fast_elem_insert (count, val))
01339 {
01340 if (val.numel () == 1)
01341 {
01342 idx_list.front ()(0) = count + 1.0;
01343 retv[j].assign (octave_value::op_asn_eq,
01344 idx_type, idx_list, val);
01345
01346 if (error_state)
01347 break;
01348 }
01349 else
01350 {
01351 error ("arrayfun: all values must be scalars when UniformOutput = true");
01352 break;
01353 }
01354 }
01355 }
01356 }
01357 }
01358 }
01359
01360 if (error_state)
01361 break;
01362 }
01363
01364 retval.resize (nargout1);
01365
01366 for (int j = 0; j < nargout1; j++)
01367 {
01368 if (nargout > 0 && retv[j].is_undefined ())
01369 retval(j) = NDArray (fdims);
01370 else
01371 retval(j) = retv[j];
01372 }
01373 }
01374 else
01375 {
01376 std::list<octave_value_list> idx_list (1);
01377 idx_list.front ().resize (1);
01378 std::string idx_type = "(";
01379
01380 OCTAVE_LOCAL_BUFFER (Cell, results, nargout1);
01381
01382 for (int j = 0; j < nargout1; j++)
01383 results[j].resize (fdims, Matrix ());
01384
01385 bool have_some_output = false;
01386
01387 for (octave_idx_type count = 0; count < k; count++)
01388 {
01389 idx_list.front ()(0) = count + 1.0;
01390
01391 for (int j = 0; j < nargin; j++)
01392 {
01393 if (mask[j])
01394 inputlist.xelem (j) = inputs[j].do_index_op (idx_list);
01395
01396 if (error_state)
01397 return retval;
01398 }
01399
01400 const octave_value_list tmp
01401 = get_output_list (count, nargout, inputlist, func,
01402 error_handler);
01403
01404 if (error_state)
01405 return retval;
01406
01407 if (nargout > 0 && tmp.length () < nargout)
01408 {
01409 error ("arrayfun: function returned fewer than nargout values");
01410 return retval;
01411 }
01412
01413 if (nargout > 0
01414 || (nargout == 0
01415 && tmp.length () > 0 && tmp(0).is_defined ()))
01416 {
01417 int num_to_copy = tmp.length ();
01418
01419 if (num_to_copy > nargout1)
01420 num_to_copy = nargout1;
01421
01422 if (num_to_copy > 0)
01423 have_some_output = true;
01424
01425 for (int j = 0; j < num_to_copy; j++)
01426 results[j](count) = tmp(j);
01427 }
01428 }
01429
01430 if (have_some_output || fdims.any_zero ())
01431 {
01432 retval.resize (nargout1);
01433
01434 for (int j = 0; j < nargout1; j++)
01435 retval(j) = results[j];
01436 }
01437 }
01438 }
01439 else
01440 error ("arrayfun: argument NAME must be a string or function handle");
01441
01442 return retval;
01443 }
01444
01445
01446
01447
01448
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507
01508
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518
01519
01520
01521
01522
01523
01524
01525
01526
01527
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565
01566
01567
01568
01569
01570
01571
01572
01573
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583
01584
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657 static void
01658 do_num2cell_helper (const dim_vector& dv,
01659 const Array<int>& dimv,
01660 dim_vector& celldv, dim_vector& arraydv,
01661 Array<int>& perm)
01662 {
01663 int dvl = dimv.length ();
01664 int maxd = dv.length ();
01665 celldv = dv;
01666 for (int i = 0; i < dvl; i++)
01667 maxd = std::max (maxd, dimv(i));
01668 if (maxd > dv.length ())
01669 celldv.resize (maxd, 1);
01670 arraydv = celldv;
01671
01672 OCTAVE_LOCAL_BUFFER_INIT (bool, sing, maxd, false);
01673
01674 perm.clear (maxd, 1);
01675 for (int i = 0; i < dvl; i++)
01676 {
01677 int k = dimv(i) - 1;
01678 if (k < 0)
01679 {
01680 error ("num2cell: dimension indices must be positive");
01681 return;
01682 }
01683 else if (i > 0 && k < dimv(i-1) - 1)
01684 {
01685 error ("num2cell: dimension indices must be strictly increasing");
01686 return;
01687 }
01688
01689 sing[k] = true;
01690 perm(i) = k;
01691 }
01692
01693 for (int k = 0, i = dvl; k < maxd; k++)
01694 if (! sing[k])
01695 perm(i++) = k;
01696
01697 for (int i = 0; i < maxd; i++)
01698 if (sing[i])
01699 celldv(i) = 1;
01700 else
01701 arraydv(i) = 1;
01702 }
01703
01704 template<class NDA>
01705 static inline typename NDA::element_type
01706 do_num2cell_elem (const NDA& array, octave_idx_type i)
01707 { return array(i); }
01708
01709 static inline Cell
01710 do_num2cell_elem (const Cell& array, octave_idx_type i)
01711 { return Cell (array(i)); }
01712
01713
01714 template<class NDA>
01715 static Cell
01716 do_num2cell (const NDA& array, const Array<int>& dimv)
01717 {
01718 if (dimv.is_empty ())
01719 {
01720 Cell retval (array.dims ());
01721 octave_idx_type nel = array.numel ();
01722 for (octave_idx_type i = 0; i < nel; i++)
01723 retval.xelem (i) = do_num2cell_elem (array, i);
01724
01725 return retval;
01726 }
01727 else
01728 {
01729 dim_vector celldv, arraydv;
01730 Array<int> perm;
01731 do_num2cell_helper (array.dims (), dimv, celldv, arraydv, perm);
01732 if (error_state)
01733 return Cell ();
01734
01735 NDA parray = array.permute (perm);
01736
01737 octave_idx_type nela = arraydv.numel (), nelc = celldv.numel ();
01738 parray = parray.reshape (dim_vector (nela, nelc));
01739
01740 Cell retval (celldv);
01741 for (octave_idx_type i = 0; i < nelc; i++)
01742 {
01743 retval.xelem (i) = NDA (parray.column (i).reshape (arraydv));
01744 }
01745
01746 return retval;
01747 }
01748 }
01749
01750
01751
01752
01753
01754 static dim_vector
01755 get_object_dims (octave_value& obj)
01756 {
01757 dim_vector retval;
01758
01759 Matrix m = obj.size ();
01760
01761 int n = m.numel ();
01762
01763 retval.resize (n);
01764
01765 for (int i = 0; i < n; i++)
01766 retval(i) = m(i);
01767
01768 return retval;
01769 }
01770
01771 static Cell
01772 do_object2cell (const octave_value& obj, const Array<int>& dimv)
01773 {
01774 Cell retval;
01775
01776
01777
01778 octave_value array = obj;
01779
01780 if (dimv.is_empty ())
01781 {
01782 dim_vector dv = get_object_dims (array);
01783
01784 if (! error_state)
01785 {
01786 retval.resize (dv);
01787
01788 octave_value_list idx (1);
01789
01790 for (octave_idx_type i = 0; i < dv.numel (); i++)
01791 {
01792 octave_quit ();
01793
01794 idx(0) = double (i+1);
01795
01796 retval.xelem(i) = array.single_subsref ("(", idx);
01797
01798 if (error_state)
01799 break;
01800 }
01801 }
01802 }
01803 else
01804 {
01805 error ("num2cell (A, dim) not implemented for class objects");
01806 }
01807
01808 return retval;
01809 }
01810
01811 DEFUN_DLD (num2cell, args, ,
01812 "-*- texinfo -*-\n\
01813 @deftypefn {Loadable Function} {@var{C} =} num2cell (@var{A})\n\
01814 @deftypefnx {Loadable Function} {@var{C} =} num2cell (@var{A}, @var{dim})\n\
01815 Convert the numeric matrix @var{A} to a cell array. If @var{dim} is\n\
01816 defined, the value @var{C} is of dimension 1 in this dimension and the\n\
01817 elements of @var{A} are placed into @var{C} in slices. For example:\n\
01818 \n\
01819 @example\n\
01820 @group\n\
01821 num2cell([1,2;3,4])\n\
01822 @result{} ans =\n\
01823 @{\n\
01824 [1,1] = 1\n\
01825 [2,1] = 3\n\
01826 [1,2] = 2\n\
01827 [2,2] = 4\n\
01828 @}\n\
01829 num2cell([1,2;3,4],1)\n\
01830 @result{} ans =\n\
01831 @{\n\
01832 [1,1] =\n\
01833 1\n\
01834 3\n\
01835 [1,2] =\n\
01836 2\n\
01837 4\n\
01838 @}\n\
01839 @end group\n\
01840 @end example\n\
01841 \n\
01842 @seealso{mat2cell}\n\
01843 @end deftypefn")
01844 {
01845 int nargin = args.length();
01846 octave_value retval;
01847
01848 if (nargin < 1 || nargin > 2)
01849 print_usage ();
01850 else
01851 {
01852 octave_value array = args(0);
01853 Array<int> dimv;
01854 if (nargin > 1)
01855 dimv = args (1).int_vector_value (true);
01856
01857 if (error_state)
01858 ;
01859 else if (array.is_bool_type ())
01860 retval = do_num2cell (array.bool_array_value (), dimv);
01861 else if (array.is_char_matrix ())
01862 retval = do_num2cell (array.char_array_value (), dimv);
01863 else if (array.is_numeric_type ())
01864 {
01865 if (array.is_integer_type ())
01866 {
01867 if (array.is_int8_type ())
01868 retval = do_num2cell (array.int8_array_value (), dimv);
01869 else if (array.is_int16_type ())
01870 retval = do_num2cell (array.int16_array_value (), dimv);
01871 else if (array.is_int32_type ())
01872 retval = do_num2cell (array.int32_array_value (), dimv);
01873 else if (array.is_int64_type ())
01874 retval = do_num2cell (array.int64_array_value (), dimv);
01875 else if (array.is_uint8_type ())
01876 retval = do_num2cell (array.uint8_array_value (), dimv);
01877 else if (array.is_uint16_type ())
01878 retval = do_num2cell (array.uint16_array_value (), dimv);
01879 else if (array.is_uint32_type ())
01880 retval = do_num2cell (array.uint32_array_value (), dimv);
01881 else if (array.is_uint64_type ())
01882 retval = do_num2cell (array.uint64_array_value (), dimv);
01883 }
01884 else if (array.is_complex_type ())
01885 {
01886 if (array.is_single_type ())
01887 retval = do_num2cell (array.float_complex_array_value (), dimv);
01888 else
01889 retval = do_num2cell (array.complex_array_value (), dimv);
01890 }
01891 else
01892 {
01893 if (array.is_single_type ())
01894 retval = do_num2cell (array.float_array_value (), dimv);
01895 else
01896 retval = do_num2cell (array.array_value (), dimv);
01897 }
01898 }
01899 else if (array.is_object ())
01900 retval = do_object2cell (array, dimv);
01901 else if (array.is_map ())
01902 retval = do_num2cell (array.map_value (), dimv);
01903 else if (array.is_cell ())
01904 retval = do_num2cell (array.cell_value (), dimv);
01905 else if (array.is_object ())
01906 retval = do_num2cell (array.cell_value (), dimv);
01907 else
01908 gripe_wrong_type_arg ("num2cell", array);
01909 }
01910
01911 return retval;
01912 }
01913
01914
01915
01916
01917
01918
01919
01920
01921
01922 static bool
01923 mat2cell_mismatch (const dim_vector& dv,
01924 const Array<octave_idx_type> *d, int nd)
01925 {
01926 for (int i = 0; i < nd; i++)
01927 {
01928 octave_idx_type s = 0;
01929 for (octave_idx_type j = 0; j < d[i].length (); j++)
01930 s += d[i](j);
01931
01932 octave_idx_type r = i < dv.length () ? dv(i) : 1;
01933
01934 if (s != r)
01935 {
01936 error ("mat2cell: mismatch on %d-th dimension (%d != %d)",
01937 i+1, r, s);
01938 return true;
01939 }
01940 }
01941
01942 return false;
01943 }
01944
01945 template<class container>
01946 static void
01947 prepare_idx (container *idx, int idim, int nd,
01948 const Array<octave_idx_type>* d)
01949 {
01950 octave_idx_type nidx = idim < nd ? d[idim].numel () : 1;
01951 if (nidx == 1)
01952 idx[0] = idx_vector::colon;
01953 else
01954 {
01955 octave_idx_type l = 0;
01956 for (octave_idx_type i = 0; i < nidx; i++)
01957 {
01958 octave_idx_type u = l + d[idim](i);
01959 idx[i] = idx_vector (l, u);
01960 l = u;
01961 }
01962 }
01963 }
01964
01965
01966
01967
01968 template <class Array2D>
01969 static Cell
01970 do_mat2cell_2d (const Array2D& a, const Array<octave_idx_type> *d, int nd)
01971 {
01972 NoAlias<Cell> retval;
01973 assert (nd == 1 || nd == 2);
01974 assert (a.ndims () == 2);
01975
01976 if (mat2cell_mismatch (a.dims (), d, nd))
01977 return retval;
01978
01979 octave_idx_type nridx = d[0].length ();
01980 octave_idx_type ncidx = nd == 1 ? 1 : d[1].length ();
01981 retval.clear (nridx, ncidx);
01982
01983 int ivec = -1;
01984 if (a.rows () > 1 && a.cols () == 1 && ncidx == 1)
01985 ivec = 0;
01986 else if (a.rows () == 1 && nridx == 1 && nd == 2)
01987 ivec = 1;
01988
01989 if (ivec >= 0)
01990 {
01991
01992 octave_idx_type l = 0, nidx = (ivec == 0 ? nridx : ncidx);
01993 for (octave_idx_type i = 0; i < nidx; i++)
01994 {
01995 octave_idx_type u = l + d[ivec](i);
01996 retval(i) = a.index (idx_vector (l, u));
01997 l = u;
01998 }
01999 }
02000 else
02001 {
02002
02003 OCTAVE_LOCAL_BUFFER (idx_vector, ridx, nridx);
02004 prepare_idx (ridx, 0, nd, d);
02005
02006 OCTAVE_LOCAL_BUFFER (idx_vector, cidx, ncidx);
02007 prepare_idx (cidx, 1, nd, d);
02008
02009 for (octave_idx_type j = 0; j < ncidx; j++)
02010 for (octave_idx_type i = 0; i < nridx; i++)
02011 {
02012 octave_quit ();
02013
02014 retval(i,j) = a.index (ridx[i], cidx[j]);
02015 }
02016 }
02017
02018 return retval;
02019 }
02020
02021
02022
02023
02024 template <class ArrayND>
02025 Cell
02026 do_mat2cell_nd (const ArrayND& a, const Array<octave_idx_type> *d, int nd)
02027 {
02028 NoAlias<Cell> retval;
02029 assert (nd >= 1);
02030
02031 if (mat2cell_mismatch (a.dims (), d, nd))
02032 return retval;
02033
02034 dim_vector rdv = dim_vector::alloc (nd);
02035 OCTAVE_LOCAL_BUFFER (octave_idx_type, nidx, nd);
02036 octave_idx_type idxtot = 0;
02037 for (int i = 0; i < nd; i++)
02038 {
02039 rdv(i) = nidx[i] = d[i].length ();
02040 idxtot += nidx[i];
02041 }
02042
02043 retval.clear (rdv);
02044
02045 OCTAVE_LOCAL_BUFFER (idx_vector, xidx, idxtot);
02046 OCTAVE_LOCAL_BUFFER (idx_vector *, idx, nd);
02047
02048 idxtot = 0;
02049 for (int i = 0; i < nd; i++)
02050 {
02051 idx[i] = xidx + idxtot;
02052 prepare_idx (idx[i], i, nd, d);
02053 idxtot += nidx[i];
02054 }
02055
02056 OCTAVE_LOCAL_BUFFER_INIT (octave_idx_type, ridx, nd, 0);
02057 NoAlias< Array<idx_vector> > ra_idx
02058 (dim_vector (1, std::max (nd, a.ndims ())), idx_vector::colon);
02059
02060 for (octave_idx_type j = 0; j < retval.numel (); j++)
02061 {
02062 octave_quit ();
02063
02064 for (int i = 0; i < nd; i++)
02065 ra_idx(i) = idx[i][ridx[i]];
02066
02067 retval(j) = a.index (ra_idx);
02068
02069 rdv.increment_index (ridx);
02070 }
02071
02072 return retval;
02073 }
02074
02075
02076 template <class ArrayND>
02077 Cell
02078 do_mat2cell (const ArrayND& a, const Array<octave_idx_type> *d, int nd)
02079 {
02080 if (a.ndims () == 2 && nd <= 2)
02081 return do_mat2cell_2d (a, d, nd);
02082 else
02083 return do_mat2cell_nd (a, d, nd);
02084 }
02085
02086
02087
02088
02089 Cell
02090 do_mat2cell (octave_value& a, const Array<octave_idx_type> *d, int nd)
02091 {
02092 NoAlias<Cell> retval;
02093 assert (nd >= 1);
02094
02095 if (mat2cell_mismatch (a.dims (), d, nd))
02096 return retval;
02097
02098 dim_vector rdv = dim_vector::alloc (nd);
02099 OCTAVE_LOCAL_BUFFER (octave_idx_type, nidx, nd);
02100 octave_idx_type idxtot = 0;
02101 for (int i = 0; i < nd; i++)
02102 {
02103 rdv(i) = nidx[i] = d[i].length ();
02104 idxtot += nidx[i];
02105 }
02106
02107 retval.clear (rdv);
02108
02109 OCTAVE_LOCAL_BUFFER (octave_value, xidx, idxtot);
02110 OCTAVE_LOCAL_BUFFER (octave_value *, idx, nd);
02111
02112 idxtot = 0;
02113 for (int i = 0; i < nd; i++)
02114 {
02115 idx[i] = xidx + idxtot;
02116 prepare_idx (idx[i], i, nd, d);
02117 idxtot += nidx[i];
02118 }
02119
02120 OCTAVE_LOCAL_BUFFER_INIT (octave_idx_type, ridx, nd, 0);
02121 octave_value_list ra_idx (std::max (nd, a.ndims ()),
02122 octave_value::magic_colon_t);
02123
02124 for (octave_idx_type j = 0; j < retval.numel (); j++)
02125 {
02126 octave_quit ();
02127
02128 for (int i = 0; i < nd; i++)
02129 ra_idx(i) = idx[i][ridx[i]];
02130
02131 retval(j) = a.do_index_op (ra_idx);
02132
02133 if (error_state)
02134 break;
02135
02136 rdv.increment_index (ridx);
02137 }
02138
02139 return retval;
02140 }
02141
02142 DEFUN_DLD (mat2cell, args, ,
02143 "-*- texinfo -*-\n\
02144 @deftypefn {Loadable Function} {@var{C} =} mat2cell (@var{A}, @var{m}, @var{n})\n\
02145 @deftypefnx {Loadable Function} {@var{C} =} mat2cell (@var{A}, @var{d1}, @var{d2}, @dots{})\n\
02146 @deftypefnx {Loadable Function} {@var{C} =} mat2cell (@var{A}, @var{r})\n\
02147 Convert the matrix @var{A} to a cell array. If @var{A} is 2-D, then\n\
02148 it is required that @code{sum (@var{m}) == size (@var{A}, 1)} and\n\
02149 @code{sum (@var{n}) == size (@var{A}, 2)}. Similarly, if @var{A} is\n\
02150 multi-dimensional and the number of dimensional arguments is equal\n\
02151 to the dimensions of @var{A}, then it is required that @code{sum (@var{di})\n\
02152 == size (@var{A}, i)}.\n\
02153 \n\
02154 Given a single dimensional argument @var{r}, the other dimensional\n\
02155 arguments are assumed to equal @code{size (@var{A},@var{i})}.\n\
02156 \n\
02157 An example of the use of mat2cell is\n\
02158 \n\
02159 @example\n\
02160 mat2cell (reshape(1:16,4,4),[3,1],[3,1])\n\
02161 @result{} @{\n\
02162 [1,1] =\n\
02163 \n\
02164 1 5 9\n\
02165 2 6 10\n\
02166 3 7 11\n\
02167 \n\
02168 [2,1] =\n\
02169 \n\
02170 4 8 12\n\
02171 \n\
02172 [1,2] =\n\
02173 \n\
02174 13\n\
02175 14\n\
02176 15\n\
02177 \n\
02178 [2,2] = 16\n\
02179 @}\n\
02180 @end example\n\
02181 @seealso{num2cell, cell2mat}\n\
02182 @end deftypefn")
02183 {
02184 int nargin = args.length();
02185 octave_value retval;
02186
02187 if (nargin < 2)
02188 print_usage ();
02189 else
02190 {
02191
02192 OCTAVE_LOCAL_BUFFER (Array<octave_idx_type>, d, nargin-1);
02193
02194 for (int i = 1; i < nargin; i++)
02195 {
02196 d[i-1] = args(i).octave_idx_type_vector_value (true);
02197 if (error_state)
02198 return retval;
02199 }
02200
02201 octave_value a = args(0);
02202 bool sparse = a.is_sparse_type ();
02203 if (sparse && nargin > 3)
02204 {
02205 error ("mat2cell: sparse arguments only support 2D indexing");
02206 return retval;
02207 }
02208
02209 switch (a.builtin_type ())
02210 {
02211 case btyp_double:
02212 {
02213 if (sparse)
02214 retval = do_mat2cell_2d (a.sparse_matrix_value (), d, nargin-1);
02215 else
02216 retval = do_mat2cell (a.array_value (), d, nargin - 1);
02217 break;
02218 }
02219 case btyp_complex:
02220 {
02221 if (sparse)
02222 retval = do_mat2cell_2d (a.sparse_complex_matrix_value (), d, nargin-1);
02223 else
02224 retval = do_mat2cell (a.complex_array_value (), d, nargin - 1);
02225 break;
02226 }
02227 #define BTYP_BRANCH(X,Y) \
02228 case btyp_ ## X: \
02229 retval = do_mat2cell (a.Y ## _value (), d, nargin - 1); \
02230 break
02231
02232 BTYP_BRANCH (float, float_array);
02233 BTYP_BRANCH (float_complex, float_complex_array);
02234 BTYP_BRANCH (bool, bool_array);
02235 BTYP_BRANCH (char, char_array);
02236
02237 BTYP_BRANCH (int8, int8_array);
02238 BTYP_BRANCH (int16, int16_array);
02239 BTYP_BRANCH (int32, int32_array);
02240 BTYP_BRANCH (int64, int64_array);
02241 BTYP_BRANCH (uint8, uint8_array);
02242 BTYP_BRANCH (uint16, uint16_array);
02243 BTYP_BRANCH (uint32, uint32_array);
02244 BTYP_BRANCH (uint64, uint64_array);
02245
02246 BTYP_BRANCH (cell, cell);
02247 BTYP_BRANCH (struct, map);
02248 #undef BTYP_BRANCH
02249
02250 case btyp_func_handle:
02251 gripe_wrong_type_arg ("mat2cell", a);
02252 break;
02253 default:
02254 retval = do_mat2cell (a, d, nargin-1);
02255 }
02256 }
02257
02258 return retval;
02259 }
02260
02261
02262
02263
02264
02265
02266
02267
02268
02269
02270
02271
02272
02273
02274
02275
02276
02277 template <class NDA>
02278 static Cell
02279 do_cellslices_nda (const NDA& array,
02280 const Array<octave_idx_type>& lb,
02281 const Array<octave_idx_type>& ub,
02282 int dim = -1)
02283 {
02284 octave_idx_type n = lb.length ();
02285 Cell retval (1, n);
02286 if (array.is_vector () && (dim == -1
02287 || (dim == 0 && array.columns () == 1)
02288 || (dim == 1 && array.rows () == 1)))
02289 {
02290 for (octave_idx_type i = 0; i < n && ! error_state; i++)
02291 retval(i) = array.index (idx_vector (lb(i) - 1, ub(i)));
02292 }
02293 else
02294 {
02295 const dim_vector dv = array.dims ();
02296 int ndims = dv.length ();
02297 if (dim < 0)
02298 dim = dv.first_non_singleton ();
02299 ndims = std::max (ndims, dim + 1);
02300
02301 Array<idx_vector> idx (dim_vector (ndims, 1), idx_vector::colon);
02302
02303 for (octave_idx_type i = 0; i < n && ! error_state; i++)
02304 {
02305 idx(dim) = idx_vector (lb(i) - 1, ub(i));
02306 retval(i) = array.index (idx);
02307 }
02308 }
02309
02310 return retval;
02311 }
02312
02313 DEFUN_DLD (cellslices, args, ,
02314 "-*- texinfo -*-\n\
02315 @deftypefn {Loadable Function} {@var{sl} =} cellslices (@var{x}, @var{lb}, @var{ub}, @var{dim})\n\
02316 Given an array @var{x}, this function produces a cell array of slices from\n\
02317 the array determined by the index vectors @var{lb}, @var{ub}, for lower and\n\
02318 upper bounds, respectively. In other words, it is equivalent to the\n\
02319 following code:\n\
02320 \n\
02321 @example\n\
02322 @group\n\
02323 n = length (lb);\n\
02324 sl = cell (1, n);\n\
02325 for i = 1:length (lb)\n\
02326 sl@{i@} = x(:,@dots{},lb(i):ub(i),@dots{},:);\n\
02327 endfor\n\
02328 @end group\n\
02329 @end example\n\
02330 \n\
02331 The position of the index is determined by @var{dim}. If not specified,\n\
02332 slicing is done along the first non-singleton dimension.\n\
02333 @seealso{cell2mat, cellindexmat, cellfun}\n\
02334 @end deftypefn")
02335 {
02336 octave_value retval;
02337 int nargin = args.length ();
02338 if (nargin == 3 || nargin == 4)
02339 {
02340 octave_value x = args(0);
02341 Array<octave_idx_type> lb = args(1).octave_idx_type_vector_value ();
02342 Array<octave_idx_type> ub = args(2).octave_idx_type_vector_value ();
02343 int dim = -1;
02344 if (nargin == 4)
02345 {
02346 dim = args(3).int_value () - 1;
02347 if (dim < 0)
02348 error ("cellslices: DIM must be a valid dimension");
02349 }
02350
02351 if (! error_state)
02352 {
02353 if (lb.length () != ub.length ())
02354 error ("cellslices: the lengths of LB and UB must match");
02355 else
02356 {
02357 Cell retcell;
02358 if (! x.is_sparse_type () && x.is_matrix_type ())
02359 {
02360
02361 if (x.is_bool_type ())
02362 retcell = do_cellslices_nda (x.bool_array_value (), lb, ub, dim);
02363 else if (x.is_char_matrix ())
02364 retcell = do_cellslices_nda (x.char_array_value (), lb, ub, dim);
02365 else if (x.is_integer_type ())
02366 {
02367 if (x.is_int8_type ())
02368 retcell = do_cellslices_nda (x.int8_array_value (), lb, ub, dim);
02369 else if (x.is_int16_type ())
02370 retcell = do_cellslices_nda (x.int16_array_value (), lb, ub, dim);
02371 else if (x.is_int32_type ())
02372 retcell = do_cellslices_nda (x.int32_array_value (), lb, ub, dim);
02373 else if (x.is_int64_type ())
02374 retcell = do_cellslices_nda (x.int64_array_value (), lb, ub, dim);
02375 else if (x.is_uint8_type ())
02376 retcell = do_cellslices_nda (x.uint8_array_value (), lb, ub, dim);
02377 else if (x.is_uint16_type ())
02378 retcell = do_cellslices_nda (x.uint16_array_value (), lb, ub, dim);
02379 else if (x.is_uint32_type ())
02380 retcell = do_cellslices_nda (x.uint32_array_value (), lb, ub, dim);
02381 else if (x.is_uint64_type ())
02382 retcell = do_cellslices_nda (x.uint64_array_value (), lb, ub, dim);
02383 }
02384 else if (x.is_complex_type ())
02385 {
02386 if (x.is_single_type ())
02387 retcell = do_cellslices_nda (x.float_complex_array_value (), lb, ub, dim);
02388 else
02389 retcell = do_cellslices_nda (x.complex_array_value (), lb, ub, dim);
02390 }
02391 else
02392 {
02393 if (x.is_single_type ())
02394 retcell = do_cellslices_nda (x.float_array_value (), lb, ub, dim);
02395 else
02396 retcell = do_cellslices_nda (x.array_value (), lb, ub, dim);
02397 }
02398 }
02399 else
02400 {
02401
02402 octave_idx_type n = lb.length ();
02403 retcell = Cell (1, n);
02404 const dim_vector dv = x.dims ();
02405 int ndims = dv.length ();
02406 if (dim < 0)
02407 dim = dv.first_non_singleton ();
02408 ndims = std::max (ndims, dim + 1);
02409 octave_value_list idx (ndims, octave_value::magic_colon_t);
02410 for (octave_idx_type i = 0; i < n && ! error_state; i++)
02411 {
02412 idx(dim) = Range (lb(i), ub(i));
02413 retcell(i) = x.do_index_op (idx);
02414 }
02415 }
02416 if (! error_state)
02417 retval = retcell;
02418 }
02419 }
02420 }
02421 else
02422 print_usage ();
02423
02424 return retval;
02425 }
02426
02427
02428
02429
02430
02431
02432
02433
02434 DEFUN_DLD (cellindexmat, args, ,
02435 "-*- texinfo -*-\n\
02436 @deftypefn {Loadable Function} {@var{y} =} cellindexmat (@var{x}, @var{varargin})\n\
02437 Given a cell array of matrices @var{x}, this function computes\n\
02438 \n\
02439 @example\n\
02440 @group\n\
02441 Y = cell (size (X));\n\
02442 for i = 1:numel (X)\n\
02443 Y@{i@} = X@{i@}(varargin@{:@});\n\
02444 endfor\n\
02445 @end group\n\
02446 @end example\n\
02447 @seealso{cellslices, cellfun}\n\
02448 @end deftypefn")
02449 {
02450 octave_value retval;
02451 if (args.length () >= 1)
02452 {
02453 if (args(0).is_cell ())
02454 {
02455 const Cell x = args(0).cell_value ();
02456 NoAlias<Cell> y(x.dims ());
02457 octave_idx_type nel = x.numel ();
02458 octave_value_list idx = args.slice (1, args.length () - 1);
02459
02460 for (octave_idx_type i = 0; i < nel; i++)
02461 {
02462 octave_quit ();
02463 octave_value tmp = x(i);
02464 y(i) = tmp.do_index_op (idx);
02465 if (error_state)
02466 break;
02467 }
02468
02469 retval = y;
02470 }
02471 else
02472 error ("cellindexmat: X must be a cell");
02473 }
02474 else
02475 print_usage ();
02476
02477 return retval;
02478 }