GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
ov-base-mat.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1996-2024 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 
44 template <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:
64  }
65 }
66 
67 template <typename MT>
69 octave_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:
90  }
91 
92  return retval.next_subsref (type, idx);
93 }
94 
95 template <typename MT>
97 octave_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 '(':
106  {
107  if (type.length () == 1)
108  retval = numeric_assign (type, idx, rhs);
109  else if (isempty ())
110  {
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 
119  octave_value tmp = octave_value::empty_conv (type, rhs);
120 
121  retval = tmp.subsasgn (type, idx, rhs);
122  }
123  else
124  {
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  panic_impossible ();
149  }
150 
151  return retval;
152 }
153 
154 template <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 ();
199 
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 
246 template <typename MT>
247 void
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  panic_impossible ();
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 
308 template <typename MT>
311 {
312  delete m_typ;
313  m_typ = new MatrixType (typ);
314  return *m_typ;
315 }
316 
317 template <typename MT>
318 void
320  typename MT::element_type rhs)
321 {
322  octave_idx_type n_idx = idx.length ();
323 
324  int nd = m_matrix.ndims ();
325 
326  MT mrhs (dim_vector (1, 1), rhs);
327 
328  // If we catch an indexing error in index_vector, we flag an error in
329  // index k. Ensure it is the right value before each idx_vector call.
330  // Same variable as used in the for loop in the default case.
331 
332  octave_idx_type k = 0;
333 
334  try
335  {
336  switch (n_idx)
337  {
338  case 0:
339  panic_impossible ();
340  break;
341 
342  case 1:
343  {
344  octave::idx_vector i = idx (0).index_vector ();
345 
346  // optimize single scalar index.
347  if (i.is_scalar () && i(0) < m_matrix.numel ())
348  m_matrix(i(0)) = rhs;
349  else
350  m_matrix.assign (i, mrhs);
351  }
352  break;
353 
354  case 2:
355  {
356  octave::idx_vector i = idx (0).index_vector ();
357 
358  k = 1;
359  octave::idx_vector j = idx (1).index_vector ();
360 
361  // optimize two scalar indices.
362  if (i.is_scalar () && j.is_scalar () && nd == 2
363  && i(0) < m_matrix.rows () && j(0) < m_matrix.columns ())
364  m_matrix(i(0), j(0)) = rhs;
365  else
366  m_matrix.assign (i, j, mrhs);
367  }
368  break;
369 
370  default:
371  {
372  Array<octave::idx_vector> idx_vec (dim_vector (n_idx, 1));
373  bool scalar_opt = n_idx == nd;
374  const dim_vector dv = m_matrix.dims ().redim (n_idx);
375 
376  for (k = 0; k < n_idx; k++)
377  {
378  idx_vec(k) = idx(k).index_vector ();
379 
380  scalar_opt = (scalar_opt && idx_vec(k).is_scalar ()
381  && idx_vec(k)(0) < dv(k));
382  }
383 
384  if (scalar_opt)
385  {
386  // optimize all scalar indices. Don't construct
387  // an index array, but rather calc a scalar index directly.
388  octave_idx_type n = 1;
389  octave_idx_type j = 0;
390  for (octave_idx_type i = 0; i < n_idx; i++)
391  {
392  j += idx_vec(i)(0) * n;
393  n *= dv (i);
394  }
395  m_matrix(j) = rhs;
396  }
397  else
398  m_matrix.assign (idx_vec, mrhs);
399  }
400  break;
401  }
402  }
403  catch (octave::index_exception& ie)
404  {
405  // Rethrow to allow more info to be reported later.
406  ie.set_pos_if_unset (n_idx, k+1);
407  throw;
408  }
409 
410  // Clear cache.
411  clear_cached_info ();
412 }
413 
414 template <typename MT>
415 void
417 {
418  octave_idx_type len = idx.length ();
419 
421 
422  for (octave_idx_type i = 0; i < len; i++)
423  ra_idx(i) = idx(i).index_vector ();
424 
425  m_matrix.delete_elements (ra_idx);
426 
427  // Clear cache.
428  clear_cached_info ();
429 }
430 
431 template <typename MT>
433 octave_base_matrix<MT>::resize (const dim_vector& dv, bool fill) const
434 {
435  MT retval (m_matrix);
436  if (fill)
437  retval.resize (dv, 0);
438  else
439  retval.resize (dv);
440  return retval;
441 }
442 
443 // Return true if this matrix has all true elements (nonzero, not NA/NaN).
444 template <typename MT>
445 bool
447 {
448  bool retval = false;
449  dim_vector dv = m_matrix.dims ();
450  int nel = dv.numel ();
451 
452  if (nel > 0)
453  {
454  MT t1 (m_matrix.reshape (dim_vector (nel, 1)));
455 
456  if (t1.any_element_is_nan ())
458 
459  if (nel > 1)
461 
462  boolNDArray t2 = t1.all ();
463 
464  retval = t2(0);
465  }
466 
467  return retval;
468 }
469 
470 template <typename MT>
471 bool
473 {
474  dim_vector dv = dims ();
475 
476  return (dv.all_ones () || dv.any_zero ());
477 }
478 
479 template <typename MT>
480 void
481 octave_base_matrix<MT>::print (std::ostream& os, bool pr_as_read_syntax)
482 {
483  print_raw (os, pr_as_read_syntax);
484  newline (os);
485 }
486 
487 template <typename MT>
488 void
490  const std::string& prefix) const
491 {
492  m_matrix.print_info (os, prefix);
493 }
494 
495 template <typename MT>
496 void
497 octave_base_matrix<MT>::short_disp (std::ostream& os) const
498 {
499  if (m_matrix.isempty ())
500  os << "[]";
501  else if (m_matrix.ndims () == 2)
502  {
503  // FIXME: should this be configurable?
504  octave_idx_type max_elts = 10;
505  octave_idx_type elts = 0;
506 
507  octave_idx_type nel = m_matrix.numel ();
508 
509  octave_idx_type nr = m_matrix.rows ();
510  octave_idx_type nc = m_matrix.columns ();
511 
512  os << '[';
513 
514  for (octave_idx_type i = 0; i < nr; i++)
515  {
516  for (octave_idx_type j = 0; j < nc; j++)
517  {
518  std::ostringstream buf;
519  octave_print_internal (buf, m_matrix(j*nr+i));
520  std::string tmp = buf.str ();
521  std::size_t pos = tmp.find_first_not_of (' ');
522  if (pos != std::string::npos)
523  os << tmp.substr (pos);
524  else if (! tmp.empty ())
525  os << tmp[0];
526 
527  if (++elts >= max_elts)
528  goto done;
529 
530  if (j < nc - 1)
531  os << ", ";
532  }
533 
534  if (i < nr - 1 && elts < max_elts)
535  os << "; ";
536  }
537 
538  done:
539 
540  if (nel <= max_elts)
541  os << ']';
542  }
543  else
544  os << "...";
545 }
546 
547 template <typename MT>
550 {
551  return make_format (m_matrix);
552 }
553 
554 template <typename MT>
555 std::string
557  octave_idx_type i,
558  octave_idx_type j) const
559 {
560  std::ostringstream buf;
561  octave_print_internal (buf, fmt, m_matrix(i, j));
562  return buf.str ();
563 }
564 
565 template <typename MT>
568 {
569  if (n < m_matrix.numel ())
570  return m_matrix(n);
571  else
572  return octave_value ();
573 }
574 
575 template <typename MT>
576 bool
578  const octave_value& x)
579 {
580  if (n < m_matrix.numel ())
581  {
582  // Don't use builtin_type () here to avoid an extra VM call.
583  typedef typename MT::element_type ET;
585  if (btyp == btyp_unknown) // Dead branch?
586  return false;
587 
588  // Set up the pointer to the proper place.
589  void *here = reinterpret_cast<void *> (&m_matrix(n));
590  // Ask x to store there if it can.
591  return x.get_rep ().fast_elem_insert_self (here, btyp);
592  }
593  else
594  return false;
595 }
Array< octave_idx_type > conv_to_int_array(const Array< octave::idx_vector > &a)
Definition: Array-util.cc:239
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:130
boolNDArray all(int dim=-1) const
Definition: boolNDArray.cc:61
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition: dim-vector.h:335
bool any_zero() const
Definition: dim-vector.h:316
dim_vector redim(int n) const
Force certain dimensionality, preserving numel ().
Definition: dim-vector.cc:226
bool all_ones() const
Definition: dim-vector.h:324
bool print_as_scalar() const
Definition: ov-base-mat.cc:472
virtual octave_value subsref(const std::string &type, const std::list< octave_value_list > &idx)
Definition: ov-base.cc:248
bool fast_elem_insert(octave_idx_type n, const octave_value &x)
Definition: ov-base-mat.cc:577
octave_value resize(const dim_vector &dv, bool fill=false) const
Definition: ov-base-mat.cc:433
bool is_true() const
Definition: ov-base-mat.cc:446
octave_value do_index_op(const octave_value_list &idx, bool resize_ok=false)
Definition: ov-base-mat.cc:156
float_display_format get_edit_display_format() const
Definition: ov-base-mat.cc:549
virtual void assign(const std::string &, const octave_value &)
Definition: ov-base.h:354
void delete_elements(const octave_value_list &idx)
Definition: ov-base-mat.cc:416
octave_value fast_elem_extract(octave_idx_type n) const
Definition: ov-base-mat.cc:567
void print_info(std::ostream &os, const std::string &prefix) const
Definition: ov-base-mat.cc:489
octave_value_list simple_subsref(char type, octave_value_list &idx, int nargout)
Definition: ov-base-mat.cc:46
void print(std::ostream &os, bool pr_as_read_syntax=false)
Definition: ov-base-mat.cc:481
void short_disp(std::ostream &os) const
Definition: ov-base-mat.cc:497
MatrixType matrix_type() const
Definition: ov-base-mat.h:139
octave_value subsasgn(const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
Definition: ov-base-mat.cc:97
std::string edit_display(const float_display_format &fmt, octave_idx_type i, octave_idx_type j) const
Definition: ov-base-mat.cc:556
octave_idx_type length() const
Definition: ovl.h:113
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:988
#define panic_impossible()
Definition: error.h:503
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
octave::idx_vector idx_vector
Definition: idx-vector.h:1022
void err_nan_to_logical_conversion()
F77_RET_T const F77_DBLE * x
octave_idx_type n
Definition: mx-inlines.cc:761
const octave_base_value const Array< octave_idx_type > & ra_idx
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
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)
Definition: pr-output.cc:1761
float_display_format make_format(const double &d)
Definition: pr-output.cc:525
F77_RET_T len
Definition: xerbla.cc:61