diff liboctave/mx-inlines.cc @ 9550:3d6a9aea2aea

refactor binary & bool ops in liboctave
author Jaroslav Hajek <highegg@gmail.com>
date Wed, 19 Aug 2009 22:55:15 +0200
parents 9f870f73ab7d
children 0c72d9284087
line wrap: on
line diff
--- a/liboctave/mx-inlines.cc	Wed Aug 19 16:24:33 2009 +0200
+++ b/liboctave/mx-inlines.cc	Wed Aug 19 22:55:15 2009 +0200
@@ -34,208 +34,270 @@
 #include "oct-cmplx.h"
 #include "oct-locbuf.h"
 #include "oct-inttypes.h"
+#include "Array-util.h"
+
+// Provides some commonly repeated, basic loop templates.
 
 template <class R, class S>
-inline void
-mx_inline_fill_vs (R *r, size_t n, S s)
-{
-  for (size_t i = 0; i < n; i++)
-    r[i] = s;
+inline void mx_inline_fill (size_t n, R *r, S s)
+{ for (size_t i = 0; i < n; i++) r[i] = s; }
+
+#define DEFMXUNOP(F, OP) \
+template <class R, class X> \
+inline void F (size_t n, R *r, const X *x) \
+{ for (size_t i = 0; i < n; i++) r[i] = OP x[i]; }
+
+DEFMXUNOP (mx_inline_uminus, -)
+DEFMXUNOP (mx_inline_not, !)
+
+#define DEFMXUNBOOLOP(F, OP) \
+template <class X> \
+inline void F (size_t n, bool *r, const X *x) \
+{ const X zero = X(); for (size_t i = 0; i < n; i++) r[i] = x[i] OP zero; }
+
+DEFMXUNBOOLOP (mx_inline_iszero, ==)
+DEFMXUNBOOLOP (mx_inline_notzero, !=)
+
+#define DEFMXBINOP(F, OP) \
+template <class R, class X, class Y> \
+inline void F (size_t n, R *r, const X *x, const Y *y) \
+{ for (size_t i = 0; i < n; i++) r[i] = x[i] OP y[i]; } \
+template <class R, class X, class Y> \
+inline void F (size_t n, R *r, const X *x, Y y) \
+{ for (size_t i = 0; i < n; i++) r[i] = x[i] OP y; } \
+template <class R, class X, class Y> \
+inline void F (size_t n, R *r, X x, const Y *y) \
+{ for (size_t i = 0; i < n; i++) r[i] = x OP y[i]; }
+
+DEFMXBINOP (mx_inline_add, +)
+DEFMXBINOP (mx_inline_sub, -)
+DEFMXBINOP (mx_inline_mul, *)
+DEFMXBINOP (mx_inline_div, /)
+
+#define DEFMXBINOPEQ(F, OP) \
+template <class R, class X> \
+inline void F (size_t n, R *r, const X *x) \
+{ for (size_t i = 0; i < n; i++) r[i] OP x[i]; } \
+template <class R, class X> \
+inline void F (size_t n, R *r, X x) \
+{ for (size_t i = 0; i < n; i++) r[i] OP x; }
+
+DEFMXBINOPEQ (mx_inline_add2, +=)
+DEFMXBINOPEQ (mx_inline_sub2, -=)
+DEFMXBINOPEQ (mx_inline_mul2, *=)
+DEFMXBINOPEQ (mx_inline_div2, /=)
+
+#define DEFMXCMPOP(F, OP) \
+template <class X, class Y> \
+inline void F (size_t n, bool *r, const X *x, const Y *y) \
+{ for (size_t i = 0; i < n; i++) r[i] = x[i] OP y[i]; } \
+template <class X, class Y> \
+inline void F (size_t n, bool *r, const X *x, Y y) \
+{ for (size_t i = 0; i < n; i++) r[i] = x[i] OP y; } \
+template <class X, class Y> \
+inline void F (size_t n, bool *r, X x, const Y *y) \
+{ for (size_t i = 0; i < n; i++) r[i] = x OP y[i]; }
+
+DEFMXCMPOP (mx_inline_lt, <)
+DEFMXCMPOP (mx_inline_le, <=)
+DEFMXCMPOP (mx_inline_gt, >)
+DEFMXCMPOP (mx_inline_ge, >=)
+DEFMXCMPOP (mx_inline_eq, ==)
+DEFMXCMPOP (mx_inline_ne, !=)
+
+// For compatibility with certain loserware, cmp ops on complex nums only
+// compare real parts, although "sort" defines ordering on complex numbers!
+
+#define DEFCMPLXCMOP(F, OP) \
+template <class X, class Y> \
+inline void F (size_t n, bool *r, const std::complex<X> *x, const Y *y) \
+{ for (size_t i = 0; i < n; i++) r[i] = real (x[i]) OP real (y[i]); } \
+template <class X, class Y> \
+inline void F (size_t n, bool *r, const std::complex<X> *x, Y y) \
+{ for (size_t i = 0; i < n; i++) r[i] = real (x[i]) OP y; } \
+template <class X, class Y> \
+inline void F (size_t n, bool *r, X x, const std::complex<Y> *y) \
+{ for (size_t i = 0; i < n; i++) r[i] = x OP real (y[i]); }
+
+#define DEFMXBOOLOP(F, EQ1, OP, EQ2) \
+template <class X, class Y> \
+inline void F (size_t n, bool *r, const X *x, const Y *y) \
+{ \
+  const X xzero = X(); \
+  const Y yzero = Y(); \
+  for (size_t i = 0; i < n; i++) \
+    r[i] = (x[i] EQ1 xzero) OP (y[i] EQ2 yzero); \
+} \
+template <class X, class Y> \
+inline void F (size_t n, bool *r, const X *x, Y y) \
+{ \
+  const X xzero = X(); \
+  const bool yy = y EQ2 Y(); \
+  for (size_t i = 0; i < n; i++) r[i] = (x[i] EQ1 xzero) OP yy; \
+} \
+template <class X, class Y> \
+inline void F (size_t n, bool *r, X x, const Y *y) \
+{ \
+  const bool xx = x EQ1 X(); \
+  const Y yzero = Y(); \
+  for (size_t i = 0; i < n; i++) r[i] = xx OP (y[i] EQ2 yzero); \
+}
+
+DEFMXBOOLOP (mx_inline_and, !=, &, !=)
+DEFMXBOOLOP (mx_inline_or, !=, |, !=)
+DEFMXBOOLOP (mx_inline_not_and, ==, &, !=)
+DEFMXBOOLOP (mx_inline_not_or, ==, |, !=)
+DEFMXBOOLOP (mx_inline_and_not, !=, &, ==)
+DEFMXBOOLOP (mx_inline_or_not, !=, |, ==)
+
+template <class T> 
+inline bool 
+mx_inline_any_nan (size_t, const T*) { return false; }
+
+#define DEFMXANYNAN(T) \
+inline bool \
+mx_inline_any_nan (size_t n, const T* t) \
+{ \
+  for (size_t i = 0; i < n; i++) \
+    if (xisnan (t[i])) return true; \
+  return false; \
 }
 
-#define VS_OP_FCN(F, OP) \
-  template <class R, class V, class S> \
-  inline void \
-  F ## _vs (R *r, const V *v, size_t n, S s) \
-  { \
-    for (size_t i = 0; i < n; i++) \
-      r[i] = v[i] OP s; \
-  }
+DEFMXANYNAN(double)
+DEFMXANYNAN(float)
+DEFMXANYNAN(Complex)
+DEFMXANYNAN(FloatComplex)
 
-VS_OP_FCN (mx_inline_add,      +)
-VS_OP_FCN (mx_inline_subtract, -)
-VS_OP_FCN (mx_inline_multiply, *)
-VS_OP_FCN (mx_inline_divide,   /)
+// Arbitrary unary/binary function mappers. Note the function reference is a
+// template parameter!
+template <class R, class X, R F(X)>
+void mx_inline_fun (size_t n, R *r, const X *x)
+{ for (size_t i = 0; i < n; i++) r[i] = F(x[i]); }
 
-#define VS_OP(F, OP, R, V, S) \
-  static inline R * \
-  F (const V *v, size_t n, S s) \
-  { \
-    R *r = 0; \
-    if (n > 0) \
-      { \
-	r = new R [n]; \
-	F ## _vs (r, v, n, s); \
-      } \
-    return r; \
-  }
+template <class R, class X, R F(const X&)>
+void mx_inline_fun (size_t n, R *r, const X *x)
+{ for (size_t i = 0; i < n; i++) r[i] = F(x[i]); }
 
-#define VS_OPS(R, V, S) \
-  VS_OP (mx_inline_add,      +, R, V, S) \
-  VS_OP (mx_inline_subtract, -, R, V, S) \
-  VS_OP (mx_inline_multiply, *, R, V, S) \
-  VS_OP (mx_inline_divide,   /, R, V, S)
+template <class R, class X, class Y, R F(X, Y)>
+void mx_inline_fun (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]); }
 
