GNU Octave  8.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-2023 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>
46 octave_base_matrix<MT>::subsref (const std::string& type,
47  const std::list<octave_value_list>& idx)
48 {
49  octave_value retval;
50 
51  switch (type[0])
52  {
53  case '(':
54  retval = do_index_op (idx.front ());
55  break;
56 
57  case '{':
58  case '.':
59  {
60  std::string nm = type_name ();
61  error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
62  }
63  break;
64 
65  default:
67  }
68 
69  return retval.next_subsref (type, idx);
70 }
71 
72 template <typename MT>
74 octave_base_matrix<MT>::subsasgn (const std::string& type,
75  const std::list<octave_value_list>& idx,
76  const octave_value& rhs)
77 {
78  octave_value retval;
79 
80  switch (type[0])
81  {
82  case '(':
83  {
84  if (type.length () == 1)
85  retval = numeric_assign (type, idx, rhs);
86  else if (isempty ())
87  {
88  // Allow conversion of empty matrix to some other type in
89  // cases like
90  //
91  // x = []; x(i).f = rhs
92 
93  if (type[1] != '.')
94  error ("invalid assignment expression");
95 
96  octave_value tmp = octave_value::empty_conv (type, rhs);
97 
98  retval = tmp.subsasgn (type, idx, rhs);
99  }
100  else
101  {
102  std::string nm = type_name ();
103  error ("in indexed assignment of %s, last lhs index must be ()",
104  nm.c_str ());
105  }
106  }
107  break;
108 
109  case '{':
110  case '.':
111  {
112  if (! isempty ())
113  {
114  std::string nm = type_name ();
115  error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
116  }
117 
118  octave_value tmp = octave_value::empty_conv (type, rhs);
119 
120  retval = tmp.subsasgn (type, idx, rhs);
121  }
122  break;
123 
124  default:
125  panic_impossible ();
126  }
127 
128  return retval;
129 }
130 
131 template <typename MT>
134  bool resize_ok)
135 {
136  octave_value retval;
137 
138  octave_idx_type n_idx = idx.length ();
139 
140  int nd = m_matrix.ndims ();
141  const MT& cmatrix = m_matrix;
142 
143  // If we catch an indexing error in index_vector, we flag an error in
144  // index k. Ensure it is the right value before each idx_vector call.
145  // Same variable as used in the for loop in the default case.
146 
147  octave_idx_type k = 0;
148 
149  try
150  {
151  switch (n_idx)
152  {
153  case 0:
154  warn_empty_index (type_name ());
155  retval = m_matrix;
156  break;
157 
158  case 1:
159  {
160  octave::idx_vector i = idx (0).index_vector ();
161 
162  // optimize single scalar index.
163  if (! resize_ok && i.is_scalar ())
164  retval = cmatrix.checkelem (i(0));
165  else
166  retval = MT (m_matrix.index (i, resize_ok));
167  }
168  break;
169 
170  case 2:
171  {
172  octave::idx_vector i = idx (0).index_vector ();
173 
174  k=1;
175  octave::idx_vector j = idx (1).index_vector ();
176 
177  // optimize two scalar indices.
178  if (! resize_ok && i.is_scalar () && j.is_scalar ())
179  retval = cmatrix.checkelem (i(0), j(0));
180  else
181  retval = MT (m_matrix.index (i, j, resize_ok));
182  }
183  break;
184 
185  default:
186  {
187  Array<octave::idx_vector> idx_vec (dim_vector (n_idx, 1));
188  bool scalar_opt = n_idx == nd && ! resize_ok;
189  const dim_vector dv = m_matrix.dims ();
190 
191  for (k = 0; k < n_idx; k++)
192  {
193  idx_vec(k) = idx(k).index_vector ();
194 
195  scalar_opt = (scalar_opt && idx_vec(k).is_scalar ());
196  }
197 
198  if (scalar_opt)
199  retval = cmatrix.checkelem (conv_to_int_array (idx_vec));
200  else
201  retval = MT (m_matrix.index (idx_vec, resize_ok));
202  }
203  break;
204  }
205  }
206  catch (octave::index_exception& ie)
207  {
208  // Rethrow to allow more info to be reported later.
209  ie.set_pos_if_unset (n_idx, k+1);
210  throw;
211  }
212 
213  return retval;
214 }
215 
216 /*
217 %% This behavior is required for Matlab compatibility.
218 %!test
219 %! a = [1, 2; 3, 4];
220 %! assert (a(), a);
221 */
222 
223 template <typename MT>
224 void
226 {
227  octave_idx_type n_idx = idx.length ();
228 
229  // If we catch an indexing error in index_vector, we flag an error in
230  // index k. Ensure it is the right value before each idx_vector call.
231  // Same variable as used in the for loop in the default case.
232 
233  octave_idx_type k = 0;
234 
235  try
236  {
237  switch (n_idx)
238  {
239  case 0:
240  panic_impossible ();
241  break;
242 
243  case 1:
244  {
245  octave::idx_vector i = idx (0).index_vector ();
246 
247  m_matrix.assign (i, rhs);
248  }
249  break;
250 
251  case 2:
252  {
253  octave::idx_vector i = idx (0).index_vector ();
254 
255  k = 1;
256  octave::idx_vector j = idx (1).index_vector ();
257 
258  m_matrix.assign (i, j, rhs);
259  }
260  break;
261 
262  default:
263  {
264  Array<octave::idx_vector> idx_vec (dim_vector (n_idx, 1));
265 
266  for (k = 0; k < n_idx; k++)
267  idx_vec(k) = idx(k).index_vector ();
268 
269  m_matrix.assign (idx_vec, rhs);
270  }
271  break;
272  }
273  }
274  catch (octave::index_exception& ie)
275  {
276  // Rethrow to allow more info to be reported later.
277  ie.set_pos_if_unset (n_idx, k+1);
278  throw;
279  }
280 
281  // Clear cache.
282  clear_cached_info ();
283 }
284 
285 template <typename MT>
288 {
289  delete m_typ;
290  m_typ = new MatrixType (typ);
291  return *m_typ;
292 }
293 
294 template <typename MT>
295 void
297  typename MT::element_type rhs)
298 {
299  octave_idx_type n_idx = idx.length ();
300 
301  int nd = m_matrix.ndims ();
302 
303  MT mrhs (dim_vector (1, 1), rhs);
304 
305  // If we catch an indexing error in index_vector, we flag an error in
306  // index k. Ensure it is the right value before each idx_vector call.
307  // Same variable as used in the for loop in the default case.
308 
309  octave_idx_type k = 0;
310 
311  try
312  {
313  switch (n_idx)
314  {
315  case 0:
316  panic_impossible ();
317  break;
318 
319  case 1:
320  {
321  octave::idx_vector i = idx (0).index_vector ();
322 
323  // optimize single scalar index.
324  if (i.is_scalar () && i(0) < m_matrix.numel ())
325  m_matrix(i(0)) = rhs;
326  else
327  m_matrix.assign (i, mrhs);
328  }
329  break;
330 
331  case 2:
332  {
333  octave::idx_vector i = idx (0).index_vector ();
334 
335  k = 1;
336  octave::idx_vector j = idx (1).index_vector ();
337 
338  // optimize two scalar indices.
339  if (i.is_scalar () && j.is_scalar () && nd == 2
340  && i(0) < m_matrix.rows () && j(0) < m_matrix.columns ())
341  m_matrix(i(0), j(0)) = rhs;
342  else
343  m_matrix.assign (i, j, mrhs);
344  }
345  break;
346 
347  default:
348  {
349  Array<octave::idx_vector> idx_vec (dim_vector (n_idx, 1));
350  bool scalar_opt = n_idx == nd;
351  const dim_vector dv = m_matrix.dims ().redim (n_idx);
352 
353  for (k = 0; k < n_idx; k++)
354  {
355  idx_vec(k) = idx(k).index_vector ();
356 
357  scalar_opt = (scalar_opt && idx_vec(k).is_scalar ()
358  && idx_vec(k)(0) < dv(k));
359  }
360 
361  if (scalar_opt)
362  {
363  // optimize all scalar indices. Don't construct
364  // an index array, but rather calc a scalar index directly.
365  octave_idx_type n = 1;
366  octave_idx_type j = 0;
367  for (octave_idx_type i = 0; i < n_idx; i++)
368  {
369  j += idx_vec(i)(0) * n;
370  n *= dv (i);
371  }
372  m_matrix(j) = rhs;
373  }
374  else
375  m_matrix.assign (idx_vec, mrhs);
376  }
377  break;
378  }
379  }
380  catch (octave::index_exception& ie)
381  {
382  // Rethrow to allow more info to be reported later.
383  ie.set_pos_if_unset (n_idx, k+1);
384  throw;
385  }
386 
387  // Clear cache.
388  clear_cached_info ();
389 }
390 
391 template <typename MT>
392 void
394 {
395  octave_idx_type len = idx.length ();
396 
398 
399  for (octave_idx_type i = 0; i < len; i++)
400  ra_idx(i) = idx(i).index_vector ();
401 
402  m_matrix.delete_elements (ra_idx);
403 
404  // Clear cache.
405  clear_cached_info ();
406 }
407 
408 template <typename MT>
410 octave_base_matrix<MT>::resize (const dim_vector& dv, bool fill) const
411 {
412  MT retval (m_matrix);
413  if (fill)
414  retval.resize (dv, 0);
415  else
416  retval.resize (dv);
417  return retval;
418 }
419 
420 // Return true if this matrix has all true elements (non-zero, not NA/NaN).
421 template <typename MT>
422 bool
424 {
425  bool retval = false;
426  dim_vector dv = m_matrix.dims ();
427  int nel = dv.numel ();
428 
429  if (nel > 0)
430  {
431  MT t1 (m_matrix.reshape (dim_vector (nel, 1)));
432 
433  if (t1.any_element_is_nan ())
435 
436  if (nel > 1)
438 
439  boolNDArray t2 = t1.all ();
440 
441  retval = t2(0);
442  }
443 
444  return retval;
445 }
446 
447 template <typename MT>
448 bool
450 {
451  dim_vector dv = dims ();
452 
453  return (dv.all_ones () || dv.any_zero ());
454 }
455 
456 template <typename MT>
457 void
458 octave_base_matrix<MT>::print (std::ostream& os, bool pr_as_read_syntax)
459 {
460  print_raw (os, pr_as_read_syntax);
461  newline (os);
462 }
463 
464 template <typename MT>
465 void
467  const std::string& prefix) const
468 {
469  m_matrix.print_info (os, prefix);
470 }
471 
472 template <typename MT>
473 void
474 octave_base_matrix<MT>::short_disp (std::ostream& os) const
475 {
476  if (m_matrix.isempty ())
477  os << "[]";
478  else if (m_matrix.ndims () == 2)
479  {
480  // FIXME: should this be configurable?
481  octave_idx_type max_elts = 10;
482  octave_idx_type elts = 0;
483 
484  octave_idx_type nel = m_matrix.numel ();
485 
486  octave_idx_type nr = m_matrix.rows ();
487  octave_idx_type nc = m_matrix.columns ();
488 
489  os << '[';
490 
491  for (octave_idx_type i = 0; i < nr; i++)
492  {
493  for (octave_idx_type j = 0; j < nc; j++)
494  {
495  std::ostringstream buf;
496  octave_print_internal (buf, m_matrix(j*nr+i));
497  std::string tmp = buf.str ();
498  std::size_t pos = tmp.find_first_not_of (' ');
499  if (pos != std::string::npos)
500  os << tmp.substr (pos);
501  else if (! tmp.empty ())
502  os << tmp[0];
503 
504  if (++elts >= max_elts)
505  goto done;
506 
507  if (j < nc - 1)
508  os << ", ";
509  }
510 
511  if (i < nr - 1 && elts < max_elts)
512  os << "; ";
513  }
514 
515  done:
516 
517  if (nel <= max_elts)
518  os << ']';
519  }
520  else
521  os << "...";
522 }
523 
524 template <typename MT>
527 {
528  return make_format (m_matrix);
529 }
530 
531 template <typename MT>
532 std::string
534  octave_idx_type i,
535  octave_idx_type j) const
536 {
537  std::ostringstream buf;
538  octave_print_internal (buf, fmt, m_matrix(i, j));
539  return buf.str ();
540 }
541 
542 template <typename MT>
545 {
546  if (n < m_matrix.numel ())
547  return m_matrix(n);
548  else
549  return octave_value ();
550 }
551 
552 template <typename MT>
553 bool
555  const octave_value& x)
556 {
557  if (n < m_matrix.numel ())
558  {
559  // Don't use builtin_type () here to avoid an extra VM call.
560  typedef typename MT::element_type ET;
562  if (btyp == btyp_unknown) // Dead branch?
563  return false;
564 
565  // Set up the pointer to the proper place.
566  void *here = reinterpret_cast<void *> (&m_matrix(n));
567  // Ask x to store there if it can.
568  return x.get_rep ().fast_elem_insert_self (here, btyp);
569  }
570  else
571  return false;
572 }
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
OCTAVE_API 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 all_ones(void) const
Definition: dim-vector.h:324
OCTAVE_API dim_vector redim(int n) const
Force certain dimensionality, preserving numel ().
Definition: dim-vector.cc:226
bool any_zero(void) const
Definition: dim-vector.h:316
virtual octave_value subsref(const std::string &type, const std::list< octave_value_list > &idx)
Definition: ov-base.cc:200
MatrixType matrix_type(void) const
Definition: ov-base-mat.h:136
OCTINTERP_API bool fast_elem_insert(octave_idx_type n, const octave_value &x)
Definition: ov-base-mat.cc:554
octave_value resize(const dim_vector &dv, bool fill=false) const
Definition: ov-base-mat.cc:410
OCTINTERP_API octave_value do_index_op(const octave_value_list &idx, bool resize_ok=false)
Definition: ov-base-mat.cc:133
virtual void assign(const std::string &, const octave_value &)
Definition: ov-base.h:340
OCTINTERP_API void delete_elements(const octave_value_list &idx)
Definition: ov-base-mat.cc:393
OCTINTERP_API octave_value fast_elem_extract(octave_idx_type n) const
Definition: ov-base-mat.cc:544
OCTINTERP_API void print_info(std::ostream &os, const std::string &prefix) const
Definition: ov-base-mat.cc:466
OCTINTERP_API bool print_as_scalar(void) const
Definition: ov-base-mat.cc:449
OCTINTERP_API void print(std::ostream &os, bool pr_as_read_syntax=false)
Definition: ov-base-mat.cc:458
OCTINTERP_API float_display_format get_edit_display_format(void) const
Definition: ov-base-mat.cc:526
OCTINTERP_API void short_disp(std::ostream &os) const
Definition: ov-base-mat.cc:474
OCTINTERP_API bool is_true(void) const
Definition: ov-base-mat.cc:423
OCTINTERP_API octave_value subsasgn(const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
Definition: ov-base-mat.cc:74
OCTINTERP_API std::string edit_display(const float_display_format &fmt, octave_idx_type i, octave_idx_type j) const
Definition: ov-base-mat.cc:533
octave_idx_type length(void) const
Definition: ovl.h:113
static OCTINTERP_API octave_value empty_conv(const std::string &type, const octave_value &rhs=octave_value())
OCTINTERP_API octave_value next_subsref(const std::string &type, const std::list< octave_value_list > &idx, std::size_t skip=1)
OCTINTERP_API 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:979
#define panic_impossible()
Definition: error.h:508
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:1039
void err_nan_to_logical_conversion(void)
F77_RET_T const F77_DBLE * x
octave_idx_type n
Definition: mx-inlines.cc:753
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:1762
float_display_format make_format(const double &d)
Definition: pr-output.cc:525
F77_RET_T len
Definition: xerbla.cc:61