changeset 13006:61be447052c3

Implement automatic bsxfun almost everywhere now except sparse matrices. * bsxfun.h: Move the .cc include since it uses the declaration of the function * oct-binmap.h: Call bsxfun on Array-Array binmap, and pass functions by pointer instead of by reference so they can be passed to do_bsxfun_op. * xor.m: Trivially call bsxfun by default.
author Jordi Gutiérrez Hermoso <jordigh@gmail.com>
date Thu, 25 Aug 2011 04:07:11 -0500
parents 4061106b1c4b
children 85dac13a911b
files liboctave/bsxfun.h liboctave/oct-binmap.h scripts/miscellaneous/xor.m
diffstat 3 files changed, 127 insertions(+), 62 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/bsxfun.h
+++ b/liboctave/bsxfun.h
@@ -27,8 +27,6 @@
 #include "Array.h"
 #include "dim-vector.h"
 
-#include "bsxfun-defs.cc"
-
 inline
 bool
 is_valid_bsxfun (const dim_vector& dx, const dim_vector& dy)
@@ -41,4 +39,6 @@
   return true;
 }
 
+#include "bsxfun-defs.cc"
+
 #endif
--- a/liboctave/oct-binmap.h
+++ b/liboctave/oct-binmap.h
@@ -27,9 +27,13 @@
 #include "Sparse.h"
 #include "Array-util.h"
 
-// This source implements a general binary maping function for arrays.
-// The syntax is binmap<type> (a, b, f, [name]). type denotes the expected
-// return type of the operation. a, b, should be one of the 6 combinations:
+#include "bsxfun.h"
+
+// This source file implements a general binary maping function for
+// arrays. The syntax is binmap<type> (a, b, f, [name]). type denotes
+// the expected return type of the operation. a, b, should be one of
+// the 6 combinations:
+//
 // Array-Array
 // Array-scalar
 // scalar-Array
@@ -37,11 +41,12 @@
 // Sparse-scalar
 // scalar-Sparse
 //
-// If both operands are nonscalar, name must be supplied. It is used as the base for error message
-// when operands are nonconforming.
+// If both operands are nonscalar, name must be supplied. It is used
+// as the base for error message when operands are nonconforming.
 //
-// The operation needs not be homogeneous, i.e. a, b and the result may be of distinct types.
-// f can have any of the four signatures:
+// The operation needs not be homogeneous, i.e. a, b and the result
+// may be of distinct types. f can have any of the four signatures:
+//
 // U f (T, R)
 // U f (const T&, R)
 // U f (T, const R&)
@@ -49,7 +54,51 @@
 //
 // Additionally, f can be an arbitrary functor object.
 //
-// octave_quit() is called at appropriate places, hence the operation is breakable.
+// octave_quit() is called at appropriate places, hence the operation
+// is breakable.
+
+// The following template wrappers are provided for automatic bsxfun
+// calls (see the function signature for do_bsxfun_op).
+
+template<typename R, typename X, typename Y, typename F>
+class bsxfun_wrapper
+{
+private:
+  static F f;
+
+public:
+  static void
+  set_f (const F& f_in)
+  {
+    f = f_in;
+  }
+
+  static void
+  op_mm (size_t n, R* r, const X* x , const Y* y)
+  {
+    for (size_t i = 0; i < n; i++)
+      r[i] = f (x[i], y[i]);
+  }
+
+  static void
+  op_sm (size_t n, R* r, X x, const Y* y)
+  {
+    for (size_t i = 0; i < n; i++)
+      r[i] = f (x, y[i]);
+  }
+
+  static void
+  op_ms (size_t n , R* r, const X* x, Y y)
+  {
+    for (size_t i = 0; i < n; i++)
+      r[i] = f (x[i], y);
+  }
+};
+
+// Static init
+template<typename R, typename X, typename Y, typename F>
+F bsxfun_wrapper<R, X, Y, F>::f;
+
 
 // scalar-Array
 template <class U, class T, class R, class F>
