GNU Octave  3.8.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-2013 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 
79  octave_idx_type *clonerep (void)
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 
96  octave_idx_type *resizerep (int n, octave_idx_type fill_value)
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  // The constructor
144  //
145  // dim_vector (n)
146  //
147  // creates an dimension vector with N rows and 1 column. It is
148  // deprecated because of the potentiol for confusion that it causes.
149  // Additional constructors of the form
150  //
151  // dim_vector (r, c)
152  // dim_vector (r, c, p)
153  // dim_vector (d1, d2, d3, d4, ...)
154  //
155  // are available for up to 7 dimensions.
156 
158  : rep (newrep (2))
159  {
160  rep[0] = n;
161  rep[1] = 1;
162  }
163 
164 #define ASSIGN_REP(i) rep[i] = d ## i;
165 #define DIM_VECTOR_CTOR(N) \
166  dim_vector (OCT_MAKE_DECL_LIST (octave_idx_type, d, N)) \
167  : rep (newrep (N)) \
168  { \
169  OCT_ITERATE_MACRO (ASSIGN_REP, N) \
170  }
171 
172  // Add more if needed.
179 
180 #undef ASSIGN_REP
181 #undef DIM_VECTOR_CTOR
182 
184  {
185 #ifdef BOUNDS_CHECKING
186  assert (i >= 0 && i < ndims ());
187 #endif
188  make_unique ();
189  return rep[i];
190  }
191 
192  octave_idx_type elem (int i) const
193  {
194 #ifdef BOUNDS_CHECKING
195  assert (i >= 0 && i < ndims ());
196 #endif
197  return rep[i];
198  }
199 
200  void chop_trailing_singletons (void)
201  {
202  int l = ndims ();
203  if (l > 2 && rep[l-1] == 1)
204  {
205  make_unique ();
206  do
207  l--;
208  while (l > 2 && rep[l-1] == 1);
209  ndims () = l;
210  }
211  }
212 
213  void chop_all_singletons (void);
214 
215  // WARNING: Only call by jit
216  octave_idx_type *to_jit (void) const
217  {
218  return rep;
219  }
220 
221 private:
222 
223  static octave_idx_type *nil_rep (void)
224  {
225  static dim_vector zv (0, 0);
226  return zv.rep;
227  }
228 
229 public:
230 
231  static octave_idx_type dim_max (void);
232 
233  explicit dim_vector (void) : rep (nil_rep ())
234  { OCTREFCOUNT_ATOMIC_INCREMENT (&(count())); }
235 
236  dim_vector (const dim_vector& dv) : rep (dv.rep)
237  { OCTREFCOUNT_ATOMIC_INCREMENT (&(count())); }
238 
239  // FIXME: Should be private, but required by array constructor for jit
240  explicit dim_vector (octave_idx_type *r) : rep (r) { }
241 
242  static dim_vector alloc (int n)
243  {
244  return dim_vector (newrep (n < 2 ? 2 : n));
245  }
246 
248  {
249  if (&dv != this)
250  {
251  if (OCTREFCOUNT_ATOMIC_DECREMENT (&(count())) == 0)
252  freerep ();
253 
254  rep = dv.rep;
255  OCTREFCOUNT_ATOMIC_INCREMENT (&(count()));
256  }
257 
258  return *this;
259  }
260 
261  ~dim_vector (void)
262  {
263  if (OCTREFCOUNT_ATOMIC_DECREMENT (&(count())) == 0)
264  freerep ();
265  }
266 
267  int length (void) const { return ndims (); }
268 
269  octave_idx_type& operator () (int i) { return elem (i); }
270 
271  octave_idx_type operator () (int i) const { return elem (i); }
272 
273  void resize (int n, int fill_value = 0)
274  {
275  int len = length ();
276 
277  if (n != len)
278  {
279  octave_idx_type *r = resizerep (n, fill_value);
280 
281  if (OCTREFCOUNT_ATOMIC_DECREMENT (&(count())) == 0)
282  freerep ();
283 
284  rep = r;
285  }
286  }
287 
288  std::string str (char sep = 'x') const;
289 
290  bool all_zero (void) const
291  {
292  bool retval = true;
293 
294  for (int i = 0; i < length (); i++)
295  {
296  if (elem (i) != 0)
297  {
298  retval = false;
299  break;
300  }
301  }
302 
303  return retval;
304  }
305 
306  bool empty_2d (void) const
307  {
308  return length () == 2 && (elem (0) == 0 || elem (1) == 0);
309  }
310 
311 
312  bool zero_by_zero (void) const
313  {
314  return length () == 2 && elem (0) == 0 && elem (1) == 0;
315  }
316 
317  bool any_zero (void) const
318  {
319  bool retval = false;
320 
321  for (int i = 0; i < length (); i++)
322  {
323  if (elem (i) == 0)
324  {
325  retval = true;
326  break;
327  }
328  }
329 
330  return retval;
331  }
332 
333  int num_ones (void) const;
334 
335  bool all_ones (void) const
336  {
337  return (num_ones () == length ());
338  }
339 
340  // Return the number of elements that a matrix with this dimension
341  // vector would have, NOT the number of dimensions (elements in the
342  // dimension vector).
343 
344  octave_idx_type numel (int n = 0) const
345  {
346  int n_dims = length ();
347 
348  octave_idx_type retval = 1;
349 
350  for (int i = n; i < n_dims; i++)
351  retval *= elem (i);
352 
353  return retval;
354  }
355 
356  // The following function will throw a std::bad_alloc ()
357  // exception if the requested size is larger than can be indexed by
358  // octave_idx_type. This may be smaller than the actual amount of
359  // memory that can be safely allocated on a system. However, if we
360  // don't fail here, we can end up with a mysterious crash inside a
361  // function that is iterating over an array using octave_idx_type
362  // indices.
363 
364  octave_idx_type safe_numel (void) const;
365 
366  bool any_neg (void) const
367  {
368  int n_dims = length ();
369  int i;
370 
371  for (i = 0; i < n_dims; i++)
372  if (elem (i) < 0)
373  break;
374 
375  return i < n_dims;
376  }
377 
378  dim_vector squeeze (void) const;
379 
380  // This corresponds to cat().
381  bool concat (const dim_vector& dvb, int dim);
382 
383  // This corresponds to [,] (horzcat, dim = 0) and [;] (vertcat, dim = 1).
384  // The rules are more relaxed here.
385  bool hvcat (const dim_vector& dvb, int dim);
386 
387  // Force certain dimensionality, preserving numel (). Missing
388  // dimensions are set to 1, redundant are folded into the trailing
389  // one. If n = 1, the result is 2d and the second dim is 1
390  // (dim_vectors are always at least 2D).
391 
392  dim_vector redim (int n) const;
393 
394  dim_vector as_column (void) const
395  {
396  if (length () == 2 && elem (1) == 1)
397  return *this;
398  else
399  return dim_vector (numel (), 1);
400  }
401 
402  dim_vector as_row (void) const
403  {
404  if (length () == 2 && elem (0) == 1)
405  return *this;
406  else
407  return dim_vector (1, numel ());
408  }
409 
410  bool is_vector (void) const
411  {
412  return (length () == 2 && (elem (0) == 1 || elem (1) == 1));
413  }
414 
415  int first_non_singleton (int def = 0) const
416  {
417  for (int i = 0; i < length (); i++)
418  {
419  if (elem (i) != 1)
420  return i;
421  }
422 
423  return def;
424  }
425 
426  // Compute a linear index from an index tuple.
427 
429  {
430  octave_idx_type k = 0;
431  for (int i = length () - 1; i >= 0; i--)
432  k = k * rep[i] + idx[i];
433 
434  return k;
435  }
436 
437  // Ditto, but the tuple may be incomplete (nidx < length ()).
438 
439  octave_idx_type compute_index (const octave_idx_type *idx, int nidx) const
440  {
441  octave_idx_type k = 0;
442  for (int i = nidx - 1; i >= 0; i--)
443  k = k * rep[i] + idx[i];
444 
445  return k;
446  }
447 
448  // Increment a multi-dimensional index tuple, optionally starting
449  // from an offset position and return the index of the last index
450  // position that was changed, or length () if just cycled over.
451 
452  int increment_index (octave_idx_type *idx, int start = 0) const
453  {
454  int i;
455  for (i = start; i < length (); i++)
456  {
457  if (++(*idx) == rep[i])
458  *idx++ = 0;
459  else
460  break;
461  }
462  return i;
463  }
464 
465  // Return cumulative dimensions.
466 
467  dim_vector cumulative (void) const
468  {
469  int nd = length ();
470  dim_vector retval = alloc (nd);
471 
472  octave_idx_type k = 1;
473  for (int i = 0; i < nd; i++)
474  retval.rep[i] = k *= rep[i];
475 
476  return retval;
477  }
478 
479  // Compute a linear index from an index tuple. Dimensions are
480  // required to be cumulative.
481 
482  octave_idx_type cum_compute_index (const octave_idx_type *idx) const
483  {
484  octave_idx_type k = idx[0];
485 
486  for (int i = 1; i < length (); i++)
487  k += rep[i-1] * idx[i];
488 
489  return k;
490  }
491 
492 
493  friend bool operator == (const dim_vector& a, const dim_vector& b);
494 };
495 
496 inline bool
497 operator == (const dim_vector& a, const dim_vector& b)
498 {
499  // Fast case.
500  if (a.rep == b.rep)
501  return true;
502 
503  bool retval = true;
504 
505  int a_len = a.length ();
506  int b_len = b.length ();
507 
508  if (a_len != b_len)
509  retval = false;
510  else
511  {
512  for (int i = 0; i < a_len; i++)
513  {
514  if (a(i) != b(i))
515  {
516  retval = false;
517  break;
518  }
519  }
520  }
521 
522  return retval;
523 }
524 
525 inline bool
526 operator != (const dim_vector& a, const dim_vector& b)
527 {
528  return ! operator == (a, b);
529 }
530 
531 #endif