commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From l..@apache.org
Subject svn commit: r1569342 [1/3] - in /commons/proper/math/trunk/src: main/java/org/apache/commons/math3/fitting/ main/java/org/apache/commons/math3/fitting/leastsquares/ main/java/org/apache/commons/math3/optim/ test/java/org/apache/commons/math3/fitting/le...
Date Tue, 18 Feb 2014 14:31:35 GMT
Author: luc
Date: Tue Feb 18 14:31:34 2014
New Revision: 1569342

URL: http://svn.apache.org/r1569342
Log:
Separate least squares algorithm from problem.

The least squares package now has two main interfaces LeastSquaresOptimizer and
LeastSquaresProblem, where the optimizer can be applied to the problem.

In this commit all of the test cases pass with one change (annotated) to
LevenbergMarquardt.testControlParameters(). The tests for Gauss Newton were
expanded to cover using the QR decomposition, which revealed a QR default
tolerance discrepancy.

A factory and a mutable builder were create for LeastSquaresProblem.

This commit is a backport of Evan Ward github commit
 https://github.com/wardev/commons-math/commit/7e9a15efb535b91afad9d8275eb2864ea2295ab4
into the current development version.

Conflicts:
	src/main/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizer.java
	src/main/java/org/apache/commons/math3/fitting/leastsquares/GaussNewtonOptimizer.java
	src/main/java/org/apache/commons/math3/optim/AbstractOptimizer.java
	src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerAbstractTest.java
	src/test/java/org/apache/commons/math3/fitting/leastsquares/GaussNewtonOptimizerTest.java
	src/test/java/org/apache/commons/math3/fitting/leastsquares/LevenbergMarquardtOptimizerTest.java

Added:
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresBuilder.java   (with props)
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresFactory.java   (with props)
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresOptimizer.java   (with props)
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresProblem.java   (with props)
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresProblemImpl.java   (with props)
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/OptimizationProblem.java   (with props)
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/OptimumImpl.java   (with props)
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optim/AbstractOptimizationProblem.java   (with props)
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/EvaluationTest.java   (contents, props changed)
      - copied, changed from r1568754, commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerTest.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/EvaluationTestValidation.java   (contents, props changed)
      - copied, changed from r1568754, commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerTestValidation.java
Removed:
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizer.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optim/AbstractOptimizer.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerTest.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerTestValidation.java
Modified:
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/AbstractCurveFitter.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/GaussianCurveFitter.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/HarmonicCurveFitter.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/PolynomialCurveFitter.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/GaussNewtonOptimizer.java
    commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LevenbergMarquardtOptimizer.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/AbstractLeastSquaresOptimizerAbstractTest.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/GaussNewtonOptimizerTest.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/LevenbergMarquardtOptimizerTest.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math3/fitting/leastsquares/MinpackTest.java

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/AbstractCurveFitter.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/AbstractCurveFitter.java?rev=1569342&r1=1569341&r2=1569342&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/AbstractCurveFitter.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/AbstractCurveFitter.java Tue Feb 18 14:31:34 2014
@@ -17,11 +17,13 @@
 package org.apache.commons.math3.fitting;
 
 import java.util.Collection;
+
 import org.apache.commons.math3.analysis.MultivariateVectorFunction;
 import org.apache.commons.math3.analysis.MultivariateMatrixFunction;
 import org.apache.commons.math3.analysis.ParametricUnivariateFunction;
-import org.apache.commons.math3.optim.PointVectorValuePair;
-import org.apache.commons.math3.optim.AbstractOptimizer;
+import org.apache.commons.math3.fitting.leastsquares.LeastSquaresOptimizer;
+import org.apache.commons.math3.fitting.leastsquares.LeastSquaresProblem;
+import org.apache.commons.math3.fitting.leastsquares.LevenbergMarquardtOptimizer;
 
 /**
  * Base class that contains common code for fitting parametric univariate
@@ -45,12 +47,10 @@ import org.apache.commons.math3.optim.Ab
  * The problem setup, such as the choice of optimization algorithm
  * for fitting a specific function is delegated to subclasses.
  *
- * @param <OPTIM> Optimizer to use for the fit.
- *
  * @version $Id$
  * @since 3.3
  */
