diff liboctave/util/oct-binmap.h @ 18789:dccbc8bff5cb stable

Fix binmap for sparse-scalar or scalar-sparse operations (bug #40813). * oct-binmap.h (binmap (Sparse, Scalar), binmap (Scalar, Sparse)): Check that function is sparsity preserving before using sparse algorithm. Initialize retval row, column indices from original sparse array. Call maybe_compress (true) to remove zero elements that function may have produced. * data.cc (Fatan2): Only preserve sparsity if *first* argument is sparse. Add %!tests to verify sparse operations. * data.cc (do_hypot): Call binmap with sparse inputs whenever at least one of the inputs is sparse. * data.cc (Fhypot): Add %!tests to verify sparse operations. * data.cc (Frem): Call binmap with sparse inputs whenever at least one of the inputs is sparse. Add %!tests to verify sparse operations.
author Rik <rik@octave.org>
date Sun, 01 Jun 2014 21:41:58 -0700
parents 658d23da2c46
children 59975c3cea6b
line wrap: on
line diff
--- a/liboctave/util/oct-binmap.h	Sun Jun 01 15:42:17 2014 +0200
+++ b/liboctave/util/oct-binmap.h	Sun Jun 01 21:41:58 2014 -0700
@@ -218,17 +218,30 @@
 Sparse<U>
 binmap (const T& x, const Sparse<R>& ys, F fcn)
 {
-  octave_idx_type nz = ys.nnz ();
-  Sparse<U> retval (ys.rows (), ys.cols (), nz);
-  for (octave_idx_type i = 0; i < nz; i++)
+  R yzero = R ();
+  U fz = fcn (x, yzero);
+
+  if (fz == U ())  // Sparsity preserving fcn
     {
+      octave_idx_type nz = ys.nnz ();
+      Sparse<U> retval (ys.rows (), ys.cols (), nz);
+      copy_or_memcpy (nz, ys.ridx (), retval.ridx ());
+      copy_or_memcpy (ys.cols () + 1, ys.cidx (), retval.cidx ());
+
+      for (octave_idx_type i = 0; i < nz; i++)
+        {
+          octave_quit ();
+          // FIXME: Could keep track of whether fcn call results in a 0.
+          //        If no zeroes are created could skip maybe_compress()
+          retval.xdata (i) = fcn (x, ys.data (i));
+        }
+
       octave_quit ();
-      retval.xdata (i) = fcn (x, ys.data (i));
+      retval.maybe_compress (true);
+      return retval;
     }
-
-  octave_quit ();
-  retval.maybe_compress ();
-  return retval;
+  else
+    return Sparse<U> (binmap<U, T, R, F> (x, ys.array_value (), fcn));
 }
 
 // Sparse-scalar
@@ -236,17 +249,30 @@
 Sparse<U>
 binmap (const Sparse<T>& xs, const R& y, F fcn)
 {
-  octave_idx_type nz = xs.nnz ();
-  Sparse<U> retval (xs.rows (), xs.cols (), nz);
-  for (octave_idx_type i = 0; i < nz; i++)
+  T xzero = T ();
+  U fz = fcn (xzero, y);
+
+  if (fz == U ())  // Sparsity preserving fcn
     {
+      octave_idx_type nz = xs.nnz ();
+      Sparse<U> retval (xs.rows (), xs.cols (), nz);
+      copy_or_memcpy (nz, xs.ridx (), retval.ridx ());
+      copy_or_memcpy (xs.cols () + 1, xs.cidx (), retval.cidx ());
+
+      for (octave_idx_type i = 0; i < nz; i++)
+        {
+          octave_quit ();
+          // FIXME: Could keep track of whether fcn call results in a 0.
+          //        If no zeroes are created could skip maybe_compress()
+          retval.xdata (i) = fcn (xs.data (i), y);
+        }
+
       octave_quit ();
-      retval.xdata (i) = fcn (xs.data (i), y);
+      retval.maybe_compress (true);
+      return retval;
     }
-
-  octave_quit ();
-  retval.maybe_compress ();
-  return retval;
+  else
+    return Sparse<U> (binmap<U, T, R, F> (xs.array_value (), y, fcn));
 }
 
 // Sparse-Sparse (treats singletons as scalars)
@@ -295,8 +321,8 @@
                   jx++;
                   jx_lt_max = jx < jx_max;
                 }
-              else if (! jx_lt_max ||
-                  (jy_lt_max && (ys.ridx (jy) < xs.ridx (jx))))
+              else if (! jx_lt_max
+                       || (jy_lt_max && (ys.ridx (jy) < xs.ridx (jx))))
                 {
                   retval.xridx (nz) = ys.ridx (jy);
                   retval.xdata (nz) = fcn (xzero, ys.data (jy));