Interior-point-optimisation  1.0-1
Interior-pointoptimisationlibrary
BarrierFunction.cc
Go to the documentation of this file.
1 /*
2  * $Id: BarrierFunction.cc 222 2014-11-09 14:04:41Z jdl3 $
3  * Copyright (C) 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"BarrierFunction.hpp"
25 
26 using namespace ipo::detail;
27 
28 BarrierFunction::BarrierFunction( Model& model, Sign const sign, double const t )
29  : model( model ), sign { sign }, t{ t }
30 {
31  size_t const SIZE { model.indexMap.size() };
32  functionGradient = gsl::vector( SIZE );
33  functionHessian = gsl::matrix( SIZE, SIZE );
34 }
35 
36 void
37 BarrierFunction::set_t( double const t ){
38  this->t = t;
39 }
40 
41 double
43  return t;
44 }
45 
46 double
47 BarrierFunction::operator()( gsl::vector const& vector ){
48  // First, the objective function
49  gsl::vector subvector { model.objectiveIndices->get( vector ) };
50  // Update
51  initialiseResultFromObjective( subvector );
52 
53  // Then the explicit constraints
54  for( size_t j { 0 }; j < model.constraints.size(); ++j ){
55  auto& constraintIndices_j = model.constraintIndices[j];
56  subvector = constraintIndices_j->get( vector );
57  auto& constraint = model.constraints[j];
58  // get bounds
59  double const upperBound { constraint.getUpperBound() };
60  double const lowerBound { constraint.getLowerBound() };
61  if( upperBound >= infinity and lowerBound <= minusInfinity ) continue;
62  double const f { (*constraint.getFunction())( subvector ) };
63  // Update
64  updateResultFromConstraint( constraint, subvector, lowerBound, f, upperBound );
65  }
66 
67  // Then any variable constraints
68  for( auto& entry : model.indexMap )
69  // Update
70  updateResultFromVariable( entry, vector );
71 
72  // Finally, return result
73  return functionValue;
74 }
75 
76 gsl::vector
77 BarrierFunction::gradient( gsl::vector const& vector ){
78  // First, the objective function
79  gsl::vector subvector { model.objectiveIndices->get( vector ) };
80  // Update
82 
83  // Then the explicit constraints
84  for( size_t j { 0 }; j < model.constraints.size(); ++j ){
85  auto& constraintIndices_j = model.constraintIndices[j];
86  subvector = constraintIndices_j->get( vector );
87  auto& constraint = model.constraints[j];
88  // get bounds
89  double const upperBound { constraint.getUpperBound() };
90  double const lowerBound { constraint.getLowerBound() };
91  if( upperBound >= infinity and lowerBound <= minusInfinity ) continue;
92  double const f { (*constraint.getFunction())( subvector ) };
93  // Update
95  }
96 
97  // Then any variable constraints
98  for( auto& entry : model.indexMap )
99  // Update
100  updateGradientFromVariable( entry, vector );
101 
102  // Finally, return result
103  return functionGradient;
104 }
105 
106 gsl::matrix
107 BarrierFunction::hessian( gsl::vector const& vector ){
108  // First, the objective function
109  gsl::vector subvector { model.objectiveIndices->get( vector ) };
110  // Update
111  initialiseHessianFromObjective( subvector );
112 
113  // Then the explicit constraints
114  for( size_t j = 0; j < model.constraints.size(); ++j ){
115  auto& constraintIndices_j = model.constraintIndices[j];
116  subvector = constraintIndices_j->get( vector );
117  auto& constraint = model.constraints[j];
118  // get bounds
119  double const upperBound { constraint.getUpperBound() };
120  double const lowerBound { constraint.getLowerBound() };
121  if( upperBound >= infinity and lowerBound <= minusInfinity ) continue;
122  double const f { (*constraint.getFunction())( subvector ) };
123  // Update
124  gsl::vector gradient { constraint.getFunction()->gradient( subvector ) };
126  }
127 
128  // Then any variable constraints
129  for( auto& entry : model.indexMap )
130  // Update
131  updateHessianFromVariable( entry, vector );
132 
133  // Finally, return result
134  return functionHessian;
135 }
136 
137 void
138 BarrierFunction::initialiseResultFromObjective( gsl::vector& subvector, bool const simul ){
139  functionValue = 0;
141  = dynamic_cast<DerivativesEstimates*>( model.objective.getFunction() );
142  if( simul and nullptr != de ){
143  de->setVector( subvector );
144  if( Sign::positive == sign )
145  functionValue += t * de->value();
146  else
147  functionValue -= t * de->value();
148  } else {
149  if( Sign::positive == sign )
150  functionValue += t * (*model.objective.getFunction())( subvector );
151  else
152  functionValue -= t * (*model.objective.getFunction())( subvector );
153  }
154 }
155 
156 void
157 BarrierFunction::updateResultFromConstraint( Constraint& constraint, gsl::vector& subvector,
158  double const& lowerBound,
159  double const& functionValue,
160  double const& upperBound ){
161  // Add constraints for upper and lower bounds.
162  if( upperBound < infinity )
163  this->functionValue -= std::log( upperBound - functionValue );
164  if( lowerBound > minusInfinity )
165  this->functionValue -= std::log( functionValue - lowerBound );
166 }
167 
168 void
169 BarrierFunction::updateResultFromVariable( std::map<Variable,size_t>::value_type& entry,
170  gsl::vector const& vector ){
171  Variable const& variable { entry.first };
172  // get bounds
173  double const upperBound { variable.getUpperBound() };
174  double const lowerBound { variable.getLowerBound() };
175  if( upperBound >= infinity and lowerBound <= minusInfinity ) return;
176  double const f = vector[entry.second];
177  // Add results for upper and lower bounds.
178  if( upperBound < infinity )
179  functionValue -= std::log( upperBound - f );
180  if( lowerBound > minusInfinity )
181  functionValue -= std::log( f - lowerBound );
182 }
183 
184 gsl::vector
185 BarrierFunction::initialiseGradientFromObjective( gsl::vector& subvector, bool const simul ){
187  de = dynamic_cast<DerivativesEstimates*>( model.objective.getFunction() );
188  gsl::vector gradient { simul and nullptr != de ? de->gradient()
189  : model.objective.getFunction()->gradient( subvector ) };
190  // In any case initialise functionGradient
191  if( functionGradient.size() != model.indexMap.size() )
192  functionGradient = gsl::vector( model.indexMap.size() );
193  functionGradient.set_all( 0 );
194  // and copy to functionGradient;
195  if( Sign::positive == sign ){
197  } else {
199  }
200  // Return objective gradient
201  return gradient;
202 }
203 
204 gsl::vector
205 BarrierFunction::updateGradientFromConstraint( size_t const constraintIndex,
206  gsl::vector& subvector,
207  double const& lowerBound,
208  double const& functionValue,
209  double const& upperBound, bool const simul ){
210  auto& constraint = model.constraints[constraintIndex];
212  de = dynamic_cast<DerivativesEstimates*>( constraint.getFunction() );
213  gsl::vector gradient { simul and nullptr != de ? de->gradient()
214  : constraint.getFunction()->gradient( subvector ) };
215  // Now gradient is set correctly
216  if( upperBound < infinity ){
217  double const scale_inv { upperBound - functionValue };
218  double const scale { 1.0 / scale_inv };
219  model.constraintIndices[constraintIndex]->add( functionGradient, gradient, scale );
220  }
221  if( lowerBound > minusInfinity ){
222  double const scale_inv { lowerBound - functionValue };
223  double const scale { 1.0 / scale_inv };
224  model.constraintIndices[constraintIndex]->add( functionGradient, gradient, scale );
225  }
226  return gradient;
227 }
228 
229 void
230 BarrierFunction::updateGradientFromVariable( std::map<Variable,size_t>::value_type& entry,
231  gsl::vector const& vector ){
232  Variable const& variable { entry.first };
233  // get bounds
234  double const upperBound { variable.getUpperBound() };
235  double const lowerBound { variable.getLowerBound() };
236  if( upperBound >= infinity and lowerBound <= minusInfinity ) return;
237  double const f { vector[entry.second] };
238  // Add results for upper and lower bounds.
239  if( upperBound < infinity ){
240  double const scale_inv { upperBound - f };
241  double const scale { 1.0 / scale_inv };
242  functionGradient[entry.second] += scale;
243  }
244  if( lowerBound > minusInfinity ){
245  double const scale_inv { lowerBound - f };
246  double const scale { 1.0 / scale_inv };
247  functionGradient[entry.second] += scale;
248  }
249 }
250 
251 void
252 BarrierFunction::initialiseHessianFromObjective( gsl::vector& subvector, bool const simul ){
253  size_t const SIZE { model.indexMap.size() };
254  // In any case initialise functionHessian
255  if( functionHessian.size1() != SIZE or functionHessian.size2() != SIZE )
256  functionHessian = gsl::matrix( SIZE, SIZE );
257  functionHessian.set_all( 0 );
258  // set hessian of objective
260  de = dynamic_cast<DerivativesEstimates*>( model.objective.getFunction() );
261  gsl::matrix hessian { simul and nullptr != de ? de->hessian()
262  : model.objective.getFunction()->hessian( subvector ) };
263  // Copy to functionHessian;
264  if( Sign::positive == sign ){
266  } else {
268  }
269 }
270 
271 void
272 BarrierFunction::updateHessianFromConstraint( size_t const constraintIndex,
273  gsl::vector& subvector,
274  double const& lowerBound,
275  double const& functionValue,
276  double const& upperBound,
277  gsl::vector& gradient, bool const simul ){
278  auto& constraint = model.constraints[constraintIndex];
280  de = dynamic_cast<DerivativesEstimates*>( constraint.getFunction() );
281  gsl::matrix hessian { simul and nullptr != de ? de->hessian()
282  : constraint.getFunction()->hessian( subvector ) };
283  // Now update from hessian
284  if( upperBound < infinity ){
285  double const scale_inv { upperBound - functionValue };
286  double const scale { 1.0 / scale_inv };
287  double const scale2 { scale * scale };
288  model.constraintIndices[constraintIndex]->add( functionHessian, gradient, scale2 );
289  model.constraintIndices[constraintIndex]->add( functionHessian, hessian, scale );
290  }
291  if( lowerBound > minusInfinity ){
292  double const scale_inv { functionValue - lowerBound };
293  double const scale { 1.0 / scale_inv };
294  double const scale2 { scale * scale };
295  model.constraintIndices[constraintIndex]->add( functionHessian, gradient, scale2 );
296  model.constraintIndices[constraintIndex]->add( functionHessian, hessian, scale );
297  }
298 }
299 
300 void
301 BarrierFunction::updateHessianFromVariable( std::map<Variable,size_t>::value_type& entry,
302  gsl::vector const& vector ){
303  Variable const& variable { entry.first };
304  // get bounds
305  double const upperBound { variable.getUpperBound() };
306  double const lowerBound { variable.getLowerBound() };
307  if( upperBound >= infinity and lowerBound <= minusInfinity ) return;
308  double const f { vector[entry.second] };
309  // Add results for upper and lower bounds.
310  if( upperBound < infinity ){
311  double const scale_inv { f - upperBound };
312  double const scale { 1.0 / scale_inv };
313  double const scale2 { scale * scale };
314  double const d { functionHessian.get( entry.second, entry.second ) + scale2 };
315  functionHessian.set( entry.second, entry.second, d );
316  }
317  if( lowerBound > minusInfinity ){
318  double const scale_inv { lowerBound - f };
319  double const scale { 1.0 / scale_inv };
320  double const scale2 { scale * scale };
321  double const d { functionHessian.get( entry.second, entry.second ) + scale2 };
322  functionHessian.set( entry.second, entry.second, d );
323  }
324 }
325 
326 void
327 BarrierFunction::setVector( gsl::vector const& vector ){
328  // vector is not actually stored anywhere
329 
330  // First, the objective function
331  auto subvector = model.objectiveIndices->get( vector );
332  // Update
333  initialiseResultFromObjective( subvector, true );
334  initialiseGradientFromObjective( subvector, true );
335  initialiseHessianFromObjective( subvector, true );
336 
337  // Then the explicit constraints
338  for( size_t j { 0 }; j < model.constraints.size(); ++j ){
339  subvector = model.constraintIndices[j]->get( vector );
340  auto& constraint = model.constraints[j];
341  // get bounds
342  double const upperBound { constraint.getUpperBound() };
343  double const lowerBound { constraint.getLowerBound() };
344  if( upperBound >= infinity and lowerBound <= minusInfinity ) continue;
345  // Try cross-casting
346  DerivativesEstimates* de = dynamic_cast<DerivativesEstimates*>( constraint.getFunction() );
347  // Make sure constraint value and derivatives are calculated
348  if( nullptr != de ) de->setVector( subvector );
349  double const f { nullptr == de ? (*constraint.getFunction())( subvector ) : de->value() };
350  // Update
351  updateResultFromConstraint( constraint, subvector, lowerBound, f, upperBound );
352  auto gradient
353  = updateGradientFromConstraint( j, subvector, lowerBound, f, upperBound, true );
354  updateHessianFromConstraint( j, subvector, lowerBound, f, upperBound, gradient, true);
355  }
356 
357  // Then any variable constraints
358  for( auto& entry : model.indexMap ){
359  // Update
360  updateResultFromVariable( entry, vector );
361  updateGradientFromVariable( entry, vector );
362  updateHessianFromVariable( entry, vector );
363  }
364 }
std::map< Variable, size_t > indexMap
Used internally to match the variables in each variable to indices in a vector.
Definition: Model.hpp:903
virtual gsl::matrix hessian()
Get Hessian value from last call to setValue();.
void set_t(double const t)
Set t to a new value.
void updateHessianFromVariable(std::map< Variable, size_t >::value_type &entry, gsl::vector const &vector)
Update hessian from a variable.
Sign const sign
Set this to true or false according as the objective is to be added or subtracted.
double functionValue
The function value.
void updateResultFromVariable(std::map< Variable, size_t >::value_type &entry, gsl::vector const &vector)
Update result from a variable.
void initialiseHessianFromObjective(gsl::vector &subvector, bool const simul=false)
Update gradient from objective.
virtual void setVector(gsl::vector const &vector)
Set value of vector.
gsl::vector functionGradient
The gradient value.
double constexpr infinity
Infinity: use for unbounded variables.
Definition: Var.hpp:30
virtual double operator()(gsl::vector const &vector)
Evaluate the function.
gsl::vector updateGradientFromConstraint(size_t const constraintIndex, gsl::vector &subvector, double const &lowerBound, double const &functionValue, double const &upperBound, bool const simul=false)
Update gradient from a constraint.
Model & model
The value t used to determine the barrier.
gsl::matrix functionHessian
The Hessian value.
double t
The value t used to determine the barrier.
Objective objective
The objective function.
Definition: Model.hpp:880
virtual gsl::vector gradient()
Get gradient value from last call to setValue();.
std::vector< Constraint > constraints
The set of constraints.
Definition: Model.hpp:872
Class for a constraint function.
Definition: Constraint.hpp:40
virtual gsl::vector gradient(gsl::vector const &vector)
Compute or estimate a gradient value.
Definition: Function.cc:31
Model an interior-point optimisation problem.
Definition: Model.hpp:325
double get_t() const
Get t value.
Namespace for classes that handle details of interior-point optimisation that are not ordinarily acce...
Definition: Model.hpp:316
void updateResultFromConstraint(Constraint &constraint, gsl::vector &subvector, double const &lowerBound, double const &functionValue, double const &upperBound)
Update result from a constraint.
gsl::vector initialiseGradientFromObjective(gsl::vector &subvector, bool const simul=false)
Update gradient from objective.
Sign
Enumerated type used to determine sign of objective in BarrierFunction.
This class represents a variable.
Definition: Variable.hpp:36
void updateHessianFromConstraint(size_t const constraintIndex, gsl::vector &subvector, double const &lowerBound, double const &functionValue, double const &upperBound, gsl::vector &gradient, bool const simul=false)
Update Hessian from a constraint.
BarrierFunction(Model &model, Sign const sign=Sign::positive, double const t=0.1)
The constructor needs a Model.
virtual ::ipo_function::Function * getFunction()
Get function.
void initialiseResultFromObjective(gsl::vector &subvector, bool const simul=false)
Update result from objective.
data lowerBound
Definition: Variable.cc:39
DerivativesEstimates(size_t const size=0)
Constructor.
double constexpr minusInfinity
Negative infinity: use for unbounded variables.
Definition: Var.hpp:34
data upperBound
Definition: Variable.cc:38
virtual gsl::matrix hessian(gsl::vector const &vector)
Compute or estimate a Hessian value.
Definition: Function.cc:54
void updateGradientFromVariable(std::map< Variable, size_t >::value_type &entry, gsl::vector const &vector)
Update gradient from a variable.
std::vector< std::shared_ptr< Subvector > > constraintIndices
Used internally to match the variables in each constraint to indices in a vector: (*constraintIndices...
Definition: Model.hpp:892
std::shared_ptr< Subvector > objectiveIndices
Used internally to match the variables in the objective to indices in a vector: objectiveIndices[i] i...
Definition: Model.hpp:886