GNU Octave 7.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
ov-base-mat.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 1996-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// 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 <ostream>
31#include <sstream>
32
33#include "Array-util.h"
34
35#include "Cell.h"
36#include "errwarn.h"
37#include "ovl.h"
38#include "oct-map.h"
39#include "ov-base.h"
40#include "ov-base-mat.h"
41#include "ov-base-scalar.h"
42#include "pr-output.h"
43
44template <typename MT>
46octave_base_matrix<MT>::subsref (const std::string& type,
47 const std::list<octave_value_list>& idx)
48{
49 octave_value retval;
50
51 switch (type[0])
52 {
53 case '(':
54 retval = do_index_op (idx.front ());
55 break;
56
57 case '{':
58 case '.':
59 {
60 std::string nm = type_name ();
61 error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
62 }
63 break;
64
65 default:
67 }
68
69 return retval.next_subsref (type, idx);
70}
71
72template <typename MT>
74octave_base_matrix<MT>::subsasgn (const std::string& type,
75 const std::list<octave_value_list>& idx,
76 const octave_value& rhs)
77{
78 octave_value retval;
79
80 switch (type[0])
81 {
82 case '(':
83 {
84 if (type.length () == 1)
85 retval = numeric_assign (type, idx, rhs);
86 else if (isempty ())
87 {
88 // Allow conversion of empty matrix to some other type in
89 // cases like
90 //
91 // x = []; x(i).f = rhs
92
93 if (type[1] != '.')
94 error ("invalid assignment expression");
95
97
98 retval = tmp.subsasgn (type, idx, rhs);
99 }
100 else
101 {
102 std::string nm = type_name ();
103 error ("in indexed assignment of %s, last lhs index must be ()",
104 nm.c_str ());
105 }
106 }
107 break;
108
109 case '{':
110 case '.':
111 {
112 if (! isempty ())
113 {
114 std::string nm = type_name ();
115 error ("%s cannot be indexed with %c", nm.c_str (), type[0]);
116 }
117
118 octave_value tmp = octave_value::empty_conv (type, rhs);
119
120 retval = tmp.subsasgn (type, idx, rhs);
121 }
122 break;
123
124 default:
126 }
127
128 return retval;
129}
131template <typename MT>
134 bool resize_ok)
135{
137
138 octave_idx_type n_idx = idx.length ();
139
140 int nd = matrix.ndims ();
141 const MT& cmatrix = matrix;
142
143 // If we catch an indexing error in index_vector, we flag an error in
144 // index k. Ensure it is the right value before each idx_vector call.
145 // Same variable as used in the for loop in the default case.
146
147 octave_idx_type k = 0;
148
149 try
150 {
151 switch (n_idx)
152 {
153 case 0:
154 warn_empty_index (type_name ());
155 retval = matrix;
156 break;
157
158 case 1:
159 {
160 octave::idx_vector i = idx (0).index_vector ();
161
162 // optimize single scalar index.
163 if (! resize_ok && i.is_scalar ())
164 retval = cmatrix.checkelem (i(0));
165 else
166 retval = MT (matrix.index (i, resize_ok));
168 break;
170 case 2:
172 octave::idx_vector i = idx (0).index_vector ();
173
174 k=1;
175 octave::idx_vector j = idx (1).index_vector ();
177 // optimize two scalar indices.
178 if (! resize_ok && i.is_scalar () && j.is_scalar ())
179 retval = cmatrix.checkelem (i(0), j(0));
180 else
181 retval = MT (matrix.index (i, j, resize_ok));
182 }
183 break;
184
185 default:
186 {
187 Array<octave::idx_vector> idx_vec (dim_vector (n_idx, 1));
188 bool scalar_opt = n_idx == nd && ! resize_ok;
189 const dim_vector dv = matrix.dims ();
190
191 for (k = 0; k < n_idx; k++)
192 {
193 idx_vec(k) = idx(k).index_vector ();
194
195 scalar_opt = (scalar_opt && idx_vec(k).is_scalar ());
197
198 if (scalar_opt)
199 retval = cmatrix.checkelem (conv_to_int_array (idx_vec));
200 else
201 retval = MT (matrix.index (idx_vec, resize_ok));
202 }
203 break;
204 }
205 }
206 catch (octave::index_exception& ie)
207 {
208 // Rethrow to allow more info to be reported later.
209 ie.set_pos_if_unset (n_idx, k+1);
210 throw;
211 }
212
213 return retval;
214}
215
216/*
217%% This behavior is required for Matlab compatibility.
218%!test
219%! a = [1, 2; 3, 4];
220%! assert (a(), a);
221*/
222
223template <typename MT>
224void
226{
227 octave_idx_type n_idx = idx.length ();
228
229 // If we catch an indexing error in index_vector, we flag an error in
230 // index k. Ensure it is the right value before each idx_vector call.
231 // Same variable as used in the for loop in the default case.
232
233 octave_idx_type k = 0;
234
235 try
236 {
237 switch (n_idx)
238 {
239 case 0:
241 break;
242
243 case 1:
244 {
245 octave::idx_vector i = idx (0).index_vector ();
246
247 matrix.assign (i, rhs);
248 }
249 break;
250
251 case 2:
252 {
253 octave::idx_vector i = idx (0).index_vector ();
254
255 k = 1;
256 octave::idx_vector j = idx (1).index_vector ();
257
258 matrix.assign (i, j, rhs);
259 }
260 break;
261
262 default:
263 {
264 Array<octave::idx_vector> idx_vec (dim_vector (n_idx, 1));
265
266 for (k = 0; k < n_idx; k++)
267 idx_vec(k) = idx(k).index_vector ();
268
269 matrix.assign (idx_vec, rhs);
270 }
271 break;
272 }
273 }
274 catch (octave::index_exception& ie)
275 {
276 // Rethrow to allow more info to be reported later.
277 ie.set_pos_if_unset (n_idx, k+1);
278 throw;
279 }
280
281 // Clear cache.
282 clear_cached_info ();
283}
284
285template <typename MT>
288{
289 delete typ;
290 typ = new MatrixType (_typ);
291 return *typ;
292}
293
294template <typename MT>
295void
297 typename MT::element_type rhs)
298{
299 octave_idx_type n_idx = idx.length ();
300
301 int nd = matrix.ndims ();
302
303 MT mrhs (dim_vector (1, 1), rhs);
304
305 // If we catch an indexing error in index_vector, we flag an error in
306 // index k. Ensure it is the right value before each idx_vector call.
307 // Same variable as used in the for loop in the default case.
308
309 octave_idx_type k = 0;
310
311 try
312 {
313 switch (n_idx)
314 {
315 case 0:
317 break;
318
319 case 1:
320 {
321 octave::idx_vector i = idx (0).index_vector ();
322
323 // optimize single scalar index.
324 if (i.is_scalar () && i(0) < matrix.numel ())
325 matrix(i(0)) = rhs;
326 else
327 matrix.assign (i, mrhs);
328 }
329 break;
330
331 case 2:
332 {
333 octave::idx_vector i = idx (0).index_vector ();
334
335 k = 1;
336 octave::idx_vector j = idx (1).index_vector ();
337
338 // optimize two scalar indices.
339 if (i.is_scalar () && j.is_scalar () && nd == 2
340 && i(0) < matrix.rows () && j(0) < matrix.columns ())
341 matrix(i(0), j(0)) = rhs;
342 else
343 matrix.assign (i, j, mrhs);
344 }
345 break;
346
347 default:
348 {
349 Array<octave::idx_vector> idx_vec (dim_vector (n_idx, 1));
350 bool scalar_opt = n_idx == nd;
351 const dim_vector dv = matrix.dims ().redim (n_idx);
352
353 for (k = 0; k < n_idx; k++)
354 {
355 idx_vec(k) = idx(k).index_vector ();
356
357 scalar_opt = (scalar_opt && idx_vec(k).is_scalar ()
358 && idx_vec(k)(0) < dv(k));
359 }
360
361 if (scalar_opt)
362 {
363 // optimize all scalar indices. Don't construct
364 // an index array, but rather calc a scalar index directly.
365 octave_idx_type n = 1;
366 octave_idx_type j = 0;
367 for (octave_idx_type i = 0; i < n_idx; i++)
368 {
369 j += idx_vec(i)(0) * n;
370 n *= dv (i);
371 }
372 matrix(j) = rhs;
373 }
374 else
375 matrix.assign (idx_vec, mrhs);
376 }
377 break;
378 }
379 }
380 catch (octave::index_exception& ie)
381 {
382 // Rethrow to allow more info to be reported later.
383 ie.set_pos_if_unset (n_idx, k+1);
384 throw;
385 }
386
387 // Clear cache.
388 clear_cached_info ();
389}
390
391template <typename MT>
392void
394{
395 octave_idx_type len = idx.length ();
396
398
399 for (octave_idx_type i = 0; i < len; i++)
400 ra_idx(i) = idx(i).index_vector ();
401
402 matrix.delete_elements (ra_idx);
403
404 // Clear cache.
405 clear_cached_info ();
406}
407
408template <typename MT>
410octave_base_matrix<MT>::resize (const dim_vector& dv, bool fill) const
411{
412 MT retval (matrix);
413 if (fill)
414 retval.resize (dv, 0);
415 else
416 retval.resize (dv);
417 return retval;
418}
419
420// Return true if this matrix has all true elements (non-zero, not NA/NaN).
421template <typename MT>
422bool
424{
425 bool retval = false;
426 dim_vector dv = matrix.dims ();
427 int nel = dv.numel ();
428
429 if (nel > 0)
430 {
431 MT t1 (matrix.reshape (dim_vector (nel, 1)));
432
433 if (t1.any_element_is_nan ())
435
436 if (nel > 1)
438
439 boolNDArray t2 = t1.all ();
440
441 retval = t2(0);
442 }
443
444 return retval;
445}
446
447template <typename MT>
448bool
450{
451 dim_vector dv = dims ();
452
453 return (dv.all_ones () || dv.any_zero ());
454}
455
456template <typename MT>
457void
458octave_base_matrix<MT>::print (std::ostream& os, bool pr_as_read_syntax)
459{
460 print_raw (os, pr_as_read_syntax);
461 newline (os);
462}
463
464template <typename MT>
465void
467 const std::string& prefix) const
468{
469 matrix.print_info (os, prefix);
470}
471
472template <typename MT>
473void
475{
476 if (matrix.isempty ())
477 os << "[]";
478 else if (matrix.ndims () == 2)
479 {
480 // FIXME: should this be configurable?
481 octave_idx_type max_elts = 10;
482 octave_idx_type elts = 0;
483
484 octave_idx_type nel = matrix.numel ();
485
486 octave_idx_type nr = matrix.rows ();
487 octave_idx_type nc = matrix.columns ();
488
489 os << '[';
490
491 for (octave_idx_type i = 0; i < nr; i++)
492 {
493 for (octave_idx_type j = 0; j < nc; j++)
494 {
495 std::ostringstream buf;
496 octave_print_internal (buf, matrix(j*nr+i));
497 std::string tmp = buf.str ();
498 std::size_t pos = tmp.find_first_not_of (' ');
499 if (pos != std::string::npos)
500 os << tmp.substr (pos);
501 else if (! tmp.empty ())
502 os << tmp[0];
503
504 if (++elts >= max_elts)
505 goto done;
506
507 if (j < nc - 1)
508 os << ", ";
509 }
510
511 if (i < nr - 1 && elts < max_elts)
512 os << "; ";
513 }
514
515 done:
516
517 if (nel <= max_elts)
518 os << ']';
519 }
520 else
521 os << "...";
522}
523
524template <typename MT>
527{
528 return make_format (matrix);
529}
530
531template <typename MT>
532std::string
535 octave_idx_type j) const
536{
537 std::ostringstream buf;
538 octave_print_internal (buf, fmt, matrix(i, j));
539 return buf.str ();
540}
541
542template <typename MT>
545{
546 if (n < matrix.numel ())
547 return matrix(n);
548 else
549 return octave_value ();
550}
551
552template <typename MT>
553bool
555 const octave_value& x)
556{
557 if (n < matrix.numel ())
558 {
559 // Don't use builtin_type () here to avoid an extra VM call.
560 typedef typename MT::element_type ET;
562 if (btyp == btyp_unknown) // Dead branch?
563 return false;
564
565 // Set up the pointer to the proper place.
566 void *here = reinterpret_cast<void *> (&matrix(n));
567 // Ask x to store there if it can.
568 return x.get_rep ().fast_elem_insert_self (here, btyp);
569 }
570 else
571 return false;
572}
Array< octave_idx_type > conv_to_int_array(const Array< octave::idx_vector > &a)
Definition: Array-util.cc:239
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:129
OCTAVE_API boolNDArray all(int dim=-1) const
Definition: boolNDArray.cc:61
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition: dim-vector.h:335
bool all_ones(void) const
Definition: dim-vector.h:324
OCTAVE_API dim_vector redim(int n) const
Force certain dimensionality, preserving numel ().
Definition: dim-vector.cc:226
bool any_zero(void) const
Definition: dim-vector.h:316
bool is_scalar(void) const
Definition: idx-vector.h:559
void set_pos_if_unset(octave_idx_type nd_arg, octave_idx_type dim_arg)
MatrixType matrix_type(void) const
Definition: ov-base-mat.h:135
OCTINTERP_API bool fast_elem_insert(octave_idx_type n, const octave_value &x)
Definition: ov-base-mat.cc:554
octave_value resize(const dim_vector &dv, bool fill=false) const
Definition: ov-base-mat.cc:410
OCTINTERP_API octave_value subsref(const std::string &type, const std::list< octave_value_list > &idx)
Definition: ov-base-mat.cc:46
OCTINTERP_API octave_value do_index_op(const octave_value_list &idx, bool resize_ok=false)
Definition: ov-base-mat.cc:133
OCTINTERP_API void delete_elements(const octave_value_list &idx)
Definition: ov-base-mat.cc:393
OCTINTERP_API octave_value fast_elem_extract(octave_idx_type n) const
Definition: ov-base-mat.cc:544
OCTINTERP_API void print_info(std::ostream &os, const std::string &prefix) const
Definition: ov-base-mat.cc:466
OCTINTERP_API bool print_as_scalar(void) const
Definition: ov-base-mat.cc:449
OCTINTERP_API void print(std::ostream &os, bool pr_as_read_syntax=false)
Definition: ov-base-mat.cc:458
OCTINTERP_API float_display_format get_edit_display_format(void) const
Definition: ov-base-mat.cc:526
OCTINTERP_API void short_disp(std::ostream &os) const
Definition: ov-base-mat.cc:474
OCTINTERP_API void assign(const octave_value_list &idx, const MT &rhs)
Definition: ov-base-mat.cc:225
OCTINTERP_API bool is_true(void) const
Definition: ov-base-mat.cc:423
OCTINTERP_API octave_value subsasgn(const std::string &type, const std::list< octave_value_list > &idx, const octave_value &rhs)
Definition: ov-base-mat.cc:74
OCTINTERP_API std::string edit_display(const float_display_format &fmt, octave_idx_type i, octave_idx_type j) const
Definition: ov-base-mat.cc:533
octave_idx_type length(void) const
Definition: ovl.h:113
static OCTINTERP_API octave_value empty_conv(const std::string &type, const octave_value &rhs=octave_value())
OCTINTERP_API octave_value next_subsref(const std::string &type, const std::list< octave_value_list > &idx, std::size_t skip=1)
OCTINTERP_API 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:980
#define panic_impossible()
Definition: error.h:411
void warn_empty_index(const std::string &type_name)
Definition: errwarn.cc:336
void warn_array_as_logical(const dim_vector &dv)
Definition: errwarn.cc:286
F77_RET_T const F77_DBLE * x
void err_nan_to_logical_conversion(void)
const octave_base_value const Array< octave_idx_type > & ra_idx
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
builtin_type_t
Definition: ov-base.h:75
@ btyp_unknown
Definition: ov-base.h:93
void octave_print_internal(std::ostream &os, const float_display_format &fmt, bool d, bool pr_as_read_syntax)
Definition: pr-output.cc:1762
float_display_format make_format(const double &d)
Definition: pr-output.cc:525
F77_RET_T len
Definition: xerbla.cc:61