00001 #ifndef SCITBX_LBFGS_DROP_CONVERGENCE_TEST_H
00002 #define SCITBX_LBFGS_DROP_CONVERGENCE_TEST_H
00003
00004 #include <scitbx/array_family/shared.h>
00005 #include <scitbx/array_family/misc_functions.h>
00006 #include <scitbx/math/linear_regression.h>
00007
00008 namespace scitbx { namespace lbfgs {
00009
00011
00035 template <typename FloatType, typename SizeType = std::size_t>
00036 class drop_convergence_test
00037 {
00038 public:
00040
00043 explicit
00044 drop_convergence_test(
00045 SizeType n_test_points=5,
00046 FloatType max_drop_eps=FloatType(1.e-5),
00047 FloatType iteration_coefficient=FloatType(2))
00048 : n_test_points_(n_test_points),
00049 max_drop_eps_(max_drop_eps),
00050 iteration_coefficient_(iteration_coefficient),
00051 max_drop_(0),
00052 max_f_(0)
00053 {
00054 SCITBX_ASSERT(n_test_points >= 2);
00055 SCITBX_ASSERT(max_drop_eps_ >= FloatType(0));
00056 SCITBX_ASSERT(iteration_coefficient_ >= FloatType(1));
00057 }
00058
00062 SizeType n_test_points() const { return n_test_points_; }
00063
00067 FloatType max_drop_eps() const { return max_drop_eps_; }
00068
00072 FloatType iteration_coefficient() const {
00073 return iteration_coefficient_;
00074 }
00075
00077
00080 bool
00081 operator()(FloatType f);
00082
00084 af::shared<FloatType> objective_function_values() const {
00085 return y_;
00086 }
00087
00089 FloatType max_drop() const { return max_drop_; }
00090
00091 protected:
00092 const SizeType n_test_points_;
00093 const FloatType max_drop_eps_;
00094 const FloatType iteration_coefficient_;
00095 af::shared<FloatType> x_;
00096 af::shared<FloatType> y_;
00097 FloatType max_drop_;
00098 FloatType max_f_;
00099 };
00100
00101 template <typename FloatType, typename SizeType>
00102 bool
00103 drop_convergence_test<FloatType, SizeType>::operator()(FloatType f)
00104 {
00105 if (x_.size()) {
00106 max_drop_ = std::max(max_drop_, y_.back() - f);
00107 }
00108 max_f_ = std::max(max_f_, fn::absolute(f));
00109 x_.push_back(x_.size() + 1);
00110 y_.push_back(f);
00111 if (x_.size() < n_test_points_) return false;
00112 if (!max_f_) return true;
00113 af::shared<FloatType> y_scaled;
00114 y_scaled.reserve(n_test_points_);
00115 for(std::size_t i=y_.size()-n_test_points_;i<y_.size();i++) {
00116 y_scaled.push_back(y_[i] / max_f_);
00117 }
00118
00119 math::linear_regression<FloatType> linreg_y(
00120 af::const_ref<FloatType>(x_.end() - n_test_points_, n_test_points_),
00121 af::const_ref<FloatType>(y_scaled.begin(), n_test_points_));
00122 SCITBX_ASSERT(linreg_y.is_well_defined());
00123
00124 FloatType sliding_tolerance =
00125 max_drop_ * max_drop_eps_ * std::pow(
00126 FloatType(x_.size()), iteration_coefficient_);
00127 if (-linreg_y.slope() * max_f_ <= sliding_tolerance) {
00128 return true;
00129 }
00130 return false;
00131 }
00132
00133 }}
00134
00135 #endif // SCITBX_LBFGS_DROP_CONVERGENCE_TEST_H