@@ -118,12 +167,24 @@
 Array<U>
 binmap (const Array<T>& xa, const Array<R>& ya, F fcn, const char *name)
 {
+  dim_vector xad = xa.dims (), yad = ya.dims ();
   if (xa.numel () == 1)
     return binmap<U, T, R, F> (xa(0), ya, fcn);
   else if (ya.numel () == 1)
     return binmap<U, T, R, F> (xa, ya(0), fcn);
-  else if (xa.dims () != ya.dims ())
-    gripe_nonconformant (name, xa.dims (), ya.dims ());
+  else if (xad != yad)
+    {
+      if (is_valid_bsxfun (xad, yad))
+        {
+          bsxfun_wrapper<U, T, R, F>::set_f(fcn);
+          return do_bsxfun_op (xa, ya,
+                               bsxfun_wrapper<U, T, R, F>::op_mm,
+                               bsxfun_wrapper<U, T, R, F>::op_sm,
+                               bsxfun_wrapper<U, T, R, F>::op_ms);
+        }
+      else
+        gripe_nonconformant (name, xad, yad);
+    }
 
   octave_idx_type len = xa.numel ();
 
@@ -273,134 +334,134 @@
                                           fcn, name));
 }
 
-// Overloads for function references.
+// Overloads for function pointers.
 
 // Signature (T, R)
 
 template <class U, class T, class R>
 inline Array<U>
-binmap (const Array<T>& xa, const Array<R>& ya, U (&fcn) (T, R), const char *name)
-{ return binmap<U, T, R, U (&) (T, R)> (xa, ya, fcn, name); }
+binmap (const Array<T>& xa, const Array<R>& ya, U (*fcn) (T, R), const char *name)
+{ return binmap<U, T, R, U (*) (T, R)> (xa, ya, fcn, name); }
 
 template <class U, class T, class R>
 inline Array<U>
-binmap (const T& x, const Array<R>& ya, U (&fcn) (T, R))
-{ return binmap<U, T, R, U (&) (T, R)> (x, ya, fcn); }
+binmap (const T& x, const Array<R>& ya, U (*fcn) (T, R))
+{ return binmap<U, T, R, U (*) (T, R)> (x, ya, fcn); }
 
 template <class U, class T, class R>
 inline Array<U>
-binmap (const Array<T>& xa, const R& y, U (&fcn) (T, R))
-{ return binmap<U, T, R, U (&) (T, R)> (xa, y, fcn); }
+binmap (const Array<T>& xa, const R& y, U (*fcn) (T, R))
+{ return binmap<U, T, R, U (*) (T, R)> (xa, y, fcn); }
 
 template <class U, class T, class R>
 inline Sparse<U>
-binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (&fcn) (T, R), const char *name)
-{ return binmap<U, T, R, U (&) (T, R)> (xa, ya, fcn, name); }
+binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (*fcn) (T, R), const char *name)
+{ return binmap<U, T, R, U (*) (T, R)> (xa, ya, fcn, name); }
 
 template <class U, class T, class R>
 inline Sparse<U>
-binmap (const T& x, const Sparse<R>& ya, U (&fcn) (T, R))
-{ return binmap<U, T, R, U (&) (T, R)> (x, ya, fcn); }
+binmap (const T& x, const Sparse<R>& ya, U (*fcn) (T, R))
+{ return binmap<U, T, R, U (*) (T, R)> (x, ya, fcn); }
 
 template <class U, class T, class R>
 inline Sparse<U>
-binmap (const Sparse<T>& xa, const R& y, U (&fcn) (T, R))
-{ return binmap<U, T, R, U (&) (T, R)> (xa, y, fcn); }
+binmap (const Sparse<T>& xa, const R& y, U (*fcn) (T, R))
+{ return binmap<U, T, R, U (*) (T, R)> (xa, y, fcn); }
 
 // Signature (const T&, const R&)
 
 template <class U, class T, class R>
 inline Array<U>
-binmap (const Array<T>& xa, const Array<R>& ya, U (&fcn) (const T&, const R&), const char *name)
-{ return binmap<U, T, R, U (&) (const T&, const R&)> (xa, ya, fcn, name); }
+binmap (const Array<T>& xa, const Array<R>& ya, U (*fcn) (const T&, const R&), const char *name)
+{ return binmap<U, T, R, U (*) (const T&, const R&)> (xa, ya, fcn, name); }
 
 template <class U, class T, class R>
 inline Array<U>
