5205
|
1 /* |
|
2 |
7017
|
3 Copyright (C) 2005, 2006, 2007 Mohamed Kamoun |
5205
|
4 |
|
5 This file is part of Octave. |
|
6 |
|
7 Octave is free software; you can redistribute it and/or modify it |
|
8 under the terms of the GNU General Public License as published by the |
7016
|
9 Free Software Foundation; either version 3 of the License, or (at your |
|
10 option) any later version. |
5205
|
11 |
|
12 Octave is distributed in the hope that it will be useful, but WITHOUT |
|
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
15 for more details. |
|
16 |
|
17 You should have received a copy of the GNU General Public License |
7016
|
18 along with Octave; see the file COPYING. If not, see |
|
19 <http://www.gnu.org/licenses/>. |
5205
|
20 |
|
21 */ |
|
22 |
|
23 #ifdef HAVE_CONFIG_H |
|
24 #include <config.h> |
|
25 #endif |
|
26 |
|
27 #include <string> |
5988
|
28 #include <vector> |
|
29 #include <list> |
5205
|
30 |
|
31 #include "lo-mappers.h" |
|
32 |
|
33 #include "Cell.h" |
5988
|
34 #include "oct-map.h" |
5205
|
35 #include "defun-dld.h" |
|
36 #include "parse.h" |
|
37 #include "variables.h" |
5451
|
38 #include "ov-colon.h" |
5988
|
39 #include "unwind-prot.h" |
5205
|
40 |
5988
|
41 extern octave_value_list |
|
42 Flasterr (const octave_value_list& args_name, int nargout_name); |
|
43 |
|
44 DEFUN_DLD (cellfun, args, nargout, |
5205
|
45 " -*- texinfo -*-\n\ |
6854
|
46 @deftypefn {Loadable Function} {} cellfun (@var{name}, @var{c})\n\ |
|
47 @deftypefnx {Loadable Function} {} cellfun (\"size\", @var{c}, @var{k})\n\ |
|
48 @deftypefnx {Loadable Function} {} cellfun (\"isclass\", @var{c}, @var{class})\n\ |
|
49 @deftypefnx {Loadable Function} {} cellfun (@var{func}, @var{c})\n\ |
|
50 @deftypefnx {Loadable Function} {} cellfun (@var{func}, @var{c}, @var{d})\n\ |
|
51 @deftypefnx {Loadable Function} {[@var{a}, @var{b}] =} cellfun (@dots{})\n\ |
|
52 @deftypefnx {Loadable Function} {} cellfun (@dots{}, 'ErrorHandler', @var{errfunc})\n\ |
|
53 @deftypefnx {Loadable Function} {} cellfun (@dots{}, 'UniformOutput', @var{val})\n\ |
5205
|
54 \n\ |
|
55 Evaluate the function named @var{name} on the elements of the cell array\n\ |
5543
|
56 @var{c}. Elements in @var{c} are passed on to the named function\n\ |
5205
|
57 individually. The function @var{name} can be one of the functions\n\ |
|
58 \n\ |
|
59 @table @code\n\ |
|
60 @item isempty\n\ |
5543
|
61 Return 1 for empty elements.\n\ |
5205
|
62 @item islogical\n\ |
|
63 Return 1 for logical elements.\n\ |
|
64 @item isreal\n\ |
|
65 Return 1 for real elements.\n\ |
|
66 @item length\n\ |
|
67 Return a vector of the lengths of cell elements.\n\ |
5543
|
68 @item ndims\n\ |
5205
|
69 Return the number of dimensions of each element.\n\ |
|
70 @item prodofsize\n\ |
|
71 Return the product of dimensions of each element.\n\ |
|
72 @item size\n\ |
|
73 Return the size along the @var{k}-th dimension.\n\ |
|
74 @item isclass\n\ |
|
75 Return 1 for elements of @var{class}.\n\ |
|
76 @end table\n\ |
|
77 \n\ |
|
78 Additionally, @code{cellfun} accepts an arbitrary function @var{func}\n\ |
|
79 in the form of an inline function, function handle, or the name of a\n\ |
5988
|
80 function (in a character string). In the case of a character string\n\ |
|
81 argument, the function must accept a single argument named @var{x}, and\n\ |
|
82 it must return a string value. The function can take one or more arguments,\n\ |
|
83 with the inputs args given by @var{c}, @var{d}, etc. Equally the function\n\ |
|
84 can return one or more output arguments. For example\n\ |
5205
|
85 \n\ |
|
86 @example\n\ |
|
87 @group\n\ |
5988
|
88 cellfun (@@atan2, @{1, 0@}, @{0, 1@})\n\ |
|
89 @result{}ans = [1.57080 0.00000]\n\ |
|
90 @end group\n\ |
|
91 @end example\n\ |
|
92 \n\ |
|
93 Note that the default output argument is an array of the same size as the\n\ |
|
94 input arguments.\n\ |
|
95 \n\ |
|
96 If the param 'UniformOutput' is set to true (the default), then the function\n\ |
|
97 must return either a single element which will be concatenated into the\n\ |
|
98 return value. If 'UniformOutput is false, the outputs are concatenated in\n\ |
|
99 a cell array. For example\n\ |
|
100 \n\ |
|
101 @example\n\ |
|
102 @group\n\ |
6623
|
103 cellfun (\"tolower(x)\", @{\"Foo\", \"Bar\", \"FooBar\"@},\n\ |
|
104 \"UniformOutput\",false)\n\ |
5205
|
105 @result{} ans = @{\"foo\", \"bar\", \"foobar\"@}\n\ |
|
106 @end group\n\ |
|
107 @end example\n\ |
5988
|
108 \n\ |
|
109 Given the parameter 'ErrorHandler', then @var{errfunc} defines a function to\n\ |
|
110 call in case @var{func} generates an error. The form of the function is\n\ |
|
111 \n\ |
|
112 @example\n\ |
|
113 function [@dots{}] = errfunc (@var{s}, @dots{})\n\ |
|
114 @end example\n\ |
|
115 \n\ |
|
116 where there is an additional input argument to @var{errfunc} relative to\n\ |
|
117 @var{func}, given by @var{s}. This is a structure with the elements\n\ |
|
118 'identifier', 'message' and 'index', giving respectively the error\n\ |
|
119 identifier, the error message, and the index into the input arguments\n\ |
|
120 of the element that caused the error. For example\n\ |
|
121 \n\ |
|
122 @example\n\ |
|
123 @group\n\ |
|
124 function y = foo (s, x), y = NaN; endfunction\n\ |
|
125 cellfun (@@factorial, @{-1,2@},'ErrorHandler',@@foo)\n\ |
|
126 @result{} ans = [NaN 2]\n\ |
|
127 @end group\n\ |
|
128 @end example\n\ |
|
129 \n\ |
5642
|
130 @seealso{isempty, islogical, isreal, length, ndims, numel, size, isclass}\n\ |
|
131 @end deftypefn") |
5205
|
132 { |
5988
|
133 octave_value_list retval; |
5205
|
134 std::string name = "function"; |
|
135 octave_function *func = 0; |
|
136 int nargin = args.length (); |
5988
|
137 nargout = (nargout < 1 ? 1 : nargout); |
5205
|
138 |
|
139 if (nargin < 2) |
|
140 { |
|
141 error ("cellfun: you must supply at least 2 arguments"); |
5823
|
142 print_usage (); |
5205
|
143 return retval; |
|
144 } |
|
145 |
|
146 if (args(0).is_function_handle () || args(0).is_inline_function ()) |
|
147 { |
|
148 func = args(0).function_value (); |
|
149 |
|
150 if (error_state) |
|
151 return retval; |
|
152 } |
|
153 else if (args(0).is_string ()) |
|
154 name = args(0).string_value (); |
|
155 else |
|
156 { |
5543
|
157 error ("cellfun: first argument must be a string or function handle"); |
5205
|
158 return retval; |
|
159 } |
|
160 |
|
161 if (! args(1).is_cell ()) |
|
162 { |
5543
|
163 error ("cellfun: second argument must be a cell array"); |
5205
|
164 |
|
165 return retval; |
|
166 } |
|
167 |
|
168 Cell f_args = args(1).cell_value (); |
|
169 |
5988
|
170 octave_idx_type k = f_args.numel (); |
5205
|
171 |
|
172 if (name == "isempty") |
|
173 { |
|
174 boolNDArray result (f_args.dims ()); |
5988
|
175 for (octave_idx_type count = 0; count < k ; count++) |
5543
|
176 result(count) = f_args.elem(count).is_empty (); |
5988
|
177 retval(0) = result; |
5205
|
178 } |
|
179 else if (name == "islogical") |
|
180 { |
|
181 boolNDArray result (f_args.dims ()); |
5988
|
182 for (octave_idx_type count= 0; count < k ; count++) |
5205
|
183 result(count) = f_args.elem(count).is_bool_type (); |
5988
|
184 retval(0) = result; |
5205
|
185 } |
|
186 else if (name == "isreal") |
|
187 { |
|
188 boolNDArray result (f_args.dims ()); |
5988
|
189 for (octave_idx_type count= 0; count < k ; count++) |
5205
|
190 result(count) = f_args.elem(count).is_real_type (); |
5988
|
191 retval(0) = result; |
5205
|
192 } |
|
193 else if (name == "length") |
|
194 { |
|
195 NDArray result (f_args.dims ()); |
5988
|
196 for (octave_idx_type count= 0; count < k ; count++) |
5544
|
197 result(count) = static_cast<double> (f_args.elem(count).length ()); |
5988
|
198 retval(0) = result; |
5205
|
199 } |
|
200 else if (name == "ndims") |
|
201 { |
|
202 NDArray result (f_args.dims ()); |
5988
|
203 for (octave_idx_type count = 0; count < k ; count++) |
5544
|
204 result(count) = static_cast<double> (f_args.elem(count).ndims ()); |
5988
|
205 retval(0) = result; |
5205
|
206 } |
|
207 else if (name == "prodofsize") |
|
208 { |
|
209 NDArray result (f_args.dims ()); |
5988
|
210 for (octave_idx_type count = 0; count < k ; count++) |
5544
|
211 result(count) = static_cast<double> (f_args.elem(count).numel ()); |
5988
|
212 retval(0) = result; |
5205
|
213 } |
|
214 else if (name == "size") |
|
215 { |
|
216 if (nargin == 3) |
|
217 { |
|
218 int d = args(2).nint_value () - 1; |
|
219 |
|
220 if (d < 0) |
7001
|
221 error ("cellfun: third argument must be a positive integer"); |
5205
|
222 |
6484
|
223 if (! error_state) |
5205
|
224 { |
|
225 NDArray result (f_args.dims ()); |
5988
|
226 for (octave_idx_type count = 0; count < k ; count++) |
5205
|
227 { |
|
228 dim_vector dv = f_args.elem(count).dims (); |
|
229 if (d < dv.length ()) |
5544
|
230 result(count) = static_cast<double> (dv(d)); |
5205
|
231 else |
|
232 result(count) = 1.0; |
|
233 } |
5988
|
234 retval(0) = result; |
5205
|
235 } |
|
236 } |
|
237 else |
5543
|
238 error ("not enough arguments for `size'"); |
5205
|
239 } |
|
240 else if (name == "isclass") |
|
241 { |
|
242 if (nargin == 3) |
|
243 { |
|
244 std::string class_name = args(2).string_value(); |
|
245 boolNDArray result (f_args.dims ()); |
5988
|
246 for (octave_idx_type count = 0; count < k ; count++) |
5205
|
247 result(count) = (f_args.elem(count).class_name() == class_name); |
|
248 |
5988
|
249 retval(0) = result; |
5205
|
250 } |
|
251 else |
5543
|
252 error ("not enough arguments for `isclass'"); |
5205
|
253 } |
|
254 else |
|
255 { |
5988
|
256 unwind_protect::begin_frame ("Fcellfun"); |
|
257 unwind_protect_int (buffer_error_messages); |
|
258 |
5205
|
259 std::string fcn_name; |
|
260 |
|
261 if (! func) |
|
262 { |
|
263 fcn_name = unique_symbol_name ("__cellfun_fcn_"); |
|
264 std::string fname = "function y = "; |
|
265 fname.append (fcn_name); |
|
266 fname.append ("(x) y = "); |
|
267 func = extract_function (args(0), "cellfun", fcn_name, fname, |
|
268 "; endfunction"); |
|
269 } |
|
270 |
|
271 if (! func) |
|
272 error ("unknown function"); |
|
273 else |
|
274 { |
5988
|
275 octave_value_list idx; |
|
276 octave_value_list inputlist; |
6484
|
277 bool uniform_output = true; |
|
278 bool have_error_handler = false; |
5988
|
279 std::string err_name; |
6484
|
280 octave_function *error_handler = 0; |
5988
|
281 int offset = 1; |
|
282 int i = 1; |
|
283 OCTAVE_LOCAL_BUFFER (Cell, inputs, nargin); |
5205
|
284 |
5988
|
285 while (i < nargin) |
5205
|
286 { |
5988
|
287 if (args(i).is_string()) |
|
288 { |
|
289 std::string arg = args(i++).string_value(); |
|
290 if (i == nargin) |
|
291 { |
|
292 error ("cellfun: parameter value is missing"); |
|
293 goto cellfun_err; |
|
294 } |
|
295 |
|
296 std::transform (arg.begin (), arg.end (), |
|
297 arg.begin (), tolower); |
|
298 |
|
299 if (arg == "uniformoutput") |
6484
|
300 uniform_output = args(i++).bool_value(); |
5988
|
301 else if (arg == "errorhandler") |
|
302 { |
|
303 if (args(i).is_function_handle () || |
|
304 args(i).is_inline_function ()) |
|
305 { |
6484
|
306 error_handler = args(i).function_value (); |
5205
|
307 |
5988
|
308 if (error_state) |
|
309 goto cellfun_err; |
|
310 } |
|
311 else if (args(i).is_string ()) |
|
312 { |
|
313 err_name = unique_symbol_name ("__cellfun_fcn_"); |
|
314 std::string fname = "function y = "; |
|
315 fname.append (fcn_name); |
|
316 fname.append ("(x) y = "); |
6484
|
317 error_handler = extract_function (args(i), "cellfun", |
|
318 err_name, fname, |
|
319 "; endfunction"); |
5988
|
320 } |
|
321 |
6484
|
322 if (! error_handler) |
5988
|
323 goto cellfun_err; |
|
324 |
6484
|
325 have_error_handler = true; |
5988
|
326 i++; |
|
327 } |
|
328 else |
|
329 { |
|
330 error ("cellfun: unrecognized parameter %s", |
|
331 arg.c_str()); |
|
332 goto cellfun_err; |
|
333 } |
|
334 offset += 2; |
|
335 } |
|
336 else |
|
337 { |
|
338 inputs[i-offset] = args(i).cell_value (); |
|
339 if (f_args.dims() != inputs[i-offset].dims()) |
|
340 { |
|
341 error ("cellfun: Dimension mismatch"); |
|
342 goto cellfun_err; |
|
343 |
|
344 } |
|
345 i++; |
|
346 } |
5205
|
347 } |
|
348 |
5988
|
349 inputlist.resize(nargin-offset); |
|
350 |
6484
|
351 if (have_error_handler) |
5988
|
352 buffer_error_messages++; |
|
353 |
6484
|
354 if (uniform_output) |
5988
|
355 { |
|
356 retval.resize(nargout); |
|
357 |
|
358 for (octave_idx_type count = 0; count < k ; count++) |
|
359 { |
5989
|
360 for (int j = 0; j < nargin-offset; j++) |
|
361 inputlist(j) = inputs[j](count); |
5988
|
362 |
|
363 octave_value_list tmp = feval (func, inputlist, nargout); |
|
364 |
6484
|
365 if (error_state && have_error_handler) |
5988
|
366 { |
|
367 octave_value_list errtmp = |
|
368 Flasterr (octave_value_list (), 2); |
|
369 |
|
370 Octave_map msg; |
|
371 msg.assign ("identifier", errtmp(1)); |
|
372 msg.assign ("message", errtmp(0)); |
|
373 msg.assign ("index", octave_value(double (count))); |
|
374 octave_value_list errlist = inputlist; |
|
375 errlist.prepend (msg); |
|
376 buffer_error_messages--; |
|
377 error_state = 0; |
6484
|
378 tmp = feval (error_handler, errlist, nargout); |
5988
|
379 buffer_error_messages++; |
|
380 |
|
381 if (error_state) |
|
382 goto cellfun_err; |
|
383 } |
|
384 |
|
385 if (tmp.length() < nargout) |
|
386 { |
|
387 error ("cellfun: too many output arguments"); |
|
388 goto cellfun_err; |
|
389 } |
|
390 |
|
391 if (error_state) |
|
392 break; |
|
393 |
|
394 if (count == 0) |
|
395 { |
5989
|
396 for (int j = 0; j < nargout; j++) |
5988
|
397 { |
|
398 octave_value val; |
5989
|
399 val = tmp(j); |
5988
|
400 |
|
401 if (error_state) |
|
402 goto cellfun_err; |
|
403 |
6422
|
404 retval(j) = val.resize(f_args.dims()); |
5988
|
405 } |
|
406 } |
|
407 else |
|
408 { |
|
409 idx(0) = octave_value (static_cast<double>(count+1)); |
5989
|
410 for (int j = 0; j < nargout; j++) |
|
411 { |
|
412 // FIXME -- need an easier way to express |
|
413 // this test. |
|
414 octave_value val = tmp(j); |
|
415 |
|
416 if (val.ndims () == 2 |
|
417 && val.rows () == 1 && val.columns () == 1) |
|
418 retval(j) = |
|
419 retval(j).subsasgn ("(", |
|
420 std::list<octave_value_list> |
|
421 (1, idx(0)), val); |
|
422 else |
|
423 error ("cellfun: expecting all values to be scalars for UniformOutput = true"); |
|
424 } |
5988
|
425 } |
|
426 |
|
427 if (error_state) |
|
428 break; |
|
429 } |
|
430 } |
|
431 else |
|
432 { |
|
433 OCTAVE_LOCAL_BUFFER (Cell, results, nargout); |
5989
|
434 for (int j = 0; j < nargout; j++) |
|
435 results[j].resize(f_args.dims()); |
5988
|
436 |
|
437 for (octave_idx_type count = 0; count < k ; count++) |
|
438 { |
5989
|
439 for (int j = 0; j < nargin-offset; j++) |
|
440 inputlist(j) = inputs[j](count); |
5988
|
441 |
|
442 octave_value_list tmp = feval (func, inputlist, nargout); |
|
443 |
6484
|
444 if (error_state && have_error_handler) |
5988
|
445 { |
|
446 octave_value_list errtmp = |
|
447 Flasterr (octave_value_list (), 2); |
|
448 |
|
449 Octave_map msg; |
|
450 msg.assign ("identifier", errtmp(1)); |
|
451 msg.assign ("message", errtmp(0)); |
|
452 msg.assign ("index", octave_value(double (count))); |
|
453 octave_value_list errlist = inputlist; |
|
454 errlist.prepend (msg); |
|
455 buffer_error_messages--; |
|
456 error_state = 0; |
6484
|
457 tmp = feval (error_handler, errlist, nargout); |
5988
|
458 buffer_error_messages++; |
|
459 |
|
460 if (error_state) |
|
461 goto cellfun_err; |
|
462 } |
|
463 |
|
464 if (tmp.length() < nargout) |
|
465 { |
|
466 error ("cellfun: too many output arguments"); |
|
467 goto cellfun_err; |
|
468 } |
|
469 |
|
470 if (error_state) |
|
471 break; |
|
472 |
|
473 |
5989
|
474 for (int j = 0; j < nargout; j++) |
|
475 results[j](count) = tmp(j); |
5988
|
476 } |
|
477 |
|
478 retval.resize(nargout); |
5989
|
479 for (int j = 0; j < nargout; j++) |
|
480 retval(j) = results[j]; |
5988
|
481 } |
|
482 |
|
483 cellfun_err: |
|
484 if (error_state) |
|
485 retval = octave_value_list(); |
5205
|
486 |
|
487 if (! fcn_name.empty ()) |
|
488 clear_function (fcn_name); |
5988
|
489 |
|
490 if (! err_name.empty ()) |
|
491 clear_function (err_name); |
5205
|
492 } |
5988
|
493 |
|
494 unwind_protect::run_frame ("Fcellfun"); |
5205
|
495 } |
|
496 |
|
497 return retval; |
|
498 } |
|
499 |
5988
|
500 /* |
|
501 |
|
502 %!error(cellfun(1)) |
|
503 %!error(cellfun('isclass',1)) |
|
504 %!error(cellfun('size',1)) |
|
505 %!error(cellfun(@sin,{[]},'BadParam',false)) |
|
506 %!error(cellfun(@sin,{[]},'UniformOuput')) |
|
507 %!error(cellfun(@sin,{[]},'ErrorHandler')) |
|
508 %!assert(cellfun(@sin,{0,1}),sin([0,1])) |
|
509 %!assert(cellfun(inline('sin(x)'),{0,1}),sin([0,1])) |
|
510 %!assert(cellfun('sin',{0,1}),sin([0,1])) |
|
511 %!assert(cellfun('isempty',{1,[]}),[false,true]) |
|
512 %!assert(cellfun('islogical',{false,pi}),[true,false]) |
|
513 %!assert(cellfun('isreal',{1i,1}),[false,true]) |
|
514 %!assert(cellfun('length',{zeros(2,2),1}),[2,1]) |
|
515 %!assert(cellfun('prodofsize',{zeros(2,2),1}),[4,1]) |
|
516 %!assert(cellfun('ndims',{zeros([2,2,2]),1}),[3,2]) |
|
517 %!assert(cellfun('isclass',{zeros([2,2,2]),'test'},'double'),[true,false]) |
|
518 %!assert(cellfun('size',{zeros([1,2,3]),1},1),[1,1]) |
|
519 %!assert(cellfun('size',{zeros([1,2,3]),1},2),[2,1]) |
|
520 %!assert(cellfun('size',{zeros([1,2,3]),1},3),[3,1]) |
|
521 %!assert(cellfun(@atan2,{1,1},{1,2}),[atan2(1,1),atan2(1,2)]) |
|
522 %!assert(cellfun(@atan2,{1,1},{1,2},'UniformOutput',false),{atan2(1,1),atan2(1,2)}) |
6422
|
523 %!assert(cellfun(@sin,{1,2;3,4}),sin([1,2;3,4])) |
|
524 %!assert(cellfun(@atan2,{1,1;1,1},{1,2;1,2}),atan2([1,1;1,1],[1,2;1,2])) |
5988
|
525 %!error(cellfun(@factorial,{-1,3})) |
|
526 %!assert(cellfun(@factorial,{-1,3},'ErrorHandler',@(x,y) NaN),[NaN,6]) |
|
527 %!test |
6704
|
528 %! [a,b,c]=cellfun(@fileparts,{fullfile("a","b","c.d"),fullfile("e","f","g.h")},'UniformOutput',false); |
|
529 %! assert(a,{fullfile("a","b"),fullfile("e","f")}) |
5988
|
530 %! assert(b,{'c','g'}) |
|
531 %! assert(c,{'.d','.h'}) |
|
532 |
|
533 */ |
|
534 |
5451
|
535 DEFUN_DLD (num2cell, args, , |
|
536 "-*- texinfo -*-\n\ |
|
537 @deftypefn {Loadable Function} {@var{c} =} num2cell (@var{m})\n\ |
|
538 @deftypefnx {Loadable Function} {@var{c} =} num2cell (@var{m}, @var{d})\n\ |
|
539 Convert to matrix @var{m} into a cell array. If @var{d} is defined the\n\ |
|
540 value @var{c} is of dimension 1 in this dimension and the elements of\n\ |
|
541 @var{m} are placed in slices in @var{c}.\n\ |
5642
|
542 @seealso{mat2cell}\n\ |
|
543 @end deftypefn") |
5451
|
544 { |
|
545 int nargin = args.length(); |
|
546 octave_value retval; |
|
547 |
|
548 if (nargin < 1 || nargin > 2) |
5823
|
549 print_usage (); |
5451
|
550 else |
|
551 { |
|
552 dim_vector dv = args(0).dims (); |
|
553 Array<int> sings; |
|
554 |
|
555 if (nargin == 2) |
|
556 { |
|
557 ColumnVector dsings = ColumnVector (args(1).vector_value |
|
558 (false, true)); |
|
559 sings.resize (dsings.length()); |
|
560 |
|
561 if (!error_state) |
5988
|
562 for (octave_idx_type i = 0; i < dsings.length(); i++) |
5451
|
563 if (dsings(i) > dv.length() || dsings(i) < 1 || |
|
564 D_NINT(dsings(i)) != dsings(i)) |
|
565 { |
|
566 error ("invalid dimension specified"); |
|
567 break; |
|
568 } |
|
569 else |
|
570 sings(i) = NINT(dsings(i)) - 1; |
|
571 } |
|
572 |
|
573 if (! error_state) |
|
574 { |
|
575 Array<bool> idx_colon (dv.length()); |
|
576 dim_vector new_dv (dv); |
|
577 octave_value_list lst (new_dv.length(), octave_value()); |
|
578 |
|
579 for (int i = 0; i < dv.length(); i++) |
|
580 { |
|
581 idx_colon(i) = false; |
|
582 for (int j = 0; j < sings.length(); j++) |
|
583 { |
|
584 if (sings(j) == i) |
|
585 { |
|
586 new_dv(i) = 1; |
|
587 idx_colon(i) = true; |
|
588 lst(i) = octave_value (octave_value::magic_colon_t); |
|
589 break; |
|
590 } |
|
591 } |
|
592 } |
|
593 |
|
594 Cell ret (new_dv); |
|
595 octave_idx_type nel = new_dv.numel(); |
|
596 octave_idx_type ntot = 1; |
|
597 |
|
598 for (int j = 0; j < new_dv.length()-1; j++) |
|
599 ntot *= new_dv(j); |
|
600 |
|
601 for (octave_idx_type i = 0; i < nel; i++) |
|
602 { |
|
603 octave_idx_type n = ntot; |
|
604 octave_idx_type ii = i; |
|
605 for (int j = new_dv.length() - 1; j >= 0 ; j--) |
|
606 { |
|
607 if (! idx_colon(j)) |
|
608 lst (j) = ii/n + 1; |
|
609 ii = ii % n; |
|
610 if (j != 0) |
|
611 n /= new_dv(j-1); |
|
612 } |
|
613 ret(i) = args(0).do_index_op(lst, 0); |
|
614 } |
|
615 |
|
616 retval = ret; |
|
617 } |
|
618 } |
|
619 |
|
620 return retval; |
|
621 } |
|
622 |
5988
|
623 /* |
|
624 |
|
625 %!assert(num2cell([1,2;3,4]),{1,2;3,4}) |
|
626 %!assert(num2cell([1,2;3,4],1),{[1;3],[2;4]}) |
|
627 %!assert(num2cell([1,2;3,4],2),{[1,2];[3,4]}) |
|
628 |
|
629 */ |
|
630 |
5784
|
631 DEFUN_DLD (mat2cell, args, , |
|
632 "-*- texinfo -*-\n\ |
|
633 @deftypefn {Loadable Function} {@var{b} =} mat2cell (@var{a}, @var{m}, @var{n})\n\ |
|
634 @deftypefnx {Loadable Function} {@var{b} =} mat2cell (@var{a}, @var{d1}, @var{d2}, @dots{})\n\ |
|
635 @deftypefnx {Loadable Function} {@var{b} =} mat2cell (@var{a}, @var{r})\n\ |
|
636 Converts the matrix @var{a} to a cell array If @var{a} is 2-D, then\n\ |
|
637 it is required that @code{sum (@var{m}) == size (@var{a}, 1)} and\n\ |
|
638 @code{sum (@var{n}) == size (@var{a}, 2)}. Similarly, if @var{a} is\n\ |
|
639 a multi-dimensional and the number of dimensional arguments is equal\n\ |
|
640 to the dimensions of @var{a}, then it is required that @code{sum (@var{di})\n\ |
|
641 == size (@var{a}, i)}.\n\ |
|
642 \n\ |
|
643 Given a single dimensional argument @var{r}, the other dimensional\n\ |
|
644 arguments are assumed to equal @code{size (@var{a},@var{i})}.\n\ |
|
645 \n\ |
|
646 An example of the use of mat2cell is\n\ |
|
647 \n\ |
|
648 @example\n\ |
|
649 @group\n\ |
|
650 mat2cell (reshape(1:16,4,4),[3,1],[3,1])\n\ |
|
651 @result{} @{\n\ |
|
652 [1,1] =\n\ |
|
653 \n\ |
|
654 1 5 9\n\ |
|
655 2 6 10\n\ |
|
656 3 7 11\n\ |
|
657 \n\ |
|
658 [2,1] =\n\ |
|
659 \n\ |
|
660 4 8 12\n\ |
|
661 \n\ |
|
662 [1,2] =\n\ |
|
663 \n\ |
|
664 13\n\ |
|
665 14\n\ |
|
666 15\n\ |
|
667 \n\ |
|
668 [2,2] = 16\n\ |
|
669 @}\n\ |
|
670 @end group\n\ |
|
671 @end example\n\ |
5829
|
672 @seealso{num2cell, cell2mat}\n\ |
5784
|
673 @end deftypefn") |
|
674 { |
|
675 int nargin = args.length(); |
|
676 octave_value retval; |
|
677 |
|
678 if (nargin < 2) |
7038
|
679 print_usage (); |
5784
|
680 else |
|
681 { |
|
682 dim_vector dv = args(0).dims(); |
|
683 dim_vector new_dv; |
|
684 new_dv.resize(dv.length()); |
|
685 |
|
686 if (nargin > 2) |
|
687 { |
|
688 octave_idx_type nmax = -1; |
|
689 |
|
690 if (nargin - 1 != dv.length()) |
|
691 error ("mat2cell: Incorrect number of dimensions"); |
|
692 else |
|
693 { |
|
694 for (octave_idx_type j = 0; j < dv.length(); j++) |
|
695 { |
|
696 ColumnVector d = ColumnVector (args(j+1).vector_value |
|
697 (false, true)); |
|
698 |
|
699 if (d.length() < 1) |
|
700 { |
|
701 error ("mat2cell: dimension can not be empty"); |
|
702 break; |
|
703 } |
|
704 else |
|
705 { |
|
706 if (nmax < d.length()) |
|
707 nmax = d.length(); |
|
708 |
|
709 for (octave_idx_type i = 1; i < d.length(); i++) |
|
710 { |
|
711 OCTAVE_QUIT; |
|
712 |
|
713 if (d(i) >= 0) |
|
714 d(i) += d(i-1); |
|
715 else |
|
716 { |
|
717 error ("mat2cell: invalid dimensional argument"); |
|
718 break; |
|
719 } |
|
720 } |
|
721 |
|
722 if (d(0) < 0) |
|
723 error ("mat2cell: invalid dimensional argument"); |
|
724 |
|
725 if (d(d.length() - 1) != dv(j)) |
|
726 error ("mat2cell: inconsistent dimensions"); |
|
727 |
|
728 if (error_state) |
|
729 break; |
|
730 |
|
731 new_dv(j) = d.length(); |
|
732 } |
|
733 } |
|
734 } |
|
735 |
|
736 if (! error_state) |
|
737 { |
|
738 // Construct a matrix with the index values |
|
739 Matrix dimargs(nmax, new_dv.length()); |
|
740 for (octave_idx_type j = 0; j < new_dv.length(); j++) |
|
741 { |
|
742 OCTAVE_QUIT; |
|
743 |
|
744 ColumnVector d = ColumnVector (args(j+1).vector_value |
|
745 (false, true)); |
|
746 |
|
747 dimargs(0,j) = d(0); |
|
748 for (octave_idx_type i = 1; i < d.length(); i++) |
|
749 dimargs(i,j) = dimargs(i-1,j) + d(i); |
|
750 } |
|
751 |
|
752 |
|
753 octave_value_list lst (new_dv.length(), octave_value()); |
|
754 Cell ret (new_dv); |
|
755 octave_idx_type nel = new_dv.numel(); |
|
756 octave_idx_type ntot = 1; |
|
757 |
|
758 for (int j = 0; j < new_dv.length()-1; j++) |
|
759 ntot *= new_dv(j); |
|
760 |
|
761 for (octave_idx_type i = 0; i < nel; i++) |
|
762 { |
|
763 octave_idx_type n = ntot; |
|
764 octave_idx_type ii = i; |
|
765 for (octave_idx_type j = new_dv.length() - 1; j >= 0; j--) |
|
766 { |
|
767 OCTAVE_QUIT; |
|
768 |
|
769 octave_idx_type idx = ii / n; |
|
770 lst (j) = Range((idx == 0 ? 1. : dimargs(idx-1,j)+1.), |
|
771 dimargs(idx,j)); |
|
772 ii = ii % n; |
|
773 if (j != 0) |
|
774 n /= new_dv(j-1); |
|
775 } |
|
776 ret(i) = args(0).do_index_op(lst, 0); |
|
777 if (error_state) |
|
778 break; |
|
779 } |
|
780 |
|
781 if (!error_state) |
|
782 retval = ret; |
|
783 } |
|
784 } |
|
785 else |
|
786 { |
|
787 ColumnVector d = ColumnVector (args(1).vector_value |
|
788 (false, true)); |
|
789 |
|
790 double sumd = 0.; |
|
791 for (octave_idx_type i = 0; i < d.length(); i++) |
|
792 { |
|
793 OCTAVE_QUIT; |
|
794 |
|
795 if (d(i) >= 0) |
|
796 sumd += d(i); |
|
797 else |
|
798 { |
|
799 error ("mat2cell: invalid dimensional argument"); |
|
800 break; |
|
801 } |
|
802 } |
|
803 |
|
804 if (sumd != dv(0)) |
|
805 error ("mat2cell: inconsistent dimensions"); |
|
806 |
|
807 new_dv(0) = d.length(); |
|
808 for (octave_idx_type i = 1; i < dv.length(); i++) |
|
809 new_dv(i) = 1; |
|
810 |
|
811 if (! error_state) |
|
812 { |
|
813 octave_value_list lst (new_dv.length(), octave_value()); |
|
814 Cell ret (new_dv); |
|
815 |
|
816 for (octave_idx_type i = 1; i < new_dv.length(); i++) |
|
817 lst (i) = Range (1., static_cast<double>(dv(i))); |
|
818 |
|
819 double idx = 0.; |
|
820 for (octave_idx_type i = 0; i < new_dv(0); i++) |
|
821 { |
|
822 OCTAVE_QUIT; |
|
823 |
|
824 lst(0) = Range(idx + 1., idx + d(i)); |
|
825 ret(i) = args(0).do_index_op(lst, 0); |
|
826 idx += d(i); |
|
827 if (error_state) |
|
828 break; |
|
829 } |
|
830 |
|
831 if (!error_state) |
|
832 retval = ret; |
|
833 } |
|
834 } |
|
835 } |
|
836 |
|
837 return retval; |
|
838 } |
|
839 |
|
840 /* |
|
841 |
|
842 %!test |
|
843 %! x = reshape(1:20,5,4); |
|
844 %! c = mat2cell(x,[3,2],[3,1]); |
|
845 %! assert(c,{[1,6,11;2,7,12;3,8,13],[16;17;18];[4,9,14;5,10,15],[19;20]}) |
|
846 |
|
847 %!test |
|
848 %! x = 'abcdefghij'; |
|
849 %! c = mat2cell(x,1,[0,4,2,0,4,0]); |
|
850 %! empty1by0str = resize('',1,0); |
|
851 %! assert(c,{empty1by0str,'abcd','ef',empty1by0str,'ghij',empty1by0str}) |
|
852 |
|
853 */ |
|
854 |
5205
|
855 /* |
|
856 ;;; Local Variables: *** |
|
857 ;;; mode: C++ *** |
|
858 ;;; End: *** |
|
859 */ |