|
bpp-core
2.1.0
|
00001 // 00002 // File: BfgsMultiDimensions.cpp 00003 // Created by: Laurent Guéguen 00004 // Created on: Dec 16 13:49 2010 00005 // 00006 00007 /* 00008 Copyright or © or Copr. Bio++ Development Team, (November 19, 2004) 00009 00010 This software is a computer program whose purpose is to provide classes 00011 for numerical calculus. 00012 00013 This software is governed by the CeCILL license under French law and 00014 abiding by the rules of distribution of free software. You can use, 00015 modify and/ or redistribute the software under the terms of the CeCILL 00016 license as circulated by CEA, CNRS and INRIA at the following URL 00017 "http://www.cecill.info". 00018 00019 As a counterpart to the access to the source code and rights to copy, 00020 modify and redistribute granted by the license, users are provided only 00021 with a limited warranty and the software's author, the holder of the 00022 economic rights, and the successive licensors have only limited 00023 liability. 00024 00025 In this respect, the user's attention is drawn to the risks associated 00026 with loading, using, modifying and/or developing or reproducing the 00027 software by the user in light of its specific status of free software, 00028 that may mean that it is complicated to manipulate, and that also 00029 therefore means that it is reserved for developers and experienced 00030 professionals having in-depth computer knowledge. Users are therefore 00031 encouraged to load and test the software's suitability as regards their 00032 requirements in conditions enabling the security of their systems and/or 00033 data to be ensured and, more generally, to use and operate it in the 00034 same conditions as regards security. 00035 00036 The fact that you are presently reading this means that you have had 00037 knowledge of the CeCILL license and that you accept its terms. 00038 */ 00039 00040 #include "BfgsMultiDimensions.h" 00041 #include "OneDimensionOptimizationTools.h" 00042 00043 using namespace bpp; 00044 00045 /******************************************************************************/ 00046 00047 BfgsMultiDimensions::BfgsMultiDimensions(DerivableFirstOrder* function) : 00048 AbstractOptimizer(function), 00049 //gtol_(gtol), 00050 slope_(0), 00051 Up_(), 00052 Lo_(), 00053 p_(), 00054 gradient_(), 00055 xi_(), 00056 dg_(), 00057 hdg_(), 00058 hessian_(), 00059 f1dim_(function) 00060 { 00061 setDefaultStopCondition_(new FunctionStopCondition(this)); 00062 setStopCondition(*getDefaultStopCondition()); 00063 setOptimizationProgressCharacter("."); 00064 } 00065 00066 /******************************************************************************/ 00067 00068 void BfgsMultiDimensions::doInit(const ParameterList& params) throw (Exception) 00069 { 00070 size_t nbParams = params.size(); 00071 p_.resize(nbParams); 00072 gradient_.resize(nbParams); 00073 xi_.resize(nbParams); 00074 dg_.resize(nbParams); 00075 hdg_.resize(nbParams); 00076 Up_.resize(nbParams); 00077 Lo_.resize(nbParams); 00078 00079 hessian_.resize(nbParams); 00080 for (size_t i = 0; i < nbParams; i++) 00081 { 00082 hessian_[i].resize(nbParams); 00083 } 00084 00085 for (size_t i = 0; i < nbParams; i++) 00086 { 00087 const Constraint* cp = params[i].getConstraint(); 00088 if (!cp) 00089 { 00090 Up_[i] = NumConstants::VERY_BIG(); 00091 Lo_[i] = -NumConstants::VERY_BIG(); 00092 } 00093 else 00094 { 00095 Up_[i] = cp->getAcceptedLimit(NumConstants::VERY_BIG()) - NumConstants::TINY(); 00096 Lo_[i] = cp->getAcceptedLimit(-NumConstants::VERY_BIG()) + NumConstants::TINY(); 00097 } 00098 } 00099 00100 getFunction_()->enableFirstOrderDerivatives(true); 00101 getFunction_()->setParameters(params); 00102 00103 getGradient(gradient_); 00104 00105 for (size_t i = 0; i < nbParams; i++) 00106 { 00107 p_[i] = getParameters()[i].getValue(); 00108 00109 for (unsigned int j = 0; j < nbParams; j++) 00110 { 00111 hessian_[i][j] = 0.0; 00112 } 00113 hessian_[i][i] = 1.0; 00114 } 00115 00116 00117 double sum = 0; 00118 for (size_t i = 0; i < nbParams; i++) 00119 { 00120 sum += p_[i] * p_[i]; 00121 } 00122 } 00123 00124 /******************************************************************************/ 00125 00126 double BfgsMultiDimensions::doStep() throw (Exception) 00127 { 00128 double f; 00129 size_t n = getParameters().size(); 00130 // Loop over iterations. 00131 00132 unsigned int i; 00133 00134 for (i = 0; i < n; i++) 00135 { 00136 p_[i] = getParameters()[i].getValue(); 00137 } 00138 00139 setDirection(); 00140 00141 getFunction()->enableFirstOrderDerivatives(false); 00142 nbEval_ += OneDimensionOptimizationTools::lineSearch(f1dim_, 00143 getParameters_(), xi_, 00144 gradient_, 00145 // getStopCondition()->getTolerance(), 00146 0, 0, 00147 getVerbose() > 0 ? getVerbose() - 1 : 0); 00148 getFunction()->enableFirstOrderDerivatives(true); 00149 00150 for (i = 0; i < n; i++) 00151 { 00152 xi_[i] = getParameters_()[i].getValue() - p_[i]; 00153 } 00154 00155 f = getFunction()->f(getParameters()); 00156 if (f > currentValue_) { 00157 printMessage("!!! Function increase !!!"); 00158 printMessage("!!! Optimization might have failed. Try to reparametrize your function to remove constraints."); 00159 tolIsReached_ = true; 00160 return f; 00161 } 00162 00163 if (tolIsReached_) 00164 { 00165 return f; 00166 } 00167 00168 //double temp, test = 0.0; 00169 //for (i = 0; i < n; i++) 00170 //{ 00171 // temp = xi_[i]; 00172 // if (p_[i] > 1.0) 00173 // temp /= p_[i]; 00174 // if (temp > test) 00175 // test = temp; 00176 //} 00177 00178 //if (test < 1e-7) 00179 //{ 00180 // tolIsReached_ = true; 00181 // return f; 00182 //} 00183 00184 for (i = 0; i < n; i++) 00185 { 00186 dg_[i] = gradient_[i]; 00187 } 00188 00189 getGradient(gradient_); 00190 //test = 0.0; 00191 00192 //for (i = 0; i < n; i++) 00193 //{ 00194 // temp = abs(gradient_[i]); 00195 // if (abs(p_[i]) > 1.0) 00196 // temp /= p_[i]; 00197 // if (temp > test) 00198 // test = temp; 00199 //} 00200 00201 //if (f > 1.0) 00202 // test /= f; 00203 00204 //if (test < gtol_) 00205 //{ 00206 // tolIsReached_ = true; 00207 // return f; 00208 //} 00209 00210 for (i = 0; i < n; i++) 00211 { 00212 dg_[i] = gradient_[i] - dg_[i]; 00213 } 00214 00215 for (i = 0; i < n; i++) 00216 { 00217 hdg_[i] = 0; 00218 for (unsigned int j = 0; j < n; j++) 00219 { 00220 hdg_[i] += hessian_[i][j] * dg_[j]; 00221 } 00222 } 00223 00224 double fae(0), fac(0), sumdg(0), sumxi(0); 00225 00226 for (i = 0; i < n; i++) 00227 { 00228 fac += dg_[i] * xi_[i]; 00229 fae += dg_[i] * hdg_[i]; 00230 sumdg += dg_[i] * dg_[i]; 00231 sumxi += xi_[i] * xi_[i]; 00232 } 00233 00234 if (fac > sqrt(1e-7 * sumdg * sumxi)) 00235 { 00236 fac = 1.0 / fac; 00237 double fad = 1.0 / fae; 00238 for (i = 0; i < n; i++) 00239 { 00240 dg_[i] = fac * xi_[i] - fad * hdg_[i]; 00241 } 00242 for (i = 0; i < n; i++) 00243 { 00244 for (unsigned int j = i; j < n; j++) 00245 { 00246 hessian_[i][j] += fac * xi_[i] * xi_[j] - fad * hdg_[i] * hdg_[j] + fae * dg_[i] * dg_[j]; 00247 hessian_[j][i] = hessian_[i][j]; 00248 } 00249 } 00250 } 00251 00252 return f; 00253 } 00254 00255 /******************************************************************************/ 00256 00257 void BfgsMultiDimensions::getGradient(std::vector<double>& gradient) const 00258 { 00259 for (unsigned int i = 0; i < gradient.size(); i++) 00260 { 00261 gradient[i] = getFunction()->getFirstOrderDerivative(getParameters()[i].getName()); 00262 } 00263 } 00264 00265 /******************************************************************************/ 00266 00267 void BfgsMultiDimensions::setDirection() 00268 { 00269 size_t nbParams = getParameters().size(); 00270 00271 for (size_t i = 0; i < nbParams; i++) 00272 { 00273 xi_[i] = 0; 00274 for (unsigned int j = 0; j < nbParams; j++) 00275 { 00276 xi_[i] -= hessian_[i][j] * gradient_[j]; 00277 } 00278 } 00279 00280 double v = 1, alpmax = 1; 00281 for (size_t i = 0; i < nbParams; i++) 00282 { 00283 if ((xi_[i] > 0) && (p_[i] + NumConstants::TINY() * xi_[i] < Up_[i])) 00284 v = (Up_[i] - p_[i]) / xi_[i]; 00285 else if ((xi_[i] < 0) && (p_[i] + NumConstants::TINY() * xi_[i] > Lo_[i])) 00286 v = (Lo_[i] - p_[i]) / xi_[i]; 00287 if (v < alpmax) 00288 alpmax = v; 00289 } 00290 00291 for (size_t i = 0; i < nbParams; i++) 00292 { 00293 if (p_[i] + NumConstants::TINY() * xi_[i] >= Up_[i]) 00294 xi_[i] = Up_[i] - p_[i]; 00295 else if (p_[i] + NumConstants::TINY() * xi_[i] <= Lo_[i]) 00296 xi_[i] = Lo_[i] - p_[i]; 00297 else 00298 xi_[i] *= alpmax; 00299 } 00300 }