GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
ov-base-sparse.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1998-2021 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 <iomanip>
31 #include <istream>
32 #include <ostream>
33 #include <sstream>
34 
35 #include "ovl.h"
36 #include "ov-base.h"
37 #include "quit.h"
38 #include "pr-output.h"
39 
40 #include "byte-swap.h"
41 #include "ls-oct-text.h"
42 #include "ls-utils.h"
43 #include "ls-hdf5.h"
44 
45 #include "boolSparse.h"
46 #include "ov-base-sparse.h"
48 #include "pager.h"
49 #include "utils.h"
50 
51 #include "lo-array-errwarn.h"
52 
53 template <typename T>
56  bool resize_ok)
57 {
59 
60  octave_idx_type n_idx = idx.length ();
61 
62  // If we catch an indexing error in index_vector, we flag an error in
63  // index k. Ensure it is the right value before each idx_vector call.
64  // Same variable as used in the for loop in the default case.
65 
66  octave_idx_type k = 0;
67 
68  try
69  {
70  switch (n_idx)
71  {
72  case 0:
73  retval = matrix;
74  break;
75 
76  case 1:
77  {
78  idx_vector i = idx (0).index_vector ();
79 
80  retval = octave_value (matrix.index (i, resize_ok));
81  }
82  break;
83 
84  case 2:
85  {
86  idx_vector i = idx (0).index_vector ();
87 
88  k = 1;
89  idx_vector j = idx (1).index_vector ();
90 
91  retval = octave_value (matrix.index (i, j, resize_ok));
92  }
93  break;
94 
95  default:
96  error ("sparse indexing needs 1 or 2 indices");
97  }
98  }
99  catch (octave::index_exception& e)
100  {
101  // Rethrow to allow more info to be reported later.
102  e.set_pos_if_unset (n_idx, k+1);
103  throw;
104  }
105 
106  return retval;
107 }
108 
109 template <typename T>
112  const std::list<octave_value_list>& idx)
113 {
115 
116  switch (type[0])
117  {
118  case '(':
119  retval = do_index_op (idx.front ());
120  break;
121 
122  case '{':
123  case '.':
124  {
125  std::string nm = type_name ();
126  error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
127  }
128  break;
129 
130  default:
131  panic_impossible ();
132  }
133 
134  return retval.next_subsref (type, idx);
135 }
136 
137 template <typename T>
140  const std::list<octave_value_list>& idx,
141  const octave_value& rhs)
142 {
144 
145  switch (type[0])
146  {
147  case '(':
148  {
149  if (type.length () != 1)
150  {
151  std::string nm = type_name ();
152  error ("in indexed assignment of %s, last lhs index must be ()",
153  nm.c_str ());
154  }
155 
156  retval = numeric_assign (type, idx, rhs);
157  }
158  break;
159 
160  case '{':
161  case '.':
162  {
163  if (! isempty ())
164  {
165  std::string nm = type_name ();
166  error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
167  }
168 
170 
171  retval = tmp.subsasgn (type, idx, rhs);
172  }
173  break;
174 
175  default:
176  panic_impossible ();
177  }
178 
179  return retval;
180 }
181 
182 template <typename T>
183 void
185 {
186 
187  octave_idx_type len = idx.length ();
188 
189  // If we catch an indexing error in index_vector, we flag an error in
190  // index k. Ensure it is the right value before each idx_vector call.
191  // Same variable as used in the for loop in the default case.
192 
193  octave_idx_type k = 0;
194 
195  try
196  {
197  switch (len)
198  {
199  case 1:
200  {
201  idx_vector i = idx (0).index_vector ();
202 
203  matrix.assign (i, rhs);
204 
205  break;
206  }
207 
208  case 2:
209  {
210  idx_vector i = idx (0).index_vector ();
211 
212  k = 1;
213  idx_vector j = idx (1).index_vector ();
214 
215  matrix.assign (i, j, rhs);
216 
217  break;
218  }
219 
220  default:
221  error ("sparse indexing needs 1 or 2 indices");
222  }
223  }
224  catch (octave::index_exception& e)
225  {
226  // Rethrow to allow more info to be reported later.
227  e.set_pos_if_unset (len, k+1);
228  throw;
229  }
230 
231  // Invalidate matrix type.
232  typ.invalidate_type ();
233 }
234 
235 template <typename MT>
236 void
238 {
239  octave_idx_type len = idx.length ();
240 
241  // If we catch an indexing error in index_vector, we flag an error in
242  // index k. Ensure it is the right value before each idx_vector call.
243  // Same variable as used in the for loop in the default case.
244 
245  octave_idx_type k = 0;
246 
247  try
248  {
249  switch (len)
250  {
251  case 1:
252  {
253  idx_vector i = idx (0).index_vector ();
254 
255  matrix.delete_elements (i);
256 
257  break;
258  }
259 
260  case 2:
261  {
262  idx_vector i = idx (0).index_vector ();
263 
264  k = 1;
265  idx_vector j = idx (1).index_vector ();
266 
267  matrix.delete_elements (i, j);
268 
269  break;
270  }
271 
272  default:
273  error ("sparse indexing needs 1 or 2 indices");
274  }
275  }
276  catch (octave::index_exception& e)
277  {
278  // Rethrow to allow more info to be reported later.
279  e.set_pos_if_unset (len, k+1);
280  throw;
281  }
282 
283  // Invalidate the matrix type
284  typ.invalidate_type ();
285 }
286 
287 template <typename T>
290 {
291  T retval (matrix);
292  retval.resize (dv);
293  return retval;
294 }
295 
296 template <typename T>
297 bool
299 {
300  bool retval = false;
301  dim_vector dv = matrix.dims ();
302  octave_idx_type nel = dv.numel ();
303  octave_idx_type nz = nnz ();
304 
305  if (nel > 0)
306  {
307  T t1 (matrix.reshape (dim_vector (nel, 1)));
308 
309  if (t1.any_element_is_nan ())
311 
312  if (nel > 1)
314 
315  if (nz == nel)
316  {
317  SparseBoolMatrix t2 = t1.all ();
318 
319  retval = t2(0);
320  }
321  }
322 
323  return retval;
324 }
325 
326 template <typename T>
327 bool
329 {
330  dim_vector dv = dims ();
331 
332  return (dv.all_ones () || dv.any_zero ());
333 }
334 
335 template <typename T>
336 void
337 octave_base_sparse<T>::print (std::ostream& os, bool pr_as_read_syntax)
338 {
339  print_raw (os, pr_as_read_syntax);
340  newline (os);
341 }
342 
343 template <typename T>
344 void
346  const std::string& prefix) const
347 {
348  matrix.print_info (os, prefix);
349 }
350 
351 template <typename T>
352 void
354  bool pr_as_read_syntax) const
355 {
356  octave::preserve_stream_state stream_state (os);
357 
358  octave_idx_type nr = matrix.rows ();
359  octave_idx_type nc = matrix.cols ();
360  octave_idx_type nz = nnz ();
361 
362  // FIXME: this should probably all be handled by a
363  // separate octave_print_internal function that can handle format
364  // compact, loose, etc.
365 
366  os << "Compressed Column Sparse (rows = " << nr
367  << ", cols = " << nc
368  << ", nnz = " << nz;
369 
370  // Avoid calling numel here since it can easily overflow
371  // octave_idx_type even when there is no real problem storing the
372  // sparse array.
373 
374  double dnr = nr;
375  double dnc = nc;
376  double dnel = dnr * dnc;
377 
378  if (dnel > 0)
379  {
380  double pct = (nz / dnel * 100);
381 
382  int prec = 2;
383 
384  // Display at least 2 significant figures and up to 4 as we
385  // approach 100%. Avoid having limited precision of the display
386  // result in reporting 100% for matrices that are not actually
387  // 100% full.
388 
389  if (pct == 100)
390  prec = 3;
391  else
392  {
393  if (pct > 99.9)
394  prec = 4;
395  else if (pct > 99)
396  prec = 3;
397 
398  if (pct > 99.99)
399  pct = 99.99;
400  }
401 
402  os << " [" << std::setprecision (prec) << pct << "%]";
403  }
404 
405  os << ")\n";
406 
407  // add one to the printed indices to go from
408  // zero-based to one-based arrays
409 
410  if (nz != 0)
411  {
412  for (octave_idx_type j = 0; j < nc; j++)
413  {
414  octave_quit ();
415 
416  // FIXME: is there an easy way to get the max row
417  // and column indices so we can set the width appropriately
418  // and line up the columns here? Similarly, we should look
419  // at all the nonzero values and display them with the same
420  // formatting rules that apply to columns of a matrix.
421 
422  for (octave_idx_type i = matrix.cidx (j); i < matrix.cidx (j+1); i++)
423  {
424  os << "\n";
425  os << " (" << matrix.ridx (i)+1 << ", " << j+1 << ") -> ";
426 
427  octave_print_internal (os, matrix.data (i), pr_as_read_syntax);
428  }
429  }
430  }
431 }
432 
433 template <typename MT>
436 {
437  return float_display_format ();
438  // return make_format (this->matrix);
439 }
440 
441 template <typename MT>
442 std::string
444  octave_idx_type i,
445  octave_idx_type j) const
446 {
447  std::ostringstream buf;
448  octave_print_internal (buf, fmt, this->matrix(i,j));
449  return buf.str ();
450 }
451 
452 template <typename T>
453 bool
455 {
456  dim_vector dv = this->dims ();
457 
458  // Ensure that additional memory is deallocated
459  matrix.maybe_compress ();
460 
461  os << "# nnz: " << nnz () << "\n";
462  os << "# rows: " << dv(0) << "\n";
463  os << "# columns: " << dv(1) << "\n";
464 
465  os << this->matrix;
466 
467  return true;
468 }
469 
470 template <typename T>
471 bool
473 {
474  octave_idx_type nz = 0;
475  octave_idx_type nr = 0;
476  octave_idx_type nc = 0;
477 
478  if (! extract_keyword (is, "nnz", nz, true)
479  || ! extract_keyword (is, "rows", nr, true)
480  || ! extract_keyword (is, "columns", nc, true))
481  error ("load: failed to extract number of rows and columns");
482 
483  T tmp (nr, nc, nz);
484 
485  is >> tmp;
486 
487  if (! is)
488  error ("load: failed to load matrix constant");
489 
490  matrix = tmp;
491 
492  return true;
493 }
494 
495 template <typename T>
498 {
499  octave_idx_type nr = matrix.rows ();
500  octave_idx_type nc = matrix.cols ();
501 
502  octave_idx_type i = n % nr;
503  octave_idx_type j = n / nr;
504 
505  return (i < nr && j < nc) ? octave_value (matrix(i,j)) : octave_value ();
506 }
507 
508 template <typename T>
511 {
512  if (umap == umap_xtolower || umap == umap_xtoupper)
513  return matrix;
514 
515  // Try the map on the dense value.
516  // FIXME: We should probably be smarter about this, especially for the
517  // cases that are expected to return sparse matrices.
518  octave_value retval = this->full_value ().map (umap);
519 
520  // Sparsify the result if possible.
521 
522  switch (umap)
523  {
524  case umap_xisalnum:
525  case umap_xisalpha:
526  case umap_xisascii:
527  case umap_xiscntrl:
528  case umap_xisdigit:
529  case umap_xisgraph:
530  case umap_xislower:
531  case umap_xisprint:
532  case umap_xispunct:
533  case umap_xisspace:
534  case umap_xisupper:
535  case umap_xisxdigit:
536  // FIXME: intentionally skip this step for string mappers.
537  // Is this wanted?
538  break;
539 
540  default:
541  {
542  switch (retval.builtin_type ())
543  {
544  case btyp_double:
545  retval = retval.sparse_matrix_value ();
546  break;
547 
548  case btyp_complex:
549  retval = retval.sparse_complex_matrix_value ();
550  break;
551 
552  case btyp_bool:
553  retval = retval.sparse_bool_matrix_value ();
554  break;
555 
556  default:
557  break;
558  }
559  }
560  }
561 
562  return retval;
563 }
Array< U > map(F fcn) const
Apply function fcn to each element of the Array<T>.
Definition: Array.h:759
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
Definition: Array.cc:1011
SparseBoolMatrix all(int dim=-1) const
Definition: boolSparse.cc:140
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:95
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition: dim-vector.h:401
bool all_ones(void) const
Definition: dim-vector.h:390
bool any_zero(void) const
Definition: dim-vector.h:382
void set_pos_if_unset(octave_idx_type nd_arg, octave_idx_type dim_arg)
bool print_as_scalar(void) const
float_display_format get_edit_display_format(void) const
virtual octave_value subsref(const std::string &type, const std::list< octave_value_list > &idx)
Definition: ov-base.cc:201
void print(std::ostream &os, bool pr_as_read_syntax=false)
bool load_ascii(std::istream &is)
void print_raw(std::ostream &os, bool pr_as_read_syntax=false) const
virtual void assign(const std::string &, const octave_value &)
Definition: ov-base.h:302
bool save_ascii(std::ostream &os)
octave_value fast_elem_extract(octave_idx_type n) const
octave_value subsasgn(const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
void delete_elements(const octave_value_list &idx)
octave_value map(octave_base_value::unary_mapper_t umap) const
bool is_true(void) const
octave_value resize(const dim_vector &dv, bool=false) const
void print_info(std::ostream &os, const std::string &prefix) const
octave_value do_index_op(const octave_value_list &idx, bool resize_ok=false)
std::string edit_display(const float_display_format &fmt, octave_idx_type i, octave_idx_type j) const
octave_idx_type length(void) const
Definition: ovl.h:113
static octave_value empty_conv(const std::string &type, const octave_value &rhs=octave_value())
Definition: ov.cc:2887
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:968
#define panic_impossible()
Definition: error.h:380
void warn_array_as_logical(const dim_vector &dv)
Definition: errwarn.cc:286
std::string extract_keyword(std::istream &is, const char *keyword, const bool next_only)
Definition: ls-oct-text.cc:84
octave_idx_type n
Definition: mx-inlines.cc:753
void err_nan_to_logical_conversion(void)
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
@ btyp_double
Definition: ov-base.h:73
@ btyp_bool
Definition: ov-base.h:85
@ btyp_complex
Definition: ov-base.h:75
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811
void octave_print_internal(std::ostream &os, const float_display_format &fmt, bool d, bool pr_as_read_syntax)
Definition: pr-output.cc:1762
F77_RET_T len
Definition: xerbla.cc:61