LSLOpt  1.0
DebugProblem.hpp
1 #pragma once
2 
3 #include <cmath>
4 
5 #include "Implementation/ProblemTraits.hpp"
6 #include "Types.hpp"
7 
8 
9 namespace LSLOpt {
10 
22 template<typename Problem, typename Scalar, typename ErrorHandler>
23 struct DebugProblem : Problem {
24 
33  template <typename ... Args>
35  ErrorHandler& error_handler,
36  Args&&... args)
37  : Problem(std::forward<Args>(args)...)
38  , m_error_handler(error_handler)
39  {
40  this->setDerivativeEpsilon();
41  this->setCompareEpsilon();
42  }
43 
51  void setDerivativeEpsilon(const Scalar& derivative_epsilon = 1e-6)
52  {
53  m_derivative_epsilon = derivative_epsilon;
54  }
55 
63  void setCompareEpsilon(const Scalar& compare_epsilon = 1e-3)
64  {
65  m_compare_epsilon = compare_epsilon;
66  }
67 
71  const Scalar& getDerivativeEpsilon() const
72  {
73  return m_derivative_epsilon;
74  }
75 
79  const Scalar& getCompareEpsilon() const
80  {
81  return m_compare_epsilon;
82  }
83 
98  {
99  using std::abs; // we need this for accessing abs()
100 
102  = Problem::gradient(x);
103 
104  bool equal = true;
105  Vector<Scalar> numerical_gradient(x.size());
106  for (Eigen::Index i = 0; i < x.size(); ++i) {
107  Vector<Scalar> x_plus(x);
108  x_plus(i) += m_derivative_epsilon;
109 
110  Vector<Scalar> x_minus(x);
111  x_minus(i) -= m_derivative_epsilon;
112 
113  if (!x_value_is_ok<Problem>(x_minus, i) || !x_value_is_ok<Problem>(x_plus, i)) {
114  continue;
115  }
116 
117  Scalar score_plus = Problem::value(x_plus);
118 
119  Scalar score_minus = Problem::value(x_minus);
120 
121  Scalar numeric_first_derivative =
122  (score_plus - score_minus) / (Scalar{2} * m_derivative_epsilon);
123  numerical_gradient(i) = numeric_first_derivative;
124 
125  if (abs(numeric_first_derivative - g(i)) > m_compare_epsilon) {
126  equal = false;
127  // do not break, we want to calculate and see the rest for debugging
128  }
129  }
130 
131  if (!equal) {
132  m_error_handler(x, numerical_gradient, g);
133  }
134 
135 
136  return g;
137  }
138 
139  private:
140 
141  template<typename U,
142  typename std::enable_if<!Implementation::problem_traits<U, Scalar>::has_lower_bound,
143  U>::type* = nullptr>
144  bool x_value_is_ok(
145  const Vector<Scalar>& x,
146  Eigen::Index i)
147  {
148  return true;
149  }
150 
151  template<typename U,
152  typename std::enable_if<Implementation::problem_traits<U, Scalar>::has_lower_bound,
153  void>::type* = nullptr>
154  bool x_value_is_ok(
155  const Vector<Scalar>& x,
156  Eigen::Index i)
157  {
158  return x(i) >= this->lower_bounds()(i) && x(i) <= this->upper_bounds()(i);
159  }
160 
161  ErrorHandler& m_error_handler;
162 
163  Scalar m_derivative_epsilon;
164  Scalar m_compare_epsilon;
165 };
166 
167 }
Debug wrapper for any problem.
Definition: DebugProblem.hpp:23
const Scalar & getCompareEpsilon() const
Get the epsilon value for comparison of analytical and numerical derivative.
Definition: DebugProblem.hpp:79
void setDerivativeEpsilon(const Scalar &derivative_epsilon=1e-6)
Set the epsilon value for numerical derivative calculation.
Definition: DebugProblem.hpp:51
Implementation::problem_traits< Problem, Scalar >::gradient_type gradient(const Vector< Scalar > &x)
Calculate and check the gradient.
Definition: DebugProblem.hpp:97
const Scalar & getDerivativeEpsilon() const
Get the epsilon value for numerical derivative calculation.
Definition: DebugProblem.hpp:71
Eigen::Matrix< Scalar, Eigen::Dynamic, 1 > Vector
Vector type used.
Definition: Types.hpp:15
void setCompareEpsilon(const Scalar &compare_epsilon=1e-3)
Set the epsilon value for comparison of analytical and numerical derivative.
Definition: DebugProblem.hpp:63
DebugProblem(ErrorHandler &error_handler, Args &&... args)
Construct a new debug problem.
Definition: DebugProblem.hpp:34
decltype(gradient_probe(*dummy_problem)) gradient_type
return type of the gradient function; void if not provided
Definition: ProblemTraits.hpp:77
BFGS optimizations.
Definition: BFGS.hpp:24