GNU Octave  6.2.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-2021 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 
68 template <typename R, typename X, typename Y, typename F>
70 {
71 private:
72 
73  static F s_fcn;
74 
75 public:
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 (size_t n, R *r, const X *x, const Y *y)
85  {
86  for (size_t i = 0; i < n; i++)
87  r[i] = s_fcn (x[i], y[i]);
88  }
89 
90  static void
91  op_sm (size_t n, R *r, X x, const Y *y)
92  {
93  for (size_t i = 0; i < n; i++)
94  r[i] = s_fcn (x, y[i]);
95  }
96 
97  static void
98  op_ms (size_t n, R *r, const X *x, Y y)
99  {
100  for (size_t i = 0; i < n; i++)
101  r[i] = s_fcn (x[i], y);
102  }
103 };
104 
105 // Static init
106 template <typename R, typename X, typename Y, typename F>
108 
109 // scalar-Array
110 template <typename U, typename T, typename R, typename F>
111 Array<U>
112 binmap (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 
121  octave_idx_type i;
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
141 template <typename U, typename T, typename R, typename F>
142 Array<U>
143 binmap (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 
152  octave_idx_type i;
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)
172 template <typename U, typename T, typename R, typename F>
173 Array<U>
174 binmap (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))
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.fortran_vec ();
201 
202  octave_idx_type i;
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
222 template <typename U, typename T, typename R, typename F>
223 Sparse<U>
224 binmap (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
253 template <typename U, typename T, typename R, typename F>
254 Sparse<U>
255 binmap (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)
284 template <typename U, typename T, typename R, typename F>
285 Sparse<U>
286 binmap (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 
363 template <typename U, typename T, typename R>
364 inline Array<U>
365 binmap (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 
369 template <typename U, typename T, typename R>
370 inline Array<U>
371 binmap (const T& x, const Array<R>& ya, U (*fcn) (T, R))
372 { return binmap<U, T, R, U (*) (T, R)> (x, ya, fcn); }
373 
374 template <typename U, typename T, typename R>
375 inline Array<U>
376 binmap (const Array<T>& xa, const R& y, U (*fcn) (T, R))
377 { return binmap<U, T, R, U (*) (T, R)> (xa, y, fcn); }
378 
379 template <typename U, typename T, typename R>
380 inline Sparse<U>
381 binmap (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 
385 template <typename U, typename T, typename R>
386 inline Sparse<U>
387 binmap (const T& x, const Sparse<R>& ya, U (*fcn) (T, R))
388 { return binmap<U, T, R, U (*) (T, R)> (x, ya, fcn); }
389 
390 template <typename U, typename T, typename R>
391 inline Sparse<U>
392 binmap (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 
397 template <typename U, typename T, typename R>
398 inline Array<U>
399 binmap (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 
403 template <typename U, typename T, typename R>
404 inline Array<U>
405 binmap (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 
408 template <typename U, typename T, typename R>
409 inline Array<U>
410 binmap (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 
413 template <typename U, typename T, typename R>
414 inline Sparse<U>
415 binmap (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 
419 template <typename U, typename T, typename R>
420 inline Sparse<U>
421 binmap (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 
424 template <typename U, typename T, typename R>
425 inline Sparse<U>
426 binmap (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 
431 template <typename U, typename T, typename R>
432 inline Array<U>
433 binmap (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 
437 template <typename U, typename T, typename R>
438 inline Array<U>
439 binmap (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 
442 template <typename U, typename T, typename R>
443 inline Array<U>
444 binmap (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 
447 template <typename U, typename T, typename R>
448 inline Sparse<U>
449 binmap (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 
453 template <typename U, typename T, typename R>
454 inline Sparse<U>
455 binmap (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 
458 template <typename U, typename T, typename R>
459 inline Sparse<U>
460 binmap (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 
465 template <typename U, typename T, typename R>
466 inline Array<U>
467 binmap (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 
471 template <typename U, typename T, typename R>
472 inline Array<U>
473 binmap (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 
476 template <typename U, typename T, typename R>
477 inline Array<U>
478 binmap (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 
481 template <typename U, typename T, typename R>
482 inline Sparse<U>
483 binmap (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 
487 template <typename U, typename T, typename R>
488 inline Sparse<U>
489 binmap (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 
492 template <typename U, typename T, typename R>
493 inline Sparse<U>
494 binmap (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)(size_t, R *, const X *, const Y *), void(*op_sv)(size_t, R *, X, const Y *), void(*op_vs)(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:128
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:377
const T * data(void) const
Size of the specified dimension.
Definition: Array.h:581
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:453
const T * fortran_vec(void) const
Size of the specified dimension.
Definition: Array.h:583
Definition: Sparse.h:49
Array< T > array_value(void) const
Definition: Sparse.cc:2688
octave_idx_type cols(void) const
Definition: Sparse.h:251
T * data(void)
Definition: Sparse.h:470
octave_idx_type * cidx(void)
Definition: Sparse.h:492
octave_idx_type nnz(void) const
Actual number of nonzero terms.
Definition: Sparse.h:238
octave_idx_type rows(void) const
Definition: Sparse.h:250
dim_vector dims(void) const
Definition: Sparse.h:270
octave_idx_type * ridx(void)
Definition: Sparse.h:479
static F s_fcn
Definition: oct-binmap.h:73
static void op_mm(size_t n, R *r, const X *x, const Y *y)
Definition: oct-binmap.h:84
static void op_ms(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
static void op_sm(size_t n, R *r, X x, const Y *y)
Definition: oct-binmap.h:91
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:95
QString name
F77_RET_T const F77_DBLE * x
octave_idx_type n
Definition: mx-inlines.cc:753
T * r
Definition: mx-inlines.cc:773
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
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811
F77_RET_T len
Definition: xerbla.cc:61