-VS_OPS (double,  double,  double)
-VS_OPS (Complex, double,  Complex)
-VS_OPS (Complex, Complex, double)
-VS_OPS (Complex, Complex, Complex)
-
-VS_OPS (float,  float,  float)
-VS_OPS (FloatComplex, float,  FloatComplex)
-VS_OPS (FloatComplex, FloatComplex, float)
-VS_OPS (FloatComplex, FloatComplex, FloatComplex)
+template <class R, class X, class Y, R F(X, Y)>
+void mx_inline_fun (size_t n, R *r, X x, const Y *y)
+{ for (size_t i = 0; i < n; i++) r[i] = F(x, y[i]); }
 
-#define SV_OP_FCN(F, OP) \
-  template <class R, class S, class V> \
-  inline void \
-  F ## _sv (R *r, S s, const V *v, size_t n) \
-  { \
-    for (size_t i = 0; i < n; i++) \
-      r[i] = s OP v[i]; \
-  } \
+template <class R, class X, class Y, R F(X, Y)>
+void mx_inline_fun (size_t n, R *r, const X *x, Y y)
+{ for (size_t i = 0; i < n; i++) r[i] = F(x[i], y); }
 
-SV_OP_FCN (mx_inline_add,      +)
-SV_OP_FCN (mx_inline_subtract, -)
-SV_OP_FCN (mx_inline_multiply, *)
-SV_OP_FCN (mx_inline_divide,   /)
+template <class R, class X, class Y, R F(const X&, const Y&)>
+void mx_inline_fun (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]); }
+
+template <class R, class X, class Y, R F(const X&, const Y&)>
+void mx_inline_fun (size_t n, R *r, X x, const Y *y)
+{ for (size_t i = 0; i < n; i++) r[i] = F(x, y[i]); }
 
