diff --git a/include/evalhyd/detail/uncertainty.hpp b/include/evalhyd/detail/uncertainty.hpp
index de7d746621195ebb48f6439fed377b4003ce1173..d3b086b24cc40a35da2c3031f0472348ccc1226a 100644
--- a/include/evalhyd/detail/uncertainty.hpp
+++ b/include/evalhyd/detail/uncertainty.hpp
@@ -16,7 +16,6 @@
 #include <xtensor/xtensor.hpp>
 #include <xtensor/xadapt.hpp>
 #include <xtensor/xrandom.hpp>
-#include <xtensor/xio.hpp>
 
 #include "maths.hpp"
 
@@ -154,41 +153,70 @@ namespace evalhyd
 
             return samples;
         }
-
-        inline auto summarise(const xt::xarray<double>& values, int summary)
+        
+        inline auto summarise_d(const xt::xarray<double>& values, int summary)
         {
-            // TODO: wait for xt::quantile to be available
-            //       or implement it internally for n-dim expressions
+            // define axis along which samples are
+            std::size_t axis = 2;
+
+            // determine shape for output values
+            std::vector<std::size_t> shp;
+            std::size_t i = 0;
+            for (auto a : values.shape())
+            {
+                if (i != axis)
+                {
+                    shp.push_back(a);
+                }
+                else
+                {
+                    if (summary == 1)
+                    {
+                        shp.push_back(2);
+                    }
+                    else if (summary == 2)
+                    {
+                        shp.push_back(7);
+                    }
+                }
+                i++;
+            }
+
             // summary 2: series of quantiles across samples
             if (summary == 2)
             {
-//                // adjust last axis size (from samples to number of statistics)
-//                auto s = values.shape();
-//                s.pop_back();
-//                s.push_back(7);
-//                xt::xarray<double> v = xt::zeros<double>(s);
-//                // quantiles
-//                xt::view(v, xt::all()) =
-//                        xt::quantile(values, {0.05, 0.10, 0.25, 0.50, 0.75, 0.90, 0.95}, -1);
-//                return v;
-                return values;
+                xt::xarray<double> v = xt::zeros<double>(shp);
+
+                // compute quantiles
+                auto quantiles = xt::quantile(
+                        values,
+                        {0.05, 0.10, 0.25, 0.50, 0.75, 0.90, 0.95},
+                        axis
+                );
+
+                // transfer quantiles into correct axis
+                // (since xt::quantile puts the quantiles on the first axis)
+                for (std::size_t q = 0; q < 7; q++)
+                {
+                    xt::view(v, xt::all(), xt::all(), q) =
+                            xt::view(quantiles, q);
+                }
+
+                return v;
             }
-            // TODO: wait for xt::stddev to be fixed for rtensor
-            //       or implement it internally for n-dim expressions
             // summary 1: mean and standard deviation across samples
             else if (summary == 1)
             {
-//                // adjust last axis size (from samples to number of statistics)
-//                auto s = values.shape();
-//                s.pop_back();
-//                s.push_back(2);
-//                xt::xarray<double> v = xt::zeros<double>(s);
-//                // mean
-//                xt::strided_view(s, xt::ellipsis(), 0) = xt::mean(values, -1);
-//                // standard deviation
-//                xt::strided_view(s, xt::ellipsis(), 1) = xt::stddev(values, -1);
-//                return v;
-                return values;
+                xt::xarray<double> v = xt::zeros<double>(shp);
+
+                // compute mean
+                xt::view(v, xt::all(), xt::all(), 0) =
+                        xt::mean(values, 2);
+                // compute standard deviation
+                xt::view(v, xt::all(), xt::all(), 1) =
+                        xt::stddev(values, 2);
+
+                return v;
             }
             // summary 0: raw (keep all samples)
             else
@@ -197,6 +225,76 @@ namespace evalhyd
             }
         }
 
