Interior-point-optimisation  1.0-1
Interior-pointoptimisationlibrary
PhaseIFunctionAndDerivatives.cc
Go to the documentation of this file.
1 /*
2  * $Id: PhaseIFunctionAndDerivatives.cc 236 2014-11-30 14:09:06Z jdl3 $
3  * Copyright (C) 2013–2014 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 
25 
26 using namespace ipo_function::detail;
27 
29  bool const upperBound )
30  : FunctionBase { 0 == function.getSize() ? 0 : function.getSize() + 1 },
31  function( function ), b { b }, upperBound { upperBound }{
32  if( size != 0 ){
33  functionGradient = gsl::vector( size );
34  functionHessian = gsl::matrix { size, size };
35  }
36 }
37 
38 double
39 PhaseIFunctionAndDerivatives::operator()( gsl::vector const& vector ){
40  size_t const SIZE { getSize() };
41  size_t const VSIZE { vector.size() };
42 
43  if( 0 == VSIZE ) return 0; // do something sane
44  if( 0 != SIZE and SIZE != VSIZE ) return 0; // do something sane.
45 
46  // We can now assume the first VSIZE elements of vector should
47  // be passed to function
48  auto subvector = vector.subvector( 0, VSIZE - 1 );
49  double const& s { vector[VSIZE - 1] };
50  double const f { function( subvector ) };
51  if( upperBound )
52  return f - b - s;
53  else
54  return b - f - s;
55 }
56 
57 gsl::vector
58 PhaseIFunctionAndDerivatives::gradient( gsl::vector const& vector ){
59  size_t const SIZE { getSize() };
60  size_t const VSIZE { vector.size() };
61 
62  if( not functionGradient )
63  functionGradient = gsl::vector( VSIZE ); // Should happen rarely
64 
65  if( 0 == VSIZE ){
66  functionGradient.set_all( 0 );
67  return functionGradient; // do something sane.
68  }
69  if( 0 != SIZE and SIZE != VSIZE ){
70  functionGradient.set_all( 0 );
71  return functionGradient; // do something sane.
72  }
73  if( 0 == SIZE and functionGradient.size() != VSIZE )
74  functionGradient = gsl::vector( VSIZE ); // Should happen rarely
75 
76  // We can now assume the first VSIZE - 1 elements of vector should
77  // be passed to gradient
78  auto subvector = vector.subvector( 0, VSIZE - 1 );
79  auto f = function.gradient( subvector );
80  for( size_t i { 0 }; i + 1 < VSIZE; ++i )
81  functionGradient[i] = upperBound ? f[i] : -f[i];
82  functionGradient[VSIZE - 1] = -1;
83  return functionGradient;
84 }
85 
86 gsl::matrix
87 PhaseIFunctionAndDerivatives::hessian( gsl::vector const& vector ){
88  size_t const SIZE { getSize() };
89  size_t const VSIZE { vector.size() };
90 
91  if( not functionHessian )
92  functionHessian = gsl::matrix { VSIZE, VSIZE }; // Should happen rarely
93 
94  if( 0 == VSIZE ){
95  functionHessian.set_all( 0 );
96  return functionHessian; // do something sane
97  }
98  if( 0 != SIZE and SIZE != VSIZE ){
99  functionHessian.set_all( 0 );
100  return functionHessian; // do something sane.
101  }
102  if( 0 == SIZE and (functionHessian.size1() != VSIZE
103  or functionHessian.size2() != VSIZE) )
104  functionHessian = gsl::matrix { VSIZE, VSIZE }; // Should happen rarely
105 
106  // We can now assume the first VSIZE - 1 elements of vector should
107  // be passed to hessian
108  auto subvector = vector.subvector( 0, VSIZE - 1 );
109  auto h = function.hessian( subvector );
110  if( upperBound ){
111  for( size_t i { 0 }; i < VSIZE; ++i )
112  for( size_t j { i }; j < VSIZE; ++j ){
113  double const value { (i + 1 == VSIZE or j + 1 == VSIZE) ? 0 : h.get( i, j ) };
114  functionHessian.set( i, j, value );
115  if( j > i ) functionHessian.set( j, i, value );
116  }
117  } else {
118  for( size_t i { 0 }; i < VSIZE; ++i )
119  for( size_t j { i }; j < VSIZE; ++j ){
120  double const value { (i + 1 == VSIZE or j + 1 == VSIZE) ? 0 : -h.get( i, j ) };
121  functionHessian.set( i, j, value );
122  if( j > i ) functionHessian.set( j, i, value );
123  }
124  }
125  return functionHessian;
126 }
127 
128 void
129 PhaseIFunctionAndDerivatives::setVector( gsl::vector const& vector ){
130  size_t const SIZE { getSize() };
131  size_t const VSIZE { vector.size() };
132 
133  if( not functionGradient )
134  functionGradient = gsl::vector( VSIZE ); // Should happen rarely
135  if( not functionHessian )
136  functionHessian = gsl::matrix( VSIZE, VSIZE ); // Should happen rarely
137 
138  if( 0 == VSIZE ){
139  functionGradient.set_all( 0 );
140  functionHessian.set_all( 0 );
141  return; // do something sane
142  }
143  if( 0 != SIZE and SIZE != VSIZE ){
144  functionGradient.set_all( 0 );
145  functionHessian.set_all( 0 );
146  return; // do something sane
147  }
148  if( 0 == SIZE and functionGradient.size() != VSIZE )
149  functionGradient = gsl::vector( VSIZE ); // Should happen rarely
150  if( 0 == SIZE and (functionHessian.size1() != VSIZE
151  or functionHessian.size2() != VSIZE) )
152  functionHessian = gsl::matrix { VSIZE, VSIZE }; // Should happen rarely
153 
154  // Deal separately with cases where function is or is not a DerivativesEstimates object
155  auto de = dynamic_cast<ipo_function::DerivativesEstimates*>( &function );
156  if( nullptr == de ){ // We need to estimate gradient and hessian as best we can
157  functionValue = (*this)( vector );
158  gradient( vector );
159  hessian( vector );
160  } else { // We are dealing with a DerivativesEstimates object
161  auto subvector = vector.subvector( 0, VSIZE - 1 );
162  de->setVector( subvector );
163  double const& s { vector[VSIZE - 1] };
164  if( upperBound )
165  functionValue = de->value() - b - s;
166  else
167  functionValue = b - de->value() - s;
168  for( size_t i { 0 }; i < VSIZE; ++i ){
169  auto fG = de->gradient();
170  auto fH = de->hessian();
171  if( i + 1 < VSIZE ) functionGradient[i] = upperBound ? fG[i] : -fG[i];
172  else functionGradient[i] = -1;
173  if( upperBound ){
174  for( size_t j { i }; j < VSIZE; ++j ){
175  double const h { (i + 1 == VSIZE or j + 1 == VSIZE) ? 0 : fH.get( i, j ) };
176  functionHessian.set( i, j, h );
177  if( j > i ) functionHessian.set( j, i, h );
178  }
179  } else {
180  for( size_t j { i }; j < VSIZE; ++j ){
181  double const h { (i + 1 == VSIZE or j + 1 == VSIZE) ? 0 : -fH.get( i, j ) };
182  functionHessian.set( i, j, h );
183  if( j > i ) functionHessian.set( j, i, h );
184  }
185  }
186  }
187  }
188 
189 }
double functionValue
The function value.
double h
Value used for default gradient estimates.
Definition: Function.hpp:82
double operator()(gsl::vector const &vector)
The function operator: computes or according as is an upper or lower bound.
gsl::vector functionGradient
The gradient value.
Namespace for details of ipo_function that are not normally needed to construct and solve a convex op...
virtual gsl::matrix hessian() const
virtual gsl::vector gradient() const
virtual double value() const
Base class for derivative estimates with Hessian.
gsl::matrix functionHessian
The Hessian value.
size_t getSize() const
Get size of vector for function arguments or zero for arbitrary size.
PhaseIFunctionAndDerivatives(Function &function, double const b, bool const upperBound)
Construct from a function and bound.
This class computes a function at a vector.
Definition: Function.hpp:38
bool const upperBound
A boolean value: true or false according as b is an upper bound or lower.
Base class for Function and DerivativesEstimates.
void setVector(gsl::vector const &vector)
Set a vector and compute function value, gradient and Hessian efficiently.
data upperBound
Definition: Variable.cc:38