-#define SV_OP(F, OP, R, S, V) \
-  static inline R * \
-  F (S s, const V *v, size_t n) \
-  { \
-    R *r = 0; \
-    if (n > 0) \
-      { \
-	r = new R [n]; \
-        F ## _sv (r, s, v, n); \
-      } \
-    return r; \
-  }
+template <class R, class X, class Y, R F(const X&, const Y&)>
+void mx_inline_fun (size_t n, R *r, const X *x, Y y)
+{ for (size_t i = 0; i < n; i++) r[i] = F(x[i], y); }
 
-#define SV_OPS(R, S, V) \
-  SV_OP (mx_inline_add,      +, R, S, V) \
-  SV_OP (mx_inline_subtract, -, R, S, V) \
-  SV_OP (mx_inline_multiply, *, R, S, V) \
-  SV_OP (mx_inline_divide,   /, R, S, V)
+// Appliers. Since these call the operation just once, we pass it as
+// a pointer, to allow the compiler reduce number of instances.
 
-SV_OPS (double,  double,  double)
-SV_OPS (Complex, double,  Complex)
-SV_OPS (Complex, Complex, double)
-SV_OPS (Complex, Complex, Complex)
-
-SV_OPS (float,  float,  float)
-SV_OPS (FloatComplex, float,  FloatComplex)
-SV_OPS (FloatComplex, FloatComplex, float)
-SV_OPS (FloatComplex, FloatComplex, FloatComplex)
-
-#define VV_OP_FCN(F, OP) \
-  template <class R, class T1, class T2> \
-  inline void \
-  F ## _vv (R *r, const T1 *v1, const T2 *v2, size_t n) \
-  { \
-    for (size_t i = 0; i < n; i++) \
-      r[i] = v1[i] OP v2[i]; \
-  } \
+template <class RNDA, class XNDA>
+inline RNDA 
+do_mx_unary_op (const XNDA& x,
+                void (*op) (size_t, typename RNDA::element_type *,
+                            const typename XNDA::element_type *))
+{
+  RNDA r (x.dims ());
+  op (r.nelem (), r.fortran_vec (), x.data ());
+  return r;
+}
 
