comparison libinterp/parse-tree/pt-mat.cc @ 15195:2fc554ffbc28

split libinterp from src * libinterp: New directory. Move all files from src directory here except Makefile.am, main.cc, main-cli.cc, mkoctfile.in.cc, mkoctfilr.in.sh, octave-config.in.cc, octave-config.in.sh. * libinterp/Makefile.am: New file, extracted from src/Makefile.am. * src/Makefile.am: Delete everything except targets and definitions needed to build and link main and utility programs. * Makefile.am (SUBDIRS): Include libinterp in the list. * autogen.sh: Run config-module.sh in libinterp/dldfcn directory, not src/dldfcn directory. * configure.ac (AC_CONFIG_SRCDIR): Use libinterp/octave.cc, not src/octave.cc. (DL_LDFLAGS, LIBOCTINTERP): Use libinterp, not src. (AC_CONFIG_FILES): Include libinterp/Makefile in the list. * find-docstring-files.sh: Look in libinterp, not src. * gui/src/Makefile.am (liboctgui_la_CPPFLAGS): Find header files in libinterp, not src.
author John W. Eaton <jwe@octave.org>
date Sat, 18 Aug 2012 16:23:39 -0400
parents src/parse-tree/pt-mat.cc@46b19589b593
children 797ac81586d1
comparison
equal deleted inserted replaced
15194:0f0b795044c3 15195:2fc554ffbc28
1 /*
2
3 Copyright (C) 1996-2012 John W. Eaton
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
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
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
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <iostream>
28
29 #include "quit.h"
30
31 #include "data.h"
32 #include "defun.h"
33 #include "error.h"
34 #include "oct-obj.h"
35 #include "pt-arg-list.h"
36 #include "pt-bp.h"
37 #include "pt-exp.h"
38 #include "pt-mat.h"
39 #include "pt-walk.h"
40 #include "utils.h"
41 #include "ov.h"
42 #include "variables.h"
43
44 #include "ov-cx-mat.h"
45 #include "ov-flt-cx-mat.h"
46 #include "ov-re-sparse.h"
47 #include "ov-cx-sparse.h"
48
49 // The character to fill with when creating string arrays.
50 char Vstring_fill_char = ' ';
51
52 // General matrices. This list type is much more work to handle than
53 // constant matrices, but it allows us to construct matrices from
54 // other matrices, variables, and functions.
55
56 // But first, some internal classes that make our job much easier.
57
58 class
59 tm_row_const
60 {
61 private:
62
63 class
64 tm_row_const_rep : public octave_base_list<octave_value>
65 {
66 public:
67
68 tm_row_const_rep (void)
69 : count (1), dv (0, 0), all_str (false),
70 all_sq_str (false), all_dq_str (false),
71 some_str (false), all_real (false), all_cmplx (false),
72 all_mt (true), any_cell (false), any_sparse (false),
73 any_class (false), all_1x1 (false),
74 first_elem_is_struct (false), class_nm (), ok (false)
75 { }
76
77 tm_row_const_rep (const tree_argument_list& row)
78 : count (1), dv (0, 0), all_str (false), all_sq_str (false),
79 some_str (false), all_real (false), all_cmplx (false),
80 all_mt (true), any_cell (false), any_sparse (false),
81 any_class (false), all_1x1 (! row.empty ()),
82 first_elem_is_struct (false), class_nm (), ok (false)
83 { init (row); }
84
85 ~tm_row_const_rep (void) { }
86
87 octave_refcount<int> count;
88
89 dim_vector dv;
90
91 bool all_str;
92 bool all_sq_str;
93 bool all_dq_str;
94 bool some_str;
95 bool all_real;
96 bool all_cmplx;
97 bool all_mt;
98 bool any_cell;
99 bool any_sparse;
100 bool any_class;
101 bool all_1x1;
102 bool first_elem_is_struct;
103
104 std::string class_nm;
105
106 bool ok;
107
108 void do_init_element (const octave_value&, bool&);
109
110 void init (const tree_argument_list&);
111
112 void cellify (void);
113
114 private:
115
116 tm_row_const_rep (const tm_row_const_rep&);
117
118 tm_row_const_rep& operator = (const tm_row_const_rep&);
119
120 };
121
122 public:
123
124 typedef tm_row_const_rep::iterator iterator;
125 typedef tm_row_const_rep::const_iterator const_iterator;
126
127 tm_row_const (void)
128 : rep (0) { }
129
130 tm_row_const (const tree_argument_list& row)
131 : rep (new tm_row_const_rep (row)) { }
132
133 tm_row_const (const tm_row_const& x)
134 : rep (x.rep)
135 {
136 if (rep)
137 rep->count++;
138 }
139
140 tm_row_const& operator = (const tm_row_const& x)
141 {
142 if (this != &x && rep != x.rep)
143 {
144 if (rep && --rep->count == 0)
145 delete rep;
146
147 rep = x.rep;
148
149 if (rep)
150 rep->count++;
151 }
152
153 return *this;
154 }
155
156 ~tm_row_const (void)
157 {
158 if (rep && --rep->count == 0)
159 delete rep;
160 }
161
162 octave_idx_type rows (void) { return rep->dv(0); }
163 octave_idx_type cols (void) { return rep->dv(1); }
164
165 bool empty (void) const { return rep->empty (); }
166
167 size_t length (void) const { return rep->length (); }
168
169 dim_vector dims (void) { return rep->dv; }
170
171 bool all_strings_p (void) const { return rep->all_str; }
172 bool all_sq_strings_p (void) const { return rep->all_sq_str; }
173 bool all_dq_strings_p (void) const { return rep->all_dq_str; }
174 bool some_strings_p (void) const { return rep->some_str; }
175 bool all_real_p (void) const { return rep->all_real; }
176 bool all_complex_p (void) const { return rep->all_cmplx; }
177 bool all_empty_p (void) const { return rep->all_mt; }
178 bool any_cell_p (void) const { return rep->any_cell; }
179 bool any_sparse_p (void) const { return rep->any_sparse; }
180 bool any_class_p (void) const { return rep->any_class; }
181 bool all_1x1_p (void) const { return rep->all_1x1; }
182 bool first_elem_struct_p (void) const { return rep->first_elem_is_struct; }
183
184 std::string class_name (void) const { return rep->class_nm; }
185
186 void cellify (void) { rep->cellify (); }
187
188 operator bool () const { return (rep && rep->ok); }
189
190 iterator begin (void) { return rep->begin (); }
191 const_iterator begin (void) const { return rep->begin (); }
192
193 iterator end (void) { return rep->end (); }
194 const_iterator end (void) const { return rep->end (); }
195
196 private:
197
198 tm_row_const_rep *rep;
199 };
200
201 std::string
202 get_concat_class (const std::string& c1, const std::string& c2)
203 {
204 std::string retval = octave_base_value::static_class_name ();
205
206 if (c1 == c2)
207 retval = c1;
208 else if (c1.empty ())
209 retval = c2;
210 else if (c2.empty ())
211 retval = c1;
212 else if (c1 == "class" || c2 == "class")
213 retval = "class";
214 else
215 {
216 bool c1_is_int = (c1 == "int8" || c1 == "uint8"
217 || c1 == "int16" || c1 == "uint16"
218 || c1 == "int32" || c1 == "uint32"
219 || c1 == "int64" || c1 == "uint64");
220 bool c2_is_int = (c2 == "int8" || c2 == "uint8"
221 || c2 == "int16" || c2 == "uint16"
222 || c2 == "int32" || c2 == "uint32"
223 || c2 == "int64" || c2 == "uint64");
224
225 bool c1_is_char = (c1 == "char");
226 bool c2_is_char = (c2 == "char");
227
228 bool c1_is_double = (c1 == "double");
229 bool c2_is_double = (c2 == "double");
230
231 bool c1_is_single = (c1 == "single");
232 bool c2_is_single = (c2 == "single");
233
234 bool c1_is_logical = (c1 == "logical");
235 bool c2_is_logical = (c2 == "logical");
236
237 bool c1_is_built_in_type
238 = (c1_is_int || c1_is_char || c1_is_double || c1_is_single
239 || c1_is_logical);
240
241 bool c2_is_built_in_type
242 = (c2_is_int || c2_is_char || c2_is_double || c2_is_single
243 || c2_is_logical);
244
245 // Order is important here...
246
247 if (c1 == "struct" && c2 == c1)
248 retval = c1;
249 else if (c1 == "cell" || c2 == "cell")
250 retval = "cell";
251 else if (c1_is_char && c2_is_built_in_type)
252 retval = c1;
253 else if (c2_is_char && c1_is_built_in_type)
254 retval = c2;
255 else if (c1_is_int && c2_is_built_in_type)
256 retval = c1;
257 else if (c2_is_int && c1_is_built_in_type)
258 retval = c2;
259 else if (c1_is_single && c2_is_built_in_type)
260 retval = c1;
261 else if (c2_is_single && c1_is_built_in_type)
262 retval = c2;
263 else if (c1_is_double && c2_is_built_in_type)
264 retval = c1;
265 else if (c2_is_double && c1_is_built_in_type)
266 retval = c2;
267 else if (c1_is_logical && c2_is_logical)
268 retval = c1;
269 }
270
271 return retval;
272 }
273
274 static void
275 eval_error (const char *msg, const dim_vector& x, const dim_vector& y)
276 {
277 ::error ("%s (%s vs %s)", msg, x.str ().c_str (), y.str ().c_str ());
278 }
279
280 void
281 tm_row_const::tm_row_const_rep::do_init_element (const octave_value& val,
282 bool& first_elem)
283 {
284 std::string this_elt_class_nm
285 = val.is_object () ? std::string ("class") : val.class_name ();
286
287 class_nm = get_concat_class (class_nm, this_elt_class_nm);
288
289 dim_vector this_elt_dv = val.dims ();
290
291 if (! this_elt_dv.zero_by_zero ())
292 {
293 all_mt = false;
294
295 if (first_elem)
296 {
297 if (val.is_map ())
298 first_elem_is_struct = true;
299
300 first_elem = false;
301 }
302 }
303
304 append (val);
305
306 if (all_str && ! val.is_string ())
307 all_str = false;
308
309 if (all_sq_str && ! val.is_sq_string ())
310 all_sq_str = false;
311
312 if (all_dq_str && ! val.is_dq_string ())
313 all_dq_str = false;
314
315 if (! some_str && val.is_string ())
316 some_str = true;
317
318 if (all_real && ! val.is_real_type ())
319 all_real = false;
320
321 if (all_cmplx && ! (val.is_complex_type () || val.is_real_type ()))
322 all_cmplx = false;
323
324 if (!any_cell && val.is_cell ())
325 any_cell = true;
326
327 if (!any_sparse && val.is_sparse_type ())
328 any_sparse = true;
329
330 if (!any_class && val.is_object ())
331 any_class = true;
332
333 all_1x1 = all_1x1 && val.numel () == 1;
334 }
335
336 void
337 tm_row_const::tm_row_const_rep::init (const tree_argument_list& row)
338 {
339 all_str = true;
340 all_sq_str = true;
341 all_dq_str = true;
342 all_real = true;
343 all_cmplx = true;
344 any_cell = false;
345 any_sparse = false;
346 any_class = false;
347
348 bool first_elem = true;
349
350 for (tree_argument_list::const_iterator p = row.begin ();
351 p != row.end ();
352 p++)
353 {
354 octave_quit ();
355
356 tree_expression *elt = *p;
357
358 octave_value tmp = elt->rvalue1 ();
359
360 if (error_state || tmp.is_undefined ())
361 {
362 ok = ! error_state;
363 return;
364 }
365 else
366 {
367 if (tmp.is_cs_list ())
368 {
369 octave_value_list tlst = tmp.list_value ();
370
371 for (octave_idx_type i = 0; i < tlst.length (); i++)
372 {
373 octave_quit ();
374
375 do_init_element (tlst(i), first_elem);
376 }
377 }
378 else
379 do_init_element (tmp, first_elem);
380 }
381 }
382
383 if (any_cell && ! any_class && ! first_elem_is_struct)
384 cellify ();
385
386 first_elem = true;
387
388 for (iterator p = begin (); p != end (); p++)
389 {
390 octave_quit ();
391
392 octave_value val = *p;
393
394 dim_vector this_elt_dv = val.dims ();
395
396 if (! this_elt_dv.zero_by_zero ())
397 {
398 all_mt = false;
399
400 if (first_elem)
401 {
402 first_elem = false;
403 dv = this_elt_dv;
404 }
405 else if (! dv.hvcat (this_elt_dv, 1))
406 {
407 eval_error ("horizontal dimensions mismatch", dv, this_elt_dv);
408 break;
409 }
410 }
411 }
412
413 ok = ! error_state;
414 }
415
416 void
417 tm_row_const::tm_row_const_rep::cellify (void)
418 {
419 bool elt_changed = false;
420
421 for (iterator p = begin (); p != end (); p++)
422 {
423 octave_quit ();
424
425 if (! p->is_cell ())
426 {
427 elt_changed = true;
428
429 *p = Cell (*p);
430 }
431 }
432
433 if (elt_changed)
434 {
435 bool first_elem = true;
436
437 for (iterator p = begin (); p != end (); p++)
438 {
439 octave_quit ();
440
441 octave_value val = *p;
442
443 dim_vector this_elt_dv = val.dims ();
444
445 if (! this_elt_dv.zero_by_zero ())
446 {
447 if (first_elem)
448 {
449 first_elem = false;
450 dv = this_elt_dv;
451 }
452 else if (! dv.hvcat (this_elt_dv, 1))
453 {
454 eval_error ("horizontal dimensions mismatch", dv, this_elt_dv);
455 break;
456 }
457 }
458 }
459 }
460 }
461
462 class
463 tm_const : public octave_base_list<tm_row_const>
464 {
465 public:
466
467 tm_const (const tree_matrix& tm)
468 : dv (0, 0), all_str (false), all_sq_str (false), all_dq_str (false),
469 some_str (false), all_real (false), all_cmplx (false),
470 all_mt (true), any_cell (false), any_sparse (false),
471 any_class (false), class_nm (), ok (false)
472 { init (tm); }
473
474 ~tm_const (void) { }
475
476 octave_idx_type rows (void) const { return dv.elem (0); }
477 octave_idx_type cols (void) const { return dv.elem (1); }
478
479 dim_vector dims (void) const { return dv; }
480
481 bool all_strings_p (void) const { return all_str; }
482 bool all_sq_strings_p (void) const { return all_sq_str; }
483 bool all_dq_strings_p (void) const { return all_dq_str; }
484 bool some_strings_p (void) const { return some_str; }
485 bool all_real_p (void) const { return all_real; }
486 bool all_complex_p (void) const { return all_cmplx; }
487 bool all_empty_p (void) const { return all_mt; }
488 bool any_cell_p (void) const { return any_cell; }
489 bool any_sparse_p (void) const { return any_sparse; }
490 bool any_class_p (void) const { return any_class; }
491 bool all_1x1_p (void) const { return all_1x1; }
492
493 std::string class_name (void) const { return class_nm; }
494
495 operator bool () const { return ok; }
496
497 private:
498
499 dim_vector dv;
500
501 bool all_str;
502 bool all_sq_str;
503 bool all_dq_str;
504 bool some_str;
505 bool all_real;
506 bool all_cmplx;
507 bool all_mt;
508 bool any_cell;
509 bool any_sparse;
510 bool any_class;
511 bool all_1x1;
512
513 std::string class_nm;
514
515 bool ok;
516
517 tm_const (void);
518
519 tm_const (const tm_const&);
520
521 tm_const& operator = (const tm_const&);
522
523 void init (const tree_matrix& tm);
524 };
525
526 void
527 tm_const::init (const tree_matrix& tm)
528 {
529 all_str = true;
530 all_sq_str = true;
531 all_dq_str = true;
532 all_real = true;
533 all_cmplx = true;
534 any_cell = false;
535 any_sparse = false;
536 any_class = false;
537 all_1x1 = ! tm.empty ();
538
539 bool first_elem = true;
540 bool first_elem_is_struct = false;
541
542 // Just eval and figure out if what we have is complex or all
543 // strings. We can't check columns until we know that this is a
544 // numeric matrix -- collections of strings can have elements of
545 // different lengths.
546
547 for (tree_matrix::const_iterator p = tm.begin (); p != tm.end (); p++)
548 {
549 octave_quit ();
550
551 tree_argument_list *elt = *p;
552
553 tm_row_const tmp (*elt);
554
555 if (first_elem)
556 {
557 first_elem_is_struct = tmp.first_elem_struct_p ();
558
559 first_elem = false;
560 }
561
562 if (tmp && ! tmp.empty ())
563 {
564 if (all_str && ! tmp.all_strings_p ())
565 all_str = false;
566
567 if (all_sq_str && ! tmp.all_sq_strings_p ())
568 all_sq_str = false;
569
570 if (all_dq_str && ! tmp.all_dq_strings_p ())
571 all_dq_str = false;
572
573 if (! some_str && tmp.some_strings_p ())
574 some_str = true;
575
576 if (all_real && ! tmp.all_real_p ())
577 all_real = false;
578
579 if (all_cmplx && ! tmp.all_complex_p ())
580 all_cmplx = false;
581
582 if (all_mt && ! tmp.all_empty_p ())
583 all_mt = false;
584
585 if (!any_cell && tmp.any_cell_p ())
586 any_cell = true;
587
588 if (!any_sparse && tmp.any_sparse_p ())
589 any_sparse = true;
590
591 if (!any_class && tmp.any_class_p ())
592 any_class = true;
593
594 all_1x1 = all_1x1 && tmp.all_1x1_p ();
595
596 append (tmp);
597 }
598 else
599 break;
600 }
601
602 if (! error_state)
603 {
604 if (any_cell && ! any_class && ! first_elem_is_struct)
605 {
606 for (iterator q = begin (); q != end (); q++)
607 {
608 octave_quit ();
609
610 q->cellify ();
611 }
612 }
613
614 first_elem = true;
615
616 for (iterator q = begin (); q != end (); q++)
617 {
618 octave_quit ();
619
620 tm_row_const elt = *q;
621
622 octave_idx_type this_elt_nr = elt.rows ();
623 octave_idx_type this_elt_nc = elt.cols ();
624
625 std::string this_elt_class_nm = elt.class_name ();
626 class_nm = get_concat_class (class_nm, this_elt_class_nm);
627
628 dim_vector this_elt_dv = elt.dims ();
629
630 all_mt = false;
631
632 if (first_elem)
633 {
634 first_elem = false;
635
636 dv = this_elt_dv;
637 }
638 else if (all_str && dv.length () == 2
639 && this_elt_dv.length () == 2)
640 {
641 // FIXME: this is Octave's specialty. Character matrices allow
642 // rows of unequal length.
643 if (this_elt_nc > cols ())
644 dv(1) = this_elt_nc;
645 dv(0) += this_elt_nr;
646 }
647 else if (! dv.hvcat (this_elt_dv, 0))
648 {
649 eval_error ("vertical dimensions mismatch", dv, this_elt_dv);
650 return;
651 }
652 }
653 }
654
655 ok = ! error_state;
656 }
657
658 tree_matrix::~tree_matrix (void)
659 {
660 while (! empty ())
661 {
662 iterator p = begin ();
663 delete *p;
664 erase (p);
665 }
666 }
667
668 bool
669 tree_matrix::has_magic_end (void) const
670 {
671 for (const_iterator p = begin (); p != end (); p++)
672 {
673 octave_quit ();
674
675 tree_argument_list *elt = *p;
676
677 if (elt && elt->has_magic_end ())
678 return true;
679 }
680
681 return false;
682 }
683
684 bool
685 tree_matrix::all_elements_are_constant (void) const
686 {
687 for (const_iterator p = begin (); p != end (); p++)
688 {
689 octave_quit ();
690
691 tree_argument_list *elt = *p;
692
693 if (! elt->all_elements_are_constant ())
694 return false;
695 }
696
697 return true;
698 }
699
700 octave_value_list
701 tree_matrix::rvalue (int nargout)
702 {
703 octave_value_list retval;
704
705 if (nargout > 1)
706 error ("invalid number of output arguments for matrix list");
707 else
708 retval = rvalue1 (nargout);
709
710 return retval;
711 }
712
713 void
714 maybe_warn_string_concat (bool all_dq_strings_p, bool all_sq_strings_p)
715 {
716 if (! (all_dq_strings_p || all_sq_strings_p))
717 warning_with_id ("Octave:mixed-string-concat",
718 "concatenation of different character string types may have unintended consequences");
719 }
720
721 template<class TYPE, class T>
722 static void
723 single_type_concat (Array<T>& result,
724 tm_const& tmp)
725 {
726 octave_idx_type r = 0, c = 0;
727
728 for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++)
729 {
730 tm_row_const row = *p;
731 // Skip empty arrays to allow looser rules.
732 if (row.dims ().any_zero ())
733 continue;
734
735 for (tm_row_const::iterator q = row.begin ();
736 q != row.end ();
737 q++)
738 {
739 octave_quit ();
740
741 TYPE ra = octave_value_extract<TYPE> (*q);
742
743 // Skip empty arrays to allow looser rules.
744 if (! error_state)
745 {
746 if (! ra.is_empty ())
747 {
748 result.insert (ra, r, c);
749
750 if (! error_state)
751 c += ra.columns ();
752 else
753 return;
754 }
755 }
756 else
757 return;
758 }
759
760 r += row.rows ();
761 c = 0;
762 }
763 }
764
765 template<class TYPE, class T>
766 static void
767 single_type_concat (Array<T>& result,
768 const dim_vector& dv,
769 tm_const& tmp)
770 {
771 if (dv.any_zero ())
772 {
773 result = Array<T> (dv);
774 return;
775 }
776
777 if (tmp.length () == 1)
778 {
779 // If possible, forward the operation to liboctave.
780 // Single row.
781 tm_row_const& row = tmp.front ();
782 if (! (equal_types<T, char>::value || equal_types<T, octave_value>::value)
783 && row.all_1x1_p ())
784 {
785 // Optimize all scalars case.
786 result.clear (dv);
787 assert (static_cast<size_t> (result.numel ()) == row.length ());
788 octave_idx_type i = 0;
789 for (tm_row_const::iterator q = row.begin ();
790 q != row.end () && ! error_state; q++)
791 result(i++) = octave_value_extract<T> (*q);
792
793 return;
794 }
795
796 octave_idx_type ncols = row.length (), i = 0;
797 OCTAVE_LOCAL_BUFFER (Array<T>, array_list, ncols);
798
799 for (tm_row_const::iterator q = row.begin ();
800 q != row.end () && ! error_state;
801 q++)
802 {
803 octave_quit ();
804
805 array_list[i] = octave_value_extract<TYPE> (*q);
806 i++;
807 }
808
809 if (! error_state)
810 result = Array<T>::cat (-2, ncols, array_list);
811 }
812 else
813 {
814 result = Array<T> (dv);
815 single_type_concat<TYPE> (result, tmp);
816 }
817 }
818
819 template<class TYPE, class T>
820 static void
821 single_type_concat (Sparse<T>& result,
822 const dim_vector& dv,
823 tm_const& tmp)
824 {
825 if (dv.any_zero ())
826 {
827 result = Sparse<T> (dv);
828 return;
829 }
830
831 // Sparse matrices require preallocation for efficient indexing; besides,
832 // only horizontal concatenation can be efficiently handled by indexing.
833 // So we just cat all rows through liboctave, then cat the final column.
834 octave_idx_type nrows = tmp.length (), j = 0;
835 OCTAVE_LOCAL_BUFFER (Sparse<T>, sparse_row_list, nrows);
836 for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++)
837 {
838 tm_row_const row = *p;
839 octave_idx_type ncols = row.length (), i = 0;
840 OCTAVE_LOCAL_BUFFER (Sparse<T>, sparse_list, ncols);
841
842 for (tm_row_const::iterator q = row.begin ();
843 q != row.end () && ! error_state;
844 q++)
845 {
846 octave_quit ();
847
848 sparse_list[i] = octave_value_extract<TYPE> (*q);
849 i++;
850 }
851
852 Sparse<T> stmp = Sparse<T>::cat (-2, ncols, sparse_list);
853 sparse_row_list[j] = stmp;
854 j++;
855 }
856
857 result = Sparse<T>::cat (-1, nrows, sparse_row_list);
858 }
859
860 template<class MAP>
861 static void
862 single_type_concat (octave_map& result,
863 const dim_vector& dv,
864 tm_const& tmp)
865 {
866 if (dv.any_zero ())
867 {
868 result = octave_map (dv);
869 return;
870 }
871
872 octave_idx_type nrows = tmp.length (), j = 0;
873 OCTAVE_LOCAL_BUFFER (octave_map, map_row_list, nrows);
874 for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++)
875 {
876 tm_row_const row = *p;
877 octave_idx_type ncols = row.length (), i = 0;
878 OCTAVE_LOCAL_BUFFER (MAP, map_list, ncols);
879
880 for (tm_row_const::iterator q = row.begin ();
881 q != row.end () && ! error_state;
882 q++)
883 {
884 octave_quit ();
885
886 map_list[i] = octave_value_extract<MAP> (*q);
887 i++;
888 }
889
890 octave_map mtmp = octave_map::cat (-2, ncols, map_list);
891 map_row_list[j] = mtmp;
892 j++;
893 }
894
895 result = octave_map::cat (-1, nrows, map_row_list);
896 }
897
898 template<class TYPE>
899 static octave_value
900 do_single_type_concat (const dim_vector& dv,
901 tm_const& tmp)
902 {
903 TYPE result;
904
905 single_type_concat<TYPE> (result, dv, tmp);
906
907 return result;
908 }
909
910 template<>
911 octave_value
912 do_single_type_concat<octave_map> (const dim_vector& dv,
913 tm_const& tmp)
914 {
915 octave_map result;
916
917 if (tmp.all_1x1_p ())
918 single_type_concat<octave_scalar_map> (result, dv, tmp);
919 else
920 single_type_concat<octave_map> (result, dv, tmp);
921
922 return result;
923 }
924
925 static octave_value
926 do_class_concat (tm_const& tmc)
927 {
928 octave_value retval;
929
930 octave_value_list rows (tmc.length (), octave_value ());
931
932 octave_idx_type j = 0;
933 for (tm_const::iterator p = tmc.begin (); p != tmc.end (); p++)
934 {
935 octave_quit ();
936
937 tm_row_const tmrc = *p;
938
939 if (tmrc.length () == 1)
940 rows(j++) = *(tmrc.begin ());
941 else
942 {
943 octave_value_list row (tmrc.length (), octave_value ());
944
945 octave_idx_type i = 0;
946 for (tm_row_const::iterator q = tmrc.begin (); q != tmrc.end (); q++)
947 row(i++) = *q;
948
949 rows(j++) = do_class_concat (row, "horzcat", 1);
950 }
951 }
952
953 if (! error_state)
954 {
955 if (rows.length () == 1)
956 retval = rows(0);
957 else
958 retval = do_class_concat (rows, "vertcat", 0);
959 }
960
961 return retval;
962 }
963
964 octave_value
965 tree_matrix::rvalue1 (int)
966 {
967 octave_value retval = Matrix ();
968
969 bool all_sq_strings_p = false;
970 bool all_dq_strings_p = false;
971 bool all_empty_p = false;
972 bool all_real_p = false;
973 bool any_sparse_p = false;
974 bool any_class_p = false;
975 bool frc_str_conv = false;
976
977 tm_const tmp (*this);
978
979 if (tmp && ! tmp.empty ())
980 {
981 dim_vector dv = tmp.dims ();
982 all_sq_strings_p = tmp.all_sq_strings_p ();
983 all_dq_strings_p = tmp.all_dq_strings_p ();
984 all_empty_p = tmp.all_empty_p ();
985 all_real_p = tmp.all_real_p ();
986 any_sparse_p = tmp.any_sparse_p ();
987 any_class_p = tmp.any_class_p ();
988 frc_str_conv = tmp.some_strings_p ();
989
990 // Try to speed up the common cases.
991
992 std::string result_type = tmp.class_name ();
993
994 if (any_class_p)
995 {
996 retval = do_class_concat (tmp);
997 }
998 else if (result_type == "double")
999 {
1000 if (any_sparse_p)
1001 {
1002 if (all_real_p)
1003 retval = do_single_type_concat<SparseMatrix> (dv, tmp);
1004 else
1005 retval = do_single_type_concat<SparseComplexMatrix> (dv, tmp);
1006 }
1007 else
1008 {
1009 if (all_real_p)
1010 retval = do_single_type_concat<NDArray> (dv, tmp);
1011 else
1012 retval = do_single_type_concat<ComplexNDArray> (dv, tmp);
1013 }
1014 }
1015 else if (result_type == "single")
1016 {
1017 if (all_real_p)
1018 retval = do_single_type_concat<FloatNDArray> (dv, tmp);
1019 else
1020 retval = do_single_type_concat<FloatComplexNDArray> (dv, tmp);
1021 }
1022 else if (result_type == "char")
1023 {
1024 char type = all_dq_strings_p ? '"' : '\'';
1025
1026 maybe_warn_string_concat (all_dq_strings_p, all_sq_strings_p);
1027
1028 charNDArray result (dv, Vstring_fill_char);
1029
1030 single_type_concat<charNDArray> (result, tmp);
1031
1032 retval = octave_value (result, type);
1033 }
1034 else if (result_type == "logical")
1035 {
1036 if (any_sparse_p)
1037 retval = do_single_type_concat<SparseBoolMatrix> (dv, tmp);
1038 else
1039 retval = do_single_type_concat<boolNDArray> (dv, tmp);
1040 }
1041 else if (result_type == "int8")
1042 retval = do_single_type_concat<int8NDArray> (dv, tmp);
1043 else if (result_type == "int16")
1044 retval = do_single_type_concat<int16NDArray> (dv, tmp);
1045 else if (result_type == "int32")
1046 retval = do_single_type_concat<int32NDArray> (dv, tmp);
1047 else if (result_type == "int64")
1048 retval = do_single_type_concat<int64NDArray> (dv, tmp);
1049 else if (result_type == "uint8")
1050 retval = do_single_type_concat<uint8NDArray> (dv, tmp);
1051 else if (result_type == "uint16")
1052 retval = do_single_type_concat<uint16NDArray> (dv, tmp);
1053 else if (result_type == "uint32")
1054 retval = do_single_type_concat<uint32NDArray> (dv, tmp);
1055 else if (result_type == "uint64")
1056 retval = do_single_type_concat<uint64NDArray> (dv, tmp);
1057 else if (result_type == "cell")
1058 retval = do_single_type_concat<Cell> (dv, tmp);
1059 else if (result_type == "struct")
1060 retval = do_single_type_concat<octave_map> (dv, tmp);
1061 else
1062 {
1063 // The line below might seem crazy, since we take a copy of
1064 // the first argument, resize it to be empty and then resize
1065 // it to be full. This is done since it means that there is
1066 // no recopying of data, as would happen if we used a single
1067 // resize. It should be noted that resize operation is also
1068 // significantly slower than the do_cat_op function, so it
1069 // makes sense to have an empty matrix and copy all data.
1070 //
1071 // We might also start with a empty octave_value using
1072 //
1073 // ctmp = octave_value_typeinfo::lookup_type
1074 // (tmp.begin() -> begin() -> type_name());
1075 //
1076 // and then directly resize. However, for some types there
1077 // might be some additional setup needed, and so this should
1078 // be avoided.
1079
1080 octave_value ctmp;
1081
1082 // Find the first non-empty object
1083
1084 if (any_sparse_p)
1085 {
1086 // Start with sparse matrix to avoid issues memory issues
1087 // with things like [ones(1,4),sprandn(1e8,4,1e-4)]
1088 if (all_real_p)
1089 ctmp = octave_sparse_matrix ().resize (dv);
1090 else
1091 ctmp = octave_sparse_complex_matrix ().resize (dv);
1092 }
1093 else
1094 {
1095 for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++)
1096 {
1097 octave_quit ();
1098
1099 tm_row_const row = *p;
1100
1101 for (tm_row_const::iterator q = row.begin ();
1102 q != row.end (); q++)
1103 {
1104 octave_quit ();
1105
1106 ctmp = *q;
1107
1108 if (! ctmp.all_zero_dims ())
1109 goto found_non_empty;
1110 }
1111 }
1112
1113 ctmp = (*(tmp.begin () -> begin ()));
1114
1115 found_non_empty:
1116
1117 if (! all_empty_p)
1118 ctmp = ctmp.resize (dim_vector (0,0)).resize (dv);
1119 }
1120
1121 if (! error_state)
1122 {
1123 // Now, extract the values from the individual elements and
1124 // insert them in the result matrix.
1125
1126 int dv_len = dv.length ();
1127 octave_idx_type ntmp = dv_len > 1 ? dv_len : 2;
1128 Array<octave_idx_type> ra_idx (dim_vector (ntmp, 1), 0);
1129
1130 for (tm_const::iterator p = tmp.begin (); p != tmp.end (); p++)
1131 {
1132 octave_quit ();
1133
1134 tm_row_const row = *p;
1135
1136 for (tm_row_const::iterator q = row.begin ();
1137 q != row.end ();
1138 q++)
1139 {
1140 octave_quit ();
1141
1142 octave_value elt = *q;
1143
1144 if (elt.is_empty ())
1145 continue;
1146
1147 ctmp = do_cat_op (ctmp, elt, ra_idx);
1148
1149 if (error_state)
1150 goto done;
1151
1152 ra_idx (1) += elt.columns ();
1153 }
1154
1155 ra_idx (0) += row.rows ();
1156 ra_idx (1) = 0;
1157 }
1158
1159 retval = ctmp;
1160
1161 if (frc_str_conv && ! retval.is_string ())
1162 retval = retval.convert_to_str ();
1163 }
1164 }
1165 }
1166
1167 done:
1168 return retval;
1169 }
1170
1171 tree_expression *
1172 tree_matrix::dup (symbol_table::scope_id scope,
1173 symbol_table::context_id context) const
1174 {
1175 tree_matrix *new_matrix = new tree_matrix (0, line (), column ());
1176
1177 for (const_iterator p = begin (); p != end (); p++)
1178 {
1179 const tree_argument_list *elt = *p;
1180
1181 new_matrix->append (elt ? elt->dup (scope, context) : 0);
1182 }
1183
1184 new_matrix->copy_base (*this);
1185
1186 return new_matrix;
1187 }
1188
1189 void
1190 tree_matrix::accept (tree_walker& tw)
1191 {
1192 tw.visit_matrix (*this);
1193 }
1194
1195 /*
1196 ## test concatenation with all zero matrices
1197 %!assert ([ "" 65*ones(1,10) ], "AAAAAAAAAA");
1198 %!assert ([ 65*ones(1,10) "" ], "AAAAAAAAAA");
1199
1200 %!test
1201 %! c = {"foo"; "bar"; "bazoloa"};
1202 %! assert ([c; "a"; "bc"; "def"], {"foo"; "bar"; "bazoloa"; "a"; "bc"; "def"});
1203
1204 %!assert (class ([int64(1), int64(1)]), "int64")
1205 %!assert (class ([int64(1), int32(1)]), "int64")
1206 %!assert (class ([int64(1), int16(1)]), "int64")
1207 %!assert (class ([int64(1), int8(1)]), "int64")
1208 %!assert (class ([int64(1), uint64(1)]), "int64")
1209 %!assert (class ([int64(1), uint32(1)]), "int64")
1210 %!assert (class ([int64(1), uint16(1)]), "int64")
1211 %!assert (class ([int64(1), uint8(1)]), "int64")
1212 %!assert (class ([int64(1), single(1)]), "int64")
1213 %!assert (class ([int64(1), double(1)]), "int64")
1214 %!assert (class ([int64(1), cell(1)]), "cell")
1215 %!assert (class ([int64(1), true]), "int64")
1216 %!assert (class ([int64(1), "a"]), "char")
1217
1218 %!assert (class ([int32(1), int64(1)]), "int32")
1219 %!assert (class ([int32(1), int32(1)]), "int32")
1220 %!assert (class ([int32(1), int16(1)]), "int32")
1221 %!assert (class ([int32(1), int8(1)]), "int32")
1222 %!assert (class ([int32(1), uint64(1)]), "int32")
1223 %!assert (class ([int32(1), uint32(1)]), "int32")
1224 %!assert (class ([int32(1), uint16(1)]), "int32")
1225 %!assert (class ([int32(1), uint8(1)]), "int32")
1226 %!assert (class ([int32(1), single(1)]), "int32")
1227 %!assert (class ([int32(1), double(1)]), "int32")
1228 %!assert (class ([int32(1), cell(1)]), "cell")
1229 %!assert (class ([int32(1), true]), "int32")
1230 %!assert (class ([int32(1), "a"]), "char")
1231
1232 %!assert (class ([int16(1), int64(1)]), "int16")
1233 %!assert (class ([int16(1), int32(1)]), "int16")
1234 %!assert (class ([int16(1), int16(1)]), "int16")
1235 %!assert (class ([int16(1), int8(1)]), "int16")
1236 %!assert (class ([int16(1), uint64(1)]), "int16")
1237 %!assert (class ([int16(1), uint32(1)]), "int16")
1238 %!assert (class ([int16(1), uint16(1)]), "int16")
1239 %!assert (class ([int16(1), uint8(1)]), "int16")
1240 %!assert (class ([int16(1), single(1)]), "int16")
1241 %!assert (class ([int16(1), double(1)]), "int16")
1242 %!assert (class ([int16(1), cell(1)]), "cell")
1243 %!assert (class ([int16(1), true]), "int16")
1244 %!assert (class ([int16(1), "a"]), "char")
1245
1246 %!assert (class ([int8(1), int64(1)]), "int8")
1247 %!assert (class ([int8(1), int32(1)]), "int8")
1248 %!assert (class ([int8(1), int16(1)]), "int8")
1249 %!assert (class ([int8(1), int8(1)]), "int8")
1250 %!assert (class ([int8(1), uint64(1)]), "int8")
1251 %!assert (class ([int8(1), uint32(1)]), "int8")
1252 %!assert (class ([int8(1), uint16(1)]), "int8")
1253 %!assert (class ([int8(1), uint8(1)]), "int8")
1254 %!assert (class ([int8(1), single(1)]), "int8")
1255 %!assert (class ([int8(1), double(1)]), "int8")
1256 %!assert (class ([int8(1), cell(1)]), "cell")
1257 %!assert (class ([int8(1), true]), "int8")
1258 %!assert (class ([int8(1), "a"]), "char")
1259
1260 %!assert (class ([uint64(1), int64(1)]), "uint64")
1261 %!assert (class ([uint64(1), int32(1)]), "uint64")
1262 %!assert (class ([uint64(1), int16(1)]), "uint64")
1263 %!assert (class ([uint64(1), int8(1)]), "uint64")
1264 %!assert (class ([uint64(1), uint64(1)]), "uint64")
1265 %!assert (class ([uint64(1), uint32(1)]), "uint64")
1266 %!assert (class ([uint64(1), uint16(1)]), "uint64")
1267 %!assert (class ([uint64(1), uint8(1)]), "uint64")
1268 %!assert (class ([uint64(1), single(1)]), "uint64")
1269 %!assert (class ([uint64(1), double(1)]), "uint64")
1270 %!assert (class ([uint64(1), cell(1)]), "cell")
1271 %!assert (class ([uint64(1), true]), "uint64")
1272 %!assert (class ([uint64(1), "a"]), "char")
1273
1274 %!assert (class ([uint32(1), int64(1)]), "uint32")
1275 %!assert (class ([uint32(1), int32(1)]), "uint32")
1276 %!assert (class ([uint32(1), int16(1)]), "uint32")
1277 %!assert (class ([uint32(1), int8(1)]), "uint32")
1278 %!assert (class ([uint32(1), uint64(1)]), "uint32")
1279 %!assert (class ([uint32(1), uint32(1)]), "uint32")
1280 %!assert (class ([uint32(1), uint16(1)]), "uint32")
1281 %!assert (class ([uint32(1), uint8(1)]), "uint32")
1282 %!assert (class ([uint32(1), single(1)]), "uint32")
1283 %!assert (class ([uint32(1), double(1)]), "uint32")
1284 %!assert (class ([uint32(1), cell(1)]), "cell")
1285 %!assert (class ([uint32(1), true]), "uint32")
1286 %!assert (class ([uint32(1), "a"]), "char")
1287
1288 %!assert (class ([uint16(1), int64(1)]), "uint16")
1289 %!assert (class ([uint16(1), int32(1)]), "uint16")
1290 %!assert (class ([uint16(1), int16(1)]), "uint16")
1291 %!assert (class ([uint16(1), int8(1)]), "uint16")
1292 %!assert (class ([uint16(1), uint64(1)]), "uint16")
1293 %!assert (class ([uint16(1), uint32(1)]), "uint16")
1294 %!assert (class ([uint16(1), uint16(1)]), "uint16")
1295 %!assert (class ([uint16(1), uint8(1)]), "uint16")
1296 %!assert (class ([uint16(1), single(1)]), "uint16")
1297 %!assert (class ([uint16(1), double(1)]), "uint16")
1298 %!assert (class ([uint16(1), cell(1)]), "cell")
1299 %!assert (class ([uint16(1), true]), "uint16")
1300 %!assert (class ([uint16(1), "a"]), "char")
1301
1302 %!assert (class ([uint8(1), int64(1)]), "uint8")
1303 %!assert (class ([uint8(1), int32(1)]), "uint8")
1304 %!assert (class ([uint8(1), int16(1)]), "uint8")
1305 %!assert (class ([uint8(1), int8(1)]), "uint8")
1306 %!assert (class ([uint8(1), uint64(1)]), "uint8")
1307 %!assert (class ([uint8(1), uint32(1)]), "uint8")
1308 %!assert (class ([uint8(1), uint16(1)]), "uint8")
1309 %!assert (class ([uint8(1), uint8(1)]), "uint8")
1310 %!assert (class ([uint8(1), single(1)]), "uint8")
1311 %!assert (class ([uint8(1), double(1)]), "uint8")
1312 %!assert (class ([uint8(1), cell(1)]), "cell")
1313 %!assert (class ([uint8(1), true]), "uint8")
1314 %!assert (class ([uint8(1), "a"]), "char")
1315
1316 %!assert (class ([single(1), int64(1)]), "int64")
1317 %!assert (class ([single(1), int32(1)]), "int32")
1318 %!assert (class ([single(1), int16(1)]), "int16")
1319 %!assert (class ([single(1), int8(1)]), "int8")
1320 %!assert (class ([single(1), uint64(1)]), "uint64")
1321 %!assert (class ([single(1), uint32(1)]), "uint32")
1322 %!assert (class ([single(1), uint16(1)]), "uint16")
1323 %!assert (class ([single(1), uint8(1)]), "uint8")
1324 %!assert (class ([single(1), single(1)]), "single")
1325 %!assert (class ([single(1), double(1)]), "single")
1326 %!assert (class ([single(1), cell(1)]), "cell")
1327 %!assert (class ([single(1), true]), "single")
1328 %!assert (class ([single(1), "a"]), "char")
1329
1330 %!assert (class ([double(1), int64(1)]), "int64")
1331 %!assert (class ([double(1), int32(1)]), "int32")
1332 %!assert (class ([double(1), int16(1)]), "int16")
1333 %!assert (class ([double(1), int8(1)]), "int8")
1334 %!assert (class ([double(1), uint64(1)]), "uint64")
1335 %!assert (class ([double(1), uint32(1)]), "uint32")
1336 %!assert (class ([double(1), uint16(1)]), "uint16")
1337 %!assert (class ([double(1), uint8(1)]), "uint8")
1338 %!assert (class ([double(1), single(1)]), "single")
1339 %!assert (class ([double(1), double(1)]), "double")
1340 %!assert (class ([double(1), cell(1)]), "cell")
1341 %!assert (class ([double(1), true]), "double")
1342 %!assert (class ([double(1), "a"]), "char")
1343
1344 %!assert (class ([cell(1), int64(1)]), "cell")
1345 %!assert (class ([cell(1), int32(1)]), "cell")
1346 %!assert (class ([cell(1), int16(1)]), "cell")
1347 %!assert (class ([cell(1), int8(1)]), "cell")
1348 %!assert (class ([cell(1), uint64(1)]), "cell")
1349 %!assert (class ([cell(1), uint32(1)]), "cell")
1350 %!assert (class ([cell(1), uint16(1)]), "cell")
1351 %!assert (class ([cell(1), uint8(1)]), "cell")
1352 %!assert (class ([cell(1), single(1)]), "cell")
1353 %!assert (class ([cell(1), double(1)]), "cell")
1354 %!assert (class ([cell(1), cell(1)]), "cell")
1355 %!assert (class ([cell(1), true]), "cell")
1356 %!assert (class ([cell(1), "a"]), "cell")
1357
1358 %!assert (class ([true, int64(1)]), "int64")
1359 %!assert (class ([true, int32(1)]), "int32")
1360 %!assert (class ([true, int16(1)]), "int16")
1361 %!assert (class ([true, int8(1)]), "int8")
1362 %!assert (class ([true, uint64(1)]), "uint64")
1363 %!assert (class ([true, uint32(1)]), "uint32")
1364 %!assert (class ([true, uint16(1)]), "uint16")
1365 %!assert (class ([true, uint8(1)]), "uint8")
1366 %!assert (class ([true, single(1)]), "single")
1367 %!assert (class ([true, double(1)]), "double")
1368 %!assert (class ([true, cell(1)]), "cell")
1369 %!assert (class ([true, true]), "logical")
1370 %!assert (class ([true, "a"]), "char")
1371
1372 %!assert (class (["a", int64(1)]), "char")
1373 %!assert (class (["a", int32(1)]), "char")
1374 %!assert (class (["a", int16(1)]), "char")
1375 %!assert (class (["a", int8(1)]), "char")
1376 %!assert (class (["a", int64(1)]), "char")
1377 %!assert (class (["a", int32(1)]), "char")
1378 %!assert (class (["a", int16(1)]), "char")
1379 %!assert (class (["a", int8(1)]), "char")
1380 %!assert (class (["a", single(1)]), "char")
1381 %!assert (class (["a", double(1)]), "char")
1382 %!assert (class (["a", cell(1)]), "cell")
1383 %!assert (class (["a", true]), "char")
1384 %!assert (class (["a", "a"]), "char")
1385
1386 %!assert (class ([cell(1), struct("foo", "bar")]), "cell")
1387 %!error [struct("foo", "bar"), cell(1)]
1388 */
1389
1390 DEFUN (string_fill_char, args, nargout,
1391 "-*- texinfo -*-\n\
1392 @deftypefn {Built-in Function} {@var{val} =} string_fill_char ()\n\
1393 @deftypefnx {Built-in Function} {@var{old_val} =} string_fill_char (@var{new_val})\n\
1394 @deftypefnx {Built-in Function} {} string_fill_char (@var{new_val}, \"local\")\n\
1395 Query or set the internal variable used to pad all rows of a character\n\
1396 matrix to the same length. It must be a single character. The default\n\
1397 value is @code{\" \"} (a single space). For example:\n\
1398 \n\
1399 @example\n\
1400 @group\n\
1401 string_fill_char (\"X\");\n\
1402 [ \"these\"; \"are\"; \"strings\" ]\n\
1403 @result{} \"theseXX\"\n\
1404 \"areXXXX\"\n\
1405 \"strings\"\n\
1406 @end group\n\
1407 @end example\n\
1408 \n\
1409 When called from inside a function with the \"local\" option, the variable is\n\
1410 changed locally for the function and any subroutines it calls. The original\n\
1411 variable value is restored when exiting the function.\n\
1412 @end deftypefn")
1413 {
1414 return SET_INTERNAL_VARIABLE (string_fill_char);
1415 }
1416
1417 /*
1418 ## string_fill_char() function call must be outside of %!test block
1419 ## due to the way a %!test block is wrapped inside a function
1420 %!shared orig_val, old_val
1421 %! orig_val = string_fill_char ();
1422 %! old_val = string_fill_char ("X");
1423 %!test
1424 %! assert (orig_val, old_val);
1425 %! assert (string_fill_char (), "X");
1426 %! assert (["these"; "are"; "strings"], ["theseXX"; "areXXXX"; "strings"]);
1427 %! string_fill_char (orig_val);
1428 %! assert (string_fill_char (), orig_val);
1429
1430 %!error (string_fill_char (1, 2))
1431 */