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-diag.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2008-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 <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:
71 error ("unexpected: index not '(', '{', or '.' in octave_base_diag<DMT,MT>::subsref - please report this bug");
72 }
73
74 return retval.next_subsref (type, idx);
75}
76
77template <typename DMT, typename MT>
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
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
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 }
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))
193 m_matrix.dgelem (i0(0)) = val;
194 retval = this;
195 this->m_count++;
196 // invalidate cache
197 m_dense_cache = octave_value ();
198 }
200 catch (octave::index_exception& ie)
202 // Rethrow to allow more info to be reported later.
203 ie.set_pos_if_unset (2, k+1);
204 throw;
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 }
236 if (! retval.is_defined ())
237 retval = numeric_assign (type, idx, rhs);
239 break;
241 case '{':
242 case '.':
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);
252 retval = tmp.subsasgn (type, idx, rhs);
253 }
254 break;
256 default:
257 error ("unexpected: index not '(', '{', or '.' in octave_base_diag<DMT,MT>::subsasgn - please report this bug");
258 }
260 return retval;
261}
263template <typename DMT, typename MT>
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).
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>)
303{ return true; }
304
305template <typename DMT, typename MT>
306double
307octave_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
324template <typename DMT, typename MT>
325float
326octave_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
343template <typename DMT, typename MT>
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
356template <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
375template <typename DMT, typename MT>
376Matrix
378{
379 return Matrix (diag_matrix_value ());
380}
381
382template <typename DMT, typename MT>
385{
386 return FloatMatrix (float_diag_matrix_value ());
387}
388
389template <typename DMT, typename MT>
392{
393 return ComplexMatrix (complex_diag_matrix_value ());
394}
395
396template <typename DMT, typename MT>
399{
400 return FloatComplexMatrix (float_complex_diag_matrix_value ());
401}
402
403template <typename DMT, typename MT>
406{
407 return NDArray (matrix_value ());
408}
409
410template <typename DMT, typename MT>
413{
414 return FloatNDArray (float_matrix_value ());
415}
416
417template <typename DMT, typename MT>
420{
421 return ComplexNDArray (complex_matrix_value ());
422}
423
424template <typename DMT, typename MT>
427{
428 return FloatComplexNDArray (float_complex_matrix_value ());
429}
430
431template <typename DMT, typename MT>
434{
435 return to_dense ().bool_array_value (warn);
436}
437
438template <typename DMT, typename MT>
441{
442 return to_dense ().char_array_value (warn);
443}
444
445template <typename DMT, typename MT>
448{
449 return SparseMatrix (diag_matrix_value ());
450}
451
452template <typename DMT, typename MT>
455{
456 return SparseComplexMatrix (complex_diag_matrix_value ());
457}
458
459template <typename DMT, typename MT>
460octave::idx_vector
461octave_base_diag<DMT, MT>::index_vector (bool require_integers) const
462{
463 return to_dense ().index_vector (require_integers);
464}
465
466template <typename DMT, typename MT>
469 char type) const
470{
471 return to_dense ().convert_to_str_internal (pad, force, type);
472}
473
474template <typename DMT, typename MT>
481
482template <typename DMT, typename MT>
483std::string
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
493template <typename DMT, typename MT>
494bool
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
505template <typename DMT, typename MT>
506bool
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
536template <typename DMT, typename MT>
537void
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
545template <typename DMT, typename MT>
546mxArray *
548{
549 return to_dense ().as_mxArray (interleaved);
550}
551
552template <typename DMT, typename MT>
553bool
555{
556 const dim_vector& dv = dims ();
557
558 return (dv.all_ones () || dv.any_zero ());
559}
560
561template <typename DMT, typename MT>
562void
563octave_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}
568template <typename DMT, typename MT>
569int
570octave_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
578template <typename DMT, typename MT>
579void
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
589template <typename DMT, typename MT>
590void
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 nr = m_matrix.rows ();
602 octave_idx_type nc = m_matrix.columns ();
603
604 os << '[';
605
606 for (octave_idx_type i = 0; i < nr; i++)
607 {
608 for (octave_idx_type j = 0; j < nc; j++)
609 {
610 std::ostringstream buf;
611 octave_print_internal (buf, m_matrix(i, j));
612 std::string tmp = buf.str ();
613 std::size_t pos = tmp.find_first_not_of (' ');
614 if (pos != std::string::npos)
615 os << tmp.substr (pos);
616 else if (! tmp.empty ())
617 os << tmp[0];
618 elts++;
619
620 if (j < nc - 1)
621 {
622 os << ", ";
623
624 if (elts >= max_elts)
625 {
626 os << "...";
627 goto done;
628 }
629 }
630 }
631
632 if (i < nr - 1)
633 {
634 os << "; ";
635
636 if (elts >= max_elts)
637 {
638 os << "...";
639 goto done;
640 }
641 }
642 }
643
644 done:
645 os << ']';
646 }
647 else
649}
650
651template <typename DMT, typename MT>
654{
655 if (n < m_matrix.numel ())
656 {
657 octave_idx_type nr = m_matrix.rows ();
658
659 octave_idx_type r = n % nr;
660 octave_idx_type c = n / nr;
661
662 return octave_value (m_matrix.elem (r, c));
663 }
664 else
665 return octave_value ();
666}
667
668template <typename DMT, typename MT>
671{
672 if (! m_dense_cache.is_defined ())
673 m_dense_cache = MT (m_matrix);
674
675 return m_dense_cache;
676}
Array< octave::idx_vector > ind2sub(const dim_vector &dv, const octave::idx_vector &idx)
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:61
Template for two dimensional diagonal array with math operators.
Definition MDiagArray2.h:54
NDArray diag(octave_idx_type k=0) const
Definition dNDArray.cc:609
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:90
octave_idx_type ndims() const
Number of dimensions.
Definition dim-vector.h:253
bool any_zero() const
Definition dim-vector.h:312
bool all_ones() const
Definition dim-vector.h:320
bool load_ascii(std::istream &is)
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
FloatComplex float_complex_value(bool=false) const
octave_value diag(octave_idx_type k=0) 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)
octave_value subsref(const std::string &type, const std::list< octave_value_list > &idx)
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
virtual void short_disp(std::ostream &os) const
Definition ov-base.h:761
octave_idx_type length() const
Definition ovl.h:111
octave_value convert_to_str_internal(bool pad, bool force, char type) const
Definition ov.h:1327
octave_value index_op(const octave_value_list &idx, bool resize_ok=false)
Definition ov.h:504
bool is_true() const
Definition ov.h:758
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:865
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:1003
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()
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)
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
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)