GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
oct-binmap.h
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2010-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_oct_binmap_h)
27#define octave_oct_binmap_h 1
28
29#include "octave-config.h"
30
31#include "Array.h"
32#include "Sparse.h"
33#include "Array-util.h"
34
35#include "bsxfun.h"
36
37// This source file implements a general binary mapping function for arrays.
38// The syntax is binmap<type> (a, b, f,[name]).
39// type denotes the expected return type of the operation.
40// a, b, should be one of the 6 combinations:
41//
42// Array-Array
43// Array-scalar
44// scalar-Array
45// Sparse-Sparse
46// Sparse-scalar
47// scalar-Sparse
48//
49// If both operands are nonscalar, name must be supplied. It is used
50// as the base for error message when operands are nonconforming.
51//
52// The operation needs not be homogeneous, i.e., a, b and the result
53// may be of distinct types. f can have any of the four signatures:
54//
55// U f (T, R)
56// U f (const T&, R)
57// U f (T, const R&)
58// U f (const T&, const R&)
59//
60// Additionally, f can be an arbitrary functor object.
61//
62// octave_quit() is called at appropriate places, hence the operation
63// is breakable.
64
65// The following template wrappers are provided for automatic bsxfun
66// calls (see the function signature for do_bsxfun_op).
67
68template <typename R, typename X, typename Y, typename F>
70{
71private:
72
73 static F s_fcn;
74
75public:
76
77 static void
78 set_f (const F& f_in)
79 {
80 s_fcn = f_in;
81 }
82
83 static void
84 op_mm (std::size_t n, R *r, const X *x, const Y *y)
85 {
86 for (std::size_t i = 0; i < n; i++)
87 r[i] = s_fcn (x[i], y[i]);
88 }
89
90 static void
91 op_sm (std::size_t n, R *r, X x, const Y *y)
92 {
93 for (std::size_t i = 0; i < n; i++)
94 r[i] = s_fcn (x, y[i]);
95 }
96
97 static void
98 op_ms (std::size_t n, R *r, const X *x, Y y)
99 {
100 for (std::size_t i = 0; i < n; i++)
101 r[i] = s_fcn (x[i], y);
102 }
103};
104
105// Static init
106template <typename R, typename X, typename Y, typename F>
108
109// scalar-Array
110template <typename U, typename T, typename R, typename F>
112binmap (const T& x, const Array<R>& ya, F fcn)
113{
114 octave_idx_type len = ya.numel ();
115
116 const R *y = ya.data ();
117
118 Array<U> result (ya.dims ());
119 U *p = result.rwdata ();
120
122 for (i = 0; i < len - 3; i += 4)
123 {
124 octave_quit ();
125
126 p[i] = fcn (x, y[i]);
127 p[i+1] = fcn (x, y[i+1]);
128 p[i+2] = fcn (x, y[i+2]);
129 p[i+3] = fcn (x, y[i+3]);
130 }
131
132 octave_quit ();
133
134 for (; i < len; i++)
135 p[i] = fcn (x, y[i]);
136
137 return result;
138}
139
140// Array-scalar
141template <typename U, typename T, typename R, typename F>
143binmap (const Array<T>& xa, const R& y, F fcn)
144{
145 octave_idx_type len = xa.numel ();
146
147 const R *x = xa.data ();
148
149 Array<U> result (xa.dims ());
150 U *p = result.rwdata ();
151
153 for (i = 0; i < len - 3; i += 4)
154 {
155 octave_quit ();
156
157 p[i] = fcn (x[i], y);
158 p[i+1] = fcn (x[i+1], y);
159 p[i+2] = fcn (x[i+2], y);
160 p[i+3] = fcn (x[i+3], y);
161 }
162
163 octave_quit ();
164
165 for (; i < len; i++)
166 p[i] = fcn (x[i], y);
167
168 return result;
169}
170
171// Array-Array (treats singletons as scalars)
172template <typename U, typename T, typename R, typename F>
174binmap (const Array<T>& xa, const Array<R>& ya, F fcn, const char *name)
175{
176 const dim_vector& xad = xa.dims ();
177 const dim_vector& yad = ya.dims ();
178 if (xa.numel () == 1)
179 return binmap<U, T, R, F> (xa(0), ya, fcn);
180 else if (ya.numel () == 1)
181 return binmap<U, T, R, F> (xa, ya(0), fcn);
182 else if (xad != yad)
183 {
184 if (! is_valid_bsxfun (name, xad, yad))
185 octave::err_nonconformant (name, xad, yad);
186
188 return do_bsxfun_op (xa, ya,
192 }
193
194 octave_idx_type len = xa.numel ();
195
196 const T *x = xa.data ();
197 const T *y = ya.data ();
198
199 Array<U> result (xa.dims ());
200 U *p = result.rwdata ();
201
203 for (i = 0; i < len - 3; i += 4)
204 {
205 octave_quit ();
206
207 p[i] = fcn (x[i], y[i]);
208 p[i+1] = fcn (x[i+1], y[i+1]);
209 p[i+2] = fcn (x[i+2], y[i+2]);
210 p[i+3] = fcn (x[i+3], y[i+3]);
211 }
212
213 octave_quit ();
214
215 for (; i < len; i++)
216 p[i] = fcn (x[i], y[i]);
217
218 return result;
219}
220
221// scalar-Sparse
222template <typename U, typename T, typename R, typename F>
224binmap (const T& x, const Sparse<R>& ys, F fcn)
225{
226 R yzero = R ();
227 U fz = fcn (x, yzero);
228
229 if (fz == U ()) // Sparsity preserving fcn
230 {
231 octave_idx_type nz = ys.nnz ();
232 Sparse<U> retval (ys.rows (), ys.cols (), nz);
233 std::copy (ys.ridx (), ys.ridx () + nz, retval.ridx ());
234 std::copy (ys.cidx (), ys.cidx () + ys.cols () + 1, retval.cidx ());
235
236 for (octave_idx_type i = 0; i < nz; i++)
237 {
238 octave_quit ();
239 retval.xdata (i) = fcn (x, ys.data (i));
240 }
241
242 octave_quit ();
243 retval.maybe_compress (true);
244 return retval;
245 }
246 else
247 return Sparse<U> (binmap<U, T, R, F> (x, ys.array_value (), fcn));
248}
249
250// Sparse-scalar
251template <typename U, typename T, typename R, typename F>
253binmap (const Sparse<T>& xs, const R& y, F fcn)
254{
255 T xzero = T ();
256 U fz = fcn (xzero, y);
257
258 if (fz == U ()) // Sparsity preserving fcn
259 {
260 octave_idx_type nz = xs.nnz ();
261 Sparse<U> retval (xs.rows (), xs.cols (), nz);
262 std::copy (xs.ridx (), xs.ridx () + nz, retval.ridx ());
263 std::copy (xs.cidx (), xs.cidx () + xs.cols () + 1, retval.cidx ());
264
265 for (octave_idx_type i = 0; i < nz; i++)
266 {
267 octave_quit ();
268 retval.xdata (i) = fcn (xs.data (i), y);
269 }
270
271 octave_quit ();
272 retval.maybe_compress (true);
273 return retval;
274 }
275 else
276 return Sparse<U> (binmap<U, T, R, F> (xs.array_value (), y, fcn));
277}
278
279// Sparse-Sparse (treats singletons as scalars)
280template <typename U, typename T, typename R, typename F>
282binmap (const Sparse<T>& xs, const Sparse<R>& ys, F fcn, const char *name)
283{
284 if (xs.rows () == 1 && xs.cols () == 1)
285 return binmap<U, T, R, F> (xs(0, 0), ys, fcn);
286 else if (ys.rows () == 1 && ys.cols () == 1)
287 return binmap<U, T, R, F> (xs, ys(0, 0), fcn);
288 else if (xs.dims () != ys.dims ())
289 octave::err_nonconformant (name, xs.dims (), ys.dims ());
290
291 T xzero = T ();
292 R yzero = R ();
293 U fz = fcn (xzero, yzero);
294
295 if (fz == U ())
296 {
297 // Sparsity-preserving function. Do it efficiently.
298 octave_idx_type nr = xs.rows ();
299 octave_idx_type nc = xs.cols ();
300 Sparse<T> retval (nr, nc, xs.nnz () + ys.nnz ());
301
302 octave_idx_type nz = 0;
303 for (octave_idx_type j = 0; j < nc; j++)
304 {
305 octave_quit ();
306
307 octave_idx_type jx = xs.cidx (j);
308 octave_idx_type jx_max = xs.cidx (j+1);
309 bool jx_lt_max = jx < jx_max;
310
311 octave_idx_type jy = ys.cidx (j);
312 octave_idx_type jy_max = ys.cidx (j+1);
313 bool jy_lt_max = jy < jy_max;
314
315 while (jx_lt_max || jy_lt_max)
316 {
317 if (! jy_lt_max
318 || (jx_lt_max && (xs.ridx (jx) < ys.ridx (jy))))
319 {
320 retval.xridx (nz) = xs.ridx (jx);
321 retval.xdata (nz) = fcn (xs.data (jx), yzero);
322 jx++;
323 jx_lt_max = jx < jx_max;
324 }
325 else if (! jx_lt_max
326 || (jy_lt_max && (ys.ridx (jy) < xs.ridx (jx))))
327 {
328 retval.xridx (nz) = ys.ridx (jy);
329 retval.xdata (nz) = fcn (xzero, ys.data (jy));
330 jy++;
331 jy_lt_max = jy < jy_max;
332 }
333 else
334 {
335 retval.xridx (nz) = xs.ridx (jx);
336 retval.xdata (nz) = fcn (xs.data (jx), ys.data (jy));
337 jx++;
338 jx_lt_max = jx < jx_max;
339 jy++;
340 jy_lt_max = jy < jy_max;
341 }
342 nz++;
343 }
344 retval.xcidx (j+1) = nz;
345 }
346
347 retval.maybe_compress (true);
348 return retval;
349 }
350 else
351 return Sparse<U> (binmap<U, T, R, F> (xs.array_value (), ys.array_value (),
352 fcn, name));
353}
354
355// Overloads for function pointers.
356
357// Signature (T, R)
358
359template <typename U, typename T, typename R>
360inline Array<U>
361binmap (const Array<T>& xa, const Array<R>& ya, U (*fcn) (T, R),
362 const char *name)
363{ return binmap<U, T, R, U (*) (T, R)> (xa, ya, fcn, name); }
364
365template <typename U, typename T, typename R>
366inline Array<U>
367binmap (const T& x, const Array<R>& ya, U (*fcn) (T, R))
368{ return binmap<U, T, R, U (*) (T, R)> (x, ya, fcn); }
369
370template <typename U, typename T, typename R>
371inline Array<U>
372binmap (const Array<T>& xa, const R& y, U (*fcn) (T, R))
373{ return binmap<U, T, R, U (*) (T, R)> (xa, y, fcn); }
374
375template <typename U, typename T, typename R>
376inline Sparse<U>
377binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (*fcn) (T, R),
378 const char *name)
379{ return binmap<U, T, R, U (*) (T, R)> (xa, ya, fcn, name); }
380
381template <typename U, typename T, typename R>
382inline Sparse<U>
383binmap (const T& x, const Sparse<R>& ya, U (*fcn) (T, R))
384{ return binmap<U, T, R, U (*) (T, R)> (x, ya, fcn); }
385
386template <typename U, typename T, typename R>
387inline Sparse<U>
388binmap (const Sparse<T>& xa, const R& y, U (*fcn) (T, R))
389{ return binmap<U, T, R, U (*) (T, R)> (xa, y, fcn); }
390
391// Signature (const T&, const R&)
392
393template <typename U, typename T, typename R>
394inline Array<U>
395binmap (const Array<T>& xa, const Array<R>& ya, U (*fcn) (const T&, const R&),
396 const char *name)
397{ return binmap<U, T, R, U (*) (const T&, const R&)> (xa, ya, fcn, name); }
398
399template <typename U, typename T, typename R>
400inline Array<U>
401binmap (const T& x, const Array<R>& ya, U (*fcn) (const T&, const R&))
402{ return binmap<U, T, R, U (*) (const T&, const R&)> (x, ya, fcn); }
403
404template <typename U, typename T, typename R>
405inline Array<U>
406binmap (const Array<T>& xa, const R& y, U (*fcn) (const T&, const R&))
407{ return binmap<U, T, R, U (*) (const T&, const R&)> (xa, y, fcn); }
408
409template <typename U, typename T, typename R>
410inline Sparse<U>
411binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (*fcn) (const T&, const R&),
412 const char *name)
413{ return binmap<U, T, R, U (*) (const T&, const R&)> (xa, ya, fcn, name); }
414
415template <typename U, typename T, typename R>
416inline Sparse<U>
417binmap (const T& x, const Sparse<R>& ya, U (*fcn) (const T&, const R&))
418{ return binmap<U, T, R, U (*) (const T&, const R&)> (x, ya, fcn); }
419
420template <typename U, typename T, typename R>
421inline Sparse<U>
422binmap (const Sparse<T>& xa, const R& y, U (*fcn) (const T&, const R&))
423{ return binmap<U, T, R, U (*) (const T&, const R&)> (xa, y, fcn); }
424
425// Signature (const T&, R)
426
427template <typename U, typename T, typename R>
428inline Array<U>
429binmap (const Array<T>& xa, const Array<R>& ya, U (*fcn) (const T&, R),
430 const char *name)
431{ return binmap<U, T, R, U (*) (const T&, R)> (xa, ya, fcn, name); }
432
433template <typename U, typename T, typename R>
434inline Array<U>
435binmap (const T& x, const Array<R>& ya, U (*fcn) (const T&, R))
436{ return binmap<U, T, R, U (*) (const T&, R)> (x, ya, fcn); }
437
438template <typename U, typename T, typename R>
439inline Array<U>
440binmap (const Array<T>& xa, const R& y, U (*fcn) (const T&, R))
441{ return binmap<U, T, R, U (*) (const T&, R)> (xa, y, fcn); }
442
443template <typename U, typename T, typename R>
444inline Sparse<U>
445binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (*fcn) (const T&, R),
446 const char *name)
447{ return binmap<U, T, R, U (*) (const T&, R)> (xa, ya, fcn, name); }
448
449template <typename U, typename T, typename R>
450inline Sparse<U>
451binmap (const T& x, const Sparse<R>& ya, U (*fcn) (const T&, R))
452{ return binmap<U, T, R, U (*) (const T&, R)> (x, ya, fcn); }
453
454template <typename U, typename T, typename R>
455inline Sparse<U>
456binmap (const Sparse<T>& xa, const R& y, U (*fcn) (const T&, R))
457{ return binmap<U, T, R, U (*) (const T&, R)> (xa, y, fcn); }
458
459// Signature (T, const R&)
460
461template <typename U, typename T, typename R>
462inline Array<U>
463binmap (const Array<T>& xa, const Array<R>& ya, U (*fcn) (T, const R&),
464 const char *name)
465{ return binmap<U, T, R, U (*) (T, const R&)> (xa, ya, fcn, name); }
466
467template <typename U, typename T, typename R>
468inline Array<U>
469binmap (const T& x, const Array<R>& ya, U (*fcn) (T, const R&))
470{ return binmap<U, T, R, U (*) (T, const R&)> (x, ya, fcn); }
471
472template <typename U, typename T, typename R>
473inline Array<U>
474binmap (const Array<T>& xa, const R& y, U (*fcn) (T, const R&))
475{ return binmap<U, T, R, U (*) (T, const R&)> (xa, y, fcn); }
476
477template <typename U, typename T, typename R>
478inline Sparse<U>
479binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (*fcn) (T, const R&),
480 const char *name)
481{ return binmap<U, T, R, U (*) (T, const R&)> (xa, ya, fcn, name); }
482
483template <typename U, typename T, typename R>
484inline Sparse<U>
485binmap (const T& x, const Sparse<R>& ya, U (*fcn) (T, const R&))
486{ return binmap<U, T, R, U (*) (T, const R&)> (x, ya, fcn); }
487
488template <typename U, typename T, typename R>
489inline Sparse<U>
490binmap (const Sparse<T>& xa, const R& y, U (*fcn) (T, const R&))
491{ return binmap<U, T, R, U (*) (T, const R&)> (xa, y, fcn); }
492
493#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))
bool is_valid_bsxfun(const std::string &name, const dim_vector &xdv, const dim_vector &ydv)
Definition bsxfun.h:39
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
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
octave_idx_type cols() const
Definition Sparse.h:349
Array< T > array_value() const
Definition Sparse.cc:2766
octave_idx_type * cidx()
Definition Sparse.h:593
T * data()
Definition Sparse.h:571
T * xdata()
Definition Sparse.h:573
octave_idx_type * ridx()
Definition Sparse.h:580
Sparse< T, Alloc > maybe_compress(bool remove_zeros=false)
Definition Sparse.h:528
octave_idx_type nnz() const
Actual number of nonzero terms.
Definition Sparse.h:336
octave_idx_type rows() const
Definition Sparse.h:348
dim_vector dims() const
Definition Sparse.h:368
octave_idx_type * xcidx()
Definition Sparse.h:599
octave_idx_type * xridx()
Definition Sparse.h:586
static void op_sm(std::size_t n, R *r, X x, const Y *y)
Definition oct-binmap.h:91
static void op_mm(std::size_t n, R *r, const X *x, const Y *y)
Definition oct-binmap.h:84
static void op_ms(std::size_t n, R *r, const X *x, Y y)
Definition oct-binmap.h:98
static void set_f(const F &f_in)
Definition oct-binmap.h:78
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:90
F77_RET_T const F77_DBLE * x
Array< U > binmap(const T &x, const Array< R > &ya, F fcn)
Definition oct-binmap.h:112
F77_RET_T len
Definition xerbla.cc:61