Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
LineMinimizer.cc
Go to the documentation of this file.
1 // -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
2 // vi: set ts=2 noet:
3 //
4 // (c) Copyright Rosetta Commons Member Institutions.
5 // (c) This file is part of the Rosetta software suite and is made available under license.
6 // (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
7 // (c) For more information, see http://www.rosettacommons.org. Questions about this can be
8 // (c) addressed to University of Washington UW TechTransfer, email: license@u.washington.edu.
9 
10 /// @file core/optimization/LineMinimizer.cc
11 /// @brief line minimizer classes
12 /// @author Phil Bradley
13 /// @author Jim Havranek
14 
15 
16 // Unit headers
18 
19 // AUTO-REMOVED #include <ObjexxFCL/ObjexxFCL.hh>
20 // AUTO-REMOVED #include <ObjexxFCL/FArray2D.hh>
21 #include <ObjexxFCL/Fmath.hh>
22 #include <basic/Tracer.hh>
23 
24 // C++ headers
25 #include <cmath>
26 //#include <cstdlib>
27 // #include <cstdio>
28 #include <iostream>
29 #include <algorithm>
30 
31 #include <basic/options/option.hh>
32 #include <basic/options/keys/optimization.OptionKeys.gen.hh>
33 
34 #include <utility/vector1.hh>
35 
36 
37 
38 //Auto using namespaces
39 namespace ObjexxFCL {
40 } using namespace ObjexxFCL; // AUTO USING NS
41 //Auto using namespaces end
42 
43 using basic::T;
44 using basic::Error;
45 using basic::Warning;
46 
47 static basic::Tracer TR("core.optimization");
48 
49 namespace core {
50 namespace optimization {
51 
52 /// @details Auto-generated virtual destructor
53 LineMinimizationAlgorithm::~LineMinimizationAlgorithm() {}
54 
55 void
56 func_1d::dump( Real displacement ) {
57  for( uint i = 1 ; i <= _starting_point.size() ; ++i ) {
58  _eval_point[i] = _starting_point[i] + ( displacement * _search_direction[i] );
59  }
60  return _func.dump( _starting_point, _eval_point );
61 }
62 
63  static basic::Tracer TR( "core.optimization.LineMinimizer" );
64 
65 
66  // Functor'ed up version of accurate line minimization
67  /////////////////////////////////////////////////////////////////////////////
68  Real
69  BrentLineMinimization::operator()(
70  Multivec & current_position,
71  Multivec & search_direction
72  )
73  {
74  int const problem_size( current_position.size() );
75 
76  _num_linemin_calls++;
77 
78  Real AX, XX, BX, FA, FX, FB;
79 
80  // check magnitude of derivative
81  Real derivmax = 0.0;
82  for ( int i = 1; i <= problem_size; ++i ) {
83  if ( std::abs(search_direction[i]) > std::abs(derivmax) ) {
84  derivmax = search_direction[i];
85  }
86  }
87 
88  if ( std::abs(derivmax) <= .0001 ) {
89  Real final_value =_func(current_position);
90  return final_value; // deriv = 0, return value
91  }
92 
93  // Construct the one-dimensional projection of the function
94  func_1d this_line_func( current_position, search_direction, _func );
95 
96  // initial step sizes from our options
97  AX = _ax;
98  XX = _xx; // initial range for bracketing
99  BX = _bx; // now set in namespace in minimize_set_func
100 
101  MNBRAK(AX,XX,BX,FA,FX,FB,this_line_func);
102 
103  Real final_value = BRENT(AX,XX,BX,FA,FX,FB,_tolerance,this_line_func);
104 
105  for ( int j = 1; j <= problem_size; ++j ) {
106  search_direction[j] *= _last_accepted_step;
107  current_position[j] += search_direction[j];
108  }
109 
110 // TR.Info << "Linemin used " << this_line_func.get_eval_count() <<
111 // " function calls" << std::endl;
112 
113  return final_value;
114  }
115 
116  /////////////////////////////////////////////////////////////////////////////
117  void
118  BrentLineMinimization::MNBRAK(
119  Real & AX,
120  Real & BX,
121  Real & CX,
122  Real & FA,
123  Real & FB,
124  Real & FC,
125  func_1d & func_eval
126  ) const
127  {
128  Real DUM, R, Q, U, ULIM, FU;
129  Real const GOLD = { 1.618034 };
130  Real const GLIMIT = { 100.0 };
131  Real const TINY = { 1.E-20 };
132 
133  FA = func_eval(AX);
134  FB = func_eval(BX);
135  if ( FB > FA ) {
136  DUM = AX;
137  AX = BX;
138  BX = DUM;
139  DUM = FB;
140  FB = FA;
141  FA = DUM;
142  }
143  CX = BX+GOLD*(BX-AX);
144  FC = func_eval(CX);
145 
146  L1:
147  if ( FB >= FC ) {
148  R = (BX-AX)*(FB-FC);
149  Q = (BX-CX)*(FB-FA);
150  U = BX-((BX-CX)*Q-(BX-AX)*R)/(2.*sign(std::max(std::abs(Q-R),TINY),Q-R));
151  ULIM = BX+GLIMIT*(CX-BX);
152  if ( (BX-U)*(U-CX) > 0.0 ) {
153  FU = func_eval(U);
154  if ( FU < FC ) {
155  AX = BX;
156  FA = FB;
157  BX = U;
158  FB = FU;
159  goto L1;
160  } else if ( FU > FB ) {
161  CX = U;
162  FC = FU;
163  goto L1;
164  }
165  U = CX+GOLD*(CX-BX);
166  FU = func_eval(U);
167 
168  } else if ( (CX-U)*(U-ULIM) > 0. ) {
169  FU = func_eval(U);
170  if ( FU < FC ) {
171  BX = CX;
172  CX = U;
173  U = CX+GOLD*(CX-BX);
174  FB = FC;
175  FC = FU;
176  FU = func_eval(U);
177  }
178  } else if ( (U-ULIM)*(ULIM-CX) >= 0. ) {
179  U = ULIM;
180  FU = func_eval(U);
181  } else {
182  U = CX+GOLD*(CX-BX);
183  FU = func_eval(U);
184  }
185  AX = BX;
186  BX = CX;
187  CX = U;
188  FA = FB;
189  FB = FC;
190  FC = FU;
191  goto L1;
192  }
193  } // mnbrak
194 
195  /////////////////////////////////////////////////////////////////////////////
196  //
197  Real
198  BrentLineMinimization::BRENT(
199  Real const AX,
200  Real const BX,
201  Real const CX,
202  Real & FA,
203  Real & FB,
204  Real const FC,
205  Real const TOL,
206  func_1d & func_eval
207  )
208  {
209  Real const brent_abs_tolerance( _abs_tolerance );
210 
211  Real BRENT; // Return value
212 
213  Real A, B, E,TOL1,TOL2;
214  Real V,W,X,FX,FV,FW,XM,R,Q,P,ETEMP,D,U,FU;
215 
216  int const ITMAX = { 100 };
217  Real const CGOLD = { 0.3819660 };
218  Real const ZEPS = { 1.0E-10 };
219  //$$$ int func_counter; // diagnostic only
220 
221  A = std::min(AX,CX);
222  B = std::max(AX,CX);
223  V = BX;
224  W = V;
225  X = V;
226  E = 0.0;
227  // these two initializations added to remove warnings
228  D = 0.0; // D will be set first time through loop, when if (E>tol) is false
229  BRENT = -999.9;
230 
231  //********************************************
232  FX = FB;
233  if ( A == AX ) {
234  FB = FC;
235  } else {
236  FB = FA;
237  FA = FC;
238  }
239 
240  // pb 3/20/07: this was already commented out:
241  // FX = F(gfrag,X);
242  //********************************************
243  //$$$ func_counter = 1;
244 
245  FV = FX;
246  FW = FX;
247  for ( int iter = 1; iter <= ITMAX; ++iter ) {
248  XM = 0.5*(A+B);
249  TOL1 = TOL*std::abs(X)+ZEPS;
250  TOL2 = 2.*TOL1;
251 
252 
253  //********************************************
254  // here, we exit BRENT if the function varies by less than a
255  // tolerance over the interval
256  if ( ( std::abs(FB-FX) <= brent_abs_tolerance ) &&
257  ( std::abs(FA-FX) <= brent_abs_tolerance ) ) break;
258 
259  //********************************************
260  // here, we exit BRENT if we have narrowed the search down to a
261  // small change in X
262  if ( std::abs(X-XM) <= (TOL2-.5*(B-A)) ) break;
263 
264  if ( std::abs(E) > TOL1 ) {
265  R = (X-W)*(FX-FV);
266  Q = (X-V)*(FX-FW);
267  P = (X-V)*Q-(X-W)*R;
268  Q = 2.*(Q-R);
269  if ( Q > 0.0 ) P = -P;
270  Q = std::abs(Q);
271  ETEMP = E;
272  E = D;
273  if ( std::abs(P) >= std::abs(.5*Q*ETEMP) ||
274  P <= Q*(A-X) || P >= Q*(B-X) ) goto L1;
275  D = P/Q;
276  U = X+D;
277  if ( U-A < TOL2 || B-U < TOL2 ) D = sign(TOL1,XM-X);
278  goto L2;
279  }
280  L1:
281  if ( X >= XM ) {
282  E = A-X;
283  } else {
284  E = B-X;
285  }
286  D = CGOLD*E;
287  L2:
288  if ( std::abs(D) >= TOL1 ) {
289  U = X+D;
290  } else {
291  U = X+sign(TOL1,D);
292  }
293 
294  // call Minimizer object's 1D function using stored data
295  FU = func_eval(U);
296  //$$$ ++func_counter;
297 
298  if ( FU <= FX ) {
299  if ( U >= X ) {
300  A = X;
301  FA = FX;
302  } else {
303  B = X;
304  FB = FX;
305  }
306  V = W;
307  FV = FW;
308  W = X;
309  FW = FX;
310  X = U;
311  FX = FU;
312  } else {
313  if ( U < X ) {
314  A = U;
315  FA = FU;
316  } else {
317  B = U;
318  FB = FU;
319  }
320  if ( FU <= FW || W == X ) {
321  V = W;
322  FV = FW;
323  W = U;
324  FW = FU;
325  } else if ( FU <= FV || V == X || V == W ) {
326  V = U;
327  FV = FU;
328  }
329  }
330 
331  if ( iter >= ITMAX ) {
332  TR.Error << "BRENT exceed maximum iterations. " << iter << std::endl;
333  std::exit( EXIT_FAILURE );
334  }
335  } // iter=1,ITMAX
336 
337 
338  _last_accepted_step = X;
339  BRENT = FX;
340 
341  return BRENT;
342  }
343 
344  /////////////////////////////////////////////////////////////////////////////
345  //
346  Real
347  ArmijoLineMinimization::operator()(
348  Multivec & current_position,
349  Multivec & search_direction
350  )
351  {
352 
353  Real const FACTOR( 0.5 );
354  int const problem_size( current_position.size() );
355 // Real max_step_limit( _nonmonotone ? 2.0 : 1.0 );
356  Real max_step_limit( 1.0 );
357 
358  _num_linemin_calls++;
359 
360  // Construct the one-dimensional projection of the function
361  func_1d this_line_func( current_position, search_direction, _func );
362 
363  // Early termination for derivatives (search_direction magnitudes) near zero
364  // Please note that the search_direction vector is not normalized
365  Real derivmax = 0.0;
366  for ( int i = 1 ; i <= problem_size; ++i ) {
367  if ( std::abs( search_direction[ i ] ) >
368  std::abs( derivmax ) ) derivmax = search_direction[ i ];
369  }
370 
371  // if ( runlevel >= gush) std::cout << "derivmax," << SS( derivmax ) << std::endl;
372  if ( std::abs(derivmax) < .0001 ) {
373  Real final_value = this_line_func( 0.0 ); // deriv = 0, return value
374  return final_value;
375  }
376 
377  //initial trial stepsize
378  Real init_step( _last_accepted_step / FACTOR );
379  if ( init_step > max_step_limit ) init_step = max_step_limit;
380 
381  Real final_value = Armijo( init_step, this_line_func );
382 
383  for ( int j = 1; j <= problem_size; ++j ) {
384  search_direction[j] *= _last_accepted_step;
385  current_position[j] += search_direction[j];
386  }
387 
388 // std::cout << "Linemin used " << this_line_func.get_eval_count() <<
389 // " function calls and returns " << final_value << " on step of " << _last_accepted_step << std::endl;
390 
391  return final_value;
392 }
393 
394 /////////////////////////////////////////////////////////////////////////////
395 //
396 Real
397 ArmijoLineMinimization::Armijo(
398  Real init_step,
399  func_1d & func_eval
400 )
401 {
402  // INPUT PARAMETERS: XX,func,gfrag,NF
403  // OUTPUT PARAMETERS: NF,FRET
404  //
405  // Given a function FUNC, and initial stepsize XX
406  // such that 0 < XX and FUNC has negative derivative _deriv_sum at 0,
407  // this routine returns a stepsize XX at least as good as that
408  // given by Armijo rule.
409  // Reference: D.P. Bertsekas, Nonlinear Programming, 2nd ed, 1999, page 29.
410  Real const FACTOR( 0.5 );
411  Real const SIGMA( 0.1 );
412  Real const SIGMA2( 0.8 );
413  static Real const MINSTEP( basic::options::option[ basic::options::OptionKeys::optimization::armijo_min_stepsize ]() ); // default 1e-8
414 
415  //std::cout << "func_to_beat is " << _func_to_beat << std::endl;
416 
417  Real func_value = func_eval( init_step );
418  _num_calls++;
419 
420  _last_accepted_step = init_step;
421 
422  if (func_value < _func_to_beat+init_step*SIGMA2*_deriv_sum ) {
423  Real test_step = init_step/FACTOR;
424  Real test_func_value = func_eval( test_step );
425  _num_calls++;
426  if (test_func_value < func_value) {
427  _last_accepted_step = test_step;
428  return test_func_value;
429  }
430  return func_value;
431  }
432 
433  Real far_step = init_step;
434  while (func_value > _func_to_beat + init_step*SIGMA*_deriv_sum) {
435  // Abort if function value is unlikely to improve.
436  if ( ( init_step <= 1e-5 * far_step ) ||
437  (init_step < MINSTEP && func_value >= _func_to_beat)) {
438  Real test_step = ( func_value - _func_to_beat ) / init_step;
439  if (!_silent) {
440  TR.Error << "Inaccurate G! step= " << ( init_step ) << " Deriv= " <<
441  ( _deriv_sum ) << " Finite Diff= " << ( test_step ) << std::endl;
442  }
443  func_eval.dump( init_step );
444  _last_accepted_step = 0.0;
445  return _func_to_beat;
446  }
447 
448  init_step *= FACTOR*FACTOR; // faster step decrease
449  // init_step *= FACTOR;
450  //std::cout << "func_eval( " << init_step << ")" << std::endl;
451  func_value = func_eval( init_step );
452  _num_calls++;
453  }
454 
455  _last_accepted_step = init_step;
456 
457  if ( init_step < 0.0 ) {
458  TR << "Forced to do parabolic fit!" << std::endl;
459  // Parabola interpolate between 0 and init_step for refinement
460  Real test_step = -_deriv_sum*init_step*init_step/
461  (2*(func_value - _func_to_beat - init_step * _deriv_sum));
462  if (test_step > 1e-3*far_step && test_step < far_step) {
463  Real test_func_value = func_eval( test_step );
464  _num_calls++;
465  if ( test_func_value < func_value ) {
466  _last_accepted_step = test_step;
467  func_value = test_func_value;
468  }
469  }
470  }
471 
472  return func_value;
473 }
474 
475  /////////////////////////////////////////////////////////////////////////////
476  //
477  Real
478  StrongWolfeLineMinimization::operator()(
479  Multivec & current_position,
480  Multivec & search_direction
481  )
482  {
483 
484  int const problem_size( current_position.size() );
485 // Real max_step_limit( _nonmonotone ? 2.0 : 1.0 );
486 
487  _num_linemin_calls++;
488 
489  // Construct the one-dimensional projection of the function
490  func_1d this_line_func( current_position, search_direction, _func );
491 
492  // Early termination for derivatives (search_direction magnitudes) near zero
493  // Please note that the search_direction vector is not normalized
494  Real derivmax = 0.0;
495  for ( int i = 1 ; i <= problem_size; ++i ) {
496  if ( std::abs( search_direction[ i ] ) >
497  std::abs( derivmax ) ) derivmax = search_direction[ i ];
498  }
499 
500  // if ( runlevel >= gush) std::cout << "derivmax," << SS( derivmax ) << std::endl;
501  if ( std::abs(derivmax) < .0001 ) {
502  Real final_value = this_line_func( 0.0 ); // deriv = 0, return value
503 // TR << "Exiting line minimization due to super small derivative" << std::endl;
504  return final_value;
505  }
506 
507  //initial trial stepsize
508  Real init_step( std::min( 2.0*_last_accepted_step, 1.0 ) );
509 
510  Real final_value = StrongWolfe( init_step, this_line_func );
511 
512  for ( int j = 1; j <= problem_size; ++j ) {
513  search_direction[j] *= _last_accepted_step;
514  current_position[j] += search_direction[j];
515  }
516 
517 // TR << "Linemin used " << this_line_func.get_eval_count() <<
518 // " function calls and " << this_line_func.get_deriv_count() << " deriv calls and returns " << final_value <<
519 // " on step of " << _last_accepted_step << std::endl;
520 
521  return final_value;
522 }
523 
524 /////////////////////////////////////////////////////////////////////////////
525 //
526 Real
527 StrongWolfeLineMinimization::StrongWolfe(
528  Real init_step,
529  func_1d & func_eval
530 )
531 {
532  // Finds iterate that satisfies the strong Wolfe criteria.
533 
534  Real const param_c1( 1.0e-1 );
535  Real const param_c2( 0.8 );
536 
537  Real func_value0( _func_to_beat );
538  Real func_value1( 0.0 );
539  Real func_value_prev( _func_to_beat );
540  Real func_value_return( 0.0 );
541 
542 // Real func_from_zoom( 0.0 );
543 
544  // We already calculated the derivative to get the search direction, there's
545  // no need to do it again
546  Real deriv0( _deriv_sum );
547  Real deriv1( 0.0 );
548  Real deriv_prev( deriv0 );
549 
550  Real alpha0( 0.0 );
551  Real alpha_max( 2.0 );
552  Real alpha_prev( alpha0 );
553  Real alpha1( init_step );
554  Size iterations( 1 );
555 
556  while( true ) {
557  func_value1 = func_eval( alpha1 );
558 
559  if( ( func_value1 > ( func_value0 + ( param_c1 * alpha1 * deriv0 ) ) ) ||
560  ( ( iterations > 1 ) && func_value1 >= func_value_prev ) ) {
561  // Call zoom
562  _last_accepted_step = zoom( alpha_prev, func_value_prev, deriv_prev, alpha1, func_value1, deriv1,
563  func_value0, deriv0, func_value_return, func_eval );
564  store_current_derivatives( func_eval._dE_dvars );
565  return func_value_return;
566  }
567 
568  deriv1 = func_eval.dfunc( alpha1 );
569 
570  if ( std::abs( deriv1 ) <= -1.0 * param_c2 * deriv0 ) {
571 // if ( deriv1 > param_c2 * deriv0 ) {
572  // This corresponds to a point that satisfies both of the strong Wolfe criteria
573  _last_accepted_step = alpha1;
574  store_current_derivatives( func_eval._dE_dvars );
575  return func_value1;
576  }
577 
578  if ( deriv1 >= 0.0 ) {
579  // Call zoom
580 // std::cout << "Zoom entry switch" << std::endl;
581 // std::cout << "Arguments " << alpha1 << " , " << func_value1 << " , " << deriv1 << "\n"
582 // << alpha_prev << " , " << func_value_prev << " , " << deriv_prev << "\n"
583 // << func_value_return << std::endl;
584  _last_accepted_step = zoom( alpha1, func_value1, deriv1, alpha_prev, func_value_prev, deriv_prev,
585  func_value0, deriv0, func_value_return, func_eval );
586  store_current_derivatives( func_eval._dE_dvars );
587  return func_value_return;
588  }
589 
590  iterations++;
591  alpha_prev = alpha1;
592  func_value_prev = func_value1;
593  deriv_prev = deriv1;
594  alpha1 = 0.5*( alpha1 + alpha_max );
595  }
596 }
597 
598 Real
599 StrongWolfeLineMinimization::zoom(
600  Real alpha_low,
601  Real func_low,
602  Real deriv_low,
603  Real alpha_high,
604  Real func_high,
605  Real deriv_high,
606  Real func_zero,
607  Real deriv_zero,
608  Real & func_return,
609  func_1d & func_eval
610 )
611 {
612  Real const param_c1( 1.0e-1 );
613  Real const param_c2( 0.8 );
614 
615  Real alpha_test( 0.0 );
616  Real func_test( 0.0 );
617  Real deriv_test( 0.0 );
618 
619  int static step_count( 0 );
620  Size iterations( 0 );
621  Size const max_iterations_to_try( 8 );
622  Real const min_interval_threshold( 1.0e-5 );
623  Real const min_step_size( 1.0e-5 );
624  Real const scale_factor( 0.66 );
625 
626 
627  // Initial guess at test point. Note that initially, deriv_high may be bogus, so this
628  // is the only interpolation we can safely use. Don't be tempted to try a cubic or quadratic
629  // with derivative interpolations.
630  alpha_test = quadratic_interpolation( alpha_low, func_low, deriv_low, alpha_high, func_high );
631 
632  while( true ) {
633 
634  iterations++;
635 
636 // if( deriv_low*(alpha_high - alpha_low) > 0.0 ) {
637 // std::cout << "Bad deriv at alpha_low!" << std::endl;
638 // }
639 
640 // std::cout << "Got point alpha_test of " << alpha_test << " from low " << alpha_low << " and high " << alpha_high << " on step " << step_count << std::endl;
641 
642  func_test = func_eval( alpha_test );
643  deriv_test = func_eval.dfunc( alpha_test );
644 
645  if( iterations > max_iterations_to_try ) {
646 // std::cout << "Warning - More'-Thuente line search exceeded max_iterations_to_try - returning current value" << std::endl;
647 // if( func_test < func_low ) {
648 // std::cout << "But at least func is less than start!" << std::endl;
649 // } else {
650 // std::cout << "And func is more than start!" << std::endl;
651 // }
652  func_return = func_test;
653  return alpha_test;
654  }
655 
656  if( std::abs( alpha_low - alpha_high ) <= min_interval_threshold ) {
657 // std::cout << "Warning - More'-Thuente line search interval below threshold - returning current value" << std::endl;
658 // if( func_test < func_low ) {
659 // std::cout << "But at least func is less than start!" << std::endl;
660 // } else {
661 // std::cout << "And func is more than start!" << std::endl;
662 // }
663  func_return = func_test;
664  return alpha_test;
665  }
666 
667  if( alpha_test <= min_step_size ) {
668 // std::cout << "Warning - More'-Thuente line search interval below threshold - returning current value" << std::endl;
669 // if( func_test < func_low ) {
670 // std::cout << "But at least func is less than start!" << std::endl;
671 // } else {
672 // std::cout << "And func is more than start!" << std::endl;
673 // }
674  func_return = func_test;
675  return alpha_test;
676  }
677 
678  step_count++;
679 
680  if( ( func_test > func_zero + param_c1 * alpha_test * deriv_zero ) ||
681  ( func_test >= func_low ) ) {
682 
683  // This is the case where the value at the test point is too high,
684  // so we need to find a new test point in between the start point and
685  // this point via interpolation.
686 
687 // std::cout << "Branch/Case 1" << std::endl;
688 
689  alpha_high = alpha_test;
690  func_high = func_test;
691  deriv_high = deriv_test;
692 
693  Real cubic_interp = cubic_interpolation( alpha_low, func_low, deriv_low, alpha_test, func_test, deriv_test );
694  Real quadratic_interp = quadratic_interpolation( alpha_low, func_low, deriv_low, alpha_test, func_test );
695 
696  if( std::abs( cubic_interp - alpha_low ) < std::abs( quadratic_interp - alpha_low ) ) {
697  alpha_test = cubic_interp;
698  } else {
699  alpha_test = 0.5 * ( cubic_interp + quadratic_interp );
700  }
701 
702  } else {
703  if( std::abs( deriv_test ) <= -1.0 * param_c2 * deriv_zero ) {
704 // if( deriv_test > param_c2 * deriv_zero ) {
705  // If we hit this we are done
706  func_return = func_test;
707  return alpha_test;
708  }
709 
710  Real save_alpha_test = alpha_test;
711  Real save_func_test = func_test;
712  Real save_deriv_test = deriv_test;
713 
714 
715  // Logic for next test point - in each case the value at the test point was lower than
716  // the start point, but the Wolfe curvature criteria was not met.
717  if( deriv_test*deriv_low < 0.0 ) {
718 
719  // This case is straightforward. The derivative at the test point is opposite to that
720  // of the start point, so the bracketing is good. We calculate the cubic and quad w/ deriv
721  // interpolated guesses at the minimum, then take whichever is closest to the test point.
722  // We want to be closer to the test point since it satisfies the sufficient descent
723  // criterion, and we just need to get closer to the actual minimum to decrease the
724  // derivative an satisfy the curvature criterion.
725 
726 // std::cout << "Case 2" << std::endl;
727 
728  Real cubic_interp = cubic_interpolation( alpha_low, func_low, deriv_low, alpha_test, func_test, deriv_test );
729  Real quadratic_interp = secant_interpolation( alpha_low, deriv_low, alpha_test, deriv_test );
730 
731 // std::cout << "Got cubic alpha_test of " << cubic_interp << " from low " << alpha_low << " and test " << alpha_test << " on step " << step_count << std::endl;
732 // std::cout << "Got secant alpha_test of " << quadratic_interp << " from low " << alpha_low << " and test " << alpha_test << " on step " << step_count << std::endl;
733 
734 // std::cout << "Derivs are low " << deriv_low << " and test " << deriv_test << std::endl;
735 
736  if( std::abs( cubic_interp - alpha_test ) >= std::abs( quadratic_interp - alpha_test ) ) {
737 // std::cout << "Using cubic" << std::endl;
738  alpha_test = cubic_interp;
739  } else {
740 // std::cout << "Using quadratic" << std::endl;
741  alpha_test = quadratic_interp;
742  }
743 
744  } else if ( std::abs( deriv_test ) <= std::abs( deriv_low ) ) {
745  // This is the hardest case - the slopes at low and test are in the same direction
746  // and func_test is lower than func_low, so we're going in the correct direction, but
747  // it's hard to tell how far to go next.
748 
749  // This is not as rigorous as in More' and Thuente 1994
750 
751 // std::cout << "Case 3" << std::endl;
752 
753 // std::cout << "Low : " << alpha_low << " , " << func_low << " , " << deriv_low << std::endl;
754 // std::cout << "Test: " << alpha_test << " , " << func_test << " , " << deriv_test << std::endl;
755 // std::cout << "High: " << alpha_high << " , " << func_high << " , " << deriv_high << std::endl;
756 
757  Real try_alpha_test = secant_interpolation( alpha_low, deriv_low, alpha_test, deriv_test );
758 // Real try_alpha_test = quadratic_interpolation( alpha_test, func_test, deriv_test, alpha_high, func_high );
759  // If this is outside of the bounds of (alpha_test, alpha_high), scale back
760  Real scaled_alpha_test = alpha_test + scale_factor*( alpha_high - alpha_test );
761 
762 // std::cout << "Got interpolated alpha_test of " << try_alpha_test << std::endl;
763  if( alpha_test > alpha_low ) {
764 // std::cout << "Rescaling case 1!" << std::endl;
765  alpha_test = std::min( scaled_alpha_test, try_alpha_test );
766  } else {
767 // std::cout << "Rescaling case 2!" << std::endl;
768  alpha_test = std::max( scaled_alpha_test, try_alpha_test );
769  }
770 // std::cout << "Post out-of-bounds check alpha_test is " << alpha_test << std::endl;
771 
772  } else {
773 // std::cout << "Case 4" << std::endl;
774 
775  // deriv_high may be totally bogus?
776  if( deriv_high == 0.0 ) {
777  alpha_test = quadratic_interpolation( alpha_test, func_test, deriv_test, alpha_high, func_high );
778  } else {
779  alpha_test = cubic_interpolation( alpha_test, func_test, deriv_test, alpha_high, func_high, deriv_high );
780  }
781  }
782 
783 
784  // Finally, adjust boundaries of the interval
785 
786  if( ( deriv_test * ( alpha_test - alpha_low ) ) >= 0.0 ) {
787 // std::cout << "Branch 2 if check" << std::endl;
788  alpha_high = alpha_low;
789  func_high = func_low;
790  deriv_high = deriv_low;
791  }
792 // std::cout << "Branch 2" << std::endl;
793  alpha_low = save_alpha_test;
794  func_low = save_func_test;
795  deriv_low = save_deriv_test;
796  }
797 
798  // Safeguard the new step
799  if( alpha_high > alpha_low ) {
800  alpha_test = std::min( alpha_low + scale_factor*( alpha_high - alpha_low ), alpha_test );
801  } else {
802  alpha_test = std::max( alpha_low + scale_factor*( alpha_high - alpha_low ), alpha_test );
803  }
804 
805 // std::cout << "For next round" << std::endl;
806 // std::cout << "Low : " << alpha_low << " , " << func_low << " , " << deriv_low << std::endl;
807 // std::cout << "Test: " << alpha_test << " , " << func_test << " , " << deriv_test << std::endl;
808 // std::cout << "High: " << alpha_high << " , " << func_high << " , " << deriv_high << std::endl;
809 
810  }
811 
812 }
813 
814 void
815 LineMinimizationAlgorithm::store_current_derivatives(
816  Multivec & curr_derivs
817 )
818 {
819 // std::cout << "Storing derivatives" << " size " << _stored_derivatives.size() << std::endl;
820  for( uint i = 1 ; i <= _stored_derivatives.size() ; ++i ) {
821  _stored_derivatives[i] = curr_derivs[i];
822 // if( i <= 10 ) std::cout << "Storing deriv " << i << " as " << _stored_derivatives[i] << std::endl;
823  }
824 }
825 
826 void
827 LineMinimizationAlgorithm::fetch_stored_derivatives(
828  Multivec & set_derivs
829 )
830 {
831 // std::cout << "Fetching derivatives" << " size " << _stored_derivatives.size() << std::endl;
832  for( uint i = 1 ; i <= _stored_derivatives.size() ; ++i ) {
833  set_derivs[i] = _stored_derivatives[i];
834 // if( i <= 10 ) std::cout << "Fetching deriv " << i << " as " << set_derivs[i] << std::endl;
835  }
836 }
837 
838 
839 Real
840 LineMinimizationAlgorithm::quadratic_interpolation(
841  Real alpha_low,
842  Real func_low,
843  Real deriv_low,
844  Real alpha_high,
845  Real func_high
846 )
847 {
848  return ( 2.0*alpha_low*( func_high - func_low ) -
849  deriv_low * ( alpha_high*alpha_high - alpha_low*alpha_low ) ) /
850  ( 2.0 * ( (func_high - func_low ) - ( deriv_low * ( alpha_high - alpha_low ) ) ) );
851 }
852 
853 Real
854 LineMinimizationAlgorithm::quadratic_deriv_interpolation(
855  Real alpha_low,
856  Real func_low,
857  Real deriv_low,
858  Real alpha_high,
859  Real func_high,
860  Real // deriv_high
861 )
862 {
863 // Real const alpha_diff( alpha_high - alpha_low );
864 // Real const deriv_diff( deriv_high - deriv_low );
865 // return ( alpha_low - ( deriv_low * alpha_diff / deriv_diff ) );
866  return ( alpha_low + ( (deriv_low/((func_low - func_high)/(alpha_high - alpha_low) + deriv_low))*0.5) *(alpha_high -alpha_low) );
867 }
868 
869 Real
870 LineMinimizationAlgorithm::secant_interpolation(
871  Real alpha_low,
872  Real deriv_low,
873  Real alpha_high,
874  Real deriv_high
875 )
876 {
877 // Real const alpha_diff( alpha_high - alpha_low );
878 // Real const deriv_diff( deriv_high - deriv_low );
879  return ( alpha_low + (deriv_low/(deriv_low - deriv_high))*(alpha_high -alpha_low) );
880 }
881 
882 Real
883 LineMinimizationAlgorithm::cubic_interpolation(
884  Real alpha_low,
885  Real func_low,
886  Real deriv_low,
887  Real alpha_high,
888  Real func_high,
889  Real deriv_high
890 )
891 {
892  Real cubic_beta1 = deriv_low + deriv_high - 3.0*( func_low - func_high )/(alpha_low - alpha_high);
893  Real max_beta_derivs = std::max( std::max( std::abs( cubic_beta1), std::abs( deriv_low ) ), std::abs( deriv_high ) );
894  Real gamma = max_beta_derivs * std::sqrt( std::pow( cubic_beta1 / max_beta_derivs, 2.0 ) - (deriv_low/max_beta_derivs)*(deriv_high/max_beta_derivs));
895  if( alpha_high < alpha_low ) gamma = -gamma;
896  Real numer = (gamma - deriv_low) + cubic_beta1;
897  Real denom = ((gamma - deriv_low) + gamma) + deriv_high;
898  Real fraction = numer/denom;
899 // Real cubic_beta2 = std::sqrt( cubic_beta1*cubic_beta1 - (deriv_low * deriv_high) );
900 // return ( alpha_high - (alpha_high - alpha_low)*( deriv_high + cubic_beta2 - cubic_beta1 ) /
901 // (deriv_high - deriv_low + 2.0*cubic_beta2 ) );
902  return ( alpha_low + fraction * ( alpha_high - alpha_low ) );
903 }
904 
905 
906 
907 
908 
909 } // namespace optimization
910 } // namespace core