| // (C) Copyright Matt Borland 2022. |
| // Use, modification and distribution are subject to the |
| // Boost Software License, Version 1.0. (See accompanying file |
| // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| |
| #include <cmath> |
| #include <iterator> |
| #include <utility> |
| #include <algorithm> |
| #include <type_traits> |
| #include <initializer_list> |
| #include <boost/math/special_functions/logaddexp.hpp> |
| |
| namespace boost { namespace math { |
| |
| // https://nhigham.com/2021/01/05/what-is-the-log-sum-exp-function/ |
| // See equation (#) |
| template <typename ForwardIterator, typename Real = typename std::iterator_traits<ForwardIterator>::value_type> |
| Real logsumexp(ForwardIterator first, ForwardIterator last) |
| { |
| using std::exp; |
| using std::log1p; |
| |
| const auto elem = std::max_element(first, last); |
| const Real max_val = *elem; |
| |
| Real arg = 0; |
| while (first != last) |
| { |
| if (first != elem) |
| { |
| arg += exp(*first - max_val); |
| } |
| |
| ++first; |
| } |
| |
| return max_val + log1p(arg); |
| } |
| |
| template <typename Container, typename Real = typename Container::value_type> |
| inline Real logsumexp(const Container& c) |
| { |
| return logsumexp(std::begin(c), std::end(c)); |
| } |
| |
| template <typename... Args, typename Real = typename std::common_type<Args...>::type, |
| typename std::enable_if<std::is_floating_point<Real>::value, bool>::type = true> |
| inline Real logsumexp(Args&& ...args) |
| { |
| std::initializer_list<Real> list {std::forward<Args>(args)...}; |
| |
| if(list.size() == 2) |
| { |
| return logaddexp(*list.begin(), *std::next(list.begin())); |
| } |
| return logsumexp(list.begin(), list.end()); |
| } |
| |
| }} // Namespace boost::math |