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