Index: ml/src/main/java/org/apache/hama/ml/math/DenseDoubleMatrix.java =================================================================== --- ml/src/main/java/org/apache/hama/ml/math/DenseDoubleMatrix.java (revision 1493881) +++ ml/src/main/java/org/apache/hama/ml/math/DenseDoubleMatrix.java (working copy) @@ -778,4 +778,37 @@ return a.subtract(b).sum(); } + @Override + /** + * {@inheritDoc} + */ + public DoubleMatrix apply(DoubleFunction fun) { + for (int r = 0; r < this.numRows; ++r) { + for (int c = 0; c < this.numColumns; ++c) { + this.set(r, c, fun.calculate(this.get(r, c))); + } + } + return this; + } + + @Override + /** + * {@inheritDoc} + */ + public DoubleMatrix apply(DoubleMatrix other, DoubleDoubleFunction fun) { + if (this.numRows != other.getRowCount() + || this.numColumns != other.getColumnCount()) { + throw new IllegalArgumentException( + "Cannot apply double double function to matrices with different sizes."); + } + + for (int r = 0; r < this.numRows; ++r) { + for (int c = 0; c < this.numColumns; ++c) { + this.set(r, c, fun.calculate(this.get(r, c), other.get(r, c))); + } + } + + return this; + } + } Index: ml/src/main/java/org/apache/hama/ml/math/DenseDoubleVector.java =================================================================== --- ml/src/main/java/org/apache/hama/ml/math/DenseDoubleVector.java (revision 1493881) +++ ml/src/main/java/org/apache/hama/ml/math/DenseDoubleVector.java (working copy) @@ -100,11 +100,34 @@ vector[index] = value; } + /** + * {@inheritDoc} + */ + @Override + public DoubleVector apply(DoubleFunction func) { + for (int i = 0; i < vector.length; i++) { + this.vector[i] = func.calculate(vector[i]); + } + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public DoubleVector apply(DoubleVector other, DoubleDoubleFunction func) { + for (int i = 0; i < vector.length; i++) { + this.vector[i] = func.calculate(vector[i], other.get(i)); + } + return this; + } + /* * (non-Javadoc) * @see de.jungblut.math.DoubleVector#apply(de.jungblut.math.function. * DoubleVectorFunction) */ + @Deprecated @Override public DoubleVector apply(DoubleVectorFunction func) { DenseDoubleVector newV = new DenseDoubleVector(this.vector); @@ -119,6 +142,7 @@ * @see de.jungblut.math.DoubleVector#apply(de.jungblut.math.DoubleVector, * de.jungblut.math.function.DoubleDoubleVectorFunction) */ + @Deprecated @Override public DoubleVector apply(DoubleVector other, DoubleDoubleVectorFunction func) { DenseDoubleVector newV = (DenseDoubleVector) deepCopy(); Index: ml/src/main/java/org/apache/hama/ml/math/DoubleDoubleFunction.java =================================================================== --- ml/src/main/java/org/apache/hama/ml/math/DoubleDoubleFunction.java (revision 0) +++ ml/src/main/java/org/apache/hama/ml/math/DoubleDoubleFunction.java (working copy) @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hama.ml.math; + +/** + * A double double function takes two arguments. + * A vector or matrix can apply the double function to each element. + * + */ +public abstract class DoubleDoubleFunction { + + /** + * Apply the function to elements to two given arguments. + * @param x1 + * @param x2 + * @return The result based on the calculation on two arguments. + */ + public abstract double calculate(double x1, double x2); + + /** + * Apply the derivative of this function to two given arguments. + * @param x1 + * @param x2 + * @return The result based on the calculation on two arguments. + */ + public abstract double calculateDerivative(double x1, double x2); + +} Index: ml/src/main/java/org/apache/hama/ml/math/DoubleDoubleFunctions.java =================================================================== --- ml/src/main/java/org/apache/hama/ml/math/DoubleDoubleFunctions.java (revision 0) +++ ml/src/main/java/org/apache/hama/ml/math/DoubleDoubleFunctions.java (working copy) @@ -0,0 +1,83 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hama.ml.math; + +/** + * DoubleDoubleFunctions contains the commonly used DoubleDoubleFunction. + * + */ +public class DoubleDoubleFunctions { + + /** + * Square error cost function. + * + *
+   * cost(x1, x2) = 0.5 * (x1 - x2) ˆ 2
+   * 
+ */ + public final static DoubleDoubleFunction SQUARED_ERROR = new DoubleDoubleFunction() { + + @Override + public double calculate(double target, double actual) { + double diff = target - actual; + return 0.5 * diff * diff; + } + + @Override + public double calculateDerivative(double target, double actual) { + return target - actual; + } + + }; + + /** + * The cross entropy cost function. + * + *
+   * cost(t, y) = - t * log(y) - (1 - t) * log(1 - y),
+   * where t denotes the target value, y denotes the estimated value.
+   * 
+ */ + public final static DoubleDoubleFunction CROSS_ENTROPY = new DoubleDoubleFunction() { + + @Override + public double calculate(double target, double actual) { + return -target * Math.log(actual) - (1 - target) * Math.log(1 - actual); + } + + @Override + public double calculateDerivative(double target, double actual) { + double adjustedTarget = target; + double adjustedActual = actual; + if (adjustedActual == 1) { + adjustedActual = 0.999; + } else if (actual == 0) { + adjustedActual = 0.001; + } + if (adjustedTarget == 1) { + adjustedTarget = 0.999; + } else if (adjustedTarget == 0) { + adjustedTarget = 0.001; + } + return -adjustedTarget / adjustedActual + (1 - adjustedTarget) + / (1 - adjustedActual); + } + + }; + +} Index: ml/src/main/java/org/apache/hama/ml/math/DoubleDoubleVectorFunction.java =================================================================== --- ml/src/main/java/org/apache/hama/ml/math/DoubleDoubleVectorFunction.java (revision 1493881) +++ ml/src/main/java/org/apache/hama/ml/math/DoubleDoubleVectorFunction.java (working copy) @@ -20,7 +20,10 @@ /** * A function that can be applied to two double vectors via {@link DoubleVector} * #apply({@link DoubleVector} v, {@link DoubleDoubleVectorFunction} f); + * + * This class will be replaced by {@link DoubleDoubleFunction} */ +@Deprecated public interface DoubleDoubleVectorFunction { /** Index: ml/src/main/java/org/apache/hama/ml/math/DoubleFunction.java =================================================================== --- ml/src/main/java/org/apache/hama/ml/math/DoubleFunction.java (revision 0) +++ ml/src/main/java/org/apache/hama/ml/math/DoubleFunction.java (working copy) @@ -0,0 +1,41 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hama.ml.math; + +/** + * A double double function takes two arguments. + * A vector or matrix can apply the double function to each element. + * + */ +public abstract class DoubleFunction { + + /** + * Apply the function to element. + * @param elem The element that the function apply to. + * @return The result after applying the function. + */ + public abstract double calculate(double value); + + /** + * Apply the gradient of the function. + * @param elem + * @return + */ + public abstract double calculateDerivative(double value); + +} Index: ml/src/main/java/org/apache/hama/ml/math/DoubleFunctions.java =================================================================== --- ml/src/main/java/org/apache/hama/ml/math/DoubleFunctions.java (revision 0) +++ ml/src/main/java/org/apache/hama/ml/math/DoubleFunctions.java (working copy) @@ -0,0 +1,65 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hama.ml.math; + +/** + * DoubleFunctions contains the common used DoubleFunction + * + */ +public final class DoubleFunctions { + + /** + * Tanh function. + * + */ + public final static DoubleFunction TANH = new DoubleFunction() { + + @Override + public double calculate(double value) { + return Math.tanh(value); + } + + @Override + public double calculateDerivative(double value) { + return 1 - value * value; + } + + }; + + /** + * The Sigmoid function + * + *
+   * f(x) = 1 / (1 + e^{-x})
+   * 
+ */ + public final static DoubleFunction SIGMOID = new DoubleFunction() { + + @Override + public double calculate(double value) { + return 1.0 / (1 + Math.exp(-value)); + } + + @Override + public double calculateDerivative(double value) { + return value * (1 - value); + } + + }; + +} Index: ml/src/main/java/org/apache/hama/ml/math/DoubleMatrix.java =================================================================== --- ml/src/main/java/org/apache/hama/ml/math/DoubleMatrix.java (revision 1493881) +++ ml/src/main/java/org/apache/hama/ml/math/DoubleMatrix.java (working copy) @@ -184,4 +184,25 @@ */ public DoubleMatrix slice(int rowOffset, int rowMax, int colOffset, int colMax); + /** + * Apply a double function f(x) onto each element of the matrix. After + * applying, each element of the current matrix will be changed from x to + * f(x). + * + * @param fun The function. + * @return The matrix itself, supply for chain operation. + */ + public DoubleMatrix apply(DoubleFunction fun); + + /** + * Apply a double double function f(x, y) onto each pair of the current matrix + * elements and given matrix. After applying, each element of the current + * matrix will be changed from x to f(x, y). + * + * @param other The matrix contributing the second argument of the function. + * @param fun The function that takes two arguments. + * @return The matrix itself, supply for chain operation. + */ + public DoubleMatrix apply(DoubleMatrix other, DoubleDoubleFunction fun); + } Index: ml/src/main/java/org/apache/hama/ml/math/DoubleVector.java =================================================================== --- ml/src/main/java/org/apache/hama/ml/math/DoubleVector.java (revision 1493881) +++ ml/src/main/java/org/apache/hama/ml/math/DoubleVector.java (working copy) @@ -66,6 +66,7 @@ * @param func the function to apply. * @return a new vector with the applied function. */ + @Deprecated public DoubleVector apply(DoubleVectorFunction func); /** @@ -76,9 +77,29 @@ * @param func the function to apply on this and the other vector. * @return a new vector with the result of the function of the two vectors. */ + @Deprecated public DoubleVector apply(DoubleVector other, DoubleDoubleVectorFunction func); /** + * Apply a given {@link DoubleVectorFunction} to this vector and return a new + * one. + * + * @param func the function to apply. + * @return a new vector with the applied function. + */ + public DoubleVector apply(DoubleFunction func); + + /** + * Apply a given {@link DoubleDoubleVectorFunction} to this vector and the + * other given vector. + * + * @param other the other vector. + * @param func the function to apply on this and the other vector. + * @return a new vector with the result of the function of the two vectors. + */ + public DoubleVector apply(DoubleVector other, DoubleDoubleFunction func); + + /** * Adds the given {@link DoubleVector} to this vector. * * @param v the other vector. Index: ml/src/main/java/org/apache/hama/ml/math/DoubleVectorFunction.java =================================================================== --- ml/src/main/java/org/apache/hama/ml/math/DoubleVectorFunction.java (revision 1493881) +++ ml/src/main/java/org/apache/hama/ml/math/DoubleVectorFunction.java (working copy) @@ -20,7 +20,10 @@ /** * A function that can be applied to a double vector via {@link DoubleVector} * #apply({@link DoubleVectorFunction} f); + * + * This class will be replaced by {@link DoubleFunction} */ +@Deprecated public interface DoubleVectorFunction { /** Index: ml/src/main/java/org/apache/hama/ml/perception/Sigmoid.java =================================================================== --- ml/src/main/java/org/apache/hama/ml/perception/Sigmoid.java (revision 1493881) +++ ml/src/main/java/org/apache/hama/ml/perception/Sigmoid.java (working copy) @@ -27,7 +27,7 @@ public class Sigmoid extends SquashingFunction { @Override - public double calculate(int index, double value) { + public double calculate(double value) { return 1.0 / (1 + Math.exp(-value)); } Index: ml/src/main/java/org/apache/hama/ml/perception/SmallMultiLayerPerceptron.java =================================================================== --- ml/src/main/java/org/apache/hama/ml/perception/SmallMultiLayerPerceptron.java (revision 1493881) +++ ml/src/main/java/org/apache/hama/ml/perception/SmallMultiLayerPerceptron.java (working copy) @@ -199,8 +199,8 @@ prevNeuronIdx, neuronIdx) * intermediateResult[prevNeuronIdx]; } // calculate via squashing function - results[neuronIdx + offset] = this.squashingFunction.calculate(0, - results[neuronIdx + offset]); + results[neuronIdx + offset] = this.squashingFunction + .calculate(results[neuronIdx + offset]); } return results; Index: ml/src/main/java/org/apache/hama/ml/perception/SquashingFunction.java =================================================================== --- ml/src/main/java/org/apache/hama/ml/perception/SquashingFunction.java (revision 1493881) +++ ml/src/main/java/org/apache/hama/ml/perception/SquashingFunction.java (working copy) @@ -17,19 +17,19 @@ */ package org.apache.hama.ml.perception; -import org.apache.hama.ml.math.DoubleVectorFunction; +import org.apache.hama.ml.math.DoubleFunction; /** * The squashing function to activate the neurons. * */ -public abstract class SquashingFunction implements DoubleVectorFunction { +public abstract class SquashingFunction extends DoubleFunction { /** * Calculates the result with a given index and value of a vector. */ @Override - public abstract double calculate(int index, double value); + public abstract double calculate(double value); /** * Apply the gradient descent to each of the elements in vector. Index: ml/src/main/java/org/apache/hama/ml/perception/Tanh.java =================================================================== --- ml/src/main/java/org/apache/hama/ml/perception/Tanh.java (revision 1493881) +++ ml/src/main/java/org/apache/hama/ml/perception/Tanh.java (working copy) @@ -20,11 +20,12 @@ /** * The hyperbolic tangent function. It is used as a squashing function in * multi-layer perceptron. + * */ public class Tanh extends SquashingFunction { @Override - public double calculate(int index, double value) { + public double calculate(double value) { return Math.tanh(value); } Index: ml/src/test/java/org/apache/hama/ml/math/TestDenseDoubleMatrix.java =================================================================== --- ml/src/test/java/org/apache/hama/ml/math/TestDenseDoubleMatrix.java (revision 0) +++ ml/src/test/java/org/apache/hama/ml/math/TestDenseDoubleMatrix.java (working copy) @@ -0,0 +1,88 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hama.ml.math; + +import static org.junit.Assert.assertArrayEquals; + +import org.junit.Test; + +/** + * Test case for {@link DenseDoubleMatrix} + * + */ +public class TestDenseDoubleMatrix { + + @Test + public void testDoubleFunction() { + double[][] values = new double[][] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; + + double[][] result = new double[][] { { 2, 3, 4 }, { 5, 6, 7 }, { 8, 9, 10 } }; + + DenseDoubleMatrix mat = new DenseDoubleMatrix(values); + mat.apply(new DoubleFunction() { + + @Override + public double calculate(double value) { + return value + 1; + } + + @Override + public double calculateDerivative(double value) { + throw new UnsupportedOperationException(); + } + + }); + + double[][] actual = mat.getValues(); + for (int i = 0; i < actual.length; ++i) { + assertArrayEquals(result[i], actual[i], 0.0001); + } + } + + @Test + public void testDoubleDoubleFunction() { + double[][] values1 = new double[][] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; + double[][] values2 = new double[][] { { 2, 3, 4 }, { 5, 6, 7 }, + { 8, 9, 10 } }; + double[][] result = new double[][] { { 3, 5, 7 }, { 9, 11, 13 }, + { 15, 17, 19 } }; + + DenseDoubleMatrix mat1 = new DenseDoubleMatrix(values1); + DenseDoubleMatrix mat2 = new DenseDoubleMatrix(values2); + + mat1.apply(mat2, new DoubleDoubleFunction() { + + @Override + public double calculate(double x1, double x2) { + return x1 + x2; + } + + @Override + public double calculateDerivative(double x1, double x2) { + throw new UnsupportedOperationException(); + } + + }); + + double[][] actual = mat1.getValues(); + for (int i = 0; i < actual.length; ++i) { + assertArrayEquals(result[i], actual[i], 0.0001); + } + } + +} Index: ml/src/test/java/org/apache/hama/ml/math/TestDenseDoubleVector.java =================================================================== --- ml/src/test/java/org/apache/hama/ml/math/TestDenseDoubleVector.java (revision 0) +++ ml/src/test/java/org/apache/hama/ml/math/TestDenseDoubleVector.java (working copy) @@ -0,0 +1,80 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hama.ml.math; + +import static org.junit.Assert.assertArrayEquals; + +import org.junit.Test; + +/** + * Testcase for {@link DenseDoubleVector} + * + */ +public class TestDenseDoubleVector { + + @Test + public void testApplyDoubleFunction() { + double[] values = new double[] { 1, 2, 3, 4, 5 }; + double[] result = new double[] { 2, 3, 4, 5, 6 }; + + DoubleVector vec1 = new DenseDoubleVector(values); + + vec1.apply(new DoubleFunction() { + + @Override + public double calculate(double value) { + return value + 1; + } + + @Override + public double calculateDerivative(double value) { + throw new UnsupportedOperationException("Not supported."); + } + + }); + + assertArrayEquals(result, vec1.toArray(), 0.0001); + } + + @Test + public void testApplyDoubleDoubleFunction() { + double[] values1 = new double[] { 1, 2, 3, 4, 5, 6 }; + double[] values2 = new double[] { 7, 8, 9, 10, 11, 12 }; + double[] result = new double[] { 8, 10, 12, 14, 16, 18 }; + + DoubleVector vec1 = new DenseDoubleVector(values1); + DoubleVector vec2 = new DenseDoubleVector(values2); + + vec1.apply(vec2, new DoubleDoubleFunction() { + + @Override + public double calculate(double x1, double x2) { + return x1 + x2; + } + + @Override + public double calculateDerivative(double x1, double x2) { + throw new UnsupportedOperationException("Not supported"); + } + + }); + + assertArrayEquals(result, vec1.toArray(), 0.0001); + + } +}