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