Virtual Testbed
Ship dynamics simulator for extreme conditions
lipo_solver.hh
1 #ifndef VTESTBED_CORE_LIPO_SOLVER_HH
2 #define VTESTBED_CORE_LIPO_SOLVER_HH
3 
4 #include <limits>
5 #include <random>
6 #include <vector>
7 
8 #include <vtestbed/base/blitz.hh>
9 #include <vtestbed/core/types.hh>
10 
11 namespace vtb {
12 
13  namespace core {
14 
21  template <class T, int N>
22  class LIPO_solver {
23 
24  public:
25  using scalar_type = T;
26  using argument_type = Vector<T,N>;
27  using value_type = T;
28 
29  private:
30  value_type _constant{T{}};
31  value_type _funceps = 0;
32  argument_type _argeps{T{}};
33  int _max_evaluations = 1000;
34  int _max_iterations = 1000;
35  scalar_type _sample_probability{T{}};
36  bool _estimate_constant = true;
37 
38  public:
39 
41  inline value_type constant() const { return this->_constant; }
43  inline argument_type argument_precision() const { return this->_argeps; }
45  inline value_type function_precision() const { return this->_funceps; }
47  inline int max_evaluations() const { return this->_max_evaluations; }
49  inline int max_iterations() const { return this->_max_iterations; }
51  inline scalar_type sample_probability() const { return this->_sample_probability; }
53  inline bool estimate_constant() const { return this->_estimate_constant; }
54  inline void constant(value_type rhs) { this->_constant = rhs; }
55  inline void argument_precision(argument_type rhs) { this->_argeps = rhs; }
56  inline void function_precision(value_type rhs) { this->_funceps = rhs; }
57  inline void max_evaluations(int rhs) { this->_max_evaluations = rhs; }
58  inline void max_iterations(int rhs) { this->_max_iterations = rhs; }
59  inline void sample_probability(scalar_type rhs) { this->_sample_probability = rhs; }
60  inline void estimate_constant(bool rhs) { this->_estimate_constant = rhs; }
61 
62  template <class Func> inline argument_type
63  solve(argument_type lbound, argument_type ubound, Func func) const {
64  using distribution_type = std::uniform_real_distribution<scalar_type>;
65  using std::min;
66  using std::max;
67  if (max_evaluations() <= 0) { return argument_type{T{}}; }
68  // Choose random point.
70  std::default_random_engine prng(dev());
71  argument_type x;
72  for (int i=0; i<N; ++i) {
73  distribution_type dist(lbound(i), ubound(i));
74  x(i) = dist(prng);
75  }
76  if (max_evaluations() <= 1) { return x; }
79  points.reserve(max_evaluations());
80  points.emplace_back(x);
81  values.reserve(max_evaluations());
82  values.emplace_back(func(x));
83  value_type max_value = values.front();
84  int nevaluations = 1;
86  value_type k = estimate_constant() ? value_type{scalar_type{}} : constant();
87  for (int i=0; i<max_iterations(); ++i) {
88  // Choose new random point.
89  for (int j=0; j<N; ++j) {
90  distribution_type dist(lbound(j), ubound(j));
91  x(j) = dist(prng);
92  }
93  auto old_nevaluations = nevaluations;
94  if (sample(prng)) {
95  points.emplace_back(x);
96  values.emplace_back(func(x));
97  ++nevaluations;
98  } else {
99  // Find new upper bound.
100  value_type min_ubound{std::numeric_limits<scalar_type>::max()};
101  for (int j=0; j<nevaluations; ++j) {
102  value_type new_ubound = values[j] + k*distance(x,points[j]);
103  if (new_ubound < min_ubound) { min_ubound = new_ubound; }
104  }
105  // Store new point.
106  if (min_ubound >= max_value) {
107  value_type func_x = func(x);
108  if (func_x > max_value) { max_value = func_x; }
109  points.emplace_back(x);
110  values.emplace_back(func_x);
111  ++nevaluations;
112  }
113  }
114  if (old_nevaluations != nevaluations) {
115  if (nevaluations >= max_evaluations()) { break; }
116  // Update the constant.
117  if (estimate_constant()) {
118  argument_type points_n = points[nevaluations-1];
119  value_type values_n = values[nevaluations-1];
120  for (int j=0; j<nevaluations-1; ++j) {
121  scalar_type length = distance(points[j],points_n);
122  value_type new_k = values[j]-values_n;
123  if (length != 0) { new_k /= length; }
124  k = max(k, new_k);
125  }
126  }
127  }
128  }
129  int max_index = 0;
130  for (int i=1; i<nevaluations; ++i) {
131  if (values[i] > values[max_index]) {
132  max_index = i;
133  }
134  }
135  return points[max_index];
136  }
137 
138  };
139 
140  }
141 
142 }
143 
144 #endif // vim:filetype=cpp
T distance(T... args)
argument_type argument_precision() const
Argument precision.
Definition: lipo_solver.hh:43
bool estimate_constant() const
Estimate Lipschitz constant or not.
Definition: lipo_solver.hh:53
int max_evaluations() const
Maximum number of function evaluations.
Definition: lipo_solver.hh:47
T max(T... args)
T length(const blitz::TinyVector< T, N > &x)
Computes vector length without overflow.
Definition: blitz.hh:471
value_type function_precision() const
Function precision.
Definition: lipo_solver.hh:45
Main namespace.
Definition: convert.hh:9
scalar_type sample_probability() const
Probability of choosing exploration step over exploitation step.
Definition: lipo_solver.hh:51
value_type constant() const
Lipschitz constant (one for each dimension).
Definition: lipo_solver.hh:41
int max_iterations() const
Maximum number of iterations of the main loop.
Definition: lipo_solver.hh:49
Multi-dimensional optimisation of non-convex functions.
Definition: lipo_solver.hh:22