GNU Octave 11.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-2026 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 // Display at least 2 significant digits, and up to 4 as we approach
331 // 100%. Avoid having limited precision of the display result in
332 // reporting 100% for matrices that are not actually 100% full.
333 int prec;
334
335 if (pct <= 99)
336 prec = 2;
337 else if (pct <= 99.9 || pct == 100)
338 prec = 3;
339 else
340 {
341 // pct is in range (99.9, 100).
342 prec = 4;
343 if (pct > 99.99)
344 pct = 99.99;
345 }
346
347 os << " [" << std::setprecision (prec) << pct << "%]";
348 }
349
350 os << ")\n";
351
352 // add one to the printed indices to go from
353 // zero-based to one-based arrays
354
355 if (nz != 0)
356 {
357 for (octave_idx_type j = 0; j < nc; j++)
358 {
359 octave_quit ();
360
361 // FIXME: is there an easy way to get the max row
362 // and column indices so we can set the width appropriately
363 // and line up the columns here? Similarly, we should look
364 // at all the nonzero values and display them with the same
365 // formatting rules that apply to columns of a matrix.
366
367 for (octave_idx_type i = matrix.cidx (j); i < matrix.cidx (j+1); i++)
368 {
369 os << "\n";
370 os << " (" << matrix.ridx (i)+1 << ", " << j+1 << ") -> ";
371
372 octave_print_internal (os, matrix.data (i), pr_as_read_syntax);
373 }
374 }
375 }
376}
377
378template <typename MT>
381{
382 return float_display_format ();
383 // return make_format (this->matrix);
384}
385
386template <typename MT>
387std::string
390 octave_idx_type j) const
391{
392 std::ostringstream buf;
393 octave_print_internal (buf, fmt, this->matrix(i, j));
394 return buf.str ();
395}
396
397template <typename T>
398bool
400{
401 const dim_vector& dv = this->dims ();
402
403 // Ensure that additional memory is deallocated
404 matrix.maybe_compress ();
405
406 os << "# nnz: " << nnz () << "\n";
407 os << "# rows: " << dv(0) << "\n";
408 os << "# columns: " << dv(1) << "\n";
409
410 os << this->matrix;
411
412 return true;
413}
414
415template <typename T>
416bool
418{
419 octave_idx_type nz = 0;
420 octave_idx_type nr = 0;
421 octave_idx_type nc = 0;
422
423 if (! extract_keyword (is, "nnz", nz, true)
424 || ! extract_keyword (is, "rows", nr, true)
425 || ! extract_keyword (is, "columns", nc, true))
426 error ("load: failed to extract number of rows and columns");
427
428 T tmp (nr, nc, nz);
429
430 if (nz > 0)
431 {
432 is >> tmp;
433
434 if (! is)
435 error ("load: failed to load matrix constant");
436 }
437
438 matrix = tmp;
439
440 return true;
441}
442
443/*
444%!test <64696>
445%! A = B = sparse (1, 2);
446%! assert (nnz (A), 0);
447%! assert (nnz (B), 0);
448%! txt_file = [tempname(), ".dat"];
449%! unwind_protect
450%! save ("-text", txt_file, "A", "B");
451%! s = load (txt_file);
452%! unwind_protect_cleanup
453%! delete ([txt_file, '*']);
454%! end_unwind_protect
455%! assert (s.A, A);
456%! assert (s.B, B);
457*/
458
459template <typename T>
462{
463 octave_idx_type nr = matrix.rows ();
464 octave_idx_type nc = matrix.cols ();
465
466 octave_idx_type i = n % nr;
467 octave_idx_type j = n / nr;
468
469 return (i < nr && j < nc) ? octave_value (matrix(i, j)) : octave_value ();
470}
471
472template <typename T>
475{
476 if (umap == umap_xtolower || umap == umap_xtoupper)
477 return matrix;
478
479 // Try the map on the dense value.
480 // FIXME: We should probably be smarter about this, especially for the
481 // cases that are expected to return sparse matrices.
482 octave_value retval = this->full_value ().map (umap);
483
484 // Sparsify the result if possible.
485
486 switch (umap)
487 {
488 case umap_xisalnum:
489 case umap_xisalpha:
490 case umap_xisascii:
491 case umap_xiscntrl:
492 case umap_xisdigit:
493 case umap_xisgraph:
494 case umap_xislower:
495 case umap_xisprint:
496 case umap_xispunct:
497 case umap_xisspace:
498 case umap_xisupper:
499 case umap_xisxdigit:
500 // FIXME: intentionally skip this step for string mappers.
501 // Is this wanted?
502 break;
503
504 default:
505 {
506 switch (retval.builtin_type ())
507 {
508 case btyp_double:
509 retval = retval.sparse_matrix_value ();
510 break;
511
512 case btyp_complex:
513 retval = retval.sparse_complex_matrix_value ();
514 break;
515
516 case btyp_bool:
517 retval = retval.sparse_bool_matrix_value ();
518 break;
519
520 default:
521 break;
522 }
523 }
524 }
525
526 return retval;
527}
SparseBoolMatrix all(int dim=-1) const
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:92
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition dim-vector.h:341
bool any_zero() const
Definition dim-vector.h:322
bool all_ones() const
Definition dim-vector.h:330
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:907
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:914
builtin_type_t builtin_type() const
Definition ov.h:688
SparseComplexMatrix sparse_complex_matrix_value(bool frc_str_conv=false) const
Definition ov.h:911
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:1008
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