You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mahout.apache.org by ap...@apache.org on 2016/03/15 23:20:14 UTC

mahout git commit: MAHOUT-1813: Functional 'apply' DSL for distributed and in-memory matrices closes apache/mahout#194

Repository: mahout
Updated Branches:
  refs/heads/master 7d71ad00a -> ff51ab448


MAHOUT-1813:  Functional 'apply' DSL for distributed and in-memory matrices closes apache/mahout#194


Project: http://git-wip-us.apache.org/repos/asf/mahout/repo
Commit: http://git-wip-us.apache.org/repos/asf/mahout/commit/ff51ab44
Tree: http://git-wip-us.apache.org/repos/asf/mahout/tree/ff51ab44
Diff: http://git-wip-us.apache.org/repos/asf/mahout/diff/ff51ab44

Branch: refs/heads/master
Commit: ff51ab448b07c5b218d1a08ed5c1194ad5b24179
Parents: 7d71ad0
Author: Andrew Palumbo <ap...@apache.org>
Authored: Tue Mar 15 18:19:49 2016 -0400
Committer: Andrew Palumbo <ap...@apache.org>
Committed: Tue Mar 15 18:19:49 2016 -0400

----------------------------------------------------------------------
 .../org/apache/mahout/math/drm/DrmLikeOps.scala | 23 ++++++-
 .../mahout/math/scalabindings/MatrixOps.scala   | 63 ++++++++++++++++++--
 .../mahout/math/scalabindings/package.scala     |  6 ++
 .../mahout/math/drm/RLikeDrmOpsSuiteBase.scala  | 14 +++++
 .../math/scalabindings/MatrixOpsSuite.scala     | 12 ++++
 5 files changed, 112 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mahout/blob/ff51ab44/math-scala/src/main/scala/org/apache/mahout/math/drm/DrmLikeOps.scala
----------------------------------------------------------------------
diff --git a/math-scala/src/main/scala/org/apache/mahout/math/drm/DrmLikeOps.scala b/math-scala/src/main/scala/org/apache/mahout/math/drm/DrmLikeOps.scala
index e2c6e17..43b4f56 100644
--- a/math-scala/src/main/scala/org/apache/mahout/math/drm/DrmLikeOps.scala
+++ b/math-scala/src/main/scala/org/apache/mahout/math/drm/DrmLikeOps.scala
@@ -19,7 +19,7 @@ package org.apache.mahout.math.drm
 
 import scala.reflect.ClassTag
 import org.apache.mahout.math.scalabindings._
-import org.apache.mahout.math.drm.logical.{OpPar, OpMapBlock, OpRowRange}
+import org.apache.mahout.math.drm.logical.{OpAewUnaryFunc, OpPar, OpMapBlock, OpRowRange}
 
 /** Common Drm ops */
 class DrmLikeOps[K](protected[drm] val drm: DrmLike[K]) {
@@ -116,4 +116,25 @@ class DrmLikeOps[K](protected[drm] val drm: DrmLike[K]) {
 
     } else rowSrc
   }
+
+  /**
+    * Apply a function element-wise.
+    *
+    * @param f         element-wise function
+    * @param evalZeros Do we have to process zero elements? true, false, auto: if auto, we will test
+    *                  the supplied function for `f(0) != 0`, and depending on the result, will
+    *                  decide if we want evaluation for zero elements. WARNING: the AUTO setting
+    *                  may not always work correctly for functions that are meant to run in a specific
+    *                  backend context, or non-deterministic functions, such as {-1,0,1} random
+    *                  generators.
+    * @return new DRM with the element-wise function applied.
+    */
+  def apply(f: Double ⇒ Double, evalZeros: AutoBooleanEnum.T = AutoBooleanEnum.AUTO) = {
+    val ezeros = evalZeros match {
+      case AutoBooleanEnum.TRUE ⇒ true
+      case AutoBooleanEnum.FALSE ⇒ false
+      case AutoBooleanEnum.AUTO ⇒ f(0) != 0
+    }
+    new OpAewUnaryFunc[K](drm, f, ezeros)
+  }
 }

