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);
+ }
+ }
+}