GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
ov-base-mat.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1996-2025 The Octave Project Developers
4//
5// See the file COPYRIGHT.md in the top-level directory of this
6// distribution or <https://octave.org/copyright/>.
7//
8// This file is part of Octave.
9//
10// Octave is free software: you can redistribute it and/or modify it
11// under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// Octave is distributed in the hope that it will be useful, but
16// WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with Octave; see the file COPYING. If not, see
22// <https://www.gnu.org/licenses/>.
23//
24////////////////////////////////////////////////////////////////////////
25
26// This file should not include config.h. It is only included in other
27// C++ source files that should have included config.h before including
28// this file.
29
30#include <ostream>
31#include <sstream>
32
33#include "Array-util.h"
34
35#include "Cell.h"
36#include "errwarn.h"
37#include "ovl.h"
38#include "oct-map.h"
39#include "ov-base.h"
40#include "ov-base-mat.h"
41#include "ov-base-scalar.h"
42#include "pr-output.h"
43
44template <typename MT>
47{
48 switch (type)
49 {
50 case '(':
51 return do_index_op (idx);
52 break;
53
54 case '{':
55 case '.':
56 {
57 std::string nm = type_name ();
58 error ("%s cannot be indexed with %c", nm.c_str (), type);
59 }
60 break;
61
62 default:
63 error ("unexpected: index not '(', '{', or '.' in octave_base_matrix<T>::simple_subsref - please report this bug");
64 }
65}
66
67template <typename MT>
69octave_base_matrix<MT>::subsref (const std::string& type,
70 const std::list<octave_value_list>& idx)
71{
72 octave_value retval;
73
74 switch (type[0])
75 {
76 case '(':
77 retval = do_index_op (idx.front ());
78 break;
79
80 case '{':
81 case '.':
82 {
83 std::string nm = type_name ();
84 error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
85 }
86 break;
87
88 default:
89 error ("unpexpected: index not '(', '{', or '.' in - octave_base_matrix<MT>::subsref please report this bug");
90 }
91
92 return retval.next_subsref (type, idx);
93}
94
95template <typename MT>
97octave_base_matrix<MT>::subsasgn (const std::string& type,
98 const std::list<octave_value_list>& idx,
99 const octave_value& rhs)
100{
101 octave_value retval;
102
103 switch (type[0])
104 {
105 case '(':
107 if (type.length () == 1)
108 retval = numeric_assign (type, idx, rhs);
109 else if (isempty ())
111 // Allow conversion of empty matrix to some other type in
112 // cases like
113 //
114 // x = []; x(i).f = rhs
115
116 if (type[1] != '.')
117 error ("invalid assignment expression");
118
120
121 retval = tmp.subsasgn (type, idx, rhs);
123 else
125 std::string nm = type_name ();
126 error ("in indexed assignment of %s, last lhs index must be ()",
127 nm.c_str ());
128 }
129 }
130 break;
131
132 case '{':
133 case '.':
134 {
135 if (! isempty ())
136 {
137 std::string nm = type_name ();
138 error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
139 }
140
141 octave_value tmp = octave_value::empty_conv (type, rhs);
142
143 retval = tmp.subsasgn (type, idx, rhs);
144 }
145 break;
146
147 default:
148 error ("unpexpected: index not '(', '{', or '.' in - octave_base_matrix<MT>::subsasgn please report this bug");
149 }
150
151 return retval;
152}
153
154template <typename MT>
157 bool resize_ok)
158{
159 octave_value retval;
160
161 octave_idx_type n_idx = idx.length ();
162
163 int nd = m_matrix.ndims ();
164 const MT& cmatrix = m_matrix;
165
166 // If we catch an indexing error in index_vector, we flag an error in
167 // index k. Ensure it is the right value before each idx_vector call.
168 // Same variable as used in the for loop in the default case.
169
170 octave_idx_type k = 0;
171
172 try
173 {
174 switch (n_idx)
175 {
176 case 0:
177 warn_empty_index (type_name ());
178 retval = m_matrix;
179 break;
180
181 case 1:
182 {
183 octave::idx_vector i = idx (0).index_vector ();
184
185 // optimize single scalar index.
186 if (! resize_ok && i.is_scalar ())
187 retval = cmatrix.checkelem (i(0));
188 else
189 retval = MT (m_matrix.index (i, resize_ok));
190 }
191 break;
192
193 case 2:
194 {
195 octave::idx_vector i = idx (0).index_vector ();
196
197 k=1;
198 octave::idx_vector j = idx (1).index_vector ();
200 // optimize two scalar indices.
201 if (! resize_ok && i.is_scalar () && j.is_scalar ())
202 retval = cmatrix.checkelem (i(0), j(0));
203 else
204 retval = MT (m_matrix.index (i, j, resize_ok));
205 }
206 break;
207
208 default:
209 {
210 Array<octave::idx_vector> idx_vec (dim_vector (n_idx, 1));
211 bool scalar_opt = n_idx == nd && ! resize_ok;
212 const dim_vector dv = m_matrix.dims ();
213
214 for (k = 0; k < n_idx; k++)
215 {
216 idx_vec(k) = idx(k).index_vector ();
217
218 scalar_opt = (scalar_opt && idx_vec(k).is_scalar ());
219 }
220
221 if (scalar_opt)
222 retval = cmatrix.checkelem (conv_to_int_array (idx_vec));
223 else
224 retval = MT (m_matrix.index (idx_vec, resize_ok));
225 }
226 break;
227 }
228 }
229 catch (octave::index_exception& ie)
230 {
231 // Rethrow to allow more info to be reported later.
232 ie.set_pos_if_unset (n_idx, k+1);
233 throw;
234 }
235
236 return retval;
237}
238
239/*
240%% This behavior is required for Matlab compatibility.
241%!test
242%! a = [1, 2; 3, 4];
243%! assert (a(), a);
244*/
245
246template <typename MT>
247void
249{
250 octave_idx_type n_idx = idx.length ();
251
252 // If we catch an indexing error in index_vector, we flag an error in
253 // index k. Ensure it is the right value before each idx_vector call.
254 // Same variable as used in the for loop in the default case.
255
256 octave_idx_type k = 0;
257
258 try
259 {
260 switch (n_idx)
261 {
262 case 0:
263 error ("unexpected: zero indices in octave_base_matrix<MT>::assign - please report this bug");
264 break;
265
266 case 1:
267 {
268 octave::idx_vector i = idx (0).index_vector ();
269
270 m_matrix.assign (i, rhs);
271 }
272 break;
273
274 case 2:
275 {
276 octave::idx_vector i = idx (0).index_vector ();
277
278 k = 1;
279 octave::idx_vector j = idx (1).index_vector ();
280
281 m_matrix.assign (i, j, rhs);
282 }
283 break;
284
285 default:
286 {
287 Array<octave::idx_vector> idx_vec (dim_vector (n_idx, 1));
288
289 for (k = 0; k < n_idx; k++)
290 idx_vec(k) = idx(k).index_vector ();
291
292 m_matrix.assign (idx_vec, rhs);
293 }
294 break;
295 }
296 }
297 catch (octave::index_exception& ie)
298 {
299 // Rethrow to allow more info to be reported later.
300 ie.set_pos_if_unset (n_idx, k+1);
301 throw;
302 }
303
304 // Clear cache.
305 clear_cached_info ();
306}
307
308template <typename MT>
311{
312 delete m_typ;
313 m_typ = new MatrixType (typ);
314 return *m_typ;
315}
316
317template <typename MT>
318void
320 typename MT::element_type rhs)
321{
322 octave_idx_type n_idx = idx.length ();
323
324 int nd = m_matrix.ndims ();
325
326 // If we catch an indexing error in index_vector, we flag an error in
327 // index k. Ensure it is the right value before each idx_vector call.
328 // Same variable as used in the for loop in the default case.
329
330 octave_idx_type k = 0;
331
332 try
333 {
334 switch (n_idx)
335 {
336 case 0:
337 error ("unexpected: zero indices in octave_base_matrix<MT>::assign - please report this bug");
338 break;
339
340 case 1:
341 {
342 octave::idx_vector i = idx (0).index_vector ();
343
344 // optimize single scalar index.
345 if (i.is_scalar () && i(0) < m_matrix.numel ())
346 m_matrix(i(0)) = rhs;
347 else
348 {
349 MT mrhs (dim_vector (1, 1), rhs);
350 m_matrix.assign (i, mrhs);
351 }
352 }
353 break;
354
355 case 2:
356 {
357 octave::idx_vector i = idx (0).index_vector ();
358
359 k = 1;
360 octave::idx_vector j = idx (1).index_vector ();
361
362 // optimize two scalar indices.
363 if (i.is_scalar () && j.is_scalar () && nd == 2
364 && i(0) < m_matrix.rows () && j(0) < m_matrix.columns ())
365 m_matrix(i(0), j(0)) = rhs;
366 else
367 {
368 MT mrhs (dim_vector (1, 1), rhs);
369 m_matrix.assign (i, j, mrhs);
370 }
371 }
372 break;
373
374 default:
375 {
376 Array<octave::idx_vector> idx_vec (dim_vector (n_idx, 1));
377 bool scalar_opt = n_idx == nd;
378 const dim_vector dv = m_matrix.dims ().redim (n_idx);
379
380 for (k = 0; k < n_idx; k++)
381 {
382 idx_vec(k) = idx(k).index_vector ();
383
384 scalar_opt = (scalar_opt && idx_vec(k).is_scalar ()
385 && idx_vec(k)(0) < dv(k));
386 }
387
388 if (scalar_opt)
389 {
390 // optimize all scalar indices. Don't construct
391 // an index array, but rather calc a scalar index directly.
392 octave_idx_type n = 1;
393 octave_idx_type j = 0;
394 for (octave_idx_type i = 0; i < n_idx; i++)
395 {
396 j += idx_vec(i)(0) * n;
397 n *= dv (i);
398 }
399 m_matrix(j) = rhs;
400 }
401 else
402 {
403 MT mrhs (dim_vector (1, 1), rhs);
404 m_matrix.assign (idx_vec, mrhs);
405 }
406 }
407 break;
408 }
409 }
410 catch (octave::index_exception& ie)
411 {
412 // Rethrow to allow more info to be reported later.
413 ie.set_pos_if_unset (n_idx, k+1);
414 throw;
415 }
416
417 // Clear cache.
418 clear_cached_info ();
419}
420
421template <typename MT>
422void
424{
425 octave_idx_type len = idx.length ();
426
428
429 for (octave_idx_type i = 0; i < len; i++)
430 ra_idx(i) = idx(i).index_vector ();
431
432 m_matrix.delete_elements (ra_idx);
433
434 // Clear cache.
435 clear_cached_info ();
436}
437
438template <typename MT>
440octave_base_matrix<MT>::resize (const dim_vector& dv, bool fill) const
441{
442 MT retval (m_matrix);
443 if (fill)
444 retval.resize (dv, 0);
445 else
446 retval.resize (dv);
447 return retval;
448}
449
450// Return true if this matrix has all true elements (nonzero, not NA/NaN).
451template <typename MT>
452bool
454{
455 bool retval = false;
456 const dim_vector& dv = m_matrix.dims ();
457 int nel = dv.numel ();
458
459 if (nel > 0)
460 {
461 MT t1 (m_matrix.reshape (dim_vector (nel, 1)));
462
463 if (t1.any_element_is_nan ())
464 octave::err_nan_to_logical_conversion ();
465
466 if (nel > 1)
468
469 boolNDArray t2 = t1.all ();
470
471 retval = t2(0);
472 }
473
474 return retval;
475}
476
477template <typename MT>
478bool
480{
481 const dim_vector& dv = dims ();
482
483 return (dv.all_ones () || dv.any_zero ());
484}
485
486template <typename MT>
487void
488octave_base_matrix<MT>::print (std::ostream& os, bool pr_as_read_syntax)
489{
490 print_raw (os, pr_as_read_syntax);
491 newline (os);
492}
493
494template <typename MT>
495void
497 const std::string& prefix) const
498{
499 m_matrix.print_info (os, prefix);
500}
501
502template <typename MT>
503void
505{
506 if (m_matrix.isempty ())
507 os << "[]";
508 else if (m_matrix.ndims () == 2)
509 {
510 // FIXME: should this be configurable?
511 octave_idx_type max_elts = 10;
512 octave_idx_type elts = 0;
513
514 octave_idx_type nr = m_matrix.rows ();
515 octave_idx_type nc = m_matrix.columns ();
516
517 os << '[';
518
519 for (octave_idx_type i = 0; i < nr; i++)
520 {
521 for (octave_idx_type j = 0; j < nc; j++)
522 {
523 std::ostringstream buf;
524 octave_print_internal (buf, m_matrix(j*nr+i));
525 std::string tmp = buf.str ();
526 std::size_t pos = tmp.find_first_not_of (' ');
527 if (pos != std::string::npos)
528 os << tmp.substr (pos);
529 else if (! tmp.empty ())
530 os << tmp[0];
531 elts++;
532
533 if (j < nc - 1)
534 {
535 os << ", ";
536
537 if (elts >= max_elts)
538 {
539 os << "...";
540 goto done;
541 }
542 }
543 }
544
545 if (i < nr - 1)
546 {
547 os << "; ";
548
549 if (elts >= max_elts)
550 {
551 os << "...";
552 goto done;
553 }
554 }
555 }
556
557 done:
558 os << ']';
559 }
560 else
562}
563
564template <typename MT>
567{
568 return make_format (m_matrix);
569}
570
571template <typename MT>
572std::string
575 octave_idx_type j) const
576{
577 std::ostringstream buf;
578 octave_print_internal (buf, fmt, m_matrix(i, j));
579 return buf.str ();
580}
581
582template <typename MT>
585{
586 if (n < m_matrix.numel ())
587 return m_matrix(n);
588 else
589 return octave_value ();
590}
591
592template <typename MT>
593bool
595 const octave_value& x)
596{
597 if (n < m_matrix.numel ())
598 {
599 // Don't use builtin_type () here to avoid an extra VM call.
600 typedef typename MT::element_type ET;
602 if (btyp == btyp_unknown) // Dead branch?
603 return false;
604
605 // Set up the pointer to the proper place.
606 void *here = reinterpret_cast<void *> (&m_matrix(n));
607 // Ask x to store there if it can.
608 return x.get_rep ().fast_elem_insert_self (here, btyp);
609 }
610 else
611 return false;
612}
Array< octave_idx_type > conv_to_int_array(const Array< octave::idx_vector > &a)
N Dimensional Array with copy-on-write semantics.
Definition Array.h:130
boolNDArray all(int dim=-1) const
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:90
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition dim-vector.h:331
bool any_zero() const
Definition dim-vector.h:312
dim_vector redim(int n) const
Force certain dimensionality, preserving numel ().
bool all_ones() const
Definition dim-vector.h:320
bool print_as_scalar() const
bool fast_elem_insert(octave_idx_type n, const octave_value &x)
octave_value resize(const dim_vector &dv, bool fill=false) const
octave_value subsref(const std::string &type, const std::list< octave_value_list > &idx)
bool is_true() const
octave_value do_index_op(const octave_value_list &idx, bool resize_ok=false)
float_display_format get_edit_display_format() const
void delete_elements(const octave_value_list &idx)
octave_value fast_elem_extract(octave_idx_type n) const
void print_info(std::ostream &os, const std::string &prefix) const
octave_value_list simple_subsref(char type, octave_value_list &idx, int nargout)
void print(std::ostream &os, bool pr_as_read_syntax=false)
void short_disp(std::ostream &os) const
MatrixType matrix_type() const
void assign(const octave_value_list &idx, const MT &rhs)
octave_value subsasgn(const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
std::string edit_display(const float_display_format &fmt, octave_idx_type i, octave_idx_type j) const
virtual void short_disp(std::ostream &os) const
Definition ov-base.h:761
octave_idx_type length() const
Definition ovl.h:111
static octave_value empty_conv(const std::string &type, const octave_value &rhs=octave_value())
octave_value next_subsref(const std::string &type, const std::list< octave_value_list > &idx, std::size_t skip=1)
octave_value subsasgn(const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
void error(const char *fmt,...)
Definition error.cc:1003
void warn_empty_index(const std::string &type_name)
Definition errwarn.cc:336
void warn_array_as_logical(const dim_vector &dv)
Definition errwarn.cc:286
F77_RET_T const F77_DBLE * x
const octave_base_value const Array< octave_idx_type > & ra_idx
builtin_type_t
Definition ov-base.h:83
@ btyp_unknown
Definition ov-base.h:101
void octave_print_internal(std::ostream &os, const float_display_format &fmt, bool d, bool pr_as_read_syntax)
float_display_format make_format(const double &d)
Definition pr-output.cc:525
F77_RET_T len
Definition xerbla.cc:61