GNU Octave  8.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
sparse.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1998-2023 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 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <cstdlib>
31 #include <string>
32 
33 #include "variables.h"
34 #include "utils.h"
35 #include "pager.h"
36 #include "defun.h"
37 #include "errwarn.h"
38 #include "quit.h"
39 #include "unwind-prot.h"
40 
41 #include "ov-re-sparse.h"
42 #include "ov-cx-sparse.h"
43 #include "ov-bool-sparse.h"
44 
46 
47 DEFUN (issparse, args, ,
48  doc: /* -*- texinfo -*-
49 @deftypefn {} {@var{tf} =} issparse (@var{x})
50 Return true if @var{x} is a sparse matrix.
51 @seealso{ismatrix}
52 @end deftypefn */)
53 {
54  if (args.length () != 1)
55  print_usage ();
56 
57  return ovl (args(0).issparse ());
58 }
59 
60 /*
61 %!assert (issparse (sparse (1)), true)
62 %!assert (issparse (1), false)
63 %!assert (issparse (sparse (false)), true)
64 %!assert (issparse (true), false)
65 %!assert (issparse (sparse (single ([1 2]))), true)
66 %!assert (issparse (single ([1, 2])), false)
67 %!assert (issparse (sparse ([1+i, 2]')), true)
68 %!assert (issparse ([1+i, 2]'), false)
69 
70 %!assert (issparse ([]), false)
71 %!assert (issparse (sparse([])), true)
72 %!assert (issparse ("test"), false)
73 %!assert (issparse (struct ("one", {1})), false)
74 %!assert (issparse (cell (1)), false)
75 
76 ## Test input validation
77 %!error issparse ()
78 %!error issparse (1,2)
79 */
80 
81 DEFUN (sparse, args, ,
82  doc: /* -*- texinfo -*-
83 @deftypefn {} {@var{s} =} sparse (@var{a})
84 @deftypefnx {} {@var{s} =} sparse (@var{i}, @var{j}, @var{sv}, @var{m}, @var{n})
85 @deftypefnx {} {@var{s} =} sparse (@var{i}, @var{j}, @var{sv})
86 @deftypefnx {} {@var{s} =} sparse (@var{m}, @var{n})
87 @deftypefnx {} {@var{s} =} sparse (@var{i}, @var{j}, @var{s}, @var{m}, @var{n}, "unique")
88 @deftypefnx {} {@var{s} =} sparse (@var{i}, @var{j}, @var{sv}, @var{m}, @var{n}, @var{nzmax})
89 Create a sparse matrix from a full matrix, or row, column, value triplets.
90 
91 If @var{a} is a full matrix, convert it to a sparse matrix representation,
92 removing all zero values in the process.
93 
94 Given the integer index vectors @var{i} and @var{j}, and a 1-by-@code{nnz}
95 vector of real or complex values @var{sv}, construct the sparse matrix
96 @code{S(@var{i}(@var{k}),@var{j}(@var{k})) = @var{sv}(@var{k})} with overall
97 dimensions @var{m} and @var{n}. If any of @var{sv}, @var{i} or @var{j} are
98 scalars, they are expanded to have a common size.
99 
100 If @var{m} or @var{n} are not specified their values are derived from the
101 maximum index in the vectors @var{i} and @var{j} as given by
102 @code{@var{m} = max (@var{i})}, @code{@var{n} = max (@var{j})}.
103 
104 @strong{Note}: if multiple values are specified with the same @var{i},
105 @var{j} indices, the corresponding value in @var{s} will be the sum of the
106 values at the repeated location. @xref{XREFaccumarray,,@code{accumarray}}, for
107 an example of how to produce different behavior such as taking the minimum
108 instead.
109 
110 If the option @qcode{"unique"} is given, and more than one value is
111 specified at the same @var{i}, @var{j} indices, then the last specified
112 value will be used.
113 
114 @code{sparse (@var{m}, @var{n})} will create an empty @var{m}x@var{n} sparse
115 matrix and is equivalent to @code{sparse ([], [], [], @var{m}, @var{n})}
116 
117 The argument @var{nzmax} is ignored but accepted for compatibility with
118 @sc{matlab}.
119 
120 Example 1 (sum at repeated indices):
121 
122 @example
123 @group
124 @var{i} = [1 1 2]; @var{j} = [1 1 2]; @var{sv} = [3 4 5];
125 sparse (@var{i}, @var{j}, @var{sv}, 3, 4)
126 @result{}
127  Compressed Column Sparse (rows = 3, cols = 4, nnz = 2 [17%])
128 
129  (1, 1) -> 7
130  (2, 2) -> 5
131 @end group
132 @end example
133 
134 Example 2 ("unique" option):
135 
136 @example
137 @group
138 @var{i} = [1 1 2]; @var{j} = [1 1 2]; @var{sv} = [3 4 5];
139 sparse (@var{i}, @var{j}, @var{sv}, 3, 4, "unique")
140 @result{}
141  Compressed Column Sparse (rows = 3, cols = 4, nnz = 2 [17%])
142 
143  (1, 1) -> 4
144  (2, 2) -> 5
145 @end group
146 @end example
147 @seealso{full, accumarray, spalloc, spdiags, speye, spones, sprand, sprandn,
148 sprandsym, spconvert, spfun}
149 @end deftypefn */)
150 {
151  int nargin = args.length ();
152 
153  if (nargin == 0 || nargin > 6)
154  print_usage ();
155 
156  octave_value retval;
157 
158  if (nargin == 1)
159  {
160  octave_value arg = args(0);
161  if (arg.islogical ())
162  retval = arg.sparse_bool_matrix_value ();
163  else if (arg.iscomplex ())
164  retval = arg.sparse_complex_matrix_value ();
165  else if (arg.isnumeric ())
166  retval = arg.sparse_matrix_value ();
167  else
168  err_wrong_type_arg ("sparse", arg);
169  }
170  else if (nargin == 2)
171  {
172  octave_idx_type m = 0;
173  octave_idx_type n = 0;
174 
175  get_dimensions (args(0), args(1), "sparse", m, n);
176 
177  if (m < 0 || n < 0)
178  error ("sparse: dimensions must be non-negative");
179 
180  retval = SparseMatrix (m, n);
181  }
182  else if (nargin >= 3)
183  {
184  bool summation = true;
185  if (nargin > 3 && args(nargin-1).is_string ())
186  {
187  std::string opt = args(nargin-1).string_value ();
188  if (opt == "unique")
189  summation = false;
190  else if (opt == "sum" || opt == "summation")
191  summation = true;
192  else
193  error ("sparse: invalid option: %s", opt.c_str ());
194 
195  nargin -= 1;
196  }
197 
198  octave_idx_type m, n, nzmax;
199  m = n = nzmax = -1;
200  if (nargin == 6)
201  {
202  nzmax = args(5).idx_type_value ();
203  nargin--;
204  }
205 
206  if (nargin == 5)
207  {
208  get_dimensions (args(3), args(4), "sparse", m, n);
209 
210  if (m < 0 || n < 0)
211  error ("sparse: dimensions must be non-negative");
212  }
213 
214  int k = 0; // index we're checking when index_vector throws
215  try
216  {
217  idx_vector i = args(0).index_vector ();
218  k = 1;
219  idx_vector j = args(1).index_vector ();
220 
221  if (args(2).islogical ())
222  retval = SparseBoolMatrix (args(2).bool_array_value (), i, j,
223  m, n, summation, nzmax);
224  else if (args(2).iscomplex ())
225  retval = SparseComplexMatrix (args(2).complex_array_value(),
226  i, j, m, n, summation, nzmax);
227  else if (args(2).isnumeric ())
228  retval = SparseMatrix (args(2).array_value (), i, j,
229  m, n, summation, nzmax);
230  else
231  err_wrong_type_arg ("sparse", args(2));
232  }
233  catch (index_exception& ie)
234  {
235  // Rethrow to allow more info to be reported later.
236  ie.set_pos_if_unset (2, k+1);
237  throw;
238  }
239  }
240 
241  return retval;
242 }
243 
244 /*
245 ## Tests for sparse constructor are in test/sparse.tst
246 %!assert (1)
247 */
248 
249 DEFUN (spalloc, args, ,
250  doc: /* -*- texinfo -*-
251 @deftypefn {} {@var{s} =} spalloc (@var{m}, @var{n}, @var{nz})
252 Create an @var{m}-by-@var{n} sparse matrix with pre-allocated space for at
253 most @var{nz} nonzero elements.
254 
255 This is useful for building a matrix incrementally by a sequence of indexed
256 assignments. Subsequent indexed assignments after @code{spalloc} will reuse
257 the pre-allocated memory, provided they are of one of the simple forms
258 
259 @itemize
260 @item @code{@var{s}(I:J) = @var{x}}
261 
262 @item @code{@var{s}(:,I:J) = @var{x}}
263 
264 @item @code{@var{s}(K:L,I:J) = @var{x}}
265 @end itemize
266 
267 @b{and} that the following conditions are met:
268 
269 @itemize
270 @item the assignment does not decrease @code{nnz (@var{S})}.
271 
272 @item after the assignment, @code{nnz (@var{S})} does not exceed @var{nz}.
273 
274 @item no index is out of bounds.
275 @end itemize
276 
277 Partial movement of data may still occur, but in general the assignment will
278 be more memory and time efficient under these circumstances. In particular,
279 it is possible to efficiently build a pre-allocated sparse matrix from a
280 contiguous block of columns.
281 
282 The amount of pre-allocated memory for a given matrix may be queried using
283 the function @code{nzmax}.
284 
285 Programming Note: Octave always reserves memory for at least one value,
286 even if @var{nz} is 0.
287 @seealso{nzmax, sparse}
288 @end deftypefn */)
289 {
290  int nargin = args.length ();
291 
292  if (nargin < 2 || nargin > 3)
293  print_usage ();
294 
295  octave_idx_type m = args(0).idx_type_value ();
296  octave_idx_type n = args(1).idx_type_value ();
297 
298  octave_idx_type nz = 0;
299  if (nargin == 3)
300  nz = args(2).idx_type_value ();
301 
302  if (m < 0 || n < 0 || nz < 0)
303  error ("spalloc: M, N, and NZ must be non-negative");
304 
305  return ovl (SparseMatrix (dim_vector (m, n), nz));
306 }
307 
308 /*
309 %!assert (issparse (spalloc (1,1)))
310 %!assert (spalloc (1,1), sparse (1,1))
311 %!test
312 %! s = spalloc (1,1,5);
313 %! assert (s, sparse (1,1));
314 %! assert (nzmax (s), 5);
315 %!assert (spalloc (1,2), sparse (1,2))
316 %!assert (spalloc (1,2,2), sparse (1,2))
317 %!assert (spalloc (2,1), sparse (2,1))
318 %!assert (spalloc (2,1,2), sparse (2,1))
319 
320 %!error spalloc ()
321 %!error spalloc (1)
322 %!error spalloc (1,2,3,4)
323 %!error <M, N, and NZ must be non-negative> spalloc (-1, 1, 1)
324 %!error <M, N, and NZ must be non-negative> spalloc (1, -1, 1)
325 %!error <M, N, and NZ must be non-negative> spalloc (1, 1, -1)
326 */
327 
OCTAVE_END_NAMESPACE(octave)
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
void set_pos_if_unset(octave_idx_type nd_arg, octave_idx_type dim_arg)
SparseMatrix sparse_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:945
bool isnumeric(void) const
Definition: ov.h:795
SparseBoolMatrix sparse_bool_matrix_value(bool warn=false) const
Definition: ov.h:952
bool iscomplex(void) const
Definition: ov.h:786
bool islogical(void) const
Definition: ov.h:780
SparseComplexMatrix sparse_complex_matrix_value(bool frc_str_conv=false) const
Definition: ov.h:949
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
OCTINTERP_API void print_usage(void)
Definition: defun-int.h:72
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:56
void error(const char *fmt,...)
Definition: error.cc:979
void err_wrong_type_arg(const char *name, const char *s)
Definition: errwarn.cc:166
class OCTAVE_API SparseMatrix
Definition: mx-fwd.h:55
class OCTAVE_API SparseComplexMatrix
Definition: mx-fwd.h:56
class OCTAVE_API SparseBoolMatrix
Definition: mx-fwd.h:57
T octave_idx_type m
Definition: mx-inlines.cc:773
octave_idx_type n
Definition: mx-inlines.cc:753
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:211
void get_dimensions(const octave_value &a, const char *warn_for, dim_vector &dim)
Definition: utils.cc:1342