Mercurial > octave
comparison libinterp/corefcn/sparse.cc @ 32058:e242124f1240
Overhaul input validation of sparse() function.
* sparse.cc (Fsparse): Decode input type and identify floating point inputs.
If input is of single type, emit new warning "Octave:sparse:double-conversion".
If input is neither floating point or logical, then call err_wrong_type_arg()
for pretty error message. Rename temporary variable 'k' to "argidx" for clarity.
New temporary variable "arg" to increase readability of code. Add FIXME note
about unreachable code due to behavior of get_dimensions().
* sparse.cc (Fissparse): Turn off warning about double-conversion temporarily
for test which has single input.
* warning_ids.m: Add description for new warning ID
"Octave:sparse:double-conversion".
* mk-sparse-tst.sh: Redo BIST tests for sparse() construction.
author | Rik <rik@octave.org> |
---|---|
date | Wed, 26 Apr 2023 10:09:09 -0700 |
parents | 87beb2f167ea |
children | bade9602c5a1 |
comparison
equal
deleted
inserted
replaced
32057:f010a32986e4 | 32058:e242124f1240 |
---|---|
60 /* | 60 /* |
61 %!assert (issparse (sparse (1)), true) | 61 %!assert (issparse (sparse (1)), true) |
62 %!assert (issparse (1), false) | 62 %!assert (issparse (1), false) |
63 %!assert (issparse (sparse (false)), true) | 63 %!assert (issparse (sparse (false)), true) |
64 %!assert (issparse (true), false) | 64 %!assert (issparse (true), false) |
65 %!assert (issparse (sparse (single ([1 2]))), true) | 65 %!test |
66 %! warning ("off", "Octave:sparse:double-conversion", "local"); | |
67 %! assert (issparse (sparse (single ([1 2]))), true); | |
66 %!assert (issparse (single ([1, 2])), false) | 68 %!assert (issparse (single ([1, 2])), false) |
67 %!assert (issparse (sparse ([1+i, 2]')), true) | 69 %!assert (issparse (sparse ([1+i, 2]')), true) |
68 %!assert (issparse ([1+i, 2]'), false) | 70 %!assert (issparse ([1+i, 2]'), false) |
69 | 71 |
70 %!assert (issparse ([]), false) | 72 %!assert (issparse ([]), false) |
79 */ | 81 */ |
80 | 82 |
81 DEFUN (sparse, args, , | 83 DEFUN (sparse, args, , |
82 doc: /* -*- texinfo -*- | 84 doc: /* -*- texinfo -*- |
83 @deftypefn {} {@var{S} =} sparse (@var{A}) | 85 @deftypefn {} {@var{S} =} sparse (@var{A}) |
86 @deftypefnx {} {@var{S} =} sparse (@var{m}, @var{n}) | |
87 @deftypefnx {} {@var{S} =} sparse (@var{i}, @var{j}, @var{sv}) | |
84 @deftypefnx {} {@var{S} =} sparse (@var{i}, @var{j}, @var{sv}, @var{m}, @var{n}) | 88 @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}) | 89 @deftypefnx {} {@var{S} =} sparse (@var{i}, @var{j}, @var{sv}, @var{m}, @var{n}, "unique") |
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}) | 90 @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 @var{A} or row, column, value | 91 Create a sparse matrix from a full matrix @var{A} or row, column, value |
90 triplets. | 92 triplets. |
91 | 93 |
92 If @var{A} is a full matrix, convert it to a sparse matrix representation, | 94 If @var{A} is a full matrix, convert it to a sparse matrix representation, |
93 removing all zero values in the process. The matrix @var{A} should be of type | 95 removing all zero values in the process. The matrix @var{A} should be of type |
94 logical or double. | 96 logical or double. |
97 | |
98 If two inputs @var{m} (rows) and @var{n} (columns) are specified then create | |
99 an empty sparse matrix with the specified dimensions. | |
95 | 100 |
96 Given the integer index vectors @var{i} and @var{j}, and a 1-by-@code{nnz} | 101 Given the integer index vectors @var{i} and @var{j}, and a 1-by-@code{nnz} |
97 vector of real or complex values @var{sv}, construct the sparse matrix | 102 vector of real or complex values @var{sv}, construct the sparse matrix |
98 @code{S(@var{i}(@var{k}),@var{j}(@var{k})) = @var{sv}(@var{k})} with overall | 103 @code{S(@var{i}(@var{k}),@var{j}(@var{k})) = @var{sv}(@var{k})} with overall |
99 dimensions @var{m} and @var{n}. If any of @var{i}, @var{j}, or @var{sv} are | 104 dimensions @var{m} and @var{n}. If any of @var{i}, @var{j}, or @var{sv} are |
109 an example of how to produce different behavior such as taking the minimum | 114 an example of how to produce different behavior such as taking the minimum |
110 instead. | 115 instead. |
111 | 116 |
112 If the option @qcode{"unique"} is given, and more than one value is specified | 117 If the option @qcode{"unique"} is given, and more than one value is specified |
113 at the same @var{i}, @var{j} indices, then only the last specified value will | 118 at the same @var{i}, @var{j} indices, then only the last specified value will |
114 be used. | 119 be used. For completeness, the option @qcode{"sum"} can be given and will |
120 be ignored as the default behavior is to sum values at repeated locations. | |
115 | 121 |
116 @code{sparse (@var{m}, @var{n})} will create an empty @var{m}x@var{n} sparse | 122 @code{sparse (@var{m}, @var{n})} will create an empty @var{m}x@var{n} sparse |
117 matrix and is equivalent to @code{sparse ([], [], [], @var{m}, @var{n})} | 123 matrix and is equivalent to @code{sparse ([], [], [], @var{m}, @var{n})} |
118 | 124 |
119 The optional final argument reserves space for @var{nzmax} values in the sparse | 125 The optional final argument reserves space for @var{nzmax} values in the sparse |
174 octave_value retval; | 180 octave_value retval; |
175 | 181 |
176 if (nargin == 1) | 182 if (nargin == 1) |
177 { | 183 { |
178 octave_value arg = args(0); | 184 octave_value arg = args(0); |
179 if (arg.islogical ()) | 185 if (arg.isfloat ()) |
186 { | |
187 if (arg.is_single_type ()) | |
188 warning_with_id ("Octave:sparse:double-conversion", | |
189 "sparse: input array cast to double"); | |
190 if (arg.iscomplex ()) | |
191 retval = arg.sparse_complex_matrix_value (); | |
192 else | |
193 retval = arg.sparse_matrix_value (); | |
194 } | |
195 else if (arg.islogical ()) | |
180 retval = arg.sparse_bool_matrix_value (); | 196 retval = arg.sparse_bool_matrix_value (); |
181 else if (arg.iscomplex ()) | |
182 retval = arg.sparse_complex_matrix_value (); | |
183 else if (arg.isnumeric ()) | |
184 retval = arg.sparse_matrix_value (); | |
185 else | 197 else |
186 err_wrong_type_arg ("sparse", arg); | 198 err_wrong_type_arg ("sparse", arg); |
187 } | 199 } |
188 else if (nargin == 2) | 200 else if (nargin == 2) |
189 { | 201 { |
190 octave_idx_type m = 0; | 202 octave_idx_type m = 0; |
191 octave_idx_type n = 0; | 203 octave_idx_type n = 0; |
192 | 204 |
193 get_dimensions (args(0), args(1), "sparse", m, n); | 205 get_dimensions (args(0), args(1), "sparse", m, n); |
194 | 206 |
207 // FIXME: this code is never active because get_dimensions() | |
208 // replaces negative dimensions with 0. | |
195 if (m < 0 || n < 0) | 209 if (m < 0 || n < 0) |
196 error ("sparse: dimensions must be non-negative"); | 210 error ("sparse: dimensions must be non-negative"); |
197 | 211 |
198 retval = SparseMatrix (m, n); | 212 retval = SparseMatrix (m, n); |
199 } | 213 } |
223 | 237 |
224 if (nargin == 5) | 238 if (nargin == 5) |
225 { | 239 { |
226 get_dimensions (args(3), args(4), "sparse", m, n); | 240 get_dimensions (args(3), args(4), "sparse", m, n); |
227 | 241 |
242 // FIXME: this code is never active because get_dimensions() | |
243 // replaces negative dimensions with 0. | |
228 if (m < 0 || n < 0) | 244 if (m < 0 || n < 0) |
229 error ("sparse: dimensions must be non-negative"); | 245 error ("sparse: dimensions must be non-negative"); |
230 } | 246 } |
231 | 247 |
232 int k = 0; // index we're checking when index_vector throws | 248 int argidx = 0; // index we're checking when index_vector throws |
233 try | 249 try |
234 { | 250 { |
235 idx_vector i = args(0).index_vector (); | 251 idx_vector i = args(0).index_vector (); |
236 k = 1; | 252 argidx = 1; |
237 idx_vector j = args(1).index_vector (); | 253 idx_vector j = args(1).index_vector (); |
238 | 254 |
239 if (args(2).islogical ()) | 255 octave_value arg = args(2); // temp var for code readability |
240 retval = SparseBoolMatrix (args(2).bool_array_value (), i, j, | 256 if (arg.isfloat ()) |
241 m, n, summation, nzmax); | 257 { |
242 else if (args(2).iscomplex ()) | 258 if (arg.is_single_type ()) |
243 retval = SparseComplexMatrix (args(2).complex_array_value(), | 259 warning_with_id ("Octave:sparse:double-conversion", |
244 i, j, m, n, summation, nzmax); | 260 "sparse: input array cast to double"); |
245 else if (args(2).isnumeric ()) | 261 if (arg.iscomplex ()) |
246 retval = SparseMatrix (args(2).array_value (), i, j, | 262 retval = SparseComplexMatrix (arg.complex_array_value (), |
247 m, n, summation, nzmax); | 263 i, j, m, n, summation, nzmax); |
264 else | |
265 retval = SparseMatrix (arg.array_value (), | |
266 i, j, m, n, summation, nzmax); | |
267 } | |
268 else if (arg.islogical ()) | |
269 retval = SparseBoolMatrix (arg.bool_array_value (), | |
270 i, j, m, n, summation, nzmax); | |
248 else | 271 else |
249 err_wrong_type_arg ("sparse", args(2)); | 272 err_wrong_type_arg ("sparse", arg); |
250 } | 273 } |
251 catch (index_exception& ie) | 274 catch (index_exception& ie) |
252 { | 275 { |
253 // Rethrow to allow more info to be reported later. | 276 // Rethrow to allow more info to be reported later. |
254 ie.set_pos_if_unset (2, k+1); | 277 ie.set_pos_if_unset (2, argidx+1); |
255 throw; | 278 throw; |
256 } | 279 } |
257 } | 280 } |
258 | 281 |
259 return retval; | 282 return retval; |