Skip to content
Browse files

MATH-1151

New interface "ValueAndJacobianFunction" (to allow separate evaluation
of either quantity) is a precondition for lazy evaluation (and is enforced
by raising an exception early rather than wait for a failed cast).


git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@1625967 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information...
1 parent 30b9f93 commit e9464c0a6db34576fa390d041e702b1f03c74b37 Gilles Sadowski committed Sep 18, 2014
View
4 src/changes/changes.xml
@@ -73,6 +73,10 @@ Users are encouraged to upgrade to this version as this release not
2. A few methods in the FastMath class are in fact slower that their
counterpart in either Math or StrictMath (cf. MATH-740 and MATH-901).
">
+ <action dev="erans" type="fix" issue="MATH-1151">
+ Interface "ValueAndJacobianFunction" is a precondition for lazy
+ evaluation (in "o.a.c.m.fitting.leastsquares").
+ </action>
<action dev="tn" type="fix" issue="MATH-1145" due-to="Anders Conbere">
Fix potential integer overflows in "MannWhitneyUTest" when providing
large sample arrays.
View
1 src/main/java/org/apache/commons/math3/exception/util/LocalizedFormats.java
@@ -143,6 +143,7 @@
INVALID_BINARY_CHROMOSOME("binary mutation works on BinaryChromosome only"),
INVALID_BRACKETING_PARAMETERS("invalid bracketing parameters: lower bound={0}, initial={1}, upper bound={2}"),
INVALID_FIXED_LENGTH_CHROMOSOME("one-point crossover only works with fixed-length chromosomes"),
+ INVALID_IMPLEMENTATION("required functionality is missing in {0}"),
INVALID_INTERVAL_INITIAL_VALUE_PARAMETERS("invalid interval, initial value parameters: lower={0}, initial={1}, upper={2}"),
INVALID_ITERATIONS_LIMITS("invalid iteration limits: min={0}, max={1}"),
INVALID_MAX_ITERATIONS("bad value for maximum iterations number: {0}"),
View
47 src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresFactory.java
@@ -16,6 +16,8 @@
*/
package org.apache.commons.math3.fitting.leastsquares;
+import org.apache.commons.math3.exception.MathIllegalStateException;
+import org.apache.commons.math3.exception.util.LocalizedFormats;
import org.apache.commons.math3.analysis.MultivariateMatrixFunction;
import org.apache.commons.math3.analysis.MultivariateVectorFunction;
import org.apache.commons.math3.fitting.leastsquares.LeastSquaresProblem.Evaluation;
@@ -275,9 +277,9 @@ private static RealMatrix squareRoot(final RealMatrix m) {
* @param jacobian the Jacobian function
* @return a function that computes both at the same time
*/
- public static MultivariateJacobianFunction model(final MultivariateVectorFunction value,
- final MultivariateMatrixFunction jacobian) {
- return new LocalMultivariateJacobianFunction(value, jacobian);
+ public static ValueAndJacobianFunction model(final MultivariateVectorFunction value,
+ final MultivariateMatrixFunction jacobian) {
+ return new LocalValueAndJacobianFunction(value, jacobian);
}
/**
@@ -288,20 +290,19 @@ public static MultivariateJacobianFunction model(final MultivariateVectorFunctio
* @param jacobian the Jacobian function
* @return a function that computes both at the same time
*/
- private static class LocalMultivariateJacobianFunction
- implements MultivariateJacobianFunction {
+ private static class LocalValueAndJacobianFunction
+ implements ValueAndJacobianFunction {
/** Model. */
private final MultivariateVectorFunction value;
/** Model's Jacobian. */
private final MultivariateMatrixFunction jacobian;
-
/**
* @param value Model function.
* @param jacobian Model's Jacobian function.
*/
- LocalMultivariateJacobianFunction(final MultivariateVectorFunction value,
- final MultivariateMatrixFunction jacobian) {
+ LocalValueAndJacobianFunction(final MultivariateVectorFunction value,
+ final MultivariateMatrixFunction jacobian) {
this.value = value;
this.jacobian = jacobian;
}
@@ -316,22 +317,12 @@ public static MultivariateJacobianFunction model(final MultivariateVectorFunctio
computeJacobian(p));
}
- /**
- * Compute the value.
- *
- * @param params Point.
- * @return the Jacobian at the given point.
- */
+ /** {@inheritDoc} */
public RealVector computeValue(final double[] params) {
return new ArrayRealVector(value.value(params), false);
}
- /**
- * Compute the Jacobian.
- *
- * @param params Point.
- * @return the Jacobian at the given point.
- */
+ /** {@inheritDoc} */
public RealMatrix computeJacobian(final double[] params) {
return new Array2DRowRealMatrix(jacobian.value(params), false);
}
@@ -380,6 +371,14 @@ public RealMatrix computeJacobian(final double[] params) {
this.model = model;
this.start = start;
this.lazyEvaluation = lazyEvaluation;
+
+ if (lazyEvaluation &&
+ !(model instanceof ValueAndJacobianFunction)) {
+ // Lazy evaluation requires that value and Jacobian
+ // can be computed separately.
+ throw new MathIllegalStateException(LocalizedFormats.INVALID_IMPLEMENTATION,
+ model.getClass().getName());
+ }
}
/** {@inheritDoc} */
@@ -403,7 +402,7 @@ public Evaluation evaluate(final RealVector point) {
final RealVector p = point.copy();
if (lazyEvaluation) {
- return new LazyUnweightedEvaluation(model,
+ return new LazyUnweightedEvaluation((ValueAndJacobianFunction) model,
target,
p);
} else {
@@ -468,7 +467,7 @@ public RealVector getResiduals() {
/** Point of evaluation. */
private final RealVector point;
/** Model and Jacobian functions. */
- private final LocalMultivariateJacobianFunction model;
+ private final ValueAndJacobianFunction model;
/** Target values for the model function at optimum. */
private final RealVector target;
@@ -479,12 +478,12 @@ public RealVector getResiduals() {
* @param target the observed values
* @param point the abscissa
*/
- private LazyUnweightedEvaluation(final MultivariateJacobianFunction model,
+ private LazyUnweightedEvaluation(final ValueAndJacobianFunction model,
final RealVector target,
final RealVector point) {
super(target.getDimension());
// Safe to cast as long as we control usage of this class.
- this.model = (LocalMultivariateJacobianFunction) model;
+ this.model = model;
this.point = point;
this.target = target;
}
View
45 src/main/java/org/apache/commons/math3/fitting/leastsquares/ValueAndJacobianFunction.java
@@ -0,0 +1,45 @@
+/*
+ * 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.commons.math3.fitting.leastsquares;
+
+import org.apache.commons.math3.linear.RealMatrix;
+import org.apache.commons.math3.linear.RealVector;
+
+/**
+ * A interface for functions that compute a vector of values and can compute their
+ * derivatives (Jacobian).
+ *
+ * @version $Id$
+ * @since 3.3
+ */
+public interface ValueAndJacobianFunction extends MultivariateJacobianFunction {
+ /**
+ * Compute the value.
+ *
+ * @param params Point.
+ * @return the value at the given point.
+ */
+ RealVector computeValue(final double[] params);
+
+ /**
+ * Compute the Jacobian.
+ *
+ * @param params Point.
+ * @return the Jacobian at the given point.
+ */
+ RealMatrix computeJacobian(final double[] params);
+}
View
1 ...n/resources/assets/org/apache/commons/math3/exception/util/LocalizedFormats_fr.properties
@@ -114,6 +114,7 @@ INVALID_BINARY_DIGIT = chiffre binaire invalide : {0}
INVALID_BINARY_CHROMOSOME = la mutation binaire ne fonctionne qu''avec BinaryChromosome
INVALID_BRACKETING_PARAMETERS = param\u00e8tres d''encadrement invalides : borne inf\u00e9rieure = {0}, valeur initiale = {1}, borne sup\u00e9rieure = {2}
INVALID_FIXED_LENGTH_CHROMOSOME = le m\u00e9lange \u00e0 un point ne fonctionne qu''avec les chromosomes \u00e0 taille fixe
+INVALID_IMPLEMENTATION = une fonctionnalit\u00e9 requise est manquante dans {0}
INVALID_INTERVAL_INITIAL_VALUE_PARAMETERS = param\u00e8tres de l''intervalle initial invalides : borne inf = {0}, valeur initiale = {1}, borne sup = {2}
INVALID_ITERATIONS_LIMITS = limites d''it\u00e9rations invalides : min = {0}, max = {1}
INVALID_MAX_ITERATIONS = valeur invalide pour le nombre maximal d''it\u00e9rations : {0}
View
2 src/test/java/org/apache/commons/math3/exception/util/LocalizedFormatsTest.java
@@ -30,7 +30,7 @@
@Test
public void testMessageNumber() {
- Assert.assertEquals(318, LocalizedFormats.values().length);
+ Assert.assertEquals(319, LocalizedFormats.values().length);
}
@Test
View
40 src/test/java/org/apache/commons/math3/fitting/leastsquares/EvaluationTest.java
@@ -13,6 +13,7 @@
*/
package org.apache.commons.math3.fitting.leastsquares;
+import org.apache.commons.math3.exception.MathIllegalStateException;
import org.apache.commons.math3.TestUtils;
import org.apache.commons.math3.analysis.MultivariateMatrixFunction;
import org.apache.commons.math3.analysis.MultivariateVectorFunction;
@@ -247,6 +248,43 @@ public void testLazyEvaluation() {
}
}
+ // MATH-1151
+ @Test
+ public void testLazyEvaluationPrecondition() {
+ final RealVector dummy = new ArrayRealVector(new double[] { 0 });
+
+ // "ValueAndJacobianFunction" is required but we implement only
+ // "MultivariateJacobianFunction".
+ final MultivariateJacobianFunction m1 = new MultivariateJacobianFunction() {
+ public Pair<RealVector, RealMatrix> value(RealVector notUsed) {
+ return new Pair<RealVector, RealMatrix>(null, null);
+ }
+ };
+
+ try {
+ // Should throw.
+ LeastSquaresFactory.create(m1, dummy, dummy, null, 0, 0, true);
+ Assert.fail("Expecting MathIllegalStateException");
+ } catch (MathIllegalStateException e) {
+ // Expected.
+ }
+
+ final MultivariateJacobianFunction m2 = new ValueAndJacobianFunction() {
+ public Pair<RealVector, RealMatrix> value(RealVector notUsed) {
+ return new Pair<RealVector, RealMatrix>(null, null);
+ }
+ public RealVector computeValue(final double[] params) {
+ return null;
+ }
+ public RealMatrix computeJacobian(final double[] params) {
+ return null;
+ }
+ };
+
+ // Should pass.
+ LeastSquaresFactory.create(m2, dummy, dummy, null, 0, 0, true);
+ }
+
@Test
public void testDirectEvaluation() {
final RealVector dummy = new ArrayRealVector(new double[] { 0 });
@@ -261,7 +299,7 @@ public void testDirectEvaluation() {
Assert.fail("Exception expected");
} catch (RuntimeException e) {
// Expecting exception.
- // Whether it is model of Jacobian that caused it is not significant.
+ // Whether it is model or Jacobian that caused it is not significant.
final String msg = e.getMessage();
Assert.assertTrue(msg.equals("dummyModel") ||
msg.equals("dummyJacobian"));

0 comments on commit e9464c0

Please sign in to comment.
Something went wrong with that request. Please try again.