Interior-point-optimisation  1.0-1
Interior-pointoptimisationlibrary
GSL.cc
Go to the documentation of this file.
1 /*
2  * $Id: GSL.cc 135 2013-06-29 15:09:42Z 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"GSL.hpp"
25 
26 using namespace gsl;
27 
28 std::tuple<gsl::matrix,double>
29 ipo::detail::modifiedCholeskyDecomp( gsl::matrix const& matrix, double maxoffl ){
30  // constant expressions
31  static double constexpr
32  eps4 { std::sqrt( std::sqrt( std::numeric_limits<double>::epsilon() ) ) };
33  static double constexpr eps2 { std::sqrt( std::numeric_limits<double>::epsilon() ) };
34  if( 0 == maxoffl ){
35  auto D = matrix.const_diagonal();
36  maxoffl = std::sqrt( std::accumulate( D.begin(), D.end(),
38  []( double const x, double const y ){
39  return x > y ? x : y; } ) );
40  }
41  double const minL2 { eps2 * maxoffl };
42 
43  // Keep local storage: we are likely to reuse it frequently.
44  static std::vector<double> D;
45 
46  size_t const N = matrix.size1();
47  if( matrix.size2() != N ) throw exception( "gsl::modifiedCholeskyDecomp():"
48  "matrix must be square.", __FILE__,
49  __LINE__, exception::GSL_EBADLEN );
50  // assumes maxoffl != 0
51  if( maxoffl == 0 )
52  throw exception( "gsl::modifiedCholeskyDecomp():"
53  "maxoffl must be nonzero.", __FILE__,
54  __LINE__, exception::GSL_ESANITY );
55 
56  gsl::matrix L( N, N ); // return matrix
57  D.resize( N ); // This should not usually adjust the capacity of D
58 
59  double const minL { eps4 * maxoffl };
60 
61  double maxAdd { 0 };
62  for( size_t j { 0 }; j < N; ++j ){
63 
64  double sumL2 { 0 };
65  for( size_t i { 0 }; i < j; ++i ){
66  double const entry { L.get( j, i ) };
67  sumL2 += entry * entry;
68  }
69  L.set( j, j, matrix.get( j, j ) - sumL2 ); // Only diagonal set
70 
71  double minLjj { 0 };
72  for( size_t i { j + 1 }; i < N; ++i ){
73  double sumLL { 0 };
74  for( size_t k { 0 }; k < j; ++k )
75  sumLL += L.get( i, k ) * L.get( j, k );
76  double const d { matrix.get( j, i ) - sumLL };
77  L.set( i, j, d );
78  minLjj = std::max( minLjj, d );
79  }
80  minLjj = std::max( minLjj / maxoffl, minL );
81 
82  if( L.get( j, j ) > minLjj * minLjj ){
83  // Normal Cholesky iteration
84  L.set( j, j, std::sqrt( L.get( j, j ) ) );
85  } else {
86  // Augment matrix
87  minLjj = std::max( minLjj, minL2 );
88  maxAdd = std::max( maxAdd, minLjj * minLjj - L.get( j, j ) );
89  L.set( j, j, minLjj );
90  }
91 
92  // complete decomposition
93  for( size_t i { j + 1 }; i < N; ++i )
94  L.set( i, j, L.get( i, j ) / L.get( j, j ) );
95  }
96 
97  // return matrix and maxAdd
98  return std::make_tuple( L, maxAdd );
99 }
100 
101 gsl::matrix
102 ipo::detail::modelHessian( gsl::matrix& matrix ){
103  // constant expressions
104  static double constexpr eps2 { std::sqrt( std::numeric_limits<double>::epsilon() )};
105  static double constexpr INF { std::numeric_limits<double>::infinity() };
106 
107  size_t const N { matrix.size1() };
108  if( matrix.size2() != N ) throw exception( "gsl::modelHessian():"
109  "matrix must be square.", __FILE__,
110  __LINE__, exception::GSL_EBADLEN );
111 
112  double maxDiag { -INF };
113  double minDiag { INF };
114  for( double const& d : matrix.const_diagonal() ){
115  maxDiag = std::max( maxDiag, d );
116  minDiag = std::min( minDiag, d );
117  }
118  double const maxPosDiag { std::max( 0.0, maxDiag ) };
119 
120  double mu { 0 };
121  if( minDiag <= eps2 * maxPosDiag ){
122  mu = 2 * (maxPosDiag - minDiag) * eps2 - minDiag;
123  maxDiag = mu;
124  }
125 
126  double maxoff { 0 };
127  for( size_t i { 0 }; i < N; ++i )
128  for( size_t j { i + 1 }; j < N; ++j )
129  maxoff = std::max( maxoff, matrix.get( i, j ) );
130  if( maxoff * (1 + 2 * eps2) > maxDiag ){
131  mu += (maxoff - maxDiag) + 2 * eps2 * maxoff;
132  maxDiag = maxoff * (1 + 2 * eps2);
133  }
134 
135  if( maxDiag == 0 ){ /* H == 0 */
136  mu = 1;
137  maxDiag = 1;
138  }
139 
140  if( mu > 0 ) /* Add mu * I to H */ matrix.diagonal().add_constant( mu );
141 
142  double const maxoffl { std::sqrt( std::max( maxDiag, maxoff / N ) ) };
143 
144  auto cholDecomp = modifiedCholeskyDecomp( matrix, maxoffl );
145  gsl::matrix L { std::get<0>( cholDecomp ) };
146  double const maxAdd { std::get<1>( cholDecomp ) };
147 
148  if( maxAdd > 0 ){ /* H not positive definite */
149  double maxev { matrix.get( 0, 0 ) };
150  double minev { maxev };
151  for( size_t i { 0 }; i < N; ++i ){
152  double offrow { 0 };
153  for( size_t j { 0 }; j + 1 < i; ++j )
154  offrow += std::fabs( matrix.get( j, i ) );
155  for( size_t j { i + 1 }; j < N; ++j )
156  offrow += std::fabs( matrix.get( i, j ) );
157  double const hii { matrix.get( i, i ) };
158  maxev = std::max( maxev, hii + offrow );
159  minev = std::min( minev, hii - offrow );
160  }
161  double const sdd { std::max( 0.0, (maxev - minev) *eps2 - minev ) };
162  mu = std::min( maxAdd, sdd );
163  matrix.diagonal().add_constant( mu ); /* H = H + mu * I */
164  }
165  cholDecomp = modifiedCholeskyDecomp( matrix, 0 );
166  L = std::get<0>( cholDecomp );
167  /* Fill upper triangle */
168  for( size_t j { 0 }; j < N; ++j )
169  for( size_t i { 0 }; i < j; ++i )
170  L.set( i, j, L.get( j, i ) );
171 
172  return L;
173 }
gsl::matrix modelHessian(gsl::matrix &matrix)
Find a Cholesky decomposition (both upper and lower triangles returned in matrix) of a matrix + mu * ...
Definition: GSL.cc:102
std::tuple< gsl::matrix, double > modifiedCholeskyDecomp(gsl::matrix const &matrix, double maxoffl)
Modified in-place Cholesky decomposition using the method of Gill, Murray and Wright (1981) to deal w...
Definition: GSL.cc:29
std::string const infinity
Infinity sign, ∞.
Definition: Format.hpp:54