-public abstract class AbstractCurveFitter<OPTIM extends AbstractOptimizer<PointVectorValuePair, OPTIM>> {
+public abstract class AbstractCurveFitter {
     /**
      * Fits a curve.
      * This method computes the coefficients of the curve that best
@@ -61,17 +61,30 @@ public abstract class AbstractCurveFitte
      */
     public double[] fit(Collection<WeightedObservedPoint> points) {
         // Perform the fit.
-        return getOptimizer(points).optimize().getPoint();
+        return getOptimizer().optimize(getProblem(points)).getPoint();
     }
 
     /**
      * Creates an optimizer set up to fit the appropriate curve.
+     * <p>
+     * The default implementation uses a {@link LevenbergMarquardtOptimizer
+     * Levenberg-Marquardt} optimizer.
+     * </p>
+     * @return the optimizer to use for fitting the curve to the
+     * given {@code points}.
+     */
+    protected LeastSquaresOptimizer getOptimizer() {
+        return LevenbergMarquardtOptimizer.create();
+    }
+
+    /**
+     * Creates a least squares problem corresponding to the appropriate curve.
      *
      * @param points Sample points.
-     * @return the optimizer to use for fitting the curve to the
+     * @return the least squares problem to use for fitting the curve to the
      * given {@code points}.
      */
-    protected abstract OPTIM getOptimizer(Collection<WeightedObservedPoint> points);
+    protected abstract LeastSquaresProblem getProblem(Collection<WeightedObservedPoint> points);
 
     /**
      * Vector function for computing function theoretical values.

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/GaussianCurveFitter.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/GaussianCurveFitter.java?rev=1569342&r1=1569341&r2=1569342&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/GaussianCurveFitter.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/GaussianCurveFitter.java Tue Feb 18 14:31:34 2014
@@ -21,6 +21,7 @@ import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.Collection;
 import java.util.Collections;
+
 import org.apache.commons.math3.analysis.function.Gaussian;
 import org.apache.commons.math3.linear.DiagonalMatrix;
 import org.apache.commons.math3.exception.NullArgumentException;
@@ -29,7 +30,8 @@ import org.apache.commons.math3.exceptio
 import org.apache.commons.math3.exception.ZeroException;
 import org.apache.commons.math3.exception.NotStrictlyPositiveException;
 import org.apache.commons.math3.exception.util.LocalizedFormats;
-import org.apache.commons.math3.fitting.leastsquares.LevenbergMarquardtOptimizer;
+import org.apache.commons.math3.fitting.leastsquares.LeastSquaresBuilder;
+import org.apache.commons.math3.fitting.leastsquares.LeastSquaresProblem;
 import org.apache.commons.math3.fitting.leastsquares.WithStartPoint;
 import org.apache.commons.math3.fitting.leastsquares.WithMaxIterations;
 import org.apache.commons.math3.util.FastMath;
@@ -70,7 +72,7 @@ import org.apache.commons.math3.util.Fas
  * @version $Id$
  * @since 3.3
  */
-public class GaussianCurveFitter extends AbstractCurveFitter<LevenbergMarquardtOptimizer>
+public class GaussianCurveFitter extends AbstractCurveFitter
     implements WithStartPoint<GaussianCurveFitter>,
                WithMaxIterations<GaussianCurveFitter> {
     /** Parametric function to be fitted. */
@@ -146,7 +148,8 @@ public class GaussianCurveFitter extends
 
     /** {@inheritDoc} */
     @Override
-    protected LevenbergMarquardtOptimizer getOptimizer(Collection<WeightedObservedPoint> observations) {
+    protected LeastSquaresProblem getProblem(Collection<WeightedObservedPoint> observations) {
+
         // Prepare least-squares problem.
         final int len = observations.size();
         final double[] target  = new double[len];
@@ -159,25 +162,26 @@ public class GaussianCurveFitter extends
             ++i;
         }
 
-        final AbstractCurveFitter.TheoreticalValuesFunction model
-            = new AbstractCurveFitter.TheoreticalValuesFunction(FUNCTION,
-                                                                observations);
+        final AbstractCurveFitter.TheoreticalValuesFunction model =
+                new AbstractCurveFitter.TheoreticalValuesFunction(FUNCTION, observations);
 
         final double[] startPoint = initialGuess != null ?
             initialGuess :
             // Compute estimation.
             new ParameterGuesser(observations).guess();
 
-        // Return a new optimizer set up to fit a Gaussian curve to the
+        // Return a new least squares problem set up to fit a Gaussian curve to the
         // observed points.
-        return LevenbergMarquardtOptimizer.create()
-            .withMaxEvaluations(Integer.MAX_VALUE)
-            .withMaxIterations(maxIter)
-            .withStartPoint(startPoint)
-            .withTarget(target)
-            .withWeight(new DiagonalMatrix(weights))
-            .withModelAndJacobian(model.getModelFunction(),
-                                  model.getModelFunctionJacobian());
+        return new LeastSquaresBuilder().
+                maxEvaluations(Integer.MAX_VALUE).
+                maxIterations(maxIter).
+                start(startPoint).
+                target(target).
+                weight(new DiagonalMatrix(weights)).
+                model(model.getModelFunction()).
+                jacobian(model.getModelFunctionJacobian()).
+                build();
+
     }
 
     /**

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/HarmonicCurveFitter.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/HarmonicCurveFitter.java?rev=1569342&r1=1569341&r2=1569342&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/HarmonicCurveFitter.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/HarmonicCurveFitter.java Tue Feb 18 14:31:34 2014
@@ -16,17 +16,19 @@
  */
 package org.apache.commons.math3.fitting;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
-import java.util.ArrayList;
+
 import org.apache.commons.math3.analysis.function.HarmonicOscillator;
-import org.apache.commons.math3.exception.ZeroException;
-import org.apache.commons.math3.exception.NumberIsTooSmallException;
 import org.apache.commons.math3.exception.MathIllegalStateException;
+import org.apache.commons.math3.exception.NumberIsTooSmallException;
+import org.apache.commons.math3.exception.ZeroException;
 import org.apache.commons.math3.exception.util.LocalizedFormats;
-import org.apache.commons.math3.fitting.leastsquares.LevenbergMarquardtOptimizer;
-import org.apache.commons.math3.fitting.leastsquares.WithStartPoint;
+import org.apache.commons.math3.fitting.leastsquares.LeastSquaresBuilder;
+import org.apache.commons.math3.fitting.leastsquares.LeastSquaresProblem;
 import org.apache.commons.math3.fitting.leastsquares.WithMaxIterations;
+import org.apache.commons.math3.fitting.leastsquares.WithStartPoint;
 import org.apache.commons.math3.linear.DiagonalMatrix;
 import org.apache.commons.math3.util.FastMath;
 
@@ -47,7 +49,7 @@ import org.apache.commons.math3.util.Fas
  * @version $Id$
  * @since 3.3
  */
-public class HarmonicCurveFitter extends AbstractCurveFitter<LevenbergMarquardtOptimizer>
+public class HarmonicCurveFitter extends AbstractCurveFitter
     implements WithStartPoint<HarmonicCurveFitter>,
                WithMaxIterations<HarmonicCurveFitter> {
     /** Parametric function to be fitted. */
@@ -99,7 +101,7 @@ public class HarmonicCurveFitter extends
 
     /** {@inheritDoc} */
     @Override
-    protected LevenbergMarquardtOptimizer getOptimizer(Collection<WeightedObservedPoint> observations) {
+    protected LeastSquaresProblem getProblem(Collection<WeightedObservedPoint> observations) {
         // Prepare least-squares problem.
         final int len = observations.size();
         final double[] target  = new double[len];
@@ -123,14 +125,16 @@ public class HarmonicCurveFitter extends
 
         // Return a new optimizer set up to fit a Gaussian curve to the
         // observed points.
-        return LevenbergMarquardtOptimizer.create()
-            .withMaxEvaluations(Integer.MAX_VALUE)
-            .withMaxIterations(maxIter)
-            .withStartPoint(startPoint)
-            .withTarget(target)
-            .withWeight(new DiagonalMatrix(weights))
-            .withModelAndJacobian(model.getModelFunction(),
-                                  model.getModelFunctionJacobian());
+        return new LeastSquaresBuilder().
+                maxEvaluations(Integer.MAX_VALUE).
+                maxIterations(maxIter).
+                start(startPoint).
+                target(target).
+                weight(new DiagonalMatrix(weights)).
+                model(model.getModelFunction()).
+                jacobian(model.getModelFunctionJacobian()).
+                build();
+
     }
 
     /**

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/PolynomialCurveFitter.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/PolynomialCurveFitter.java?rev=1569342&r1=1569341&r2=1569342&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/PolynomialCurveFitter.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/PolynomialCurveFitter.java Tue Feb 18 14:31:34 2014
@@ -17,11 +17,13 @@
 package org.apache.commons.math3.fitting;
 
 import java.util.Collection;
+
 import org.apache.commons.math3.analysis.polynomials.PolynomialFunction;
 import org.apache.commons.math3.exception.MathInternalError;
-import org.apache.commons.math3.fitting.leastsquares.LevenbergMarquardtOptimizer;
-import org.apache.commons.math3.fitting.leastsquares.WithStartPoint;
+import org.apache.commons.math3.fitting.leastsquares.LeastSquaresBuilder;
+import org.apache.commons.math3.fitting.leastsquares.LeastSquaresProblem;
 import org.apache.commons.math3.fitting.leastsquares.WithMaxIterations;
+import org.apache.commons.math3.fitting.leastsquares.WithStartPoint;
 import org.apache.commons.math3.linear.DiagonalMatrix;
 
 /**
@@ -37,7 +39,7 @@ import org.apache.commons.math3.linear.D
  * @version $Id$
  * @since 3.3
  */
-public class PolynomialCurveFitter extends AbstractCurveFitter<LevenbergMarquardtOptimizer>
+public class PolynomialCurveFitter extends AbstractCurveFitter
     implements WithStartPoint<PolynomialCurveFitter>,
                WithMaxIterations<PolynomialCurveFitter> {
     /** Parametric function to be fitted. */
@@ -90,7 +92,7 @@ public class PolynomialCurveFitter exten
 
     /** {@inheritDoc} */
     @Override
-    protected LevenbergMarquardtOptimizer getOptimizer(Collection<WeightedObservedPoint> observations) {
+    protected LeastSquaresProblem getProblem(Collection<WeightedObservedPoint> observations) {
         // Prepare least-squares problem.
         final int len = observations.size();
         final double[] target  = new double[len];
@@ -103,23 +105,25 @@ public class PolynomialCurveFitter exten
             ++i;
         }
 
-        final AbstractCurveFitter.TheoreticalValuesFunction model
-            = new AbstractCurveFitter.TheoreticalValuesFunction(FUNCTION,
-                                                                observations);
+        final AbstractCurveFitter.TheoreticalValuesFunction model =
+                new AbstractCurveFitter.TheoreticalValuesFunction(FUNCTION, observations);
 
         if (initialGuess == null) {
             throw new MathInternalError();
         }
 
-        // Return a new optimizer set up to fit a Gaussian curve to the
+        // Return a new least squares problem set up to fit a polynomial curve to the
         // observed points.
-        return LevenbergMarquardtOptimizer.create()
-            .withMaxEvaluations(Integer.MAX_VALUE)
-            .withMaxIterations(maxIter)
-            .withStartPoint(initialGuess)
-            .withTarget(target)
-            .withWeight(new DiagonalMatrix(weights))
-            .withModelAndJacobian(model.getModelFunction(),
-                                  model.getModelFunctionJacobian());
+        return new LeastSquaresBuilder().
+                maxEvaluations(Integer.MAX_VALUE).
+                maxIterations(maxIter).
+                start(initialGuess).
+                target(target).
+                weight(new DiagonalMatrix(weights)).
+                model(model.getModelFunction()).
+                jacobian(model.getModelFunctionJacobian()).
+                build();
+
     }
+
 }

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/GaussNewtonOptimizer.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/GaussNewtonOptimizer.java?rev=1569342&r1=1569341&r2=1569342&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/GaussNewtonOptimizer.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/GaussNewtonOptimizer.java Tue Feb 18 14:31:34 2014
@@ -16,11 +16,11 @@
  */
 package org.apache.commons.math3.fitting.leastsquares;
 
-import org.apache.commons.math3.exception.DimensionMismatchException;
 import org.apache.commons.math3.exception.ConvergenceException;
-import org.apache.commons.math3.exception.NullArgumentException;
 import org.apache.commons.math3.exception.MathInternalError;
+import org.apache.commons.math3.exception.NullArgumentException;
 import org.apache.commons.math3.exception.util.LocalizedFormats;
+import org.apache.commons.math3.fitting.leastsquares.LeastSquaresProblem.Evaluation;
 import org.apache.commons.math3.linear.ArrayRealVector;
 import org.apache.commons.math3.linear.BlockRealMatrix;
 import org.apache.commons.math3.linear.DecompositionSolver;
@@ -30,38 +30,58 @@ import org.apache.commons.math3.linear.R
 import org.apache.commons.math3.linear.SingularMatrixException;
 import org.apache.commons.math3.optim.ConvergenceChecker;
 import org.apache.commons.math3.optim.PointVectorValuePair;
+import org.apache.commons.math3.util.Incrementor;
 
 /**
- * Gauss-Newton least-squares solver.
- *
- * <p>
- * This class solve a least-square problem by solving the normal equations
- * of the linearized problem at each iteration. Either LU decomposition or
- * QR decomposition can be used to solve the normal equations. LU decomposition
- * is faster but QR decomposition is more robust for difficult problems.
+ * Gauss-Newton least-squares solver. <p/> <p> This class solve a least-square problem by
+ * solving the normal equations of the linearized problem at each iteration. Either LU
+ * decomposition or QR decomposition can be used to solve the normal equations. LU
+ * decomposition is faster but QR decomposition is more robust for difficult problems.
  * </p>
  *
  * @version $Id$
  * @since 3.3
  */
-public class GaussNewtonOptimizer extends AbstractLeastSquaresOptimizer<GaussNewtonOptimizer> {
+public class GaussNewtonOptimizer implements LeastSquaresOptimizer {
+
+    /**
+     * The singularity threshold for matrix decompositions. Determines when a {@link
+     * ConvergenceException} is thrown. The current value was the default value for {@link
+     * LUDecomposition}.
+     */
+    private static final double SINGULARITY_THRESHOLD = 1e-11;
+
     /** Indicator for using LU decomposition. */
     private boolean useLU = true;
 
     /**
-     * Default constructor.
+     * Creates a Gauss Newton optimizer.
+     *
+     * The default for the algorithm is to solve the normal equations
+     * using LU decomposition.
      */
-    protected GaussNewtonOptimizer() {}
+    public GaussNewtonOptimizer() {
+        this(true);
+    }
 
     /**
-     * Copy constructor.
+     * Creates a Gauss Newton optimizer.
      *
-     * @param other object to copy.
+     * @param useLU if {@code true} the {@link LUDecomposition} will be used to solve the
+     *              normal equations. Otherwise the {@link QRDecomposition} will be used.
      */
-    protected GaussNewtonOptimizer(GaussNewtonOptimizer other) {
-        super(other);
+    public GaussNewtonOptimizer(boolean useLU) {
+        this.useLU = useLU;
+    }
 
-        this.useLU = other.useLU;
+    /**
+     * If the LU decomposition is used in the optimization.
+     *
+     * @return {@code true} if the LU decomposition is used. {@code false} if the QR
+     *         decomposition is used.
+     */
+    public boolean isUseLU() {
+        return useLU;
     }
 
     /**
@@ -79,48 +99,20 @@ public class GaussNewtonOptimizer extend
     }
 
     /** {@inheritDoc} */
-    @Override
-    public GaussNewtonOptimizer shallowCopy() {
-        return new GaussNewtonOptimizer(this);
-    }
-
-    /**
-     * @param newUseLU Whether to use LU decomposition.
-     * @return this instance.
-     */
-    public GaussNewtonOptimizer withLU(boolean newUseLU) {
-        this.useLU = newUseLU;
-        return self();
-    }
-
-    /**
-     * @return {@code true} if LU decomposition is used.
-     */
-    public boolean getLU() {
-        return useLU;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public PointVectorValuePair doOptimize() {
+    public Optimum optimize(final LeastSquaresProblem lsp) {
+        //create local evaluation and iteration counts
+        final Incrementor evaluationCounter = lsp.getEvaluationCounter();
+        final Incrementor iterationCounter = lsp.getIterationCounter();
         final ConvergenceChecker<PointVectorValuePair> checker
-            = getConvergenceChecker();
+                = lsp.getConvergenceChecker();
 
         // Computation will be useless without a checker (see "for-loop").
         if (checker == null) {
             throw new NullArgumentException();
         }
 
-        final double[] targetValues = getTarget();
-        final int nR = targetValues.length; // Number of observed data.
-
-        final RealMatrix weightMatrix = getWeight();
-        if (weightMatrix.getRowDimension() != nR) {
-            throw new DimensionMismatchException(weightMatrix.getRowDimension(), nR);
-        }
-        if (weightMatrix.getColumnDimension() != nR) {
-            throw new DimensionMismatchException(weightMatrix.getColumnDimension(), nR);
-        }
+        final RealMatrix weightMatrix = lsp.getWeight();
+        final int nR = weightMatrix.getRowDimension(); // Number of observed data.
 
         // Diagonal of the weight matrix.
         final double[] residualsWeights = new double[nR];
@@ -128,29 +120,31 @@ public class GaussNewtonOptimizer extend
             residualsWeights[i] = weightMatrix.getEntry(i, i);
         }
 
-        final double[] currentPoint = getStart();
+        final double[] currentPoint = lsp.getStart();
         final int nC = currentPoint.length;
 
         // iterate until convergence is reached
         PointVectorValuePair current = null;
-        for (boolean converged = false; !converged;) {
-            incrementIterationCount();
+        for (boolean converged = false; !converged; ) {
+            iterationCounter.incrementCount();
 
             // evaluate the objective function and its jacobian
             PointVectorValuePair previous = current;
             // Value of the objective function at "currentPoint".
-            final double[] currentObjective = computeObjectiveValue(currentPoint);
-            final double[] currentResiduals = computeResiduals(currentObjective);
-            final RealMatrix weightedJacobian = computeWeightedJacobian(currentPoint);
+            evaluationCounter.incrementCount();
+            final Evaluation value = lsp.evaluate(currentPoint);
+            final double[] currentObjective = value.computeValue();
+            final double[] currentResiduals = value.computeResiduals();
+            final RealMatrix weightedJacobian = value.computeWeightedJacobian();
             current = new PointVectorValuePair(currentPoint, currentObjective);
 
             // build the linear problem
-            final double[]   b = new double[nC];
+            final double[] b = new double[nC];
             final double[][] a = new double[nC][nC];
             for (int i = 0; i < nR; ++i) {
 
-                final double[] grad   = weightedJacobian.getRow(i);
-                final double weight   = residualsWeights[i];
+                final double[] grad = weightedJacobian.getRow(i);
+                final double weight = residualsWeights[i];
                 final double residual = currentResiduals[i];
 
                 // compute the normal equation
@@ -171,9 +165,12 @@ public class GaussNewtonOptimizer extend
 
             // Check convergence.
             if (previous != null) {
-                converged = checker.converged(getIterations(), previous, current);
+                converged = checker.converged(iterationCounter.getCount(), previous, current);
                 if (converged) {
-                    return current;
+                    return new OptimumImpl(
+                            value,
+                            evaluationCounter.getCount(),
+                            iterationCounter.getCount());
                 }
             }
 
@@ -181,8 +178,8 @@ public class GaussNewtonOptimizer extend
                 // solve the linearized least squares problem
                 RealMatrix mA = new BlockRealMatrix(a);
                 DecompositionSolver solver = useLU ?
-                        new LUDecomposition(mA).getSolver() :
-                        new QRDecomposition(mA).getSolver();
+                        new LUDecomposition(mA, SINGULARITY_THRESHOLD).getSolver() :
+                        new QRDecomposition(mA, SINGULARITY_THRESHOLD).getSolver();
                 final double[] dX = solver.solve(new ArrayRealVector(b, false)).toArray();
                 // update the estimated parameters
                 for (int i = 0; i < nC; ++i) {
@@ -195,4 +192,12 @@ public class GaussNewtonOptimizer extend
         // Must never happen.
         throw new MathInternalError();
     }
+
+    @Override
+    public String toString() {
+        return "GaussNewtonOptimizer{" +
+                "useLU=" + useLU +
+                '}';
+    }
+
 }

Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresBuilder.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresBuilder.java?rev=1569342&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresBuilder.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresBuilder.java Tue Feb 18 14:31:34 2014
@@ -0,0 +1,66 @@
+package org.apache.commons.math3.fitting.leastsquares;
+
+import org.apache.commons.math3.analysis.MultivariateMatrixFunction;
+import org.apache.commons.math3.analysis.MultivariateVectorFunction;
+import org.apache.commons.math3.linear.RealMatrix;
+import org.apache.commons.math3.optim.ConvergenceChecker;
+import org.apache.commons.math3.optim.PointVectorValuePair;
+
+/** @author Evan Ward */
+public class LeastSquaresBuilder {
+
+    private int maxEvaluations;
+    private int maxIterations;
+    private ConvergenceChecker<PointVectorValuePair> checker;
+    private MultivariateVectorFunction model;
+    private MultivariateMatrixFunction jacobian;
+    private double[] target;
+    private double[] start;
+    private RealMatrix weight;
+
+
+    public LeastSquaresProblem build(){
+        return LeastSquaresFactory.create(model, jacobian, target, start, weight, checker, maxEvaluations, maxIterations);
+    }
+
+    public LeastSquaresBuilder maxEvaluations(final int maxEvaluations) {
+        this.maxEvaluations = maxEvaluations;
+        return this;
+    }
+
+    public LeastSquaresBuilder maxIterations(final int maxIterations) {
+        this.maxIterations = maxIterations;
+        return this;
+    }
+
+    public LeastSquaresBuilder checker(final ConvergenceChecker<PointVectorValuePair> checker) {
+        this.checker = checker;
+        return this;
+    }
+
+    public LeastSquaresBuilder model(final MultivariateVectorFunction model) {
+        this.model = model;
+        return this;
+    }
+
+    public LeastSquaresBuilder jacobian(final MultivariateMatrixFunction jacobian) {
+        this.jacobian = jacobian;
+        return this;
+    }
+
+    public LeastSquaresBuilder target(final double[] target) {
+        this.target = target;
+        return this;
+    }
+
+    public LeastSquaresBuilder start(final double[] start) {
+        this.start = start;
+        return this;
+    }
+
+    public LeastSquaresBuilder weight(final RealMatrix weight) {
+        this.weight = weight;
+        return this;
+    }
+
+}

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresBuilder.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresFactory.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresFactory.java?rev=1569342&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresFactory.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresFactory.java Tue Feb 18 14:31:34 2014
@@ -0,0 +1,102 @@
+package org.apache.commons.math3.fitting.leastsquares;
+
+import org.apache.commons.math3.analysis.MultivariateMatrixFunction;
+import org.apache.commons.math3.analysis.MultivariateVectorFunction;
+import org.apache.commons.math3.linear.RealMatrix;
+import org.apache.commons.math3.optim.ConvergenceChecker;
+import org.apache.commons.math3.optim.PointVectorValuePair;
+import org.apache.commons.math3.util.Incrementor;
+
+/** @author Evan Ward */
+public class LeastSquaresFactory {
+
+    /**
+     * Create a {@link org.apache.commons.math3.fitting.leastsquares.LeastSquaresProblem}
+     * from the given elements.
+     *
+     * @param model          the model function. Produces the computed values.
+     * @param jacobian       the jacobian of the model with respect to the parameters
+     * @param observed       the observed (target) values
+     * @param start          the initial guess.
+     * @param weight         the weight matrix
+     * @param checker        convergence checker
+     * @param maxEvaluations the maximum number of times to evaluate the model
+     * @param maxIterations  the maximum number to times to iterate in the algorithm
+     * @return the specified General Least Squares problem.
+     */
+    public static LeastSquaresProblem create(final MultivariateVectorFunction model,
+                                             final MultivariateMatrixFunction jacobian,
+                                             final double[] observed,
+                                             final double[] start,
+                                             final RealMatrix weight,
+                                             final ConvergenceChecker<PointVectorValuePair> checker,
+                                             final int maxEvaluations,
+                                             final int maxIterations) {
+        return new LeastSquaresProblemImpl(
+                maxEvaluations,
+                maxIterations,
+                checker,
+                observed,
+                weight,
+                model,
+                jacobian,
+                start
+        );
+    }
+
+    /**
+     * Count the evaluations of a particular problem. The {@code counter} will be
+     * incremented every time {@link LeastSquaresProblem#evaluate(double[])} is called on
+     * the <em>returned</em> problem.
+     *
+     * @param problem the problem to track.
+     * @param counter the counter to increment.
+     * @return a least squares problem that tracks evaluations
+     */
+    public static LeastSquaresProblem countEvaluations(final LeastSquaresProblem problem,
+                                                       final Incrementor counter) {
+        //TODO adapter?
+        return new LeastSquaresProblem() {
+
+            public Evaluation evaluate(double[] point) {
+                counter.incrementCount();
+                return problem.evaluate(point);
+            }
+
+            /* delegate the rest */
+
+            public double[] getStart() {
+                return problem.getStart();
+            }
+
+            public int getObservationSize() {
+                return problem.getObservationSize();
+            }
+
+            public int getParameterSize() {
+                return problem.getParameterSize();
+            }
+
+            public RealMatrix getWeight() {
+                return problem.getWeight();
+            }
+
+            public RealMatrix getWeightSquareRoot() {
+                return problem.getWeightSquareRoot();
+            }
+
+            public Incrementor getEvaluationCounter() {
+                return problem.getEvaluationCounter();
+            }
+
+            public Incrementor getIterationCounter() {
+                return problem.getIterationCounter();
+            }
+
+            public ConvergenceChecker<PointVectorValuePair> getConvergenceChecker() {
+                return problem.getConvergenceChecker();
+            }
+        };
+    }
+
+}

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresFactory.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresOptimizer.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresOptimizer.java?rev=1569342&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresOptimizer.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresOptimizer.java Tue Feb 18 14:31:34 2014
@@ -0,0 +1,48 @@
+package org.apache.commons.math3.fitting.leastsquares;
+
+import org.apache.commons.math3.fitting.leastsquares.LeastSquaresProblem.Evaluation;
+
+/**
+ * An algorithm that can be applied to a non-linear least squares problem.
+ *
+ * @version $Id$
+ */
+public interface LeastSquaresOptimizer {
+
+    /**
+     * Solve the non-linear least squares problem.
+     *
+     *
+     * @param leastSquaresProblem the problem definition, including model function and
+     *                            convergence criteria.
+     * @return The optimum.
+     */
+    Optimum optimize(LeastSquaresProblem leastSquaresProblem);
+
+    /**
+     * The optimum found by the optimizer. This object contains the point, its value, and
+     * some metadata.
+     */
+    //TODO Solution?
+    interface Optimum extends Evaluation {
+
+        /**
+         * Get the number of times the model was evaluated in order to produce this
+         * optimum.
+         *
+         * @return the number of model (objective) function evaluations
+         */
+        int getEvaluations();
+
+        /**
+         * Get the number of times the algorithm iterated in order to produce this
+         * optimum. In general least squares it is common to have one {@link
+         * #getEvaluations() evaluation} per iterations.
+         *
+         * @return the number of iterations
+         */
+        int getIterations();
+
+    }
+
+}

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresOptimizer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresOptimizer.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresProblem.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresProblem.java?rev=1569342&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresProblem.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresProblem.java Tue Feb 18 14:31:34 2014
@@ -0,0 +1,149 @@
+package org.apache.commons.math3.fitting.leastsquares;
+
+import org.apache.commons.math3.exception.DimensionMismatchException;
+import org.apache.commons.math3.linear.RealMatrix;
+import org.apache.commons.math3.optim.PointVectorValuePair;
+
+/**
+ * The data necessary to define a non-linear least squares problem. Includes the observed
+ * values, computed model function, weights, and convergence/divergence criteria.
+ *
+ * @author Evan Ward
+ */
+public interface LeastSquaresProblem extends OptimizationProblem<PointVectorValuePair> {
+
+    /**
+     * Gets the initial guess.
+     *
+     * @return the initial guess values.
+     */
+    double[] getStart();
+
+    /** Get the number of observations (rows in the Jacobian) in this problem.
+     *
+     * @return the number of scalar observations
+     */
+    int getObservationSize();
+
+    /** Get the number of parameters (columns in the Jacobian) in this problem.
+     *
+     * @return the number of scalar parameters
+     */
+    int getParameterSize();
+
+    /**
+     * Evaluate the model at the specified point.
+     *
+     * @param point the parameter values.
+     * @return the model's value and derivative at the given point.
+     */
+    Evaluation evaluate(double[] point);
+
+    /**
+     * Gets the weight matrix of the observations.
+     * <p/>
+     * TODO Is it possible to leave out this method and have the weights implicit in the
+     * {@link Evaluation}?
+     *
+     * @return the weight matrix.
+     */
+    RealMatrix getWeight();
+
+    /**Get the square root of the weight matrix.
+     * TODO delete this method
+     * @return the square root of the weight matrix
+     */
+    RealMatrix getWeightSquareRoot();
+
+    public interface Evaluation {
+
+        /**
+         * Get the covariance matrix of the optimized parameters. <br/> Note that this
+         * operation involves the inversion of the <code>J<sup>T</sup>J</code> matrix,
+         * where {@code J} is the Jacobian matrix. The {@code threshold} parameter is a
+         * way for the caller to specify that the result of this computation should be
+         * considered meaningless, and thus trigger an exception.
+         *
+         * @param threshold Singularity threshold.
+         * @return the covariance matrix.
+         * @throws org.apache.commons.math3.linear.SingularMatrixException
+         *          if the covariance matrix cannot be computed (singular problem).
+         */
+        double[][] computeCovariances(double threshold);
+
+        /**
+         * Computes an estimate of the standard deviation of the parameters. The returned
+         * values are the square root of the diagonal coefficients of the covariance
+         * matrix, {@code sd(a[i]) ~= sqrt(C[i][i])}, where {@code a[i]} is the optimized
+         * value of the {@code i}-th parameter, and {@code C} is the covariance matrix.
+         *
+         * @param covarianceSingularityThreshold Singularity threshold (see {@link
+         *                                       #computeCovariances(double[], double)
+         *                                       computeCovariances}).
+         * @return an estimate of the standard deviation of the optimized parameters
+         * @throws org.apache.commons.math3.linear.SingularMatrixException
+         *          if the covariance matrix cannot be computed.
+         */
+        double[] computeSigma(double covarianceSingularityThreshold);
+
+        /**
+         * Computes the normalized cost. It is the square-root of the sum of squared of
+         * the residuals, divided by the number of measurements.
+         *
+         * @return the cost.
+         */
+        double computeRMS();
+
+        /**
+         * Computes the objective (model) function value.
+         *
+         * @return the objective function value at the specified point.
+         * @throws org.apache.commons.math3.exception.TooManyEvaluationsException
+         *          if the maximal number of evaluations (of the model vector function) is
+         *          exceeded.
+         */
+        double[] computeValue();
+
+        /**
+         * Computes the weighted Jacobian matrix.
+         *
+         * @return the weighted Jacobian: W<sup>1/2</sup> J.
+         * @throws DimensionMismatchException if the Jacobian dimension does not match
+         *                                    problem dimension.
+         */
+        RealMatrix computeWeightedJacobian();
+
+        /**
+         * Computes the Jacobian matrix.
+         *
+         * @return the Jacobian at the specified point.
+         */
+        double[][] computeJacobian();
+
+        /**
+         * Computes the cost.
+         *
+         * @return the cost.
+         * @see #computeResiduals(double[])
+         */
+        double computeCost();
+
+        /**
+         * Computes the residuals. The residual is the difference between the observed
+         * (target) values and the model (objective function) value. There is one residual
+         * for each element of the vector-valued function.
+         *
+         * @return the residuals.
+         * @throws DimensionMismatchException if {@code params} has a wrong length.
+         */
+        double[] computeResiduals();
+
+
+        /**
+         * Get the abscissa (independent variables) of this evaluation.
+         *
+         * @return the point provided to {@link #evaluate(double[])}.
+         */
+        double[] getPoint();
+    }
+}

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresProblem.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresProblem.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresProblemImpl.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresProblemImpl.java?rev=1569342&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresProblemImpl.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresProblemImpl.java Tue Feb 18 14:31:34 2014
@@ -0,0 +1,257 @@
+/*
+ * 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.MultivariateMatrixFunction;
+import org.apache.commons.math3.analysis.MultivariateVectorFunction;
+import org.apache.commons.math3.exception.DimensionMismatchException;
+import org.apache.commons.math3.linear.ArrayRealVector;
+import org.apache.commons.math3.linear.DecompositionSolver;
+import org.apache.commons.math3.linear.DiagonalMatrix;
+import org.apache.commons.math3.linear.EigenDecomposition;
+import org.apache.commons.math3.linear.MatrixUtils;
+import org.apache.commons.math3.linear.QRDecomposition;
+import org.apache.commons.math3.linear.RealMatrix;
+import org.apache.commons.math3.optim.AbstractOptimizationProblem;
+import org.apache.commons.math3.optim.ConvergenceChecker;
+import org.apache.commons.math3.optim.PointVectorValuePair;
+import org.apache.commons.math3.util.FastMath;
+
+/**
+ * A private, "field" immutable (not "real" immutable) implementation of {@link
+ * LeastSquaresProblem}.
+ *
+ * @version $Id$
+ * @since 3.3
+ */
+class LeastSquaresProblemImpl
+        extends AbstractOptimizationProblem<PointVectorValuePair>
+        implements LeastSquaresProblem {
+
+    /** Target values for the model function at optimum. */
+    private double[] target;
+    /** Weight matrix. */
+    private RealMatrix weight;
+    /** Model function. */
+    private MultivariateVectorFunction model;
+    /** Jacobian of the model function. */
+    private MultivariateMatrixFunction jacobian;
+    /** Square-root of the weight matrix. */
+    private RealMatrix weightSqrt;
+    /** Initial guess. */
+    private double[] start;
+
+    LeastSquaresProblemImpl(final int maxEvaluations,
+                            final int maxIterations,
+                            final ConvergenceChecker<PointVectorValuePair> checker,
+                            final double[] target,
+                            final RealMatrix weight,
+                            final MultivariateVectorFunction model,
+                            final MultivariateMatrixFunction jacobian,
+                            final double[] start) {
+        super(maxEvaluations, maxIterations, checker);
+        this.target = target;
+        this.weight = weight;
+        this.model = model;
+        this.jacobian = jacobian;
+        this.weightSqrt = squareRoot(weight);
+        this.start = start;
+    }
+
+    public int getObservationSize() {
+        return target.length;
+    }
+
+    public int getParameterSize() {
+        return start.length;
+    }
+
+    /**
+     * Gets the target values.
+     *
+     * @return the target values.
+     */
+    public double[] getTarget() {
+        return target == null ? null : target.clone();
+    }
+
+    public double[] getStart() {
+        return start == null ? null : start.clone();
+    }
+
+    /**
+     * Gets the square-root of the weight matrix.
+     *
+     * @return the square-root of the weight matrix.
+     */
+    public RealMatrix getWeightSquareRoot() {
+        return weightSqrt == null ? null : weightSqrt.copy();
+    }
+
+    /**
+     * Gets the model function.
+     *
+     * @return the model function.
+     */
+    public MultivariateVectorFunction getModel() {
+        return model;
+    }
+
+    /**
+     * Gets the model function's Jacobian.
+     *
+     * @return the Jacobian.
+     */
+    public MultivariateMatrixFunction getJacobian() {
+        return jacobian;
+    }
+
+    public RealMatrix getWeight() {
+        return weight.copy();
+    }
+
+    public Evaluation evaluate(final double[] point) {
+        //TODO evaluate value and jacobian in one function call
+        return new EvaluationImpl(
+                this.model.value(point),
+                this.jacobian.value(point),
+                this.weight,
+                this.weightSqrt,
+                this.target,
+                point);
+    }
+
+    /**
+     * Container with the model evaluation at a particular point.
+     * <p/>
+     * TODO revisit lazy evaluation
+     */
+    private static class EvaluationImpl implements Evaluation {
+
+        /** the point of evaluation */
+        private final double[] point;
+        /** value at point */
+        private final double[] values;
+        /** deriviative at point */
+        private final double[][] jacobian;
+        /* references to data defined by the least squares problem. Not modified.
+         * Could be a reference to the problem.
+         */
+        private final RealMatrix weight;
+        private final RealMatrix weightSqrt;
+        private final double[] target;
+
+        private EvaluationImpl(final double[] values,
+                               final double[][] jacobian,
+                               final RealMatrix weight,
+                               final RealMatrix weightSqrt,
+                               final double[] target,
+                               final double[] point) {
+            this.values = values;
+            this.jacobian = jacobian;
+            this.weight = weight;
+            this.weightSqrt = weightSqrt;
+            this.target = target;
+            this.point = point;
+        }
+
+        public double[][] computeCovariances(double threshold) {
+            // Set up the Jacobian.
+            final RealMatrix j = computeWeightedJacobian();
+
+            // Compute transpose(J)J.
+            final RealMatrix jTj = j.transpose().multiply(j);
+
+            // Compute the covariances matrix.
+            final DecompositionSolver solver
+                    = new QRDecomposition(jTj, threshold).getSolver();
+            return solver.getInverse().getData();
+        }
+
+        public double[] computeSigma(double covarianceSingularityThreshold) {
+            final double[][] cov = computeCovariances(covarianceSingularityThreshold);
+            final int nC = cov.length;
+            final double[] sig = new double[nC];
+            for (int i = 0; i < nC; ++i) {
+                sig[i] = FastMath.sqrt(cov[i][i]);
+            }
+            return sig;
+        }
+
+        public double computeRMS() {
+            final double cost = computeCost();
+            return FastMath.sqrt(cost * cost / target.length);
+        }
+
+        public double[] computeValue() {
+            return this.values;
+        }
+
+        public RealMatrix computeWeightedJacobian() {
+            return weightSqrt.multiply(MatrixUtils.createRealMatrix(computeJacobian()));
+        }
+
+        public double[][] computeJacobian() {
+            return this.jacobian;
+        }
+
+        public double computeCost() {
+            final ArrayRealVector r = new ArrayRealVector(computeResiduals());
+            return FastMath.sqrt(r.dotProduct(weight.operate(r)));
+        }
+
+        public double[] computeResiduals() {
+            final double[] objectiveValue = this.computeValue();
+            if (objectiveValue.length != target.length) {
+                throw new DimensionMismatchException(target.length,
+                        objectiveValue.length);
+            }
+
+            final double[] residuals = new double[target.length];
+            for (int i = 0; i < target.length; i++) {
+                residuals[i] = target[i] - objectiveValue[i];
+            }
+
+            return residuals;
+        }
+
+        public double[] getPoint() {
+            //TODO copy?
+            return this.point;
+        }
+    }
+
+    /**
+     * Computes the square-root of the weight matrix.
+     *
+     * @param m Symmetric, positive-definite (weight) matrix.
+     * @return the square-root of the weight matrix.
+     */
+    private RealMatrix squareRoot(RealMatrix m) {
+        if (m instanceof DiagonalMatrix) {
+            final int dim = m.getRowDimension();
+            final RealMatrix sqrtM = new DiagonalMatrix(dim);
+            for (int i = 0; i < dim; i++) {
+                sqrtM.setEntry(i, i, FastMath.sqrt(m.getEntry(i, i)));
+            }
+            return sqrtM;
+        } else {
+            final EigenDecomposition dec = new EigenDecomposition(m);
+            return dec.getSquareRoot();
+        }
+    }
+}

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresProblemImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LeastSquaresProblemImpl.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LevenbergMarquardtOptimizer.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LevenbergMarquardtOptimizer.java?rev=1569342&r1=1569341&r2=1569342&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LevenbergMarquardtOptimizer.java (original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/LevenbergMarquardtOptimizer.java Tue Feb 18 14:31:34 2014
@@ -17,11 +17,14 @@
 package org.apache.commons.math3.fitting.leastsquares;
 
 import java.util.Arrays;
+
+import org.apache.commons.math3.fitting.leastsquares.LeastSquaresProblem.Evaluation;
 import org.apache.commons.math3.linear.RealMatrix;
 import org.apache.commons.math3.exception.ConvergenceException;
 import org.apache.commons.math3.exception.util.LocalizedFormats;
 import org.apache.commons.math3.optim.ConvergenceChecker;
 import org.apache.commons.math3.optim.PointVectorValuePair;
+import org.apache.commons.math3.util.Incrementor;
 import org.apache.commons.math3.util.Precision;
 import org.apache.commons.math3.util.FastMath;
 
@@ -105,7 +108,8 @@ import org.apache.commons.math3.util.Fas
  * @version $Id$
  * @since 3.3
  */
-public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer<LevenbergMarquardtOptimizer> {
+public class LevenbergMarquardtOptimizer implements LeastSquaresOptimizer {
+
     /** Twice the "epsilon machine". */
     private static final double TWO_EPS = 2 * Precision.EPSILON;
     /** Positive input variable used in determining the initial step bound. */
@@ -137,7 +141,6 @@ public class LevenbergMarquardtOptimizer
      * @param other object to copy.
      */
     protected LevenbergMarquardtOptimizer(LevenbergMarquardtOptimizer other) {
-        super(other);
 
         this.initialStepBoundFactor = other.initialStepBoundFactor;
         this.costRelativeTolerance = other.costRelativeTolerance;
@@ -169,12 +172,6 @@ public class LevenbergMarquardtOptimizer
         return new LevenbergMarquardtOptimizer();
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public LevenbergMarquardtOptimizer shallowCopy() {
-        return new LevenbergMarquardtOptimizer(this);
-    }
-
     /**
      * @param newInitialStepBoundFactor Positive input variable used in
      * determining the initial step bound. This bound is set to the
@@ -239,6 +236,14 @@ public class LevenbergMarquardtOptimizer
         return self();
     }
 
+    /** Get this.
+     *
+     * @return this
+     */
+    private LevenbergMarquardtOptimizer self(){
+        return this;
+    }
+
     /**
      * Gets the value of a tuning parameter.
      * @see #withInitialStepBoundFactor(double)
@@ -290,11 +295,18 @@ public class LevenbergMarquardtOptimizer
     }
 
     /** {@inheritDoc} */
-    @Override
-    protected PointVectorValuePair doOptimize() {
-        final int nR = getTarget().length; // Number of observed data.
-        final double[] currentPoint = getStart();
-        final int nC = currentPoint.length; // Number of parameters.
+    public Optimum optimize(final LeastSquaresProblem problem) {
+        //pull in relevant data from the problem as locals
+        final int nR = problem.getObservationSize(); // Number of observed data.
+        final int nC = problem.getParameterSize(); // Number of parameters.
+        final double[] currentPoint = problem.getStart();
+        //counters
+        final Incrementor iterationCounter = problem.getIterationCounter();
+        final Incrementor evaluationCounter = problem.getEvaluationCounter();
+        //convergence criterion
+        final ConvergenceChecker<PointVectorValuePair> checker
+                = problem.getConvergenceChecker();
+        final RealMatrix weightMatrixSqrt = problem.getWeightSquareRoot();
 
         // arrays shared with the other private methods
         final int solvedCols  = FastMath.min(nR, nC);
@@ -313,25 +325,27 @@ public class LevenbergMarquardtOptimizer
         double[] work2   = new double[nC];
         double[] work3   = new double[nC];
 
-        final RealMatrix weightMatrixSqrt = getWeightSquareRoot();
 
         // Evaluate the function at the starting point and calculate its norm.
-        double[] currentObjective = computeObjectiveValue(currentPoint);
-        double[] currentResiduals = computeResiduals(currentObjective);
+        evaluationCounter.incrementCount();
+        //value will be reassigned in the loop
+        Evaluation value = problem.evaluate(currentPoint);
+        double[] currentObjective = value.computeValue();
+        double[] currentResiduals = value.computeResiduals();
         PointVectorValuePair current = new PointVectorValuePair(currentPoint, currentObjective);
-        double currentCost = computeCost(currentResiduals);
+        double currentCost = value.computeCost();
 
         // Outer loop.
         boolean firstIteration = true;
-        final ConvergenceChecker<PointVectorValuePair> checker = getConvergenceChecker();
         while (true) {
-            incrementIterationCount();
+            iterationCounter.incrementCount();
 
             final PointVectorValuePair previous = current;
+            final Evaluation previousValue = value;
 
             // QR decomposition of the jacobian matrix
-            final InternalData internalData = qrDecomposition(computeWeightedJacobian(currentPoint),
-                                                              solvedCols);
+            final InternalData internalData
+                    = qrDecomposition(value.computeWeightedJacobian(), solvedCols);
             final double[][] weightedJacobian = internalData.weightedJacobian;
             final int[] permutation = internalData.permutation;
             final double[] diagR = internalData.diagR;
@@ -388,7 +402,10 @@ public class LevenbergMarquardtOptimizer
             }
             if (maxCosine <= orthoTolerance) {
                 // Convergence has been reached.
-                return current;
+                return new OptimumImpl(
+                        value,
+                        evaluationCounter.getCount(),
+                        iterationCounter.getCount());
             }
 
             // rescale if necessary
@@ -433,10 +450,12 @@ public class LevenbergMarquardtOptimizer
                 }
 
                 // Evaluate the function at x + p and calculate its norm.
-                currentObjective = computeObjectiveValue(currentPoint);
-                currentResiduals = computeResiduals(currentObjective);
+                evaluationCounter.incrementCount();
+                value = problem.evaluate(currentPoint);
+                currentObjective = value.computeValue();
+                currentResiduals = value.computeResiduals();
                 current = new PointVectorValuePair(currentPoint, currentObjective);
-                currentCost = computeCost(currentResiduals);
+                currentCost = value.computeCost();
 
                 // compute the scaled actual reduction
                 double actRed = -1.0;
@@ -494,8 +513,8 @@ public class LevenbergMarquardtOptimizer
                     xNorm = FastMath.sqrt(xNorm);
 
                     // tests for convergence.
-                    if (checker != null && checker.converged(getIterations(), previous, current)) {
-                        return current;
+                    if (checker != null && checker.converged(iterationCounter.getCount(), previous, current)) {
+                        return new OptimumImpl(value, iterationCounter.getCount(), evaluationCounter.getCount());
                     }
                 } else {
                     // failed iteration, reset the previous values
@@ -512,6 +531,7 @@ public class LevenbergMarquardtOptimizer
                     oldObj    = tmpVec;
                     // Reset "current" to previous values.
                     current = new PointVectorValuePair(currentPoint, currentObjective);
+                    value = previousValue;
                 }
 
                 // Default convergence criteria.
@@ -519,7 +539,7 @@ public class LevenbergMarquardtOptimizer
                      preRed <= costRelativeTolerance &&
                      ratio <= 2.0) ||
                     delta <= parRelativeTolerance * xNorm) {
-                    return current;
+                    return new OptimumImpl(value, iterationCounter.getCount(), evaluationCounter.getCount());
                 }
 
                 // tests for termination and stringent tolerances

Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/OptimizationProblem.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/OptimizationProblem.java?rev=1569342&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/OptimizationProblem.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/OptimizationProblem.java Tue Feb 18 14:31:34 2014
@@ -0,0 +1,30 @@
+package org.apache.commons.math3.fitting.leastsquares;
+
+import org.apache.commons.math3.optim.ConvergenceChecker;
+import org.apache.commons.math3.util.Incrementor;
+
+/** @author Evan Ward */
+public interface OptimizationProblem<PAIR> {
+    /**
+     * Get a independent Incrementor that counts up to {@link #getMaxEvaluations()} and
+     * then throws an exception.
+     *
+     * @return a counter for the evaluations.
+     */
+    Incrementor getEvaluationCounter();
+
+    /**
+     * Get a independent Incrementor that counts up to {@link #getMaxIterations()} and
+     * then throws an exception.
+     *
+     * @return a counter for the evaluations.
+     */
+    Incrementor getIterationCounter();
+
+    /**
+     * Gets the convergence checker.
+     *
+     * @return the object used to check for convergence.
+     */
+    ConvergenceChecker<PAIR> getConvergenceChecker();
+}

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/OptimizationProblem.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/OptimizationProblem.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/OptimumImpl.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/OptimumImpl.java?rev=1569342&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/OptimumImpl.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/OptimumImpl.java Tue Feb 18 14:31:34 2014
@@ -0,0 +1,90 @@
+package org.apache.commons.math3.fitting.leastsquares;
+
+import org.apache.commons.math3.fitting.leastsquares.LeastSquaresOptimizer.Optimum;
+import org.apache.commons.math3.fitting.leastsquares.LeastSquaresProblem.Evaluation;
+import org.apache.commons.math3.linear.RealMatrix;
+
+/**
+ * A pedantic implementation of {@link Optimum}.
+ *
+ * @version $Id$
+ */
+class OptimumImpl implements Optimum {
+
+    /** abscissa and ordinate */
+    private final Evaluation value;
+    /** number of evaluations to compute this optimum */
+    private final int evaluations;
+    /** number of iterations to compute this optimum */
+    private final int iterations;
+
+    /**
+     * Construct an optimum from an evaluation and the values of the counters.
+     *
+     * @param value       the function value
+     * @param evaluations number of times the function was evaluated
+     * @param iterations  number of iterations of the algorithm
+     */
+    OptimumImpl(final Evaluation value, final int evaluations, final int iterations) {
+        this.value = value;
+        this.evaluations = evaluations;
+        this.iterations = iterations;
+    }
+
+    /* auto-generated implementations */
+
+    /** {@inheritDoc} */
+    public int getEvaluations() {
+        return evaluations;
+    }
+
+    /** {@inheritDoc} */
+    public int getIterations() {
+        return iterations;
+    }
+
+    /** {@inheritDoc} */
+    public double[][] computeCovariances(double threshold) {
+        return value.computeCovariances(threshold);
+    }
+
+    /** {@inheritDoc} */
+    public double[] computeSigma(double covarianceSingularityThreshold) {
+        return value.computeSigma(covarianceSingularityThreshold);
+    }
+
+    /** {@inheritDoc} */
+    public double computeRMS() {
+        return value.computeRMS();
+    }
+
+    /** {@inheritDoc} */
+    public double[] computeValue() {
+        return value.computeValue();
+    }
+
+    /** {@inheritDoc} */
+    public RealMatrix computeWeightedJacobian() {
+        return value.computeWeightedJacobian();
+    }
+
+    /** {@inheritDoc} */
+    public double[][] computeJacobian() {
+        return value.computeJacobian();
+    }
+
+    /** {@inheritDoc} */
+    public double computeCost() {
+        return value.computeCost();
+    }
+
+    /** {@inheritDoc} */
+    public double[] computeResiduals() {
+        return value.computeResiduals();
+    }
+
+    /** {@inheritDoc} */
+    public double[] getPoint() {
+        return value.getPoint();
+    }
+}

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/OptimumImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/fitting/leastsquares/OptimumImpl.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"

Added: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optim/AbstractOptimizationProblem.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optim/AbstractOptimizationProblem.java?rev=1569342&view=auto
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optim/AbstractOptimizationProblem.java (added)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optim/AbstractOptimizationProblem.java Tue Feb 18 14:31:34 2014
@@ -0,0 +1,96 @@
+/*
+ * 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.optim;
+
+import org.apache.commons.math3.exception.TooManyEvaluationsException;
+import org.apache.commons.math3.exception.TooManyIterationsException;
+import org.apache.commons.math3.fitting.leastsquares.OptimizationProblem;
+import org.apache.commons.math3.util.Incrementor;
+
+/**
+ * Base class for implementing optimizers. It contains the boiler-plate code for counting
+ * the number of evaluations of the objective function and the number of iterations of the
+ * algorithm, and storing the convergence checker.
+ *
+ * @param <PAIR>  Type of the point/value pair returned by the optimization algorithm.
+ * @param <OPTIM> Type of a subclass of this class. This parameter allows to implement
+ *                fluent API methods at upper levels of the class hierarchy (since the
+ *                fluent API requires that the actual type of the subclass is returned).
+ * @version $Id$
+ * @since 3.3
+ */
+public abstract class AbstractOptimizationProblem<PAIR>
+        implements OptimizationProblem<PAIR> {
+
+    /** max evaluations */
+    private final int maxEvaluations;
+    /** max iterations */
+    private final int maxIterations;
+    /** Convergence checker. */
+    private ConvergenceChecker<PAIR> checker = null;
+
+
+    public Incrementor getEvaluationCounter() {
+        return new Incrementor(this.maxEvaluations, MAX_EVAL_CALLBACK);
+    }
+
+    public Incrementor getIterationCounter() {
+        return new Incrementor(this.maxIterations, MAX_ITER_CALLBACK);
+    }
+
+    protected AbstractOptimizationProblem(final int maxEvaluations,
+                                          final int maxIterations,
+                                          final ConvergenceChecker<PAIR> checker) {
+        this.maxEvaluations = maxEvaluations;
+        this.maxIterations = maxIterations;
+        this.checker = checker;
+    }
+
+    public ConvergenceChecker<PAIR> getConvergenceChecker() {
+        return checker;
+    }
+
+    /** Defines the action to perform when reaching the maximum number of evaluations. */
+    private static class MaxEvalCallback
+            implements Incrementor.MaxCountExceededCallback {
+        /**
+         * {@inheritDoc}
+         *
+         * @throws TooManyEvaluationsException
+         */
+        public void trigger(int max) {
+            throw new TooManyEvaluationsException(max);
+        }
+    }
+
+    private static final MaxEvalCallback MAX_EVAL_CALLBACK = new MaxEvalCallback();
+
+    /** Defines the action to perform when reaching the maximum number of evaluations. */
+    private static class MaxIterCallback
+            implements Incrementor.MaxCountExceededCallback {
+        /**
+         * {@inheritDoc}
+         *
+         * @throws TooManyIterationsException
+         */
+        public void trigger(int max) {
+            throw new TooManyIterationsException(max);
+        }
+    }
+
+    private static final MaxIterCallback MAX_ITER_CALLBACK = new MaxIterCallback();
+}

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optim/AbstractOptimizationProblem.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: commons/proper/math/trunk/src/main/java/org/apache/commons/math3/optim/AbstractOptimizationProblem.java
------------------------------------------------------------------------------
    svn:keywords = "Author Date Id Revision"



Mime
View raw message