GNU Octave 7.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
oct-binmap.h
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2010-2022 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.fortran_vec ();
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.fortran_vec ();
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 dim_vector xad = xa.dims ();
177 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))
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.fortran_vec ();
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 // FIXME: Could keep track of whether fcn call results in a 0.
240 // If no zeroes are created could skip maybe_compress()
241 retval.xdata (i) = fcn (x, ys.data (i));
242 }
243
244 octave_quit ();
245 retval.maybe_compress (true);
246 return retval;
247 }
248 else
249 return Sparse<U> (binmap<U, T, R, F> (x, ys.array_value (), fcn));
250}
251
252// Sparse-scalar
253template <typename U, typename T, typename R, typename F>
255binmap (const Sparse<T>& xs, const R& y, F fcn)
256{
257 T xzero = T ();
258 U fz = fcn (xzero, y);
259
260 if (fz == U ()) // Sparsity preserving fcn
261 {
262 octave_idx_type nz = xs.nnz ();
263 Sparse<U> retval (xs.rows (), xs.cols (), nz);
264 std::copy (xs.ridx (), xs.ridx () + nz, retval.ridx ());
265 std::copy (xs.cidx (), xs.cidx () + xs.cols () + 1, retval.cidx ());
266
267 for (octave_idx_type i = 0; i < nz; i++)
268 {
269 octave_quit ();
270 // FIXME: Could keep track of whether fcn call results in a 0.
271 // If no zeroes are created could skip maybe_compress()
272 retval.xdata (i) = fcn (xs.data (i), y);
273 }
274
275 octave_quit ();
276 retval.maybe_compress (true);
277 return retval;
278 }
279 else
280 return Sparse<U> (binmap<U, T, R, F> (xs.array_value (), y, fcn));
281}
282
283// Sparse-Sparse (treats singletons as scalars)
284template <typename U, typename T, typename R, typename F>
286binmap (const Sparse<T>& xs, const Sparse<R>& ys, F fcn, const char *name)
287{
288 if (xs.rows () == 1 && xs.cols () == 1)
289 return binmap<U, T, R, F> (xs(0, 0), ys, fcn);
290 else if (ys.rows () == 1 && ys.cols () == 1)
291 return binmap<U, T, R, F> (xs, ys(0, 0), fcn);
292 else if (xs.dims () != ys.dims ())
293 octave::err_nonconformant (name, xs.dims (), ys.dims ());
294
295 T xzero = T ();
296 R yzero = R ();
297 U fz = fcn (xzero, yzero);
298
299 if (fz == U ())
300 {
301 // Sparsity-preserving function. Do it efficiently.
302 octave_idx_type nr = xs.rows ();
303 octave_idx_type nc = xs.cols ();
304 Sparse<T> retval (nr, nc, xs.nnz () + ys.nnz ());
305
306 octave_idx_type nz = 0;
307 for (octave_idx_type j = 0; j < nc; j++)
308 {
309 octave_quit ();
310
311 octave_idx_type jx = xs.cidx (j);
312 octave_idx_type jx_max = xs.cidx (j+1);
313 bool jx_lt_max = jx < jx_max;
314
315 octave_idx_type jy = ys.cidx (j);
316 octave_idx_type jy_max = ys.cidx (j+1);
317 bool jy_lt_max = jy < jy_max;
318
319 while (jx_lt_max || jy_lt_max)
320 {
321 if (! jy_lt_max
322 || (jx_lt_max && (xs.ridx (jx) < ys.ridx (jy))))
323 {
324 retval.xridx (nz) = xs.ridx (jx);
325 retval.xdata (nz) = fcn (xs.data (jx), yzero);
326 jx++;
327 jx_lt_max = jx < jx_max;
328 }
329 else if (! jx_lt_max
330 || (jy_lt_max && (ys.ridx (jy) < xs.ridx (jx))))
331 {
332 retval.xridx (nz) = ys.ridx (jy);
333 retval.xdata (nz) = fcn (xzero, ys.data (jy));
334 jy++;
335 jy_lt_max = jy < jy_max;
336 }
337 else
338 {
339 retval.xridx (nz) = xs.ridx (jx);
340 retval.xdata (nz) = fcn (xs.data (jx), ys.data (jy));
341 jx++;
342 jx_lt_max = jx < jx_max;
343 jy++;
344 jy_lt_max = jy < jy_max;
345 }
346 nz++;
347 }
348 retval.xcidx (j+1) = nz;
349 }
350
351 retval.maybe_compress (true);
352 return retval;
353 }
354 else
355 return Sparse<U> (binmap<U, T, R, F> (xs.array_value (), ys.array_value (),
356 fcn, name));
357}
358
359// Overloads for function pointers.
360
361// Signature (T, R)
362
363template <typename U, typename T, typename R>
364inline Array<U>
365binmap (const Array<T>& xa, const Array<R>& ya, U (*fcn) (T, R),
366 const char *name)
367{ return binmap<U, T, R, U (*) (T, R)> (xa, ya, fcn, name); }
368
369template <typename U, typename T, typename R>
370inline Array<U>
371binmap (const T& x, const Array<R>& ya, U (*fcn) (T, R))
372{ return binmap<U, T, R, U (*) (T, R)> (x, ya, fcn); }
373
374template <typename U, typename T, typename R>
375inline Array<U>
376binmap (const Array<T>& xa, const R& y, U (*fcn) (T, R))
377{ return binmap<U, T, R, U (*) (T, R)> (xa, y, fcn); }
378
379template <typename U, typename T, typename R>
380inline Sparse<U>
381binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (*fcn) (T, R),
382 const char *name)
383{ return binmap<U, T, R, U (*) (T, R)> (xa, ya, fcn, name); }
384
385template <typename U, typename T, typename R>
386inline Sparse<U>
387binmap (const T& x, const Sparse<R>& ya, U (*fcn) (T, R))
388{ return binmap<U, T, R, U (*) (T, R)> (x, ya, fcn); }
389
390template <typename U, typename T, typename R>
391inline Sparse<U>
392binmap (const Sparse<T>& xa, const R& y, U (*fcn) (T, R))
393{ return binmap<U, T, R, U (*) (T, R)> (xa, y, fcn); }
394
395// Signature (const T&, const R&)
396
397template <typename U, typename T, typename R>
398inline Array<U>
399binmap (const Array<T>& xa, const Array<R>& ya, U (*fcn) (const T&, const R&),
400 const char *name)
401{ return binmap<U, T, R, U (*) (const T&, const R&)> (xa, ya, fcn, name); }
402
403template <typename U, typename T, typename R>
404inline Array<U>
405binmap (const T& x, const Array<R>& ya, U (*fcn) (const T&, const R&))
406{ return binmap<U, T, R, U (*) (const T&, const R&)> (x, ya, fcn); }
407
408template <typename U, typename T, typename R>
409inline Array<U>
410binmap (const Array<T>& xa, const R& y, U (*fcn) (const T&, const R&))
411{ return binmap<U, T, R, U (*) (const T&, const R&)> (xa, y, fcn); }
412
413template <typename U, typename T, typename R>
414inline Sparse<U>
415binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (*fcn) (const T&, const R&),
416 const char *name)
417{ return binmap<U, T, R, U (*) (const T&, const R&)> (xa, ya, fcn, name); }
418
419template <typename U, typename T, typename R>
420inline Sparse<U>
421binmap (const T& x, const Sparse<R>& ya, U (*fcn) (const T&, const R&))
422{ return binmap<U, T, R, U (*) (const T&, const R&)> (x, ya, fcn); }
423
424template <typename U, typename T, typename R>
425inline Sparse<U>
426binmap (const Sparse<T>& xa, const R& y, U (*fcn) (const T&, const R&))
427{ return binmap<U, T, R, U (*) (const T&, const R&)> (xa, y, fcn); }
428
429// Signature (const T&, R)
430
431template <typename U, typename T, typename R>
432inline Array<U>
433binmap (const Array<T>& xa, const Array<R>& ya, U (*fcn) (const T&, R),
434 const char *name)
435{ return binmap<U, T, R, U (*) (const T&, R)> (xa, ya, fcn, name); }
436
437template <typename U, typename T, typename R>
438inline Array<U>
439binmap (const T& x, const Array<R>& ya, U (*fcn) (const T&, R))
440{ return binmap<U, T, R, U (*) (const T&, R)> (x, ya, fcn); }
441
442template <typename U, typename T, typename R>
443inline Array<U>
444binmap (const Array<T>& xa, const R& y, U (*fcn) (const T&, R))
445{ return binmap<U, T, R, U (*) (const T&, R)> (xa, y, fcn); }
446
447template <typename U, typename T, typename R>
448inline Sparse<U>
449binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (*fcn) (const T&, R),
450 const char *name)
451{ return binmap<U, T, R, U (*) (const T&, R)> (xa, ya, fcn, name); }
452
453template <typename U, typename T, typename R>
454inline Sparse<U>
455binmap (const T& x, const Sparse<R>& ya, U (*fcn) (const T&, R))
456{ return binmap<U, T, R, U (*) (const T&, R)> (x, ya, fcn); }
457
458template <typename U, typename T, typename R>
459inline Sparse<U>
460binmap (const Sparse<T>& xa, const R& y, U (*fcn) (const T&, R))
461{ return binmap<U, T, R, U (*) (const T&, R)> (xa, y, fcn); }
462
463// Signature (T, const R&)
464
465template <typename U, typename T, typename R>
466inline Array<U>
467binmap (const Array<T>& xa, const Array<R>& ya, U (*fcn) (T, const R&),
468 const char *name)
469{ return binmap<U, T, R, U (*) (T, const R&)> (xa, ya, fcn, name); }
470
471template <typename U, typename T, typename R>
472inline Array<U>
473binmap (const T& x, const Array<R>& ya, U (*fcn) (T, const R&))
474{ return binmap<U, T, R, U (*) (T, const R&)> (x, ya, fcn); }
475
476template <typename U, typename T, typename R>
477inline Array<U>
478binmap (const Array<T>& xa, const R& y, U (*fcn) (T, const R&))
479{ return binmap<U, T, R, U (*) (T, const R&)> (xa, y, fcn); }
480
481template <typename U, typename T, typename R>
482inline Sparse<U>
483binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (*fcn) (T, const R&),
484 const char *name)
485{ return binmap<U, T, R, U (*) (T, const R&)> (xa, ya, fcn, name); }
486
487template <typename U, typename T, typename R>
488inline Sparse<U>
489binmap (const T& x, const Sparse<R>& ya, U (*fcn) (T, const R&))
490{ return binmap<U, T, R, U (*) (T, const R&)> (x, ya, fcn); }
491
492template <typename U, typename T, typename R>
493inline Sparse<U>
494binmap (const Sparse<T>& xa, const R& y, U (*fcn) (T, const R&))
495{ return binmap<U, T, R, U (*) (T, const R&)> (xa, y, fcn); }
496
497#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
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:129
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:411
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:487
const T * data(void) const
Size of the specified dimension.
Definition: Array.h:616
OCTARRAY_API T * fortran_vec(void)
Size of the specified dimension.
Definition: Array.cc:1744
Definition: Sparse.h:49
octave_idx_type rows(void) const
Definition: Sparse.h:351
T * data(void)
Definition: Sparse.h:574
T * xdata(void)
Definition: Sparse.h:576
octave_idx_type nnz(void) const
Actual number of nonzero terms.
Definition: Sparse.h:339
OCTAVE_API Array< T > array_value(void) const
Definition: Sparse.cc:2766
octave_idx_type * xridx(void)
Definition: Sparse.h:589
dim_vector dims(void) const
Definition: Sparse.h:371
octave_idx_type * ridx(void)
Definition: Sparse.h:583
octave_idx_type * cidx(void)
Definition: Sparse.h:596
octave_idx_type * xcidx(void)
Definition: Sparse.h:602
Sparse< T, Alloc > maybe_compress(bool remove_zeros=false)
Definition: Sparse.h:531
octave_idx_type cols(void) const
Definition: Sparse.h:352
static F s_fcn
Definition: oct-binmap.h:73
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:94
QString name
F77_RET_T const F77_DBLE * x
void F(const TSRC *v, TRES *r, octave_idx_type m, octave_idx_type n)
Definition: mx-inlines.cc:757
void err_nonconformant(const char *op, octave_idx_type op1_len, octave_idx_type op2_len)
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