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-sparse.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1998-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 <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 "errwarn.h"
42#include "ls-oct-text.h"
43#include "ls-utils.h"
44#include "ls-hdf5.h"
45
46#include "boolSparse.h"
47#include "ov-base-sparse.h"
49#include "pager.h"
50#include "utils.h"
51
52#include "lo-array-errwarn.h"
53
54template <typename T>
57 bool resize_ok)
58{
59 octave_value retval;
60
61 octave_idx_type n_idx = idx.length ();
62
63 // If we catch an indexing error in index_vector, we flag an error in
64 // index k. Ensure it is the right value before each idx_vector call.
65 // Same variable as used in the for loop in the default case.
66
67 octave_idx_type k = 0;
68
69 try
70 {
71 switch (n_idx)
72 {
73 case 0:
74 retval = matrix;
75 break;
76
77 case 1:
78 {
79 octave::idx_vector i = idx (0).index_vector ();
80
81 retval = octave_value (matrix.index (i, resize_ok));
82 }
83 break;
84
85 case 2:
86 {
87 octave::idx_vector i = idx (0).index_vector ();
88
89 k = 1;
90 octave::idx_vector j = idx (1).index_vector ();
91
92 retval = octave_value (matrix.index (i, j, resize_ok));
93 }
94 break;
95
96 default:
97 error ("sparse indexing needs 1 or 2 indices");
98 }
99 }
100 catch (octave::index_exception& ie)
101 {
102 // Rethrow to allow more info to be reported later.
103 ie.set_pos_if_unset (n_idx, k+1);
104 throw;
105 }
106
107 return retval;
108}
109
110template <typename T>
112octave_base_sparse<T>::subsref (const std::string& type,
113 const std::list<octave_value_list>& idx)
114{
115 octave_value retval;
116
117 switch (type[0])
118 {
119 case '(':
120 retval = do_index_op (idx.front ());
121 break;
122
123 case '{':
124 case '.':
125 {
126 std::string nm = type_name ();
127 error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
128 }
129 break;
130
131 default:
132 error ("unexpected: index not '(', '{', or '.' in octave_base_sparse<T>::subsref - please report this bug");
133 }
134
135 return retval.next_subsref (type, idx);
136}
137
138template <typename T>
140octave_base_sparse<T>::subsasgn (const std::string& type,
141 const std::list<octave_value_list>& idx,
142 const octave_value& rhs)
143{
144 octave_value retval;
145
146 switch (type[0])
147 {
148 case '(':
149 {
150 if (type.length () != 1)
151 {
152 std::string nm = type_name ();
153 error ("in indexed assignment of %s, last lhs index must be ()",
154 nm.c_str ());
155 }
156
157 retval = numeric_assign (type, idx, rhs);
158 }
159 break;
160
161 case '{':
162 case '.':
163 {
164 if (! isempty ())
165 {
166 std::string nm = type_name ();
167 error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
168 }
169
170 octave_value tmp = octave_value::empty_conv (type, rhs);
171
172 retval = tmp.subsasgn (type, idx, rhs);
174 break;
175
176 default:
177 error ("unexpected: index not '(', '{', or '.' in octave_base_sparse<T>::subsasgn - please report this bug");
178 }
180 return retval;
181}
182
183template <typename MT>
184void
186{
187 octave_idx_type len = idx.length ();
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 octave::idx_vector i = idx (0).index_vector ();
202
203 matrix.delete_elements (i);
204
205 break;
206 }
207
208 case 2:
209 {
210 octave::idx_vector i = idx (0).index_vector ();
211
212 k = 1;
213 octave::idx_vector j = idx (1).index_vector ();
214
215 matrix.delete_elements (i, j);
216
217 break;
218 }
219
220 default:
221 error ("sparse indexing needs 1 or 2 indices");
222 }
223 }
224 catch (octave::index_exception& ie)
225 {
226 // Rethrow to allow more info to be reported later.
227 ie.set_pos_if_unset (len, k+1);
228 throw;
229 }
230
231 // Invalidate the matrix type
232 typ.invalidate_type ();
234
235template <typename T>
238{
239 T retval (matrix);
240 retval.resize (dv);
241 return retval;
242}
244template <typename T>
245bool
248 bool retval = false;
249 const dim_vector& dv = matrix.dims ();
250 octave_idx_type nel = dv.numel ();
251 octave_idx_type nz = nnz ();
253 if (nel > 0)
254 {
255 T t1 (matrix.reshape (dim_vector (nel, 1)));
256
257 if (t1.any_element_is_nan ())
258 octave::err_nan_to_logical_conversion ();
259
260 if (nel > 1)
262
263 if (nz == nel)
264 {
265 SparseBoolMatrix t2 = t1.all ();
267 retval = t2(0);
268 }
269 }
270
271 return retval;
272}
273
274template <typename T>
275bool
277{
278 const dim_vector& dv = dims ();
279
280 return (dv.all_ones () || dv.any_zero ());
281}
282
283template <typename T>
284void
285octave_base_sparse<T>::print (std::ostream& os, bool pr_as_read_syntax)
286{
287 print_raw (os, pr_as_read_syntax);
288 newline (os);
289}
290
291template <typename T>
292void
294 const std::string& prefix) const
295{
296 matrix.print_info (os, prefix);
297}
298
299template <typename T>
300void
302 bool pr_as_read_syntax) const
303{
304 octave::preserve_stream_state stream_state (os);
305
306 octave_idx_type nr = matrix.rows ();
307 octave_idx_type nc = matrix.cols ();
308 octave_idx_type nz = nnz ();
309
310 // FIXME: this should probably all be handled by a
311 // separate octave_print_internal function that can handle format
312 // compact, loose, etc.
313
314 os << "Compressed Column Sparse (rows = " << nr
315 << ", cols = " << nc
316 << ", nnz = " << nz;
317
318 // Avoid calling numel here since it can easily overflow
319 // octave_idx_type even when there is no real problem storing the
320 // sparse array.
321
322 double dnr = nr;
323 double dnc = nc;
324 double dnel = dnr * dnc;
325
326 if (dnel > 0)
327 {
328 double pct = (nz / dnel * 100);
329
330 int prec = 2;
331
332 // Display at least 2 significant figures and up to 4 as we
333 // approach 100%. Avoid having limited precision of the display
334 // result in reporting 100% for matrices that are not actually
335 // 100% full.
336
337 if (pct == 100)
338 prec = 3;
339 else
340 {
341 if (pct > 99.9)
342 prec = 4;
343 else if (pct > 99)
344 prec = 3;
345
346 if (pct > 99.99)
347 pct = 99.99;
348 }
349
350 os << " [" << std::setprecision (prec) << pct << "%]";
351 }
352
353 os << ")\n";
354
355 // add one to the printed indices to go from
356 // zero-based to one-based arrays
357
358 if (nz != 0)
359 {
360 for (octave_idx_type j = 0; j < nc; j++)
361 {
362 octave_quit ();
363
364 // FIXME: is there an easy way to get the max row
365 // and column indices so we can set the width appropriately
366 // and line up the columns here? Similarly, we should look
367 // at all the nonzero values and display them with the same
368 // formatting rules that apply to columns of a matrix.
369
370 for (octave_idx_type i = matrix.cidx (j); i < matrix.cidx (j+1); i++)
371 {
372 os << "\n";
373 os << " (" << matrix.ridx (i)+1 << ", " << j+1 << ") -> ";
374
375 octave_print_internal (os, matrix.data (i), pr_as_read_syntax);
376 }
377 }
378 }
379}
380
381template <typename MT>
384{
385 return float_display_format ();
386 // return make_format (this->matrix);
387}
388
389template <typename MT>
390std::string
393 octave_idx_type j) const
394{
395 std::ostringstream buf;
396 octave_print_internal (buf, fmt, this->matrix(i, j));
397 return buf.str ();
398}
399
400template <typename T>
401bool
403{
404 const dim_vector& dv = this->dims ();
405
406 // Ensure that additional memory is deallocated
407 matrix.maybe_compress ();
408
409 os << "# nnz: " << nnz () << "\n";
410 os << "# rows: " << dv(0) << "\n";
411 os << "# columns: " << dv(1) << "\n";
412
413 os << this->matrix;
414
415 return true;
416}
417
418template <typename T>
419bool
421{
422 octave_idx_type nz = 0;
423 octave_idx_type nr = 0;
424 octave_idx_type nc = 0;
425
426 if (! extract_keyword (is, "nnz", nz, true)
427 || ! extract_keyword (is, "rows", nr, true)
428 || ! extract_keyword (is, "columns", nc, true))
429 error ("load: failed to extract number of rows and columns");
430
431 T tmp (nr, nc, nz);
432
433 if (nz > 0)
434 {
435 is >> tmp;
436
437 if (! is)
438 error ("load: failed to load matrix constant");
439 }
440
441 matrix = tmp;
442
443 return true;
444}
445
446/*
447%!test <64696>
448%! A = B = sparse (1, 2);
449%! assert (nnz (A), 0);
450%! assert (nnz (B), 0);
451%! txt_file = [tempname(), ".dat"];
452%! unwind_protect
453%! save ("-text", txt_file, "A", "B");
454%! s = load (txt_file);
455%! unwind_protect_cleanup
456%! unlink (txt_file);
457%! end_unwind_protect
458%! assert (s.A, A);
459%! assert (s.B, B);
460*/
461
462template <typename T>
465{
466 octave_idx_type nr = matrix.rows ();
467 octave_idx_type nc = matrix.cols ();
468
469 octave_idx_type i = n % nr;
470 octave_idx_type j = n / nr;
471
472 return (i < nr && j < nc) ? octave_value (matrix(i, j)) : octave_value ();
473}
474
475template <typename T>
478{
479 if (umap == umap_xtolower || umap == umap_xtoupper)
480 return matrix;
481
482 // Try the map on the dense value.
483 // FIXME: We should probably be smarter about this, especially for the
484 // cases that are expected to return sparse matrices.
485 octave_value retval = this->full_value ().map (umap);
486
487 // Sparsify the result if possible.
488
489 switch (umap)
490 {
491 case umap_xisalnum:
492 case umap_xisalpha:
493 case umap_xisascii:
494 case umap_xiscntrl:
495 case umap_xisdigit:
496 case umap_xisgraph:
497 case umap_xislower:
498 case umap_xisprint:
499 case umap_xispunct:
500 case umap_xisspace:
501 case umap_xisupper:
502 case umap_xisxdigit:
503 // FIXME: intentionally skip this step for string mappers.
504 // Is this wanted?
505 break;
506
507 default:
508 {
509 switch (retval.builtin_type ())
510 {
511 case btyp_double:
512 retval = retval.sparse_matrix_value ();
513 break;
514
515 case btyp_complex:
516 retval = retval.sparse_complex_matrix_value ();
517 break;
518
519 case btyp_bool:
520 retval = retval.sparse_bool_matrix_value ();
521 break;
522
523 default:
524 break;
525 }
526 }
527 }
528
529 return retval;
530}
SparseBoolMatrix all(int dim=-1) const
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:90
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition dim-vector.h:331
bool any_zero() const
Definition dim-vector.h:312
bool all_ones() const
Definition dim-vector.h:320
octave_value subsref(const std::string &type, const std::list< octave_value_list > &idx)
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
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
float_display_format get_edit_display_format() const
bool print_as_scalar() 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() const
Definition ovl.h:111
SparseMatrix sparse_matrix_value(bool frc_str_conv=false) const
Definition ov.h:909
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)
SparseBoolMatrix sparse_bool_matrix_value(bool warn=false) const
Definition ov.h:916
builtin_type_t builtin_type() const
Definition ov.h:690
SparseComplexMatrix sparse_complex_matrix_value(bool frc_str_conv=false) const
Definition ov.h:913
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
std::string extract_keyword(std::istream &is, const char *keyword, const bool next_only)
@ btyp_double
Definition ov-base.h:84
@ btyp_bool
Definition ov-base.h:96
@ btyp_complex
Definition ov-base.h:86
void octave_print_internal(std::ostream &os, const float_display_format &fmt, bool d, bool pr_as_read_syntax)
F77_RET_T len
Definition xerbla.cc:61