Mercurial > hg > octave-nkf
annotate src/pt-mat.cc @ 11951:9cfbc1a1bf0b release-3-0-x
this branch is no longer maintained and is closed for further development
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Sat, 22 Jan 2011 00:59:43 -0500 |
parents | 28b0618cf67c |
children |
rev | line source |
---|---|
1741 | 1 /* |
2 | |
7017 | 3 Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, |
4 2005, 2006, 2007 John W. Eaton | |
1741 | 5 |
6 This file is part of Octave. | |
7 | |
8 Octave is free software; you can redistribute it and/or modify it | |
9 under the terms of the GNU General Public License as published by the | |
7016 | 10 Free Software Foundation; either version 3 of the License, or (at your |
11 option) any later version. | |
1741 | 12 |
13 Octave is distributed in the hope that it will be useful, but WITHOUT | |
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 for more details. | |
17 | |
18 You should have received a copy of the GNU General Public License | |
7016 | 19 along with Octave; see the file COPYING. If not, see |
20 <http://www.gnu.org/licenses/>. | |
1741 | 21 |
22 */ | |
23 | |
24 #ifdef HAVE_CONFIG_H | |
25 #include <config.h> | |
26 #endif | |
27 | |
3503 | 28 #include <iostream> |
1741 | 29 |
5502 | 30 #include "quit.h" |
31 | |
2172 | 32 #include "defun.h" |
1741 | 33 #include "error.h" |
34 #include "oct-obj.h" | |
2982 | 35 #include "pt-arg-list.h" |
3770 | 36 #include "pt-bp.h" |
1741 | 37 #include "pt-exp.h" |
38 #include "pt-mat.h" | |
2124 | 39 #include "pt-walk.h" |
2201 | 40 #include "utils.h" |
2371 | 41 #include "ov.h" |
42 #include "variables.h" | |
1741 | 43 |
5630 | 44 #include "ov-re-sparse.h" |
45 #include "ov-cx-sparse.h" | |
46 | |
2254 | 47 // The character to fill with when creating string arrays. |
3836 | 48 char Vstring_fill_char = ' '; |
2254 | 49 |
1741 | 50 // General matrices. This list type is much more work to handle than |
51 // constant matrices, but it allows us to construct matrices from | |
52 // other matrices, variables, and functions. | |
53 | |
1827 | 54 // But first, some internal classes that make our job much easier. |
1741 | 55 |
1827 | 56 class |
57 tm_row_const | |
1741 | 58 { |
1827 | 59 private: |
60 | |
61 class | |
4219 | 62 tm_row_const_rep : public octave_base_list<octave_value> |
1827 | 63 { |
64 public: | |
65 | |
66 tm_row_const_rep (void) | |
5514 | 67 : count (1), dv (0, 0), all_str (false), |
5280 | 68 all_sq_str (false), all_dq_str (false), |
5502 | 69 some_str (false), all_real (false), all_cmplx (false), |
5630 | 70 all_mt (true), any_sparse (false), |
71 class_nm (octave_base_value::static_class_name ()), ok (false) | |
5533 | 72 { } |
1827 | 73 |
2971 | 74 tm_row_const_rep (const tree_argument_list& row) |
5514 | 75 : count (1), dv (0, 0), all_str (false), all_sq_str (false), |
5502 | 76 some_str (false), all_real (false), all_cmplx (false), |
5630 | 77 all_mt (true), any_sparse (false), |
78 class_nm (octave_base_value::static_class_name ()), ok (false) | |
3110 | 79 { init (row); } |
1827 | 80 |
81 ~tm_row_const_rep (void) { } | |
82 | |
83 int count; | |
84 | |
4765 | 85 dim_vector dv; |
1741 | 86 |
1827 | 87 bool all_str; |
5280 | 88 bool all_sq_str; |
89 bool all_dq_str; | |
3110 | 90 bool some_str; |
5502 | 91 bool all_real; |
92 bool all_cmplx; | |
2602 | 93 bool all_mt; |
5630 | 94 bool any_sparse; |
1827 | 95 |
5533 | 96 std::string class_nm; |
97 | |
1827 | 98 bool ok; |
99 | |
4501 | 100 bool do_init_element (tree_expression *, const octave_value&, bool&); |
101 | |
2971 | 102 void init (const tree_argument_list&); |
1827 | 103 |
104 private: | |
105 | |
106 tm_row_const_rep (const tm_row_const_rep&); | |
107 | |
2971 | 108 tm_row_const_rep& operator = (const tm_row_const_rep&); |
2419 | 109 |
3661 | 110 void eval_error (const char *msg, int l, int c, |
111 int x = -1, int y = -1) const; | |
2419 | 112 |
113 void eval_warning (const char *msg, int l, int c) const; | |
1827 | 114 }; |
115 | |
116 public: | |
117 | |
4219 | 118 typedef tm_row_const_rep::iterator iterator; |
119 typedef tm_row_const_rep::const_iterator const_iterator; | |
120 | |
2990 | 121 tm_row_const (void) |
122 : rep (0) { } | |
1827 | 123 |
2971 | 124 tm_row_const (const tree_argument_list& row) |
125 : rep (new tm_row_const_rep (row)) { } | |
1827 | 126 |
2990 | 127 tm_row_const (const tm_row_const& x) |
128 : rep (x.rep) | |
129 { | |
130 if (rep) | |
131 rep->count++; | |
132 } | |
1827 | 133 |
134 tm_row_const& operator = (const tm_row_const& x) | |
2990 | 135 { |
136 if (this != &x && rep != x.rep) | |
137 { | |
138 if (rep && --rep->count == 0) | |
139 delete rep; | |
1741 | 140 |
2990 | 141 rep = x.rep; |
1827 | 142 |
2990 | 143 if (rep) |
144 rep->count++; | |
145 } | |
1741 | 146 |
2990 | 147 return *this; |
148 } | |
1827 | 149 |
150 ~tm_row_const (void) | |
2990 | 151 { |
152 if (rep && --rep->count == 0) | |
153 delete rep; | |
154 } | |
1741 | 155 |
5514 | 156 octave_idx_type rows (void) { return rep->dv(0); } |
157 octave_idx_type cols (void) { return rep->dv(1); } | |
4765 | 158 |
6200 | 159 bool empty (void) const { return rep->empty (); } |
160 | |
4765 | 161 dim_vector dims (void) { return rep->dv; } |
1827 | 162 |
2868 | 163 bool all_strings_p (void) const { return rep->all_str; } |
5280 | 164 bool all_sq_strings_p (void) const { return rep->all_sq_str; } |
165 bool all_dq_strings_p (void) const { return rep->all_dq_str; } | |
3110 | 166 bool some_strings_p (void) const { return rep->some_str; } |
5502 | 167 bool all_real_p (void) const { return rep->all_real; } |
168 bool all_complex_p (void) const { return rep->all_cmplx; } | |
2868 | 169 bool all_empty_p (void) const { return rep->all_mt; } |
5630 | 170 bool any_sparse_p (void) const { return rep->any_sparse; } |
1827 | 171 |
5533 | 172 std::string class_name (void) const { return rep->class_nm; } |
173 | |
4219 | 174 operator bool () const { return (rep && rep->ok); } |
1827 | 175 |
4219 | 176 iterator begin (void) { return rep->begin (); } |
177 const_iterator begin (void) const { return rep->begin (); } | |
178 | |
179 iterator end (void) { return rep->end (); } | |
180 const_iterator end (void) const { return rep->end (); } | |
1827 | 181 |
182 private: | |
183 | |
184 tm_row_const_rep *rep; | |
185 }; | |
186 | |
11844
28b0618cf67c
Special case single type conacation in Fcat. Rework cell2mat to take advantage. Cut trailing singletons in cat
David Bateman <dbateman@free.fr>
parents:
7270
diff
changeset
|
187 std::string |
5533 | 188 get_concat_class (const std::string& c1, const std::string& c2) |
189 { | |
190 std::string retval = octave_base_value::static_class_name (); | |
191 | |
192 if (c1 == c2) | |
193 retval = c1; | |
194 else | |
195 { | |
196 bool c1_is_int = (c1 == "int8" || c1 == "uint8" | |
197 || c1 == "int16" || c1 == "uint16" | |
198 || c1 == "int32" || c1 == "uint32" | |
199 || c1 == "int64" || c1 == "uint64"); | |
200 bool c2_is_int = (c2 == "int8" || c2 == "uint8" | |
201 || c2 == "int16" || c2 == "uint16" | |
202 || c2 == "int32" || c2 == "uint32" | |
203 || c2 == "int64" || c2 == "uint64"); | |
204 | |
205 bool c1_is_char = (c1 == "char"); | |
206 bool c2_is_char = (c2 == "char"); | |
207 | |
208 bool c1_is_double = (c1 == "double"); | |
209 bool c2_is_double = (c2 == "double"); | |
210 | |
211 bool c1_is_single = (c1 == "single"); | |
212 bool c2_is_single = (c2 == "single"); | |
213 | |
214 bool c1_is_logical = (c1 == "logical"); | |
215 bool c2_is_logical = (c2 == "logical"); | |
216 | |
217 bool c1_is_built_in_type | |
218 = (c1_is_int || c1_is_char || c1_is_double || c1_is_single | |
219 || c1_is_logical); | |
220 | |
221 bool c2_is_built_in_type | |
222 = (c2_is_int || c2_is_char || c2_is_double || c2_is_single | |
223 || c2_is_logical); | |
224 | |
225 // Order is important here... | |
226 | |
227 if (c1_is_char && c2_is_built_in_type) | |
228 retval = c1; | |
229 else if (c2_is_char && c1_is_built_in_type) | |
230 retval = c2; | |
231 else if (c1_is_int && c2_is_built_in_type) | |
232 retval = c1; | |
233 else if (c2_is_int && c1_is_built_in_type) | |
234 retval = c2; | |
235 else if (c1_is_single && c2_is_built_in_type) | |
236 retval = c1; | |
237 else if (c2_is_single && c1_is_built_in_type) | |
238 retval = c2; | |
239 else if (c1_is_double && c2_is_built_in_type) | |
240 retval = c1; | |
241 else if (c2_is_double && c1_is_built_in_type) | |
242 retval = c2; | |
243 else if (c1_is_logical && c2_is_logical) | |
244 retval = c1; | |
245 } | |
246 | |
247 return retval; | |
248 } | |
249 | |
4501 | 250 bool |
251 tm_row_const::tm_row_const_rep::do_init_element (tree_expression *elt, | |
252 const octave_value& val, | |
253 bool& first_elem) | |
254 { | |
5275 | 255 octave_idx_type this_elt_nr = val.rows (); |
256 octave_idx_type this_elt_nc = val.columns (); | |
4501 | 257 |
5533 | 258 std::string this_elt_class_nm = val.class_name (); |
259 | |
4765 | 260 dim_vector this_elt_dv = val.dims (); |
261 | |
5502 | 262 if (! this_elt_dv.all_zero ()) |
4501 | 263 { |
264 all_mt = false; | |
265 | |
266 if (first_elem) | |
267 { | |
268 first_elem = false; | |
269 | |
5533 | 270 class_nm = this_elt_class_nm; |
271 | |
4765 | 272 dv.resize (this_elt_dv.length ()); |
273 for (int i = 2; i < dv.length (); i++) | |
274 dv.elem (i) = this_elt_dv.elem (i); | |
275 | |
276 dv.elem (0) = this_elt_nr; | |
277 | |
278 dv.elem (1) = 0; | |
4501 | 279 } |
4765 | 280 else |
4501 | 281 { |
5533 | 282 class_nm = get_concat_class (class_nm, this_elt_class_nm); |
283 | |
5045 | 284 int len = (this_elt_dv.length () < dv.length () |
285 ? this_elt_dv.length () : dv.length ()); | |
286 | |
4765 | 287 if (this_elt_nr != dv (0)) |
288 { | |
289 eval_error ("number of rows must match", | |
290 elt->line (), elt->column (), this_elt_nr, dv (0)); | |
291 return false; | |
292 } | |
5045 | 293 for (int i = 2; i < len; i++) |
4765 | 294 { |
295 if (this_elt_dv (i) != dv (i)) | |
296 { | |
297 eval_error ("dimensions mismatch", elt->line (), elt->column (), this_elt_dv (i), dv (i)); | |
298 return false; | |
299 } | |
300 } | |
5045 | 301 |
302 if (this_elt_dv.length () > len) | |
303 for (int i = len; i < this_elt_dv.length (); i++) | |
304 if (this_elt_dv (i) != 1) | |
305 { | |
306 eval_error ("dimensions mismatch", elt->line (), elt->column (), this_elt_dv (i), 1); | |
307 return false; | |
308 } | |
309 | |
310 if (dv.length () > len) | |
311 for (int i = len; i < dv.length (); i++) | |
312 if (dv (i) != 1) | |
313 { | |
314 eval_error ("dimensions mismatch", elt->line (), elt->column (), 1, dv (i)); | |
315 return false; | |
316 } | |
4501 | 317 } |
4765 | 318 dv.elem (1) = dv.elem (1) + this_elt_nc; |
4501 | 319 |
320 } | |
5781 | 321 else |
4501 | 322 eval_warning ("empty matrix found in matrix list", |
323 elt->line (), elt->column ()); | |
324 | |
4915 | 325 append (val); |
326 | |
4501 | 327 if (all_str && ! val.is_string ()) |
328 all_str = false; | |
329 | |
5280 | 330 if (all_sq_str && ! val.is_sq_string ()) |
331 all_sq_str = false; | |
332 | |
333 if (all_dq_str && ! val.is_dq_string ()) | |
334 all_dq_str = false; | |
335 | |
4501 | 336 if (! some_str && val.is_string ()) |
337 some_str = true; | |
338 | |
5502 | 339 if (all_real && ! val.is_real_type ()) |
340 all_real = false; | |
341 | |
342 if (all_cmplx && ! (val.is_complex_type () || val.is_real_type ())) | |
343 all_cmplx = false; | |
4501 | 344 |
5631 | 345 if (!any_sparse && val.is_sparse_type ()) |
5630 | 346 any_sparse = true; |
347 | |
4501 | 348 return true; |
349 } | |
350 | |
1827 | 351 void |
2971 | 352 tm_row_const::tm_row_const_rep::init (const tree_argument_list& row) |
1827 | 353 { |
354 all_str = true; | |
5280 | 355 all_sq_str = true; |
356 all_dq_str = true; | |
5502 | 357 all_real = true; |
358 all_cmplx = true; | |
5630 | 359 any_sparse = false; |
1827 | 360 |
361 bool first_elem = true; | |
362 | |
4219 | 363 for (tree_argument_list::const_iterator p = row.begin (); |
364 p != row.end (); | |
365 p++) | |
1827 | 366 { |
5502 | 367 OCTAVE_QUIT; |
368 | |
4219 | 369 tree_expression *elt = *p; |
1827 | 370 |
2971 | 371 octave_value tmp = elt->rvalue (); |
1827 | 372 |
373 if (error_state || tmp.is_undefined ()) | |
374 break; | |
375 else | |
376 { | |
4501 | 377 if (tmp.is_cs_list ()) |
1827 | 378 { |
4587 | 379 octave_value_list tlst = tmp.list_value (); |
2602 | 380 |
5275 | 381 for (octave_idx_type i = 0; i < tlst.length (); i++) |
1827 | 382 { |
5502 | 383 OCTAVE_QUIT; |
384 | |
4587 | 385 if (! do_init_element (elt, tlst(i), first_elem)) |
4501 | 386 goto done; |
1827 | 387 } |
388 } | |
4501 | 389 else |
390 { | |
391 if (! do_init_element (elt, tmp, first_elem)) | |
392 goto done; | |
393 } | |
1827 | 394 } |
395 } | |
396 | |
4501 | 397 done: |
398 | |
1827 | 399 ok = ! error_state; |
1741 | 400 } |
401 | |
2419 | 402 void |
403 tm_row_const::tm_row_const_rep::eval_error (const char *msg, int l, | |
3661 | 404 int c, int x, int y) const |
2419 | 405 { |
406 if (l == -1 && c == -1) | |
3661 | 407 { |
408 if (x == -1 || y == -1) | |
409 ::error ("%s", msg); | |
410 else | |
411 ::error ("%s (%d != %d)", msg, x, y); | |
412 } | |
2419 | 413 else |
3661 | 414 { |
415 if (x == -1 || y == -1) | |
416 ::error ("%s near line %d, column %d", msg, l, c); | |
417 else | |
418 ::error ("%s (%d != %d) near line %d, column %d", msg, x, y, l, c); | |
419 } | |
2419 | 420 } |
421 | |
422 void | |
423 tm_row_const::tm_row_const_rep::eval_warning (const char *msg, int l, | |
424 int c) const | |
425 { | |
426 if (l == -1 && c == -1) | |
5781 | 427 warning_with_id ("Octave:empty-list-elements", "%s", msg); |
2419 | 428 else |
5781 | 429 warning_with_id ("Octave:empty-list-elements", |
430 "%s near line %d, column %d", msg, l, c); | |
2419 | 431 } |
432 | |
1827 | 433 class |
4219 | 434 tm_const : public octave_base_list<tm_row_const> |
1827 | 435 { |
436 public: | |
437 | |
438 tm_const (const tree_matrix& tm) | |
5514 | 439 : dv (0, 0), all_str (false), all_sq_str (false), all_dq_str (false), |
5502 | 440 some_str (false), all_real (false), all_cmplx (false), |
5630 | 441 all_mt (true), any_sparse (false), |
442 class_nm (octave_base_value::static_class_name ()), ok (false) | |
5533 | 443 { init (tm); } |
1827 | 444 |
445 ~tm_const (void) { } | |
446 | |
5514 | 447 octave_idx_type rows (void) const { return dv.elem (0); } |
448 octave_idx_type cols (void) const { return dv.elem (1); } | |
4765 | 449 |
450 dim_vector dims (void) const { return dv; } | |
1827 | 451 |
2868 | 452 bool all_strings_p (void) const { return all_str; } |
5280 | 453 bool all_sq_strings_p (void) const { return all_sq_str; } |
454 bool all_dq_strings_p (void) const { return all_dq_str; } | |
3110 | 455 bool some_strings_p (void) const { return some_str; } |
5502 | 456 bool all_real_p (void) const { return all_real; } |
457 bool all_complex_p (void) const { return all_cmplx; } | |
2868 | 458 bool all_empty_p (void) const { return all_mt; } |
5630 | 459 bool any_sparse_p (void) const { return any_sparse; } |
1827 | 460 |
5533 | 461 std::string class_name (void) const { return class_nm; } |
462 | |
3145 | 463 operator bool () const { return ok; } |
1827 | 464 |
465 private: | |
466 | |
4765 | 467 dim_vector dv; |
1827 | 468 |
469 bool all_str; | |
5280 | 470 bool all_sq_str; |
471 bool all_dq_str; | |
3110 | 472 bool some_str; |
5502 | 473 bool all_real; |
474 bool all_cmplx; | |
2602 | 475 bool all_mt; |
5630 | 476 bool any_sparse; |
1827 | 477 |
5533 | 478 std::string class_nm; |
479 | |
1827 | 480 bool ok; |
481 | |
482 tm_const (void); | |
483 | |
484 tm_const (const tm_const&); | |
485 | |
486 tm_const& operator = (const tm_const&); | |
487 | |
488 void init (const tree_matrix& tm); | |
489 }; | |
490 | |
491 void | |
492 tm_const::init (const tree_matrix& tm) | |
1741 | 493 { |
1827 | 494 all_str = true; |
5280 | 495 all_sq_str = true; |
496 all_dq_str = true; | |
5502 | 497 all_real = true; |
498 all_cmplx = true; | |
5630 | 499 any_sparse = false; |
1827 | 500 |
501 bool first_elem = true; | |
502 | |
503 // Just eval and figure out if what we have is complex or all | |
504 // strings. We can't check columns until we know that this is a | |
505 // numeric matrix -- collections of strings can have elements of | |
506 // different lengths. | |
507 | |
4219 | 508 for (tree_matrix::const_iterator p = tm.begin (); p != tm.end (); p++) |
1827 | 509 { |
5502 | 510 OCTAVE_QUIT; |
511 | |
4219 | 512 tree_argument_list *elt = *p; |
1827 | 513 |
514 tm_row_const tmp (*elt); | |
515 | |
6200 | 516 if (tmp && ! tmp.empty ()) |
1827 | 517 { |
2868 | 518 if (all_str && ! tmp.all_strings_p ()) |
1827 | 519 all_str = false; |
520 | |
5280 | 521 if (all_sq_str && ! tmp.all_sq_strings_p ()) |
522 all_sq_str = false; | |
523 | |
524 if (all_dq_str && ! tmp.all_dq_strings_p ()) | |
525 all_dq_str = false; | |
526 | |
3110 | 527 if (! some_str && tmp.some_strings_p ()) |
528 some_str = true; | |
529 | |
5502 | 530 if (all_real && ! tmp.all_real_p ()) |
531 all_real = false; | |
532 | |
533 if (all_cmplx && ! tmp.all_complex_p ()) | |
534 all_cmplx = false; | |
1827 | 535 |
2868 | 536 if (all_mt && ! tmp.all_empty_p ()) |
2602 | 537 all_mt = false; |
538 | |
5630 | 539 if (!any_sparse && tmp.any_sparse_p ()) |
540 any_sparse = true; | |
541 | |
1827 | 542 append (tmp); |
543 } | |
544 else | |
545 break; | |
546 } | |
547 | |
548 if (! error_state) | |
549 { | |
4219 | 550 for (iterator p = begin (); p != end (); p++) |
1827 | 551 { |
5502 | 552 OCTAVE_QUIT; |
553 | |
4219 | 554 tm_row_const elt = *p; |
1827 | 555 |
5275 | 556 octave_idx_type this_elt_nr = elt.rows (); |
557 octave_idx_type this_elt_nc = elt.cols (); | |
1827 | 558 |
5533 | 559 std::string this_elt_class_nm = elt.class_name (); |
560 | |
4765 | 561 dim_vector this_elt_dv = elt.dims (); |
562 | |
563 if (!this_elt_dv.all_zero ()) | |
1827 | 564 { |
2602 | 565 all_mt = false; |
566 | |
1827 | 567 if (first_elem) |
568 { | |
569 first_elem = false; | |
570 | |
5533 | 571 class_nm = this_elt_class_nm; |
572 | |
4765 | 573 dv.resize (this_elt_dv.length ()); |
574 for (int i = 2; i < dv.length (); i++) | |
575 dv.elem (i) = this_elt_dv.elem (i); | |
576 | |
577 dv.elem (0) = 0; | |
578 | |
579 dv.elem (1) = this_elt_nc; | |
1827 | 580 } |
581 else if (all_str) | |
582 { | |
5533 | 583 class_nm = get_concat_class (class_nm, this_elt_class_nm); |
584 | |
4765 | 585 if (this_elt_nc > cols ()) |
586 dv.elem (1) = this_elt_nc; | |
1827 | 587 } |
4765 | 588 else |
1827 | 589 { |
5533 | 590 class_nm = get_concat_class (class_nm, this_elt_class_nm); |
591 | |
4765 | 592 bool get_out = false; |
5045 | 593 int len = (this_elt_dv.length () < dv.length () |
594 ? this_elt_dv.length () : dv.length ()); | |
4765 | 595 |
5045 | 596 for (int i = 1; i < len; i++) |
4765 | 597 { |
598 if (i == 1 && this_elt_nc != dv (1)) | |
599 { | |
600 ::error ("number of columns must match (%d != %d)", | |
601 this_elt_nc, dv (1)); | |
602 get_out = true; | |
603 break; | |
604 } | |
605 else if (this_elt_dv (i) != dv (i)) | |
606 { | |
607 ::error ("dimensions mismatch (dim = %i, %d != %d)", i+1, this_elt_dv (i), dv (i)); | |
608 get_out = true; | |
609 break; | |
610 } | |
611 } | |
612 | |
5045 | 613 if (this_elt_dv.length () > len) |
614 for (int i = len; i < this_elt_dv.length (); i++) | |
615 if (this_elt_dv (i) != 1) | |
616 { | |
617 ::error ("dimensions mismatch (dim = %i, %d != %d)", i+1, this_elt_dv (i), 1); | |
618 get_out = true; | |
619 break; | |
620 } | |
621 | |
622 if (dv.length () > len) | |
623 for (int i = len; i < dv.length (); i++) | |
624 if (dv (i) != 1) | |
625 { | |
626 ::error ("dimensions mismatch (dim = %i, %d != %d)", i+1, 1, dv(i)); | |
627 get_out = true; | |
628 break; | |
629 } | |
630 | |
4765 | 631 if (get_out) |
632 break; | |
1827 | 633 } |
4765 | 634 dv.elem (0) = dv.elem (0) + this_elt_nr; |
1827 | 635 } |
5781 | 636 else |
637 warning_with_id ("Octave:empty-list-elements", | |
638 "empty matrix found in matrix list"); | |
1827 | 639 } |
640 } | |
641 | |
642 ok = ! error_state; | |
1741 | 643 } |
644 | |
2990 | 645 tree_matrix::~tree_matrix (void) |
646 { | |
4219 | 647 while (! empty ()) |
2990 | 648 { |
4219 | 649 iterator p = begin (); |
650 delete *p; | |
651 erase (p); | |
2990 | 652 } |
653 } | |
654 | |
1827 | 655 bool |
4267 | 656 tree_matrix::has_magic_end (void) const |
657 { | |
658 for (const_iterator p = begin (); p != end (); p++) | |
659 { | |
5502 | 660 OCTAVE_QUIT; |
661 | |
4267 | 662 tree_argument_list *elt = *p; |
663 | |
664 if (elt && elt->has_magic_end ()) | |
665 return true; | |
666 } | |
667 | |
668 return false; | |
669 } | |
670 | |
671 bool | |
2529 | 672 tree_matrix::all_elements_are_constant (void) const |
1827 | 673 { |
4219 | 674 for (const_iterator p = begin (); p != end (); p++) |
1827 | 675 { |
5502 | 676 OCTAVE_QUIT; |
677 | |
4219 | 678 tree_argument_list *elt = *p; |
1827 | 679 |
2529 | 680 if (! elt->all_elements_are_constant ()) |
1827 | 681 return false; |
682 } | |
683 | |
684 return true; | |
685 } | |
686 | |
2971 | 687 octave_value_list |
688 tree_matrix::rvalue (int nargout) | |
689 { | |
690 octave_value_list retval; | |
691 | |
3770 | 692 MAYBE_DO_BREAKPOINT; |
693 | |
2971 | 694 if (nargout > 1) |
695 error ("invalid number of output arguments for matrix list"); | |
696 else | |
697 retval = rvalue (); | |
698 | |
699 return retval; | |
700 } | |
701 | |
11844
28b0618cf67c
Special case single type conacation in Fcat. Rework cell2mat to take advantage. Cut trailing singletons in cat
David Bateman <dbateman@free.fr>
parents:
7270
diff
changeset
|
702 void |
5280 | 703 maybe_warn_string_concat (bool all_dq_strings_p, bool all_sq_strings_p) |
704 { | |
5781 | 705 if (! (all_dq_strings_p || all_sq_strings_p)) |
706 warning_with_id ("Octave:string-concat", | |
707 "concatenation of different character string types may have unintended consequences"); | |
5280 | 708 } |
709 | |
5502 | 710 #define SINGLE_TYPE_CONCAT(TYPE, EXTRACTOR) \ |
711 do \ | |
712 { \ | |
713 int dv_len = dv.length (); \ | |
714 Array<octave_idx_type> ra_idx (dv_len > 1 ? dv_len : 2, 0); \ | |
715 \ | |
716 for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++) \ | |
717 { \ | |
718 OCTAVE_QUIT; \ | |
719 \ | |
720 tm_row_const row = *p; \ | |
721 \ | |
722 for (tm_row_const::iterator q = row.begin (); \ | |
723 q != row.end (); \ | |
724 q++) \ | |
725 { \ | |
726 OCTAVE_QUIT; \ | |
727 \ | |
728 TYPE ra = q->EXTRACTOR (); \ | |
729 \ | |
730 if (! error_state) \ | |
731 { \ | |
732 result.insert (ra, ra_idx); \ | |
733 \ | |
734 if (! error_state) \ | |
735 ra_idx(1) += ra.columns (); \ | |
736 else \ | |
737 goto done; \ | |
738 } \ | |
739 else \ | |
740 goto done; \ | |
741 } \ | |
742 \ | |
743 ra_idx(0) += row.rows (); \ | |
744 ra_idx(1) = 0; \ | |
745 } \ | |
746 } \ | |
747 while (0) | |
748 | |
5533 | 749 #define DO_SINGLE_TYPE_CONCAT(TYPE, EXTRACTOR) \ |
750 do \ | |
751 { \ | |
752 TYPE result (dv); \ | |
753 \ | |
754 SINGLE_TYPE_CONCAT(TYPE, EXTRACTOR); \ | |
755 \ | |
756 retval = result; \ | |
757 } \ | |
758 while (0) | |
759 | |
2086 | 760 octave_value |
2971 | 761 tree_matrix::rvalue (void) |
1741 | 762 { |
6200 | 763 octave_value retval = Matrix (); |
1741 | 764 |
4915 | 765 bool all_strings_p = false; |
5280 | 766 bool all_sq_strings_p = false; |
767 bool all_dq_strings_p = false; | |
4915 | 768 bool all_empty_p = false; |
5502 | 769 bool all_real_p = false; |
770 bool all_complex_p = false; | |
5630 | 771 bool any_sparse_p = false; |
4915 | 772 bool frc_str_conv = false; |
1741 | 773 |
4915 | 774 tm_const tmp (*this); |
3110 | 775 |
6200 | 776 if (tmp && ! tmp.empty ()) |
1827 | 777 { |
4765 | 778 dim_vector dv = tmp.dims (); |
4915 | 779 all_strings_p = tmp.all_strings_p (); |
5280 | 780 all_sq_strings_p = tmp.all_sq_strings_p (); |
781 all_dq_strings_p = tmp.all_dq_strings_p (); | |
4915 | 782 all_empty_p = tmp.all_empty_p (); |
5502 | 783 all_real_p = tmp.all_real_p (); |
784 all_complex_p = tmp.all_complex_p (); | |
5630 | 785 any_sparse_p = tmp.any_sparse_p (); |
4915 | 786 frc_str_conv = tmp.some_strings_p (); |
1741 | 787 |
5502 | 788 // Try to speed up the common cases. |
4915 | 789 |
5533 | 790 std::string result_type = tmp.class_name (); |
791 | |
792 if (result_type == "double") | |
793 { | |
6823 | 794 if (any_sparse_p) |
795 { | |
796 if (all_real_p) | |
797 DO_SINGLE_TYPE_CONCAT (SparseMatrix, sparse_matrix_value); | |
798 else | |
799 DO_SINGLE_TYPE_CONCAT (SparseComplexMatrix, sparse_complex_matrix_value); | |
800 } | |
5533 | 801 else |
6823 | 802 { |
803 if (all_real_p) | |
804 DO_SINGLE_TYPE_CONCAT (NDArray, array_value); | |
805 else | |
806 DO_SINGLE_TYPE_CONCAT (ComplexNDArray, complex_array_value); | |
807 } | |
5533 | 808 } |
809 #if 0 | |
810 else if (result_type == "single") | |
811 #endif | |
812 else if (result_type == "char") | |
5280 | 813 { |
7270 | 814 char type = all_dq_strings_p ? '"' : '\''; |
5280 | 815 |
816 maybe_warn_string_concat (all_dq_strings_p, all_sq_strings_p); | |
817 | |
5502 | 818 charNDArray result (dv, Vstring_fill_char); |
819 | |
820 SINGLE_TYPE_CONCAT (charNDArray, char_array_value); | |
821 | |
822 retval = octave_value (result, true, type); | |
823 } | |
5533 | 824 else if (result_type == "logical") |
6823 | 825 { |
826 if (any_sparse_p) | |
827 DO_SINGLE_TYPE_CONCAT (SparseBoolMatrix, sparse_bool_matrix_value); | |
828 else | |
829 DO_SINGLE_TYPE_CONCAT (boolNDArray, bool_array_value); | |
830 } | |
5533 | 831 else if (result_type == "int8") |
832 DO_SINGLE_TYPE_CONCAT (int8NDArray, int8_array_value); | |
833 else if (result_type == "int16") | |
834 DO_SINGLE_TYPE_CONCAT (int16NDArray, int16_array_value); | |
835 else if (result_type == "int32") | |
836 DO_SINGLE_TYPE_CONCAT (int32NDArray, int32_array_value); | |
837 else if (result_type == "int64") | |
838 DO_SINGLE_TYPE_CONCAT (int64NDArray, int64_array_value); | |
839 else if (result_type == "uint8") | |
840 DO_SINGLE_TYPE_CONCAT (uint8NDArray, uint8_array_value); | |
841 else if (result_type == "uint16") | |
842 DO_SINGLE_TYPE_CONCAT (uint16NDArray, uint16_array_value); | |
843 else if (result_type == "uint32") | |
844 DO_SINGLE_TYPE_CONCAT (uint32NDArray, uint32_array_value); | |
845 else if (result_type == "uint64") | |
846 DO_SINGLE_TYPE_CONCAT (uint64NDArray, uint64_array_value); | |
4915 | 847 else |
848 { | |
5502 | 849 // The line below might seem crazy, since we take a copy of |
850 // the first argument, resize it to be empty and then resize | |
851 // it to be full. This is done since it means that there is | |
852 // no recopying of data, as would happen if we used a single | |
853 // resize. It should be noted that resize operation is also | |
854 // significantly slower than the do_cat_op function, so it | |
855 // makes sense to have an empty matrix and copy all data. | |
856 // | |
857 // We might also start with a empty octave_value using | |
858 // | |
859 // ctmp = octave_value_typeinfo::lookup_type | |
860 // (tmp.begin() -> begin() -> type_name()); | |
861 // | |
862 // and then directly resize. However, for some types there | |
863 // might be some additional setup needed, and so this should | |
864 // be avoided. | |
865 | |
866 octave_value ctmp; | |
867 | |
5164 | 868 // Find the first non-empty object |
5502 | 869 |
5630 | 870 if (any_sparse_p) |
5164 | 871 { |
5630 | 872 // Start with sparse matrix to avoid issues memory issues |
873 // with things like [ones(1,4),sprandn(1e8,4,1e-4)] | |
874 if (all_real_p) | |
875 ctmp = octave_sparse_matrix ().resize (dv); | |
876 else | |
877 ctmp = octave_sparse_complex_matrix ().resize (dv); | |
878 } | |
879 else | |
880 { | |
881 for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++) | |
5164 | 882 { |
5502 | 883 OCTAVE_QUIT; |
884 | |
5630 | 885 tm_row_const row = *p; |
5502 | 886 |
5630 | 887 for (tm_row_const::iterator q = row.begin (); |
888 q != row.end (); q++) | |
889 { | |
890 OCTAVE_QUIT; | |
891 | |
892 ctmp = *q; | |
5164 | 893 |
5630 | 894 if (! ctmp.all_zero_dims ()) |
895 goto found_non_empty; | |
896 } | |
897 } | |
5164 | 898 |
5630 | 899 ctmp = (*(tmp.begin() -> begin())); |
900 | |
901 found_non_empty: | |
5502 | 902 |
5630 | 903 if (! all_empty_p) |
904 ctmp = ctmp.resize (dim_vector (0,0)).resize (dv); | |
905 } | |
4915 | 906 |
5502 | 907 if (! error_state) |
1827 | 908 { |
5502 | 909 // Now, extract the values from the individual elements and |
910 // insert them in the result matrix. | |
911 | |
912 int dv_len = dv.length (); | |
6867 | 913 Array<octave_idx_type> ra_idx (dv_len > 1 ? dv_len : 2, 0); |
5502 | 914 |
915 for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++) | |
916 { | |
917 OCTAVE_QUIT; | |
918 | |
919 tm_row_const row = *p; | |
920 | |
921 for (tm_row_const::iterator q = row.begin (); | |
922 q != row.end (); | |
923 q++) | |
924 { | |
925 OCTAVE_QUIT; | |
1741 | 926 |
5502 | 927 octave_value elt = *q; |
928 | |
929 ctmp = do_cat_op (ctmp, elt, ra_idx); | |
930 | |
931 if (error_state) | |
932 goto done; | |
933 | |
934 ra_idx (1) += elt.columns (); | |
935 } | |
936 | |
937 ra_idx (0) += row.rows (); | |
938 ra_idx (1) = 0; | |
939 } | |
940 | |
941 retval = ctmp; | |
942 | |
943 if (frc_str_conv && ! retval.is_string ()) | |
944 retval = retval.convert_to_str (); | |
1741 | 945 } |
946 } | |
947 } | |
948 | |
1827 | 949 done: |
1741 | 950 return retval; |
951 } | |
952 | |
5861 | 953 tree_expression * |
954 tree_matrix::dup (symbol_table *sym_tab) | |
955 { | |
956 tree_matrix *new_matrix = new tree_matrix (0, line (), column ()); | |
957 | |
958 for (iterator p = begin (); p != end (); p++) | |
959 { | |
960 tree_argument_list *elt = *p; | |
961 | |
6039 | 962 new_matrix->append (elt ? elt->dup (sym_tab) : 0); |
5861 | 963 } |
964 | |
965 new_matrix->copy_base (*this); | |
966 | |
967 return new_matrix; | |
968 } | |
969 | |
1741 | 970 void |
2124 | 971 tree_matrix::accept (tree_walker& tw) |
1741 | 972 { |
2124 | 973 tw.visit_matrix (*this); |
1741 | 974 } |
975 | |
5794 | 976 DEFUN (string_fill_char, args, nargout, |
977 "-*- texinfo -*-\n\ | |
978 @deftypefn {Built-in Function} {@var{val} =} string_fill_char ()\n\ | |
979 @deftypefnx {Built-in Function} {@var{old_val} =} string_fill_char (@var{new_val})\n\ | |
980 Query or set the internal variable used to pad all rows of a character\n\ | |
981 matrix to the same length. It must be a single character. The default\n\ | |
982 value is @code{\" \"} (a single space). For example,\n\ | |
3361 | 983 \n\ |
984 @example\n\ | |
985 @group\n\ | |
5794 | 986 string_fill_char (\"X\");\n\ |
3361 | 987 [ \"these\"; \"are\"; \"strings\" ]\n\ |
988 @result{} \"theseXX\"\n\ | |
989 \"areXXXX\"\n\ | |
990 \"strings\"\n\ | |
991 @end group\n\ | |
992 @end example\n\ | |
5794 | 993 @end deftypefn") |
994 { | |
995 return SET_INTERNAL_VARIABLE (string_fill_char); | |
2172 | 996 } |
997 | |
1741 | 998 /* |
999 ;;; Local Variables: *** | |
1000 ;;; mode: C++ *** | |
1001 ;;; End: *** | |
1002 */ |