http://git-wip-us.apache.org/repos/asf/mahout/blob/ff51ab44/math-scala/src/main/scala/org/apache/mahout/math/scalabindings/MatrixOps.scala
----------------------------------------------------------------------
diff --git a/math-scala/src/main/scala/org/apache/mahout/math/scalabindings/MatrixOps.scala b/math-scala/src/main/scala/org/apache/mahout/math/scalabindings/MatrixOps.scala
index cb92e1d..f3be285 100644
--- a/math-scala/src/main/scala/org/apache/mahout/math/scalabindings/MatrixOps.scala
+++ b/math-scala/src/main/scala/org/apache/mahout/math/scalabindings/MatrixOps.scala
@@ -128,10 +128,60 @@ class MatrixOps(val m: Matrix) {
   }
 
   /**
-   * Warning: This provides read-only view only.
+    * Apply a function element-wise without side-effects to the argument (creates a new matrix).
+    *
+    * @param f         element-wise function "value" ⇒ "new value"
+    * @param evalZeros Do we have to process zero elements? true, false, auto: if auto, we will test
+    *                  the supplied function for `f(0) != 0`, and depending on the result, will
+    *                  decide if we want evaluation for zero elements. WARNING: the AUTO setting
+    *                  may not always work correctly for functions that are meant to run in a specific
+    *                  backend context, or non-deterministic functions, such as {-1,0,1} random
+    *                  generators.
+    * @return new DRM with the element-wise function applied.
+    */
+  def apply(f: Double ⇒ Double, evalZeros: AutoBooleanEnum.T): Matrix = {
+    val ezeros = evalZeros match {
+      case AutoBooleanEnum.TRUE ⇒ true
+      case AutoBooleanEnum.FALSE ⇒ false
+      case AutoBooleanEnum.AUTO ⇒ f(0) != 0
+    }
+    if (ezeros) m.cloned := f else m.cloned ::= f
+  }
+
+  /**
+    * Apply a function element-wise without side-effects to the argument (creates a new matrix).
+    *
+    * @param f         element-wise function (row, column, value) ⇒ "new value"
+    * @param evalZeros Do we have to process zero elements? true, false, auto: if auto, we will test
+    *                  the supplied function for `f(0) != 0`, and depending on the result, will
+    *                  decide if we want evaluation for zero elements. WARNING: the AUTO setting
+    *                  may not always work correctly for functions that are meant to run in a specific
+    *                  backend context, or non-deterministic functions, such as {-1,0,1} random
+    *                  generators.
+    * @return new DRM with the element-wise function applied.
+    */
+  def apply(f: (Int, Int, Double) ⇒ Double, evalZeros: AutoBooleanEnum.T): Matrix = {
+    val ezeros = evalZeros match {
+      case AutoBooleanEnum.TRUE ⇒ true
+      case AutoBooleanEnum.FALSE ⇒ false
+      case AutoBooleanEnum.AUTO ⇒ f(0,0,0) != 0
+    }
+    if (ezeros) m.cloned := f else m.cloned ::= f
+  }
+
+  /** A version of function apply with default AUTO treatment of `evalZeros`. */
+  def apply(f: Double ⇒ Double): Matrix = apply(f, AutoBooleanEnum.AUTO)
+
+  /** A version of function apply with default AUTO treatment of `evalZeros`. */
+  def apply(f: (Int, Int, Double) ⇒ Double): Matrix = apply(f, AutoBooleanEnum.AUTO)
+
+
+  /**
+    * Warning: This provides read-only view only.
    * In most cases that's what one wants. To get a copy,
    * use <code>m.t cloned</code>
-   * @return transposed view
+    *
+    * @return transposed view
    */
   def t = Matrices.transposedView(m)
 