-binmap (const T& x, const Array<R>& ya, U (&fcn) (const T&, const R&))
-{ return binmap<U, T, R, U (&) (const T&, const R&)> (x, ya, fcn); }
+binmap (const T& x, const Array<R>& ya, U (*fcn) (const T&, const R&))
+{ return binmap<U, T, R, U (*) (const T&, const R&)> (x, ya, fcn); }
 
 template <class U, class T, class R>
 inline Array<U>
-binmap (const Array<T>& xa, const R& y, U (&fcn) (const T&, const R&))
-{ return binmap<U, T, R, U (&) (const T&, const R&)> (xa, y, fcn); }
+binmap (const Array<T>& xa, const R& y, U (*fcn) (const T&, const R&))
+{ return binmap<U, T, R, U (*) (const T&, const R&)> (xa, y, fcn); }
 
 template <class U, class T, class R>
 inline Sparse<U>
-binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (&fcn) (const T&, const R&), const char *name)
-{ return binmap<U, T, R, U (&) (const T&, const R&)> (xa, ya, fcn, name); }
+binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (*fcn) (const T&, const R&), const char *name)
+{ return binmap<U, T, R, U (*) (const T&, const R&)> (xa, ya, fcn, name); }
 
 template <class U, class T, class R>
 inline Sparse<U>
-binmap (const T& x, const Sparse<R>& ya, U (&fcn) (const T&, const R&))
-{ return binmap<U, T, R, U (&) (const T&, const R&)> (x, ya, fcn); }
+binmap (const T& x, const Sparse<R>& ya, U (*fcn) (const T&, const R&))
+{ return binmap<U, T, R, U (*) (const T&, const R&)> (x, ya, fcn); }
 
 template <class U, class T, class R>
 inline Sparse<U>
-binmap (const Sparse<T>& xa, const R& y, U (&fcn) (const T&, const R&))
-{ return binmap<U, T, R, U (&) (const T&, const R&)> (xa, y, fcn); }
+binmap (const Sparse<T>& xa, const R& y, U (*fcn) (const T&, const R&))
+{ return binmap<U, T, R, U (*) (const T&, const R&)> (xa, y, fcn); }
 
 // Signature (const T&, R)
 
 template <class U, class T, class R>
 inline Array<U>
-binmap (const Array<T>& xa, const Array<R>& ya, U (&fcn) (const T&, R), const char *name)
-{ return binmap<U, T, R, U (&) (const T&, R)> (xa, ya, fcn, name); }
+binmap (const Array<T>& xa, const Array<R>& ya, U (*fcn) (const T&, R), const char *name)
+{ return binmap<U, T, R, U (*) (const T&, R)> (xa, ya, fcn, name); }
 
 template <class U, class T, class R>
 inline Array<U>
-binmap (const T& x, const Array<R>& ya, U (&fcn) (const T&, R))
-{ return binmap<U, T, R, U (&) (const T&, R)> (x, ya, fcn); }
+binmap (const T& x, const Array<R>& ya, U (*fcn) (const T&, R))
+{ return binmap<U, T, R, U (*) (const T&, R)> (x, ya, fcn); }
 
 template <class U, class T, class R>
 inline Array<U>
-binmap (const Array<T>& xa, const R& y, U (&fcn) (const T&, R))
-{ return binmap<U, T, R, U (&) (const T&, R)> (xa, y, fcn); }
+binmap (const Array<T>& xa, const R& y, U (*fcn) (const T&, R))
+{ return binmap<U, T, R, U (*) (const T&, R)> (xa, y, fcn); }
 
 template <class U, class T, class R>
 inline Sparse<U>
-binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (&fcn) (const T&, R), const char *name)
-{ return binmap<U, T, R, U (&) (const T&, R)> (xa, ya, fcn, name); }
+binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (*fcn) (const T&, R), const char *name)
+{ return binmap<U, T, R, U (*) (const T&, R)> (xa, ya, fcn, name); }
 
 template <class U, class T, class R>
 inline Sparse<U>
