GNU Octave  4.0.0
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-2015 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 <cassert>
28 #include <limits>
29 
30 #include <sstream>
31 #include <string>
32 
33 #include "lo-error.h"
34 #include "lo-macros.h"
35 #include "oct-refcount.h"
36 
37 // Rationale: This implementation is more tricky than Array, but the
38 // big plus is that dim_vector requires only one allocation instead of
39 // two. It is (slightly) patterned after GCC's basic_string
40 // implementation. rep is a pointer to an array of memory, comprising
41 // count, length, and the data:
42 //
43 // <count>
44 // <ndims>
45 // rep --> <dims[0]>
46 // <dims[1]>
47 // ...
48 //
49 // The inlines count(), ndims() recover this data from the rep. Note
50 // that rep points to the beginning of dims to grant faster access
51 // (reinterpret_cast is assumed to be an inexpensive operation).
52 
53 class
54 OCTAVE_API
56 {
57 private:
58 
60 
61  octave_idx_type& ndims (void) const { return rep[-1]; }
62 
63  octave_idx_type& count (void) const { return rep[-2]; }
64 
65  //! Construct a new rep with count = 1 and ndims given.
66 
67  static octave_idx_type *newrep (int ndims)
68  {
69  octave_idx_type *r = new octave_idx_type [ndims + 2];
70 
71  *r++ = 1;
72  *r++ = ndims;
73 
74  return r;
75  }
76 
77  //! Clone this->rep.
78 
80  {
81  int l = ndims ();
82 
83  octave_idx_type *r = new octave_idx_type [l + 2];
84 
85  *r++ = 1;
86  *r++ = l;
87 
88  for (int i = 0; i < l; i++)
89  r[i] = rep[i];
90 
91  return r;
92  }
93 
94  //! Clone and resize this->rep to length n, filling by given value.
95 
97  {
98  int l = ndims ();
99 
100  if (n < 2)
101  n = 2;
102 
103  octave_idx_type *r = new octave_idx_type [n + 2];
104 
105  *r++ = 1;
106  *r++ = n;
107 
108  if (l > n)
109  l = n;
110 
111  int j;
112  for (j = 0; j < l; j++)
113  r[j] = rep[j];
114  for (; j < n; j++)
115  r[j] = fill_value;
116 
117  return r;
118  }
119 
120  //! Free the rep.
121 
122  void freerep (void)
123  {
124  assert (count () == 0);
125  delete [] (rep - 2);
126  }
127 
128  void make_unique (void)
129  {
130  if (count () > 1)
131  {
132  octave_idx_type *new_rep = clonerep ();
133 
134  if (OCTREFCOUNT_ATOMIC_DECREMENT(&(count())) == 0)
135  freerep ();
136 
137  rep = new_rep;
138  }
139  }
140 
141 public:
142 
143 // There are constructors for up to 7 dimensions initialized this way.
144 // More can be added if necessary.
145 #define ASSIGN_REP(i) rep[i] = d ## i;
146 #define DIM_VECTOR_CTOR(N) \
147  dim_vector (OCT_MAKE_DECL_LIST (octave_idx_type, d, N)) \
148  : rep (newrep (N)) \
149  { \
150  OCT_ITERATE_MACRO (ASSIGN_REP, N) \
151  }
152 
153  //! Construct dim_vector for 2 dimensional array.
154  /*!
155  It can be used to construct a 2D array. Example:
156 
157  @code{.cc}
158  dim_vector dv (7, 5);
159  Matrix mat (dv);
160  @endcode
161 
162  The constructed dim_vector @c dv will have two elements, @f$[7, 5]@f$,
163  one for each dimension. It can then be used to construct a Matrix
164  with such dimensions, i.e., 7 rows and 5 columns.
165 
166  There are constructors available for up to 7 dimensions. For a higher
167  number of dimensions, use redim() or resize().
168 
169  Note that that there is no constructor for a 1 element dim_vector.
170  This is because there are no 1 dimensional Array in liboctave. Such
171  constructor did exist in liboctave but was removed in version 4.0.0
172  due to its potential for confusion.
173  */
175 
176  //! Construct dim_vector for 3 dimensional array.
177  /*!
178  It can be used to construct a 3D array. Example:
179 
180  @code{.cc}
181  NDArray A (dim_vector (7, 5, 4));
182  @endcode
183 
184  This will construct a 3 dimensional NDArray of lengths 7, 5, and 4,
185  on the first, second, and third dimension (rows, columns, and pages)
186  respectively.
187  */
189 
190  //! Construct dim_vector for 4 dimensional array.
191  //! @see dim_vector(octave_idx_type d0, octave_idx_type d1)
193  //! Construct dim_vector for 5 dimensional array.
194  //! @see dim_vector(octave_idx_type d0, octave_idx_type d1)
195  DIM_VECTOR_CTOR (5)
196  //! Construct dim_vector for 6 dimensional array.
197  //! @see dim_vector(octave_idx_type d0, octave_idx_type d1)
198  DIM_VECTOR_CTOR (6)
199  //! Construct dim_vector for 7 dimensional array.
200  //! @see dim_vector(octave_idx_type d0, octave_idx_type d1)
201  DIM_VECTOR_CTOR (7)
202 
203 #undef ASSIGN_REP
204 #undef DIM_VECTOR_CTOR
205 
207  {
208 #ifdef BOUNDS_CHECKING
209  assert (i >= 0 && i < ndims ());
210 #endif
211  make_unique ();
212  return rep[i];
213  }
215  octave_idx_type elem (int i) const
216  {
217 #ifdef BOUNDS_CHECKING
218  assert (i >= 0 && i < ndims ());
219 #endif
220  return rep[i];
221  }
222 
223  void chop_trailing_singletons (void)
224  {
225  int l = ndims ();
226  if (l > 2 && rep[l-1] == 1)
227  {
228  make_unique ();
229  do
230  l--;
231  while (l > 2 && rep[l-1] == 1);
232  ndims () = l;
233  }
234  }
235 
236  void chop_all_singletons (void);
238  // WARNING: Only call by jit
239  octave_idx_type *to_jit (void) const
240  {
241  return rep;
242  }
243 
244 private:
245 
246  static octave_idx_type *nil_rep (void)
247  {
248  static dim_vector zv (0, 0);
249  return zv.rep;
250  }
251 
252 public:
253 
254  static octave_idx_type dim_max (void);
255 
256  explicit dim_vector (void) : rep (nil_rep ())
257  { OCTREFCOUNT_ATOMIC_INCREMENT (&(count())); }
258 
259  dim_vector (const dim_vector& dv) : rep (dv.rep)
260  { OCTREFCOUNT_ATOMIC_INCREMENT (&(count())); }
262  // FIXME: Should be private, but required by array constructor for jit
263  explicit dim_vector (octave_idx_type *r) : rep (r) { }
264 
265  static dim_vector alloc (int n)
266  {
267  return dim_vector (newrep (n < 2 ? 2 : n));
268  }
269 
270  dim_vector& operator = (const dim_vector& dv)
271  {
272  if (&dv != this)
273  {
274  if (OCTREFCOUNT_ATOMIC_DECREMENT (&(count())) == 0)
275  freerep ();
276 
277  rep = dv.rep;
278  OCTREFCOUNT_ATOMIC_INCREMENT (&(count()));
279  }
280 
281  return *this;
282  }
284  ~dim_vector (void)
285  {
286  if (OCTREFCOUNT_ATOMIC_DECREMENT (&(count())) == 0)
287  freerep ();
288  }
289 
290  int length (void) const { return ndims (); }
291 
292  octave_idx_type& operator () (int i) { return elem (i); }
293 
294  octave_idx_type operator () (int i) const { return elem (i); }
295 
296  void resize (int n, int fill_value = 0)
297  {
298  int len = length ();
299 
300  if (n != len)
301  {
302  octave_idx_type *r = resizerep (n, fill_value);
303 
304  if (OCTREFCOUNT_ATOMIC_DECREMENT (&(count())) == 0)
305  freerep ();
306 
307  rep = r;
308  }
309  }
310 
311  std::string str (char sep = 'x') const;
312 
313  bool all_zero (void) const
314  {
315  bool retval = true;
316 
317  for (int i = 0; i < length (); i++)
318  {
319  if (elem (i) != 0)
320  {
321  retval = false;
322  break;
323  }
324  }
325 
326  return retval;
327  }
328 
329  bool empty_2d (void) const
330  {
331  return length () == 2 && (elem (0) == 0 || elem (1) == 0);
332  }
333 
334 
335  bool zero_by_zero (void) const
336  {
337  return length () == 2 && elem (0) == 0 && elem (1) == 0;
338  }
339 
340  bool any_zero (void) const
341  {
342  bool retval = false;
343 
344  for (int i = 0; i < length (); i++)
345  {
346  if (elem (i) == 0)
347  {
348  retval = true;
349  break;
350  }
351  }
352 
353  return retval;
354  }
355 
356  int num_ones (void) const;
357 
358  bool all_ones (void) const
359  {
360  return (num_ones () == length ());
361  }
362 
363  //! Number of elements that a matrix with this dimensions would have.
364  /*!
365  Return the number of elements that a matrix with this dimension
366  vector would have, NOT the number of dimensions (elements in the
367  dimension vector).
368  */
369 
370  octave_idx_type numel (int n = 0) const
371  {
372  int n_dims = length ();
373 
374  octave_idx_type retval = 1;
375 
376  for (int i = n; i < n_dims; i++)
377  retval *= elem (i);
378 
379  return retval;
380  }
381 
382  /*!
383  The following function will throw a std::bad_alloc ()
384  exception if the requested size is larger than can be indexed by
385  octave_idx_type. This may be smaller than the actual amount of
386  memory that can be safely allocated on a system. However, if we
387  don't fail here, we can end up with a mysterious crash inside a
388  function that is iterating over an array using octave_idx_type
389  indices.
390  */
391 
392  octave_idx_type safe_numel (void) const;
393 
394  bool any_neg (void) const
395  {
396  int n_dims = length ();
397  int i;
398 
399  for (i = 0; i < n_dims; i++)
400  if (elem (i) < 0)
401  break;
402 
403  return i < n_dims;
404  }
405 
406  dim_vector squeeze (void) const;
407 
408  //! This corresponds to cat().
409  bool concat (const dim_vector& dvb, int dim);
410 
411  //! This corresponds to [,] (horzcat, dim = 0) and [;] (vertcat, dim = 1).
412  // The rules are more relaxed here.
413  bool hvcat (const dim_vector& dvb, int dim);
415  /*!
416  Force certain dimensionality, preserving numel (). Missing
417  dimensions are set to 1, redundant are folded into the trailing
418  one. If n = 1, the result is 2d and the second dim is 1
419  (dim_vectors are always at least 2D).
420  */
421  dim_vector redim (int n) const;
423  dim_vector as_column (void) const
424  {
425  if (length () == 2 && elem (1) == 1)
426  return *this;
427  else
428  return dim_vector (numel (), 1);
429  }
431  dim_vector as_row (void) const
432  {
433  if (length () == 2 && elem (0) == 1)
434  return *this;
435  else
436  return dim_vector (1, numel ());
437  }
438 
439  bool is_vector (void) const
440  {
441  return (length () == 2 && (elem (0) == 1 || elem (1) == 1));
442  }
443 
444  int first_non_singleton (int def = 0) const
445  {
446  for (int i = 0; i < length (); i++)
447  {
448  if (elem (i) != 1)
449  return i;
450  }
451 
452  return def;
453  }
454 
455  //! Compute a linear index from an index tuple.
456 
458  {
460  for (int i = length () - 1; i >= 0; i--)
461  k = k * rep[i] + idx[i];
462 
463  return k;
464  }
465 
466  //! Ditto, but the tuple may be incomplete (nidx < length ()).
467 
468  octave_idx_type compute_index (const octave_idx_type *idx, int nidx) const
469  {
470  octave_idx_type k = 0;
471  for (int i = nidx - 1; i >= 0; i--)
472  k = k * rep[i] + idx[i];
473 
474  return k;
475  }
476 
477  /*/!
478  Increment a multi-dimensional index tuple, optionally starting
479  from an offset position and return the index of the last index
480  position that was changed, or length () if just cycled over.
481  */
482 
483  int increment_index (octave_idx_type *idx, int start = 0) const
484  {
485  int i;
486  for (i = start; i < length (); i++)
487  {
488  if (++(*idx) == rep[i])
489  *idx++ = 0;
490  else
491  break;
492  }
493  return i;
494  }
495 
496  //! Return cumulative dimensions.
497 
498  dim_vector cumulative (void) const
499  {
500  int nd = length ();
501  dim_vector retval = alloc (nd);
502 
503  octave_idx_type k = 1;
504  for (int i = 0; i < nd; i++)
505  retval.rep[i] = k *= rep[i];
506 
507  return retval;
508  }
509 
510  //! Compute a linear index from an index tuple. Dimensions are
511  //! required to be cumulative.
512 
513  octave_idx_type cum_compute_index (const octave_idx_type *idx) const
514  {
515  octave_idx_type k = idx[0];
516 
517  for (int i = 1; i < length (); i++)
518  k += rep[i-1] * idx[i];
520  return k;
521  }
522 
523 
524  friend bool operator == (const dim_vector& a, const dim_vector& b);
525 };
526 
527 inline bool
528 operator == (const dim_vector& a, const dim_vector& b)
529 {
530  // Fast case.
531  if (a.rep == b.rep)
532  return true;
533 
534  bool retval = true;
535 
536  int a_len = a.length ();
537  int b_len = b.length ();
538 
539  if (a_len != b_len)
540  retval = false;
541  else
542  {
543  for (int i = 0; i < a_len; i++)
544  {
545  if (a(i) != b(i))
546  {
547  retval = false;
548  break;
549  }
550  }
551  }
552 
553  return retval;
554 }
555 
556 inline bool
557 operator != (const dim_vector& a, const dim_vector& b)
558 {
559  return ! operator == (a, b);
560 }
561 
562 #endif
octave_idx_type compute_index(octave_idx_type n, const dim_vector &dims)
Definition: Array-util.cc:178
octave_idx_type & count(void) const
Definition: dim-vector.h:63
bool all_ones(const Array< octave_idx_type > &arr)
Definition: Array-util.cc:359
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:96
bool operator!=(const dim_vector &a, const dim_vector &b)
Definition: dim-vector.h:548
ComplexSVD & operator=(const ComplexSVD &a)
Definition: CmplxSVD.h:62
#define OCTREFCOUNT_ATOMIC_DECREMENT(x)
Definition: oct-refcount.h:45
bool is_vector(const dim_vector &dim)
Definition: Array-util.cc:141
ComplexNDArray concat(NDArray &ra, ComplexNDArray &rb, const Array< octave_idx_type > &ra_idx)
Definition: CNDArray.cc:664
void make_unique(void)
Definition: dim-vector.h:128
#define OCTREFCOUNT_ATOMIC_INCREMENT(x)
Definition: oct-refcount.h:44
octave_idx_type * rep
Definition: dim-vector.h:59
void freerep(void)
Free the rep.
Definition: dim-vector.h:122
void increment_index(Array< octave_idx_type > &ra_idx, const dim_vector &dimensions, int start_dimension)
Definition: Array-util.cc:59
octave_idx_type & ndims(void) const
Definition: dim-vector.h:61
static int elem
Definition: __contourc__.cc:49
bool operator==(const dim_vector &a, const dim_vector &b)
Definition: dim-vector.h:519
#define DIM_VECTOR_CTOR(N)
Definition: dim-vector.h:146
static octave_idx_type * newrep(int ndims)
Construct a new rep with count = 1 and ndims given.
Definition: dim-vector.h:67
octave_idx_type elem(int i) const
Definition: dim-vector.h:206
octave_idx_type * clonerep(void)
Clone this->rep.
Definition: dim-vector.h:79
octave_idx_type num_ones(const Array< octave_idx_type > &ra_idx)
Definition: Array-util.cc:101
int length(void) const
Definition: dim-vector.h:281