GNU Octave 7.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-2022 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
45OCTAVE_NAMESPACE_BEGIN
46
47DEFUN (issparse, args, ,
48 doc: /* -*- texinfo -*-
49@deftypefn {} {} issparse (@var{x})
50Return 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
81DEFUN (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})
89Create a sparse matrix from a full matrix, or row, column, value triplets.
90
91If @var{a} is a full matrix, convert it to a sparse matrix representation,
92removing all zero values in the process.
93
94Given the integer index vectors @var{i} and @var{j}, and a 1-by-@code{nnz}
95vector 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
97dimensions @var{m} and @var{n}. If any of @var{sv}, @var{i} or @var{j} are
98scalars, they are expanded to have a common size.
99
100If @var{m} or @var{n} are not specified their values are derived from the
101maximum 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
106values at the repeated location. @xref{XREFaccumarray,,@code{accumarray}}, for
107an example of how to produce different behavior such as taking the minimum
108instead.
109
110If the option @qcode{"unique"} is given, and more than one value is
111specified at the same @var{i}, @var{j} indices, then the last specified
112value will be used.
113
114@code{sparse (@var{m}, @var{n})} will create an empty @var{m}x@var{n} sparse
115matrix and is equivalent to @code{sparse ([], [], [], @var{m}, @var{n})}
116
117The argument @var{nzmax} is ignored but accepted for compatibility with
118@sc{matlab}.
119
120Example 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];
125sparse (@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
134Example 2 ("unique" option):
135
136@example
137@group
138@var{i} = [1 1 2]; @var{j} = [1 1 2]; @var{sv} = [3 4 5];
139sparse (@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,
148sprandsym, 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 // Temporarily disable sparse_auto_mutate if set (it's obsolete anyway).
159 unwind_protect_var<bool> restore_var (Vsparse_auto_mutate, false);
160
161 if (nargin == 1)
162 {
163 octave_value arg = args(0);
164 if (arg.islogical ())
165 retval = arg.sparse_bool_matrix_value ();
166 else if (arg.iscomplex ())
167 retval = arg.sparse_complex_matrix_value ();
168 else if (arg.isnumeric ())
169 retval = arg.sparse_matrix_value ();
170 else
171 err_wrong_type_arg ("sparse", arg);
172 }
173 else if (nargin == 2)
174 {
175 octave_idx_type m = 0;
176 octave_idx_type n = 0;
177
178 get_dimensions (args(0), args(1), "sparse", m, n);
179
180 if (m < 0 || n < 0)
181 error ("sparse: dimensions must be non-negative");
182
183 retval = SparseMatrix (m, n);
184 }
185 else if (nargin >= 3)
186 {
187 bool summation = true;
188 if (nargin > 3 && args(nargin-1).is_string ())
189 {
190 std::string opt = args(nargin-1).string_value ();
191 if (opt == "unique")
192 summation = false;
193 else if (opt == "sum" || opt == "summation")
194 summation = true;
195 else
196 error ("sparse: invalid option: %s", opt.c_str ());
197
198 nargin -= 1;
199 }
200
201 octave_idx_type m, n, nzmax;
202 m = n = nzmax = -1;
203 if (nargin == 6)
204 {
205 nzmax = args(5).idx_type_value ();
206 nargin--;
207 }
208
209 if (nargin == 5)
210 {
211 get_dimensions (args(3), args(4), "sparse", m, n);
212
213 if (m < 0 || n < 0)
214 error ("sparse: dimensions must be non-negative");
215 }
216
217 int k = 0; // index we're checking when index_vector throws
218 try
219 {
220 idx_vector i = args(0).index_vector ();
221 k = 1;
222 idx_vector j = args(1).index_vector ();
223
224 if (args(2).islogical ())
225 retval = SparseBoolMatrix (args(2).bool_array_value (), i, j,
226 m, n, summation, nzmax);
227 else if (args(2).iscomplex ())
228 retval = SparseComplexMatrix (args(2).complex_array_value(),
229 i, j, m, n, summation, nzmax);
230 else if (args(2).isnumeric ())
231 retval = SparseMatrix (args(2).array_value (), i, j,
232 m, n, summation, nzmax);
233 else
234 err_wrong_type_arg ("sparse", args(2));
235 }
236 catch (index_exception& ie)
237 {
238 // Rethrow to allow more info to be reported later.
239 ie.set_pos_if_unset (2, k+1);
240 throw;
241 }
242 }
243
244 return retval;
245}
246
247/*
248## Tests for sparse constructor are in test/sparse.tst
249%!assert (1)
250*/
251
252DEFUN (spalloc, args, ,
253 doc: /* -*- texinfo -*-
254@deftypefn {} {@var{s} =} spalloc (@var{m}, @var{n}, @var{nz})
255Create an @var{m}-by-@var{n} sparse matrix with pre-allocated space for at
256most @var{nz} nonzero elements.
257
258This is useful for building a matrix incrementally by a sequence of indexed
259assignments. Subsequent indexed assignments after @code{spalloc} will reuse
260the pre-allocated memory, provided they are of one of the simple forms
261
262@itemize
263@item @code{@var{s}(I:J) = @var{x}}
264
265@item @code{@var{s}(:,I:J) = @var{x}}
266
267@item @code{@var{s}(K:L,I:J) = @var{x}}
268@end itemize
269
270@b{and} that the following conditions are met:
271
272@itemize
273@item the assignment does not decrease @code{nnz (@var{S})}.
274
275@item after the assignment, @code{nnz (@var{S})} does not exceed @var{nz}.
276
277@item no index is out of bounds.
278@end itemize
279
280Partial movement of data may still occur, but in general the assignment will
281be more memory and time efficient under these circumstances. In particular,
282it is possible to efficiently build a pre-allocated sparse matrix from a
283contiguous block of columns.
284
285The amount of pre-allocated memory for a given matrix may be queried using
286the function @code{nzmax}.
287
288Programming Note: Octave always reserves memory for at least one value,
289even if @var{nz} is 0.
290@seealso{nzmax, sparse}
291@end deftypefn */)
292{
293 int nargin = args.length ();
294
295 if (nargin < 2 || nargin > 3)
296 print_usage ();
297
298 octave_idx_type m = args(0).idx_type_value ();
299 octave_idx_type n = args(1).idx_type_value ();
300
301 octave_idx_type nz = 0;
302 if (nargin == 3)
303 nz = args(2).idx_type_value ();
304
305 if (m < 0 || n < 0 || nz < 0)
306 error ("spalloc: M, N, and NZ must be non-negative");
307
308 return ovl (SparseMatrix (dim_vector (m, n), nz));
309}
310
311/*
312%!assert (issparse (spalloc (1,1)))
313%!assert (spalloc (1,1), sparse (1,1))
314%!test
315%! s = spalloc (1,1,5);
316%! assert (s, sparse (1,1));
317%! assert (nzmax (s), 5);
318%!assert (spalloc (1,2), sparse (1,2))
319%!assert (spalloc (1,2,2), sparse (1,2))
320%!assert (spalloc (2,1), sparse (2,1))
321%!assert (spalloc (2,1,2), sparse (2,1))
322
323%!error spalloc ()
324%!error spalloc (1)
325%!error spalloc (1,2,3,4)
326%!error <M, N, and NZ must be non-negative> spalloc (-1, 1, 1)
327%!error <M, N, and NZ must be non-negative> spalloc (1, -1, 1)
328%!error <M, N, and NZ must be non-negative> spalloc (1, 1, -1)
329*/
330
331OCTAVE_NAMESPACE_END
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
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
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:980
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
bool Vsparse_auto_mutate
Definition: ov-base.cc:103
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:1339