// (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) #ifndef BOOST_MATH_STATISTICS_CHATTERJEE_CORRELATION_HPP #define BOOST_MATH_STATISTICS_CHATTERJEE_CORRELATION_HPP #include #include #include #include #include #include #include #include #include #include #include #ifdef BOOST_MATH_EXEC_COMPATIBLE #include #include #include #endif namespace boost { namespace math { namespace statistics { namespace detail { template std::size_t chatterjee_transform(BDIter begin, BDIter end) { std::size_t sum = 0; while(++begin != end) { if(*begin > *std::prev(begin)) { sum += *begin - *std::prev(begin); } else { sum += *std::prev(begin) - *begin; } } return sum; } template ReturnType chatterjee_correlation_seq_impl(ForwardIterator u_begin, ForwardIterator u_end, ForwardIterator v_begin, ForwardIterator v_end) { using std::abs; BOOST_MATH_ASSERT_MSG(std::is_sorted(u_begin, u_end), "The x values must be sorted in order to use this functionality"); const std::vector rank_vector = rank(v_begin, v_end); std::size_t sum = chatterjee_transform(rank_vector.begin(), rank_vector.end()); ReturnType result = static_cast(1) - (static_cast(3 * sum) / static_cast(rank_vector.size() * rank_vector.size() - 1)); // If the result is 1 then Y is constant and all the elements must be ties if (abs(result - static_cast(1)) < std::numeric_limits::epsilon()) { return std::numeric_limits::quiet_NaN(); } return result; } } // Namespace detail template ::value, double, Real>::type> inline ReturnType chatterjee_correlation(const Container& u, const Container& v) { return detail::chatterjee_correlation_seq_impl(std::begin(u), std::end(u), std::begin(v), std::end(v)); } }}} // Namespace boost::math::statistics #ifdef BOOST_MATH_EXEC_COMPATIBLE namespace boost::math::statistics { namespace detail { template ReturnType chatterjee_correlation_par_impl(ExecutionPolicy&& exec, ForwardIterator u_begin, ForwardIterator u_end, ForwardIterator v_begin, ForwardIterator v_end) { using std::abs; BOOST_MATH_ASSERT_MSG(std::is_sorted(std::forward(exec), u_begin, u_end), "The x values must be sorted in order to use this functionality"); auto rank_vector = rank(std::forward(exec), v_begin, v_end); const auto num_threads = std::thread::hardware_concurrency() == 0 ? 2u : std::thread::hardware_concurrency(); std::vector> future_manager {}; const auto elements_per_thread = std::ceil(static_cast(rank_vector.size()) / num_threads); auto it = rank_vector.begin(); auto end = rank_vector.end(); for(std::size_t i {}; i < num_threads - 1; ++i) { future_manager.emplace_back(std::async(std::launch::async | std::launch::deferred, [it, elements_per_thread]() -> std::size_t { return chatterjee_transform(it, std::next(it, elements_per_thread)); })); it = std::next(it, elements_per_thread - 1); } future_manager.emplace_back(std::async(std::launch::async | std::launch::deferred, [it, end]() -> std::size_t { return chatterjee_transform(it, end); })); std::size_t sum {}; for(std::size_t i {}; i < future_manager.size(); ++i) { sum += future_manager[i].get(); } ReturnType result = static_cast(1) - (static_cast(3 * sum) / static_cast(rank_vector.size() * rank_vector.size() - 1)); // If the result is 1 then Y is constant and all the elements must be ties if (abs(result - static_cast(1)) < std::numeric_limits::epsilon()) { return std::numeric_limits::quiet_NaN(); } return result; } } // Namespace detail template , double, Real>> inline ReturnType chatterjee_correlation(ExecutionPolicy&& exec, const Container& u, const Container& v) { if constexpr (std::is_same_v, decltype(std::execution::seq)>) { return detail::chatterjee_correlation_seq_impl(std::cbegin(u), std::cend(u), std::cbegin(v), std::cend(v)); } else { return detail::chatterjee_correlation_par_impl(std::forward(exec), std::cbegin(u), std::cend(u), std::cbegin(v), std::cend(v)); } } } // Namespace boost::math::statistics #endif #endif // BOOST_MATH_STATISTICS_CHATTERJEE_CORRELATION_HPP