GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
bsxfun-defs.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2009-2024 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if ! defined (octave_bsxfun_defs_h)
27 #define octave_bsxfun_defs_h 1
28 
29 // This file should *not* include config.h. It is only included in other C++
30 // source files that should have included config.h before including this file.
31 
32 #include <algorithm>
33 
34 #include "dim-vector.h"
35 #include "lo-error.h"
36 #include "mx-inlines.cc"
37 #include "oct-locbuf.h"
38 
39 template <typename R, typename X, typename Y>
41 do_bsxfun_op (const Array<X>& x, const Array<Y>& y,
42  void (*op_vv) (std::size_t, R *, const X *, const Y *),
43  void (*op_sv) (std::size_t, R *, X, const Y *),
44  void (*op_vs) (std::size_t, R *, const X *, Y))
45 {
46  int nd = std::max (x.ndims (), y.ndims ());
47  dim_vector dvx = x.dims ().redim (nd);
48  dim_vector dvy = y.dims ().redim (nd);
49 
50  // Construct the result dimensions.
51  dim_vector dvr;
52  dvr.resize (nd);
53  for (int i = 0; i < nd; i++)
54  {
55  octave_idx_type xk = dvx(i);
56  octave_idx_type yk = dvy(i);
57  if (xk == 1)
58  dvr(i) = yk;
59  else if (yk == 1 || xk == yk)
60  dvr(i) = xk;
61  else
63  ("bsxfun: nonconformant dimensions: %s and %s",
64  x.dims ().str ().c_str (), y.dims ().str ().c_str ());
65  }
66 
67  Array<R> retval (dvr);
68 
69  const X *xvec = x.data ();
70  const Y *yvec = y.data ();
71  R *rvec = retval.fortran_vec ();
72 
73  // Fold the common leading dimensions.
74  octave_idx_type start, ldr = 1;
75  for (start = 0; start < nd; start++)
76  {
77  if (dvx(start) != dvy(start))
78  break;
79  ldr *= dvr(start);
80  }
81 
82  if (retval.isempty ())
83  ; // do nothing
84  else if (start == nd)
85  op_vv (retval.numel (), rvec, xvec, yvec);
86  else
87  {
88  // Determine the type of the low-level loop.
89  bool xsing = false;
90  bool ysing = false;
91  if (ldr == 1)
92  {
93  xsing = dvx(start) == 1;
94  ysing = dvy(start) == 1;
95  if (xsing || ysing)
96  {
97  ldr *= dvx(start) * dvy(start);
98  start++;
99  }
100  }
101  dim_vector cdvx = dvx.cumulative ();
102  dim_vector cdvy = dvy.cumulative ();
103  // Nullify singleton dims to achieve a spread effect.
104  for (int i = std::max (start, octave_idx_type (1)); i < nd; i++)
105  {
106  if (dvx(i) == 1)
107  cdvx(i-1) = 0;
108  if (dvy(i) == 1)
109  cdvy(i-1) = 0;
110  }
111 
112  octave_idx_type niter = dvr.numel (start);
113  // The index array.
115  for (octave_idx_type iter = 0; iter < niter; iter++)
116  {
117  octave_quit ();
118 
119  // Compute indices.
120  // FIXME: performance impact noticeable?
121  octave_idx_type xidx = cdvx.cum_compute_index (idx);
122  octave_idx_type yidx = cdvy.cum_compute_index (idx);
123  octave_idx_type ridx = dvr.compute_index (idx);
124 
125  // Apply the low-level loop.
126  if (xsing)
127  op_sv (ldr, rvec + ridx, xvec[xidx], yvec + yidx);
128  else if (ysing)
129  op_vs (ldr, rvec + ridx, xvec + xidx, yvec[yidx]);
130  else
131  op_vv (ldr, rvec + ridx, xvec + xidx, yvec + yidx);
132 
133  dvr.increment_index (idx + start, start);
134  }
135  }
136 
137  return retval;
138 }
139 
140 template <typename R, typename X>
141 void
143  void (*op_vv) (std::size_t, R *, const X *),
144  void (*op_vs) (std::size_t, R *, X))
145 {
146  dim_vector dvr = r.dims ();
147  dim_vector dvx = x.dims ();
148  octave_idx_type nd = r.ndims ();
149  dvx = dvx.redim (nd);
150 
151  const X *xvec = x.data ();
152  R *rvec = r.fortran_vec ();
153 
154  // Fold the common leading dimensions.
155  octave_idx_type start, ldr = 1;
156  for (start = 0; start < nd; start++)
157  {
158  if (dvr(start) != dvx(start))
159  break;
160  ldr *= dvr(start);
161  }
162 
163  if (r.isempty ())
164  ; // do nothing
165  else if (start == nd)
166  op_vv (r.numel (), rvec, xvec);
167  else
168  {
169  // Determine the type of the low-level loop.
170  bool xsing = false;
171  if (ldr == 1)
172  {
173  xsing = dvx(start) == 1;
174  if (xsing)
175  {
176  ldr *= dvr(start) * dvx(start);
177  start++;
178  }
179  }
180 
181  dim_vector cdvx = dvx.cumulative ();
182  // Nullify singleton dims to achieve a spread effect.
183  for (int i = std::max (start, octave_idx_type (1)); i < nd; i++)
184  {
185  if (dvx(i) == 1)
186  cdvx(i-1) = 0;
187  }
188 
189  octave_idx_type niter = dvr.numel (start);
190  // The index array.
192  for (octave_idx_type iter = 0; iter < niter; iter++)
193  {
194  octave_quit ();
195 
196  // Compute indices.
197  // FIXME: performance impact noticeable?
198  octave_idx_type xidx = cdvx.cum_compute_index (idx);
199  octave_idx_type ridx = dvr.compute_index (idx);
200 
201  // Apply the low-level loop.
202  if (xsing)
203  op_vs (ldr, rvec + ridx, xvec[xidx]);
204  else
205  op_vv (ldr, rvec + ridx, xvec + xidx);
206 
207  dvr.increment_index (idx + start, start);
208  }
209  }
210 }
211 
212 #define BSXFUN_OP_DEF(OP, ARRAY) \
213  ARRAY bsxfun_ ## OP (const ARRAY& x, const ARRAY& y)
214 
215 #define BSXFUN_OP2_DEF(OP, ARRAY, ARRAY1, ARRAY2) \
216  ARRAY bsxfun_ ## OP (const ARRAY1& x, const ARRAY2& y)
217 
218 #define BSXFUN_REL_DEF(OP, ARRAY) \
219  boolNDArray bsxfun_ ## OP (const ARRAY& x, const ARRAY& y)
220 
221 #define BSXFUN_OP_DEF_MXLOOP(OP, ARRAY, LOOP) \
222  BSXFUN_OP_DEF(OP, ARRAY) \
223  { return do_bsxfun_op<ARRAY::element_type, ARRAY::element_type, ARRAY::element_type> \
224  (x, y, LOOP, LOOP, LOOP); }
225 
226 #define BSXFUN_OP2_DEF_MXLOOP(OP, ARRAY, ARRAY1, ARRAY2, LOOP) \
227  BSXFUN_OP2_DEF(OP, ARRAY, ARRAY1, ARRAY2) \
228  { return do_bsxfun_op<ARRAY::element_type, ARRAY1::element_type, ARRAY2::element_type> \
229  (x, y, LOOP, LOOP, LOOP); }
230 
231 #define BSXFUN_REL_DEF_MXLOOP(OP, ARRAY, LOOP) \
232  BSXFUN_REL_DEF(OP, ARRAY) \
233  { return do_bsxfun_op<bool, ARRAY::element_type, ARRAY::element_type> \
234  (x, y, LOOP, LOOP, LOOP); }
235 
236 #define BSXFUN_STDOP_DEFS_MXLOOP(ARRAY) \
237  BSXFUN_OP_DEF_MXLOOP (add, ARRAY, mx_inline_add) \
238  BSXFUN_OP_DEF_MXLOOP (sub, ARRAY, mx_inline_sub) \
239  BSXFUN_OP_DEF_MXLOOP (mul, ARRAY, mx_inline_mul) \
240  BSXFUN_OP_DEF_MXLOOP (div, ARRAY, mx_inline_div) \
241  BSXFUN_OP_DEF_MXLOOP (min, ARRAY, mx_inline_xmin) \
242  BSXFUN_OP_DEF_MXLOOP (max, ARRAY, mx_inline_xmax)
243 
244 #define BSXFUN_STDREL_DEFS_MXLOOP(ARRAY) \
245  BSXFUN_REL_DEF_MXLOOP (eq, ARRAY, mx_inline_eq) \
246  BSXFUN_REL_DEF_MXLOOP (ne, ARRAY, mx_inline_ne) \
247  BSXFUN_REL_DEF_MXLOOP (lt, ARRAY, mx_inline_lt) \
248  BSXFUN_REL_DEF_MXLOOP (le, ARRAY, mx_inline_le) \
249  BSXFUN_REL_DEF_MXLOOP (gt, ARRAY, mx_inline_gt) \
250  BSXFUN_REL_DEF_MXLOOP (ge, ARRAY, mx_inline_ge)
251 
252 //For bsxfun power with mixed integer/float types
253 #define BSXFUN_POW_MIXED_MXLOOP(INT_TYPE) \
254  BSXFUN_OP2_DEF_MXLOOP (pow, INT_TYPE, INT_TYPE, NDArray, mx_inline_pow) \
255  BSXFUN_OP2_DEF_MXLOOP (pow, INT_TYPE, INT_TYPE, FloatNDArray, mx_inline_pow) \
256  BSXFUN_OP2_DEF_MXLOOP (pow, INT_TYPE, NDArray, INT_TYPE, mx_inline_pow) \
257  BSXFUN_OP2_DEF_MXLOOP (pow, INT_TYPE, FloatNDArray, INT_TYPE, mx_inline_pow)
258 
259 #endif
Array< R > do_bsxfun_op(const Array< X > &x, const Array< Y > &y, void(*op_vv)(std::size_t, R *, const X *, const Y *), void(*op_sv)(std::size_t, R *, X, const Y *), void(*op_vs)(std::size_t, R *, const X *, Y))
Definition: bsxfun-defs.cc:41
void do_inplace_bsxfun_op(Array< R > &r, const Array< X > &x, void(*op_vv)(std::size_t, R *, const X *), void(*op_vs)(std::size_t, R *, X))
Definition: bsxfun-defs.cc:142
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
N Dimensional Array with copy-on-write semantics.
Definition: Array.h:130
T * fortran_vec()
Size of the specified dimension.
Definition: Array-base.cc:1764
int ndims() const
Size of the specified dimension.
Definition: Array.h:671
const T * data() const
Size of the specified dimension.
Definition: Array.h:663
bool isempty() const
Size of the specified dimension.
Definition: Array.h:651
const dim_vector & dims() const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:503
octave_idx_type numel() const
Number of elements in the array.
Definition: Array.h:414
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
octave_idx_type compute_index(const octave_idx_type *idx) const
Linear index from an index tuple.
Definition: dim-vector.h:456
std::string str(char sep='x') const
Definition: dim-vector.cc:68
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition: dim-vector.h:335
void resize(int n, int fill_value=0)
Definition: dim-vector.h:272
int increment_index(octave_idx_type *idx, int start=0) const
Increment a multi-dimensional index tuple, optionally starting from an offset position and return the...
Definition: dim-vector.h:473
dim_vector cumulative() const
Return cumulative dimensions.
Definition: dim-vector.h:488
octave_idx_type cum_compute_index(const octave_idx_type *idx) const
Compute a linear index from an index tuple.
Definition: dim-vector.h:503
dim_vector redim(int n) const
Force certain dimensionality, preserving numel ().
Definition: dim-vector.cc:226
OCTAVE_NORETURN liboctave_error_handler current_liboctave_error_handler
Definition: lo-error.c:41
F77_RET_T const F77_DBLE * x
T * r
Definition: mx-inlines.cc:781
#define OCTAVE_LOCAL_BUFFER_INIT(T, buf, size, value)
Definition: oct-locbuf.h:50