+        inline auto summarise_p(const xt::xarray<double>& values, int summary)
+        {
+            // define axis along which samples are
+            std::size_t axis = 3;
+
+            // determine shape for output values
+            std::vector<std::size_t> shp;
+            std::size_t i = 0;
+            for (auto a : values.shape())
+            {
+                if (i != axis)
+                {
+                    shp.push_back(a);
+                }
+                else
+                {
+                    if (summary == 1)
+                    {
+                        shp.push_back(2);
+                    }
+                    else if (summary == 2)
+                    {
+                        shp.push_back(7);
+                    }
+                }
+                i++;
+            }
+
+            // summary 2: series of quantiles across samples
+            if (summary == 2)
+            {
+                xt::xarray<double> v = xt::zeros<double>(shp);
+
+                // compute quantiles
+                auto quantiles = xt::quantile(
+                        values,
+                        {0.05, 0.10, 0.25, 0.50, 0.75, 0.90, 0.95},
+                        axis
+                );
+
+                // transfer quantiles into correct axis
+                // (since xt::quantile puts the quantiles on the first axis)
+                for (std::size_t q = 0; q < 7; q++)
+                {
+                    xt::view(v, xt::all(), xt::all(), xt::all(), q) =
+                            xt::view(quantiles, q);
+                }
+
+                return v;
+            }
+            // summary 1: mean and standard deviation across samples
+            else if (summary == 1)
+            {
+                xt::xarray<double> v = xt::zeros<double>(shp);
+
+                // compute mean
+                xt::view(v, xt::all(), xt::all(), xt::all(), 0) =
+                        xt::mean(values, axis);
+                // compute standard deviation
+                xt::view(v, xt::all(), xt::all(), xt::all(), 1) =
+                        xt::stddev(values, axis);
+
+                return v;
+            }
+            // summary 0: raw (keep all samples)
+            else
+            {
+                return values;
+            }
+        }
     }
 }
 
diff --git a/include/evalhyd/detail/utils.hpp b/include/evalhyd/detail/utils.hpp
index 839b49d53f7ccfafb17e8d29f0b8bdc156f1cf9d..94eae5387361ff4cbbd8513e3c4698048667f6f7 100644
--- a/include/evalhyd/detail/utils.hpp
+++ b/include/evalhyd/detail/utils.hpp
@@ -88,8 +88,7 @@ namespace evalhyd
                 );
             }
             auto summary = bootstrap.find("summary")->second;
-            // TODO: change upper bound when mean+stddev and quantiles implemented
-            if ((summary < 0) || (summary > 0))
+            if ((summary < 0) || (summary > 2))
             {
                 throw std::runtime_error(
                         "invalid value for bootstrap summary"
diff --git a/include/evalhyd/evald.hpp b/include/evalhyd/evald.hpp
index f6539c396cf9dd4566bea5ffa96c17061b4de768..682619161b4668990947dcf42e14a0d425ab5b87 100644
--- a/include/evalhyd/evald.hpp
+++ b/include/evalhyd/evald.hpp
@@ -437,25 +437,25 @@ namespace evalhyd
             if ( metric == "RMSE" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_RMSE(), summary)
+                        uncertainty::summarise_d(evaluator.get_RMSE(), summary)
                 );
             }
             else if ( metric == "NSE" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_NSE(), summary)
+                        uncertainty::summarise_d(evaluator.get_NSE(), summary)
                 );
             }
             else if ( metric == "KGE" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_KGE(), summary)
+                        uncertainty::summarise_d(evaluator.get_KGE(), summary)
                 );
             }
             else if ( metric == "KGEPRIME" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_KGEPRIME(), summary)
+                        uncertainty::summarise_d(evaluator.get_KGEPRIME(), summary)
                 );
             }
         }
diff --git a/include/evalhyd/evalp.hpp b/include/evalhyd/evalp.hpp
index 8cf1fa78a644aaad990a06c4e5ddeff923beeaca..80a14ce28a939120c16b1f72c3e50556fae688c0 100644
--- a/include/evalhyd/evalp.hpp
+++ b/include/evalhyd/evalp.hpp
@@ -400,121 +400,121 @@ namespace evalhyd
             if ( metric == "BS" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_BS(), summary)
