diff --git a/include/boost/math/differentiation/detail/reverse_mode_autodiff_memory_management.hpp b/include/boost/math/differentiation/detail/reverse_mode_autodiff_memory_management.hpp index 843e3f969..a626ce5d6 100644 --- a/include/boost/math/differentiation/detail/reverse_mode_autodiff_memory_management.hpp +++ b/include/boost/math/differentiation/detail/reverse_mode_autodiff_memory_management.hpp @@ -23,407 +23,433 @@ namespace detail { template class flat_linear_allocator_iterator { - /** + /** * @brief enables iterating over linear allocator with * c++ iterators */ public: - using raw_allocator_type = std::remove_const_t; - using value_type = typename allocator_type::value_type; - using pointer = typename allocator_type::value_type *; - using const_ptr_type = const value_type *; - using reference = typename allocator_type::value_type &; - using const_reference_type = const value_type &; - using iterator_category = std::random_access_iterator_tag; - using difference_type = ptrdiff_t; + using raw_allocator_type = std::remove_const_t; + using value_type = typename allocator_type::value_type; + using pointer = typename allocator_type::value_type*; + using const_ptr_type = const value_type*; + using reference = typename allocator_type::value_type&; + using const_reference_type = const value_type&; + using iterator_category = std::random_access_iterator_tag; + using difference_type = ptrdiff_t; private: - const allocator_type *storage_ = nullptr; - size_t index_ = 0; - size_t begin_ = 0; - size_t end_ = 0; + const allocator_type* storage_ = nullptr; + size_t index_ = 0; + size_t begin_ = 0; + size_t end_ = 0; public: - flat_linear_allocator_iterator() = default; + flat_linear_allocator_iterator() = default; - explicit flat_linear_allocator_iterator(allocator_type *storage, size_t index) - : storage_(storage) - , index_(index) - , begin_(0) - , end_(storage->size()) - {} + explicit flat_linear_allocator_iterator(allocator_type* storage, size_t index) + : storage_(storage) + , index_(index) + , begin_(0) + , end_(storage->size()) + { + } - explicit flat_linear_allocator_iterator(allocator_type *storage, - size_t index, - size_t begin, - size_t end) - : storage_(storage) - , index_(index) - , begin_(begin) - , end_(end) - {} + explicit flat_linear_allocator_iterator(allocator_type* storage, + size_t index, + size_t begin, + size_t end) + : storage_(storage) + , index_(index) + , begin_(begin) + , end_(end) + { + } - explicit flat_linear_allocator_iterator(const allocator_type *storage, size_t index) - : storage_(storage) - , index_(index) - , begin_(0) - , end_(storage->size()) - {} + explicit flat_linear_allocator_iterator(const allocator_type* storage, + size_t index) + : storage_(storage) + , index_(index) + , begin_(0) + , end_(storage->size()) + { + } - explicit flat_linear_allocator_iterator(const allocator_type *storage, - size_t index, - size_t begin, - size_t end) - : storage_(storage) - , index_(index) - , begin_(begin) - , end_(end) - {} - reference operator*() - { - BOOST_MATH_ASSERT(index_ >= begin_ && index_ < end_); - return (*storage_->data_[index_ / buffer_size])[index_ % buffer_size]; - } + explicit flat_linear_allocator_iterator(const allocator_type* storage, + size_t index, + size_t begin, + size_t end) + : storage_(storage) + , index_(index) + , begin_(begin) + , end_(end) + { + } + reference operator*() + { + BOOST_MATH_ASSERT(index_ >= begin_ && index_ < end_); + return (*storage_->data_[index_ / buffer_size])[index_ % buffer_size]; + } - const_reference_type operator*() const - { - BOOST_MATH_ASSERT(index_ >= begin_ && index_ < end_); - return (*storage_->data_[index_ / buffer_size])[index_ % buffer_size]; - } + const_reference_type operator*() const + { + BOOST_MATH_ASSERT(index_ >= begin_ && index_ < end_); + return (*storage_->data_[index_ / buffer_size])[index_ % buffer_size]; + } - pointer operator->() - { - BOOST_MATH_ASSERT(index_ >= begin_ && index_ < end_); - return &operator*(); - } + pointer operator->() + { + BOOST_MATH_ASSERT(index_ >= begin_ && index_ < end_); + return &operator*(); + } - const_ptr_type operator->() const - { - BOOST_MATH_ASSERT(index_ >= begin_ && index_ < end_); - return &operator*(); - } - flat_linear_allocator_iterator &operator++() - { - ++index_; - return *this; - } + const_ptr_type operator->() const + { + BOOST_MATH_ASSERT(index_ >= begin_ && index_ < end_); + return &operator*(); + } + flat_linear_allocator_iterator& operator++() + { + ++index_; + return *this; + } - flat_linear_allocator_iterator operator++(int) - { - auto tmp = *this; - ++(*this); - return tmp; - } + flat_linear_allocator_iterator operator++(int) + { + auto tmp = *this; + ++(*this); + return tmp; + } - flat_linear_allocator_iterator &operator--() - { - --index_; - return *this; - } + flat_linear_allocator_iterator& operator--() + { + --index_; + return *this; + } - flat_linear_allocator_iterator operator--(int) - { - auto tmp = *this; - --(*this); - return tmp; - } + flat_linear_allocator_iterator operator--(int) + { + auto tmp = *this; + --(*this); + return tmp; + } - bool operator==(const flat_linear_allocator_iterator &other) const - { - return index_ == other.index_ && storage_ == other.storage_; - } + bool operator==(const flat_linear_allocator_iterator& other) const + { + return index_ == other.index_ && storage_ == other.storage_; + } - bool operator!=(const flat_linear_allocator_iterator &other) const { return !(*this == other); } + bool operator!=(const flat_linear_allocator_iterator& other) const + { + return !(*this == other); + } - flat_linear_allocator_iterator operator+(difference_type n) const - { - return flat_linear_allocator_iterator(storage_, index_ + static_cast(n), begin_, end_); - } + flat_linear_allocator_iterator operator+(difference_type n) const + { + return flat_linear_allocator_iterator( + storage_, index_ + static_cast(n), begin_, end_); + } - flat_linear_allocator_iterator &operator+=(difference_type n) - { - index_ += n; - return *this; - } + flat_linear_allocator_iterator& operator+=(difference_type n) + { + index_ += n; + return *this; + } - flat_linear_allocator_iterator operator-(difference_type n) const - { - return flat_linear_allocator_iterator(storage_, index_ - n, begin_, end_); - } - flat_linear_allocator_iterator &operator-=(difference_type n) - { - index_ -= n; - return *this; - } + flat_linear_allocator_iterator operator-(difference_type n) const + { + return flat_linear_allocator_iterator(storage_, index_ - n, begin_, end_); + } + flat_linear_allocator_iterator& operator-=(difference_type n) + { + index_ -= n; + return *this; + } - difference_type operator-(const flat_linear_allocator_iterator &other) const - { - return static_cast(index_) - static_cast(other.index_); - } + difference_type operator-(const flat_linear_allocator_iterator& other) const + { + return static_cast(index_) - + static_cast(other.index_); + } - reference operator[](difference_type n) { return *(*this + n); } + reference operator[](difference_type n) { return *(*this + n); } - const_reference_type operator[](difference_type n) const { return *(*this + n); } + const_reference_type operator[](difference_type n) const + { + return *(*this + n); + } - bool operator<(const flat_linear_allocator_iterator &other) const - { - return index_ < other.index_; - } + bool operator<(const flat_linear_allocator_iterator& other) const + { + return index_ < other.index_; + } - bool operator>(const flat_linear_allocator_iterator &other) const - { - return index_ > other.index_; - } + bool operator>(const flat_linear_allocator_iterator& other) const + { + return index_ > other.index_; + } - bool operator<=(const flat_linear_allocator_iterator &other) const - { - return index_ <= other.index_; - } + bool operator<=(const flat_linear_allocator_iterator& other) const + { + return index_ <= other.index_; + } - bool operator>=(const flat_linear_allocator_iterator &other) const - { - return index_ >= other.index_; - } + bool operator>=(const flat_linear_allocator_iterator& other) const + { + return index_ >= other.index_; + } - bool operator!() const noexcept { return storage_ == nullptr; } + bool operator!() const noexcept { return storage_ == nullptr; } }; /* memory management helps for tape */ template class flat_linear_allocator { - /** @brief basically a vector> + /** @brief basically a vector> * intended to work like a vector that allocates memory in chunks * and doesn't invalidate references * */ public: - // store vector of unique pointers to arrays - // to avoid vector reference invalidation - using buffer_type = std::array; - using buffer_ptr = std::unique_ptr>; + // store vector of unique pointers to arrays + // to avoid vector reference invalidation + using buffer_type = std::array; + using buffer_ptr = std::unique_ptr>; private: - std::vector data_; - size_t total_size_ = 0; - std::vector checkpoints_; //{0}; + std::vector data_; + size_t total_size_ = 0; + std::vector checkpoints_; //{0}; public: - friend class flat_linear_allocator_iterator, - buffer_size>; - friend class flat_linear_allocator_iterator, - buffer_size>; - using value_type = RealType; - using iterator - = flat_linear_allocator_iterator, buffer_size>; - using const_iterator - = flat_linear_allocator_iterator, - buffer_size>; + friend class flat_linear_allocator_iterator< + flat_linear_allocator, + buffer_size>; + friend class flat_linear_allocator_iterator< + const flat_linear_allocator, + buffer_size>; + using value_type = RealType; + using iterator = + flat_linear_allocator_iterator, + buffer_size>; + using const_iterator = flat_linear_allocator_iterator< + const flat_linear_allocator, + buffer_size>; - size_t buffer_id() const noexcept { return total_size_ / buffer_size; } - size_t item_id() const noexcept { return total_size_ % buffer_size; } + size_t buffer_id() const noexcept { return total_size_ / buffer_size; } + size_t item_id() const noexcept { return total_size_ % buffer_size; } private: - void allocate_buffer() - { - data_.emplace_back(std::make_unique()); - } + void allocate_buffer() + { + data_.emplace_back(std::make_unique()); + } public: - flat_linear_allocator() { allocate_buffer(); } - flat_linear_allocator(const flat_linear_allocator &) = delete; - flat_linear_allocator &operator=(const flat_linear_allocator &) = delete; - flat_linear_allocator(flat_linear_allocator &&) = delete; - flat_linear_allocator &operator=(flat_linear_allocator &&) = delete; - ~flat_linear_allocator() - { - destroy_all(); - data_.clear(); - } + flat_linear_allocator() { allocate_buffer(); } + flat_linear_allocator(const flat_linear_allocator&) = delete; + flat_linear_allocator& operator=(const flat_linear_allocator&) = delete; + flat_linear_allocator(flat_linear_allocator&&) = delete; + flat_linear_allocator& operator=(flat_linear_allocator&&) = delete; + ~flat_linear_allocator() + { + destroy_all(); + data_.clear(); + } - void destroy_all() - { - for (size_t i = 0; i < total_size_; ++i) { - size_t bid = i / buffer_size; - size_t iid = i % buffer_size; - (*data_[bid])[iid].~RealType(); - } + void destroy_all() + { + for (size_t i = 0; i < total_size_; ++i) { + size_t bid = i / buffer_size; + size_t iid = i % buffer_size; + (*data_[bid])[iid].~RealType(); } - /** @brief + } + /** @brief * helper functions to clear tape and create block in tape */ - void clear() - { - data_.clear(); - total_size_ = 0; - checkpoints_.clear(); - allocate_buffer(); + void clear() + { + data_.clear(); + total_size_ = 0; + checkpoints_.clear(); + allocate_buffer(); + } + + // doesn't delete anything, only sets the current index to zero + void reset() { total_size_ = 0; } + void rewind() { total_size_ = 0; }; + + // adds current index as a checkpoint to be able to walk back to + void add_checkpoint() + { + if (total_size_ > 0) { + checkpoints_.push_back(total_size_ - 1); + } else { + checkpoints_.push_back(0); } + }; - // doesn't delete anything, only sets the current index to zero - void reset() { total_size_ = 0; } - void rewind() { total_size_ = 0; }; - - // adds current index as a checkpoint to be able to walk back to - void add_checkpoint() - { - if (total_size_ > 0) { - checkpoints_.push_back(total_size_); //- 1); - } else { - checkpoints_.push_back(0); - } - }; - - /** @brief clears all checkpoints + /** @brief clears all checkpoints * */ - void reset_checkpoints() { checkpoints_.clear(); } + void reset_checkpoints() { checkpoints_.clear(); } - void rewind_to_last_checkpoint() { total_size_ = checkpoints_.back(); } - void rewind_to_checkpoint_at(size_t index) { total_size_ = checkpoints_[index]; } + void rewind_to_last_checkpoint() { total_size_ = checkpoints_.back(); } + void rewind_to_checkpoint_at(size_t index) + { + total_size_ = checkpoints_[index]; + } - void fill(const RealType &val) - { - for (size_t i = 0; i < total_size_; ++i) { - size_t bid = i / buffer_size; - size_t iid = i % buffer_size; - (*data_[bid])[iid] = val; - } + void fill(const RealType& val) + { + for (size_t i = 0; i < total_size_; ++i) { + size_t bid = i / buffer_size; + size_t iid = i % buffer_size; + (*data_[bid])[iid] = val; } + } - /** @brief emplaces back object at the end of the + /** @brief emplaces back object at the end of the * data structure, calls default constructor */ - iterator emplace_back() - { - if (item_id() == 0 && total_size_ != 0) { - allocate_buffer(); - } - size_t bid = buffer_id(); - size_t iid = item_id(); + iterator emplace_back() + { + if (item_id() == 0 && total_size_ != 0) { + allocate_buffer(); + } + size_t bid = buffer_id(); + size_t iid = item_id(); - RealType *ptr = &(*data_[bid])[iid]; - new (ptr) RealType(); - ++total_size_; - return iterator(this, total_size_ - 1); - }; + RealType* ptr = &(*data_[bid])[iid]; + new (ptr) RealType(); + ++total_size_; + return iterator(this, total_size_ - 1); + }; - /** @brief, emplaces back object at end of data structure, + /** @brief, emplaces back object at end of data structure, * passes arguments to constructor */ - template - iterator emplace_back(Args &&...args) - { - if (item_id() == 0 && total_size_ != 0) { - allocate_buffer(); - } - BOOST_MATH_ASSERT(buffer_id() < data_.size()); - BOOST_MATH_ASSERT(item_id() < buffer_size); - RealType *ptr = &(*data_[buffer_id()])[item_id()]; - new (ptr) RealType(std::forward(args)...); - ++total_size_; - return iterator(this, total_size_ - 1); + template + iterator emplace_back(Args&&... args) + { + if (item_id() == 0 && total_size_ != 0) { + allocate_buffer(); } - /** @brief default constructs n objects at end of + BOOST_MATH_ASSERT(buffer_id() < data_.size()); + BOOST_MATH_ASSERT(item_id() < buffer_size); + RealType* ptr = &(*data_[buffer_id()])[item_id()]; + new (ptr) RealType(std::forward(args)...); + ++total_size_; + return iterator(this, total_size_ - 1); + } + /** @brief default constructs n objects at end of * data structure, n known at compile time */ - template - iterator emplace_back_n() - { - size_t bid = buffer_id(); - size_t iid = item_id(); - if (iid + n < buffer_size) { - RealType *ptr = &(*data_[bid])[iid]; - for (size_t i = 0; i < n; ++i) { - new (ptr + i) RealType(); - } - total_size_ += n; - return iterator(this, total_size_ - n, total_size_ - n, total_size_); - } else { - size_t allocs_in_curr_buffer = buffer_size - iid; - size_t allocs_in_next_buffer = n - (buffer_size - iid); - RealType *ptr = &(*data_[bid])[iid]; - for (size_t i = 0; i < allocs_in_curr_buffer; ++i) { - new (ptr + i) RealType(); - } - allocate_buffer(); - bid = data_.size() - 1; - iid = 0; - total_size_ += n; + template + iterator emplace_back_n() + { + size_t bid = buffer_id(); + size_t iid = item_id(); + if (iid + n < buffer_size) { + RealType* ptr = &(*data_[bid])[iid]; + for (size_t i = 0; i < n; ++i) { + new (ptr + i) RealType(); + } + total_size_ += n; + return iterator(this, total_size_ - n, total_size_ - n, total_size_); + } else { + size_t allocs_in_curr_buffer = buffer_size - iid; + size_t allocs_in_next_buffer = n - (buffer_size - iid); + RealType* ptr = &(*data_[bid])[iid]; + for (size_t i = 0; i < allocs_in_curr_buffer; ++i) { + new (ptr + i) RealType(); + } + allocate_buffer(); + bid = data_.size() - 1; + iid = 0; + total_size_ += n; - RealType *ptr2 = &(*data_[bid])[iid]; - for (size_t i = 0; i < allocs_in_next_buffer; i++) { - new (ptr2 + i) RealType(); - } - return iterator(this, total_size_ - n, total_size_ - n, total_size_); - } + RealType* ptr2 = &(*data_[bid])[iid]; + for (size_t i = 0; i < allocs_in_next_buffer; i++) { + new (ptr2 + i) RealType(); + } + return iterator(this, total_size_ - n, total_size_ - n, total_size_); } - /** @brief default constructs n objects at end of + } + /** @brief default constructs n objects at end of * data structure, n known at run time */ - iterator emplace_back_n(size_t n) - { - size_t bid = buffer_id(); - size_t iid = item_id(); - if (iid + n < buffer_size) { - RealType *ptr = &(*data_[bid])[iid]; - for (size_t i = 0; i < n; ++i) { - new (ptr + i) RealType(); - } - total_size_ += n; - return iterator(this, total_size_ - n, total_size_ - n, total_size_); - } else { - size_t allocs_in_curr_buffer = buffer_size - iid; - size_t allocs_in_next_buffer = n - (buffer_size - iid); - RealType *ptr = &(*data_[bid])[iid]; - for (size_t i = 0; i < allocs_in_curr_buffer; ++i) { - new (ptr + i) RealType(); - } - allocate_buffer(); - bid = data_.size() - 1; - iid = 0; - total_size_ += n; + iterator emplace_back_n(size_t n) + { + size_t bid = buffer_id(); + size_t iid = item_id(); + if (iid + n < buffer_size) { + RealType* ptr = &(*data_[bid])[iid]; + for (size_t i = 0; i < n; ++i) { + new (ptr + i) RealType(); + } + total_size_ += n; + return iterator(this, total_size_ - n, total_size_ - n, total_size_); + } else { + size_t allocs_in_curr_buffer = buffer_size - iid; + size_t allocs_in_next_buffer = n - (buffer_size - iid); + RealType* ptr = &(*data_[bid])[iid]; + for (size_t i = 0; i < allocs_in_curr_buffer; ++i) { + new (ptr + i) RealType(); + } + allocate_buffer(); + bid = data_.size() - 1; + iid = 0; + total_size_ += n; - RealType *ptr2 = &(*data_[bid])[iid]; - for (size_t i = 0; i < allocs_in_next_buffer; i++) { - new (ptr2 + i) RealType(); - } - return iterator(this, total_size_ - n, total_size_ - n, total_size_); - } + RealType* ptr2 = &(*data_[bid])[iid]; + for (size_t i = 0; i < allocs_in_next_buffer; i++) { + new (ptr2 + i) RealType(); + } + return iterator(this, total_size_ - n, total_size_ - n, total_size_); } + } - /** @brief number of elements */ - size_t size() const { return total_size_; } + /** @brief number of elements */ + size_t size() const { return total_size_; } - /** @brief total capacity */ - size_t capacity() const { return data_.size() * buffer_size; } + /** @brief total capacity */ + size_t capacity() const { return data_.size() * buffer_size; } - /** @brief iterator helpers */ - iterator begin() { return iterator(this, 0); } - iterator end() { return iterator(this, total_size_); } - const_iterator begin() const { return const_iterator(this, 0); } - const_iterator end() const { return const_iterator(this, total_size_); } + /** @brief iterator helpers */ + iterator begin() { return iterator(this, 0); } + iterator end() { return iterator(this, total_size_); } + const_iterator begin() const { return const_iterator(this, 0); } + const_iterator end() const { return const_iterator(this, total_size_); } - iterator last_checkpoint() { return iterator(this, checkpoints_.back(), 0, total_size_); } - iterator first_checkpoint() { return iterator(this, checkpoints_[0], 0, total_size_); }; - iterator checkpoint_at(size_t index) - { - return iterator(this, checkpoints_[index], 0, total_size_); - }; + iterator last_checkpoint() + { + return iterator(this, checkpoints_.back(), 0, total_size_); + } + iterator first_checkpoint() + { + return iterator(this, checkpoints_[0], 0, total_size_); + }; + iterator checkpoint_at(size_t index) + { + return iterator(this, checkpoints_[index], 0, total_size_); + }; - /** @brief searches for item in allocator + /** @brief searches for item in allocator * only used to find gradient nodes for propagation */ - iterator find(const RealType *const item) - { - return std::find_if(begin(), end(), [&](const RealType &val) { return &val == item; }); - } - /** @brief vector like access, + iterator find(const RealType* const item) + { + return std::find_if( + begin(), end(), [&](const RealType& val) { return &val == item; }); + } + /** @brief vector like access, * currently unused anywhere but very useful for debugging */ - RealType &operator[](std::size_t i) - { - BOOST_MATH_ASSERT(i < total_size_); - return (*data_[i / buffer_size])[i % buffer_size]; - } - const RealType &operator[](std::size_t i) const - { - BOOST_MATH_ASSERT(i < total_size_); - return (*data_[i / buffer_size])[i % buffer_size]; - } + RealType& operator[](std::size_t i) + { + BOOST_MATH_ASSERT(i < total_size_); + return (*data_[i / buffer_size])[i % buffer_size]; + } + const RealType& operator[](std::size_t i) const + { + BOOST_MATH_ASSERT(i < total_size_); + return (*data_[i / buffer_size])[i % buffer_size]; + } }; } // namespace detail } // namespace reverse_mode diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 279d54759..d03fb3ecd 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -1368,6 +1368,13 @@ test-suite test_reverse_mode_autodiff [ run test_reverse_mode_autodiff_basic_math_ops.cpp /boost/test//boost_unit_test_framework : : : gcc-mingw:-Wa,-mbig-obj off msvc:/bigobj release ] [ run test_reverse_mode_autodiff_error_functions.cpp /boost/test//boost_unit_test_framework : : : gcc-mingw:-Wa,-mbig-obj off msvc:/bigobj release ] ; + +test-suite gradient_based_optimizers + : + [ run test_gradient_descent_optimizer.cpp /boost/test//boost_unit_test_framework : : : gcc-mingw:-Wa,-mbig-obj off msvc:/bigobj release ] + [ run test_nesterov_optimizer.cpp /boost/test//boost_unit_test_framework : : : gcc-mingw:-Wa,-mbig-obj off msvc:/bigobj release ] + [ run test_lbfgs.cpp /boost/test//boost_unit_test_framework : : : gcc-mingw:-Wa,-mbig-obj off msvc:/bigobj release ] + ; # BEGIN AUTODIFF LONG RUNNING TESTS test-suite autodiff-long-running-tests : @@ -2355,6 +2362,6 @@ explicit no_eh_tests ; # Some aliases which group blocks of tests for CI testing: alias github_ci_block_1 : special_fun float128_tests distribution_tests mp misc concepts ; -alias github_ci_block_2 : quadrature interpolators autodiff test_reverse_mode_autodiff ../example//examples ../tools ; +alias github_ci_block_2 : quadrature interpolators autodiff test_reverse_mode_autodiff gradient_based_optimizers ../example//examples ../tools ; explicit github_ci_block_1 ; explicit github_ci_block_2 ;