-VV_OP_FCN (mx_inline_add,      +)
-VV_OP_FCN (mx_inline_subtract, -)
-VV_OP_FCN (mx_inline_multiply, *)
-VV_OP_FCN (mx_inline_divide,   /)
-
-#define VV_OP(F, OP, R, T1, T2) \
-  static inline R * \
-  F (const T1 *v1, const T2 *v2, size_t n) \
-  { \
-    R *r = 0; \
-    if (n > 0) \
-      { \
-	r = new R [n]; \
-	F ## _vv (r, v1, v2, n); \
-      } \
-    return r; \
-  }
+template <class RNDA, class XNDA, class YNDA>
+inline RNDA 
+do_mm_binary_op (const XNDA& x, const YNDA& y,
+                 void (*op) (size_t, typename RNDA::element_type *,
+                             const typename XNDA::element_type *,
+                             const typename YNDA::element_type *),
+                 const char *opname)
+{
+  dim_vector dx = x.dims (), dy = y.dims ();
+  if (dx == dy)
+    {
+      RNDA r (dx);
+      op (r.nelem (), r.fortran_vec (), x.data (), y.data ());
+      return r;
+    }
+  else
+    {
+      gripe_nonconformant (opname, dx, dy);
+      return RNDA ();
+    }
+}
 
-#define VV_OPS(R, T1, T2) \
-  VV_OP (mx_inline_add,      +, R, T1, T2) \
-  VV_OP (mx_inline_subtract, -, R, T1, T2) \
-  VV_OP (mx_inline_multiply, *, R, T1, T2) \
-  VV_OP (mx_inline_divide,   /, R, T1, T2)
-
-VV_OPS (double,  double,  double)
-VV_OPS (Complex, double,  Complex)
-VV_OPS (Complex, Complex, double)
-VV_OPS (Complex, Complex, Complex)
-
-VV_OPS (float,  float,  float)
-VV_OPS (FloatComplex, float,  FloatComplex)
-VV_OPS (FloatComplex, FloatComplex, float)
-VV_OPS (FloatComplex, FloatComplex, FloatComplex)
-
-#define VS_OP2(F, OP, V, S) \
-  static inline V * \
-  F (V *v, size_t n, S s) \
-  { \
-    for (size_t i = 0; i < n; i++) \
-      v[i] OP s; \
-    return v; \
-  }
+template <class RNDA, class XNDA, class YS>
+inline RNDA 
+do_ms_binary_op (const XNDA& x, const YS& y,
+                 void (*op) (size_t, typename RNDA::element_type *,
+                             const typename XNDA::element_type *, YS))
+{
+  RNDA r (x.dims ());
+  op (r.nelem (), r.fortran_vec (), x.data (), y);
+  return r;
+}
 
-#define VS_OP2S(V, S) \
-  VS_OP2 (mx_inline_add2,      +=, V, S) \
-  VS_OP2 (mx_inline_subtract2, -=, V, S) \
-  VS_OP2 (mx_inline_multiply2, *=, V, S) \
-  VS_OP2 (mx_inline_divide2,   /=, V, S) \
-  VS_OP2 (mx_inline_copy,       =, V, S)
-
-VS_OP2S (double,  double)
-VS_OP2S (Complex, double)
-VS_OP2S (Complex, Complex)
-
-VS_OP2S (float,  float)
-VS_OP2S (FloatComplex, float)
-VS_OP2S (FloatComplex, FloatComplex)
-
-#define VV_OP2(F, OP, T1, T2) \
-  static inline T1 * \
-  F (T1 *v1, const T2 *v2, size_t n) \
-  { \
-    for (size_t i = 0; i < n; i++) \
-      v1[i] OP v2[i]; \
-    return v1; \
-  }
+template <class RNDA, class XS, class YNDA>
+inline RNDA 
+do_sm_binary_op (const XS& x, const YNDA& y,
+                 void (*op) (size_t, typename RNDA::element_type *, XS,
+                             const typename YNDA::element_type *))
+{
+  RNDA r (y.dims ());
+  op (r.nelem (), r.fortran_vec (), x, y.data ());
+  return r;
+}
 