+                        uncertainty::summarise_p(evaluator.get_BS(), summary)
                 );
             }
             else if ( metric == "BSS" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_BSS(), summary)
+                        uncertainty::summarise_p(evaluator.get_BSS(), summary)
                 );
             }
             else if ( metric == "BS_CRD" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_BS_CRD(), summary)
+                        uncertainty::summarise_p(evaluator.get_BS_CRD(), summary)
                 );
             }
             else if ( metric == "BS_LBD" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_BS_LBD(), summary)
+                        uncertainty::summarise_p(evaluator.get_BS_LBD(), summary)
                 );
             }
             else if ( metric == "QS" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_QS(), summary)
+                        uncertainty::summarise_p(evaluator.get_QS(), summary)
                 );
             }
             else if ( metric == "CRPS" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_CRPS(), summary)
+                        uncertainty::summarise_p(evaluator.get_CRPS(), summary)
                 );
             }
             else if ( metric == "POD" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_POD(), summary)
+                        uncertainty::summarise_p(evaluator.get_POD(), summary)
                 );
             }
             else if ( metric == "POFD" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_POFD(), summary)
+                        uncertainty::summarise_p(evaluator.get_POFD(), summary)
                 );
             }
             else if ( metric == "FAR" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_FAR(), summary)
+                        uncertainty::summarise_p(evaluator.get_FAR(), summary)
                 );
             }
             else if ( metric == "CSI" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_CSI(), summary)
+                        uncertainty::summarise_p(evaluator.get_CSI(), summary)
                 );
             }
             else if ( metric == "ROCSS" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_ROCSS(), summary)
+                        uncertainty::summarise_p(evaluator.get_ROCSS(), summary)
                 );
             }
             else if ( metric == "RANK_HIST" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_RANK_HIST(), summary)
+                        uncertainty::summarise_p(evaluator.get_RANK_HIST(), summary)
                 );
             }
             else if ( metric == "DS" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_DS(), summary)
+                        uncertainty::summarise_p(evaluator.get_DS(), summary)
                 );
             }
             else if ( metric == "AS" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_AS(), summary)
+                        uncertainty::summarise_p(evaluator.get_AS(), summary)
                 );
             }
             else if ( metric == "CR" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_CR(), summary)
+                        uncertainty::summarise_p(evaluator.get_CR(), summary)
                 );
             }
             else if ( metric == "AW" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_AW(), summary)
+                        uncertainty::summarise_p(evaluator.get_AW(), summary)
                 );
             }
             else if ( metric == "AWN" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_AWN(), summary)
+                        uncertainty::summarise_p(evaluator.get_AWN(), summary)
                 );
             }
             else if ( metric == "AWI" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_AWI(), summary)
+                        uncertainty::summarise_p(evaluator.get_AWI(), summary)
                 );
             }
             else if ( metric == "WS" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_WS(), summary)
+                        uncertainty::summarise_p(evaluator.get_WS(), summary)
                 );
             }
             else if ( metric == "WSS" )
             {
                 r.emplace_back(
-                        uncertainty::summarise(evaluator.get_WSS(), summary)
+                        uncertainty::summarise_p(evaluator.get_WSS(), summary)
                 );
             }
         }
diff --git a/tests/test_determinist.cpp b/tests/test_determinist.cpp
index 0ddcd1860a22bd40bb23f8f44d44d6d548fcdf3c..c37e93f814565a267bc13981ce0fc50ae2a042f1 100644
--- a/tests/test_determinist.cpp
+++ b/tests/test_determinist.cpp
@@ -12,6 +12,8 @@
 #include <xtensor/xtensor.hpp>
 #include <xtensor/xview.hpp>
 #include <xtensor/xmanipulation.hpp>
+#include <xtensor/xmath.hpp>
+#include <xtensor/xsort.hpp>
 #include <xtensor/xcsv.hpp>
 
 #include "evalhyd/evald.hpp"
