GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
dim-vector.h
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2003-2018 John W. Eaton
4 Copyirght (C) 2009, 2010 VZLU Prague
5 
6 This file is part of Octave.
7 
8 Octave is free software: you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <https://www.gnu.org/licenses/>.
21 
22 */
23 
24 #if ! defined (octave_dim_vector_h)
25 #define octave_dim_vector_h 1
26 
27 #include "octave-config.h"
28 
29 #include <cassert>
30 
31 #include <algorithm>
32 #include <initializer_list>
33 #include <string>
34 
35 #include "oct-refcount.h"
36 
37 template <typename T> class Array;
38 
39 //! Vector representing the dimensions (size) of an Array.
40 //!
41 //! A dim_vector is used to represent dimensions of an Array. It is used
42 //! on its constructor to specify its size, or when reshaping it.
43 //!
44 //! @code{.cc}
45 //! // Matrix with 10 rows and 20 columns.
46 //! Matrix m Matrix (dim_vector (10, 20));
47 //!
48 //! // Change its size to 5 rows and 40 columns.
49 //! Matrix m2 = m.reshape (dim_vector (5, 40));
50 //!
51 //! // Five dimensional Array of length 10, 20, 3, 8, 7 on each dimension.
52 //! NDArray a (dim_vector (10, 20, 3, 8, 7));
53 //!
54 //! // Uninitialized array of same size as other.
55 //! NDArray b (a.dims ());
56 //! @endcode
57 //!
58 //! The main thing to understand about this class, is that methods such as
59 //! ndims() and numel(), return the value for an Array of these dimensions,
60 //! not the actual number of elements in the dim_vector.
61 //!
62 //! @code{.cc}
63 //! dim_vector d (10, 5, 3);
64 //! octave_idx_type n = d.numel (); // returns 150
65 //! octave_idx_type nd = d.ndims (); // returns 3
66 //! @endcode
67 //!
68 //! ## Implementation details ##
69 //!
70 //! This implementation is more tricky than Array, but the big plus is that
71 //! dim_vector requires only one allocation instead of two. It is (slightly)
72 //! patterned after GCC's basic_string implementation. rep is a pointer to an
73 //! array of memory, comprising count, length, and the data:
74 //!
75 //! @verbatim
76 //! <count>
77 //! <ndims>
78 //! rep --> <dims[0]>
79 //! <dims[1]>
80 //! ...
81 //! @endverbatim
82 //!
83 //! The inlines count(), ndims() recover this data from the rep. Note
84 //! that rep points to the beginning of dims to grant faster access
85 //! (reinterpret_cast is assumed to be an inexpensive operation).
86 
87 class
88 OCTAVE_API
90 {
91 private:
92 
94 
95  octave_idx_type& count (void) const { return rep[-2]; }
96 
97  //! Construct a new rep with count = 1 and ndims given.
98 
99  static octave_idx_type * newrep (int ndims)
100  {
101  octave_idx_type *r = new octave_idx_type [ndims + 2];
102 
103  *r++ = 1;
104  *r++ = ndims;
105 
106  return r;
107  }
108 
109  //! Clone this->rep.
110 
112  {
113  int nd = ndims ();
114 
115  octave_idx_type *r = newrep (nd);
116 
117  std::copy_n (rep, nd, r);
118 
119  return r;
120  }
121 
122  //! Clone and resize this->rep to length n, filling by given value.
123 
125  {
126  int nd = ndims ();
127 
128  if (n < 2)
129  n = 2;
130 
131  octave_idx_type *r = newrep (n);
132 
133  if (nd > n)
134  nd = n;
135 
136  std::copy_n (rep, nd, r);
137  std::fill_n (r + nd, n - nd, fill_value);
138 
139  return r;
140  }
141 
142  //! Free the rep.
143 
144  void freerep (void)
145  {
146  assert (count () == 0);
147  delete [] (rep - 2);
148  }
149 
150  void make_unique (void)
151  {
152  if (count () > 1)
153  {
154  octave_idx_type *new_rep = clonerep ();
155 
156  if (OCTAVE_ATOMIC_DECREMENT (&(count ())) == 0)
157  freerep ();
158 
159  rep = new_rep;
160  }
161  }
162 
163 public:
164 
165  //! Construct dim_vector for a N dimensional array.
166  //!
167  //! Each argument to constructor defines the length of an additional
168  //! dimension. A dim_vector always represents a minimum of 2 dimensions
169  //! (just like an Array has at least 2 dimensions) and there is no
170  //! upper limit on the number of dimensions.
171  //!
172  //! @code{.cc}
173  //! dim_vector dv (7, 5);
174  //! Matrix mat (dv);
175  //! @endcode
176  //!
177  //! The constructed dim_vector @c dv will have two elements, @f$[7, 5]@f$,
178  //! one for each dimension. It can then be used to construct a Matrix
179  //! with such dimensions, i.e., 7 rows and 5 columns.
180  //!
181  //! @code{.cc}
182  //! NDArray x (dim_vector (7, 5, 10));
183  //! @endcode
184  //!
185  //! This will construct a 3 dimensional NDArray of lengths 7, 5, and 10,
186  //! on the first, second, and third dimension (rows, columns, and pages)
187  //! respectively.
188  //!
189  //! Note that that there is no constructor that accepts only one
190  //! dimension length to avoid confusion. The source for such confusion
191  //! is that constructor could mean:
192  //! - a column vector, i.e., assume @f$[N, 1]@f$;
193  //! - a square matrix, i.e., as is common in Octave interpreter;
194  //! - support for a 1 dimensional Array (does not exist);
195  //!
196  //! Using r, c, and lengths... as arguments, allow us to check at compile
197  //! time that there's at least 2 dimensions specified, while maintaining
198  //! type safety.
199 
200  template <typename... Ints>
202  Ints... lengths) : rep (newrep (2 + sizeof... (Ints)))
203  {
204  std::initializer_list<octave_idx_type> all_lengths = {r, c, lengths...};
205  for (const octave_idx_type l: all_lengths)
206  *rep++ = l;
207  rep -= all_lengths.size ();
208  }
209 
210  // Fast access with absolutely no checking
211 
212  octave_idx_type& xelem (int i) { return rep[i]; }
213 
214  octave_idx_type xelem (int i) const { return rep[i]; }
215 
216  // Safe access to to elements
217 
219  {
220  make_unique ();
221  return xelem (i);
222  }
223 
224  octave_idx_type elem (int i) const { return xelem (i); }
225 
227  {
228  int nd = ndims ();
229  if (nd > 2 && rep[nd-1] == 1)
230  {
231  make_unique ();
232  do
233  nd--;
234  while (nd > 2 && rep[nd-1] == 1);
235  rep[-1] = nd;
236  }
237  }
238 
239  void chop_all_singletons (void);
240 
241  // WARNING: Only call by jit
242  octave_idx_type * to_jit (void) const
243  {
244  return rep;
245  }
246 
247 private:
248 
249  static octave_idx_type *nil_rep (void);
250 
251 public:
252 
253  static octave_idx_type dim_max (void);
254 
255  explicit dim_vector (void) : rep (nil_rep ())
256  { OCTAVE_ATOMIC_INCREMENT (&(count ())); }
257 
259  { OCTAVE_ATOMIC_INCREMENT (&(count ())); }
260 
261  // FIXME: Should be private, but required by array constructor for jit
262  explicit dim_vector (octave_idx_type *r) : rep (r) { }
263 
264  static dim_vector alloc (int n)
265  {
266  return dim_vector (newrep (n < 2 ? 2 : n));
267  }
268 
270  {
271  if (&dv != this)
272  {
273  if (OCTAVE_ATOMIC_DECREMENT (&(count ())) == 0)
274  freerep ();
275 
276  rep = dv.rep;
277  OCTAVE_ATOMIC_INCREMENT (&(count ()));
278  }
279 
280  return *this;
281  }
282 
283  ~dim_vector (void)
284  {
285  if (OCTAVE_ATOMIC_DECREMENT (&(count ())) == 0)
286  freerep ();
287  }
288 
289  //! Number of dimensions.
290  //!
291  //! Returns the number of dimensions of the dim_vector. This is number of
292  //! elements in the dim_vector including trailing singletons. It is also
293  //! the number of dimensions an Array with this dim_vector would have.
294 
295  octave_idx_type ndims (void) const { return rep[-1]; }
296 
297  //! Number of dimensions.
298  //! Synonymous with ndims().
299  //!
300  //! While this method is not officially deprecated, consider using ndims()
301  //! instead to avoid confusion. Array does not have length because of its
302  //! odd definition as length of the longest dimension.
303 
304  int length (void) const { return ndims (); }
305 
306  octave_idx_type& operator () (int i) { return elem (i); }
307 
308  octave_idx_type operator () (int i) const { return elem (i); }
309 
310  void resize (int n, int fill_value = 0)
311  {
312  int len = ndims ();
313 
314  if (n != len)
315  {
316  octave_idx_type *r = resizerep (n, fill_value);
317 
318  if (OCTAVE_ATOMIC_DECREMENT (&(count ())) == 0)
319  freerep ();
320 
321  rep = r;
322  }
323  }
324 
325  std::string str (char sep = 'x') const;
326 
327  bool all_zero (void) const
328  {
329  return std::all_of (rep, rep + ndims (),
330  [] (octave_idx_type dim) { return dim == 0; });
331  }
332 
333  bool empty_2d (void) const
334  {
335  return ndims () == 2 && (xelem (0) == 0 || xelem (1) == 0);
336  }
337 
338  bool zero_by_zero (void) const
339  {
340  return ndims () == 2 && xelem (0) == 0 && xelem (1) == 0;
341  }
342 
343  bool any_zero (void) const
344  {
345  return std::any_of (rep, rep + ndims (),
346  [] (octave_idx_type dim) { return dim == 0; });
347  }
348 
349  int num_ones (void) const;
350 
351  bool all_ones (void) const
352  {
353  return (num_ones () == ndims ());
354  }
355 
356  //! Number of elements that a matrix with this dimensions would have.
357  //!
358  //! Return the number of elements that a matrix with this dimension
359  //! vector would have, NOT the number of dimensions (elements in the
360  //! dimension vector).
361 
362  octave_idx_type numel (int n = 0) const
363  {
364  int n_dims = ndims ();
365 
367 
368  for (int i = n; i < n_dims; i++)
369  retval *= elem (i);
370 
371  return retval;
372  }
373 
374  //! The following function will throw a std::bad_alloc ()
375  //! exception if the requested size is larger than can be indexed by
376  //! octave_idx_type. This may be smaller than the actual amount of
377  //! memory that can be safely allocated on a system. However, if we
378  //! don't fail here, we can end up with a mysterious crash inside a
379  //! function that is iterating over an array using octave_idx_type
380  //! indices.
381 
382  octave_idx_type safe_numel (void) const;
383 
384  bool any_neg (void) const
385  {
386  return std::any_of (rep, rep + ndims (),
387  [] (octave_idx_type dim) { return dim < 0; });
388  }
389 
390  dim_vector squeeze (void) const;
391 
392  //! This corresponds to cat().
393  bool concat (const dim_vector& dvb, int dim);
394 
395  //! This corresponds to [,] (horzcat, dim = 0) and [;] (vertcat, dim = 1).
396  // The rules are more relaxed here.
397  bool hvcat (const dim_vector& dvb, int dim);
398 
399  //! Force certain dimensionality, preserving numel (). Missing
400  //! dimensions are set to 1, redundant are folded into the trailing
401  //! one. If n = 1, the result is 2d and the second dim is 1
402  //! (dim_vectors are always at least 2D).
403 
404  dim_vector redim (int n) const;
405 
406  dim_vector as_column (void) const
407  {
408  if (ndims () == 2 && xelem (1) == 1)
409  return *this;
410  else
411  return dim_vector (numel (), 1);
412  }
413 
414  dim_vector as_row (void) const
415  {
416  if (ndims () == 2 && xelem (0) == 1)
417  return *this;
418  else
419  return dim_vector (1, numel ());
420  }
421 
422  bool isvector (void) const
423  {
424  return (ndims () == 2 && (xelem (0) == 1 || xelem (1) == 1));
425  }
426 
427  OCTAVE_DEPRECATED (4.4, "use 'isvector' instead")
428  bool is_vector (void) const
429  { return isvector (); }
430 
431  bool is_nd_vector (void) const
432  {
433  int num_non_one = 0;
434 
435  for (int i = 0; i < ndims (); i++)
436  {
437  if (xelem (i) != 1)
438  {
439  num_non_one++;
440 
441  if (num_non_one > 1)
442  break;
443  }
444  }
445 
446  return num_non_one == 1;
447  }
448 
449  // Create a vector with length N. If this object is a vector,
450  // preserve the orientation, otherwise, create a column vector.
451 
453  {
454  dim_vector orig_dims;
455 
456  if (is_nd_vector ())
457  {
458  orig_dims = *this;
459 
460  for (int i = 0; i < orig_dims.ndims (); i++)
461  {
462  if (orig_dims(i) != 1)
463  {
464  orig_dims(i) = n;
465  break;
466  }
467  }
468  }
469  else
470  orig_dims = dim_vector (n, 1);
471 
472  return orig_dims;
473  }
474 
475  int first_non_singleton (int def = 0) const
476  {
477  for (int i = 0; i < ndims (); i++)
478  {
479  if (xelem (i) != 1)
480  return i;
481  }
482 
483  return def;
484  }
485 
486  //! Linear index from an index tuple.
488  { return compute_index (idx, ndims ()); }
489 
490  //! Linear index from an incomplete index tuple (nidx < length ()).
491  octave_idx_type compute_index (const octave_idx_type *idx, int nidx) const
492  {
493  octave_idx_type k = 0;
494  for (int i = nidx - 1; i >= 0; i--)
495  k = rep[i] * k + idx[i];
496 
497  return k;
498  }
499 
500  //! Increment a multi-dimensional index tuple, optionally starting
501  //! from an offset position and return the index of the last index
502  //! position that was changed, or length () if just cycled over.
503 
504  int increment_index (octave_idx_type *idx, int start = 0) const
505  {
506  int i;
507  for (i = start; i < ndims (); i++)
508  {
509  if (++(*idx) == rep[i])
510  *idx++ = 0;
511  else
512  break;
513  }
514  return i;
515  }
516 
517  //! Return cumulative dimensions.
518 
519  dim_vector cumulative (void) const
520  {
521  int nd = ndims ();
522  dim_vector retval = alloc (nd);
523 
524  octave_idx_type k = 1;
525  for (int i = 0; i < nd; i++)
526  retval.rep[i] = (k *= rep[i]);
527 
528  return retval;
529  }
530 
531  //! Compute a linear index from an index tuple. Dimensions are
532  //! required to be cumulative.
533 
535  {
536  octave_idx_type k = idx[0];
537 
538  for (int i = 1; i < ndims (); i++)
539  k += rep[i-1] * idx[i];
540 
541  return k;
542  }
543 
544  friend bool operator == (const dim_vector& a, const dim_vector& b);
545 
546  Array<octave_idx_type> as_array (void) const;
547 };
548 
549 inline bool
551 {
552  // Fast case.
553  if (a.rep == b.rep)
554  return true;
555 
556  int a_len = a.ndims ();
557  int b_len = b.ndims ();
558 
559  if (a_len != b_len)
560  return false;
561 
562  return std::equal (a.rep, a.rep + a_len, b.rep);
563 }
564 
565 inline bool
567 {
568  return ! operator == (a, b);
569 }
570 
571 #endif
octave_idx_type compute_index(octave_idx_type n, const dim_vector &dims)
Definition: Array-util.cc:175
octave_idx_type compute_index(const octave_idx_type *idx, int nidx) const
Linear index from an incomplete index tuple (nidx < length ()).
Definition: dim-vector.h:491
octave_idx_type compute_index(const octave_idx_type *idx) const
Linear index from an index tuple.
Definition: dim-vector.h:487
octave_idx_type * resizerep(int n, octave_idx_type fill_value)
Clone and resize this->rep to length n, filling by given value.
Definition: dim-vector.h:124
dim_vector(const octave_idx_type r, const octave_idx_type c, Ints... lengths)
Construct dim_vector for a N dimensional array.
Definition: dim-vector.h:201
bool operator!=(const dim_vector &a, const dim_vector &b)
Definition: dim-vector.h:566
octave_idx_type xelem(int i) const
Definition: dim-vector.h:214
#define OCTAVE_ATOMIC_DECREMENT(x)
Definition: oct-refcount.h:61
octave_idx_type & count(void) const
Definition: dim-vector.h:95
bool zero_by_zero(void) const
Definition: dim-vector.h:338
Array< T > squeeze(void) const
Chop off leading singleton dimensions.
Definition: Array.cc:116
dim_vector cumulative(void) const
Return cumulative dimensions.
Definition: dim-vector.h:519
dim_vector make_nd_vector(octave_idx_type n) const
Definition: dim-vector.h:452
dim_vector as_row(void) const
Definition: dim-vector.h:414
for large enough k
Definition: lu.cc:617
void resize(int n, int fill_value=0)
Definition: dim-vector.h:310
octave_idx_type & xelem(int i)
Definition: dim-vector.h:212
ComplexNDArray concat(NDArray &ra, ComplexNDArray &rb, const Array< octave_idx_type > &ra_idx)
Definition: CNDArray.cc:653
void make_unique(void)
Definition: dim-vector.h:150
octave_idx_type & elem(int i)
Definition: dim-vector.h:218
#define OCTAVE_ATOMIC_INCREMENT(x)
Definition: oct-refcount.h:60
nd example oindent opens the file binary numeric values will be read assuming they are stored in IEEE format with the least significant bit and then converted to the native representation Opening a file that is already open simply opens it again and returns a separate file id It is not an error to open a file several though writing to the same file through several different file ids may produce unexpected results The possible values of text mode reading and writing automatically converts linefeeds to the appropriate line end character for the you may append a you must also open the file in binary mode The parameter conversions are currently only supported for and permissions will be set to and then everything is written in a single operation This is very efficient and improves performance c
Definition: file-io.cc:587
octave_base_value * rep
The real representation.
Definition: ov.h:1505
octave_idx_type * rep
Definition: dim-vector.h:93
bool any_zero(void) const
Definition: dim-vector.h:343
calling an anonymous function involves an overhead quite comparable to the overhead of an m file function Passing a handle to a built in function is because the interpreter is not involved in the internal loop For a
Definition: cellfun.cc:400
void freerep(void)
Free the rep.
Definition: dim-vector.h:144
bool is_vector(void) const
Definition: Array.h:574
int increment_index(octave_idx_type *idx, int start=0) const
Increment a multi-dimensional index tuple, optionally starting from an offset position and return the...
Definition: dim-vector.h:504
octave_idx_type * to_jit(void) const
Definition: dim-vector.h:242
void make_unique(void)
Definition: Array.h:187
std::string str
Definition: hash.cc:118
int first_non_singleton(int def=0) const
Definition: dim-vector.h:475
static int elem
Definition: __contourc__.cc:47
bool empty_2d(void) const
Definition: dim-vector.h:333
octave_value retval
Definition: data.cc:6246
bool all_zero(void) const
Definition: dim-vector.h:327
static dim_vector alloc(int n)
Definition: dim-vector.h:264
bool isvector(const dim_vector &dim)
Definition: Array-util.cc:138
octave_idx_type elem(int i) const
Definition: dim-vector.h:224
bool operator==(const dim_vector &a, const dim_vector &b)
Definition: dim-vector.h:550
T & xelem(octave_idx_type n)
Definition: Array.h:458
~dim_vector(void)
Definition: dim-vector.h:283
bool any_neg(void) const
Definition: dim-vector.h:384
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:125
bool is_nd_vector(void) const
Definition: Array.h:577
bool all_ones(void) const
Definition: dim-vector.h:351
T::size_type numel(const T &str)
Definition: oct-string.cc:61
octave::sys::time start
Definition: graphics.cc:12337
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition: dim-vector.h:362
T & operator()(octave_idx_type n)
Definition: Array.h:502
static octave_idx_type * newrep(int ndims)
Construct a new rep with count = 1 and ndims given.
Definition: dim-vector.h:99
bool isvector(void) const
Definition: dim-vector.h:422
b
Definition: cellfun.cc:400
static Array< T >::ArrayRep * nil_rep(void)
Definition: Array.cc:41
for i
Definition: data.cc:5264
octave_idx_type * clonerep(void)
Clone this->rep.
Definition: dim-vector.h:111
octave_idx_type ndims(void) const
Number of dimensions.
Definition: dim-vector.h:295
octave_idx_type num_ones(const Array< octave_idx_type > &ra_idx)
Definition: Array-util.cc:100
dim_vector(void)
Definition: dim-vector.h:255
octave_idx_type cum_compute_index(const octave_idx_type *idx) const
Compute a linear index from an index tuple.
Definition: dim-vector.h:534
bool is_nd_vector(void) const
Definition: dim-vector.h:431
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
void chop_trailing_singletons(void)
Definition: dim-vector.h:226
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:888
dim_vector as_column(void) const
Definition: dim-vector.h:406
Array< T > & operator=(const Array< T > &a)
Definition: Array.h:311
dim_vector dv
Definition: sub2ind.cc:263
dim_vector(octave_idx_type *r)
Definition: dim-vector.h:262
int length(void) const
Number of dimensions.
Definition: dim-vector.h:304
Array< T >::ArrayRep * rep
Definition: Array.h:218
dim_vector(const dim_vector &dv)
Definition: dim-vector.h:258
int ndims(void) const
Definition: Array.h:590