GNU Octave 7.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-2022 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
49template <typename DMT, typename MT>
51octave_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
77template <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
101template <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
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;
148
149template <typename DMT, typename MT>
151octave_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 }
168 octave_value_list jdx = idx.front ();
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->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))
221 m_matrix.dgelem (i0(0)) = val;
222 retval = this;
223 this->count++;
224 // invalidate cache
225 m_dense_cache = octave_value ();
226 }
227 }
229 {
230 // Rethrow to allow more info to be reported later.
231 ie.set_pos_if_unset (2, k+1);
232 throw;
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]);
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:
258 }
259
260 return retval;
261}
262
263template <typename DMT, typename MT>
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 (non-zero, not NA/NaN).
280template <typename DMT, typename MT>
281bool
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
296template <typename T> inline T helper_getreal (T x) { return x; }
297template <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.
301template <typename T> inline T helper_iscomplex (T) { return false; }
302template <typename T> inline T helper_iscomplex (std::complex<T>) { return true; }
303
304template <typename DMT, typename MT>
305double
306octave_base_diag<DMT, MT>::double_value (bool force_conversion) const
307{
308 typedef typename DMT::element_type el_type;
309
310 if (helper_iscomplex (el_type ()) && ! force_conversion)
311 warn_implicit_conversion ("Octave:imag-to-real",
312 "complex matrix", "real scalar");
313
314 if (isempty ())
315 err_invalid_conversion (type_name (), "real scalar");
316
317 warn_implicit_conversion ("Octave:array-to-scalar",
318 type_name (), "real scalar");
319
320 return helper_getreal (el_type (m_matrix (0, 0)));
321}
322
323template <typename DMT, typename MT>
324float
325octave_base_diag<DMT, MT>::float_value (bool force_conversion) const
326{
327 typedef typename DMT::element_type el_type;
328
329 if (helper_iscomplex (el_type ()) && ! force_conversion)
330 warn_implicit_conversion ("Octave:imag-to-real",
331 "complex matrix", "real scalar");
332
333 if (! (numel () > 0))
334 err_invalid_conversion (type_name (), "real scalar");
335
336 warn_implicit_conversion ("Octave:array-to-scalar",
337 type_name (), "real scalar");
338
339 return helper_getreal (el_type (m_matrix (0, 0)));
340}
341
342template <typename DMT, typename MT>
345{
346 if (rows () == 0 || columns () == 0)
347 err_invalid_conversion (type_name (), "complex scalar");
348
349 warn_implicit_conversion ("Octave:array-to-scalar",
350 type_name (), "complex scalar");
351
352 return m_matrix(0, 0);
353}
354
355template <typename DMT, typename MT>
358{
359 float tmp = lo_ieee_float_nan_value ();
360
361 FloatComplex retval (tmp, tmp);
362
363 if (rows () == 0 || columns () == 0)
364 err_invalid_conversion (type_name (), "complex scalar");
365
366 warn_implicit_conversion ("Octave:array-to-scalar",
367 type_name (), "complex scalar");
368
369 retval = m_matrix (0, 0);
370
371 return retval;
372}
373
374template <typename DMT, typename MT>
375Matrix
377{
378 return Matrix (diag_matrix_value ());
379}
380
381template <typename DMT, typename MT>
384{
385 return FloatMatrix (float_diag_matrix_value ());
386}
387
388template <typename DMT, typename MT>
391{
392 return ComplexMatrix (complex_diag_matrix_value ());
393}
394
395template <typename DMT, typename MT>
398{
399 return FloatComplexMatrix (float_complex_diag_matrix_value ());
400}
401
402template <typename DMT, typename MT>
405{
406 return NDArray (matrix_value ());
407}
408
409template <typename DMT, typename MT>
412{
413 return FloatNDArray (float_matrix_value ());
414}
415
416template <typename DMT, typename MT>
419{
420 return ComplexNDArray (complex_matrix_value ());
421}
422
423template <typename DMT, typename MT>
426{
427 return FloatComplexNDArray (float_complex_matrix_value ());
428}
429
430template <typename DMT, typename MT>
433{
434 return to_dense ().bool_array_value (warn);
435}
436
437template <typename DMT, typename MT>
440{
441 return to_dense ().char_array_value (warn);
442}
443
444template <typename DMT, typename MT>
447{
448 return SparseMatrix (diag_matrix_value ());
449}
450
451template <typename DMT, typename MT>
454{
455 return SparseComplexMatrix (complex_diag_matrix_value ());
456}
457
458template <typename DMT, typename MT>
460octave_base_diag<DMT, MT>::index_vector (bool require_integers) const
461{
462 return to_dense ().index_vector (require_integers);
463}
464
465template <typename DMT, typename MT>
468 char type) const
469{
470 return to_dense ().convert_to_str_internal (pad, force, type);
471}
472
473template <typename DMT, typename MT>
476{
477 // FIXME
478 return float_display_format ();
479}
480
481template <typename DMT, typename MT>
482std::string
485 octave_idx_type j) const
486{
487 std::ostringstream buf;
488 octave_print_internal (buf, fmt, m_matrix(i, j));
489 return buf.str ();
490}
491
492template <typename DMT, typename MT>
493bool
495{
496 os << "# rows: " << m_matrix.rows () << "\n"
497 << "# columns: " << m_matrix.columns () << "\n";
498
499 os << m_matrix.extract_diag ();
500
501 return true;
502}
503
504template <typename DMT, typename MT>
505bool
507{
508 octave_idx_type r = 0;
509 octave_idx_type c = 0;
510
511 if (! extract_keyword (is, "rows", r, true)
512 || ! extract_keyword (is, "columns", c, true))
513 error ("load: failed to extract number of rows and columns");
514
515 octave_idx_type l = (r < c ? r : c);
516 MT tmp (l, 1);
517 is >> tmp;
518
519 if (! is)
520 error ("load: failed to load diagonal matrix constant");
521
522 // This is a little tricky, as we have the Matrix type, but
523 // not ColumnVector type. We need to help the compiler get
524 // through the inheritance tree.
525 typedef typename DMT::element_type el_type;
526 m_matrix = DMT (MDiagArray2<el_type> (MArray<el_type> (tmp)));
527 m_matrix.resize (r, c);
528
529 // Invalidate cache. Probably not necessary, but safe.
530 m_dense_cache = octave_value ();
531
532 return true;
533}
534
535template <typename DMT, typename MT>
536void
538 bool pr_as_read_syntax) const
539{
540 return octave_print_internal (os, m_matrix, pr_as_read_syntax,
541 current_print_indent_level ());
542}
543
544template <typename DMT, typename MT>
545mxArray *
547{
548 return to_dense ().as_mxArray (interleaved);
549}
550
551template <typename DMT, typename MT>
552bool
554{
555 dim_vector dv = dims ();
556
557 return (dv.all_ones () || dv.any_zero ());
558}
559
560template <typename DMT, typename MT>
561void
562octave_base_diag<DMT, MT>::print (std::ostream& os, bool pr_as_read_syntax)
563{
564 print_raw (os, pr_as_read_syntax);
565 newline (os);
566}
567template <typename DMT, typename MT>
568int
570 oct_data_conv::data_type output_type,
571 int skip,
573{
574 return to_dense ().write (os, block_size, output_type, skip, flt_fmt);
575}
576
577template <typename DMT, typename MT>
578void
580 const std::string& prefix) const
581{
582 m_matrix.print_info (os, prefix);
583}
584
585// FIXME: this function is duplicated in octave_base_matrix<T>. Could
586// it somehow be shared instead?
587
588template <typename DMT, typename MT>
589void
591{
592 if (m_matrix.isempty ())
593 os << "[]";
594 else if (m_matrix.ndims () == 2)
595 {
596 // FIXME: should this be configurable?
597 octave_idx_type max_elts = 10;
598 octave_idx_type elts = 0;
599
600 octave_idx_type nel = m_matrix.numel ();
601
602 octave_idx_type nr = m_matrix.rows ();
603 octave_idx_type nc = m_matrix.columns ();
604
605 os << '[';
606
607 for (octave_idx_type i = 0; i < nr; i++)
608 {
609 for (octave_idx_type j = 0; j < nc; j++)
610 {
611 std::ostringstream buf;
612 octave_print_internal (buf, m_matrix(i, j));
613 std::string tmp = buf.str ();
614 std::size_t pos = tmp.find_first_not_of (' ');
615 if (pos != std::string::npos)
616 os << tmp.substr (pos);
617 else if (! tmp.empty ())
618 os << tmp[0];
619
620 if (++elts >= max_elts)
621 goto done;
622
623 if (j < nc - 1)
624 os << ", ";
625 }
626
627 if (i < nr - 1 && elts < max_elts)
628 os << "; ";
629 }
630
631 done:
632
633 if (nel <= max_elts)
634 os << ']';
635 }
636 else
637 os << "...";
638}
639
640template <typename DMT, typename MT>
643{
644 if (n < m_matrix.numel ())
645 {
646 octave_idx_type nr = m_matrix.rows ();
647
648 octave_idx_type r = n % nr;
649 octave_idx_type c = n / nr;
650
651 return octave_value (m_matrix.elem (r, c));
652 }
653 else
654 return octave_value ();
655}
656
657template <typename DMT, typename MT>
660{
661 if (! m_dense_cache.is_defined ())
662 m_dense_cache = MT (m_matrix);
663
664 return m_dense_cache;
665}
Array< octave::idx_vector > ind2sub(const dim_vector &dv, const octave::idx_vector &idx)
Definition: Array-util.cc:619
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:129
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
OCTAVE_API 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
bool all_ones(void) const
Definition: dim-vector.h:324
octave_idx_type ndims(void) const
Number of dimensions.
Definition: dim-vector.h:257
bool any_zero(void) const
Definition: dim-vector.h:316
bool is_scalar(void) const
Definition: idx-vector.h:559
octave_idx_type length(octave_idx_type n=0) const
Definition: idx-vector.h:537
bool is_colon_equiv(octave_idx_type n) const
Definition: idx-vector.h:565
void set_pos_if_unset(octave_idx_type nd_arg, octave_idx_type dim_arg)
OCTINTERP_API bool is_true(void) const
OCTINTERP_API bool load_ascii(std::istream &is)
OCTINTERP_API void print_info(std::ostream &os, const std::string &prefix) const
OCTINTERP_API boolNDArray bool_array_value(bool warn=false) const
OCTINTERP_API Matrix matrix_value(bool=false) const
OCTINTERP_API bool save_ascii(std::ostream &os)
OCTINTERP_API Complex complex_value(bool=false) const
OCTINTERP_API NDArray array_value(bool=false) const
OCTINTERP_API FloatComplexNDArray float_complex_array_value(bool=false) const
OCTINTERP_API ComplexMatrix complex_matrix_value(bool=false) const
OCTINTERP_API FloatComplex float_complex_value(bool=false) const
OCTINTERP_API octave_value diag(octave_idx_type k=0) const
Definition: ov-base-diag.cc:79
OCTINTERP_API FloatComplexMatrix float_complex_matrix_value(bool=false) const
OCTINTERP_API FloatNDArray float_array_value(bool=false) const
OCTINTERP_API octave_value resize(const dim_vector &dv, bool fill=false) const
OCTINTERP_API octave::idx_vector index_vector(bool=false) const
OCTINTERP_API octave_value fast_elem_extract(octave_idx_type n) const
OCTINTERP_API float_display_format get_edit_display_format(void) const
OCTINTERP_API octave_value to_dense(void) const
OCTINTERP_API float float_value(bool=false) const
OCTINTERP_API octave_value do_index_op(const octave_value_list &idx, bool resize_ok=false)
OCTINTERP_API octave_value subsasgn(const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
OCTINTERP_API octave_value subsref(const std::string &type, const std::list< octave_value_list > &idx)
Definition: ov-base-diag.cc:51
OCTINTERP_API charNDArray char_array_value(bool=false) const
OCTINTERP_API SparseComplexMatrix sparse_complex_matrix_value(bool=false) const
OCTINTERP_API void print(std::ostream &os, bool pr_as_read_syntax=false)
OCTINTERP_API 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
OCTINTERP_API ComplexNDArray complex_array_value(bool=false) const
OCTINTERP_API std::string edit_display(const float_display_format &fmt, octave_idx_type i, octave_idx_type j) const
OCTINTERP_API bool print_as_scalar(void) const
OCTINTERP_API void short_disp(std::ostream &os) const
OCTINTERP_API octave_value convert_to_str_internal(bool pad, bool force, char type) const
OCTINTERP_API mxArray * as_mxArray(bool interleaved) const
OCTINTERP_API double double_value(bool=false) const
OCTINTERP_API FloatMatrix float_matrix_value(bool=false) const
OCTINTERP_API void print_raw(std::ostream &os, bool pr_as_read_syntax=false) const
OCTINTERP_API SparseMatrix sparse_matrix_value(bool=false) const
octave_idx_type length(void) const
Definition: ovl.h:113
octave_value convert_to_str_internal(bool pad, bool force, char type) const
Definition: ov.h:1416
octave_value index_op(const octave_value_list &idx, bool resize_ok=false)
Definition: ov.h:550
static OCTINTERP_API octave_value empty_conv(const std::string &type, const octave_value &rhs=octave_value())
bool is_defined(void) const
Definition: ov.h:637
OCTINTERP_API octave_value next_subsref(const std::string &type, const std::list< octave_value_list > &idx, std::size_t skip=1)
NDArray array_value(bool frc_str_conv=false) const
Definition: ov.h:904
octave_value resize(const dim_vector &dv, bool fill=false) const
Definition: ov.h:625
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:980
#define panic_impossible()
Definition: error.h:411
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
float lo_ieee_float_nan_value(void)
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
class OCTAVE_API NDArray
Definition: mx-fwd.h:38
class OCTAVE_API Matrix
Definition: mx-fwd.h:31
class OCTAVE_API ComplexMatrix
Definition: mx-fwd.h:32
class OCTAVE_API SparseMatrix
Definition: mx-fwd.h:55
class OCTAVE_API FloatComplexMatrix
Definition: mx-fwd.h:34
class OCTAVE_API FloatMatrix
Definition: mx-fwd.h:33
class OCTAVE_API ComplexNDArray
Definition: mx-fwd.h:39
class OCTAVE_API SparseComplexMatrix
Definition: mx-fwd.h:56
class OCTAVE_API FloatComplexNDArray
Definition: mx-fwd.h:41
class OCTAVE_API FloatNDArray
Definition: mx-fwd.h:40
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:71
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:1762