GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
dim-vector.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2003-2024 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // or <https://octave.org/copyright/>.
7 //
8 // Copyirght (C) 2009, 2010 VZLU Prague
9 //
10 // This file is part of Octave.
11 //
12 // Octave is free software: you can redistribute it and/or modify it
13 // under the terms of the GNU General Public License as published by
14 // the Free Software Foundation, either version 3 of the License, or
15 // (at your option) any later version.
16 //
17 // Octave is distributed in the hope that it will be useful, but
18 // WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with Octave; see the file COPYING. If not, see
24 // <https://www.gnu.org/licenses/>.
25 //
26 ////////////////////////////////////////////////////////////////////////
27 
28 #if defined (HAVE_CONFIG_H)
29 # include "config.h"
30 #endif
31 
32 #include <limits>
33 #include <new>
34 #include <sstream>
35 
36 #include "Array.h"
37 #include "dim-vector.h"
38 
39 // The maximum allowed value for a dimension extent. This will normally be a
40 // tiny bit off the maximum value of octave_idx_type.
41 // Currently 1 is subtracted to allow safe conversion of any 2D Array into
42 // Sparse, but this offset may change in the future.
45 {
47 }
48 
49 void
51 {
52  int j = 0;
53  int nd = ndims ();
54 
55  for (int i = 0; i < nd; i++)
56  {
57  if (xelem(i) != 1)
58  xelem(j++) = xelem(i);
59  }
60 
61  if (j == 1)
62  xelem(1) = 1;
63 
64  m_num_dims = (j > 2 ? j : 2);
65 }
66 
67 std::string
68 dim_vector::str (char sep) const
69 {
70  std::ostringstream buf;
71 
72  for (int i = 0; i < ndims (); i++)
73  {
74  buf << xelem (i);
75 
76  if (i < ndims () - 1)
77  buf << sep;
78  }
79 
80  std::string retval = buf.str ();
81 
82  return retval;
83 }
84 
85 int
87 {
88  int retval = 0;
89 
90  for (int i = 0; i < ndims (); i++)
91  if (xelem (i) == 1)
92  retval++;
93 
94  return retval;
95 }
96 
99 {
100  octave_idx_type idx_max = dim_max ();
101  octave_idx_type n = 1;
102  int n_dims = ndims ();
103 
104  for (int i = 0; i < n_dims; i++)
105  {
106  n *= xelem(i);
107  if (xelem(i) != 0)
108  idx_max /= xelem(i);
109  if (idx_max <= 0)
110  throw std::bad_alloc ();
111  }
112 
113  return n;
114 }
115 
118 {
119  dim_vector new_dims = *this;
120  new_dims.chop_all_singletons ();
121 
122  // preserve orientation if there is only one non-singleton dimension left
123  if (new_dims.ndims () == 2 && xelem(0) == 1 && new_dims.elem(1) == 1)
124  return new_dims.as_row ();
125 
126  return new_dims;
127 }
128 
129 // This is the rule for cat(). cat (dim, A, B) works if one
130 // of the following holds, in this order:
131 //
132 // 1. size (A, k) == size (B, k) for all k != dim.
133 // In this case, size (C, dim) = size (A, dim) + size (B, dim) and
134 // other sizes remain intact.
135 //
136 // 2. A is 0x0, in which case B is the result
137 // 3. B is 0x0, in which case A is the result
138 
139 bool
140 dim_vector::concat (const dim_vector& dvb, int dim)
141 {
142  int orig_nd = ndims ();
143  int ndb = dvb.ndims ();
144  int new_nd = (dim < ndb ? ndb : dim + 1);
145  if (new_nd > orig_nd)
146  resize (new_nd, 1);
147  else
148  new_nd = orig_nd;
149 
150  bool match = true;
151 
152  for (int i = 0; i < ndb; i++)
153  {
154  if (i != dim && xelem(i) != dvb(i))
155  {
156  match = false;
157  break;
158  }
159  }
160 
161  for (int i = ndb; i < new_nd; i++)
162  {
163  if (i != dim && xelem(i) != 1)
164  {
165  match = false;
166  break;
167  }
168  }
169 
170  if (match)
171  xelem(dim) += (dim < ndb ? dvb(dim) : 1);
172  else
173  {
174  // Dimensions don't match. The only allowed fix is to omit 0x0.
175  if (ndb == 2 && dvb(0) == 0 && dvb(1) == 0)
176  match = true;
177  else if (orig_nd == 2 && xelem(0) == 0 && xelem(1) == 0)
178  {
179  *this = dvb;
180  match = true;
181  }
182  }
183 
185 
186  return match;
187 }
188 
189 // Rules for horzcat/vertcat are yet looser.
190 // two arrays A, B can be concatenated
191 // horizontally (dim = 2) or vertically (dim = 1) if one of the
192 // following holds, in this order:
193 //
194 // 1. cat (dim, A, B) works
195 //
196 // 2. A, B are 2D and one of them is an empty vector, in which
197 // case the result is the other one except if both of them
198 // are empty vectors, in which case the result is 0x0.
199 
200 bool
201 dim_vector::hvcat (const dim_vector& dvb, int dim)
202 {
203  if (concat (dvb, dim))
204  return true;
205  else if (ndims () == 2 && dvb.ndims () == 2)
206  {
207  bool e2dv = xelem(0) + xelem(1) == 1;
208  bool e2dvb = dvb(0) + dvb(1) == 1;
209  if (e2dvb)
210  {
211  if (e2dv)
212  *this = dim_vector ();
213  return true;
214  }
215  else if (e2dv)
216  {
217  *this = dvb;
218  return true;
219  }
220  }
221 
222  return false;
223 }
224 
226 dim_vector::redim (int n) const
227 {
228  int n_dims = ndims ();
229 
230  if (n_dims == n)
231  return *this;
232  else if (n_dims < n)
233  {
234  dim_vector retval = alloc (n);
235 
236  std::copy_n (m_dims, n_dims, retval.m_dims);
237  std::fill_n (retval.m_dims + n_dims, n - n_dims, 1);
238 
239  return retval;
240  }
241  else
242  {
243  if (n < 1)
244  n = 1;
245 
246  dim_vector retval = alloc (n);
247 
248  std::copy_n (m_dims, n-1, retval.m_dims);
249 
250  // Accumulate overflow dimensions into last remaining dimension
251  int k = xelem(n-1);
252  for (int i = n; i < n_dims; i++)
253  k *= xelem(i);
254 
255  retval.xelem(n-1) = k;
256 
257  // All dim_vectors are at least 2-D. Make Nx1 if necessary.
258  if (n == 1)
259  retval.xelem(1) = 1;
260 
261  return retval;
262  }
263 }
264 
267 {
268  octave_idx_type nd = ndims ();
269 
270  Array<octave_idx_type> retval (dim_vector (1, nd));
271 
272  for (octave_idx_type i = 0; i < nd; i++)
273  retval(i) = elem (i);
274 
275  return retval;
276 }
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
bool concat(const dim_vector &dvb, int dim)
This corresponds to cat().
Definition: dim-vector.cc:140
octave_idx_type safe_numel() const
The following function will throw a std::bad_alloc () exception if the requested size is larger than ...
Definition: dim-vector.cc:98
std::string str(char sep='x') const
Definition: dim-vector.cc:68
void chop_trailing_singletons()
Definition: dim-vector.h:164
dim_vector squeeze() const
Definition: dim-vector.cc:117
void resize(int n, int fill_value=0)
Definition: dim-vector.h:272
static dim_vector alloc(int n)
Definition: dim-vector.h:202
Array< octave_idx_type > as_array() const
Definition: dim-vector.cc:266
octave_idx_type ndims() const
Number of dimensions.
Definition: dim-vector.h:257
static octave_idx_type dim_max()
Definition: dim-vector.cc:44
void chop_all_singletons()
Definition: dim-vector.cc:50
bool hvcat(const dim_vector &dvb, int dim)
This corresponds to [,] (horzcat, dim = 0) and [;] (vertcat, dim = 1).
Definition: dim-vector.cc:201
octave_idx_type & xelem(int i)
Definition: dim-vector.h:151
int num_ones() const
Definition: dim-vector.cc:86
dim_vector redim(int n) const
Force certain dimensionality, preserving numel ().
Definition: dim-vector.cc:226
octave_idx_type & elem(int i)
Definition: dim-vector.h:157
dim_vector as_row() const
Definition: dim-vector.h:387
octave_idx_type n
Definition: mx-inlines.cc:761