diff --git a/src/stan/optimization/lbfgs_update.hpp b/src/stan/optimization/lbfgs_update.hpp index ba9d7afcb62..1f8719d4b12 100644 --- a/src/stan/optimization/lbfgs_update.hpp +++ b/src/stan/optimization/lbfgs_update.hpp @@ -2,7 +2,7 @@ #define STAN_OPTIMIZATION_LBFGS_UPDATE_HPP #include -#include +#include #include #include @@ -72,8 +72,8 @@ class LBFGSUpdate { **/ inline void search_direction(VectorT &pk, const VectorT &gk) const { std::vector alphas(_buf.size()); - typename boost::circular_buffer::const_reverse_iterator buf_rit; - typename boost::circular_buffer::const_iterator buf_it; + typename stan::util::ring_buffer::const_reverse_iterator buf_rit; + typename stan::util::ring_buffer::const_iterator buf_it; typename std::vector::const_iterator alpha_it; typename std::vector::reverse_iterator alpha_rit; @@ -103,7 +103,7 @@ class LBFGSUpdate { } protected: - boost::circular_buffer _buf; + stan::util::ring_buffer _buf; Scalar _gammak; }; } // namespace optimization diff --git a/src/stan/services/pathfinder/single.hpp b/src/stan/services/pathfinder/single.hpp index 7202fa6dcf2..a0df4efd0f0 100644 --- a/src/stan/services/pathfinder/single.hpp +++ b/src/stan/services/pathfinder/single.hpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include @@ -659,8 +659,8 @@ inline auto pathfinder_lbfgs_single( + std::to_string(lbfgs.logp())); } int ret = 0; - boost::circular_buffer param_buff(max_history_size); - boost::circular_buffer grad_buff(max_history_size); + stan::util::ring_buffer param_buff(max_history_size); + stan::util::ring_buffer grad_buff(max_history_size); Eigen::VectorXd prev_params = Eigen::Map(cont_vector.data(), cont_vector.size()); std::size_t history_size = 0; diff --git a/src/stan/util/ring_buffer.hpp b/src/stan/util/ring_buffer.hpp new file mode 100644 index 00000000000..caf65a85830 --- /dev/null +++ b/src/stan/util/ring_buffer.hpp @@ -0,0 +1,130 @@ +#ifndef STAN_UTIL_RING_BUFFER_HPP +#define STAN_UTIL_RING_BUFFER_HPP + +#include +#include +#include +#include +#include +#include + +namespace stan { +namespace util { + +/** Fixed-capacity buffer that overwrites its oldest element when full. */ +template +class ring_buffer { + public: + explicit ring_buffer(size_t capacity) : buf_(capacity) { + if (capacity == 0) { + throw std::domain_error("ring_buffer capacity must be > 0"); + } + } + + size_t size() const { return size_; } + size_t capacity() const { return buf_.size(); } + + void clear() { + start_ = 0; + size_ = 0; + } + + void push_back() { + if (size_ < capacity()) { + ++size_; + } else { + start_ = (start_ + 1) % capacity(); + } + } + + template + void push_back(U&& value) { + push_back(); + back() = std::forward(value); + } + + T& back() { return (*this)[size_ - 1]; } + + T& operator[](size_t i) { return buf_[(start_ + i) % capacity()]; } + const T& operator[](size_t i) const { + return buf_[(start_ + i) % capacity()]; + } + + void rset_capacity(size_t new_capacity) { + if (new_capacity == 0) { + throw std::domain_error("ring_buffer capacity must be > 0"); + } + if (new_capacity == capacity()) { + return; + } + + std::vector new_buf(new_capacity); + size_t keep = std::min(size_, new_capacity); + for (size_t i = 0; i < keep; ++i) { + new_buf[i] = std::move((*this)[size_ - keep + i]); + } + buf_ = std::move(new_buf); + start_ = 0; + size_ = keep; + } + + class const_iterator { + public: + using iterator_category = std::bidirectional_iterator_tag; + using value_type = T; + using difference_type = std::ptrdiff_t; + using pointer = const T*; + using reference = const T&; + + const_iterator() = default; + const_iterator(const ring_buffer* buffer, size_t pos) + : buffer_(buffer), pos_(pos) {} + + reference operator*() const { return (*buffer_)[pos_]; } + + const_iterator& operator++() { + ++pos_; + return *this; + } + const_iterator operator++(int) { + const_iterator result = *this; + ++*this; + return result; + } + const_iterator& operator--() { + --pos_; + return *this; + } + + bool operator==(const const_iterator& other) const { + return buffer_ == other.buffer_ && pos_ == other.pos_; + } + bool operator!=(const const_iterator& other) const { + return !(*this == other); + } + + private: + const ring_buffer* buffer_ = nullptr; + size_t pos_ = 0; + }; + + const_iterator begin() const { return const_iterator(this, 0); } + const_iterator end() const { return const_iterator(this, size_); } + + using const_reverse_iterator = std::reverse_iterator; + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } + + private: + std::vector buf_; + size_t start_ = 0; + size_t size_ = 0; +}; + +} // namespace util +} // namespace stan +#endif diff --git a/src/stan/variational/advi.hpp b/src/stan/variational/advi.hpp index 681ce65e82c..579e222b41d 100644 --- a/src/stan/variational/advi.hpp +++ b/src/stan/variational/advi.hpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include @@ -335,7 +335,7 @@ class advi { // Heuristic to estimate how far to look back in rolling window int cb_size = static_cast(std::max(0.1 * max_iterations / eval_elbo_, 2.0)); - boost::circular_buffer elbo_diff(cb_size); + stan::util::ring_buffer elbo_diff(cb_size); logger.info("Begin stochastic gradient ascent."); logger.info( @@ -528,10 +528,10 @@ class advi { * @param[in] cb circular buffer with some number of values in it. * @return median of values in circular buffer. */ - double circ_buff_median(const boost::circular_buffer& cb) const { + double circ_buff_median(const stan::util::ring_buffer& cb) const { // FIXME: naive implementation; creates a copy as a vector std::vector v; - for (boost::circular_buffer::const_iterator i = cb.begin(); + for (stan::util::ring_buffer::const_iterator i = cb.begin(); i != cb.end(); ++i) { v.push_back(*i); }