00001 #ifndef OPENTISSUE_CORE_MATH_OPTIMIZATION_PROJECTED_STEEPEST_DESCENT_H
00002 #define OPENTISSUE_CORE_MATH_OPTIMIZATION_PROJECTED_STEEPEST_DESCENT_H
00003
00004
00005
00006
00007
00008
00009
00010 #include <OpenTissue/configuration.h>
00011
00012 #include <OpenTissue/core/math/big/big_types.h>
00013 #include <OpenTissue/core/math/optimization/optimization_constants.h>
00014 #include <OpenTissue/core/math/optimization/optimization_armijo_projected_backtracking.h>
00015 #include <OpenTissue/core/math/optimization/optimization_stationary_point.h>
00016
00017 #include <OpenTissue/core/math/math_value_traits.h>
00018 #include <OpenTissue/core/math/math_is_number.h>
00019
00020 #include <cmath>
00021 #include <stdexcept>
00022 #include <cassert>
00023
00024
00025 extern double convex_lambda;
00026
00027 namespace OpenTissue
00028 {
00029 namespace math
00030 {
00031 namespace optimization
00032 {
00033
00089
00090 template <
00091 typename T
00092 , typename function_functor
00093 , typename gradient_functor
00094 , typename projection_operator
00095 >
00096 inline void projected_steepest_descent(
00097 function_functor & f
00098 , gradient_functor & nabla_f
00099 , boost::numeric::ublas::vector<T> & x
00100 , projection_operator const & P
00101 , size_t const & max_iterations
00102 , T const & absolute_tolerance
00103 , T const & relative_tolerance
00104 , T const & stagnation_tolerance
00105 , size_t & status
00106 , size_t & iteration
00107 , T & error
00108 , T const & alpha
00109 , T const & beta
00110 , ublas::vector<T> * profiling = 0
00111 )
00112 {
00113 using std::fabs;
00114 using std::min;
00115 using std::max;
00116
00117 typedef ublas::compressed_matrix<T> matrix_type;
00118 typedef ublas::vector<T> vector_type;
00119 typedef T real_type;
00120 typedef OpenTissue::math::ValueTraits<T> value_traits;
00121
00122 if(max_iterations <= 0)
00123 throw std::invalid_argument("max_iterations must be larger than zero");
00124 if(absolute_tolerance < value_traits::zero() )
00125 throw std::invalid_argument("absolute_tolerance must be non-negative");
00126 if(relative_tolerance < value_traits::zero() )
00127 throw std::invalid_argument("relative_tolerance must be non-negative");
00128 if(stagnation_tolerance < value_traits::zero() )
00129 throw std::invalid_argument("stagnation_tolerance must be non-negative");
00130 if (beta >= value_traits::one() )
00131 throw std::invalid_argument("Illegal beta value");
00132 if (alpha <= value_traits::zero() )
00133 throw std::invalid_argument("Illegal alpha value");
00134 if(beta<=alpha)
00135 throw std::invalid_argument("beta must be larger than alpha");
00136 if(profiling == &x)
00137 throw std::logic_error("profiling must not point to x-vector");
00138
00139 error = value_traits::infinity();
00140 iteration = 0;
00141
00142 status = OK;
00143
00144 size_t const m = x.size();
00145 if(m==0)
00146 return;
00147
00148 status = ITERATING;
00149
00150 if(profiling)
00151 {
00152 (*profiling).resize( max_iterations );
00153 (*profiling).clear();
00154 }
00155
00156
00157 vector_type dx;
00158 vector_type x_old;
00159 vector_type x0;
00160 vector_type nabla_f_k;
00161
00162
00163 dx.resize(m);
00164 x_old.resize(m);
00165 nabla_f_k.resize(m);
00166 x0.resize (m);
00167 x0.assign (x);
00168
00169
00170
00171 x = P(x);
00172 real_type f_0 = f(x);
00173 ublas::noalias( nabla_f_k ) = nabla_f(x) - convex_lambda * (x - x0);
00174
00175
00176 for (; iteration < max_iterations; ++iteration)
00177 {
00178 if(profiling)
00179 (*profiling)(iteration) = f_0;
00180
00181
00182 if(stationary_point( nabla_f_k, absolute_tolerance, error ) )
00183 {
00184 status = ABSOLUTE_CONVERGENCE;
00185 return;
00186 }
00187
00188
00189 dx.assign( -nabla_f_k );
00190
00191
00192 x_old.assign( x );
00193 real_type f_tau = f_0;
00194 armijo_projected_backtracking(
00195 f
00196 , nabla_f_k
00197 , x_old
00198 , x
00199 , dx
00200 , relative_tolerance
00201 , stagnation_tolerance
00202 , alpha
00203 , beta
00204 , f_tau
00205 , status
00206 , P
00207 );
00208
00209 if(status != OK)
00210 return;
00211
00212
00213 f_0 = f_tau;
00214 ublas::noalias( nabla_f_k ) = nabla_f(x) - convex_lambda * (x - x0);
00215
00216 }
00217 }
00218
00219
00220
00263 template <
00264 typename T
00265 , typename function_functor
00266 , typename gradient_functor
00267 , typename projection_operator
00268 >
00269 inline void projected_steepest_descent(
00270 function_functor & f
00271 , gradient_functor & nabla_f
00272 , boost::numeric::ublas::vector<T> & x
00273 , projection_operator const & P
00274 , size_t const & max_iterations
00275 , T const & absolute_tolerance
00276 , T const & relative_tolerance
00277 , T const & stagnation_tolerance
00278 , size_t & status
00279 , size_t & iteration
00280 , T & error
00281 , T const & tau
00282 , ublas::vector<T> * profiling = 0
00283 )
00284 {
00285 using std::fabs;
00286 using std::min;
00287 using std::max;
00288
00289 typedef ublas::compressed_matrix<T> matrix_type;
00290 typedef ublas::vector<T> vector_type;
00291 typedef T real_type;
00292 typedef OpenTissue::math::ValueTraits<T> value_traits;
00293
00294 if(max_iterations <= 0)
00295 throw std::invalid_argument("max_iterations must be larger than zero");
00296 if(absolute_tolerance < value_traits::zero() )
00297 throw std::invalid_argument("absolute_tolerance must be non-negative");
00298 if(relative_tolerance < value_traits::zero() )
00299 throw std::invalid_argument("relative_tolerance must be non-negative");
00300 if(stagnation_tolerance < value_traits::zero() )
00301 throw std::invalid_argument("stagnation_tolerance must be non-negative");
00302 if(profiling == &x)
00303 throw std::logic_error("profiling must not point to x-vector");
00304 if(tau < value_traits::zero() )
00305 throw std::invalid_argument("step size must be a positive number");
00306
00307 error = value_traits::infinity();
00308 iteration = 0;
00309
00310 status = OK;
00311
00312 size_t const m = x.size();
00313 if(m==0)
00314 return;
00315
00316 status = ITERATING;
00317
00318 if(profiling)
00319 {
00320 (*profiling).resize( max_iterations );
00321 (*profiling).clear();
00322 }
00323
00324
00325 vector_type dx;
00326 vector_type x_new;
00327 vector_type nabla_f_k;
00328
00329
00330 dx.resize(m);
00331 x_new.resize(m);
00332 nabla_f_k.resize(m);
00333
00334
00335
00336 x = P(x);
00337 real_type f_0 = f(x);
00338 ublas::noalias( nabla_f_k ) = nabla_f(x);
00339
00340
00341 for (; iteration < max_iterations; ++iteration)
00342 {
00343 if(profiling)
00344 (*profiling)(iteration) = f_0;
00345
00346
00347 if(stationary_point( nabla_f_k, absolute_tolerance, error ) )
00348 {
00349 status = ABSOLUTE_CONVERGENCE;
00350 return;
00351 }
00352
00353 dx.assign( -nabla_f_k );
00354
00355 x_new = P(x + tau*dx);
00356 T f_1 = f(x_new);
00357
00358 assert( is_number( f_1 ) || !"projected_steepest_descent(): internal error, NAN is encountered?");
00359
00360 T gamma = ublas::inner_prod( nabla_f_k, x_new - x );
00361 assert( is_number( gamma ) || !"projected_steepest_descent(): internal error, NAN is encountered?");
00362
00363
00364 if( gamma >= value_traits::zero() )
00365 {
00366 status = NON_DESCENT_DIRECTION;
00367 f_1 = f_0;
00368 x_new.assign( x );
00369 }
00370
00371 if(stagnation( x, x_new, stagnation_tolerance ) )
00372 {
00373 status = STAGNATION;
00374 }
00375
00376 if(relative_convergence(f_0,f_1, relative_tolerance) )
00377 {
00378 status = RELATIVE_CONVERGENCE;
00379 }
00380
00381 x.assign( x_new );
00382 f_0 = f_1;
00383 nabla_f_k.assign( nabla_f(x) );
00384
00385 if(status != ITERATING)
00386 return;
00387
00388 }
00389 }
00390
00391
00392 }
00393 }
00394 }
00395
00396
00397 #endif