@@ -409,3 +411,114 @@ TEST(DeterministTests, TestBootstrap)
         ) << "Failure for (" << all_metrics_d[m] << ")";
     }
 }
+
+TEST(DeterministTests, TestBootstrapSummary)
+{
+    // read in data
+    std::ifstream ifs;
+
+    ifs.open(EVALHYD_DATA_DIR "/q_obs_1yr.csv");
+    xt::xtensor<std::string, 1> x_dts = xt::squeeze(xt::load_csv<std::string>(ifs, ',', 0, 1));
+    ifs.close();
+    std::vector<std::string> datetimes (x_dts.begin(), x_dts.end());
+
+    ifs.open(EVALHYD_DATA_DIR "/q_obs_1yr.csv");
+    xt::xtensor<double, 1> observed = xt::squeeze(xt::load_csv<double>(ifs, ',', 1));
+    ifs.close();
+
+    ifs.open(EVALHYD_DATA_DIR "/q_prd_1yr.csv");
+    xt::xtensor<double, 2> predicted = xt::load_csv<double>(ifs, ',', 1);
+    ifs.close();
+
+    // compute metrics via bootstrap with raw summary
+    std::unordered_map<std::string, int> bootstrap_0 =
+            {{"n_samples", 10}, {"len_sample", 3}, {"summary", 0}};
+
+    std::vector<xt::xarray<double>> metrics_raw =
+            evalhyd::evald(
+                    xt::eval(xt::view(observed, xt::newaxis(), xt::all())),
+                    predicted,
+                    all_metrics_d,
+                    {},  // transform
+                    {},  // exponent
+                    {},  // epsilon
+                    xt::xtensor<bool, 3>({}),  // t_msk
+                    xt::xtensor<std::array<char, 32>, 2>({}),  // m_cdt
+                    bootstrap_0,
+                    datetimes
+            );
+
+    // compute metrics via bootstrap with mean and standard deviation summary
+    std::unordered_map<std::string, int> bootstrap_1 =
+            {{"n_samples", 10}, {"len_sample", 3}, {"summary", 1}};
+
+    std::vector<xt::xarray<double>> metrics_mas =
+            evalhyd::evald(
+                    xt::eval(xt::view(observed, xt::newaxis(), xt::all())),
+                    predicted,
+                    all_metrics_d,
+                    {},  // transform
+                    {},  // exponent
+                    {},  // epsilon
+                    xt::xtensor<bool, 3>({}),  // t_msk
+                    xt::xtensor<std::array<char, 32>, 2>({}),  // m_cdt
+                    bootstrap_1,
+                    datetimes
+            );
+
+    // check results are identical
+    for (std::size_t m = 0; m < all_metrics_d.size(); m++)
+    {
+        // mean
+        EXPECT_TRUE(
+                xt::all(xt::isclose(
+                        xt::mean(metrics_raw[m], 2),
+                        xt::view(metrics_mas[m], xt::all(), xt::all(), 0)
+                ))
+        ) << "Failure for (" << all_metrics_d[m] << ") on mean";
+        // standard deviation
+        EXPECT_TRUE(
+                xt::all(xt::isclose(
+                        xt::stddev(metrics_raw[m], 2),
+                        xt::view(metrics_mas[m], xt::all(), xt::all(), 1)
+                ))
+        ) << "Failure for (" << all_metrics_d[m] << ") on standard deviation";
+    }
+
+    // compute metrics via bootstrap with quantiles summary
+    std::unordered_map<std::string, int> bootstrap_2 =
+            {{"n_samples", 10}, {"len_sample", 3}, {"summary", 2}};
+
+    std::vector<xt::xarray<double>> metrics_qtl =
+            evalhyd::evald(
+                    xt::eval(xt::view(observed, xt::newaxis(), xt::all())),
+                    predicted,
+                    all_metrics_d,
+                    {},  // transform
+                    {},  // exponent
+                    {},  // epsilon
+                    xt::xtensor<bool, 3>({}),  // t_msk
+                    xt::xtensor<std::array<char, 32>, 2>({}),  // m_cdt
+                    bootstrap_2,
+                    datetimes
+            );
+
+    // check results are identical
+    for (std::size_t m = 0; m < all_metrics_d.size(); m++)
+    {
+        // quantiles
+        std::vector<double> quantiles = {0.05, 0.10, 0.25, 0.50, 0.75, 0.90, 0.95};
+        std::size_t i = 0;
+
+        for (auto q : quantiles)
+        {
+            EXPECT_TRUE(
+                    xt::all(xt::isclose(
+                            xt::quantile(metrics_raw[m], {q}, 2),
+                            xt::view(metrics_qtl[m], xt::all(), xt::all(), i)
+                    ))
+            ) << "Failure for (" << all_metrics_d[m] << ") on quantile " << q;
+            i++;
+        }
+    }
+}
diff --git a/tests/test_probabilist.cpp b/tests/test_probabilist.cpp
index e0d8dd4ee856675594cd827548d729ebd502f029..31961005581e569e2ee897bfd9ba9577207b4b3f 100644
--- a/tests/test_probabilist.cpp
+++ b/tests/test_probabilist.cpp
@@ -12,6 +12,7 @@
 #include <xtl/xoptional.hpp>
 #include <xtensor/xtensor.hpp>
 #include <xtensor/xview.hpp>
