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.cc
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 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 
28 #include <iostream>
29 
30 #include "dim-vector.h"
31 
32 // The maximum allowed value for a dimension extent. This will normally be a
33 // tiny bit off the maximum value of octave_idx_type.
34 // Currently 1 is subtracted to allow safe conversion of any 2D Array into
35 // Sparse, but this offset may change in the future.
38 {
40 }
41 
42 void
44 {
45  make_unique ();
46 
47  int j = 0;
48  int l = ndims ();
49 
50  for (int i = 0; i < l; i++)
51  {
52  if (rep[i] != 1)
53  rep[j++] = rep[i];
54  }
55 
56  if (j == 1)
57  rep[1] = 1;
58 
59  ndims () = j > 2 ? j : 2;
60 }
61 
62 std::string
63 dim_vector::str (char sep) const
64 {
65  std::ostringstream buf;
66 
67  for (int i = 0; i < length (); i++)
68  {
69  buf << elem (i);
70 
71  if (i < length () - 1)
72  buf << sep;
73  }
74 
75  std::string retval = buf.str ();
76 
77  return retval;
78 }
79 
80 int
82 {
83  int retval = 0;
84 
85  for (int i = 0; i < length (); i++)
86  if (elem (i) == 1)
87  retval++;
88 
89  return retval;
90 }
91 
94 {
96  octave_idx_type n = 1;
97  int n_dims = length ();
98 
99  for (int i = 0; i < n_dims; i++)
100  {
101  n *= rep[i];
102  if (rep[i] != 0)
103  idx_max /= rep[i];
104  if (idx_max <= 0)
105  throw std::bad_alloc ();
106  }
107 
108  return n;
109 }
110 
113 {
114  dim_vector new_dims = *this;
115 
116  bool dims_changed = 1;
117 
118  int k = 0;
119 
120  for (int i = 0; i < length (); i++)
121  {
122  if (elem (i) == 1)
123  dims_changed = true;
124  else
125  new_dims(k++) = elem (i);
126  }
127 
128  if (dims_changed)
129  {
130  if (k == 0)
131  new_dims = dim_vector (1, 1);
132  else if (k == 1)
133  {
134  // There is one non-singleton dimension, so we need
135  // to decide the correct orientation.
136 
137  if (elem (0) == 1)
138  {
139  // The original dimension vector had a leading
140  // singleton dimension.
141 
142  octave_idx_type tmp = new_dims(0);
143 
144  new_dims.resize (2);
145 
146  new_dims(0) = 1;
147  new_dims(1) = tmp;
148  }
149  else
150  {
151  // The first element of the original dimension vector
152  // was not a singleton dimension.
153 
154  new_dims.resize (2);
155 
156  new_dims(1) = 1;
157  }
158  }
159  else
160  new_dims.resize (k);
161  }
162 
163  return new_dims;
164 }
165 
166 // This is the rule for cat(). cat (dim, A, B) works if one
167 // of the following holds, in this order:
168 //
169 // 1. size (A, k) == size (B, k) for all k != dim.
170 // In this case, size (C, dim) = size (A, dim) + size (B, dim) and
171 // other sizes remain intact.
172 //
173 // 2. A is 0x0, in which case B is the result
174 // 3. B is 0x0, in which case A is the result
175 
176 bool
177 dim_vector::concat (const dim_vector& dvb, int dim)
178 {
179  int orig_nd = ndims (), ndb = dvb.ndims ();
180  int new_nd = dim < ndb ? ndb : dim + 1;
181  if (new_nd > orig_nd)
182  resize (new_nd, 1);
183  else
184  new_nd = orig_nd;
185 
186  make_unique ();
187 
188  bool match = true;
189 
190  for (int i = 0; i < ndb; i++)
191  {
192  if (i != dim && rep[i] != dvb(i))
193  {
194  match = false;
195  break;
196  }
197  }
198 
199  for (int i = ndb; i < new_nd; i++)
200  {
201  if (i != dim && rep[i] != 1)
202  {
203  match = false;
204  break;
205  }
206  }
207 
208  if (match)
209  rep[dim] += (dim < ndb ? dvb(dim) : 1);
210  else
211  {
212  // Dimensions don't match. The only allowed fix is
213  // to omit 0x0.
214  if (ndb == 2 && dvb(0) == 0 && dvb(1) == 0)
215  match = true;
216  else if (orig_nd == 2 && rep[0] == 0 && rep[1] == 0)
217  {
218  *this = dvb;
219  match = true;
220  }
221  }
222 
224 
225  return match;
226 }
227 
228 // Rules for horzcat/vertcat are yet looser.
229 // two arrays A, B can be concatenated
230 // horizontally (dim = 2) or vertically (dim = 1) if one of the
231 // following holds, in this order:
232 //
233 // 1. cat (dim, A, B) works
234 //
235 // 2. A, B are 2D and one of them is an empty vector, in which
236 // case the result is the other one except if both of them
237 // are empty vectors, in which case the result is 0x0.
238 
239 bool
240 dim_vector::hvcat (const dim_vector& dvb, int dim)
241 {
242  if (concat (dvb, dim))
243  return true;
244  else if (length () == 2 && dvb.length () == 2)
245  {
246  bool e2dv = rep[0] + rep[1] == 1;
247  bool e2dvb = dvb(0) + dvb(1) == 1;
248  if (e2dvb)
249  {
250  if (e2dv)
251  *this = dim_vector ();
252  return true;
253  }
254  else if (e2dv)
255  {
256  *this = dvb;
257  return true;
258  }
259  }
260 
261  return false;
262 }
263 
265 dim_vector::redim (int n) const
266 {
267  int n_dims = length ();
268 
269  if (n_dims == n)
270  return *this;
271  else if (n_dims < n)
272  {
273  dim_vector retval = alloc (n);
274 
275  for (int i = 0; i < n_dims; i++)
276  retval.rep[i] = rep[i];
277 
278  for (int i = n_dims; i < n; i++)
279  retval.rep[i] = 1;
280 
281  return retval;
282  }
283  else
284  {
285  if (n < 1) n = 1;
286 
287  dim_vector retval = alloc (n);
288 
289  retval.rep[1] = 1;
290 
291  for (int i = 0; i < n-1; i++)
292  retval.rep[i] = rep[i];
293 
294  int k = rep[n-1];
295  for (int i = n; i < n_dims; i++)
296  k *= rep[i];
297 
298  retval.rep[n-1] = k;
299 
300  return retval;
301  }
302 }