@@ -143,7 +193,8 @@ class MatrixOps(val m: Matrix) {
 
   /**
    * Assigning from a row-wise collection of vectors
-   * @param that -
+    *
+    * @param that -
    */
   def :=(that: TraversableOnce[Vector]) = {
     var row = 0
@@ -212,7 +263,8 @@ class MatrixOps(val m: Matrix) {
    * Ideally, we would probably want to override equals(). But that is not
    * possible without modifying AbstractMatrix implementation in Mahout
    * which would require discussion at Mahout team.
-   * @param that
+    *
+    * @param that
    * @return
    */
   def equiv(that: Matrix) =
@@ -233,7 +285,8 @@ class MatrixOps(val m: Matrix) {
 
   /**
    * test if rank == min(nrow,ncol).
-   * @return
+    *
+    * @return
    */
   def isFullRank: Boolean =
     new QRDecomposition(if (nrow < ncol) m t else m cloned).hasFullRank

http://git-wip-us.apache.org/repos/asf/mahout/blob/ff51ab44/math-scala/src/main/scala/org/apache/mahout/math/scalabindings/package.scala
----------------------------------------------------------------------
diff --git a/math-scala/src/main/scala/org/apache/mahout/math/scalabindings/package.scala b/math-scala/src/main/scala/org/apache/mahout/math/scalabindings/package.scala
index 426996b..6a3aa06 100644
--- a/math-scala/src/main/scala/org/apache/mahout/math/scalabindings/package.scala
+++ b/math-scala/src/main/scala/org/apache/mahout/math/scalabindings/package.scala
@@ -29,6 +29,12 @@ package object scalabindings {
   // Reserved "ALL" range
   final val `::`: Range = null
 
+  // Some enums
+  object AutoBooleanEnum extends Enumeration {
+    type T = Value
+    val TRUE, FALSE, AUTO = Value
+  }
+
   implicit def seq2Vector(s: TraversableOnce[AnyVal]) =
     new DenseVector(s.map(_.asInstanceOf[Number].doubleValue()).toArray)
 

http://git-wip-us.apache.org/repos/asf/mahout/blob/ff51ab44/math-scala/src/test/scala/org/apache/mahout/math/drm/RLikeDrmOpsSuiteBase.scala
----------------------------------------------------------------------
diff --git a/math-scala/src/test/scala/org/apache/mahout/math/drm/RLikeDrmOpsSuiteBase.scala b/math-scala/src/test/scala/org/apache/mahout/math/drm/RLikeDrmOpsSuiteBase.scala
index b46ee30..685c540 100644
--- a/math-scala/src/test/scala/org/apache/mahout/math/drm/RLikeDrmOpsSuiteBase.scala
+++ b/math-scala/src/test/scala/org/apache/mahout/math/drm/RLikeDrmOpsSuiteBase.scala
@@ -634,5 +634,19 @@ trait RLikeDrmOpsSuiteBase extends DistributedMahoutSuite with Matchers {
 
   }
 
+  test("functional apply()") {
+    val mxA = sparse (
+      (1 -> 3) :: (7 -> 7) :: Nil,
+      (4 -> 5) :: (5 -> 8) :: Nil
+    )
+
+    val mxAControl = mxA cloned
+    val drmA = drmParallelize(mxA)
+
+    (drmA(x => x + 1).collect - (mxAControl + 1)).norm should be < 1e-7
+    (drmA(x => x * 2).collect - (2 * mxAControl)).norm should be < 1e-7
+
+  }
+
 
 }

http://git-wip-us.apache.org/repos/asf/mahout/blob/ff51ab44/math-scala/src/test/scala/org/apache/mahout/math/scalabindings/MatrixOpsSuite.scala
----------------------------------------------------------------------
diff --git a/math-scala/src/test/scala/org/apache/mahout/math/scalabindings/MatrixOpsSuite.scala b/math-scala/src/test/scala/org/apache/mahout/math/scalabindings/MatrixOpsSuite.scala
index 5c8a310..1296d9e 100644
--- a/math-scala/src/test/scala/org/apache/mahout/math/scalabindings/MatrixOpsSuite.scala
+++ b/math-scala/src/test/scala/org/apache/mahout/math/scalabindings/MatrixOpsSuite.scala
@@ -131,6 +131,18 @@ class MatrixOpsSuite extends FunSuite with MahoutSuite {
     g.sum shouldBe 3
   }
 
+  test("functional apply()") {
+    val mxA = sparse (
+      (1 -> 3) :: (7 -> 7) :: Nil,
+      (4 -> 5) :: (5 -> 8) :: Nil
+    )
+    val mxAControl = mxA cloned
+
+    (mxA(x ⇒ x + 1) - (mxAControl + 1)).norm should be < 1e-7
+    (mxA(x ⇒ x * 2) - (2 * mxAControl)).norm should be < 1e-7
+
+  }
+
   test("sparse") {
 
     val a = sparse((1, 3) :: Nil,