+#include <xtensor/xmath.hpp>
 #include <xtensor/xsort.hpp>
 #include <xtensor/xmanipulation.hpp>
 #include <xtensor/xcsv.hpp>
@@ -965,4 +966,146 @@ TEST(ProbabilistTests, TestBootstrap)
                 ))
         ) << "Failure for (" << all_metrics_p[m] << ")";
     }
-}
\ No newline at end of file
+}
+
+TEST(ProbabilistTests, TestBootstrapSummary)
+{
+    xt::xtensor<double, 2> thresholds = {{ 33.87, 55.67 }};
+    std::vector<double> confidence_levels = {30., 80.};
+
+    // read in data
+    std::ifstream ifs;
+
+    ifs.open(EVALHYD_DATA_DIR "/q_obs_1yr.csv");
+    xt::xtensor<std::string, 1> x_dts = xt::squeeze(xt::load_csv<std::string>(ifs, ',', 0, 1));
+    ifs.close();
+    std::vector<std::string> datetimes (x_dts.begin(), x_dts.end());
+
+    ifs.open(EVALHYD_DATA_DIR "/q_obs_1yr.csv");
+    xt::xtensor<double, 1> observed = xt::squeeze(xt::load_csv<double>(ifs, ',', 1));
+    ifs.close();
+
+    ifs.open(EVALHYD_DATA_DIR "/q_prd_1yr.csv");
+    xt::xtensor<double, 2> predicted = xt::load_csv<double>(ifs, ',', 1);
+    ifs.close();
+
+    // compute metrics via bootstrap
+    std::unordered_map<std::string, int> bootstrap_0 =
+            {{"n_samples", 10}, {"len_sample", 3}, {"summary", 0}};
+
+    std::vector<xt::xarray<double>> metrics_raw =
+            evalhyd::evalp(
+                    xt::eval(xt::view(observed, xt::newaxis(), xt::all())),
+                    xt::eval(xt::view(predicted, xt::newaxis(), xt::newaxis(), xt::all(), xt::all())),
+                    all_metrics_p,
+                    thresholds,
+                    "high",  // events
+                    confidence_levels,
+                    xt::xtensor<bool, 4>({}),  // t_msk
+                    xt::xtensor<std::array<char, 32>, 2>({}),  // m_cdt
+                    bootstrap_0,
+                    datetimes
+            );
+
+    // compute metrics via bootstrap with mean and standard deviation summary
+    std::unordered_map<std::string, int> bootstrap_1 =
+            {{"n_samples", 10}, {"len_sample", 3}, {"summary", 1}};
+
+    std::vector<xt::xarray<double>> metrics_mas =
+            evalhyd::evalp(
+                    xt::eval(xt::view(observed, xt::newaxis(), xt::all())),
+                    xt::eval(xt::view(predicted, xt::newaxis(), xt::newaxis(), xt::all(), xt::all())),
+                    all_metrics_p,
+                    thresholds,
+                    "high",  // events
+                    confidence_levels,
+                    xt::xtensor<bool, 4>({}),  // t_msk
+                    xt::xtensor<std::array<char, 32>, 2>({}),  // m_cdt
+                    bootstrap_1,
+                    datetimes
+            );
+
+    // check results are identical
+    for (std::size_t m = 0; m < all_metrics_p.size(); m++)
+    {
+        // ---------------------------------------------------------------------
+        // /!\ skip ranks-based metrics because it contains a random process
+        //     for which setting the seed will not work because the time series
+        //     lengths are different between "bts" and "rep", which
+        //     results in different tensor shapes, and hence in different
+        //     random ranks for ties
+        if ((all_metrics_p[m] == "RANK_HIST")
+            || (all_metrics_p[m] == "DS")
+            || (all_metrics_p[m] == "AS"))
+        {
+            continue;
+        }
+        // ---------------------------------------------------------------------
+
+        // mean
+        EXPECT_TRUE(
+                xt::all(xt::isclose(
+                        xt::mean(metrics_raw[m], 3),
+                        xt::view(metrics_mas[m], xt::all(), xt::all(), xt::all(), 0)
+                ))
+        ) << "Failure for (" << all_metrics_p[m] << ") on mean";
+        // standard deviation
+        EXPECT_TRUE(
+                xt::all(xt::isclose(
+                        xt::stddev(metrics_raw[m], 3),
+                        xt::view(metrics_mas[m], xt::all(), xt::all(), xt::all(), 1)
+                ))
+        ) << "Failure for (" << all_metrics_p[m] << ") on standard deviation";
+    }
+
+    // compute metrics via bootstrap with quantiles summary
+    std::unordered_map<std::string, int> bootstrap_2 =
+            {{"n_samples", 10}, {"len_sample", 3}, {"summary", 2}};
+
+    std::vector<xt::xarray<double>> metrics_qtl =
+            evalhyd::evalp(
+                    xt::eval(xt::view(observed, xt::newaxis(), xt::all())),
+                    xt::eval(xt::view(predicted, xt::newaxis(), xt::newaxis(), xt::all(), xt::all())),
+                    all_metrics_p,
+                    thresholds,
+                    "high",  // events
+                    confidence_levels,
+                    xt::xtensor<bool, 4>({}),  // t_msk
+                    xt::xtensor<std::array<char, 32>, 2>({}),  // m_cdt
+                    bootstrap_2,
+                    datetimes
+            );
+
+    // check results are identical
+    for (std::size_t m = 0; m < all_metrics_p.size(); m++)
+    {
+        // ---------------------------------------------------------------------
+        // /!\ skip ranks-based metrics because it contains a random process
+        //     for which setting the seed will not work because the time series
+        //     lengths are different between "bts" and "rep", which
+        //     results in different tensor shapes, and hence in different
+        //     random ranks for ties
+        if ((all_metrics_p[m] == "RANK_HIST")
+            || (all_metrics_p[m] == "DS")
+            || (all_metrics_p[m] == "AS"))
+        {
+            continue;
+        }
+        // ---------------------------------------------------------------------
+
+        // quantiles
+        std::vector<double> quantiles = {0.05, 0.10, 0.25, 0.50, 0.75, 0.90, 0.95};
+        std::size_t i = 0;
+
+        for (auto q : quantiles)
+        {
+            EXPECT_TRUE(
+                    xt::all(xt::isclose(
+                            xt::quantile(metrics_raw[m], {q}, 3),
+                            xt::view(metrics_qtl[m], xt::all(), xt::all(), xt::all(), i)
+                    ))
+            ) << "Failure for (" << all_metrics_p[m] << ") on quantile " << q;
+            i++;
+        }
+    }
+}