GNU Octave  4.4.1
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-2018 Jaroslav Hajek
4 
5 This file is part of Octave.
6 
7 Octave is free software: you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <https://www.gnu.org/licenses/>.
20 
21 */
22 
23 // This file should not include config.h. It is only included in other
24 // C++ source files that should have included config.h before including
25 // this file.
26 
27 #include <iostream>
28 
29 #include "mach-info.h"
30 #include "lo-ieee.h"
31 
32 #include "ov-base-diag.h"
33 #include "mxarray.h"
34 #include "ov-base.h"
35 #include "ov-base-mat.h"
36 #include "pr-output.h"
37 #include "error.h"
38 #include "errwarn.h"
39 #include "oct-stream.h"
40 #include "ops.h"
41 
42 #include "ls-oct-text.h"
43 
44 template <typename DMT, typename MT>
47  const std::list<octave_value_list>& idx)
48 {
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 DMT, typename MT>
75 {
77  if (matrix.rows () == 1 || matrix.cols () == 1)
78  {
79  // Rather odd special case. This is a row or column vector
80  // represented as a diagonal matrix with a single nonzero entry, but
81  // Fdiag semantics are to product a diagonal matrix for vector
82  // inputs.
83  if (k == 0)
84  // Returns Diag2Array<T> with nnz <= 1.
85  retval = matrix.build_diag_matrix ();
86  else
87  // Returns Array<T> matrix
88  retval = matrix.array_value ().diag (k);
89  }
90  else
91  // Returns Array<T> vector
92  retval = matrix.extract_diag (k);
93  return retval;
94 }
95 
96 template <typename DMT, typename MT>
99  bool resize_ok)
100 {
102 
103  if (idx.length () == 2 && ! resize_ok)
104  {
105  int k = 0; // index we're accesing when index_vector throws
106  try
107  {
108  idx_vector idx0 = idx(0).index_vector ();
109  k = 1;
110  idx_vector idx1 = idx(1).index_vector ();
111 
112  if (idx0.is_scalar () && idx1.is_scalar ())
113  {
114  retval = matrix.checkelem (idx0(0), idx1(0));
115  }
116  else
117  {
118  octave_idx_type m = idx0.length (matrix.rows ());
119  octave_idx_type n = idx1.length (matrix.columns ());
120  if (idx0.is_colon_equiv (m) && idx1.is_colon_equiv (n)
121  && m <= matrix.rows () && n <= matrix.rows ())
122  {
123  DMT rm (matrix);
124  rm.resize (m, n);
125  retval = rm;
126  }
127  else
128  retval = to_dense ().do_index_op (idx, resize_ok);
129  }
130  }
131  catch (octave::index_exception& e)
132  {
133  // Rethrow to allow more info to be reported later.
134  e.set_pos_if_unset (2, k+1);
135  throw;
136  }
137  }
138  else
139  retval = to_dense ().do_index_op (idx, resize_ok);
140 
141  return retval;
142 }
143 
144 template <typename DMT, typename MT>
147  const std::list<octave_value_list>& idx,
148  const octave_value& rhs)
149 {
151 
152  switch (type[0])
153  {
154  case '(':
155  {
156  if (type.length () != 1)
157  {
158  std::string nm = type_name ();
159  error ("in indexed assignment of %s, last lhs index must be ()",
160  nm.c_str ());
161  }
162 
163  octave_value_list jdx = idx.front ();
164 
165  // FIXME: Mostly repeated code for cases 1 and 2 could be
166  // consolidated for DRY (Don't Repeat Yourself).
167  // Check for assignments to diagonal elements which should not
168  // destroy the diagonal property of the matrix.
169  // If D is a diagonal matrix then the assignment can be
170  // 1) linear, D(i) = x, where ind2sub results in case #2 below
171  // 2) subscript D(i,i) = x, where both indices are equal.
172  if (jdx.length () == 1 && jdx(0).is_scalar_type ())
173  {
174  typename DMT::element_type val;
175  int k = 0;
176  try
177  {
178  idx_vector ind = jdx(0).index_vector ();
179  k = 1;
180  dim_vector dv (matrix.rows (), matrix.cols ());
181  Array<idx_vector> ivec = ind2sub (dv, ind);
182  idx_vector i0 = ivec(0);
183  idx_vector i1 = ivec(1);
184 
185  if (i0(0) == i1(0)
186  && chk_valid_scalar (rhs, val))
187  {
188  matrix.dgelem (i0(0)) = val;
189  retval = this;
190  this->count++;
191  // invalidate cache
192  dense_cache = octave_value ();
193  }
194  }
195  catch (octave::index_exception& e)
196  {
197  // Rethrow to allow more info to be reported later.
198  e.set_pos_if_unset (2, k+1);
199  throw;
200  }
201  }
202  else if (jdx.length () == 2
203  && jdx(0).is_scalar_type () && jdx(1).is_scalar_type ())
204  {
205  typename DMT::element_type val;
206  int k = 0;
207  try
208  {
209  idx_vector i0 = jdx(0).index_vector ();
210  k = 1;
211  idx_vector i1 = jdx(1).index_vector ();
212  if (i0(0) == i1(0)
213  && i0(0) < matrix.rows () && i1(0) < matrix.cols ()
214  && chk_valid_scalar (rhs, val))
215  {
216  matrix.dgelem (i0(0)) = val;
217  retval = this;
218  this->count++;
219  // invalidate cache
220  dense_cache = octave_value ();
221  }
222  }
223  catch (octave::index_exception& e)
224  {
225  // Rethrow to allow more info to be reported later.
226  e.set_pos_if_unset (2, k+1);
227  throw;
228  }
229  }
230 
231  if (! retval.is_defined ())
232  retval = numeric_assign (type, idx, rhs);
233  }
234  break;
235 
236  case '{':
237  case '.':
238  {
239  if (! isempty ())
240  {
241  std::string nm = type_name ();
242  error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
243  }
244 
246 
247  retval = tmp.subsasgn (type, idx, rhs);
248  }
249  break;
250 
251  default:
252  panic_impossible ();
253  }
254 
255  return retval;
256 }
257 
258 template <typename DMT, typename MT>
261 {
263  if (dv.ndims () == 2)
264  {
265  DMT rm (matrix);
266  rm.resize (dv(0), dv(1));
267  retval = rm;
268  }
269  else
270  retval = to_dense ().resize (dv, fill);
271  return retval;
272 }
273 
274 // Return true if this matrix has all true elements (non-zero, not NA/NaN).
275 template <typename DMT, typename MT>
276 bool
278 {
279  if (dims ().numel () > 1)
280  {
282  // Throw error if any NaN or NA by calling is_true().
283  octave_value (matrix.extract_diag ()).is_true ();
284  return false; // > 1x1 diagonal always has zeros
285  }
286  else
287  return to_dense ().is_true (); // 0x0 or 1x1, handle NaN etc.
288 }
289 
290 // FIXME: This should be achieveable using ::real
291 template <typename T> inline T helper_getreal (T x) { return x; }
292 template <typename T> inline T helper_getreal (std::complex<T> x)
293 { return x.real (); }
294 // FIXME: We really need some traits so that ad hoc hooks like this
295 // are not necessary.
296 template <typename T> inline T helper_iscomplex (T) { return false; }
297 template <typename T> inline T helper_iscomplex (std::complex<T>) { return true; }
298 
299 template <typename DMT, typename MT>
300 double
301 octave_base_diag<DMT, MT>::double_value (bool force_conversion) const
302 {
303  typedef typename DMT::element_type el_type;
304 
305  if (helper_iscomplex (el_type ()) && ! force_conversion)
306  warn_implicit_conversion ("Octave:imag-to-real",
307  "complex matrix", "real scalar");
308 
309  if (isempty ())
310  err_invalid_conversion (type_name (), "real scalar");
311 
312  warn_implicit_conversion ("Octave:array-to-scalar",
313  type_name (), "real scalar");
314 
315  return helper_getreal (el_type (matrix (0, 0)));
316 }
317 
318 template <typename DMT, typename MT>
319 float
320 octave_base_diag<DMT, MT>::float_value (bool force_conversion) const
321 {
322  typedef typename DMT::element_type el_type;
323 
324  if (helper_iscomplex (el_type ()) && ! force_conversion)
325  warn_implicit_conversion ("Octave:imag-to-real",
326  "complex matrix", "real scalar");
327 
328  if (! (numel () > 0))
329  err_invalid_conversion (type_name (), "real scalar");
330 
331  warn_implicit_conversion ("Octave:array-to-scalar",
332  type_name (), "real scalar");
333 
334  return helper_getreal (el_type (matrix (0, 0)));
335 }
336 
337 template <typename DMT, typename MT>
338 Complex
340 {
341  if (rows () == 0 || columns () == 0)
342  err_invalid_conversion (type_name (), "complex scalar");
343 
344  warn_implicit_conversion ("Octave:array-to-scalar",
345  type_name (), "complex scalar");
346 
347  return matrix(0, 0);
348 }
349 
350 template <typename DMT, typename MT>
353 {
354  float tmp = lo_ieee_float_nan_value ();
355 
357 
358  if (rows () == 0 || columns () == 0)
359  err_invalid_conversion (type_name (), "complex scalar");
360 
361  warn_implicit_conversion ("Octave:array-to-scalar",
362  type_name (), "complex scalar");
363 
364  retval = matrix (0, 0);
365 
366  return retval;
367 }
368 
369 template <typename DMT, typename MT>
370 Matrix
372 {
373  return Matrix (diag_matrix_value ());
374 }
375 
376 template <typename DMT, typename MT>
379 {
380  return FloatMatrix (float_diag_matrix_value ());
381 }
382 
383 template <typename DMT, typename MT>
386 {
387  return ComplexMatrix (complex_diag_matrix_value ());
388 }
389 
390 template <typename DMT, typename MT>
393 {
394  return FloatComplexMatrix (float_complex_diag_matrix_value ());
395 }
396 
397 template <typename DMT, typename MT>
398 NDArray
400 {
401  return NDArray (matrix_value ());
402 }
403 
404 template <typename DMT, typename MT>
407 {
408  return FloatNDArray (float_matrix_value ());
409 }
410 
411 template <typename DMT, typename MT>
414 {
415  return ComplexNDArray (complex_matrix_value ());
416 }
417 
418 template <typename DMT, typename MT>
421 {
422  return FloatComplexNDArray (float_complex_matrix_value ());
423 }
424 
425 template <typename DMT, typename MT>
428 {
429  return to_dense ().bool_array_value (warn);
430 }
431 
432 template <typename DMT, typename MT>
435 {
436  return to_dense ().char_array_value (warn);
437 }
438 
439 template <typename DMT, typename MT>
442 {
443  return SparseMatrix (diag_matrix_value ());
444 }
445 
446 template <typename DMT, typename MT>
449 {
450  return SparseComplexMatrix (complex_diag_matrix_value ());
451 }
452 
453 template <typename DMT, typename MT>
455 octave_base_diag<DMT, MT>::index_vector (bool require_integers) const
456 {
457  return to_dense ().index_vector (require_integers);
458 }
459 
460 template <typename DMT, typename MT>
463  char type) const
464 {
465  return to_dense ().convert_to_str_internal (pad, force, type);
466 }
467 
468 template <typename DMT, typename MT>
471 {
472  // FIXME
473  return float_display_format ();
474 }
475 
476 template <typename DMT, typename MT>
480  octave_idx_type j) const
481 {
482  std::ostringstream buf;
483  octave_print_internal (buf, fmt, matrix(i,j));
484  return buf.str ();
485 }
486 
487 template <typename DMT, typename MT>
488 bool
490 {
491  os << "# rows: " << matrix.rows () << "\n"
492  << "# columns: " << matrix.columns () << "\n";
493 
494  os << matrix.extract_diag ();
495 
496  return true;
497 }
498 
499 template <typename DMT, typename MT>
500 bool
502 {
503  octave_idx_type r = 0;
504  octave_idx_type c = 0;
505 
506  if (! extract_keyword (is, "rows", r, true)
507  || ! extract_keyword (is, "columns", c, true))
508  error ("load: failed to extract number of rows and columns");
509 
510  octave_idx_type l = (r < c ? r : c);
511  MT tmp (l, 1);
512  is >> tmp;
513 
514  if (! is)
515  error ("load: failed to load diagonal matrix constant");
516 
517  // This is a little tricky, as we have the Matrix type, but
518  // not ColumnVector type. We need to help the compiler get
519  // through the inheritance tree.
520  typedef typename DMT::element_type el_type;
522  matrix.resize (r, c);
523 
524  // Invalidate cache. Probably not necessary, but safe.
525  dense_cache = octave_value ();
526 
527  return true;
528 }
529 
530 template <typename DMT, typename MT>
531 void
533  bool pr_as_read_syntax) const
534 {
535  return octave_print_internal (os, matrix, pr_as_read_syntax,
536  current_print_indent_level ());
537 }
538 
539 template <typename DMT, typename MT>
540 mxArray *
542 {
543  return to_dense ().as_mxArray ();
544 }
545 
546 template <typename DMT, typename MT>
547 bool
549 {
550  dim_vector dv = dims ();
551 
552  return (dv.all_ones () || dv.any_zero ());
553 }
554 
555 template <typename DMT, typename MT>
556 void
557 octave_base_diag<DMT, MT>::print (std::ostream& os, bool pr_as_read_syntax)
558 {
559  print_raw (os, pr_as_read_syntax);
560  newline (os);
561 }
562 template <typename DMT, typename MT>
563 int
565  oct_data_conv::data_type output_type,
566  int skip,
568 {
569  return to_dense ().write (os, block_size, output_type, skip, flt_fmt);
570 }
571 
572 template <typename DMT, typename MT>
573 void
575  const std::string& prefix) const
576 {
577  matrix.print_info (os, prefix);
578 }
579 
580 // FIXME: this function is duplicated in octave_base_matrix<T>. Could
581 // it somehow be shared instead?
582 
583 template <typename DMT, typename MT>
584 void
586 {
587  if (matrix.isempty ())
588  os << "[]";
589  else if (matrix.ndims () == 2)
590  {
591  // FIXME: should this be configurable?
592  octave_idx_type max_elts = 10;
593  octave_idx_type elts = 0;
594 
595  octave_idx_type nel = matrix.numel ();
596 
597  octave_idx_type nr = matrix.rows ();
598  octave_idx_type nc = matrix.columns ();
599 
600  os << '[';
601 
602  for (octave_idx_type i = 0; i < nr; i++)
603  {
604  for (octave_idx_type j = 0; j < nc; j++)
605  {
606  std::ostringstream buf;
607  octave_print_internal (buf, matrix(i,j));
608  std::string tmp = buf.str ();
609  size_t pos = tmp.find_first_not_of (' ');
610  if (pos != std::string::npos)
611  os << tmp.substr (pos);
612  else if (! tmp.empty ())
613  os << tmp[0];
614 
615  if (++elts >= max_elts)
616  goto done;
617 
618  if (j < nc - 1)
619  os << ", ";
620  }
621 
622  if (i < nr - 1 && elts < max_elts)
623  os << "; ";
624  }
625 
626  done:
627 
628  if (nel <= max_elts)
629  os << ']';
630  }
631  else
632  os << "...";
633 }
634 
635 template <typename DMT, typename MT>
638 {
639  if (n < matrix.numel ())
640  {
641  octave_idx_type nr = matrix.rows ();
642 
643  octave_idx_type r = n % nr;
644  octave_idx_type c = n / nr;
645 
646  return octave_value (matrix.elem (r, c));
647  }
648  else
649  return octave_value ();
650 }
651 
652 template <typename DMT, typename MT>
655 {
656  if (! dense_cache.is_defined ())
657  dense_cache = MT (matrix);
658 
659  return dense_cache;
660 }
Matrix matrix_value(bool=false) const
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
void print(std::ostream &os, bool pr_as_read_syntax=false)
Template for N-dimensional array classes with like-type math operators.
Definition: MArray.h:32
T helper_iscomplex(T)
characters Given a string matrix
Definition: hex2num.cc:155
mxArray * as_mxArray(void) const
ind
Definition: sub2ind.cc:107
identity matrix If supplied two scalar respectively For allows like xample val
Definition: data.cc:4986
bool load_ascii(std::istream &is)
std::string edit_display(const float_display_format &fmt, octave_idx_type i, octave_idx_type j) const
FloatMatrix float_matrix_value(bool=false) const
for large enough k
Definition: lu.cc:617
bool is_true(void) const
void error(const char *fmt,...)
Definition: error.cc:578
void short_disp(std::ostream &os) const
charNDArray char_array_value(bool=false) const
octave::mach_info::float_format flt_fmt
Definition: load-save.cc:736
bool is_defined(void) const
Definition: ov.h:523
nd example oindent opens the file binary numeric values will be read assuming they are stored in IEEE format with the least significant bit and then converted to the native representation Opening a file that is already open simply opens it again and returns a separate file id It is not an error to open a file several though writing to the same file through several different file ids may produce unexpected results The possible values of text mode reading and writing automatically converts linefeeds to the appropriate line end character for the you may append a you must also open the file in binary mode The parameter conversions are currently only supported for and permissions will be set to and then everything is written in a single operation This is very efficient and improves performance c
Definition: file-io.cc:587
i e
Definition: data.cc:2591
octave_value do_index_op(const octave_value_list &idx, bool resize_ok=false)
Definition: ov-base-diag.cc:98
idx_vector index_vector(bool=false) const
octave_value to_dense(void) const
Template for two dimensional diagonal array with math operators.
Definition: MDiagArray2.h:32
bool any_zero(void) const
Definition: dim-vector.h:343
octave_value resize(const dim_vector &dv, bool fill=false) const
Definition: ov.h:511
float float_value(bool=false) const
FloatComplexMatrix float_complex_matrix_value(bool=false) const
boolNDArray bool_array_value(bool warn=false) const
done
Definition: syscalls.cc:251
void octave_print_internal(std::ostream &os, const float_display_format &fmt, bool d, bool pr_as_read_syntax)
Definition: pr-output.cc:1780
OCTAVE_EXPORT octave_value_list isdir nd deftypefn *std::string nm
Definition: utils.cc:975
void print_raw(std::ostream &os, bool pr_as_read_syntax=false) const
octave_value subsasgn(const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
std::string extract_keyword(std::istream &is, const char *keyword, const bool next_only)
Definition: ls-oct-text.cc:82
octave_value diag(octave_idx_type k=0) const
Definition: ov-base-diag.cc:74
double double_value(bool=false) const
octave_value convert_to_str_internal(bool pad, bool force, char type) const
Definition: ov.h:1256
float_display_format get_edit_display_format(void) const
double tmp
Definition: data.cc:6252
octave_idx_type length(octave_idx_type n=0) const
Definition: idx-vector.h:557
octave_value retval
Definition: data.cc:6246
#define panic_impossible()
Definition: error.h:40
bool is_true(const std::string &s)
idx type
Definition: ov.cc:3114
Definition: dMatrix.h:36
the exceeded dimensions are set to if fewer subscripts than dimensions are the exceeding dimensions are merged into the final requested dimension For consider the following dims
Definition: sub2ind.cc:255
float lo_ieee_float_nan_value(void)
Definition: lo-ieee.cc:123
FloatComplexNDArray float_complex_array_value(bool=false) const
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:125
Array< idx_vector > ind2sub(const dim_vector &dv, const idx_vector &idx)
Definition: Array-util.cc:618
bool all_ones(void) const
Definition: dim-vector.h:351
T::size_type numel(const T &str)
Definition: oct-string.cc:61
void err_invalid_conversion(const std::string &from, const std::string &to)
Definition: errwarn.cc:68
octave_value subsref(const std::string &type, const std::list< octave_value_list > &idx)
Definition: ov-base-diag.cc:46
SparseMatrix sparse_matrix_value(bool=false) const
ComplexNDArray complex_array_value(bool=false) const
bool is_colon_equiv(octave_idx_type n) const
Definition: idx-vector.h:584
octave_value fast_elem_extract(octave_idx_type n) const
void print_info(std::ostream &os, const std::string &prefix) const
FloatNDArray float_array_value(bool=false) const
octave_value convert_to_str_internal(bool pad, bool force, char type) const
void warn_implicit_conversion(const char *id, const char *from, const char *to)
Definition: errwarn.cc:338
octave_idx_type length(void) const
Definition: ovl.h:96
bool print_as_scalar(void) const
NDArray array_value(bool=false) const
bool save_ascii(std::ostream &os)
for i
Definition: data.cc:5264
void warn_array_as_logical(const dim_vector &dv)
Definition: errwarn.cc:282
std::complex< float > FloatComplex
Definition: oct-cmplx.h:32
Complex complex_value(bool=false) const
octave_idx_type ndims(void) const
Number of dimensions.
Definition: dim-vector.h:295
std::complex< double > Complex
Definition: oct-cmplx.h:31
ComplexMatrix complex_matrix_value(bool=false) const
FloatComplex float_complex_value(bool=false) const
write the output to stdout if nargout is
Definition: load-save.cc:1612
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
bool is_scalar(void) const
Definition: idx-vector.h:578
octave_value resize(const dim_vector &dv, bool fill=false) const
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:888
dim_vector dv
Definition: sub2ind.cc:263
octave_value next_subsref(const std::string &type, const std::list< octave_value_list > &idx, size_t skip=1)
octave::stream os
Definition: file-io.cc:627
F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T const F77_DBLE * x
static octave_value empty_conv(const std::string &type, const octave_value &rhs=octave_value())
Definition: ov.cc:2867
SparseComplexMatrix sparse_complex_matrix_value(bool=false) const
T helper_getreal(T x)
octave_value do_index_op(const octave_value_list &idx, bool resize_ok=false)
Definition: ov.h:444