// Copyright Maksym Zhelyenzyakov 2025-2026. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // https://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_MATH_OPTIMIZATION_NESTEROV_HPP #define BOOST_MATH_OPTIMIZATION_NESTEROV_HPP #include #include #include #include namespace boost { namespace math { namespace optimization { namespace rdiff = boost::math::differentiation::reverse_mode; /** * @brief The nesterov_update_policy class */ template struct nesterov_update_policy { RealType lr_, mu_; nesterov_update_policy(RealType lr, RealType mu) : lr_(lr) , mu_(mu) {}; template::value>::type> void operator()(ArgumentType& x, RealType& g, RealType& v) { RealType v_prev = v; v = mu_ * v - lr_ * g; x.get_value() += -mu_ * v_prev + (static_cast(1) + mu_) * v; } template::value, int>::type = 0> void operator()(ArgumentType& x, RealType& g, RealType& v) const { const RealType v_prev = v; v = mu_ * v - lr_ * g; x += -mu_ * v_prev + (static_cast(1) + mu_) * v; } RealType lr() const noexcept { return lr_; } RealType mu() const noexcept { return mu_; } }; /** * @brief The nesterov_accelerated_gradient class * * https://jlmelville.github.io/mize/nesterov.html */ template class nesterov_accelerated_gradient : public abstract_optimizer< ArgumentContainer, RealType, Objective, InitializationPolicy, ObjectiveEvalPolicy, GradEvalPolicy, nesterov_update_policy, nesterov_accelerated_gradient> { using base_opt = abstract_optimizer, nesterov_accelerated_gradient>; std::vector v_; public: using base_opt::base_opt; nesterov_accelerated_gradient(Objective&& objective, ArgumentContainer& x, InitializationPolicy&& ip, ObjectiveEvalPolicy&& oep, GradEvalPolicy&& gep, nesterov_update_policy&& up) : base_opt(std::forward(objective), x, std::forward(ip), std::forward(oep), std::forward(gep), std::forward>(up)) , v_(x.size(), RealType(0)) { } void step() { auto& x = this->arguments(); auto& g = this->gradients(); auto& obj = this->objective_value(); auto& obj_eval = this->obj_eval_; auto& grad_eval = this->grad_eval_; auto& objective = this->objective_; auto& update = this->update_; grad_eval(objective, x, obj_eval, obj, g); for (size_t i = 0; i < x.size(); ++i) { update(x[i], g[i], v_[i]); } } }; template auto make_nag(Objective&& obj, ArgumentContainer& x, RealType lr = RealType{ 0.01 }, RealType mu = RealType{ 0.95 }) { return nesterov_accelerated_gradient< ArgumentContainer, RealType, std::decay_t, tape_initializer_rvar, reverse_mode_function_eval_policy, reverse_mode_gradient_evaluation_policy>( std::forward(obj), x, tape_initializer_rvar{}, reverse_mode_function_eval_policy{}, reverse_mode_gradient_evaluation_policy{}, nesterov_update_policy(lr, mu)); } template auto make_nag(Objective&& obj, ArgumentContainer& x, RealType lr, RealType mu, InitializationPolicy&& ip) { return nesterov_accelerated_gradient< ArgumentContainer, RealType, std::decay_t, InitializationPolicy, reverse_mode_function_eval_policy, reverse_mode_gradient_evaluation_policy>( std::forward(obj), x, std::forward(ip), reverse_mode_function_eval_policy{}, reverse_mode_gradient_evaluation_policy{}, nesterov_update_policy(lr, mu)); } template auto make_nag(Objective&& obj, ArgumentContainer& x, RealType lr, RealType mu, InitializationPolicy&& ip, ObjectiveEvalPolicy&& oep, GradEvalPolicy&& gep) { return nesterov_accelerated_gradient, InitializationPolicy, ObjectiveEvalPolicy, GradEvalPolicy>( std::forward(obj), x, std::forward(ip), std::forward(oep), std::forward(gep), nesterov_update_policy{ lr, mu }); } } // namespace optimization } // namespace math } // namespace boost #endif