Author: dfilimon
Date: Fri May  3 16:04:13 2013
New Revision: 1478853

URL: http://svn.apache.org/r1478853
Log:
Part of MAHOUT-1202.

Makes DoubleFunction and DoubleDoubleFunction abstract
classes and adds method for a function class that can speedup vector operations
that check if a function has certain properties (is associative/commutative
etc.)


Added:
    mahout/trunk/math/src/test/java/org/apache/mahout/math/FunctionTest.java
Modified:
    mahout/trunk/core/src/main/java/org/apache/mahout/ep/Mapping.java
    
mahout/trunk/math/src/main/java/org/apache/mahout/math/decomposer/lanczos/LanczosSolver.java
    
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/DoubleDoubleFunction.java
    
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/DoubleFunction.java
    
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/Functions.java
    mahout/trunk/math/src/main/java/org/apache/mahout/math/function/Mult.java
    
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/PlusMult.java
    
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/SquareRootFunction.java
    
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/TimesFunction.java
    
mahout/trunk/math/src/main/java/org/apache/mahout/math/jet/math/Constants.java
    
mahout/trunk/math/src/main/java/org/apache/mahout/math/jet/random/AbstractDistribution.java
    
mahout/trunk/math/src/main/java/org/apache/mahout/math/jet/random/engine/RandomEngine.java
    
mahout/trunk/math/src/main/java/org/apache/mahout/math/random/AbstractSamplerFunction.java

Modified: mahout/trunk/core/src/main/java/org/apache/mahout/ep/Mapping.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/core/src/main/java/org/apache/mahout/ep/Mapping.java?rev=1478853&r1=1478852&r2=1478853&view=diff
==============================================================================
--- mahout/trunk/core/src/main/java/org/apache/mahout/ep/Mapping.java (original)
+++ mahout/trunk/core/src/main/java/org/apache/mahout/ep/Mapping.java Fri May  
3 16:04:13 2013
@@ -17,20 +17,20 @@
 
 package org.apache.mahout.ep;
 
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
 import com.google.common.base.Preconditions;
 import org.apache.hadoop.io.Writable;
 import org.apache.mahout.classifier.sgd.PolymorphicWritable;
 import org.apache.mahout.math.function.DoubleFunction;
 
-import java.io.DataInput;
-import java.io.DataOutput;
-import java.io.IOException;
-
 /**
  * Provides coordinate tranformations so that evolution can proceed on the 
entire space of
  * reals but have the output limited and squished in convenient (and safe) 
ways.
  */
