Molassembler  3.0.0
Molecule graph and conformer library
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Common.h
Go to the documentation of this file.
1 
8 #ifndef INCLUDE_TEMPLE_OPTIMIZATION_COMMON_H
9 #define INCLUDE_TEMPLE_OPTIMIZATION_COMMON_H
10 
11 #include <Eigen/Core>
12 
13 namespace Scine {
14 namespace Molassembler {
15 namespace Temple {
16 
18 namespace Optimization {
19 
20 template<typename FloatType>
22  static_assert(
23  std::is_floating_point<FloatType>::value,
24  "This struct is not intended for anything else but floats"
25  );
26 
27  FloatType current;
28  FloatType proposed;
29 
31  FloatType absDelta() const {
32  return std::fabs(proposed - current);
33  }
34 
35  void propagate() { current = proposed; }
36 };
37 
38 template<typename EigenType>
40  EigenType current;
41  EigenType proposed;
42 
43  typename EigenType::Scalar deltaNorm() const {
44  return (proposed - current).norm();
45  }
46 
47  void propagate() {
48  /* Swapping instead of moving proposed into current is three moves instead
49  * of one, but avoids allocation of new memory (after moving from proposed,
50  * we need to resize proposed to have the same size). Assuming moves are
51  * cheap (trade ownership of allocated memory) and allocation could be
52  * costly, this might be cheaper.
53  */
54  std::swap(current, proposed);
55  }
56 };
57 
58 template<typename FloatType, typename VectorType, typename UpdateFunction>
60  UpdateFunction function;
61 
62  NegateFunction(UpdateFunction&& fn) : function(fn) {}
63 
64  void operator() (
65  const VectorType& parameters,
66  FloatType& value,
67  Eigen::Ref<VectorType> gradient
68  ) {
69  function(parameters, value, gradient);
70  value *= -1;
71  gradient *= -1;
72  }
73 };
74 
75 template<typename VectorType, typename UpdateFunction>
76 auto negateFunction(UpdateFunction&& fn) {
77  using FloatType = typename VectorType::Scalar;
78  return NegateFunction<FloatType, VectorType, UpdateFunction>(std::forward<UpdateFunction>(fn));
79 }
80 
81 template<typename Function, typename FloatType>
82 auto numericalGradient(
83  Function&& function,
84  const Eigen::Matrix<FloatType, Eigen::Dynamic, 1>& parameters
85 ) {
86  using VectorType = Eigen::Matrix<FloatType, Eigen::Dynamic, 1>;
87  const unsigned P = parameters.size();
88  VectorType numericalGradient(P);
89  VectorType diffParameters = parameters;
90 
91  // Central differences for all individual parameters
92  constexpr FloatType h = 1e-4;
93  FloatType a;
94  FloatType b;
95  for(unsigned i = 0; i < P; ++i) {
96  diffParameters(i) += h;
97  b = function(diffParameters);
98  diffParameters(i) -= 2 * h;
99  a = function(diffParameters);
100  diffParameters(i) = parameters(i);
101  numericalGradient(i) = (b - a) / (2 * h);
102  }
103 
104  return numericalGradient;
105 }
106 
107 template<typename Function, typename FloatType>
108 auto numericalHessian(
109  Function&& function,
110  const Eigen::Matrix<FloatType, Eigen::Dynamic, 1>& parameters
111 ) {
112  using VectorType = Eigen::Matrix<FloatType, Eigen::Dynamic, 1>;
113  using MatrixType = Eigen::Matrix<FloatType, Eigen::Dynamic, Eigen::Dynamic>;
114  const unsigned P = parameters.size();
115  MatrixType numericalHessian(P, P);
116  VectorType diffParameters = parameters;
117 
118  // Form the hessian using finite differences
119  constexpr FloatType h = 1e-4;
120  FloatType a;
121  FloatType b;
122  FloatType c;
123  FloatType d;
124  for(unsigned i = 0; i < P; ++i) {
125  // Diagonal second derivative from forward and backward derivative
126  b = function(diffParameters);
127  diffParameters(i) += h;
128  c = function(diffParameters);
129  diffParameters(i) -= 2 * h;
130  a = function(diffParameters);
131  diffParameters(i) = parameters(i);
132  numericalHessian(i, i) = (a - 2 * b + c) / (h * h);
133 
134  // Cross terms from two central derivatives
135  for(unsigned j = i + 1; j < P; ++j) {
136  // (i) + h, (j) + h -> a
137  diffParameters(i) += h;
138  diffParameters(j) += h;
139  a = function(diffParameters);
140  // (i) + h, (j) - h - > b
141  diffParameters(j) -= 2 * h;
142  b = function(diffParameters);
143  // (i) - h, (j) - h -> d
144  diffParameters(i) -= 2 * h;
145  d = function(diffParameters);
146  // (i) - h, (j) + h -> c
147  diffParameters(j) += 2 * h;
148  c = function(diffParameters);
149 
150  numericalHessian(i, j) = (a - b - c + d) / (4 * h * h);
151  numericalHessian(j, i) = numericalHessian(i, j);
152  }
153  }
154 
155  return numericalHessian;
156 }
157 
158 } // namespace Optimization
159 } // namespace Temple
160 } // namespace Molassembler
161 } // namespace Scine
162 
163 #endif
FloatType absDelta() const
Returns signed difference: proposed - current.
Definition: Common.h:31