You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by er...@apache.org on 2013/07/30 17:04:23 UTC
svn commit: r1508481 [2/5] - in /commons/proper/math/trunk/src:
main/java/org/apache/commons/math3/fitting/leastsquares/
main/java/org/apache/commons/math3/optim/
test/java/org/apache/commons/math3/fitting/leastsquares/
test/resources/org/apache/common...
Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithConvergenceChecker.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithConvergenceChecker.java?rev=1508481&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithConvergenceChecker.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithConvergenceChecker.java Tue Jul 30 15:04:22 2013
@@ -0,0 +1,39 @@
+/*
+ * 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.optim.ConvergenceChecker;
+import org.apache.commons.math3.optim.PointVectorValuePair;
+
+/**
+ * Interface for "fluent-API" that advertizes a capability of the optimizer.
+ *
+ * @param <T> Concrete optimizer implementation.
+ *
+ * @version $Id$
+ * @since 3.3
+ */
+public interface WithConvergenceChecker<T> {
+ /**
+ * Creates a new instance with the specified parameter.
+ *
+ * @param checker Convergence checker.
+ * @return a new optimizer instance with all fields identical to this
+ * instance except for the given argument.
+ */
+ T withConvergenceChecker(ConvergenceChecker<PointVectorValuePair> checker);
+}
Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithConvergenceChecker.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithConvergenceChecker.java
------------------------------------------------------------------------------
svn:keywords = Id Revision
Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithMaxEvaluations.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithMaxEvaluations.java?rev=1508481&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithMaxEvaluations.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithMaxEvaluations.java Tue Jul 30 15:04:22 2013
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+/**
+ * Interface for "fluent-API" that advertizes a capability of the optimizer.
+ *
+ * @param <T> Concrete optimizer implementation.
+ *
+ * @version $Id$
+ * @since 3.3
+ */
+public interface WithMaxEvaluations<T> {
+ /**
+ * Creates a new instance with the specified parameter.
+ *
+ * @param maxEval Maximum number of evaluations of the model function.
+ * @return a new optimizer instance with all fields identical to this
+ * instance except for the given argument.
+ */
+ T withMaxEvaluations(int maxEval);
+}
Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithMaxEvaluations.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithMaxEvaluations.java
------------------------------------------------------------------------------
svn:keywords = Id Revision
Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithMaxIterations.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithMaxIterations.java?rev=1508481&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithMaxIterations.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithMaxIterations.java Tue Jul 30 15:04:22 2013
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+/**
+ * Interface for "fluent-API" that advertizes a capability of the optimizer.
+ *
+ * @param <T> Concrete optimizer implementation.
+ *
+ * @version $Id$
+ * @since 3.3
+ */
+public interface WithMaxIterations<T> {
+ /**
+ * Creates a new instance with the specified parameter.
+ *
+ * @param maxIter Maximum number of iterations.
+ * @return a new optimizer instance with all fields identical to this
+ * instance except for the given argument.
+ */
+ T withMaxIterations(int maxIter);
+}
Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithMaxIterations.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithMaxIterations.java
------------------------------------------------------------------------------
svn:keywords = Id Revision
Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithModelAndJacobian.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithModelAndJacobian.java?rev=1508481&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithModelAndJacobian.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithModelAndJacobian.java Tue Jul 30 15:04:22 2013
@@ -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.commons.math3.fitting.leastsquares;
+
+import org.apache.commons.math3.analysis.MultivariateVectorFunction;
+import org.apache.commons.math3.analysis.MultivariateMatrixFunction;
+
+/**
+ * Interface for "fluent-API" that advertizes a capability of the optimizer.
+ *
+ * @param <T> Concrete optimizer implementation.
+ *
+ * @version $Id$
+ * @since 3.3
+ */
+public interface WithModelAndJacobian<T> {
+ /**
+ * Creates a new instance with the specified parameters.
+ *
+ * @param model ModelFunction.
+ * @param jacobian Jacobian of the model function.
+ * @return a new optimizer instance with all fields identical to this
+ * instance except for the given arguments.
+ */
+ T withModelAndJacobian(MultivariateVectorFunction model,
+ MultivariateMatrixFunction jacobian);
+}
Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithModelAndJacobian.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithModelAndJacobian.java
------------------------------------------------------------------------------
svn:keywords = Id Revision
Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithStartPoint.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithStartPoint.java?rev=1508481&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithStartPoint.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithStartPoint.java Tue Jul 30 15:04:22 2013
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+/**
+ * Interface for "fluent-API" that advertizes a capability of the optimizer.
+ *
+ * @param <T> Concrete optimizer implementation.
+ *
+ * @version $Id$
+ * @since 3.3
+ */
+public interface WithStartPoint<T> {
+ /**
+ * Creates a new instance with the specified parameter.
+ *
+ * @param start Initial guess for the parameters of the model function.
+ * @return a new optimizer instance with all fields identical to this
+ * instance except for the given argument.
+ */
+ T withStartPoint(double[] start);
+}
Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithStartPoint.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithStartPoint.java
------------------------------------------------------------------------------
svn:keywords = Id Revision
Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithTarget.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithTarget.java?rev=1508481&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithTarget.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithTarget.java Tue Jul 30 15:04:22 2013
@@ -0,0 +1,36 @@
+/*
+ * 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;
+
+/**
+ * Interface for "fluent-API" that advertizes a capability of the optimizer.
+ *
+ * @param <T> Concrete optimizer implementation.
+ *
+ * @version $Id$
+ * @since 3.3
+ */
+public interface WithTarget<T> {
+ /**
+ * Creates a new instance with the specified parameter.
+ *
+ * @param target Objective points of the model function.
+ * @return a new optimizer instance with all fields identical to this
+ * instance except for the given argument.
+ */
+ T withTarget(double[] target);
+}
Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithTarget.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithTarget.java
------------------------------------------------------------------------------
svn:keywords = Id Revision
Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithWeight.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithWeight.java?rev=1508481&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithWeight.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithWeight.java Tue Jul 30 15:04:22 2013
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+/**
+ * Interface for "fluent-API" that advertizes a capability of the optimizer.
+ *
+ * @param <T> Concrete optimizer implementation.
+ *
+ * @version $Id$
+ * @since 3.3
+ */
+public interface WithWeight<T> {
+ /**
+ * Creates a new instance with the specified parameter.
+ *
+ * @param weight Weight matrix of the observations.
+ * @return a new optimizer instance with all fields identical to this
+ * instance except for the given argument.
+ */
+ T withWeight(RealMatrix weight);
+}
Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithWeight.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/WithWeight.java
------------------------------------------------------------------------------
svn:keywords = Id Revision
Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/package-info.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/package-info.java?rev=1508481&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/package-info.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/package-info.java Tue Jul 30 15:04:22 2013
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+/**
+ * This package provides algorithms that minimize the residuals
+ * between observations and model values.
+ * The {@link org.apache.commons.math3.fitting.leastsquares.AbstractLeastSquaresOptimizer
+ * non-linear least-squares optimizers} minimize the distance (called <em>cost</em> or
+ * <em>χ<sup>2</sup></em>) between model and observations.
+ *
+ * <br/>
+ * Algorithms in this category need access to a <em>model function</em>
+ * (represented by a {@link org.apache.commons.math3.analysis.MultivariateVectorFunction
+ * MultivariateVectorFunction}).
+ * Such a model predicts a set of values which the algorithm tries to match with a set
+ * of given set of {@link WithTarget observed values}.
+ * <br/>
+ * The algorithms implemented in this package also require that the user specifies the
+ * Jacobian matrix of the model (represented by a
+ * {@link org.apache.commons.math3.analysis.MultivariateMatrixFunction
+ * MultivariateMatrixFunction}).
+ */
+package org.apache.commons.math3.fitting.leastsquares;
Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/package-info.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/package-info.java
------------------------------------------------------------------------------
svn:keywords = Id Revision
Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optim/BaseOptimizer.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optim/BaseOptimizer.java?rev=1508481&r1=1508480&r2=1508481&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optim/BaseOptimizer.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optim/BaseOptimizer.java Tue Jul 30 15:04:22 2013
@@ -45,10 +45,21 @@ public abstract class BaseOptimizer<PAIR
* @param checker Convergence checker.
*/
protected BaseOptimizer(ConvergenceChecker<PAIR> checker) {
+ this(checker, 0, Integer.MAX_VALUE);
+ }
+
+ /**
+ * @param checker Convergence checker.
+ * @param maxEval Maximum number of objective function evaluations.
+ * @param maxIter Maximum number of algorithm iterations.
+ */
+ protected BaseOptimizer(ConvergenceChecker<PAIR> checker,
+ int maxEval,
+ int maxIter) {
this.checker = checker;
- evaluations = new Incrementor(0, new MaxEvalCallback());
- iterations = new Incrementor(Integer.MAX_VALUE, new MaxIterCallback());
+ evaluations = new Incrementor(maxEval, new MaxEvalCallback());
+ iterations = new Incrementor(maxIter, new MaxIterCallback());
}
/**
@@ -144,6 +155,25 @@ public abstract class BaseOptimizer<PAIR
}
/**
+ * Performs the optimization.
+ *
+ * @return a point/value pair that satifies the convergence criteria.
+ * @throws TooManyEvaluationsException if the maximal number of
+ * evaluations is exceeded.
+ * @throws TooManyIterationsException if the maximal number of
+ * iterations is exceeded.
+ */
+ public PAIR optimize()
+ throws TooManyEvaluationsException,
+ TooManyIterationsException {
+ // Reset counters.
+ evaluations.resetCount();
+ iterations.resetCount();
+ // Perform optimization.
+ return doOptimize();
+ }
+
+ /**
* Performs the bulk of the optimization algorithm.
*
* @return the point/value pair giving the optimal value of the
Added: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerAbstractTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerAbstractTest.java?rev=1508481&view=auto
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerAbstractTest.java (added)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerAbstractTest.java Tue Jul 30 15:04:22 2013
@@ -0,0 +1,643 @@
+/*
+ * 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 java.io.IOException;
+import java.io.Serializable;
+import java.util.Arrays;
+import org.apache.commons.math3.analysis.MultivariateVectorFunction;
+import org.apache.commons.math3.analysis.MultivariateMatrixFunction;
+import org.apache.commons.math3.exception.ConvergenceException;
+import org.apache.commons.math3.exception.DimensionMismatchException;
+import org.apache.commons.math3.exception.NumberIsTooSmallException;
+import org.apache.commons.math3.geometry.euclidean.twod.Vector2D;
+import org.apache.commons.math3.linear.BlockRealMatrix;
+import org.apache.commons.math3.linear.RealMatrix;
+import org.apache.commons.math3.linear.DiagonalMatrix;
+import org.apache.commons.math3.optim.PointVectorValuePair;
+import org.apache.commons.math3.util.FastMath;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Some of the unit tests are re-implementations of the MINPACK
+ * <a href="http://www.netlib.org/minpack/ex/file17">file17</a> and
+ * <a href="http://www.netlib.org/minpack/ex/file22">file22</a> test files.
+ * The redistribution policy for MINPACK is available
+ * <a href="http://www.netlib.org/minpack/disclaimer">here</a>.
+ *
+ * <T> Concrete implementation of an optimizer.
+ *
+ * @version $Id$
+ */
+public abstract class AbstractLeastSquaresOptimizerAbstractTest<T extends AbstractLeastSquaresOptimizer &
+ WithTarget<T> &
+ WithWeight<T> &
+ WithModelAndJacobian<T> &
+ WithConvergenceChecker<T> &
+ WithStartPoint<T> &
+ WithMaxIterations<T> &
+ WithMaxEvaluations<T>> {
+ /**
+ * @return a concrete optimizer.
+ */
+ public abstract T createOptimizer();
+
+ /**
+ * @return the default number of allowed iterations (which will be
+ * used when not specified otherwise).
+ */
+ public abstract int getMaxIterations();
+
+ @Test
+ public void testGetIterations() {
+ T optim = createOptimizer()
+ .withMaxEvaluations(100)
+ .withMaxIterations(getMaxIterations())
+ .withTarget(new double[] { 1 })
+ .withWeight(new DiagonalMatrix(new double[] { 1 }))
+ .withStartPoint(new double[] { 3 })
+ .withModelAndJacobian(new MultivariateVectorFunction() {
+ public double[] value(double[] point) {
+ return new double[] {
+ FastMath.pow(point[0], 4)
+ };
+ }},
+ new MultivariateMatrixFunction() {
+ public double[][] value(double[] point) {
+ return new double[][] {
+ { 0.25 * FastMath.pow(point[0], 3) }
+ };
+ }
+ });
+
+ optim.optimize();
+ Assert.assertTrue(optim.getIterations() > 0);
+ }
+
+ @Test
+ public void testTrivial() {
+ LinearProblem problem
+ = new LinearProblem(new double[][] { { 2 } },
+ new double[] { 3 });
+ T optimizer = createOptimizer()
+ .withMaxEvaluations(100)
+ .withMaxIterations(getMaxIterations())
+ .withModelAndJacobian(problem.getModelFunction(),
+ problem.getModelFunctionJacobian())
+ .withTarget(problem.getTarget())
+ .withWeight(new DiagonalMatrix(new double[] { 1 }))
+ .withStartPoint(new double[] { 0 });
+
+ PointVectorValuePair optimum = optimizer.optimize();
+
+ Assert.assertEquals(0, optimizer.computeRMS(optimum.getPoint()), 1e-10);
+ Assert.assertEquals(1.5, optimum.getPoint()[0], 1e-10);
+ Assert.assertEquals(3.0, optimum.getValue()[0], 1e-10);
+ }
+
+ @Test
+ public void testQRColumnsPermutation() {
+ LinearProblem problem
+ = new LinearProblem(new double[][] { { 1, -1 }, { 0, 2 }, { 1, -2 } },
+ new double[] { 4, 6, 1 });
+
+ T optimizer = createOptimizer()
+ .withMaxEvaluations(100)
+ .withMaxIterations(getMaxIterations())
+ .withModelAndJacobian(problem.getModelFunction(),
+ problem.getModelFunctionJacobian())
+ .withTarget(problem.getTarget())
+ .withWeight(new DiagonalMatrix(new double[] { 1, 1, 1 }))
+ .withStartPoint(new double[] { 0, 0 });
+
+ PointVectorValuePair optimum = optimizer.optimize();
+
+ Assert.assertEquals(0, optimizer.computeRMS(optimum.getPoint()), 1e-10);
+ Assert.assertEquals(7, optimum.getPoint()[0], 1e-10);
+ Assert.assertEquals(3, optimum.getPoint()[1], 1e-10);
+ Assert.assertEquals(4, optimum.getValue()[0], 1e-10);
+ Assert.assertEquals(6, optimum.getValue()[1], 1e-10);
+ Assert.assertEquals(1, optimum.getValue()[2], 1e-10);
+ }
+
+ @Test
+ public void testNoDependency() {
+ LinearProblem problem = new LinearProblem(new double[][] {
+ { 2, 0, 0, 0, 0, 0 },
+ { 0, 2, 0, 0, 0, 0 },
+ { 0, 0, 2, 0, 0, 0 },
+ { 0, 0, 0, 2, 0, 0 },
+ { 0, 0, 0, 0, 2, 0 },
+ { 0, 0, 0, 0, 0, 2 }
+ }, new double[] { 0, 1.1, 2.2, 3.3, 4.4, 5.5 });
+ T optimizer = createOptimizer()
+ .withMaxEvaluations(100)
+ .withMaxIterations(getMaxIterations())
+ .withModelAndJacobian(problem.getModelFunction(),
+ problem.getModelFunctionJacobian())
+ .withTarget(problem.getTarget())
+ .withWeight(new DiagonalMatrix(new double[] { 1, 1, 1, 1, 1, 1 }))
+ .withStartPoint(new double[] { 0, 0, 0, 0, 0, 0 });
+
+ double[] optimum = optimizer.optimize().getPoint();
+ Assert.assertEquals(0, optimizer.computeRMS(optimum), 1e-10);
+ for (int i = 0; i < problem.target.length; ++i) {
+ Assert.assertEquals(0.55 * i, optimum[i], 1e-10);
+ }
+ }
+
+ @Test
+ public void testOneSet() {
+ LinearProblem problem = new LinearProblem(new double[][] {
+ { 1, 0, 0 },
+ { -1, 1, 0 },
+ { 0, -1, 1 }
+ }, new double[] { 1, 1, 1});
+
+ T optimizer = createOptimizer()
+ .withMaxEvaluations(100)
+ .withMaxIterations(getMaxIterations())
+ .withModelAndJacobian(problem.getModelFunction(),
+ problem.getModelFunctionJacobian())
+ .withTarget(problem.getTarget())
+ .withWeight(new DiagonalMatrix(new double[] { 1, 1, 1 }))
+ .withStartPoint(new double[] { 0, 0, 0 });
+
+ double[] optimum = optimizer.optimize().getPoint();
+ Assert.assertEquals(0, optimizer.computeRMS(optimum), 1e-10);
+ Assert.assertEquals(1, optimum[0], 1e-10);
+ Assert.assertEquals(2, optimum[1], 1e-10);
+ Assert.assertEquals(3, optimum[2], 1e-10);
+ }
+
+ @Test
+ public void testTwoSets() {
+ double epsilon = 1e-7;
+ LinearProblem problem = new LinearProblem(new double[][] {
+ { 2, 1, 0, 4, 0, 0 },
+ { -4, -2, 3, -7, 0, 0 },
+ { 4, 1, -2, 8, 0, 0 },
+ { 0, -3, -12, -1, 0, 0 },
+ { 0, 0, 0, 0, epsilon, 1 },
+ { 0, 0, 0, 0, 1, 1 }
+ }, new double[] { 2, -9, 2, 2, 1 + epsilon * epsilon, 2});
+
+ T optimizer = createOptimizer()
+ .withMaxEvaluations(100)
+ .withMaxIterations(getMaxIterations())
+ .withModelAndJacobian(problem.getModelFunction(),
+ problem.getModelFunctionJacobian())
+ .withTarget(problem.getTarget())
+ .withWeight(new DiagonalMatrix(new double[] { 1, 1, 1, 1, 1, 1 }))
+ .withStartPoint(new double[] { 0, 0, 0, 0, 0, 0 });
+
+ double[] optimum = optimizer.optimize().getPoint();
+
+ Assert.assertEquals(0, optimizer.computeRMS(optimum), 1e-10);
+ Assert.assertEquals(3, optimum[0], 1e-10);
+ Assert.assertEquals(4, optimum[1], 1e-10);
+ Assert.assertEquals(-1, optimum[2], 1e-10);
+ Assert.assertEquals(-2, optimum[3], 1e-10);
+ Assert.assertEquals(1 + epsilon, optimum[4], 1e-10);
+ Assert.assertEquals(1 - epsilon, optimum[5], 1e-10);
+ }
+
+ @Test(expected=ConvergenceException.class)
+ public void testNonInvertible() throws Exception {
+ LinearProblem problem = new LinearProblem(new double[][] {
+ { 1, 2, -3 },
+ { 2, 1, 3 },
+ { -3, 0, -9 }
+ }, new double[] { 1, 1, 1 });
+
+ T optimizer = createOptimizer()
+ .withMaxEvaluations(100)
+ .withMaxIterations(getMaxIterations())
+ .withModelAndJacobian(problem.getModelFunction(),
+ problem.getModelFunctionJacobian())
+ .withTarget(problem.getTarget())
+ .withWeight(new DiagonalMatrix(new double[] { 1, 1, 1 }))
+ .withStartPoint(new double[] { 0, 0, 0 });
+
+ optimizer.optimize();
+ }
+
+ @Test
+ public void testIllConditioned() {
+ LinearProblem problem1 = new LinearProblem(new double[][] {
+ { 10, 7, 8, 7 },
+ { 7, 5, 6, 5 },
+ { 8, 6, 10, 9 },
+ { 7, 5, 9, 10 }
+ }, new double[] { 32, 23, 33, 31 });
+ T optimizer = createOptimizer()
+ .withMaxEvaluations(100)
+ .withMaxIterations(getMaxIterations())
+ .withModelAndJacobian(problem1.getModelFunction(),
+ problem1.getModelFunctionJacobian())
+ .withTarget(problem1.getTarget())
+ .withWeight(new DiagonalMatrix(new double[] { 1, 1, 1, 1 }))
+ .withStartPoint(new double[] { 0, 1, 2, 3 });
+
+ double[] optimum = optimizer.optimize().getPoint();
+
+ Assert.assertEquals(0, optimizer.computeRMS(optimum), 1e-10);
+ Assert.assertEquals(1, optimum[0], 1e-10);
+ Assert.assertEquals(1, optimum[1], 1e-10);
+ Assert.assertEquals(1, optimum[2], 1e-10);
+ Assert.assertEquals(1, optimum[3], 1e-10);
+
+ LinearProblem problem2 = new LinearProblem(new double[][] {
+ { 10.00, 7.00, 8.10, 7.20 },
+ { 7.08, 5.04, 6.00, 5.00 },
+ { 8.00, 5.98, 9.89, 9.00 },
+ { 6.99, 4.99, 9.00, 9.98 }
+ }, new double[] { 32, 23, 33, 31 });
+
+ optimizer = optimizer
+ .withModelAndJacobian(problem2.getModelFunction(),
+ problem2.getModelFunctionJacobian())
+ .withTarget(problem2.getTarget());
+
+ optimum = optimizer.optimize().getPoint();
+
+ Assert.assertEquals(0, optimizer.computeRMS(optimum), 1e-10);
+ Assert.assertEquals(-81, optimum[0], 1e-8);
+ Assert.assertEquals(137, optimum[1], 1e-8);
+ Assert.assertEquals(-34, optimum[2], 1e-8);
+ Assert.assertEquals( 22, optimum[3], 1e-8);
+ }
+
+ @Test
+ public void testMoreEstimatedParametersSimple() {
+ LinearProblem problem = new LinearProblem(new double[][] {
+ { 3, 2, 0, 0 },
+ { 0, 1, -1, 1 },
+ { 2, 0, 1, 0 }
+ }, new double[] { 7, 3, 5 });
+
+ T optimizer = createOptimizer()
+ .withMaxEvaluations(100)
+ .withMaxIterations(getMaxIterations())
+ .withModelAndJacobian(problem.getModelFunction(),
+ problem.getModelFunctionJacobian())
+ .withTarget(problem.getTarget())
+ .withWeight(new DiagonalMatrix(new double[] { 1, 1, 1 }))
+ .withStartPoint(new double[] { 7, 6, 5, 4 });
+
+ double[] optimum = optimizer.optimize().getPoint();
+ Assert.assertEquals(0, optimizer.computeRMS(optimum), 1e-10);
+ }
+
+ @Test
+ public void testMoreEstimatedParametersUnsorted() {
+ LinearProblem problem = new LinearProblem(new double[][] {
+ { 1, 1, 0, 0, 0, 0 },
+ { 0, 0, 1, 1, 1, 0 },
+ { 0, 0, 0, 0, 1, -1 },
+ { 0, 0, -1, 1, 0, 1 },
+ { 0, 0, 0, -1, 1, 0 }
+ }, new double[] { 3, 12, -1, 7, 1 });
+
+ T optimizer = createOptimizer()
+ .withMaxEvaluations(100)
+ .withMaxIterations(getMaxIterations())
+ .withModelAndJacobian(problem.getModelFunction(),
+ problem.getModelFunctionJacobian())
+ .withTarget(problem.getTarget())
+ .withWeight(new DiagonalMatrix(new double[] { 1, 1, 1, 1, 1 }))
+ .withStartPoint(new double[] { 2, 2, 2, 2, 2, 2 });
+
+ double[] optimum = optimizer.optimize().getPoint();
+
+ Assert.assertEquals(0, optimizer.computeRMS(optimum), 1e-10);
+ Assert.assertEquals(3, optimum[2], 1e-10);
+ Assert.assertEquals(4, optimum[3], 1e-10);
+ Assert.assertEquals(5, optimum[4], 1e-10);
+ Assert.assertEquals(6, optimum[5], 1e-10);
+ }
+
+ @Test
+ public void testRedundantEquations() {
+ LinearProblem problem = new LinearProblem(new double[][] {
+ { 1, 1 },
+ { 1, -1 },
+ { 1, 3 }
+ }, new double[] { 3, 1, 5 });
+
+ T optimizer = createOptimizer()
+ .withMaxEvaluations(100)
+ .withMaxIterations(getMaxIterations())
+ .withModelAndJacobian(problem.getModelFunction(),
+ problem.getModelFunctionJacobian())
+ .withTarget(problem.getTarget())
+ .withWeight(new DiagonalMatrix(new double[] { 1, 1, 1 }))
+ .withStartPoint(new double[] { 1, 1 });
+
+ double[] optimum = optimizer.optimize().getPoint();
+
+ Assert.assertEquals(0, optimizer.computeRMS(optimum), 1e-10);
+ Assert.assertEquals(2, optimum[0], 1e-10);
+ Assert.assertEquals(1, optimum[1], 1e-10);
+ }
+
+ @Test
+ public void testInconsistentEquations() {
+ LinearProblem problem = new LinearProblem(new double[][] {
+ { 1, 1 },
+ { 1, -1 },
+ { 1, 3 }
+ }, new double[] { 3, 1, 4 });
+
+ T optimizer = createOptimizer()
+ .withMaxEvaluations(100)
+ .withMaxIterations(getMaxIterations())
+ .withModelAndJacobian(problem.getModelFunction(),
+ problem.getModelFunctionJacobian())
+ .withTarget(problem.getTarget())
+ .withWeight(new DiagonalMatrix(new double[] { 1, 1, 1 }))
+ .withStartPoint(new double[] { 1, 1 });
+
+ double[] optimum = optimizer.optimize().getPoint();
+
+ Assert.assertTrue(optimizer.computeRMS(optimum) > 0.1);
+ }
+
+ @Test(expected=DimensionMismatchException.class)
+ public void testInconsistentSizes1() {
+ LinearProblem problem
+ = new LinearProblem(new double[][] { { 1, 0 },
+ { 0, 1 } },
+ new double[] { -1, 1 });
+ T optimizer = createOptimizer()
+ .withMaxEvaluations(100)
+ .withMaxIterations(getMaxIterations())
+ .withModelAndJacobian(problem.getModelFunction(),
+ problem.getModelFunctionJacobian())
+ .withTarget(problem.getTarget())
+ .withWeight(new DiagonalMatrix(new double[] { 1, 1 }))
+ .withStartPoint(new double[] { 0, 0 });
+
+ double[] optimum = optimizer.optimize().getPoint();
+
+ Assert.assertEquals(0, optimizer.computeRMS(optimum), 1e-10);
+ Assert.assertEquals(-1, optimum[0], 1e-10);
+ Assert.assertEquals(1, optimum[1], 1e-10);
+
+ optimizer.withWeight(new DiagonalMatrix(new double[] { 1 })).optimize();
+ }
+
+ @Test(expected=DimensionMismatchException.class)
+ public void testInconsistentSizes2() {
+ LinearProblem problem
+ = new LinearProblem(new double[][] { { 1, 0 }, { 0, 1 } },
+ new double[] { -1, 1 });
+
+ T optimizer = createOptimizer()
+ .withMaxEvaluations(100)
+ .withMaxIterations(getMaxIterations())
+ .withModelAndJacobian(problem.getModelFunction(),
+ problem.getModelFunctionJacobian())
+ .withTarget(problem.getTarget())
+ .withWeight(new DiagonalMatrix(new double[] { 1, 1 }))
+ .withStartPoint(new double[] { 0, 0 });
+
+ double[] optimum = optimizer.optimize().getPoint();
+
+ Assert.assertEquals(0, optimizer.computeRMS(optimum), 1e-10);
+ Assert.assertEquals(-1, optimum[0], 1e-10);
+ Assert.assertEquals(1, optimum[1], 1e-10);
+
+ optimizer
+ .withTarget(new double[] { 1 })
+ .withWeight(new DiagonalMatrix(new double[] { 1 }))
+ .optimize();
+ }
+
+ @Test
+ public void testCircleFitting() {
+ CircleVectorial circle = new CircleVectorial();
+ circle.addPoint( 30, 68);
+ circle.addPoint( 50, -6);
+ circle.addPoint(110, -20);
+ circle.addPoint( 35, 15);
+ circle.addPoint( 45, 97);
+
+ T optimizer = createOptimizer()
+ .withMaxEvaluations(100)
+ .withMaxIterations(getMaxIterations())
+ .withModelAndJacobian(circle.getModelFunction(),
+ circle.getModelFunctionJacobian())
+ .withTarget(new double[] { 0, 0, 0, 0, 0 })
+ .withWeight(new DiagonalMatrix(new double[] { 1, 1, 1, 1, 1 }))
+ .withStartPoint(new double[] { 98.680, 47.345 });
+
+ double[] optimum = optimizer.optimize().getPoint();
+ Assert.assertTrue(optimizer.getEvaluations() < 10);
+
+ double rms = optimizer.computeRMS(optimum);
+ Assert.assertEquals(1.768262623567235, FastMath.sqrt(circle.getN()) * rms, 1e-10);
+
+ Vector2D center = new Vector2D(optimum[0], optimum[1]);
+ Assert.assertEquals(69.96016176931406, circle.getRadius(center), 1e-6);
+ Assert.assertEquals(96.07590211815305, center.getX(), 1e-6);
+ Assert.assertEquals(48.13516790438953, center.getY(), 1e-6);
+
+ double[][] cov = optimizer.computeCovariances(optimum, 1e-14);
+ Assert.assertEquals(1.839, cov[0][0], 0.001);
+ Assert.assertEquals(0.731, cov[0][1], 0.001);
+ Assert.assertEquals(cov[0][1], cov[1][0], 1e-14);
+ Assert.assertEquals(0.786, cov[1][1], 0.001);
+
+ // add perfect measurements and check errors are reduced
+ double r = circle.getRadius(center);
+ for (double d= 0; d < 2 * FastMath.PI; d += 0.01) {
+ circle.addPoint(center.getX() + r * FastMath.cos(d), center.getY() + r * FastMath.sin(d));
+ }
+
+ double[] target = new double[circle.getN()];
+ Arrays.fill(target, 0);
+ double[] weights = new double[circle.getN()];
+ Arrays.fill(weights, 2);
+ optimizer = optimizer.withTarget(target).withWeight(new DiagonalMatrix(weights));
+ optimum = optimizer.optimize().getPoint();
+
+ cov = optimizer.computeCovariances(optimum, 1e-14);
+ Assert.assertEquals(0.0016, cov[0][0], 0.001);
+ Assert.assertEquals(3.2e-7, cov[0][1], 1e-9);
+ Assert.assertEquals(cov[0][1], cov[1][0], 1e-14);
+ Assert.assertEquals(0.0016, cov[1][1], 0.001);
+ }
+
+ @Test
+ public void testCircleFittingBadInit() {
+ CircleVectorial circle = new CircleVectorial();
+ double[][] points = circlePoints;
+ double[] target = new double[points.length];
+ Arrays.fill(target, 0);
+ double[] weights = new double[points.length];
+ Arrays.fill(weights, 2);
+ for (int i = 0; i < points.length; ++i) {
+ circle.addPoint(points[i][0], points[i][1]);
+ }
+ T optimizer = createOptimizer()
+ .withMaxEvaluations(100)
+ .withMaxIterations(getMaxIterations())
+ .withModelAndJacobian(circle.getModelFunction(),
+ circle.getModelFunctionJacobian())
+ .withTarget(target)
+ .withWeight(new DiagonalMatrix(weights))
+ .withStartPoint(new double[] { -12, -12 });
+
+ double[] optimum = optimizer.optimize().getPoint();
+
+ Vector2D center = new Vector2D(optimum[0], optimum[1]);
+ Assert.assertTrue(optimizer.getEvaluations() < 25);
+ Assert.assertEquals( 0.043, optimizer.computeRMS(optimum), 1e-3);
+ Assert.assertEquals( 0.292235, circle.getRadius(center), 1e-6);
+ Assert.assertEquals(-0.151738, center.getX(), 1e-6);
+ Assert.assertEquals( 0.2075001, center.getY(), 1e-6);
+ }
+
+ @Test
+ public void testCircleFittingGoodInit() {
+ CircleVectorial circle = new CircleVectorial();
+ double[][] points = circlePoints;
+ double[] target = new double[points.length];
+ Arrays.fill(target, 0);
+ double[] weights = new double[points.length];
+ Arrays.fill(weights, 2);
+ for (int i = 0; i < points.length; ++i) {
+ circle.addPoint(points[i][0], points[i][1]);
+ }
+ T optimizer = createOptimizer()
+ .withMaxEvaluations(100)
+ .withMaxIterations(getMaxIterations())
+ .withModelAndJacobian(circle.getModelFunction(),
+ circle.getModelFunctionJacobian())
+ .withTarget(target)
+ .withWeight(new DiagonalMatrix(weights))
+ .withStartPoint(new double[] { 0, 0 });
+
+ double[] optimum = optimizer.optimize().getPoint();
+
+ Assert.assertEquals(-0.1517383071957963, optimum[0], 1e-6);
+ Assert.assertEquals(0.2074999736353867, optimum[1], 1e-6);
+ Assert.assertEquals(0.04268731682389561, optimizer.computeRMS(optimum), 1e-8);
+ }
+
+ private final double[][] circlePoints = new double[][] {
+ {-0.312967, 0.072366}, {-0.339248, 0.132965}, {-0.379780, 0.202724},
+ {-0.390426, 0.260487}, {-0.361212, 0.328325}, {-0.346039, 0.392619},
+ {-0.280579, 0.444306}, {-0.216035, 0.470009}, {-0.149127, 0.493832},
+ {-0.075133, 0.483271}, {-0.007759, 0.452680}, { 0.060071, 0.410235},
+ { 0.103037, 0.341076}, { 0.118438, 0.273884}, { 0.131293, 0.192201},
+ { 0.115869, 0.129797}, { 0.072223, 0.058396}, { 0.022884, 0.000718},
+ {-0.053355, -0.020405}, {-0.123584, -0.032451}, {-0.216248, -0.032862},
+ {-0.278592, -0.005008}, {-0.337655, 0.056658}, {-0.385899, 0.112526},
+ {-0.405517, 0.186957}, {-0.415374, 0.262071}, {-0.387482, 0.343398},
+ {-0.347322, 0.397943}, {-0.287623, 0.458425}, {-0.223502, 0.475513},
+ {-0.135352, 0.478186}, {-0.061221, 0.483371}, { 0.003711, 0.422737},
+ { 0.065054, 0.375830}, { 0.108108, 0.297099}, { 0.123882, 0.222850},
+ { 0.117729, 0.134382}, { 0.085195, 0.056820}, { 0.029800, -0.019138},
+ {-0.027520, -0.072374}, {-0.102268, -0.091555}, {-0.200299, -0.106578},
+ {-0.292731, -0.091473}, {-0.356288, -0.051108}, {-0.420561, 0.014926},
+ {-0.471036, 0.074716}, {-0.488638, 0.182508}, {-0.485990, 0.254068},
+ {-0.463943, 0.338438}, {-0.406453, 0.404704}, {-0.334287, 0.466119},
+ {-0.254244, 0.503188}, {-0.161548, 0.495769}, {-0.075733, 0.495560},
+ { 0.001375, 0.434937}, { 0.082787, 0.385806}, { 0.115490, 0.323807},
+ { 0.141089, 0.223450}, { 0.138693, 0.131703}, { 0.126415, 0.049174},
+ { 0.066518, -0.010217}, {-0.005184, -0.070647}, {-0.080985, -0.103635},
+ {-0.177377, -0.116887}, {-0.260628, -0.100258}, {-0.335756, -0.056251},
+ {-0.405195, -0.000895}, {-0.444937, 0.085456}, {-0.484357, 0.175597},
+ {-0.472453, 0.248681}, {-0.438580, 0.347463}, {-0.402304, 0.422428},
+ {-0.326777, 0.479438}, {-0.247797, 0.505581}, {-0.152676, 0.519380},
+ {-0.071754, 0.516264}, { 0.015942, 0.472802}, { 0.076608, 0.419077},
+ { 0.127673, 0.330264}, { 0.159951, 0.262150}, { 0.153530, 0.172681},
+ { 0.140653, 0.089229}, { 0.078666, 0.024981}, { 0.023807, -0.037022},
+ {-0.048837, -0.077056}, {-0.127729, -0.075338}, {-0.221271, -0.067526}
+ };
+
+ public void doTestStRD(final StatisticalReferenceDataset dataset,
+ final double errParams,
+ final double errParamsSd) {
+ final double[] w = new double[dataset.getNumObservations()];
+ Arrays.fill(w, 1);
+
+ final double[][] data = dataset.getData();
+ final double[] initial = dataset.getStartingPoint(0);
+ final StatisticalReferenceDataset.LeastSquaresProblem problem = dataset.getLeastSquaresProblem();
+
+ final T optimizer = createOptimizer()
+ .withMaxEvaluations(100)
+ .withMaxIterations(getMaxIterations())
+ .withModelAndJacobian(problem.getModelFunction(),
+ problem.getModelFunctionJacobian())
+ .withTarget(data[1])
+ .withWeight(new DiagonalMatrix(w))
+ .withStartPoint(initial);
+
+ final double[] actual = optimizer.optimize().getPoint();
+ for (int i = 0; i < actual.length; i++) {
+ double expected = dataset.getParameter(i);
+ double delta = FastMath.abs(errParams * expected);
+ Assert.assertEquals(dataset.getName() + ", param #" + i,
+ expected, actual[i], delta);
+ }
+ }
+
+ @Test
+ public void testKirby2() throws IOException {
+ doTestStRD(StatisticalReferenceDatasetFactory.createKirby2(), 1E-7, 1E-7);
+ }
+
+ @Test
+ public void testHahn1() throws IOException {
+ doTestStRD(StatisticalReferenceDatasetFactory.createHahn1(), 1E-7, 1E-4);
+ }
+
+ static class LinearProblem {
+ private final RealMatrix factors;
+ private final double[] target;
+
+ public LinearProblem(double[][] factors, double[] target) {
+ this.factors = new BlockRealMatrix(factors);
+ this.target = target;
+ }
+
+ public double[] getTarget() {
+ return target;
+ }
+
+ public MultivariateVectorFunction getModelFunction() {
+ return new MultivariateVectorFunction() {
+ public double[] value(double[] params) {
+ return factors.operate(params);
+ }
+ };
+ }
+
+ public MultivariateMatrixFunction getModelFunctionJacobian() {
+ return new MultivariateMatrixFunction() {
+ public double[][] value(double[] params) {
+ return factors.getData();
+ }
+ };
+ }
+ }
+}
Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerAbstractTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerAbstractTest.java
------------------------------------------------------------------------------
svn:keywords = Id Revision
Added: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerTest.java?rev=1508481&view=auto
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerTest.java (added)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerTest.java Tue Jul 30 15:04:22 2013
@@ -0,0 +1,109 @@
+/*
+ * 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 java.io.IOException;
+import java.util.Arrays;
+import org.apache.commons.math3.optim.PointVectorValuePair;
+import org.apache.commons.math3.linear.DiagonalMatrix;
+import org.apache.commons.math3.util.FastMath;
+import org.junit.Test;
+import org.junit.Assert;
+/**
+ * The only features tested here are utility methods defined
+ * in {@link AbstractLeastSquaresOptimizer} that compute the
+ * chi-square and parameters standard-deviations.
+ */
+public class AbstractLeastSquaresOptimizerTest {
+ @Test
+ public void testComputeCost() throws IOException {
+ final StatisticalReferenceDataset dataset
+ = StatisticalReferenceDatasetFactory.createKirby2();
+ final double[] a = dataset.getParameters();
+ final double[] y = dataset.getData()[1];
+ final double[] w = new double[y.length];
+ Arrays.fill(w, 1d);
+
+ StatisticalReferenceDataset.LeastSquaresProblem problem
+ = dataset.getLeastSquaresProblem();
+
+ final LevenbergMarquardtOptimizer optim = LevenbergMarquardtOptimizer.create()
+ .withModelAndJacobian(problem.getModelFunction(),
+ problem.getModelFunctionJacobian())
+ .withTarget(y)
+ .withWeight(new DiagonalMatrix(w))
+ .withStartPoint(a);
+
+ final double expected = dataset.getResidualSumOfSquares();
+ final double cost = optim.computeCost(optim.computeResiduals(optim.getModel().value(optim.getStart())));
+ final double actual = cost * cost;
+ Assert.assertEquals(dataset.getName(), expected, actual, 1e-11 * expected);
+ }
+
+ @Test
+ public void testComputeRMS() throws IOException {
+ final StatisticalReferenceDataset dataset
+ = StatisticalReferenceDatasetFactory.createKirby2();
+ final double[] a = dataset.getParameters();
+ final double[] y = dataset.getData()[1];
+ final double[] w = new double[y.length];
+ Arrays.fill(w, 1d);
+
+ StatisticalReferenceDataset.LeastSquaresProblem problem
+ = dataset.getLeastSquaresProblem();
+
+ final LevenbergMarquardtOptimizer optim = LevenbergMarquardtOptimizer.create()
+ .withModelAndJacobian(problem.getModelFunction(),
+ problem.getModelFunctionJacobian())
+ .withTarget(y)
+ .withWeight(new DiagonalMatrix(w))
+ .withStartPoint(a);
+
+ final double expected = FastMath.sqrt(dataset.getResidualSumOfSquares() /
+ dataset.getNumObservations());
+ final double actual = optim.computeRMS(optim.getStart());
+ Assert.assertEquals(dataset.getName(), expected, actual, 1e-11 * expected);
+ }
+
+ @Test
+ public void testComputeSigma() throws IOException {
+ final StatisticalReferenceDataset dataset
+ = StatisticalReferenceDatasetFactory.createKirby2();
+ final double[] a = dataset.getParameters();
+ final double[] y = dataset.getData()[1];
+ final double[] w = new double[y.length];
+ Arrays.fill(w, 1d);
+
+ StatisticalReferenceDataset.LeastSquaresProblem problem
+ = dataset.getLeastSquaresProblem();
+
+ final LevenbergMarquardtOptimizer optim = LevenbergMarquardtOptimizer.create()
+ .withModelAndJacobian(problem.getModelFunction(),
+ problem.getModelFunctionJacobian())
+ .withTarget(y)
+ .withWeight(new DiagonalMatrix(w))
+ .withStartPoint(a);
+
+ final double[] expected = dataset.getParametersStandardDeviations();
+
+ final double cost = optim.computeCost(optim.computeResiduals(optim.getModel().value(optim.getStart())));
+ final double[] sig = optim.computeSigma(optim.getStart(), 1e-14);
+ final int dof = y.length - a.length;
+ for (int i = 0; i < sig.length; i++) {
+ final double actual = FastMath.sqrt(cost * cost / dof) * sig[i];
+ Assert.assertEquals(dataset.getName() + ", parameter #" + i,
+ expected[i], actual, 1e-6 * expected[i]);
+ }
+ }
+}
Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerTest.java
------------------------------------------------------------------------------
svn:keywords = Id Revision
Added: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerTestValidation.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerTestValidation.java?rev=1508481&view=auto
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerTestValidation.java (added)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerTestValidation.java Tue Jul 30 15:04:22 2013
@@ -0,0 +1,308 @@
+/*
+ * 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 java.util.Arrays;
+import java.util.List;
+import java.util.ArrayList;
+import java.awt.geom.Point2D;
+import org.apache.commons.math3.optim.PointVectorValuePair;
+import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
+import org.apache.commons.math3.stat.descriptive.StatisticalSummary;
+import org.apache.commons.math3.linear.DiagonalMatrix;
+import org.apache.commons.math3.util.FastMath;
+import org.junit.Test;
+import org.junit.Assert;
+
+/**
+ * This class demonstrates the main functionality of the
+ * {@link AbstractLeastSquaresOptimizer}, common to the
+ * optimizer implementations in package
+ * {@link org.apache.commons.math3.fitting.leastsquares}.
+ * <br/>
+ * Not enabled by default, as the class name does not end with "Test".
+ * <br/>
+ * Invoke by running
+ * <pre><code>
+ * mvn test -Dtest=AbstractLeastSquaresOptimizerTestValidation
+ * </code></pre>
+ * or by running
+ * <pre><code>
+ * mvn test -Dtest=AbstractLeastSquaresOptimizerTestValidation -DargLine="-DmcRuns=1234 -server"
+ * </code></pre>
+ */
+public class AbstractLeastSquaresOptimizerTestValidation {
+ /** Number of runs. */
+ private static final int MONTE_CARLO_RUNS = Integer.parseInt(System.getProperty("mcRuns",
+ "100"));
+
+ /**
+ * Using a Monte-Carlo procedure, this test checks the error estimations
+ * as provided by the square-root of the diagonal elements of the
+ * covariance matrix.
+ * <br/>
+ * The test generates sets of observations, each sampled from
+ * a Gaussian distribution.
+ * <br/>
+ * The optimization problem solved is defined in class
+ * {@link StraightLineProblem}.
+ * <br/>
+ * The output (on stdout) will be a table summarizing the distribution
+ * of parameters generated by the Monte-Carlo process and by the direct
+ * estimation provided by the diagonal elements of the covariance matrix.
+ */
+ @Test
+ public void testParametersErrorMonteCarloObservations() {
+ // Error on the observations.
+ final double yError = 15;
+
+ // True values of the parameters.
+ final double slope = 123.456;
+ final double offset = -98.765;
+
+ // Samples generator.
+ final RandomStraightLinePointGenerator lineGenerator
+ = new RandomStraightLinePointGenerator(slope, offset,
+ yError,
+ -1e3, 1e4,
+ 138577L);
+
+ // Number of observations.
+ final int numObs = 100; // XXX Should be a command-line option.
+ // number of parameters.
+ final int numParams = 2;
+
+ // Parameters found for each of Monte-Carlo run.
+ final SummaryStatistics[] paramsFoundByDirectSolution = new SummaryStatistics[numParams];
+ // Sigma estimations (square-root of the diagonal elements of the
+ // covariance matrix), for each Monte-Carlo run.
+ final SummaryStatistics[] sigmaEstimate = new SummaryStatistics[numParams];
+
+ // Initialize statistics accumulators.
+ for (int i = 0; i < numParams; i++) {
+ paramsFoundByDirectSolution[i] = new SummaryStatistics();
+ sigmaEstimate[i] = new SummaryStatistics();
+ }
+
+ final double[] init = { slope, offset };
+
+ // Monte-Carlo (generates many sets of observations).
+ final int mcRepeat = MONTE_CARLO_RUNS;
+ int mcCount = 0;
+ while (mcCount < mcRepeat) {
+ // Observations.
+ final Point2D.Double[] obs = lineGenerator.generate(numObs);
+
+ final StraightLineProblem problem = new StraightLineProblem(yError);
+ for (int i = 0; i < numObs; i++) {
+ final Point2D.Double p = obs[i];
+ problem.addPoint(p.x, p.y);
+ }
+
+ // Direct solution (using simple regression).
+ final double[] regress = problem.solve();
+
+ // Estimation of the standard deviation (diagonal elements of the
+ // covariance matrix).
+ // Dummy optimizer (to compute the covariance matrix).
+ final AbstractLeastSquaresOptimizer optim = LevenbergMarquardtOptimizer.create()
+ .withModelAndJacobian(problem.getModelFunction(),
+ problem.getModelFunctionJacobian())
+ .withTarget(problem.target())
+ .withWeight(new DiagonalMatrix(problem.weight()));
+
+ final double[] sigma = optim.computeSigma(init, 1e-14);
+
+ // Accumulate statistics.
+ for (int i = 0; i < numParams; i++) {
+ paramsFoundByDirectSolution[i].addValue(regress[i]);
+ sigmaEstimate[i].addValue(sigma[i]);
+ }
+
+ // Next Monte-Carlo.
+ ++mcCount;
+ }
+
+ // Print statistics.
+ final String line = "--------------------------------------------------------------";
+ System.out.println(" True value Mean Std deviation");
+ for (int i = 0; i < numParams; i++) {
+ System.out.println(line);
+ System.out.println("Parameter #" + i);
+
+ StatisticalSummary s = paramsFoundByDirectSolution[i].getSummary();
+ System.out.printf(" %+.6e %+.6e %+.6e\n",
+ init[i],
+ s.getMean(),
+ s.getStandardDeviation());
+
+ s = sigmaEstimate[i].getSummary();
+ System.out.printf("sigma: %+.6e (%+.6e)\n",
+ s.getMean(),
+ s.getStandardDeviation());
+ }
+ System.out.println(line);
+
+ // Check the error estimation.
+ for (int i = 0; i < numParams; i++) {
+ Assert.assertEquals(paramsFoundByDirectSolution[i].getSummary().getStandardDeviation(),
+ sigmaEstimate[i].getSummary().getMean(),
+ 8e-2);
+ }
+ }
+
+ /**
+ * In this test, the set of observations is fixed.
+ * Using a Monte-Carlo procedure, it generates sets of parameters,
+ * and determine the parameter change that will result in the
+ * normalized chi-square becoming larger by one than the value from
+ * the best fit solution.
+ * <br/>
+ * The optimization problem solved is defined in class
+ * {@link StraightLineProblem}.
+ * <br/>
+ * The output (on stdout) will be a list of lines containing:
+ * <ul>
+ * <li>slope of the straight line,</li>
+ * <li>intercept of the straight line,</li>
+ * <li>chi-square of the solution defined by the above two values.</li>
+ * </ul>
+ * The output is separated into two blocks (with a blank line between
+ * them); the first block will contain all parameter sets for which
+ * {@code chi2 < chi2_b + 1}
+ * and the second block, all sets for which
+ * {@code chi2 >= chi2_b + 1}
+ * where {@code chi2_b} is the lowest chi-square (corresponding to the
+ * best solution).
+ */
+ @Test
+ public void testParametersErrorMonteCarloParameters() {
+ // Error on the observations.
+ final double yError = 15;
+
+ // True values of the parameters.
+ final double slope = 123.456;
+ final double offset = -98.765;
+
+ // Samples generator.
+ final RandomStraightLinePointGenerator lineGenerator
+ = new RandomStraightLinePointGenerator(slope, offset,
+ yError,
+ -1e3, 1e4,
+ 13839013L);
+
+ // Number of observations.
+ final int numObs = 10;
+ // number of parameters.
+ final int numParams = 2;
+
+ // Create a single set of observations.
+ final Point2D.Double[] obs = lineGenerator.generate(numObs);
+
+ final StraightLineProblem problem = new StraightLineProblem(yError);
+ for (int i = 0; i < numObs; i++) {
+ final Point2D.Double p = obs[i];
+ problem.addPoint(p.x, p.y);
+ }
+
+ // Direct solution (using simple regression).
+ final double[] regress = problem.solve();
+
+ // Dummy optimizer (to compute the chi-square).
+ final AbstractLeastSquaresOptimizer optim = LevenbergMarquardtOptimizer.create()
+ .withModelAndJacobian(problem.getModelFunction(),
+ problem.getModelFunctionJacobian())
+ .withTarget(problem.target())
+ .withWeight(new DiagonalMatrix(problem.weight()));
+
+ final double[] init = { slope, offset };
+ // Get chi-square of the best parameters set for the given set of
+ // observations.
+ final double bestChi2N = getChi2N(optim, problem, regress);
+ final double[] sigma = optim.computeSigma(regress, 1e-14);
+
+ // Monte-Carlo (generates a grid of parameters).
+ final int mcRepeat = MONTE_CARLO_RUNS;
+ final int gridSize = (int) FastMath.sqrt(mcRepeat);
+
+ // Parameters found for each of Monte-Carlo run.
+ // Index 0 = slope
+ // Index 1 = offset
+ // Index 2 = normalized chi2
+ final List<double[]> paramsAndChi2 = new ArrayList<double[]>(gridSize * gridSize);
+
+ final double slopeRange = 10 * sigma[0];
+ final double offsetRange = 10 * sigma[1];
+ final double minSlope = slope - 0.5 * slopeRange;
+ final double minOffset = offset - 0.5 * offsetRange;
+ final double deltaSlope = slopeRange/ gridSize;
+ final double deltaOffset = offsetRange / gridSize;
+ for (int i = 0; i < gridSize; i++) {
+ final double s = minSlope + i * deltaSlope;
+ for (int j = 0; j < gridSize; j++) {
+ final double o = minOffset + j * deltaOffset;
+ final double chi2N = getChi2N(optim, problem, new double[] {s, o});
+
+ paramsAndChi2.add(new double[] {s, o, chi2N});
+ }
+ }
+
+ // Output (for use with "gnuplot").
+
+ // Some info.
+
+ // For plotting separately sets of parameters that have a large chi2.
+ final double chi2NPlusOne = bestChi2N + 1;
+ int numLarger = 0;
+
+ final String lineFmt = "%+.10e %+.10e %.8e\n";
+
+ // Point with smallest chi-square.
+ System.out.printf(lineFmt, regress[0], regress[1], bestChi2N);
+ System.out.println(); // Empty line.
+
+ // Points within the confidence interval.
+ for (double[] d : paramsAndChi2) {
+ if (d[2] <= chi2NPlusOne) {
+ System.out.printf(lineFmt, d[0], d[1], d[2]);
+ }
+ }
+ System.out.println(); // Empty line.
+
+ // Points outside the confidence interval.
+ for (double[] d : paramsAndChi2) {
+ if (d[2] > chi2NPlusOne) {
+ ++numLarger;
+ System.out.printf(lineFmt, d[0], d[1], d[2]);
+ }
+ }
+ System.out.println(); // Empty line.
+
+ System.out.println("# sigma=" + Arrays.toString(sigma));
+ System.out.println("# " + numLarger + " sets filtered out");
+ }
+
+ /**
+ * @return the normalized chi-square.
+ */
+ private double getChi2N(AbstractLeastSquaresOptimizer optim,
+ StraightLineProblem problem,
+ double[] params) {
+ final double[] t = problem.target();
+ final double[] w = problem.weight();
+ final double cost = optim.computeCost(optim.computeResiduals(optim.getModel().value(params)));
+ return cost * cost / (t.length - params.length);
+ }
+}
+
Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerTestValidation.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerTestValidation.java
------------------------------------------------------------------------------
svn:keywords = Id Revision
Added: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/CircleProblem.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/CircleProblem.java?rev=1508481&view=auto
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/CircleProblem.java (added)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/CircleProblem.java Tue Jul 30 15:04:22 2013
@@ -0,0 +1,175 @@
+/*
+ * 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 java.util.ArrayList;
+import org.apache.commons.math3.analysis.MultivariateVectorFunction;
+import org.apache.commons.math3.analysis.MultivariateMatrixFunction;
+import org.apache.commons.math3.util.MathUtils;
+import org.apache.commons.math3.util.FastMath;
+
+/**
+ * Class that models a circle.
+ * The parameters of problem are:
+ * <ul>
+ * <li>the x-coordinate of the circle center,</li>
+ * <li>the y-coordinate of the circle center,</li>
+ * <li>the radius of the circle.</li>
+ * </ul>
+ * The model functions are:
+ * <ul>
+ * <li>for each triplet (cx, cy, r), the (x, y) coordinates of a point on the
+ * corresponding circle.</li>
+ * </ul>
+ */
+class CircleProblem {
+ /** Cloud of points assumed to be fitted by a circle. */
+ private final ArrayList<double[]> points;
+ /** Error on the x-coordinate of the points. */
+ private final double xSigma;
+ /** Error on the y-coordinate of the points. */
+ private final double ySigma;
+ /** Number of points on the circumference (when searching which
+ model point is closest to a given "observation". */
+ private final int resolution;
+
+ /**
+ * @param xError Assumed error for the x-coordinate of the circle points.
+ * @param yError Assumed error for the y-coordinate of the circle points.
+ * @param searchResolution Number of points to try when searching the one
+ * that is closest to a given "observed" point.
+ */
+ public CircleProblem(double xError,
+ double yError,
+ int searchResolution) {
+ points = new ArrayList<double[]>();
+ xSigma = xError;
+ ySigma = yError;
+ resolution = searchResolution;
+ }
+
+ /**
+ * @param xError Assumed error for the x-coordinate of the circle points.
+ * @param yError Assumed error for the y-coordinate of the circle points.
+ */
+ public CircleProblem(double xError,
+ double yError) {
+ this(xError, yError, 500);
+ }
+
+ public void addPoint(double px, double py) {
+ points.add(new double[] { px, py });
+ }
+
+ public double[] target() {
+ final double[] t = new double[points.size() * 2];
+ for (int i = 0; i < points.size(); i++) {
+ final double[] p = points.get(i);
+ final int index = i * 2;
+ t[index] = p[0];
+ t[index + 1] = p[1];
+ }
+
+ return t;
+ }
+
+ public double[] weight() {
+ final double wX = 1 / (xSigma * xSigma);
+ final double wY = 1 / (ySigma * ySigma);
+ final double[] w = new double[points.size() * 2];
+ for (int i = 0; i < points.size(); i++) {
+ final int index = i * 2;
+ w[index] = wX;
+ w[index + 1] = wY;
+ }
+
+ return w;
+ }
+
+ public MultivariateVectorFunction getModelFunction() {
+ return new MultivariateVectorFunction() {
+ public double[] value(double[] params) {
+ final double cx = params[0];
+ final double cy = params[1];
+ final double r = params[2];
+
+ final double[] model = new double[points.size() * 2];
+
+ final double deltaTheta = MathUtils.TWO_PI / resolution;
+ for (int i = 0; i < points.size(); i++) {
+ final double[] p = points.get(i);
+ final double px = p[0];
+ final double py = p[1];
+
+ double bestX = 0;
+ double bestY = 0;
+ double dMin = Double.POSITIVE_INFINITY;
+
+ // Find the angle for which the circle passes closest to the
+ // current point (using a resolution of 100 points along the
+ // circumference).
+ for (double theta = 0; theta <= MathUtils.TWO_PI; theta += deltaTheta) {
+ final double currentX = cx + r * FastMath.cos(theta);
+ final double currentY = cy + r * FastMath.sin(theta);
+ final double dX = currentX - px;
+ final double dY = currentY - py;
+ final double d = dX * dX + dY * dY;
+ if (d < dMin) {
+ dMin = d;
+ bestX = currentX;
+ bestY = currentY;
+ }
+ }
+
+ final int index = i * 2;
+ model[index] = bestX;
+ model[index + 1] = bestY;
+ }
+
+ return model;
+ }
+ };
+ }
+
+ public MultivariateMatrixFunction getModelFunctionJacobian() {
+ return new MultivariateMatrixFunction() {
+ public double[][] value(double[] point) {
+ return jacobian(point);
+ }
+ };
+ }
+
+ private double[][] jacobian(double[] params) {
+ final double[][] jacobian = new double[points.size() * 2][3];
+
+ for (int i = 0; i < points.size(); i++) {
+ final int index = i * 2;
+ // Partial derivative wrt x-coordinate of center.
+ jacobian[index][0] = 1;
+ jacobian[index + 1][0] = 0;
+ // Partial derivative wrt y-coordinate of center.
+ jacobian[index][1] = 0;
+ jacobian[index + 1][1] = 1;
+ // Partial derivative wrt radius.
+ final double[] p = points.get(i);
+ jacobian[index][2] = (p[0] - params[0]) / params[2];
+ jacobian[index + 1][2] = (p[1] - params[1]) / params[2];
+ }
+
+ return jacobian;
+ }
+}
Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/CircleProblem.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/CircleProblem.java
------------------------------------------------------------------------------
svn:keywords = Id Revision
Added: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/CircleVectorial.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/CircleVectorial.java?rev=1508481&view=auto
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/CircleVectorial.java (added)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/CircleVectorial.java Tue Jul 30 15:04:22 2013
@@ -0,0 +1,94 @@
+/*
+ * 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 java.util.ArrayList;
+import org.apache.commons.math3.analysis.MultivariateVectorFunction;
+import org.apache.commons.math3.analysis.MultivariateMatrixFunction;
+import org.apache.commons.math3.geometry.euclidean.twod.Vector2D;
+
+/**
+ * Class used in the tests.
+ */
+class CircleVectorial {
+ private ArrayList<Vector2D> points;
+
+ public CircleVectorial() {
+ points = new ArrayList<Vector2D>();
+ }
+
+ public void addPoint(double px, double py) {
+ points.add(new Vector2D(px, py));
+ }
+
+ public int getN() {
+ return points.size();
+ }
+
+ public double getRadius(Vector2D center) {
+ double r = 0;
+ for (Vector2D point : points) {
+ r += point.distance(center);
+ }
+ return r / points.size();
+ }
+
+ public MultivariateVectorFunction getModelFunction() {
+ return new MultivariateVectorFunction() {
+ public double[] value(double[] params) {
+ Vector2D center = new Vector2D(params[0], params[1]);
+ double radius = getRadius(center);
+ double[] residuals = new double[points.size()];
+ for (int i = 0; i < residuals.length; i++) {
+ residuals[i] = points.get(i).distance(center) - radius;
+ }
+
+ return residuals;
+ }
+ };
+ }
+
+ public MultivariateMatrixFunction getModelFunctionJacobian() {
+ return new MultivariateMatrixFunction() {
+ public double[][] value(double[] params) {
+ final int n = points.size();
+ final Vector2D center = new Vector2D(params[0], params[1]);
+
+ double dRdX = 0;
+ double dRdY = 0;
+ for (Vector2D pk : points) {
+ double dk = pk.distance(center);
+ dRdX += (center.getX() - pk.getX()) / dk;
+ dRdY += (center.getY() - pk.getY()) / dk;
+ }
+ dRdX /= n;
+ dRdY /= n;
+
+ // Jacobian of the radius residuals.
+ double[][] jacobian = new double[n][2];
+ for (int i = 0; i < n; i++) {
+ final Vector2D pi = points.get(i);
+ final double di = pi.distance(center);
+ jacobian[i][0] = (center.getX() - pi.getX()) / di - dRdX;
+ jacobian[i][1] = (center.getY() - pi.getY()) / di - dRdY;
+ }
+
+ return jacobian;
+ }
+ };
+ }
+}
Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/CircleVectorial.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/CircleVectorial.java
------------------------------------------------------------------------------
svn:keywords = Id Revision