Code simplified in AbstractLeastSquaresOptimizer

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/math/trunk@985828 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Dimitri Pourbaix 2010-08-16 08:45:10 +00:00
parent 19f58cfa37
commit 93362abb9b
4 changed files with 53 additions and 56 deletions

View File

@ -50,13 +50,13 @@ public abstract class AbstractLeastSquaresOptimizer implements DifferentiableMul
protected VectorialConvergenceChecker checker; protected VectorialConvergenceChecker checker;
/** /**
* Jacobian matrix. * Jacobian matrix of the weighted residuals.
* <p>This matrix is in canonical form just after the calls to * <p>This matrix is in canonical form just after the calls to
* {@link #updateJacobian()}, but may be modified by the solver * {@link #updateJacobian()}, but may be modified by the solver
* in the derived class (the {@link LevenbergMarquardtOptimizer * in the derived class (the {@link LevenbergMarquardtOptimizer
* Levenberg-Marquardt optimizer} does this).</p> * Levenberg-Marquardt optimizer} does this).</p>
*/ */
protected double[][] jacobian; protected double[][] weightedResidualJacobian;
/** Number of columns of the jacobian matrix. */ /** Number of columns of the jacobian matrix. */
protected int cols; protected int cols;
@ -81,15 +81,9 @@ public abstract class AbstractLeastSquaresOptimizer implements DifferentiableMul
/** Current objective function value. */ /** Current objective function value. */
protected double[] objective; protected double[] objective;
/** Current residuals. */
protected double[] residuals;
/** Weighted Jacobian */
protected double[][] wjacobian;
/** Weighted residuals */ /** Weighted residuals */
protected double[] wresiduals; protected double[] weightedResiduals;
/** Cost value (square root of the sum of the residuals). */ /** Cost value (square root of the sum of the residuals). */
protected double cost; protected double cost;
@ -188,17 +182,17 @@ public abstract class AbstractLeastSquaresOptimizer implements DifferentiableMul
*/ */
protected void updateJacobian() throws FunctionEvaluationException { protected void updateJacobian() throws FunctionEvaluationException {
++jacobianEvaluations; ++jacobianEvaluations;
jacobian = jF.value(point); weightedResidualJacobian = jF.value(point);
if (jacobian.length != rows) { if (weightedResidualJacobian.length != rows) {
throw new FunctionEvaluationException(point, LocalizedFormats.DIMENSIONS_MISMATCH_SIMPLE, throw new FunctionEvaluationException(point, LocalizedFormats.DIMENSIONS_MISMATCH_SIMPLE,
jacobian.length, rows); weightedResidualJacobian.length, rows);
} }
for (int i = 0; i < rows; i++) { for (int i = 0; i < rows; i++) {
final double[] ji = jacobian[i]; final double[] ji = weightedResidualJacobian[i];
double wi = Math.sqrt(residualsWeights[i]); double wi = Math.sqrt(residualsWeights[i]);
for (int j = 0; j < cols; ++j) { for (int j = 0; j < cols; ++j) {
ji[j] *= -1.0; //ji[j] *= -1.0;
wjacobian[i][j] = ji[j]*wi; weightedResidualJacobian[i][j] = -ji[j]*wi;
} }
} }
} }
@ -225,8 +219,7 @@ public abstract class AbstractLeastSquaresOptimizer implements DifferentiableMul
int index = 0; int index = 0;
for (int i = 0; i < rows; i++) { for (int i = 0; i < rows; i++) {
final double residual = targetValues[i] - objective[i]; final double residual = targetValues[i] - objective[i];
residuals[i] = residual; weightedResiduals[i]= residual*Math.sqrt(residualsWeights[i]);
wresiduals[i]= residual*Math.sqrt(residualsWeights[i]);
cost += residualsWeights[i] * residual * residual; cost += residualsWeights[i] * residual * residual;
index += cols; index += cols;
} }
@ -278,7 +271,7 @@ public abstract class AbstractLeastSquaresOptimizer implements DifferentiableMul
for (int j = i; j < cols; ++j) { for (int j = i; j < cols; ++j) {
double sum = 0; double sum = 0;
for (int k = 0; k < rows; ++k) { for (int k = 0; k < rows; ++k) {
sum += wjacobian[k][i] * wjacobian[k][j]; sum += weightedResidualJacobian[k][i] * weightedResidualJacobian[k][j];
} }
jTj[i][j] = sum; jTj[i][j] = sum;
jTj[j][i] = sum; jTj[j][i] = sum;
@ -343,15 +336,13 @@ public abstract class AbstractLeastSquaresOptimizer implements DifferentiableMul
targetValues = target.clone(); targetValues = target.clone();
residualsWeights = weights.clone(); residualsWeights = weights.clone();
this.point = startPoint.clone(); this.point = startPoint.clone();
this.residuals = new double[target.length];
// arrays shared with the other private methods // arrays shared with the other private methods
rows = target.length; rows = target.length;
cols = point.length; cols = point.length;
jacobian = new double[rows][cols];
wjacobian = new double[rows][cols]; weightedResidualJacobian = new double[rows][cols];
wresiduals = new double[rows]; this.weightedResiduals = new double[rows];
cost = Double.POSITIVE_INFINITY; cost = Double.POSITIVE_INFINITY;

View File

@ -81,7 +81,7 @@ public class GaussNewtonOptimizer extends AbstractLeastSquaresOptimizer {
final double[][] a = new double[cols][cols]; final double[][] a = new double[cols][cols];
for (int i = 0; i < rows; ++i) { for (int i = 0; i < rows; ++i) {
final double[] grad = jacobian[i]; final double[] grad = weightedResidualJacobian[i];
final double weight = residualsWeights[i]; final double weight = residualsWeights[i];
final double residual = objective[i] - targetValues[i]; final double residual = objective[i] - targetValues[i];

View File

@ -270,7 +270,7 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
VectorialPointValuePair current = new VectorialPointValuePair(point, objective); VectorialPointValuePair current = new VectorialPointValuePair(point, objective);
while (true) { while (true) {
for (int i=0;i<rows;i++) { for (int i=0;i<rows;i++) {
qtf[i]=wresiduals[i]; qtf[i]=weightedResiduals[i];
} }
incrementIterationsCounter(); incrementIterationsCounter();
@ -285,7 +285,7 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
// so let jacobian contain the R matrix with its diagonal elements // so let jacobian contain the R matrix with its diagonal elements
for (int k = 0; k < solvedCols; ++k) { for (int k = 0; k < solvedCols; ++k) {
int pk = permutation[k]; int pk = permutation[k];
wjacobian[k][pk] = diagR[pk]; weightedResidualJacobian[k][pk] = diagR[pk];
} }
if (firstIteration) { if (firstIteration) {
@ -318,7 +318,7 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
if (s != 0) { if (s != 0) {
double sum = 0; double sum = 0;
for (int i = 0; i <= j; ++i) { for (int i = 0; i <= j; ++i) {
sum += wjacobian[i][pj] * qtf[i]; sum += weightedResidualJacobian[i][pj] * qtf[i];
} }
maxCosine = Math.max(maxCosine, Math.abs(sum) / (s * cost)); maxCosine = Math.max(maxCosine, Math.abs(sum) / (s * cost));
} }
@ -345,8 +345,8 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
oldX[pj] = point[pj]; oldX[pj] = point[pj];
} }
double previousCost = cost; double previousCost = cost;
double[] tmpVec = residuals; double[] tmpVec = weightedResiduals;
residuals = oldRes; weightedResiduals = oldRes;
oldRes = tmpVec; oldRes = tmpVec;
tmpVec = objective; tmpVec = objective;
objective = oldObj; objective = oldObj;
@ -387,7 +387,7 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
double dirJ = lmDir[pj]; double dirJ = lmDir[pj];
work1[j] = 0; work1[j] = 0;
for (int i = 0; i <= j; ++i) { for (int i = 0; i <= j; ++i) {
work1[i] += wjacobian[i][pj] * dirJ; work1[i] += weightedResidualJacobian[i][pj] * dirJ;
} }
} }
double coeff1 = 0; double coeff1 = 0;
@ -443,8 +443,8 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
int pj = permutation[j]; int pj = permutation[j];
point[pj] = oldX[pj]; point[pj] = oldX[pj];
} }
tmpVec = residuals; tmpVec = weightedResiduals;
residuals = oldRes; weightedResiduals = oldRes;
oldRes = tmpVec; oldRes = tmpVec;
tmpVec = objective; tmpVec = objective;
objective = oldObj; objective = oldObj;
@ -514,7 +514,7 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
int pk = permutation[k]; int pk = permutation[k];
double ypk = lmDir[pk] / diagR[pk]; double ypk = lmDir[pk] / diagR[pk];
for (int i = 0; i < k; ++i) { for (int i = 0; i < k; ++i) {
lmDir[permutation[i]] -= ypk * wjacobian[i][pk]; lmDir[permutation[i]] -= ypk * weightedResidualJacobian[i][pk];
} }
lmDir[pk] = ypk; lmDir[pk] = ypk;
} }
@ -550,7 +550,7 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
int pj = permutation[j]; int pj = permutation[j];
double sum = 0; double sum = 0;
for (int i = 0; i < j; ++i) { for (int i = 0; i < j; ++i) {
sum += wjacobian[i][pj] * work1[permutation[i]]; sum += weightedResidualJacobian[i][pj] * work1[permutation[i]];
} }
double s = (work1[pj] - sum) / diagR[pj]; double s = (work1[pj] - sum) / diagR[pj];
work1[pj] = s; work1[pj] = s;
@ -565,7 +565,7 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
int pj = permutation[j]; int pj = permutation[j];
double sum = 0; double sum = 0;
for (int i = 0; i <= j; ++i) { for (int i = 0; i <= j; ++i) {
sum += wjacobian[i][pj] * qy[i]; sum += weightedResidualJacobian[i][pj] * qy[i];
} }
sum /= diag[pj]; sum /= diag[pj];
sum2 += sum * sum; sum2 += sum * sum;
@ -625,7 +625,7 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
work1[pj] /= work2[j]; work1[pj] /= work2[j];
double tmp = work1[pj]; double tmp = work1[pj];
for (int i = j + 1; i < solvedCols; ++i) { for (int i = j + 1; i < solvedCols; ++i) {
work1[permutation[i]] -= wjacobian[i][pj] * tmp; work1[permutation[i]] -= weightedResidualJacobian[i][pj] * tmp;
} }
} }
sum2 = 0; sum2 = 0;
@ -676,7 +676,7 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
for (int j = 0; j < solvedCols; ++j) { for (int j = 0; j < solvedCols; ++j) {
int pj = permutation[j]; int pj = permutation[j];
for (int i = j + 1; i < solvedCols; ++i) { for (int i = j + 1; i < solvedCols; ++i) {
wjacobian[i][pj] = wjacobian[j][permutation[i]]; weightedResidualJacobian[i][pj] = weightedResidualJacobian[j][permutation[i]];
} }
lmDir[j] = diagR[pj]; lmDir[j] = diagR[pj];
work[j] = qy[j]; work[j] = qy[j];
@ -707,7 +707,7 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
final double sin; final double sin;
final double cos; final double cos;
double rkk = wjacobian[k][pk]; double rkk = weightedResidualJacobian[k][pk];
if (Math.abs(rkk) < Math.abs(lmDiag[k])) { if (Math.abs(rkk) < Math.abs(lmDiag[k])) {
final double cotan = rkk / lmDiag[k]; final double cotan = rkk / lmDiag[k];
sin = 1.0 / Math.sqrt(1.0 + cotan * cotan); sin = 1.0 / Math.sqrt(1.0 + cotan * cotan);
@ -720,17 +720,17 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
// compute the modified diagonal element of R and // compute the modified diagonal element of R and
// the modified element of (Qty,0) // the modified element of (Qty,0)
wjacobian[k][pk] = cos * rkk + sin * lmDiag[k]; weightedResidualJacobian[k][pk] = cos * rkk + sin * lmDiag[k];
final double temp = cos * work[k] + sin * qtbpj; final double temp = cos * work[k] + sin * qtbpj;
qtbpj = -sin * work[k] + cos * qtbpj; qtbpj = -sin * work[k] + cos * qtbpj;
work[k] = temp; work[k] = temp;
// accumulate the tranformation in the row of s // accumulate the tranformation in the row of s
for (int i = k + 1; i < solvedCols; ++i) { for (int i = k + 1; i < solvedCols; ++i) {
double rik = wjacobian[i][pk]; double rik = weightedResidualJacobian[i][pk];
final double temp2 = cos * rik + sin * lmDiag[i]; final double temp2 = cos * rik + sin * lmDiag[i];
lmDiag[i] = -sin * rik + cos * lmDiag[i]; lmDiag[i] = -sin * rik + cos * lmDiag[i];
wjacobian[i][pk] = temp2; weightedResidualJacobian[i][pk] = temp2;
} }
} }
@ -738,8 +738,8 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
// store the diagonal element of s and restore // store the diagonal element of s and restore
// the corresponding diagonal element of R // the corresponding diagonal element of R
lmDiag[j] = wjacobian[j][permutation[j]]; lmDiag[j] = weightedResidualJacobian[j][permutation[j]];
wjacobian[j][permutation[j]] = lmDir[j]; weightedResidualJacobian[j][permutation[j]] = lmDir[j];
} }
@ -759,7 +759,7 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
int pj = permutation[j]; int pj = permutation[j];
double sum = 0; double sum = 0;
for (int i = j + 1; i < nSing; ++i) { for (int i = j + 1; i < nSing; ++i) {
sum += wjacobian[i][pj] * work[i]; sum += weightedResidualJacobian[i][pj] * work[i];
} }
work[j] = (work[j] - sum) / lmDiag[j]; work[j] = (work[j] - sum) / lmDiag[j];
} }
@ -800,8 +800,8 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
for (int k = 0; k < cols; ++k) { for (int k = 0; k < cols; ++k) {
permutation[k] = k; permutation[k] = k;
double norm2 = 0; double norm2 = 0;
for (int i = 0; i < wjacobian.length; ++i) { for (int i = 0; i < weightedResidualJacobian.length; ++i) {
double akk = wjacobian[i][k]; double akk = weightedResidualJacobian[i][k];
norm2 += akk * akk; norm2 += akk * akk;
} }
jacNorm[k] = Math.sqrt(norm2); jacNorm[k] = Math.sqrt(norm2);
@ -815,8 +815,8 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
double ak2 = Double.NEGATIVE_INFINITY; double ak2 = Double.NEGATIVE_INFINITY;
for (int i = k; i < cols; ++i) { for (int i = k; i < cols; ++i) {
double norm2 = 0; double norm2 = 0;
for (int j = k; j < wjacobian.length; ++j) { for (int j = k; j < weightedResidualJacobian.length; ++j) {
double aki = wjacobian[j][permutation[i]]; double aki = weightedResidualJacobian[j][permutation[i]];
norm2 += aki * aki; norm2 += aki * aki;
} }
if (Double.isInfinite(norm2) || Double.isNaN(norm2)) { if (Double.isInfinite(norm2) || Double.isNaN(norm2)) {
@ -837,24 +837,24 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
permutation[k] = pk; permutation[k] = pk;
// choose alpha such that Hk.u = alpha ek // choose alpha such that Hk.u = alpha ek
double akk = wjacobian[k][pk]; double akk = weightedResidualJacobian[k][pk];
double alpha = (akk > 0) ? -Math.sqrt(ak2) : Math.sqrt(ak2); double alpha = (akk > 0) ? -Math.sqrt(ak2) : Math.sqrt(ak2);
double betak = 1.0 / (ak2 - akk * alpha); double betak = 1.0 / (ak2 - akk * alpha);
beta[pk] = betak; beta[pk] = betak;
// transform the current column // transform the current column
diagR[pk] = alpha; diagR[pk] = alpha;
wjacobian[k][pk] -= alpha; weightedResidualJacobian[k][pk] -= alpha;
// transform the remaining columns // transform the remaining columns
for (int dk = cols - 1 - k; dk > 0; --dk) { for (int dk = cols - 1 - k; dk > 0; --dk) {
double gamma = 0; double gamma = 0;
for (int j = k; j < wjacobian.length; ++j) { for (int j = k; j < weightedResidualJacobian.length; ++j) {
gamma += wjacobian[j][pk] * wjacobian[j][permutation[k + dk]]; gamma += weightedResidualJacobian[j][pk] * weightedResidualJacobian[j][permutation[k + dk]];
} }
gamma *= betak; gamma *= betak;
for (int j = k; j < wjacobian.length; ++j) { for (int j = k; j < weightedResidualJacobian.length; ++j) {
wjacobian[j][permutation[k + dk]] -= gamma * wjacobian[j][pk]; weightedResidualJacobian[j][permutation[k + dk]] -= gamma * weightedResidualJacobian[j][pk];
} }
} }
@ -874,11 +874,11 @@ public class LevenbergMarquardtOptimizer extends AbstractLeastSquaresOptimizer {
int pk = permutation[k]; int pk = permutation[k];
double gamma = 0; double gamma = 0;
for (int i = k; i < rows; ++i) { for (int i = k; i < rows; ++i) {
gamma += wjacobian[i][pk] * y[i]; gamma += weightedResidualJacobian[i][pk] * y[i];
} }
gamma *= beta[pk]; gamma *= beta[pk];
for (int i = k; i < rows; ++i) { for (int i = k; i < rows; ++i) {
y[i] -= gamma * wjacobian[i][pk]; y[i] -= gamma * weightedResidualJacobian[i][pk];
} }
} }
} }

View File

@ -52,8 +52,14 @@ The <action> type attribute can be add,update,fix,remove.
If the output is not quite correct, check for invisible trailing spaces! If the output is not quite correct, check for invisible trailing spaces!
--> -->
<release version="2.2" date="TBD" description="TBD"> <release version="2.2" date="TBD" description="TBD">
<action dev="dimpbx" type="fix" issue="MATH-406">
Bug fixed in Levenberg-Marquardt (handling of weights).
</action>
<action dev="dimpbx" type="fix" issue="MATH-405">
Bug fixed in Levenberg-Marquardt (consistency of current).
</action>
<action dev="dimpbx" type="fix" issue="MATH-377"> <action dev="dimpbx" type="fix" issue="MATH-377">
Fixed bug in chi-square computation in AbstractLeastSquaresOptimizer. Bug fixed in chi-square computation in AbstractLeastSquaresOptimizer.
</action> </action>
<action dev="luc" type="add" issue="MATH-400" due-to="J. Lewis Muir"> <action dev="luc" type="add" issue="MATH-400" due-to="J. Lewis Muir">
Added support for Gaussian curve fitting. Added support for Gaussian curve fitting.