-binmap (const T& x, const Sparse<R>& ya, U (&fcn) (const T&, R))
-{ return binmap<U, T, R, U (&) (const T&, R)> (x, ya, fcn); }
+binmap (const T& x, const Sparse<R>& ya, U (*fcn) (const T&, R))
+{ return binmap<U, T, R, U (*) (const T&, R)> (x, ya, fcn); }
 
 template <class U, class T, class R>
 inline Sparse<U>
-binmap (const Sparse<T>& xa, const R& y, U (&fcn) (const T&, R))
-{ return binmap<U, T, R, U (&) (const T&, R)> (xa, y, fcn); }
+binmap (const Sparse<T>& xa, const R& y, U (*fcn) (const T&, R))
+{ return binmap<U, T, R, U (*) (const T&, R)> (xa, y, fcn); }
 
 // Signature (T, const R&)
 
 template <class U, class T, class R>
 inline Array<U>
-binmap (const Array<T>& xa, const Array<R>& ya, U (&fcn) (T, const R&), const char *name)
-{ return binmap<U, T, R, U (&) (T, const R&)> (xa, ya, fcn, name); }
+binmap (const Array<T>& xa, const Array<R>& ya, U (*fcn) (T, const R&), const char *name)
+{ return binmap<U, T, R, U (*) (T, const R&)> (xa, ya, fcn, name); }
 
 template <class U, class T, class R>
 inline Array<U>
-binmap (const T& x, const Array<R>& ya, U (&fcn) (T, const R&))
-{ return binmap<U, T, R, U (&) (T, const R&)> (x, ya, fcn); }
+binmap (const T& x, const Array<R>& ya, U (*fcn) (T, const R&))
+{ return binmap<U, T, R, U (*) (T, const R&)> (x, ya, fcn); }
 
 template <class U, class T, class R>
 inline Array<U>
-binmap (const Array<T>& xa, const R& y, U (&fcn) (T, const R&))
-{ return binmap<U, T, R, U (&) (T, const R&)> (xa, y, fcn); }
+binmap (const Array<T>& xa, const R& y, U (*fcn) (T, const R&))
+{ return binmap<U, T, R, U (*) (T, const R&)> (xa, y, fcn); }
 
 template <class U, class T, class R>
 inline Sparse<U>
-binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (&fcn) (T, const R&), const char *name)
-{ return binmap<U, T, R, U (&) (T, const R&)> (xa, ya, fcn, name); }
+binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (*fcn) (T, const R&), const char *name)
+{ return binmap<U, T, R, U (*) (T, const R&)> (xa, ya, fcn, name); }
 
 template <class U, class T, class R>
 inline Sparse<U>
-binmap (const T& x, const Sparse<R>& ya, U (&fcn) (T, const R&))
-{ return binmap<U, T, R, U (&) (T, const R&)> (x, ya, fcn); }
+binmap (const T& x, const Sparse<R>& ya, U (*fcn) (T, const R&))
+{ return binmap<U, T, R, U (*) (T, const R&)> (x, ya, fcn); }
 
 template <class U, class T, class R>
 inline Sparse<U>
-binmap (const Sparse<T>& xa, const R& y, U (&fcn) (T, const R&))
-{ return binmap<U, T, R, U (&) (T, const R&)> (xa, y, fcn); }
+binmap (const Sparse<T>& xa, const R& y, U (*fcn) (T, const R&))
+{ return binmap<U, T, R, U (*) (T, const R&)> (xa, y, fcn); }
 
 #endif
--- a/scripts/miscellaneous/xor.m
+++ b/scripts/miscellaneous/xor.m
@@ -48,7 +48,11 @@
       ## Typecast to logicals is necessary for other numeric types.
       z = logical (x) != logical (y);
     else
-      error ("xor: X and Y must be of common size or scalars");
+      try
+        z = bsxfun (@xor, x, y);
+      catch
+        error ("xor: X and Y must be of compatible size or scalars");
+      end_try_catch
     endif
   else
     print_usage ();