📄 levenbergmarquardtestimator.java
字号:
/* * 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.math.estimation;import java.io.Serializable;import java.util.Arrays;/** * This class solves a least squares problem. * * <p>This implementation <em>should</em> work even for over-determined systems * (i.e. systems having more variables than equations). Over-determined systems * are solved by ignoring the variables which have the smallest impact according * to their jacobian column norm. Only the rank of the matrix and some loop bounds * are changed to implement this. This feature has undergone only basic testing * for now and should still be considered experimental.</p> * * <p>The resolution engine is a simple translation of the MINPACK <a * href="http://www.netlib.org/minpack/lmder.f">lmder</a> routine with minor * changes. The changes include the over-determined resolution and the Q.R. * decomposition which has been rewritten following the algorithm described in the * P. Lascaux and R. Theodor book <i>Analyse numérique matricielle * appliquée à l'art de l'ingénieur</i>, Masson 1986. The * redistribution policy for MINPACK is available <a * href="http://www.netlib.org/minpack/disclaimer">here</a>, for convenience, it * is reproduced below.</p> * * <table border="0" width="80%" cellpadding="10" align="center" bgcolor="#E0E0E0"> * <tr><td> * Minpack Copyright Notice (1999) University of Chicago. * All rights reserved * </td></tr> * <tr><td> * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * <ol> * <li>Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer.</li> * <li>Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution.</li> * <li>The end-user documentation included with the redistribution, if any, * must include the following acknowledgment: * <code>This product includes software developed by the University of * Chicago, as Operator of Argonne National Laboratory.</code> * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear.</li> * <li><strong>WARRANTY DISCLAIMER. THE SOFTWARE IS SUPPLIED "AS IS" * WITHOUT WARRANTY OF ANY KIND. THE COPYRIGHT HOLDER, THE * UNITED STATES, THE UNITED STATES DEPARTMENT OF ENERGY, AND * THEIR EMPLOYEES: (1) DISCLAIM ANY WARRANTIES, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO ANY IMPLIED WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE * OR NON-INFRINGEMENT, (2) DO NOT ASSUME ANY LEGAL LIABILITY * OR RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR * USEFULNESS OF THE SOFTWARE, (3) DO NOT REPRESENT THAT USE OF * THE SOFTWARE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS, (4) * DO NOT WARRANT THAT THE SOFTWARE WILL FUNCTION * UNINTERRUPTED, THAT IT IS ERROR-FREE OR THAT ANY ERRORS WILL * BE CORRECTED.</strong></li> * <li><strong>LIMITATION OF LIABILITY. IN NO EVENT WILL THE COPYRIGHT * HOLDER, THE UNITED STATES, THE UNITED STATES DEPARTMENT OF * ENERGY, OR THEIR EMPLOYEES: BE LIABLE FOR ANY INDIRECT, * INCIDENTAL, CONSEQUENTIAL, SPECIAL OR PUNITIVE DAMAGES OF * ANY KIND OR NATURE, INCLUDING BUT NOT LIMITED TO LOSS OF * PROFITS OR LOSS OF DATA, FOR ANY REASON WHATSOEVER, WHETHER * SUCH LIABILITY IS ASSERTED ON THE BASIS OF CONTRACT, TORT * (INCLUDING NEGLIGENCE OR STRICT LIABILITY), OR OTHERWISE, * EVEN IF ANY OF SAID PARTIES HAS BEEN WARNED OF THE * POSSIBILITY OF SUCH LOSS OR DAMAGES.</strong></li> * <ol></td></tr> * </table> * @author Argonne National Laboratory. MINPACK project. March 1980 (original fortran) * @author Burton S. Garbow (original fortran) * @author Kenneth E. Hillstrom (original fortran) * @author Jorge J. More (original fortran) * @version $Revision: 620312 $ $Date: 2008-02-10 12:28:59 -0700 (Sun, 10 Feb 2008) $ * @since 1.2 * */public class LevenbergMarquardtEstimator extends AbstractEstimator implements Serializable { /** * Build an estimator for least squares problems. * <p>The default values for the algorithm settings are: * <ul> * <li>{@link #setInitialStepBoundFactor initial step bound factor}: 100.0</li> * <li>{@link #setMaxCostEval maximal cost evaluations}: 1000</li> * <li>{@link #setCostRelativeTolerance cost relative tolerance}: 1.0e-10</li> * <li>{@link #setParRelativeTolerance parameters relative tolerance}: 1.0e-10</li> * <li>{@link #setOrthoTolerance orthogonality tolerance}: 1.0e-10</li> * </ul> * </p> */ public LevenbergMarquardtEstimator() { // set up the superclass with a default max cost evaluations setting setMaxCostEval(1000); // default values for the tuning parameters setInitialStepBoundFactor(100.0); setCostRelativeTolerance(1.0e-10); setParRelativeTolerance(1.0e-10); setOrthoTolerance(1.0e-10); } /** * Set the positive input variable used in determining the initial step bound. * This bound is set to the product of initialStepBoundFactor and the euclidean norm of diag*x if nonzero, * or else to initialStepBoundFactor itself. In most cases factor should lie * in the interval (0.1, 100.0). 100.0 is a generally recommended value * * @param initialStepBoundFactor initial step bound factor * @see #estimate */ public void setInitialStepBoundFactor(double initialStepBoundFactor) { this.initialStepBoundFactor = initialStepBoundFactor; } /** * Set the desired relative error in the sum of squares. * * @param costRelativeTolerance desired relative error in the sum of squares * @see #estimate */ public void setCostRelativeTolerance(double costRelativeTolerance) { this.costRelativeTolerance = costRelativeTolerance; } /** * Set the desired relative error in the approximate solution parameters. * * @param parRelativeTolerance desired relative error * in the approximate solution parameters * @see #estimate */ public void setParRelativeTolerance(double parRelativeTolerance) { this.parRelativeTolerance = parRelativeTolerance; } /** * Set the desired max cosine on the orthogonality. * * @param orthoTolerance desired max cosine on the orthogonality * between the function vector and the columns of the jacobian * @see #estimate */ public void setOrthoTolerance(double orthoTolerance) { this.orthoTolerance = orthoTolerance; } /** * Solve an estimation problem using the Levenberg-Marquardt algorithm. * <p>The algorithm used is a modified Levenberg-Marquardt one, based * on the MINPACK <a href="http://www.netlib.org/minpack/lmder.f">lmder</a> * routine. The algorithm settings must have been set up before this method * is called with the {@link #setInitialStepBoundFactor}, * {@link #setMaxCostEval}, {@link #setCostRelativeTolerance}, * {@link #setParRelativeTolerance} and {@link #setOrthoTolerance} methods. * If these methods have not been called, the default values set up by the * {@link #LevenbergMarquardtEstimator() constructor} will be used.</p> * <p>The authors of the original fortran function are:</p> * <ul> * <li>Argonne National Laboratory. MINPACK project. March 1980</li> * <li>Burton S. Garbow</li> * <li>Kenneth E. Hillstrom</li> * <li>Jorge J. More</li> * </ul> * <p>Luc Maisonobe did the Java translation.</p> * * @param problem estimation problem to solve * @exception EstimationException if convergence cannot be * reached with the specified algorithm settings or if there are more variables * than equations * @see #setInitialStepBoundFactor * @see #setCostRelativeTolerance * @see #setParRelativeTolerance * @see #setOrthoTolerance */ public void estimate(EstimationProblem problem) throws EstimationException { initializeEstimate(problem); // arrays shared with the other private methods solvedCols = Math.min(rows, cols); diagR = new double[cols]; jacNorm = new double[cols]; beta = new double[cols]; permutation = new int[cols]; lmDir = new double[cols]; // local variables double delta = 0, xNorm = 0; double[] diag = new double[cols]; double[] oldX = new double[cols]; double[] oldRes = new double[rows]; double[] work1 = new double[cols]; double[] work2 = new double[cols]; double[] work3 = new double[cols]; // evaluate the function at the starting point and calculate its norm updateResidualsAndCost(); // outer loop lmPar = 0; boolean firstIteration = true; while (true) { // compute the Q.R. decomposition of the jacobian matrix updateJacobian(); qrDecomposition(); // compute Qt.res qTy(residuals); // now we don't need Q anymore, // so let jacobian contain the R matrix with its diagonal elements for (int k = 0; k < solvedCols; ++k) { int pk = permutation[k]; jacobian[k * cols + pk] = diagR[pk]; } if (firstIteration) { // scale the variables according to the norms of the columns // of the initial jacobian xNorm = 0; for (int k = 0; k < cols; ++k) { double dk = jacNorm[k]; if (dk == 0) { dk = 1.0; } double xk = dk * parameters[k].getEstimate(); xNorm += xk * xk; diag[k] = dk; } xNorm = Math.sqrt(xNorm); // initialize the step bound delta delta = (xNorm == 0) ? initialStepBoundFactor : (initialStepBoundFactor * xNorm); } // check orthogonality between function vector and jacobian columns double maxCosine = 0; if (cost != 0) { for (int j = 0; j < solvedCols; ++j) { int pj = permutation[j]; double s = jacNorm[pj]; if (s != 0) { double sum = 0; for (int i = 0, index = pj; i <= j; ++i, index += cols) { sum += jacobian[index] * residuals[i]; } maxCosine = Math.max(maxCosine, Math.abs(sum) / (s * cost)); } } } if (maxCosine <= orthoTolerance) { return; } // rescale if necessary for (int j = 0; j < cols; ++j) { diag[j] = Math.max(diag[j], jacNorm[j]); } // inner loop
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -