/* * (C) Copyright Nick Thompson 2018. * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include using boost::multiprecision::cpp_bin_float_50; using boost::multiprecision::cpp_complex_50; /* * Test checklist: * 1) Does it work with multiprecision? * 2) Does it work with .cbegin()/.cend() if the data is not altered? * 3) Does it work with ublas and std::array? (Checking Eigen and Armadillo will make the CI system really unhappy.) * 4) Does it work with std::forward_list if a forward iterator is all that is required? * 5) Does it work with complex data if complex data is sensible? */ using boost::math::statistics::means_and_covariance; using boost::math::statistics::covariance; template void test_covariance() { std::cout << std::setprecision(std::numeric_limits::digits10+1); Real tol = std::numeric_limits::epsilon(); using std::abs; // Covariance of a single thing is zero: std::array u1{8}; std::array v1{17}; auto [mu_u1, mu_v1, cov1] = means_and_covariance(u1, v1); BOOST_TEST(abs(cov1) < tol); BOOST_TEST(abs(mu_u1 - 8) < tol); BOOST_TEST(abs(mu_v1 - 17) < tol); std::array u2{8, 4}; std::array v2{3, 7}; auto [mu_u2, mu_v2, cov2] = means_and_covariance(u2, v2); BOOST_TEST(abs(cov2+4) < tol); BOOST_TEST(abs(mu_u2 - 6) < tol); BOOST_TEST(abs(mu_v2 - 5) < tol); std::vector u3{1,2,3}; std::vector v3{1,1,1}; auto [mu_u3, mu_v3, cov3] = means_and_covariance(u3, v3); // Since v is constant, covariance(u,v) = 0 against everything any u: BOOST_TEST(abs(cov3) < tol); BOOST_TEST(abs(mu_u3 - 2) < tol); BOOST_TEST(abs(mu_v3 - 1) < tol); // Make sure we pull the correct symbol out of means_and_covariance: cov3 = covariance(u3, v3); BOOST_TEST(abs(cov3) < tol); cov3 = covariance(v3, u3); // Covariance is symmetric: cov(u,v) = cov(v,u) BOOST_TEST(abs(cov3) < tol); // cov(u,u) = sigma(u)^2: cov3 = covariance(u3, u3); Real expected = Real(2)/Real(3); BOOST_TEST(abs(cov3 - expected) < tol); std::mt19937 gen(15); // Can't template standard library on multiprecision, so use double and cast back: std::uniform_real_distribution dis(-1.0, 1.0); std::vector u(500); std::vector v(500); for(size_t i = 0; i < u.size(); ++i) { u[i] = (Real) dis(gen); v[i] = (Real) dis(gen); } Real mu_u = boost::math::statistics::mean(u); Real mu_v = boost::math::statistics::mean(v); Real sigma_u_sq = boost::math::statistics::variance(u); Real sigma_v_sq = boost::math::statistics::variance(v); auto [mu_u_, mu_v_, cov_uv] = means_and_covariance(u, v); BOOST_TEST(abs(mu_u - mu_u_) < tol); BOOST_TEST(abs(mu_v - mu_v_) < tol); // Cauchy-Schwartz inequality: BOOST_TEST(cov_uv*cov_uv <= sigma_u_sq*sigma_v_sq); // cov(X, X) = sigma(X)^2: Real cov_uu = covariance(u, u); BOOST_TEST(abs(cov_uu - sigma_u_sq) < tol); Real cov_vv = covariance(v, v); BOOST_TEST(abs(cov_vv - sigma_v_sq) < tol); } template void test_correlation_coefficient() { using boost::math::statistics::correlation_coefficient; Real tol = std::numeric_limits::epsilon(); std::vector u{1}; std::vector v{1}; Real rho_uv = correlation_coefficient(u, v); BOOST_TEST(abs(rho_uv - 1) < tol); u = {1,1}; v = {1,1}; rho_uv = correlation_coefficient(u, v); BOOST_TEST(abs(rho_uv - 1) < tol); u = {1, 2, 3}; v = {1, 2, 3}; rho_uv = correlation_coefficient(u, v); BOOST_TEST(abs(rho_uv - 1) < tol); u = {1, 2, 3}; v = {-1, -2, -3}; rho_uv = correlation_coefficient(u, v); BOOST_TEST(abs(rho_uv + 1) < tol); rho_uv = correlation_coefficient(v, u); BOOST_TEST(abs(rho_uv + 1) < tol); u = {1, 2, 3}; v = {0, 0, 0}; rho_uv = correlation_coefficient(v, u); BOOST_TEST(abs(rho_uv) < tol); u = {1, 2, 3}; v = {0, 0, 3}; rho_uv = correlation_coefficient(v, u); // mu_u = 2, sigma_u^2 = 2/3, mu_v = 1, sigma_v^2 = 2, cov(u,v) = 1. BOOST_TEST(abs(rho_uv - sqrt(Real(3))/Real(2)) < tol); } int main() { test_covariance(); test_covariance(); test_covariance(); test_covariance(); test_correlation_coefficient(); test_correlation_coefficient(); test_correlation_coefficient(); test_correlation_coefficient(); return boost::report_errors(); }