20 #include <basic/Tracer.hh>
22 #include <ObjexxFCL/FArray2D.hh>
23 #include <utility/exit.hh>
25 #include <basic/options/option.hh>
26 #include <basic/options/keys/optimization.OptionKeys.gen.hh>
34 #include <utility/vector1.hh>
42 namespace optimization {
44 using namespace ObjexxFCL;
46 static basic::Tracer
TR(
"core.optimization.LineMinimizer" );
52 ) : func_( func_in ), options_( options_in ) {}
63 Multivec phipsi( phipsi_inout ), dE_dphipsi( phipsi_inout );
70 if ( type ==
"linmin" ) {
72 linmin( phipsi, dE_dphipsi, end_func, ITMAX );
73 }
else if ( type ==
"dfpmin" ) {
74 dfpmin( phipsi, end_func, fractional_converge_test, ITMAX );
75 }
else if ( type ==
"dfpmin_armijo" ) {
78 dfpmin_armijo( phipsi, end_func, fractional_converge_test, armijo_line_search, ITMAX );
79 }
else if ( type ==
"dfpmin_armijo_nonmonotone" ) {
82 dfpmin_armijo( phipsi, end_func, fractional_converge_test, armijo_line_search, ITMAX );
83 }
else if ( type ==
"dfpmin_atol" ) {
84 dfpmin( phipsi, end_func, absolute_converge_test, ITMAX );
85 }
else if ( type ==
"dfpmin_armijo_atol" ) {
88 dfpmin_armijo( phipsi, end_func, absolute_converge_test, armijo_line_search, ITMAX );
89 }
else if ( type ==
"dfpmin_armijo_nonmonotone_atol" ) {
92 dfpmin_armijo( phipsi, end_func, absolute_converge_test, armijo_line_search, ITMAX );
93 }
else if ( type ==
"dfpmin_strong_wolfe" ) {
95 dfpmin_armijo( phipsi, end_func, fractional_converge_test, strong_wolfe_line_search, ITMAX );
96 }
else if ( type ==
"dfpmin_strong_wolfe_atol" ) {
98 dfpmin_armijo( phipsi, end_func, absolute_converge_test, strong_wolfe_line_search, ITMAX );
99 }
else if ( type ==
"lbfgs_armijo" ) {
102 lbfgs( phipsi, end_func, fractional_converge_test, armijo_line_search, ITMAX );
103 }
else if ( type ==
"lbfgs_armijo_atol" ) {
106 lbfgs( phipsi, end_func, absolute_converge_test, armijo_line_search, ITMAX );
107 }
else if ( type ==
"lbfgs_armijo_nonmonotone" ) {
110 lbfgs( phipsi, end_func, fractional_converge_test, armijo_line_search, ITMAX );
111 }
else if ( type ==
"lbfgs_armijo_nonmonotone_atol" ) {
114 lbfgs( phipsi, end_func, absolute_converge_test, armijo_line_search, ITMAX );
115 }
else if ( type ==
"lbfgs_strong_wolfe" ) {
117 lbfgs( phipsi, end_func, fractional_converge_test, strong_wolfe_line_search, ITMAX );
118 }
else if ( type ==
"GA" ) {
120 gam.
run(phipsi, ITMAX);
122 utility_exit_with_message(
"unknown type of minimization '"+type+
"'");
125 phipsi_inout = phipsi;
126 return func_( phipsi );
138 return ( 2.0f*std::abs( Fnew - Fold ) <=
148 return ( std::abs( Fnew - Fold ) <=
tolerance );
157 int const problem_size( current_position.size() );
158 int const max_iter( std::max( 200, problem_size/10 ));
164 Multivec descent_direction( problem_size, 0.0);
165 Real current_value(
_func( current_position ) );
166 _func.
dfunc( current_position, descent_direction );
168 std::transform( descent_direction.begin(), descent_direction.end(),
169 descent_direction.begin(), std::negate<Real>() );
173 while( iter++ < max_iter ) {
174 Real previous_value = current_value;
175 current_value =
_line_min( current_position, descent_direction );
177 if(
_converged(current_value, previous_value) )
return current_value;
181 TR.Warning <<
"WARNING: Minimization has exceeded " << max_iter <<
"iterations but has not converged!" << std::endl;
182 return current_value;
212 int const N( P.size() );
220 FArray2D< Real > HESSIN(
N,
N, 0.0 );
230 for (
int i = 1; i <=
N; ++i ) {
237 for (
int ITER = 1; ITER <= ITMAX; ++ITER ) {
241 TR.Warning <<
"WARNING: ABORTING MINIMIZATION TRIGGERED BY abort_min" << std::endl;
248 FRET = (*line_min)(
P, XI );
251 if ( converge_test( FRET, FP ) ) {
257 for (
int i = 1; i <=
N; ++i ) {
264 for (
int i = 1; i <=
N; ++i ) {
267 for (
int i = 1; i <=
N; ++i ) {
269 for (
int j = 1; j <=
N; ++j ) {
270 HDG[i] += HESSIN(i,j)*DG[j];
277 for (
int i = 1; i <=
N; ++i ) {
281 if ( FAC != 0.0 ) FAC = 1.0/FAC;
287 for (
int i = 1; i <=
N; ++i ) {
288 DG[i] = FAC*XI[i] - FAD*HDG[i];
290 for (
int i = 1; i <=
N; ++i ) {
291 for (
int j = 1; j <=
N; ++j ) {
292 HESSIN(i,j) += FAC*XI[i]*XI[j] - FAD*HDG[i]*HDG[j] + FAE*DG[i]*DG[j];
295 for (
int i = 1; i <=
N; ++i ) {
297 for (
int j = 1; j <=
N; ++j ) {
298 XI[i] -= HESSIN(i,j)*G[j];
304 TR.Warning <<
"WARNING: DFPMIN MAX CYCLES " << ITMAX <<
" EXCEEDED, BUT FUNC NOT CONVERGED!" << std::endl;
325 int const N( P.size() );
326 Real const EPS( 1.
E-5 );
328 FArray2D< Real > HESSIN(
N,
N, 0.0 );
334 int const prior_func_memory_size( line_min->nonmonotone() ? 3 : 1 );
335 Multivec prior_func_memory( prior_func_memory_size );
337 if ( line_min->nonmonotone() ) line_min->_last_accepted_step = 0.005;
353 int func_memory_filled( 1 );
354 prior_func_memory[ 1 ] = prior_func_value;
356 for (
int i = 1; i <=
N; ++i ) {
361 Real FAC, FAE, FAD, FAF;
363 for (
int ITER = 1; ITER <= ITMAX; ++ITER ) {
364 line_min->_deriv_sum = 0.0;
368 for (
int i = 1; i <=
N; ++i ) {
369 line_min->_deriv_sum += XI[i]*G[i];
371 if ( std::abs( G[i] ) > Gmax ) {
372 Gmax=std::abs( G[i] );
376 Gnorm = std::sqrt(Gnorm);
378 line_min->_func_to_beat = prior_func_memory[ 1 ];
379 for(
int i = 2 ; i <= func_memory_filled ; ++i ) {
380 if( line_min->_func_to_beat < prior_func_memory[ i ] ) {
381 line_min->_func_to_beat = prior_func_memory[ i ];
386 FRET = (*line_min)(
P, XI );
390 if ( converge_test( FRET, prior_func_value ) ) {
399 if (std::abs(FRET-prior_func_value)<=EPS ) {
401 for (
int i = 1; i <=
N; ++i ) {
402 XInorm += XI[i]*XI[i];
404 if ( line_min->_deriv_sum < -1e-3*Gnorm*XInorm ) {
414 TR.Warning <<
":( reset HESSIN from failed line search" << std::endl;
416 line_min->_deriv_sum = 0.0;
417 for (
int i = 1; i <=
N; ++i ) {
418 for (
int j = 1; j < i; ++j ) {
421 for (
int j = i+1; j <=
N; ++j ) {
424 if ( HESSIN(i,i) < 0.01 ) HESSIN(i,i) = 0.01;
425 XI[i] = -HESSIN(i,i)*G[i];
426 line_min->_deriv_sum += XI[i]*G[i];
429 FRET = (*line_min)(
P, XI );
433 if (std::abs(FRET-prior_func_value)<=EPS)
442 prior_func_value = FRET;
445 if( func_memory_filled < prior_func_memory_size ) {
446 func_memory_filled++;
448 for(
int i = 1 ; i < func_memory_filled ; ++ i ) {
449 prior_func_memory[ i ] = prior_func_memory[ i + 1 ];
452 prior_func_memory[ func_memory_filled ] = prior_func_value;
454 for (
int i = 1; i <=
N; ++i ) {
461 if ( line_min->provide_stored_derivatives() ) {
462 line_min->fetch_stored_derivatives( G );
470 line_min->_deriv_sum = 0.0;
472 for (
int i = 1; i <=
N; ++i ) {
473 line_min->_deriv_sum += XI[i]*DG[i];
474 DRVNEW += XI[i]*G[i];
482 if ( HOPT == 1 || DRVNEW > 0.95*line_min->_deriv_sum ) {
483 for (
int i = 1; i <=
N; ++i ) {
485 for (
int j = 1; j <=
N; ++j ) {
486 HDG[i] += HESSIN(i,j)*DG[j];
492 for (
int i = 1; i <=
N; ++i ) {
500 for (
int i = 1; i <=
N; ++i ) {
501 DG[i] = FAC*XI[i] - FAD*HDG[i];
503 for (
int i = 1; i <=
N; ++i ) {
504 for (
int j = 1; j <=
N; ++j ) {
505 HESSIN(i,j) += FAC*XI[i]*XI[j] - FAD*HDG[i]*HDG[j] + FAE*DG[i]*DG[j];
510 for (
int i = 1; i <=
N; ++i ) {
512 for (
int j = 1; j <=
N; ++j ) {
513 XI[i] -= HESSIN(i,j)*G[j];
519 for (
int i = 1; i <=
N; ++i ) {
520 DRVNEW += XI[i]*G[i];
525 if (FAF<0.01) FAF=0.01;
526 for (
int i = 1; i <=
N; ++i ) {
527 for (
int j = 1; j <=
N; ++j ) {
538 TR.Warning <<
"WARNING: DFPMIN (Armijo) MAX CYCLES " << ITMAX <<
" EXCEEDED, BUT FUNC NOT CONVERGED!" << std::endl;
591 int const N( X.size() );
592 static int M( basic::options::option[ basic::options::OptionKeys::optimization::lbfgs_M ]() );
593 int const PAST( line_min->nonmonotone() ? 3 : 1 );
608 for (
int i=1; i<=M; ++i) {
611 lm[i].s.resize(
N,0.0);
612 lm[i].y.resize(
N,0.0);
619 int func_memory_filled( 1 );
621 pf[1] = prior_func_value;
627 for (
int i = 1; i <=
N; ++i ) {
629 invdnorm += D[i]*D[i];
631 invdnorm = 1.0/sqrt( invdnorm );
635 line_min->_last_accepted_step = 2*invdnorm;
637 for (
int ITER = 1; ITER <= ITMAX; ++ITER ) {
643 line_min->_deriv_sum = 0.0;
646 for (
int i = 1; i <=
N; ++i ) {
647 line_min->_deriv_sum += D[i]*G[i];
649 if ( std::abs( G[i] ) > Gmax ) {
650 Gmax=std::abs( G[i] );
653 Gnorm = std::sqrt(Gnorm);
655 line_min->_func_to_beat = pf[ 1 ];
656 for(
int i = 2 ; i <= func_memory_filled ; ++i ) {
657 if( line_min->_func_to_beat < pf[ i ] )
658 line_min->_func_to_beat = pf[ i ];
662 FRET = (*line_min)(
X,
D );
664 if ( converge_test( FRET, prior_func_value ) || line_min->_last_accepted_step == 0) {
668 if (line_min->_last_accepted_step == 0) {
686 line_min->_deriv_sum = 0.0;
687 for (
int i = 1; i <=
N; ++i ) {
689 line_min->_deriv_sum += D[i]*G[i];
692 if ( sqrt( -line_min->_deriv_sum ) > 1e-6 ) {
693 invdnorm = 1.0/sqrt( -line_min->_deriv_sum );
696 line_min->_last_accepted_step = 0.1*invdnorm;
697 func_memory_filled = 1;
698 prior_func_value = FRET;
699 pf[1] = prior_func_value;
702 FRET = (*line_min)(
X,
D );
708 if (line_min->_last_accepted_step == 0) {
710 TR <<
"Line search failed even after resetting Hessian; aborting at iter#" << ITER << std::endl;
717 prior_func_value = FRET;
720 if ( func_memory_filled < PAST ) {
721 func_memory_filled++;
723 for(
int i = 1 ; i < PAST ; ++ i ) {
724 pf[ i ] = pf[ i + 1 ];
727 pf[ func_memory_filled ] = prior_func_value;
732 if ( line_min->provide_stored_derivatives() ) {
733 line_min->fetch_stored_derivatives( G );
749 for (
int i = 1; i <=
N; ++i ) {
750 lm[CURPOS].s[i] = X[i] - XP[i];
751 lm[CURPOS].y[i] = G[i] - GP[i];
752 ys += lm[CURPOS].y[i]*lm[CURPOS].s[i];
753 yy += lm[CURPOS].y[i]*lm[CURPOS].y[i];
769 int bound = std::min( M,K );
772 if (CURPOS > M) CURPOS = 1;
775 for (
int i = 1; i <=
N; ++i ) {
780 for (
int pts=0; pts<bound; ++pts ) {
784 if (std::fabs(lm[j].ys) < 1e-9)
continue;
788 for (
int i = 1; i <=
N; ++i ) {
789 lm[j].alpha += lm[j].s[i] * D[i];
791 lm[j].alpha /= lm[j].ys;
794 for (
int i = 1; i <=
N; ++i ) {
795 D[i] += -lm[j].alpha * lm[j].y[i];
803 for (
int pts=0; pts<bound; ++pts ) {
804 if (std::fabs(lm[j].ys) < 1e-9)
continue;
808 for (
int i = 1; i <=
N; ++i ) {
809 beta += lm[j].y[i] * D[i];
814 for (
int i = 1; i <=
N; ++i ) {
815 D[i] += (lm[j].alpha - beta) * lm[j].s[i];
824 TR.Warning <<
"WARNING: LBFGS MAX CYCLES " << ITMAX <<
" EXCEEDED, BUT FUNC NOT CONVERGED!" << std::endl;
841 FRET = test_brent( P, XI );