GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
ov-base-diag.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2008-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 <istream>
31 #include <ostream>
32 #include <sstream>
33 
34 #include "mach-info.h"
35 #include "lo-ieee.h"
36 
37 #include "ov-base-diag.h"
38 #include "mxarray.h"
39 #include "ov-base.h"
40 #include "ov-base-mat.h"
41 #include "pr-output.h"
42 #include "error.h"
43 #include "errwarn.h"
44 #include "oct-stream.h"
45 #include "ops.h"
46 
47 #include "ls-oct-text.h"
48 
49 template <typename DMT, typename MT>
51 octave_base_diag<DMT, MT>::subsref (const std::string& type,
52  const std::list<octave_value_list>& idx)
53 {
54  octave_value retval;
55 
56  switch (type[0])
57  {
58  case '(':
59  retval = do_index_op (idx.front ());
60  break;
61 
62  case '{':
63  case '.':
64  {
65  std::string nm = type_name ();
66  error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
67  }
68  break;
69 
70  default:
72  }
73 
74  return retval.next_subsref (type, idx);
75 }
76 
77 template <typename DMT, typename MT>
80 {
81  octave_value retval;
82  if (m_matrix.rows () == 1 || m_matrix.cols () == 1)
83  {
84  // Rather odd special case. This is a row or column vector
85  // represented as a diagonal matrix with a single nonzero entry, but
86  // Fdiag semantics are to product a diagonal matrix for vector
87  // inputs.
88  if (k == 0)
89  // Returns Diag2Array<T> with nnz <= 1.
90  retval = m_matrix.build_diag_matrix ();
91  else
92  // Returns Array<T> matrix
93  retval = m_matrix.array_value ().diag (k);
94  }
95  else
96  // Returns Array<T> vector
97  retval = m_matrix.extract_diag (k);
98  return retval;
99 }
100 
101 template <typename DMT, typename MT>
104  bool resize_ok)
105 {
106  octave_value retval;
107 
108  if (idx.length () == 2 && ! resize_ok)
109  {
110  int k = 0; // index we're accessing when index_vector throws
111  try
112  {
113  octave::idx_vector idx0 = idx(0).index_vector ();
114  k = 1;
115  octave::idx_vector idx1 = idx(1).index_vector ();
116 
117  if (idx0.is_scalar () && idx1.is_scalar ())
118  {
119  retval = m_matrix.checkelem (idx0(0), idx1(0));
120  }
121  else
122  {
123  octave_idx_type m = idx0.length (m_matrix.rows ());
124  octave_idx_type n = idx1.length (m_matrix.columns ());
125  if (idx0.is_colon_equiv (m) && idx1.is_colon_equiv (n)
126  && m <= m_matrix.rows () && n <= m_matrix.rows ())
127  {
128  DMT rm (m_matrix);
129  rm.resize (m, n);
130  retval = rm;
131  }
132  else
133  retval = to_dense ().index_op (idx, resize_ok);
134  }
135  }
136  catch (octave::index_exception& ie)
137  {
138  // Rethrow to allow more info to be reported later.
139  ie.set_pos_if_unset (2, k+1);
140  throw;
141  }
142  }
143  else
144  retval = to_dense ().index_op (idx, resize_ok);
145 
146  return retval;
147 }
148 
149 template <typename DMT, typename MT>
151 octave_base_diag<DMT, MT>::subsasgn (const std::string& type,
152  const std::list<octave_value_list>& idx,
153  const octave_value& rhs)
154 {
155  octave_value retval;
156 
157  switch (type[0])
158  {
159  case '(':
160  {
161  if (type.length () != 1)
162  {
163  std::string nm = type_name ();
164  error ("in indexed assignment of %s, last lhs index must be ()",
165  nm.c_str ());
166  }
167 
168  octave_value_list jdx = idx.front ();
169 
170  // FIXME: Mostly repeated code for cases 1 and 2 could be
171  // consolidated for DRY (Don't Repeat Yourself).
172  // Check for assignments to diagonal elements which should not
173  // destroy the diagonal property of the matrix.
174  // If D is a diagonal matrix then the assignment can be
175  // 1) linear, D(i) = x, where ind2sub results in case #2 below
176  // 2) subscript D(i,i) = x, where both indices are equal.
177  if (jdx.length () == 1 && jdx(0).is_scalar_type ())
178  {
179  typename DMT::element_type val;
180  int k = 0;
181  try
182  {
183  octave::idx_vector ind = jdx(0).index_vector ();
184  k = 1;
185  dim_vector dv (m_matrix.rows (), m_matrix.cols ());
186  Array<octave::idx_vector> ivec = ind2sub (dv, ind);
187  octave::idx_vector i0 = ivec(0);
188  octave::idx_vector i1 = ivec(1);
189 
190  if (i0(0) == i1(0)
191  && chk_valid_scalar (rhs, val))
192  {
193  m_matrix.dgelem (i0(0)) = val;
194  retval = this;
195  this->m_count++;
196  // invalidate cache
197  m_dense_cache = octave_value ();
198  }
199  }
200  catch (octave::index_exception& ie)
201  {
202  // Rethrow to allow more info to be reported later.
203  ie.set_pos_if_unset (2, k+1);
204  throw;
205  }
206  }
207  else if (jdx.length () == 2
208  && jdx(0).is_scalar_type () && jdx(1).is_scalar_type ())
209  {
210  typename DMT::element_type val;
211  int k = 0;
212  try
213  {
214  octave::idx_vector i0 = jdx(0).index_vector ();
215  k = 1;
216  octave::idx_vector i1 = jdx(1).index_vector ();
217  if (i0(0) == i1(0)
218  && i0(0) < m_matrix.rows () && i1(0) < m_matrix.cols ()
219  && chk_valid_scalar (rhs, val))
220  {
221  m_matrix.dgelem (i0(0)) = val;
222  retval = this;
223  this->m_count++;
224  // invalidate cache
225  m_dense_cache = octave_value ();
226  }
227  }
228  catch (octave::index_exception& ie)
229  {
230  // Rethrow to allow more info to be reported later.
231  ie.set_pos_if_unset (2, k+1);
232  throw;
233  }
234  }
235 
236  if (! retval.is_defined ())
237  retval = numeric_assign (type, idx, rhs);
238  }
239  break;
240 
241  case '{':
242  case '.':
243  {
244  if (! isempty ())
245  {
246  std::string nm = type_name ();
247  error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
248  }
249 
250  octave_value tmp = octave_value::empty_conv (type, rhs);
251 
252  retval = tmp.subsasgn (type, idx, rhs);
253  }
254  break;
255 
256  default:
257  panic_impossible ();
258  }
259 
260  return retval;
261 }
262 
263 template <typename DMT, typename MT>
265 octave_base_diag<DMT, MT>::resize (const dim_vector& dv, bool fill) const
266 {
267  octave_value retval;
268  if (dv.ndims () == 2)
269  {
270  DMT rm (m_matrix);
271  rm.resize (dv(0), dv(1));
272  retval = rm;
273  }
274  else
275  retval = to_dense ().resize (dv, fill);
276  return retval;
277 }
278 
279 // Return true if this matrix has all true elements (nonzero, not NA/NaN).
280 template <typename DMT, typename MT>
281 bool
283 {
284  if (dims ().numel () > 1)
285  {
286  warn_array_as_logical (dims ());
287  // Throw error if any NaN or NA by calling is_true().
288  octave_value (m_matrix.extract_diag ()).is_true ();
289  return false; // > 1x1 diagonal always has zeros
290  }
291  else
292  return to_dense ().is_true (); // 0x0 or 1x1, handle NaN etc.
293 }
294 
295 // FIXME: This should be achieveable using ::real
296 template <typename T> inline T helper_getreal (T x) { return x; }
297 template <typename T> inline T helper_getreal (std::complex<T> x)
298 { return x.real (); }
299 // FIXME: We really need some traits so that ad hoc hooks like this
300 // are not necessary.
301 template <typename T> inline T helper_iscomplex (T) { return false; }
302 template <typename T> inline T helper_iscomplex (std::complex<T>)
303 { return true; }
304 
305 template <typename DMT, typename MT>
306 double
307 octave_base_diag<DMT, MT>::double_value (bool force_conversion) const
308 {
309  typedef typename DMT::element_type el_type;
310 
311  if (helper_iscomplex (el_type ()) && ! force_conversion)
312  warn_implicit_conversion ("Octave:imag-to-real",
313  "complex matrix", "real scalar");
314 
315  if (isempty ())
316  err_invalid_conversion (type_name (), "real scalar");
317 
318  warn_implicit_conversion ("Octave:array-to-scalar",
319  type_name (), "real scalar");
320 
321  return helper_getreal (el_type (m_matrix (0, 0)));
322 }
323 
324 template <typename DMT, typename MT>
325 float
326 octave_base_diag<DMT, MT>::float_value (bool force_conversion) const
327 {
328  typedef typename DMT::element_type el_type;
329 
330  if (helper_iscomplex (el_type ()) && ! force_conversion)
331  warn_implicit_conversion ("Octave:imag-to-real",
332  "complex matrix", "real scalar");
333 
334  if (! (numel () > 0))
335  err_invalid_conversion (type_name (), "real scalar");
336 
337  warn_implicit_conversion ("Octave:array-to-scalar",
338  type_name (), "real scalar");
339 
340  return helper_getreal (el_type (m_matrix (0, 0)));
341 }
342 
343 template <typename DMT, typename MT>
344 Complex
346 {
347  if (rows () == 0 || columns () == 0)
348  err_invalid_conversion (type_name (), "complex scalar");
349 
350  warn_implicit_conversion ("Octave:array-to-scalar",
351  type_name (), "complex scalar");
352 
353  return m_matrix(0, 0);
354 }
355 
356 template <typename DMT, typename MT>
359 {
360  float tmp = lo_ieee_float_nan_value ();
361 
362  FloatComplex retval (tmp, tmp);
363 
364  if (rows () == 0 || columns () == 0)
365  err_invalid_conversion (type_name (), "complex scalar");
366 
367  warn_implicit_conversion ("Octave:array-to-scalar",
368  type_name (), "complex scalar");
369 
370  retval = m_matrix (0, 0);
371 
372  return retval;
373 }
374 
375 template <typename DMT, typename MT>
376 Matrix
378 {
379  return Matrix (diag_matrix_value ());
380 }
381 
382 template <typename DMT, typename MT>
385 {
386  return FloatMatrix (float_diag_matrix_value ());
387 }
388 
389 template <typename DMT, typename MT>
392 {
393  return ComplexMatrix (complex_diag_matrix_value ());
394 }
395 
396 template <typename DMT, typename MT>
399 {
400  return FloatComplexMatrix (float_complex_diag_matrix_value ());
401 }
402 
403 template <typename DMT, typename MT>
404 NDArray
406 {
407  return NDArray (matrix_value ());
408 }
409 
410 template <typename DMT, typename MT>
413 {
414  return FloatNDArray (float_matrix_value ());
415 }
416 
417 template <typename DMT, typename MT>
420 {
421  return ComplexNDArray (complex_matrix_value ());
422 }
423 
424 template <typename DMT, typename MT>
427 {
428  return FloatComplexNDArray (float_complex_matrix_value ());
429 }
430 
431 template <typename DMT, typename MT>
434 {
435  return to_dense ().bool_array_value (warn);
436 }
437 
438 template <typename DMT, typename MT>
441 {
442  return to_dense ().char_array_value (warn);
443 }
444 
445 template <typename DMT, typename MT>
448 {
449  return SparseMatrix (diag_matrix_value ());
450 }
451 
452 template <typename DMT, typename MT>
455 {
456  return SparseComplexMatrix (complex_diag_matrix_value ());
457 }
458 
459 template <typename DMT, typename MT>
461 octave_base_diag<DMT, MT>::index_vector (bool require_integers) const
462 {
463  return to_dense ().index_vector (require_integers);
464 }
465 
466 template <typename DMT, typename MT>
469  char type) const
470 {
471  return to_dense ().convert_to_str_internal (pad, force, type);
472 }
473 
474 template <typename DMT, typename MT>
477 {
478  // FIXME
479  return float_display_format ();
480 }
481 
482 template <typename DMT, typename MT>
483 std::string
485  octave_idx_type i,
486  octave_idx_type j) const
487 {
488  std::ostringstream buf;
489  octave_print_internal (buf, fmt, m_matrix(i, j));
490  return buf.str ();
491 }
492 
493 template <typename DMT, typename MT>
494 bool
496 {
497  os << "# rows: " << m_matrix.rows () << "\n"
498  << "# columns: " << m_matrix.columns () << "\n";
499 
500  os << m_matrix.extract_diag ();
501 
502  return true;
503 }
504 
505 template <typename DMT, typename MT>
506 bool
508 {
509  octave_idx_type r = 0;
510  octave_idx_type c = 0;
511 
512  if (! extract_keyword (is, "rows", r, true)
513  || ! extract_keyword (is, "columns", c, true))
514  error ("load: failed to extract number of rows and columns");
515 
516  octave_idx_type l = (r < c ? r : c);
517  MT tmp (l, 1);
518  is >> tmp;
519 
520  if (! is)
521  error ("load: failed to load diagonal matrix constant");
522 
523  // This is a little tricky, as we have the Matrix type, but
524  // not ColumnVector type. We need to help the compiler get
525  // through the inheritance tree.
526  typedef typename DMT::element_type el_type;
527  m_matrix = DMT (MDiagArray2<el_type> (MArray<el_type> (tmp)));
528  m_matrix.resize (r, c);
529 
530  // Invalidate cache. Probably not necessary, but safe.
531  m_dense_cache = octave_value ();
532 
533  return true;
534 }
535 
536 template <typename DMT, typename MT>
537 void
539  bool pr_as_read_syntax) const
540 {
541  return octave_print_internal (os, m_matrix, pr_as_read_syntax,
542  current_print_indent_level ());
543 }
544 
545 template <typename DMT, typename MT>
546 mxArray *
548 {
549  return to_dense ().as_mxArray (interleaved);
550 }
551 
552 template <typename DMT, typename MT>
553 bool
555 {
556  dim_vector dv = dims ();
557 
558  return (dv.all_ones () || dv.any_zero ());
559 }
560 
561 template <typename DMT, typename MT>
562 void
563 octave_base_diag<DMT, MT>::print (std::ostream& os, bool pr_as_read_syntax)
564 {
565  print_raw (os, pr_as_read_syntax);
566  newline (os);
567 }
568 template <typename DMT, typename MT>
569 int
570 octave_base_diag<DMT, MT>::write (octave::stream& os, int block_size,
571  oct_data_conv::data_type output_type,
572  int skip,
573  octave::mach_info::float_format flt_fmt) const
574 {
575  return to_dense ().write (os, block_size, output_type, skip, flt_fmt);
576 }
577 
578 template <typename DMT, typename MT>
579 void
581  const std::string& prefix) const
582 {
583  m_matrix.print_info (os, prefix);
584 }
585 
586 // FIXME: this function is duplicated in octave_base_matrix<T>. Could
587 // it somehow be shared instead?
588 
589 template <typename DMT, typename MT>
590 void
592 {
593  if (m_matrix.isempty ())
594  os << "[]";
595  else if (m_matrix.ndims () == 2)
596  {
597  // FIXME: should this be configurable?
598  octave_idx_type max_elts = 10;
599  octave_idx_type elts = 0;
600 
601  octave_idx_type nel = m_matrix.numel ();
602 
603  octave_idx_type nr = m_matrix.rows ();
604  octave_idx_type nc = m_matrix.columns ();
605 
606  os << '[';
607 
608  for (octave_idx_type i = 0; i < nr; i++)
609  {
610  for (octave_idx_type j = 0; j < nc; j++)
611  {
612  std::ostringstream buf;
613  octave_print_internal (buf, m_matrix(i, j));
614  std::string tmp = buf.str ();
615  std::size_t pos = tmp.find_first_not_of (' ');
616  if (pos != std::string::npos)
617  os << tmp.substr (pos);
618  else if (! tmp.empty ())
619  os << tmp[0];
620 
621  if (++elts >= max_elts)
622  goto done;
623 
624  if (j < nc - 1)
625  os << ", ";
626  }
627 
628  if (i < nr - 1 && elts < max_elts)
629  os << "; ";
630  }
631 
632  done:
633 
634  if (nel <= max_elts)
635  os << ']';
636  }
637  else
638  os << "...";
639 }
640 
641 template <typename DMT, typename MT>
644 {
645  if (n < m_matrix.numel ())
646  {
647  octave_idx_type nr = m_matrix.rows ();
648 
649  octave_idx_type r = n % nr;
650  octave_idx_type c = n / nr;
651 
652  return octave_value (m_matrix.elem (r, c));
653  }
654  else
655  return octave_value ();
656 }
657 
658 template <typename DMT, typename MT>
661 {
662  if (! m_dense_cache.is_defined ())
663  m_dense_cache = MT (m_matrix);
664 
665  return m_dense_cache;
666 }
Array< octave::idx_vector > ind2sub(const dim_vector &dv, const octave::idx_vector &idx)
Definition: Array-util.cc:598
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:130
Template for N-dimensional array classes with like-type math operators.
Definition: MArray.h:63
Template for two dimensional diagonal array with math operators.
Definition: MDiagArray2.h:56
Definition: dMatrix.h:42
NDArray diag(octave_idx_type k=0) const
Definition: dNDArray.cc:609
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
octave_idx_type ndims() const
Number of dimensions.
Definition: dim-vector.h:257
bool any_zero() const
Definition: dim-vector.h:316
bool all_ones() const
Definition: dim-vector.h:324
bool load_ascii(std::istream &is)
virtual octave_value subsref(const std::string &type, const std::list< octave_value_list > &idx)
Definition: ov-base.cc:248
void print_info(std::ostream &os, const std::string &prefix) const
boolNDArray bool_array_value(bool warn=false) const
Matrix matrix_value(bool=false) const
bool save_ascii(std::ostream &os)
Complex complex_value(bool=false) const
NDArray array_value(bool=false) const
FloatComplexNDArray float_complex_array_value(bool=false) const
ComplexMatrix complex_matrix_value(bool=false) const
virtual octave_value diag(octave_idx_type k=0) const
Definition: ov-base.cc:1041
FloatComplex float_complex_value(bool=false) const
FloatComplexMatrix float_complex_matrix_value(bool=false) const
FloatNDArray float_array_value(bool=false) const
octave_value resize(const dim_vector &dv, bool fill=false) const
octave::idx_vector index_vector(bool=false) const
octave_value fast_elem_extract(octave_idx_type n) const
octave_value to_dense() const
float float_value(bool=false) const
octave_value do_index_op(const octave_value_list &idx, bool resize_ok=false)
octave_value subsasgn(const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
charNDArray char_array_value(bool=false) const
SparseComplexMatrix sparse_complex_matrix_value(bool=false) const
void print(std::ostream &os, bool pr_as_read_syntax=false)
int write(octave::stream &os, int block_size, oct_data_conv::data_type output_type, int skip, octave::mach_info::float_format flt_fmt) const
ComplexNDArray complex_array_value(bool=false) const
std::string edit_display(const float_display_format &fmt, octave_idx_type i, octave_idx_type j) const
void short_disp(std::ostream &os) const
octave_value convert_to_str_internal(bool pad, bool force, char type) const
float_display_format get_edit_display_format() const
bool print_as_scalar() const
mxArray * as_mxArray(bool interleaved) const
bool is_true() const
double double_value(bool=false) const
FloatMatrix float_matrix_value(bool=false) const
void print_raw(std::ostream &os, bool pr_as_read_syntax=false) const
SparseMatrix sparse_matrix_value(bool=false) const
octave_idx_type length() const
Definition: ovl.h:113
octave_value convert_to_str_internal(bool pad, bool force, char type) const
Definition: ov.h:1312
octave_value index_op(const octave_value_list &idx, bool resize_ok=false)
Definition: ov.h:504
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)
bool is_defined() const
Definition: ov.h:592
NDArray array_value(bool frc_str_conv=false) const
Definition: ov.h:859
octave_value resize(const dim_vector &dv, bool fill=false) const
Definition: ov.h:580
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_array_as_logical(const dim_vector &dv)
Definition: errwarn.cc:286
void err_invalid_conversion(const std::string &from, const std::string &to)
Definition: errwarn.cc:71
void warn_implicit_conversion(const char *id, const char *from, const char *to)
Definition: errwarn.cc:344
octave::idx_vector idx_vector
Definition: idx-vector.h:1022
float lo_ieee_float_nan_value()
Definition: lo-ieee.cc:116
F77_RET_T const F77_DBLE * x
std::string extract_keyword(std::istream &is, const char *keyword, const bool next_only)
Definition: ls-oct-text.cc:84
float_format
Definition: mach-info.h:38
T octave_idx_type m
Definition: mx-inlines.cc:781
octave_idx_type n
Definition: mx-inlines.cc:761
T * r
Definition: mx-inlines.cc:781
std::complex< double > Complex
Definition: oct-cmplx.h:33
std::complex< float > FloatComplex
Definition: oct-cmplx.h:34
T::size_type numel(const T &str)
Definition: oct-string.cc:74
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
T helper_getreal(T x)
T helper_iscomplex(T)
void octave_print_internal(std::ostream &os, const float_display_format &fmt, bool d, bool pr_as_read_syntax)
Definition: pr-output.cc:1761