-public abstract class Mapping implements DoubleFunction, Writable {
+public abstract class Mapping extends DoubleFunction implements Writable {
 
   private Mapping() {
   }

Modified: 
mahout/trunk/math/src/main/java/org/apache/mahout/math/decomposer/lanczos/LanczosSolver.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/math/src/main/java/org/apache/mahout/math/decomposer/lanczos/LanczosSolver.java?rev=1478853&r1=1478852&r2=1478853&view=diff
==============================================================================
--- 
mahout/trunk/math/src/main/java/org/apache/mahout/math/decomposer/lanczos/LanczosSolver.java
 (original)
+++ 
mahout/trunk/math/src/main/java/org/apache/mahout/math/decomposer/lanczos/LanczosSolver.java
 Fri May  3 16:04:13 2013
@@ -18,6 +18,9 @@
 package org.apache.mahout.math.decomposer.lanczos;
 
 
+import java.util.EnumMap;
+import java.util.Map;
+
 import com.google.common.base.Preconditions;
 import org.apache.mahout.math.Matrix;
 import org.apache.mahout.math.Vector;
@@ -28,9 +31,6 @@ import org.apache.mahout.math.solver.Eig
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.EnumMap;
-import java.util.Map;
-
 /**
  * <p>Simple implementation of the <a 
href="http://en.wikipedia.org/wiki/Lanczos_algorithm";>Lanczos algorithm</a> for
  * finding eigenvalues of a symmetric matrix, applied to non-symmetric 
matrices by applying Matrix.timesSquared(vector)
@@ -76,7 +76,7 @@ public class LanczosSolver {
   private final Map<TimingSection, Long> startTimes = new 
EnumMap<TimingSection, Long>(TimingSection.class);
   private final Map<TimingSection, Long> times = new EnumMap<TimingSection, 
Long>(TimingSection.class);
 
-  private static final class Scale implements DoubleFunction {
+  private static final class Scale extends DoubleFunction {
     private final double d;
 
     private Scale(double d) {

Modified: 
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/DoubleDoubleFunction.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/math/src/main/java/org/apache/mahout/math/function/DoubleDoubleFunction.java?rev=1478853&r1=1478852&r2=1478853&view=diff
==============================================================================
--- 
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/DoubleDoubleFunction.java
 (original)
+++ 
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/DoubleDoubleFunction.java
 Fri May  3 16:04:13 2013
@@ -29,7 +29,7 @@ package org.apache.mahout.math.function;
 /**
  * Interface that represents a function object: a function that takes two 
arguments and returns a single value.
  **/
-public interface DoubleDoubleFunction {
+public abstract class DoubleDoubleFunction {
 
   /**
    * Apply the function to the arguments and return the result
@@ -38,5 +38,61 @@ public interface DoubleDoubleFunction {
    * @param arg2 a double for the second argument
    * @return the result of applying the function
    */
-  double apply(double arg1, double arg2);
+  public abstract double apply(double arg1, double arg2);
+
+  /**
+   * @return true iff f(x, 0) = x for any x
+   */
+  public boolean isLikeRightPlus() {
+    return false;
+  }
+
+  /**
+   * @return true iff f(0, y) = 0 for any y
+   */
+  public boolean isLikeLeftMult() {
+    return false;
+  }
+
+  /**
+   * @return true iff f(x, 0) = 0 for any x
+   */
+  public boolean isLikeRightMult() {
+    return false;
+  }
+
+  /**
+   * @return true iff f(x, 0) = f(0, y) = 0 for any x, y
+   */
+  public boolean isLikeMult() {
+    return isLikeLeftMult() && isLikeRightMult();
+  }
+
+  /**
+   * @return true iff f(x, y) = f(y, x) for any x, y
+   */
+  public boolean isCommutative() {
+    return false;
+  }
+
+  /**
+   * @return true iff f(x, f(y, z)) = f(f(x, y), z) for any x, y, z
+   */
+  public boolean isAssociative() {
+    return false;
+  }
+
+  /**
+   * @return true iff f(x, y) = f(y, x) for any x, y AND f(x, f(y, z)) = 
f(f(x, y), z) for any x, y, z
+   */
+  public boolean isAssociativeAndCommutative() {
+    return isAssociative() && isCommutative();
+  }
+
+  /**
+   * @return true iff f(0, 0) != 0
+   */
+  public boolean isDensifying() {
+    return apply(0.0, 0.0) != 0.0;
+  }
 }

Modified: 
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/DoubleFunction.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/math/src/main/java/org/apache/mahout/math/function/DoubleFunction.java?rev=1478853&r1=1478852&r2=1478853&view=diff
==============================================================================
--- 
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/DoubleFunction.java
 (original)
+++ 
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/DoubleFunction.java
 Fri May  3 16:04:13 2013
@@ -32,14 +32,17 @@ It is provided "as is" without expressed
  * Interface that represents a function object: a function that takes a single 
argument and returns a single value.
  * @see org.apache.mahout.math.map
  */
-public interface DoubleFunction {
+public abstract class DoubleFunction {
 
   /**
    * Apply the function to the argument and return the result
    *
-   * @param arg1 double for the argument
+   * @param x double for the argument
    * @return the result of applying the function
    */
-  double apply(double arg1);
+  public abstract double apply(double x);
 
+  public boolean isDensifying() {
+    return Math.abs(apply(0.0)) != 0.0;
+  }
 }

Modified: 
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/Functions.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/math/src/main/java/org/apache/mahout/math/function/Functions.java?rev=1478853&r1=1478852&r2=1478853&view=diff
==============================================================================
--- 
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/Functions.java 
(original)
+++ 
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/Functions.java 
Fri May  3 16:04:13 2013
@@ -26,10 +26,13 @@ It is provided "as is" without expressed
 
 package org.apache.mahout.math.function;
 
-import org.apache.mahout.math.jet.random.engine.MersenneTwister;
 
 import java.util.Date;
 
+import com.google.common.base.Preconditions;
+import org.apache.mahout.math.jet.random.engine.MersenneTwister;
+
+
 /**
  * Function objects to be passed to generic methods. Contains the functions of 
{@link java.lang.Math} as function
  * objects, as well as a few more basic functions. <p>Function objects 
conveniently allow to express arbitrary functions
@@ -298,7 +301,6 @@ public final class Functions {
     }
   };
 
-
   /*
    * <H3>Binary functions</H3>
    */
@@ -328,6 +330,53 @@ public final class Functions {
     public double apply(double a, double b) {
       return a / b;
     }
+
+    /**
+     * x / 0 = infinity or undefined depending on x
+     * @return true iff f(x, 0) = x for any x
+     */
+    @Override
+    public boolean isLikeRightPlus() {
+      return false;
+    }
+
+    /**
+     * 0 / y = 0 unless y = 0
+     * @return true iff f(0, y) = 0 for any y
+     */
+    @Override
+    public boolean isLikeLeftMult() {
+      return false;
+    }
+
+    /**
+     * x / 0 = infinity or undefined depending on x
+     * @return true iff f(x, 0) = 0 for any x
+     */
+    @Override
+    public boolean isLikeRightMult() {
+      return false;
+    }
+
+    /**
+     * x / y != y / x
+     * @return true iff f(x, y) = f(y, x) for any x, y
+     */
+    @Override
+    public boolean isCommutative() {
+      return false;
+    }
+
+    /**
+     * x / (y / z) = x * z / y
+     * (x / y) / z = x / (y * z)
+     * @return true iff f(x, f(y, z)) = f(f(x, y), z) for any x, y, z
+     */
+    @Override
+    public boolean isAssociative() {
+      return false;
+    }
+
   };
 
   /** Function that returns <tt>a == b ? 1 : 0</tt>. */
@@ -337,6 +386,15 @@ public final class Functions {
     public double apply(double a, double b) {
       return a == b ? 1 : 0;
     }
+
+    /**
+     * x = y iff y = x
+     * @return true iff f(x, y) = f(y, x) for any x, y
+     */
+    @Override
+    public boolean isCommutative() {
+      return true;
+    }
   };
 
   /** Function that returns <tt>a > b ? 1 : 0</tt>. */
@@ -409,6 +467,104 @@ public final class Functions {
     public double apply(double a, double b) {
       return Math.max(a, b);
     }
+
+    /**
+     * max(x, 0) = x or 0 depending on the sign of x
+     * @return true iff f(x, 0) = x for any x
+     */
+    @Override
+    public boolean isLikeRightPlus() {
+      return false;
+    }
+
+    /**
+     * max(0, y) = y or 0 depending on the sign of y
+     * @return true iff f(0, y) = 0 for any y
+     */
+    @Override
+    public boolean isLikeLeftMult() {
+      return false;
+    }
+
+    /**
+     * max(x, 0) = x or 0 depending on the sign of x
+     * @return true iff f(x, 0) = 0 for any x
+     */
+    @Override
+    public boolean isLikeRightMult() {
+      return false;
+    }
+
+    /**
+     * max(x, max(y, z)) = max(max(x, y), z)
+     * @return true iff f(x, f(y, z)) = f(f(x, y), z) for any x, y, z
+     */
+    @Override
+    public boolean isAssociative() {
+      return true;
+    }
+
+    /**
+     * max(x, y) = max(y, x)
+     * @return true iff f(x, y) = f(y, x) for any x, y
+     */
+    @Override
+    public boolean isCommutative() {
+      return true;
+    }
+  };
+
+  public static final DoubleDoubleFunction MAX_ABS = new 
DoubleDoubleFunction() {
+
+    @Override
+    public double apply(double a, double b) {
+      return Math.max(Math.abs(a), Math.abs(b));
+    }
+
+    /**
+     * max(|x|, 0) = |x|
+     * @return true iff f(x, 0) = x for any x
+     */
+    @Override
+    public boolean isLikeRightPlus() {
+      return true;
+    }
+
+    /**
+     * max(0, |y|) = |y|
+     * @return true iff f(0, y) = 0 for any y
+     */
+    @Override
+    public boolean isLikeLeftMult() {
+      return false;
+    }
+
+    /**
+     * max(|x|, 0) = |x|
+     * @return true iff f(x, 0) = 0 for any x
+     */
+    @Override
+    public boolean isLikeRightMult() {
+      return false;
+    }
+
+    /**
+     * max(|x|, max(|y|, |z|)) = max(max(|x|, |y|), |z|)
+     * @return true iff f(x, f(y, z)) = f(f(x, y), z) for any x, y, z
+     */
+    @Override
+    public boolean isAssociative() {
+      return true;
+    }
+
+    /**
+     * max(|x|, |y|) = max(|y\, |x\)
+     * @return true iff f(x, y) = f(y, x) for any x, y
+     */
+    @Override
+    public boolean isCommutative() {
+      return true;
+    }
   };
 
   /** Function that returns <tt>Math.min(a,b)</tt>. */
@@ -418,15 +574,107 @@ public final class Functions {
     public double apply(double a, double b) {
       return Math.min(a, b);
     }
+
+    /**
+     * min(x, 0) = x or 0 depending on the sign of x
+     * @return true iff f(x, 0) = x for any x
+     */
+    @Override
+    public boolean isLikeRightPlus() {
+      return false;
+    }
+
+    /**
+     * min(0, y) = y or 0 depending on the sign of y
+     * @return true iff f(0, y) = 0 for any y
+     */
+    @Override
+    public boolean isLikeLeftMult() {
+      return false;
+    }
+
+    /**
+     * min(x, 0) = x or 0 depending on the sign of x
+     * @return true iff f(x, 0) = 0 for any x
+     */
+    @Override
+    public boolean isLikeRightMult() {
+      return false;
+    }
+
+    /**
+     * min(x, min(y, z)) = min(min(x, y), z)
+     * @return true iff f(x, f(y, z)) = f(f(x, y), z) for any x, y, z
+     */
+    @Override
+    public boolean isAssociative() {
+      return true;
+    }
+
+    /**
+     * min(x, y) = min(y, x)
+     * @return true iff f(x, y) = f(y, x) for any x, y
+     */
+    @Override
+    public boolean isCommutative() {
+      return true;
+    }
   };
 
   /** Function that returns <tt>a - b</tt>. */
   public static final DoubleDoubleFunction MINUS = plusMult(-1);
-  /*
-  new DoubleDoubleFunction() {
-    public final double apply(double a, double b) { return a - b; }
-  };
+
+  public static final DoubleDoubleFunction MINUS_SQUARED = new 
DoubleDoubleFunction() {
+    @Override
+    public double apply(double x, double y) {
+      return (x - y) * (x - y);
+    }
+
+    /**
+     * (x - 0)^2 = x^2 != x
+     * @return true iff f(x, 0) = x for any x
   */
+    @Override
+    public boolean isLikeRightPlus() {
+      return false;
+    }
+
+    /**
+     * (0 - y)^2 != 0
+     * @return true iff f(0, y) = 0 for any y
+     */
+    @Override
+    public boolean isLikeLeftMult() {
+      return false;
+    }
+
+    /**
+     * (x - 0)^2 != x
+     * @return true iff f(x, 0) = 0 for any x
+     */
+    @Override
+    public boolean isLikeRightMult() {
+      return false;
+    }
+
+    /**
+     * (x - y)^2 = (y - x)^2
+     * @return true iff f(x, y) = f(y, x) for any x, y
+     */
+    @Override
+    public boolean isCommutative() {
+      return true;
+    }
+
+    /**
+     * (x - (y - z)^2)^2 != ((x - y)^2 - z)^2
+     * @return true iff f(x, f(y, z)) = f(f(x, y), z) for any x, y, z
+     */
+    @Override
+    public boolean isAssociative() {
+      return false;
+    }
+  };
 
   /** Function that returns <tt>a % b</tt>. */
   public static final DoubleDoubleFunction MOD = new DoubleDoubleFunction() {
@@ -438,29 +686,115 @@ public final class Functions {
   };
 
   /** Function that returns <tt>a * b</tt>. */
-  public static final DoubleDoubleFunction MULT = new DoubleDoubleFunction() {
+  public static final DoubleDoubleFunction MULT = new TimesFunction();
+
+  /** Function that returns <tt>a + b</tt>. */
+  public static final DoubleDoubleFunction PLUS = plusMult(1);
+
+  /** Function that returns <tt>Math.abs(a) + Math.abs(b)</tt>. */
+  public static final DoubleDoubleFunction PLUS_ABS = new 
DoubleDoubleFunction() {
 
     @Override
     public double apply(double a, double b) {
-      return a * b;
+      return Math.abs(a) + Math.abs(b);
+    }
+
+    /**
+     * abs(x) + abs(0) = abs(x) != x
+     * @return true iff f(x, 0) = x for any x
+     */
+    @Override
+    public boolean isLikeRightPlus() {
+      return false;
     }
-  };
-  
-  /** Function that returns <tt>a + b</tt>. */
-  public static final DoubleDoubleFunction PLUS = new DoubleDoubleFunction() {
     
+    /**
+     * abs(0) + abs(y) = abs(y) != 0 unless y = 0
+     * @return true iff f(0, y) = 0 for any y
+     */
     @Override
-    public double apply(double a, double b) {
-      return a + b;
+    public boolean isLikeLeftMult() {
+      return false;
+    }
+
+    /**
+     * abs(x) + abs(0) = abs(x) != 0 unless x = 0
+     * @return true iff f(x, 0) = 0 for any x
+     */
+    @Override
+    public boolean isLikeRightMult() {
+      return false;
+    }
+
+    /**
+     * abs(x) + abs(abs(y) + abs(z)) = abs(x) + abs(y) + abs(z)
+     * abs(abs(x) + abs(y)) + abs(z) = abs(x) + abs(y) + abs(z)
+     * @return true iff f(x, f(y, z)) = f(f(x, y), z) for any x, y, z
+     */
+    @Override
+    public boolean isAssociative() {
+      return true;
+    }
+
+    /**
+     * abs(x) + abs(y) = abs(y) + abs(x)
+     * @return true iff f(x, y) = f(y, x) for any x, y
+     */
+    @Override
+    public boolean isCommutative() {
+      return true;
     }
   };
 
-  /** Function that returns <tt>Math.abs(a) + Math.abs(b)</tt>. */
-  public static final DoubleDoubleFunction PLUS_ABS = new 
DoubleDoubleFunction() {
+  public static final DoubleDoubleFunction MINUS_ABS = new 
DoubleDoubleFunction() {
+    @Override
+    public double apply(double x, double y) {
+      return Math.abs(x - y);
+    }
 
+    /**
+     * |x - 0| = |x|
+     * @return true iff f(x, 0) = x for any x
+     */
     @Override
-    public double apply(double a, double b) {
-      return Math.abs(a) + Math.abs(b);
+    public boolean isLikeRightPlus() {
+      return false;
+    }
+
+    /**
+     * |0 - y| = |y|
+     * @return true iff f(0, y) = 0 for any y
+     */
+    @Override
+    public boolean isLikeLeftMult() {
+      return false;
+    }
+
+    /**
+     * |x - 0| = |x|
+     * @return true iff f(x, 0) = 0 for any x
+     */
+    @Override
+    public boolean isLikeRightMult() {
+      return false;
+    }
+
+    /**
+     * |x - y| = |y - x|
+     * @return true iff f(x, y) = f(y, x) for any x, y
+     */
+    @Override
+    public boolean isCommutative() {
+      return true;
+    }
+
+    /**
+     * |x - |y - z|| != ||x - y| - z| (|5 - |4 - 3|| = 1; ||5 - 4| - 3| = |1 - 
3| = 2)
+     * @return true iff f(x, f(y, z)) = f(f(x, y), z) for any x, y, z
+     */
+    @Override
+    public boolean isAssociative() {
+      return false;
     }
   };
 
@@ -471,8 +805,329 @@ public final class Functions {
     public double apply(double a, double b) {
       return Math.pow(a, b);
     }
+
+    /**
+     * x^0 = 1 for any x unless x = 0 (undefined)
+     * @return true iff f(x, 0) = x for any x
+     */
+    @Override
+    public boolean isLikeRightPlus() {
+      return false;
+    }
+
+    /**
+     * 0^y = 0 for any y unless y = 0 (undefined, but Math.pow(0, 0) = 1)
+     * @return true iff f(0, y) = 0 for any y
+     */
+    @Override
+    public boolean isLikeLeftMult() {
+      return false;
+    }
+
+    /**
+     * x^0 = 1 for any x (even x = 0)
+     * @return true iff f(x, 0) = 0 for any x
+     */
+    @Override
+    public boolean isLikeRightMult() {
+      return false;
+    }
+
+    /**
+     * x^y != y^x (2^3 != 3^2)
+     * @return true iff f(x, y) = f(y, x) for any x, y
+     */
+    @Override
+    public boolean isCommutative() {
+      return false;
+    }
+
+    /**
+     * x^(y^z) != (x^y)^z ((2^3)^4 = 8^4 = 2^12 != 2^(3^4) = 2^81)
+     * @return true iff f(x, f(y, z)) = f(f(x, y), z) for any x, y, z
+     */
+    @Override
+    public boolean isAssociative() {
+      return false;
+    }
   };
 
+  public static final DoubleDoubleFunction SECOND = new DoubleDoubleFunction() 
{
+    @Override
+    public double apply(double x, double y) {
+      return y;
+    }
+
+    /**
+     * f(x, 0) = x for any x
+     * @return true iff f(x, 0) = x for any x
+     */
+    @Override
+    public boolean isLikeRightPlus() {
+      return false;
+    }
+
+    /**
+     * f(0, y) = y for any y
+     * @return true iff f(0, y) = 0 for any y
+     */
+    @Override
+    public boolean isLikeLeftMult() {
+      return false;
+    }
+
+    /**
+     * f(x, 0) = 0 for any x
+     * @return true iff f(x, 0) = 0 for any x
+     */
+    @Override
+    public boolean isLikeRightMult() {
+      return true;
+    }
+
+    /**
+     * f(x, y) = x != y = f(y, x) for any x, y unless x = y
+     * @return true iff f(x, y) = f(y, x) for any x, y
+     */
+    @Override
+    public boolean isCommutative() {
+      return false;
+    }
+
+    /**
+     * f(x, f(y, z)) = f(x, z) = z
+     * f(f(x, y), z) = z
+     * @return true iff f(x, f(y, z)) = f(f(x, y), z) for any x, y, z
+     */
+    @Override
+    public boolean isAssociative() {
+      return true;
+    }
+  };
+
+  /**
+   * This function is specifically designed to be used when assigning a vector 
to one that is all zeros (created
+   * by like()). It enables iteration only through the nonzeros of the right 
hand side by declaring isLikeRightPlus
+   * to be true. This is NOT generally true for SECOND (hence the other 
function above).
+   */
+  public static final DoubleDoubleFunction SECOND_LEFT_ZERO = new 
DoubleDoubleFunction() {
+    @Override
+    public double apply(double x, double y) {
+      Preconditions.checkArgument(x == 0, "This special version of SECOND 
needs x == 0");
+      return y;
+    }
+
+    /**
+     * f(x, 0) = 0 for any x; we're only assigning to left hand sides that are 
strictly 0
+     * @return true iff f(x, 0) = x for any x
+     */
+    @Override
+    public boolean isLikeRightPlus() {
+      return true;
+    }
+
+    /**
+     * f(0, y) = y for any y
+     * @return true iff f(0, y) = 0 for any y
+     */
+    @Override
+    public boolean isLikeLeftMult() {
+      return false;
+    }
+
+    /**
+     * f(x, 0) = 0 for any x
+     * @return true iff f(x, 0) = 0 for any x
+     */
+    @Override
+    public boolean isLikeRightMult() {
+      return true;
+    }
+
+    /**
+     * f(x, y) = x != y = f(y, x) for any x, y unless x = y
+     * @return true iff f(x, y) = f(y, x) for any x, y
+     */
+    @Override
+    public boolean isCommutative() {
+      return false;
+    }
+
+    /**
+     * f(x, f(y, z)) = f(x, z) = z
+     * f(f(x, y), z) = z
+     * @return true iff f(x, f(y, z)) = f(f(x, y), z) for any x, y, z
+     */
+    @Override
+    public boolean isAssociative() {
+      return true;
+    }
+  };
+  public static final DoubleDoubleFunction MULT_SQUARE_LEFT = new 
DoubleDoubleFunction() {
+    @Override
+    public double apply(double x, double y) {
+      return x * x * y;
+    }
+
+    /**
+     * x * x * 0 = 0
+     * @return true iff f(x, 0) = x for any x
+     */
+    @Override
+    public boolean isLikeRightPlus() {
+      return false;
+    }
+
+    /**
+     * 0 * 0 * y = 0
+     * @return true iff f(0, y) = 0 for any y
+     */
+    @Override
+    public boolean isLikeLeftMult() {
+      return true;
+    }
+
+    /**
+     * x * x * 0 = 0
+     * @return true iff f(x, 0) = 0 for any x
+     */
+    @Override
+    public boolean isLikeRightMult() {
+      return true;
+    }
+
+    /**
+     * x * x * y != y * y * x
+     * @return true iff f(x, y) = f(y, x) for any x, y
+     */
+    @Override
+    public boolean isCommutative() {
+      return false;
+    }
+
+    /**
+     * x * x * y * y * z != x * x * y * x * x * y * z
+     * @return true iff f(x, f(y, z)) = f(f(x, y), z) for any x, y, z
+     */
+    @Override
+    public boolean isAssociative() {
+      return false;
+    }
+  };
+
+  public static final DoubleDoubleFunction MULT_RIGHT_PLUS1 = new 
DoubleDoubleFunction() {
+
+    /**
+     * Apply the function to the arguments and return the result
+     *
+     * @param x a double for the first argument
+     * @param y a double for the second argument
+     * @return the result of applying the function
+     */
+    @Override
+    public double apply(double x, double y) {
+      return x * (y + 1);
+    }
+
+    /**
+     * x * 1 = x
+     * @return true iff f(x, 0) = x for any x
+     */
+    @Override
+    public boolean isLikeRightPlus() {
+      return true;
+    }
+
+    /**
+     * 0 * y = 0
+     * @return true iff f(0, y) = 0 for any y
+     */
+    @Override
+    public boolean isLikeLeftMult() {
+      return true;
+    }
+
+    /**
+     * x * 1 = x != 0
+     * @return true iff f(x, 0) = 0 for any x
+     */
+    @Override
+    public boolean isLikeRightMult() {
+      return false;
+    }
+
+    /**
+     * x * (y + 1) != y * (x + 1)
+     * @return true iff f(x, y) = f(y, x) for any x, y
+     */
+    @Override
+    public boolean isCommutative() {
+      return false;
+    }
+
+    /**
+     * @return true iff f(x, f(y, z)) = f(f(x, y), z) for any x, y, z
+     */
+    @Override
+    public boolean isAssociative() {
+      return false;
+    }
+  };
+
+  public static DoubleDoubleFunction reweigh(final double wx, final double wy) 
{
+    final double tw = wx + wy;
+    return new DoubleDoubleFunction() {
+      @Override
+      public double apply(double x, double y) {
+        return (wx * x + wy * y) / tw;
+      }
+
+      /**
+       * f(x, 0) = wx * x / tw = x iff wx = tw (practically, impossible, as tw 
= wx + wy and wy > 0)
+       * @return true iff f(x, 0) = x for any x
+       */
+      @Override
+      public boolean isLikeRightPlus() {
+        return wx == tw;
+      }
+
+      /**
+       * f(0, y) = wy * y / tw = 0 iff y = 0
+       * @return true iff f(0, y) = 0 for any y
+       */
+      @Override
+      public boolean isLikeLeftMult() {
+        return false;
+      }
+
+      /**
+       * f(x, 0) = wx * x / tw = 0 iff x = 0
+       * @return true iff f(x, 0) = 0 for any x
+       */
+      @Override
+      public boolean isLikeRightMult() {
+        return false;
+      }
+
+      /**
+       * wx * x + wy * y = wx * y + wy * x iff wx = wy
+       * @return true iff f(x, y) = f(y, x) for any x, y
+       */
+      @Override
+      public boolean isCommutative() {
+        return wx == wy;
+      }
+
+      /**
+       * @return true iff f(x, f(y, z)) = f(f(x, y), z) for any x, y, z
+       */
+      @Override
+      public boolean isAssociative() {
+        return false;
+      }
+    };
+  }
+
   private Functions() {
   }
 
@@ -540,6 +1195,59 @@ public final class Functions {
       public double apply(double a, double b) {
         return f.apply(g.apply(a), h.apply(b));
       }
+
+      /**
+       * fx(c, 0) = f(g(x), h(0)) = f(g(x), 0) = g(x) = x if h(0) = 0 and f 
isLikeRightPlus and g(x) = x
+       * Impossible to check whether g(x) = x for any x, so we return false.
+       * @return true iff f(x, 0) = x for any x
+       */
+      @Override
+      public boolean isLikeRightPlus() {
+        return false;
+      }
+
+      /**
+       * fc(0, y) = f(g(0), h(y)) = f(0, h(y)) = 0 if g(0) = 0 and f 
isLikeLeftMult
+       * @return true iff f(0, y) = 0 for any y
+       */
+      @Override
+      public boolean isLikeLeftMult() {
+        return g.apply(0) == 0 && f.isLikeLeftMult();
+      }
+
+      /**
+       * fc(x, 0) = f(g(x), h(0)) = f(g(x), 0) = 0 if h(0) = 0 and f 
isLikeRightMult
+       * @return true iff f(x, 0) = 0 for any x
+       */
+      @Override
+      public boolean isLikeRightMult() {
+        return h.apply(0) == 0 && f.isLikeRightMult();
+      }
+
+      /**
+       * fc(x, y) = f(g(x), h(y)) = f(h(y), g(x))
+       * fc(y, x) = f(g(y), h(x)) = f(h(x), g(y))
+       * Either g(x) = g(y) for any x, y and h(x) = h(y) for any x, y or g = h 
and f isCommutative.
+       * Can only check if g = h (reference equality, assuming they're both 
the same static function in
+       * this file) and f isCommutative. There are however other scenarios 
when this might happen that are NOT
+       * covered by this definition.
+       * @return true iff f(x, y) = f(y, x) for any x, y
+       */
+      @Override
+      public boolean isCommutative() {
+        return g.equals(h) && f.isCommutative();
+      }
+
+      /**
+       * fc(x, fc(y, z)) = f(g(x), h(f(g(y), h(z))))
+       * fc(fc(x, y), z) = f(g(f(g(x), h(y))), h(z))
+       * Impossible to check.
+       * @return true iff f(x, f(y, z)) = f(f(x, y), z) for any x, y, z
+       */
+      @Override
+      public boolean isAssociative() {
+        return false;
+      }
     };
   }
 
@@ -548,7 +1256,7 @@ public final class Functions {
    *
    * @param g a unary function.
    * @param h a binary function.
-   * @return the unary function <tt>g( h(a,b) )</tt>.
+   * @return the binary function <tt>g( h(a,b) )</tt>.
    */
   public static DoubleDoubleFunction chain(final DoubleFunction g, final 
DoubleDoubleFunction h) {
     return new DoubleDoubleFunction() {
@@ -557,6 +1265,54 @@ public final class Functions {
       public double apply(double a, double b) {
         return g.apply(h.apply(a, b));
       }
+
+      /**
+       * g(h(x, 0)) = g(x) = x for any x iff g(x) = x and h isLikeRightPlus
+       * Impossible to check.
+       * @return true iff f(x, 0) = x for any x
+       */
+      @Override
+      public boolean isLikeRightPlus() {
+        return false;
+      }
+
+      /**
+       * g(h(0, y)) = g(0) = 0 for any y iff g(0) = 0 and h isLikeLeftMult
+       * @return true iff f(0, y) = 0 for any y
+       */
+      @Override
+      public boolean isLikeLeftMult() {
+        return !g.isDensifying() && h.isLikeLeftMult();
+      }
+
+      /**
+       * g(h(x, 0)) = g(0) = 0 for any x iff g(0) = 0 and h isLikeRightMult
+       * @return true iff f(x, 0) = 0 for any x
+       */
+      @Override
+      public boolean isLikeRightMult() {
+        return !g.isDensifying() && h.isLikeRightMult();
+      }
+
+      /**
+       * fc(x, y) = g(h(x, y)) = g(h(y, x)) = fc(y, x) iff h isCommutative
+       * @return true iff f(x, y) = f(y, x) for any x, y
+       */
+      @Override
+      public boolean isCommutative() {
+        return h.isCommutative();
+      }
+
+      /**
+       * fc(x, fc(y, z)) = g(h(x, g(h(y, z)))
+       * fc(fc(x, y), z) = g(h(g(h(x, y)), z))
+       * Impossible to check.
+       * @return true iff f(x, f(y, z)) = f(f(x, y), z) for any x, y, z
+       */
+      @Override
+      public boolean isAssociative() {
+        return false;
+      }
     };
   }
 
@@ -794,11 +1550,6 @@ public final class Functions {
    */
   public static DoubleDoubleFunction plusMult(double constant) {
     return new PlusMult(constant);
-    /*
-    return new DoubleDoubleFunction() {
-      public final double apply(double a, double b) { return a + b*constant; }
-    };
-    */
   }
 
   /** Constructs a function that returns <tt>Math.pow(a,b)</tt>. <tt>a</tt> is 
a variable, <tt>b</tt> is fixed. */
@@ -807,8 +1558,12 @@ public final class Functions {
 
       @Override
       public double apply(double a) {
+        if (b == 2) {
+          return a * a;
+        } else {
         return Math.pow(a, b);
       }
+      }
     };
   }
 
@@ -857,4 +1612,58 @@ public final class Functions {
       }
     };
   }
+
+  public static DoubleDoubleFunction minusAbsPow(final double exponent) {
+    return new DoubleDoubleFunction() {
+      @Override
+      public double apply(double x, double y) {
+        return Math.pow(Math.abs(x - y), exponent);
+      }
+
+      /**
+       * |x - 0|^p = |x|^p != x unless x > 0 and p = 1
+       * @return true iff f(x, 0) = x for any x
+       */
+      @Override
+      public boolean isLikeRightPlus() {
+        return false;
+      }
+
+      /**
+       * |0 - y|^p = |y|^p
+       * @return true iff f(0, y) = 0 for any y
+       */
+      @Override
+      public boolean isLikeLeftMult() {
+        return false;
+      }
+
+      /**
+       * |x - 0|^p = |x|^p
+       * @return true iff f(x, 0) = 0 for any x
+       */
+      @Override
+      public boolean isLikeRightMult() {
+        return false;
+      }
+
+      /**
+       * |x - y|^p = |y - x|^p
+       * @return true iff f(x, y) = f(y, x) for any x, y
+       */
+      @Override
+      public boolean isCommutative() {
+        return true;
+      }
+
+      /**
+       * |x - |y - z|^p|^p != ||x - y|^p - z|^p
+       * @return true iff f(x, f(y, z)) = f(f(x, y), z) for any x, y, z
+       */
+      @Override
+      public boolean isAssociative() {
+        return false;
+      }
+    };
+  }
 }

Modified: 
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/Mult.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/math/src/main/java/org/apache/mahout/math/function/Mult.java?rev=1478853&r1=1478852&r2=1478853&view=diff
==============================================================================
--- mahout/trunk/math/src/main/java/org/apache/mahout/math/function/Mult.java 
(original)
+++ mahout/trunk/math/src/main/java/org/apache/mahout/math/function/Mult.java 
Fri May  3 16:04:13 2013
@@ -37,7 +37,7 @@ package org.apache.mahout.math.function;
  * Intended to be passed to <tt>matrix.assign(function)</tt> methods.
  */
 
-public final class Mult implements DoubleFunction {
+public final class Mult extends DoubleFunction {
 
   private double multiplicator;
 

Modified: 
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/PlusMult.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/math/src/main/java/org/apache/mahout/math/function/PlusMult.java?rev=1478853&r1=1478852&r2=1478853&view=diff
==============================================================================
--- 
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/PlusMult.java 
(original)
+++ 
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/PlusMult.java 
Fri May  3 16:04:13 2013
@@ -26,6 +26,8 @@ It is provided "as is" without expressed
 
 package org.apache.mahout.math.function;
 
+import org.apache.mahout.math.jet.math.Constants;
+
 /**
  * Only for performance tuning of compute intensive linear algebraic 
computations.
  * Constructs functions that return one of
@@ -39,7 +41,7 @@ package org.apache.mahout.math.function;
  * Intended to be passed to <tt>matrix.assign(otherMatrix,function)</tt> 
methods.
  */
 
-public final class PlusMult implements DoubleDoubleFunction {
+public final class PlusMult extends DoubleDoubleFunction {
 
   private double multiplicator;
 
@@ -67,6 +69,54 @@ public final class PlusMult implements D
     return multiplicator;
   }
 
+  /**
+   * x + 0 * c = x
+   * @return true iff f(x, 0) = x for any x
+   */
+  @Override
+  public boolean isLikeRightPlus() {
+    return true;
+  }
+
+  /**
+   * 0 + y * c = y * c != 0
+   * @return true iff f(0, y) = 0 for any y
+   */
+  @Override
+  public boolean isLikeLeftMult() {
+    return false;
+  }
+
+  /**
+   * x + 0 * c = x != 0
+   * @return true iff f(x, 0) = 0 for any x
+   */
+  @Override
+  public boolean isLikeRightMult() {
+    return false;
+  }
+
+  /**
+   * x + y * c = y + x * c iff c = 1
+   * @return true iff f(x, y) = f(y, x) for any x, y
+   */
+  @Override
+  public boolean isCommutative() {
+    return Math.abs(multiplicator - 1.0) < Constants.EPSILON;
+  }
+
+  /**
+   * f(x, f(y, z)) = x + c * (y + c * z) = x + c * y + c^2  * z
+   * f(f(x, y), z) = (x + c * y) + c * z = x + c * y + c * z
+   * true only for c = 0 or c = 1
+   * @return true iff f(x, f(y, z)) = f(f(x, y), z) for any x, y, z
+   */
+  @Override
+  public boolean isAssociative() {
+    return Math.abs(multiplicator - 0.0) < Constants.EPSILON ||
+        Math.abs(multiplicator - 1.0) < Constants.EPSILON;
+  }
+
   public void setMultiplicator(double multiplicator) {
     this.multiplicator = multiplicator;
   }

Modified: 
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/SquareRootFunction.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/math/src/main/java/org/apache/mahout/math/function/SquareRootFunction.java?rev=1478853&r1=1478852&r2=1478853&view=diff
==============================================================================
--- 
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/SquareRootFunction.java
 (original)
+++ 
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/SquareRootFunction.java
 Fri May  3 16:04:13 2013
@@ -17,7 +17,7 @@
 
 package org.apache.mahout.math.function;
 
-public final class SquareRootFunction implements DoubleFunction {
+public final class SquareRootFunction extends DoubleFunction {
 
   @Override
   public double apply(double arg1) {

Modified: 
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/TimesFunction.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/math/src/main/java/org/apache/mahout/math/function/TimesFunction.java?rev=1478853&r1=1478852&r2=1478853&view=diff
==============================================================================
--- 
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/TimesFunction.java
 (original)
+++ 
mahout/trunk/math/src/main/java/org/apache/mahout/math/function/TimesFunction.java
 Fri May  3 16:04:13 2013
@@ -16,7 +16,7 @@
  */
 package org.apache.mahout.math.function;
 
-public final class TimesFunction implements DoubleDoubleFunction {
+public final class TimesFunction extends DoubleDoubleFunction {
 
   /**
    * Computes the product of two numbers.
@@ -29,4 +29,49 @@ public final class TimesFunction impleme
   public double apply(double x, double y) {
     return x * y;
   }
+
+  /**
+   * x * 0 = y only if y = 0
+   * @return true iff f(x, 0) = x for any x
+   */
+  @Override
+  public boolean isLikeRightPlus() {
+    return false;
+  }
+
+  /**
+   * 0 * y = 0 for any y
+   * @return true iff f(0, y) = 0 for any y
+   */
+  @Override
+  public boolean isLikeLeftMult() {
+    return true;
+  }
+
+  /**
+   * x * 0 = 0 for any x
+   * @return true iff f(x, 0) = 0 for any x
+   */
+  @Override
+  public boolean isLikeRightMult() {
+    return true;
+  }
+
+  /**
+   * x * y = y * x for any x, y
+   * @return true iff f(x, y) = f(y, x) for any x, y
+   */
+  @Override
+  public boolean isCommutative() {
+    return true;
+  }
+
+  /**
+   * x * (y * z) = (x * y) * z for any x, y, z
+   * @return true iff f(x, f(y, z)) = f(f(x, y), z) for any x, y, z
+   */
+  @Override
+  public boolean isAssociative() {
+    return true;
+  }
 }

Modified: 
mahout/trunk/math/src/main/java/org/apache/mahout/math/jet/math/Constants.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/math/src/main/java/org/apache/mahout/math/jet/math/Constants.java?rev=1478853&r1=1478852&r2=1478853&view=diff
==============================================================================
--- 
mahout/trunk/math/src/main/java/org/apache/mahout/math/jet/math/Constants.java 
(original)
+++ 
mahout/trunk/math/src/main/java/org/apache/mahout/math/jet/math/Constants.java 
Fri May  3 16:04:13 2013
@@ -42,6 +42,8 @@ public final class Constants {
   public static final double BIG = 4.503599627370496e15;
   public static final double BIG_INVERSE = 2.22044604925031308085e-16;
 
+  public static final double EPSILON = 1E-6;
+
   private Constants() {
   }
 }

Modified: 
mahout/trunk/math/src/main/java/org/apache/mahout/math/jet/random/AbstractDistribution.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/math/src/main/java/org/apache/mahout/math/jet/random/AbstractDistribution.java?rev=1478853&r1=1478852&r2=1478853&view=diff
==============================================================================
--- 
mahout/trunk/math/src/main/java/org/apache/mahout/math/jet/random/AbstractDistribution.java
 (original)
+++ 
mahout/trunk/math/src/main/java/org/apache/mahout/math/jet/random/AbstractDistribution.java
 Fri May  3 16:04:13 2013
@@ -25,12 +25,12 @@ It is provided "as is" without expressed
 */
 package org.apache.mahout.math.jet.random;
 
+import java.util.Random;
+
 import org.apache.mahout.math.function.DoubleFunction;
 import org.apache.mahout.math.function.IntFunction;
 
-import java.util.Random;
-
-public abstract class AbstractDistribution implements DoubleFunction, 
IntFunction {
+public abstract class AbstractDistribution extends DoubleFunction implements 
IntFunction {
 
   private Random randomGenerator;
 

Modified: 
mahout/trunk/math/src/main/java/org/apache/mahout/math/jet/random/engine/RandomEngine.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/math/src/main/java/org/apache/mahout/math/jet/random/engine/RandomEngine.java?rev=1478853&r1=1478852&r2=1478853&view=diff
==============================================================================
--- 
mahout/trunk/math/src/main/java/org/apache/mahout/math/jet/random/engine/RandomEngine.java
 (original)
+++ 
mahout/trunk/math/src/main/java/org/apache/mahout/math/jet/random/engine/RandomEngine.java
 Fri May  3 16:04:13 2013
@@ -54,7 +54,7 @@ import org.apache.mahout.math.function.I
  * @see MersenneTwister
  * @see java.util.Random
  */
-public abstract class RandomEngine implements DoubleFunction, IntFunction {
+public abstract class RandomEngine extends DoubleFunction implements 
IntFunction {
 
   /**
    * Equivalent to <tt>raw()</tt>. This has the effect that random engines can 
now be used as function objects,

Modified: 
mahout/trunk/math/src/main/java/org/apache/mahout/math/random/AbstractSamplerFunction.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/math/src/main/java/org/apache/mahout/math/random/AbstractSamplerFunction.java?rev=1478853&r1=1478852&r2=1478853&view=diff
==============================================================================
--- 
mahout/trunk/math/src/main/java/org/apache/mahout/math/random/AbstractSamplerFunction.java
 (original)
+++ 
mahout/trunk/math/src/main/java/org/apache/mahout/math/random/AbstractSamplerFunction.java
 Fri May  3 16:04:13 2013
@@ -22,7 +22,7 @@ import org.apache.mahout.math.function.D
 /**
  * This shim allows samplers to be used to initialize vectors.
  */
-public abstract class AbstractSamplerFunction implements Sampler<Double>, 
DoubleFunction {
+public abstract class AbstractSamplerFunction extends DoubleFunction 
implements Sampler<Double> {
   /**
    * Apply the function to the argument and return the result
    *

Added: mahout/trunk/math/src/test/java/org/apache/mahout/math/FunctionTest.java
URL: 
http://svn.apache.org/viewvc/mahout/trunk/math/src/test/java/org/apache/mahout/math/FunctionTest.java?rev=1478853&view=auto
==============================================================================
--- mahout/trunk/math/src/test/java/org/apache/mahout/math/FunctionTest.java 
(added)
+++ mahout/trunk/math/src/test/java/org/apache/mahout/math/FunctionTest.java 
Fri May  3 16:04:13 2013
@@ -0,0 +1,116 @@
+package org.apache.mahout.math;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.List;
+import java.util.Random;
+
+import com.google.common.collect.Lists;
+import org.apache.mahout.common.RandomUtils;
+import org.apache.mahout.math.function.DoubleDoubleFunction;
+import org.apache.mahout.math.function.Functions;
+import org.apache.mahout.math.jet.math.Constants;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(Parameterized.class)
+public class FunctionTest {
+  private static final int NUM_POINTS = 100;
+
+  private final Random random = RandomUtils.getRandom();
+
+  private DoubleDoubleFunction function;
+  private String functionName;
+
+  @Parameterized.Parameters
+  public static Collection<Object[]> generateData() {
+    List<Object[]> data = Lists.newArrayList();
+    for (Field field : Functions.class.getDeclaredFields()) {
+      if (field.getType().isAssignableFrom(DoubleDoubleFunction.class)
+          && Modifier.isStatic(field.getModifiers())
+          && !field.getName().equals("SECOND_LEFT_ZERO")) {
+        try {
+          data.add(new Object[] {field.get(null), field.getName()});
+        } catch (IllegalAccessException e) {
+          System.out.printf("Couldn't access Functions field %s\n", 
field.getName());
+        }
+      }
+    }
+    return data;
+  }
+
+  public FunctionTest(DoubleDoubleFunction function, String functionName) {
+    this.function = function;
+    this.functionName = functionName;
+  }
+
+  @Test
+  public void testIsLikeRightPlus() {
+    if (!function.isLikeRightPlus()) {
+      return;
+    }
+    for (int i = 0; i < NUM_POINTS; ++i) {
+      double x = random.nextDouble();
+      assertEquals(functionName, x, function.apply(x, 0), 0);
+    }
+  }
+
+  @Test
+  public void testIsLikeLeftMult() {
+    if (!function.isLikeLeftMult()) {
+      return;
+    }
+    for (int i = 0; i < NUM_POINTS; ++i) {
+      double y = random.nextDouble();
+      assertEquals(functionName, 0, function.apply(0, y), 0);
+    }
+  }
+
+  @Test
+  public void testIsLikeRightMult() {
+    if (!function.isLikeRightMult()) {
+      return;
+    }
+    for (int i = 0; i < NUM_POINTS; ++i) {
+      double x = random.nextDouble();
+      assertEquals(functionName, 0, function.apply(x, 0), 0);
+    }
+  }
+
+  @Test
+  public void testIsCommutative() {
+    if (!function.isCommutative()) {
+      return;
+    }
+    for (int i = 0; i < NUM_POINTS; ++i) {
+      double x = random.nextDouble();
+      double y = random.nextDouble();
+      assertEquals(functionName, function.apply(x, y), function.apply(y, x), 
Constants.EPSILON);
+    }
+  }
+
+  @Test
+  public void testIsAssociative() {
+    if (!function.isAssociative()) {
+      return;
+    }
+    for (int i = 0; i < NUM_POINTS; ++i) {
+      double x = random.nextDouble();
+      double y = random.nextDouble();
+      double z = random.nextDouble();
+      assertEquals(functionName, function.apply(x, function.apply(y, z)), 
function.apply(function.apply(x, y), z),
+          Constants.EPSILON);
+    }
+  }
+
+  @Test
+  public void testIsDensifying() {
+    if (!function.isDensifying()) {
+      assertEquals(functionName, 0, function.apply(0, 0), 0);
+    }
+  }
+}


Reply via email to