00001
00010 #ifndef JMATH_JOPTIMIZATION_HPP
00011 #define JMATH_JOPTIMIZATION_HPP
00012
00013 #ifdef USE_JMATH_SERIALIZATION
00014 #include "jmath/serialize_vector.hpp"
00015 #include "jmath/serialize_matrix.hpp"
00016 #include "jmath/serialize_symmetric.hpp"
00017 #include "jmath/serialize_banded.hpp"
00018 #else
00019 #include "boost/numeric/ublas/vector.hpp"
00020 #include "boost/numeric/ublas/matrix.hpp"
00021 #include "boost/numeric/ublas/symmetric.hpp"
00022 #include "boost/numeric/ublas/banded.hpp"
00023 #endif
00024
00025 #include "boost/numeric/ublas/io.hpp"
00026
00027 #include "boost/numeric/ublas/matrix_proxy.hpp"
00028 #include "boost/numeric/ublas/vector_proxy.hpp"
00029
00030 #include "jmath/ublasCompatibility.hpp"
00031
00032 #include "boost/numeric/bindings/lapack/gesv.hpp"
00033 #include "boost/numeric/bindings/traits/ublas_matrix.hpp"
00034 #include "boost/numeric/bindings/traits/ublas_vector.hpp"
00035
00038
00039 namespace ublas = boost::numeric::ublas;
00041 namespace lapack = boost::numeric::bindings::lapack;
00042
00043
00044 namespace joptimization {
00045 namespace methods {
00050 template< class _TFunction_, typename _TType_ >
00051 struct GaussNewton {
00052 typedef _TType_ Type;
00053 typedef _TFunction_ Function;
00054 static void computeM(const ublas::matrix<_TType_>& jacobian,
00055 const _TFunction_* f,
00056 ublas::vector<_TType_>& parameters,
00057 ublas::vector<_TType_>& values,
00058 ublas::matrix<_TType_>& M);
00059 };
00060
00066 template< class _TFunction_, typename _TType_ >
00067 struct Newton {
00068 typedef _TType_ Type;
00069 typedef _TFunction_ Function;
00070 static void computeM(const ublas::matrix<_TType_>& jacobian,
00071 const _TFunction_* f,
00072 ublas::vector<_TType_>& parameters,
00073 ublas::vector<_TType_>& values,
00074 ublas::matrix<_TType_>& M);
00075 };
00076 }
00077
00167 namespace algorithms {
00177 template< class _TFunction_, typename _TType_ >
00178 _TType_ gradientDescent(_TFunction_* f,
00179 ublas::vector<_TType_>& parameters,
00180 int iter,
00181 _TType_ epsilon,
00182 _TType_ gamma);
00191 template< class _TMethod_ >
00192 typename _TMethod_::Type gaussNewton(typename _TMethod_::Function* f,
00193 ublas::vector<typename _TMethod_::Type>& parameters,
00194 int iter,
00195 typename _TMethod_::Type epsilon);
00206 template< class _TFunction_, typename _TType_ >
00207 _TType_ levenbergMarquardt(_TFunction_* f,
00208 ublas::vector<_TType_>& parameters,
00209 int iter,
00210 _TType_ epsilon,
00211 _TType_ lambda0,
00212 _TType_ nu);
00213 }
00214 }
00215
00216 namespace optimization {
00217 namespace details {
00218
00219 template<typename _TType_>
00220 double computeRemain(const ublas::vector<_TType_>& values) {
00221 _TType_ remain = 0.0;
00222 for(unsigned-int j = 0; j < values.size(); j++)
00223 {
00224 _TType_ v = values[j];
00225 remain += v * v;
00226 }
00227 return sqrt(remain / values.size() );
00228 }
00229
00230 template<typename _TType_>
00231 ublas::vector<double> solve(const ublas::matrix<_TType_>& M,
00232 const ublas::matrix<_TType_>& jacobian,
00233 const ublas::vector<_TType_>& values,
00234 int p_count) {
00235 ublas::matrix<_TType_> MD(M.size1(),M.size2());
00236 MD = M;
00237
00238
00239
00240 ublas::vector<_TType_> B(p_count);
00241 B = ublas::prec_prod(ublas::trans(jacobian), values);
00242 B = B * -1.0;
00243
00244 int ierr = lapack::gesv(MD, B);
00245 if (ierr!=0) {
00246 throw(jmath::LapackException(ierr,
00247 "joptimization::dtails::solve: error in lapack::gesv() routine",
00248 __FILE__,
00249 __LINE__));
00250 }
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267 return B;
00268 }
00269 }
00270 namespace methods {
00271 template< class _TFunction_, typename _TType_ >
00272 void GaussNewton< _TFunction_, _TType_ >::computeM(const ublas::matrix<_TType_>& jacobian,
00273 const _TFunction_* f,
00274 ublas::vector<_TType_>& parameters,
00275 ublas::vector<_TType_>& values,
00276 ublas::matrix<_TType_> &M) {
00277 M = ublas::prec_prod( ublas::trans(jacobian), jacobian);
00278 }
00279 template< class _TFunction_, typename _TType_ >
00280 void Newton< _TFunction_, _TType_ >::computeM(const ublas::matrix<_TType_>& jacobian,
00281 const _TFunction_* f,
00282 ublas::vector<_TType_>& parameters,
00283 ublas::vector<_TType_>& values,
00284 ublas::matrix<_TType_> &M) {
00285 M = ublas::prec_prod( ublas::trans(jacobian), jacobian);
00286
00287 for(int i = 0; i < f->count(); i++) {
00288 ublas::matrix< _TType_ > hessian = f->hessian( parameters,i);
00289 hessian = values[0] * hessian;
00290
00291 M = hessian + M;
00292 }
00293 }
00294 }
00295 namespace algorithms {
00296
00297 template< class _TFunction_, typename _TType_ >
00298 _TType_ gradientDescent(_TFunction_* f,
00299 ublas::vector<_TType_>& parameters,
00300 int iter,
00301 _TType_ epsilon,
00302 _TType_ gamma) {
00303 int p_count = parameters.size();
00304 int f_count = f->count();
00305 for(int i = 0; i < iter; i++) {
00306
00307 ublas::vector<_TType_> values = f->values(parameters);
00308
00309 _TType_ remain = details::computeRemain(values);
00310 JFR_DEBUG("Iteration " << i << ", error : " << remain << std::endl);
00311 if(remain < epsilon) {
00312 return remain;
00313 }
00314
00315 ublas::matrix<_TType_> jacobian = f->jacobian(parameters);
00316
00317
00318
00319 for(int j = 0; j < p_count; j++) {
00320 double update = 0.0;
00321 for(int i = 0; i < f_count; i++) {
00322 update += values[i] * jacobian(i,j);
00323 }
00324
00325 parameters[j] -= update * gamma;
00326 }
00327 JFR_DEBUG("parameters = " << parameters << std::endl);
00328 }
00329 return details::computeRemain(f->values(parameters));
00330 }
00331
00332 template< class _TMethod_ >
00333 typename _TMethod_::Type gaussNewton(typename _TMethod_::Function* f,
00334 ublas::vector<typename _TMethod_::Type>& parameters,
00335 int iter,
00336 typename _TMethod_::Type epsilon) {
00337 int p_count = parameters.size();
00338 int f_count = f->count();
00339 for(int i = 0; i < iter; i++) {
00340
00341 ublas::vector<typename _TMethod_::Type> values = f->values(parameters);
00342
00343 typename _TMethod_::Type remain = details::computeRemain(values);
00344 JFR_DEBUG("Iteration " << i << ", error : " << remain << std::endl);
00345 if(remain < epsilon) {
00346 return remain;
00347 }
00348
00349 ublas::matrix<typename _TMethod_::Type> jacobian = f->jacobian(parameters);
00350
00351
00352 ublas::matrix<typename _TMethod_::Type> M(jacobian.size2(), jacobian.size2());
00353 _TMethod_::computeM(jacobian, f, parameters, values, M);
00354 ublas::vector<typename _TMethod_::Type> X = details::solve(M, jacobian, values, p_count);
00355
00356 X = X + parameters;
00357 JFR_DEBUG(" Parameters " << parameters << endl);
00358 }
00359 return details::computeRemain(f->values(parameters));
00360 }
00361 template< class _TFunction_, typename _TType_ >
00362 _TType_ levenbergMarquardt(_TFunction_* f,
00363 ublas::vector<_TType_>& parameters,
00364 int iter,
00365 _TType_ epsilon,
00366 _TType_ lambda0,
00367 _TType_ nu) {
00368 int p_count = parameters.size();
00369
00370 _TType_ lambda = lambda0 / nu;
00371 _TType_ invnu = 1.0 / nu;
00372 if(nu < invnu) {
00373 double t = nu;
00374 nu = invnu;
00375 invnu = t;
00376 }
00377
00378 ublas::vector<_TType_> values = f->values(parameters);
00379
00380 _TType_ previousremain = details::computeRemain(f->values(parameters));
00381
00382 for(int i = 0; i < iter; i++) {
00383 if(previousremain < epsilon) {
00384 return previousremain;
00385 }
00386
00387 ublas::matrix<_TType_> jacobian = f->jacobian(parameters);
00388
00389
00390 ublas::matrix<_TType_> M(jacobian.size2(), jacobian.size2());
00391 M = ublas::prec_prod( ublas::trans(jacobian), jacobian);
00392
00393
00394 ublas::identity_matrix<_TType_> M2(jacobian.size2());
00395 M2 = M2 * -lambda;
00396
00397
00398 M = M + M2;
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411 ublas::vector<_TType_> X = details::solve(M2, jacobian, values, p_count);
00412
00413 ublas::vector<double> newparameters = parameters;
00414
00415 X = X + newparameters;
00416 ublas::vector<_TType_> newvalues = f->values(newparameters);
00417 double newremain = details::computeRemain(newvalues);
00418
00419 JFR_DEBUG( "Iteration " << i << ", error : " << previousremain << ", new error " << newremain << ", lambda : "<< lambda << std::endl );
00420 if(newremain < previousremain) {
00421 parameters = newparameters;
00422 values = newvalues;
00423 previousremain = newremain;
00424 lambda *= invnu;
00425
00426 } else {
00427 lambda *= nu;
00428 }
00429 if(lambda == 0.0 or lambda >= 1.0e200) {
00430 lambda = lambda0;
00431
00432 }
00433 JFR_DEBUG(" Parameters " << parameters << endl);
00434 }
00435 return details::computeRemain(f->values(parameters));
00436 }
00437 }
00438 }
00439
00440 #endif