GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
bsxfun-defs.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2009-2025 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
39template <typename R, typename X, typename Y>
41do_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 const dim_vector& dvx = x.dims ().redim (nd);
48 const 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.rwdata ();
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
140template <typename R, typename X>
141void
143 void (*op_vv) (std::size_t, R *, const X *),
144 void (*op_vs) (std::size_t, R *, X))
145{
146 const 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.rwdata ();
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))
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))
N Dimensional Array with copy-on-write semantics.
Definition Array.h:130
const dim_vector & dims() const
Return a const-reference so that dims ()(i) works efficiently.
Definition Array.h:507
int ndims() const
Size of the specified dimension.
Definition Array.h:679
bool isempty() const
Size of the specified dimension.
Definition Array.h:652
const T * data() const
Size of the specified dimension.
Definition Array.h:665
T * rwdata()
Size of the specified dimension.
octave_idx_type numel() const
Number of elements in the array.
Definition Array.h:418
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:90
octave_idx_type compute_index(const octave_idx_type *idx) const
Linear index from an index tuple.
Definition dim-vector.h:452
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:331
void resize(int n, int fill_value=0)
Definition dim-vector.h:268
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:469
dim_vector cumulative() const
Return cumulative dimensions.
Definition dim-vector.h:484
octave_idx_type cum_compute_index(const octave_idx_type *idx) const
Compute a linear index from an index tuple.
Definition dim-vector.h:499
dim_vector redim(int n) const
Force certain dimensionality, preserving numel ().
OCTAVE_NORETURN liboctave_error_handler current_liboctave_error_handler
Definition lo-error.c:41
F77_RET_T const F77_DBLE * x
#define OCTAVE_LOCAL_BUFFER_INIT(T, buf, size, value)
Definition oct-locbuf.h:50