-#define VV_OP2S(T1, T2) \
-  VV_OP2 (mx_inline_add2,      +=, T1, T2) \
-  VV_OP2 (mx_inline_subtract2, -=, T1, T2) \
-  VV_OP2 (mx_inline_multiply2, *=, T1, T2) \
-  VV_OP2 (mx_inline_divide2,   /=, T1, T2) \
-  VV_OP2 (mx_inline_copy,       =, T1, T2)
-
-VV_OP2S (double,  double)
-VV_OP2S (Complex, double)
-VV_OP2S (Complex, Complex)
-
-VV_OP2S (float,  float)
-VV_OP2S (FloatComplex, float)
-VV_OP2S (FloatComplex, FloatComplex)
+template <class RNDA, class XNDA>
+inline RNDA& 
+do_mm_inplace_op (RNDA& r, const XNDA& x,
+                  void (*op) (size_t, typename RNDA::element_type *,
+                              const typename XNDA::element_type *),
+                  const char *opname)
+{
+  dim_vector dr = r.dims (), dx = x.dims ();
+  if (dr == dx)
+    {
+      op (r.nelem (), r.fortran_vec (), x.data ());
+      return r;
+    }
+  else
+    {
+      gripe_nonconformant (opname, dr, dx);
+      return RNDA ();
+    }
+}
 
-#define OP_EQ_FCN(T1, T2) \
-  static inline bool \
-  mx_inline_equal (const T1 *x, const T2 *y, size_t n) \
-  { \
-    for (size_t i = 0; i < n; i++) \
-      if (x[i] != y[i]) \
-	return false; \
-    return true; \
-  }
+template <class RNDA, class XS>
+inline RNDA& 
+do_ms_inplace_op (RNDA& r, const XS& x,
+                  void (*op) (size_t, typename RNDA::element_type *, XS))
+{
+  op (r.nelem (), r.fortran_vec (), x);
+  return r;
+}
 
-OP_EQ_FCN (bool,    bool)
-OP_EQ_FCN (char,    char)
-OP_EQ_FCN (double,  double)
-OP_EQ_FCN (Complex, Complex)
-OP_EQ_FCN (float,  float)
-OP_EQ_FCN (FloatComplex, FloatComplex)
+template <class T1, class T2>
+inline bool
+mx_inline_equal (size_t n, const T1 *x, const T2 *y)
+{
+  for (size_t i = 0; i < n; i++)
+    if (x[i] != y[i])
+      return false;
+  return true;
+}
 
 #define OP_DUP_FCN(OP, F, R, T) \
   static inline R * \
@@ -293,11 +355,6 @@
 inline T cabsq (const std::complex<T>& c) 
 { return c.real () * c.real () + c.imag () * c.imag (); }
 
-#define OP_RED_SUM(ac, el) ac += el
-#define OP_RED_PROD(ac, el) ac *= el
-#define OP_RED_SUMSQ(ac, el) ac += el*el
-#define OP_RED_SUMSQC(ac, el) ac += cabsq (el)
-
 // default. works for integers and bool.
 template <class T>
 inline bool xis_true (T x) { return x; }
@@ -319,6 +376,11 @@
 inline bool xis_true (const FloatComplex& x) { return ! xisnan (x) && x != 0.0f; }
 inline bool xis_false (const FloatComplex& x) { return x == 0.0f; }
 
+#define OP_RED_SUM(ac, el) ac += el
+#define OP_RED_PROD(ac, el) ac *= el
+#define OP_RED_SUMSQ(ac, el) ac += el*el
+#define OP_RED_SUMSQC(ac, el) ac += cabsq (el)
+
 // The following two implement a simple short-circuiting.
 #define OP_RED_ANYC(ac, el) if (xis_true (el)) { ac = true; break; } else continue
 #define OP_RED_ALLC(ac, el) if (xis_false (el)) { ac = false; break; } else continue