Interior-point-optimisation  1.0-1
Interior-pointoptimisationlibrary
LineSearch.cc
Go to the documentation of this file.
1 /*
2  * $Id: LineSearch.cc 219 2014-11-09 08:59:54Z jdl3 $
3  * Copyright (C) 2011, 2013 John D Lamb
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or (at
8  * your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 # include<config.h>
22 #endif
23 
24 #include"LineSearch.hpp"
25 
26 using namespace ipo::detail;
27 
28 LineSearch::Parameters::Parameters( double const alpha, double const beta,
29  double const epsilon, size_t const maxNoImproveSteps ){
30  setAlpha( alpha );
31  setBeta( beta );
32  setEpsilon( epsilon );
33  setMaxNoImproveSteps( maxNoImproveSteps );
34  setVectorDigits( 0 );
35  setOutputStream( nullptr );
36 }
37 
40 
41 LineSearch::LineSearch( ipo_function::Function& function, double const alpha,
42  double const beta,
43  double const epsilon, size_t const maxNoImproveSteps )
44  : parameters { alpha, beta, epsilon, maxNoImproveSteps }, function( function ){}
45 
46 void
48  if( alpha <= 0 ) alpha = std::numeric_limits<double>::epsilon();
49  if( alpha >= 0.5 ) alpha = 0.5 - std::numeric_limits<double>::epsilon();
50  this->alpha = alpha;
51 }
52 
53 void
55  if( beta <= 0 ) beta = std::numeric_limits<double>::epsilon();
56  if( beta >= 1 ) beta = 1 - std::numeric_limits<double>::epsilon();
57  this->beta = beta;
58 }
59 
60 void
62  if( epsilon <= 0 ) epsilon = std::numeric_limits<double>::epsilon();
63  this->epsilon = epsilon;
64 }
65 
66 double
68  return alpha;
69 }
70 
71 double
73  return beta;
74 }
75 
76 double
78  return epsilon;
79 }
80 
81 double
82 LineSearch::operator()( gsl::vector& vector, gsl::vector const direction,
83  double const functionValue, gsl::vector const gradientValue ){
84  // Initialise
85  double const& epsilon { parameters.getEpsilon() };
86  size_t const SIZE { vector.size() };
87  auto const outputStream = parameters.getOutputStream();
88  // storage
89  gsl::vector testPoint { gsl::vector( SIZE ) };
90  // Local function
91  auto fDeltat = [&testPoint,this]( gsl::vector const& x, gsl::vector const& delta,
92  double const t )->double {
93  // compute testPoint
94  testPoint.memcpy( delta );
95  testPoint.scale( t );
96  testPoint.add( x );
97  return this->function( testPoint );
98  };
99 
100  // Get gradient and delta
101  auto gradient = [this,&epsilon,&vector,&gradientValue]()->gsl::vector {
102  if( gradientValue.get() == nullptr ){
103  // Have to compute a gradient value
105  gradientEstimate( this->function, epsilon );
106  gradientEstimate.setVector( vector );
107  return gradientEstimate.gradient();
108  } else
109  return gradientValue;
110  }();
111 
112  double d { 0 };
113  gsl::blas::ddot( gradient, direction, &d );
114  double const delta { parameters.getAlpha() * d };
115 
116  // get initial function value
117  double const f0 { functionValue > -std::numeric_limits<double>::infinity() ?
118  functionValue : function( vector ) };
119 
120  // initialise t to 1
121  double t { 1 };
122 
123  // Set up to check improvement
124  double fBest { f0 };
125  double fLast { f0 };
126  double tBest { 1 };
127  size_t nonImproving { 0 };
128  bool feasibleStep { false };
129 
130  // loop: check for infinite case
131  bool positiveStepSize { false };
132  double f { fDeltat( vector, direction, t ) };
133  // Possible output
134  size_t iteration { 0 };
135  size_t const& digits { parameters.getVectorDigits() };
136  if( outputStream != nullptr ){
137  *outputStream << "Line search:" << std::endl;
138  *outputStream << "step "
139  << ( digits > 0 ? "x " : "") << "f(x)" << std::endl;
140  *outputStream << " " << std::setw( 4 ) << iteration << " ";
141  if( digits > 0 ){
142  *outputStream << "( ";
143  for( size_t i = 0; i < SIZE; ++i ){
144  *outputStream << std::setw( 4 + digits ) << std::setprecision( digits ) << std::fixed
145  << testPoint.get( i ) << " ";
146  }
147  *outputStream << ")";
148  }
149  size_t const d { std::max( static_cast<size_t>( 6 ), digits ) };
150  *outputStream << std::setw( 4 + d ) << std::setprecision( d ) << std::fixed
151  << f * functionScale << std::endl;
152  }
153  while( f > f0 + t * delta or f != f ){ // or condition forces check for NaN
154  ++iteration;
155  positiveStepSize = true;
156  // compute testPoint
157  if( f < f0 ) feasibleStep = true;
158  // Decide whether improvement has occurred
159  if( f < fBest ){
160  nonImproving = 0;
161  tBest = t;
162  fBest = f;
163  } else if( f < fLast ){
164  nonImproving = 0;
165  } else {
166  if( feasibleStep ){
167  if( ++nonImproving > parameters.getMaxNoImproveSteps() )
168  break; // and return
169  }
170  }
171  constexpr double std_eps { std::numeric_limits<double>::epsilon() };
172  if( t < std_eps ) break;
173  // Record last observed value
174  fLast = f;
175  // New value of t
176  t *= parameters.getBeta();
177  // New value of f
178  f = fDeltat( vector, direction, t );
179  // Possibly put some output
180  if( parameters.getOutputStream() != nullptr ){
181  *outputStream << " " << std::setw( 4 ) << iteration << " ";
182  if( digits > 0 ){
183  *outputStream << "( ";
184  for( size_t i { 0 }; i < SIZE; ++i ){
185  *outputStream << std::setw( 4 + digits ) << std::setprecision( digits ) << std::fixed
186  << testPoint.get( i ) << " ";
187  }
188  *outputStream << ")";
189  }
190  size_t const d { std::max( static_cast<size_t>( 6 ), digits ) };
191  *outputStream << std::setw( 4 + d ) << std::setprecision( d ) << std::fixed
192  << f * functionScale << std::endl;
193  }
194  }
195  if( fBest < f ){
196  t = tBest;
197  f = fDeltat( vector, direction, t ); // Changes testPoint.
198  }
199 
200  if( f < f0 and (positiveStepSize or true) ){
201  // return testpoint
202  vector = testPoint;
203 
204  // return t
205  return t;
206  } else {
207  return 0;
208  }
209 
210 }
211 
212 void
214  this->maxNoImproveSteps = maxNoImproveSteps;
215 }
216 
217 size_t
219  return maxNoImproveSteps;
220 }
virtual void setVector(gsl::vector const &vector)
Set the vector to a new value.
void setMaxNoImproveSteps(size_t maxNoImproveSteps)
Set the value of maxNoImproveSteps.
Definition: LineSearch.cc:213
double functionScale
Scaling factor for output of function values.
Definition: LineSearch.hpp:224
size_t getVectorDigits() const
Get the value of vectorDigits.
Definition: LineSearch.hpp:110
This class estimates a function value, gradient and Hessian at a given vector.
double getAlpha() const
Get the value of alpha.
Definition: LineSearch.cc:67
LineSearch(ipo_function::Function &function, double const alpha=1e-3, double const beta=0.8, double const epsilon=std::sqrt(std::numeric_limits< double >::epsilon()), size_t const maxNoImproveSteps=10)
Set up the line search function object with a function and some default parameters.
Definition: LineSearch.cc:41
virtual gsl::vector gradient() const
double alpha
A value in (0,0.5): usually quite small 0.0001–0.3 (default 1e-3 though 1e-4 is suggested in Dennis ...
Definition: LineSearch.hpp:132
Parameters & getParameters()
Get parameters by reference.
Definition: LineSearch.cc:39
double operator()(gsl::vector &vector, gsl::vector const direction, double const functionValue=-std::numeric_limits< double >::infinity(), gsl::vector const gradientValue=gsl::vector(nullptr))
Carry out the line search.
Definition: LineSearch.cc:82
void setVectorDigits(size_t const vectorDigits)
Set the number of significant digits of entries of vector to show in each step.
Definition: LineSearch.hpp:103
void setOutputStream(std::ostream *outputStream)
Set outputStream.
Definition: LineSearch.hpp:115
Namespace for classes that handle details of interior-point optimisation that are not ordinarily acce...
Definition: Model.hpp:316
This class computes a function at a vector.
Definition: Function.hpp:38
void setBeta(double beta)
Set the value of beta.
Definition: LineSearch.cc:54
Parameters(double const alpha=1e-3, double const beta=0.8, double const epsilon=std::sqrt(std::numeric_limits< double >::epsilon()), size_t const maxNoImproveSteps=10)
Set up some default parameters.
Definition: LineSearch.cc:28
Line search parameters.
Definition: LineSearch.hpp:42
void setEpsilon(double epsilon)
Set the value of epsilon.
Definition: LineSearch.cc:61
void setAlpha(double alpha)
Set the value of alpha.
Definition: LineSearch.cc:47
double getBeta() const
Get the value of beta.
Definition: LineSearch.cc:72
std::ostream * getOutputStream() const
Get the current value of outputStream.
Definition: LineSearch.hpp:121
double getEpsilon() const
Get the value of epsilon.
Definition: LineSearch.cc:77
size_t getMaxNoImproveSteps() const
Get the value of maxNoImproveSteps.
Definition: LineSearch.cc:218
std::string const infinity
Infinity sign, ∞.
Definition: Format.hpp:54