4513
|
1 /* |
|
2 |
|
3 Copyright (C) 2003 John W. Eaton |
|
4 |
|
5 This file is part of Octave. |
|
6 |
|
7 Octave is free software; you can redistribute it and/or modify it |
|
8 under the terms of the GNU General Public License as published by the |
|
9 Free Software Foundation; either version 2, or (at your option) any |
|
10 later version. |
|
11 |
|
12 Octave is distributed in the hope that it will be useful, but WITHOUT |
|
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
15 for more details. |
|
16 |
|
17 You should have received a copy of the GNU General Public License |
|
18 along with Octave; see the file COPYING. If not, write to the Free |
5307
|
19 Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
|
20 02110-1301, USA. |
4513
|
21 |
|
22 */ |
|
23 |
|
24 #if !defined (octave_dim_vector_h) |
|
25 #define octave_dim_vector_h 1 |
|
26 |
|
27 #include <cassert> |
5765
|
28 #include <sstream> |
4543
|
29 #include <string> |
|
30 |
6216
|
31 #include "lo-error.h" |
5275
|
32 #include "oct-types.h" |
4513
|
33 |
|
34 class |
|
35 dim_vector |
|
36 { |
4548
|
37 protected: |
4513
|
38 |
4548
|
39 class dim_vector_rep |
|
40 { |
|
41 public: |
4513
|
42 |
5275
|
43 octave_idx_type *dims; |
4548
|
44 int ndims; |
|
45 int count; |
4513
|
46 |
6216
|
47 dim_vector_rep (void) |
|
48 : dims (new octave_idx_type [2]), ndims (2), count (1) |
|
49 { |
|
50 dims[0] = 0; |
|
51 dims[1] = 0; |
|
52 } |
4548
|
53 |
6216
|
54 |
|
55 dim_vector_rep (octave_idx_type n) |
|
56 : dims (new octave_idx_type [2]), ndims (2), count (1) |
4548
|
57 { |
|
58 dims[0] = n; |
6216
|
59 dims[1] = 1; |
4548
|
60 } |
4513
|
61 |
6216
|
62 dim_vector_rep (octave_idx_type r, octave_idx_type c) |
|
63 : dims (new octave_idx_type [2]), ndims (2), count (1) |
4548
|
64 { |
|
65 dims[0] = r; |
|
66 dims[1] = c; |
|
67 } |
4513
|
68 |
5275
|
69 dim_vector_rep (octave_idx_type r, octave_idx_type c, octave_idx_type p) |
|
70 : dims (new octave_idx_type [3]), ndims (3), count (1) |
4513
|
71 { |
4548
|
72 dims[0] = r; |
|
73 dims[1] = c; |
|
74 dims[2] = p; |
|
75 } |
|
76 |
|
77 dim_vector_rep (const dim_vector_rep& dv) |
5275
|
78 : dims (dv.ndims > 0 ? new octave_idx_type [dv.ndims] : 0), |
4548
|
79 ndims (dv.ndims > 0 ? dv.ndims : 0), count (1) |
|
80 { |
|
81 if (dims) |
4513
|
82 { |
|
83 for (int i = 0; i < ndims; i++) |
|
84 dims[i] = dv.dims[i]; |
|
85 } |
|
86 } |
|
87 |
6216
|
88 dim_vector_rep (octave_idx_type n, const dim_vector_rep *dv, |
|
89 int fill_value = 0) |
5275
|
90 : dims ((dv && n > 0) ? new octave_idx_type [n] : 0), |
4548
|
91 ndims (n > 0 ? n : 0), count (1) |
4513
|
92 { |
4548
|
93 if (dims) |
4513
|
94 { |
4548
|
95 int dv_ndims = dv ? dv->ndims : 0; |
4513
|
96 |
4565
|
97 int min_len = n < dv_ndims ? n : dv_ndims; |
|
98 |
|
99 for (int i = 0; i < min_len; i++) |
4548
|
100 dims[i] = dv->dims[i]; |
4513
|
101 |
4548
|
102 for (int i = dv_ndims; i < n; i++) |
4887
|
103 dims[i] = fill_value; |
4513
|
104 } |
|
105 } |
|
106 |
4548
|
107 ~dim_vector_rep (void) { delete [] dims; } |
4513
|
108 |
4548
|
109 int length (void) const { return ndims; } |
4513
|
110 |
5275
|
111 octave_idx_type& elem (int i) |
4513
|
112 { |
4548
|
113 assert (i >= 0 && i < ndims); |
|
114 return dims[i]; |
|
115 } |
4513
|
116 |
5275
|
117 octave_idx_type elem (int i) const |
4548
|
118 { |
|
119 assert (i >= 0 && i < ndims); |
4513
|
120 return dims[i]; |
|
121 } |
|
122 |
4673
|
123 void chop_trailing_singletons (void) |
|
124 { |
|
125 for (int i = ndims - 1; i > 1; i--) |
|
126 { |
|
127 if (dims[i] == 1) |
|
128 ndims--; |
|
129 else |
|
130 break; |
|
131 } |
|
132 } |
|
133 |
4548
|
134 private: |
|
135 |
|
136 // No assignment! |
|
137 |
|
138 dim_vector_rep& operator = (const dim_vector_rep& dv); |
|
139 }; |
|
140 |
|
141 dim_vector_rep *rep; |
|
142 |
|
143 void make_unique (void) |
|
144 { |
|
145 if (rep->count > 1) |
|
146 { |
|
147 --rep->count; |
|
148 rep = new dim_vector_rep (*rep); |
|
149 } |
|
150 } |
|
151 |
|
152 private: |
|
153 |
|
154 dim_vector_rep *nil_rep (void) const |
|
155 { |
|
156 static dim_vector_rep *nr = new dim_vector_rep (); |
|
157 |
|
158 return nr; |
|
159 } |
|
160 |
|
161 public: |
|
162 |
|
163 explicit dim_vector (void) |
|
164 : rep (nil_rep ()) { rep->count++; } |
|
165 |
5275
|
166 explicit dim_vector (octave_idx_type n) |
4548
|
167 : rep (new dim_vector_rep (n)) { } |
|
168 |
5275
|
169 explicit dim_vector (octave_idx_type r, octave_idx_type c) |
4548
|
170 : rep (new dim_vector_rep (r, c)) { } |
|
171 |
5275
|
172 explicit dim_vector (octave_idx_type r, octave_idx_type c, octave_idx_type p) |
4548
|
173 : rep (new dim_vector_rep (r, c, p)) { } |
|
174 |
|
175 dim_vector (const dim_vector& dv) |
|
176 : rep (dv.rep) { rep->count++; } |
|
177 |
|
178 dim_vector& operator = (const dim_vector& dv) |
|
179 { |
|
180 if (&dv != this) |
|
181 { |
|
182 if (--rep->count <= 0) |
|
183 delete rep; |
|
184 |
|
185 rep = dv.rep; |
|
186 rep->count++; |
|
187 } |
|
188 |
|
189 return *this; |
|
190 } |
|
191 |
|
192 ~dim_vector (void) |
|
193 { |
|
194 if (--rep->count <= 0) |
|
195 delete rep; |
|
196 } |
|
197 |
|
198 int length (void) const { return rep->length (); } |
|
199 |
5275
|
200 octave_idx_type& elem (int i) { make_unique (); return rep->elem (i); } |
4548
|
201 |
5275
|
202 octave_idx_type elem (int i) const { return rep->elem (i); } |
4513
|
203 |
5275
|
204 octave_idx_type& operator () (int i) { return elem (i); } |
4513
|
205 |
5275
|
206 octave_idx_type operator () (int i) const { return elem (i); } |
4513
|
207 |
4887
|
208 void resize (int n, int fill_value = 0) |
4548
|
209 { |
|
210 int len = length (); |
4513
|
211 |
4548
|
212 if (n != len) |
|
213 { |
6216
|
214 if (n < 2) |
|
215 { |
|
216 (*current_liboctave_error_handler) |
|
217 ("unable to resize object to fewer than 2 dimensions"); |
|
218 return; |
|
219 } |
|
220 |
4548
|
221 dim_vector_rep *old_rep = rep; |
4513
|
222 |
4887
|
223 rep = new dim_vector_rep (n, old_rep, fill_value); |
4513
|
224 |
4548
|
225 if (--old_rep->count <= 0) |
|
226 delete old_rep; |
|
227 } |
|
228 } |
4513
|
229 |
4559
|
230 std::string str (char sep = 'x') const |
4548
|
231 { |
5765
|
232 std::ostringstream buf; |
4543
|
233 |
4548
|
234 for (int i = 0; i < length (); i++) |
|
235 { |
|
236 buf << elem (i); |
4543
|
237 |
4548
|
238 if (i < length () - 1) |
4559
|
239 buf << sep; |
4548
|
240 } |
4543
|
241 |
5765
|
242 std::string retval = buf.str (); |
4543
|
243 |
4548
|
244 return retval; |
|
245 } |
4543
|
246 |
|
247 bool all_zero (void) const |
4548
|
248 { |
|
249 bool retval = true; |
4543
|
250 |
4548
|
251 for (int i = 0; i < length (); i++) |
|
252 { |
|
253 if (elem (i) != 0) |
|
254 { |
|
255 retval = false; |
|
256 break; |
|
257 } |
|
258 } |
4543
|
259 |
4548
|
260 return retval; |
|
261 } |
4559
|
262 |
|
263 bool any_zero (void) const |
|
264 { |
|
265 bool retval = false; |
|
266 |
|
267 for (int i = 0; i < length (); i++) |
|
268 { |
|
269 if (elem (i) == 0) |
|
270 { |
|
271 retval = true; |
|
272 break; |
|
273 } |
|
274 } |
|
275 |
|
276 return retval; |
|
277 } |
4567
|
278 |
4635
|
279 int |
|
280 num_ones (void) const |
|
281 { |
|
282 int retval = 0; |
|
283 |
|
284 for (int i = 0; i < length (); i++) |
|
285 if (elem (i) == 1) |
|
286 retval++; |
|
287 |
|
288 return retval; |
|
289 } |
|
290 |
4655
|
291 bool |
|
292 all_ones (void) const |
|
293 { |
|
294 return (num_ones () == length ()); |
|
295 } |
|
296 |
4567
|
297 // This is the number of elements that a matrix with this dimension |
|
298 // vector would have, NOT the number of dimensions (elements in the |
|
299 // dimension vector). |
|
300 |
5275
|
301 octave_idx_type numel (void) const |
4567
|
302 { |
|
303 int n_dims = length (); |
|
304 |
5275
|
305 octave_idx_type retval = n_dims > 0 ? elem (0) : 0; |
4567
|
306 |
|
307 for (int i = 1; i < n_dims; i++) |
|
308 retval *= elem (i); |
|
309 |
|
310 return retval; |
|
311 } |
4673
|
312 |
|
313 void chop_trailing_singletons (void) |
|
314 { |
|
315 make_unique (); |
|
316 rep->chop_trailing_singletons (); |
|
317 } |
4735
|
318 |
|
319 dim_vector squeeze (void) const |
|
320 { |
|
321 dim_vector new_dims = *this; |
|
322 |
|
323 bool dims_changed = 1; |
|
324 |
|
325 int k = 0; |
|
326 |
|
327 for (int i = 0; i < length (); i++) |
|
328 { |
|
329 if (elem (i) == 1) |
|
330 dims_changed = true; |
|
331 else |
|
332 new_dims(k++) = elem (i); |
|
333 } |
|
334 |
|
335 if (dims_changed) |
|
336 { |
|
337 if (k == 0) |
|
338 new_dims = dim_vector (1, 1); |
|
339 else if (k == 1) |
|
340 { |
|
341 // There is one non-singleton dimension, so we need |
|
342 // to decide the correct orientation. |
|
343 |
|
344 if (elem (0) == 1) |
|
345 { |
|
346 // The original dimension vector had a leading |
|
347 // singleton dimension. |
|
348 |
5275
|
349 octave_idx_type tmp = new_dims(0); |
4735
|
350 |
|
351 new_dims.resize (2); |
|
352 |
|
353 new_dims(0) = 1; |
|
354 new_dims(1) = tmp; |
|
355 } |
|
356 else |
|
357 { |
|
358 // The first element of the original dimension vector |
|
359 // was not a singleton dimension. |
|
360 |
|
361 new_dims.resize (2); |
|
362 |
|
363 new_dims(1) = 1; |
|
364 } |
|
365 } |
|
366 else |
|
367 new_dims.resize(k); |
|
368 } |
|
369 |
|
370 return new_dims; |
|
371 } |
4915
|
372 |
|
373 bool concat (const dim_vector& dvb, int dim = 0) |
|
374 { |
|
375 if (all_zero ()) |
|
376 { |
|
377 *this = dvb; |
|
378 return true; |
|
379 } |
|
380 |
|
381 if (dvb.all_zero ()) |
|
382 return true; |
|
383 |
|
384 int na = length (); |
|
385 int nb = dvb.length (); |
|
386 |
|
387 // Find the max and min value of na and nb |
|
388 int n_max = na > nb ? na : nb; |
|
389 int n_min = na < nb ? na : nb; |
|
390 |
|
391 // The elements of the dimension vectors can only differ |
|
392 // if the dim variable differs from the actual dimension |
|
393 // they differ. |
|
394 |
|
395 for (int i = 0; i < n_min; i++) |
|
396 { |
|
397 if (elem(i) != dvb(i) && dim != i) |
|
398 return false; |
|
399 } |
|
400 |
|
401 // Ditto. |
|
402 for (int i = n_min; i < n_max; i++) |
|
403 { |
|
404 if (na > n_min) |
|
405 { |
|
406 if (elem(i) != 1 && dim != i) |
|
407 return false; |
|
408 } |
|
409 else |
|
410 { |
|
411 if (dvb(i) != 1 && dim != i) |
|
412 return false; |
|
413 } |
|
414 } |
|
415 |
|
416 // If we want to add the dimension vectors at a dimension |
|
417 // larger than both, then we need to set n_max to this number |
|
418 // so that we resize *this to the right dimension. |
|
419 |
|
420 n_max = n_max > (dim + 1) ? n_max : (dim + 1); |
|
421 |
|
422 // Resize *this to the appropriate dimensions. |
|
423 |
|
424 if (n_max > na) |
|
425 { |
|
426 dim_vector_rep *old_rep = rep; |
|
427 |
|
428 rep = new dim_vector_rep (n_max, old_rep, 1); |
|
429 |
|
430 if (--old_rep->count <= 0) |
|
431 delete old_rep; |
|
432 } |
|
433 |
|
434 // Larger or equal since dim has been decremented by one. |
|
435 |
|
436 if (dim >= nb) |
4940
|
437 elem (dim)++; |
4915
|
438 else |
|
439 elem (dim) += dvb(dim); |
|
440 |
|
441 return true; |
|
442 } |
4513
|
443 }; |
|
444 |
4543
|
445 static inline bool |
|
446 operator == (const dim_vector& a, const dim_vector& b) |
|
447 { |
|
448 bool retval = true; |
|
449 |
|
450 int a_len = a.length (); |
|
451 int b_len = b.length (); |
|
452 |
|
453 if (a_len != b_len) |
|
454 retval = false; |
|
455 else |
|
456 { |
|
457 for (int i = 0; i < a_len; i++) |
|
458 { |
|
459 if (a(i) != b(i)) |
|
460 { |
|
461 retval = false; |
|
462 break; |
|
463 } |
|
464 } |
|
465 } |
|
466 |
|
467 return retval; |
|
468 } |
|
469 |
|
470 static inline bool |
|
471 operator != (const dim_vector& a, const dim_vector& b) |
|
472 { |
|
473 return ! operator == (a, b); |
|
474 } |
|
475 |
4513
|
476 #endif |
|
477 |
|
478 /* |
|
479 ;;; Local Variables: *** |
|
480 ;;; mode: C++ *** |
|
481 ;;; End: *** |
|
482 */ |