| // (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 |