def test_residuals_with_quantiles_metrics(self, config):
        """Tests residuals with quantile metrics from expected probabilistic or quantile historical forecasts."""
        metric, lpo, stochastic_pred = config
        is_interval_metric = metric.__name__ == "iw"

        # multi-quantile metrics yield more components
        q = [0.05, 0.50, 0.60, 0.95]
        q_interval = [(0.05, 0.50), (0.50, 0.60), (0.60, 0.95), (0.05, 0.60)]

        y = lt(length=20)
        y = y.stack(y + 1.0)
        if not is_interval_metric:
            q_comp_names_expected = pd.Index(
                likelihood_component_names(
                    components=y.components,
                    parameter_names=quantile_names(q),
                )
            )
        else:
            q_comp_names_expected = pd.Index(
                likelihood_component_names(
                    components=y.components,
                    parameter_names=quantile_interval_names(q_interval),
                )
            )
        # historical forecasts
        vals = np.random.random((10, 1, 100))
        if not stochastic_pred:
            vals = np.quantile(vals, q, axis=2).transpose((1, 0, 2))
            comp_names = pd.Index(
                likelihood_component_names(
                    components=y.components,
                    parameter_names=quantile_names(q=q),
                )
            )
        else:
            comp_names = y.components
        vals = np.concatenate([vals, vals + 1], axis=1)
        hfc = TimeSeries.from_times_and_values(
            times=generate_index(start=y.start_time() + 10 * y.freq, length=10),
            values=vals,
            columns=comp_names,
        )

        y = [y, y]
        if lpo:
            hfc = [hfc, hfc]
        else:
            hfc = [[hfc, hfc], [hfc]]

        metric_kwargs = {"component_reduction": None}
        if not is_interval_metric:
            metric_kwargs["q"] = q
        else:
            metric_kwargs["q_interval"] = q_interval

        model = NaiveDrift()

        # return TimeSeries
        bts = model.residuals(
            series=y,
            historical_forecasts=hfc,
            metric=metric,
            last_points_only=lpo,
            metric_kwargs=metric_kwargs,
        )
        assert isinstance(bts, list) and len(bts) == 2
        if lpo:
            bts = [[bt] for bt in bts]

        # `ae` with time and component reduction is equal to `mae` with component reduction
        hfc_single = hfc[0][0] if not lpo else hfc[0]
        bt_expected = metric(y[0], hfc_single, **metric_kwargs)
        shape_expected = (len(hfc_single), len(q) * y[0].n_components)
        for bt_list in bts:
            for bt in bt_list:
                assert bt.shape[:2] == shape_expected
                assert bt.components.equals(q_comp_names_expected)
                np.testing.assert_array_almost_equal(bt.values(), bt_expected)

        # values only
        bts = model.residuals(
            series=y,
            historical_forecasts=hfc,
            metric=metric,
            last_points_only=lpo,
            metric_kwargs=metric_kwargs,
            values_only=True,
        )
        assert isinstance(bts, list) and len(bts) == 2
        if lpo:
            bts = [[bt] for bt in bts]

        # `ae` with time and component reduction is equal to `mae` with component reduction
        for bt_list in bts:
            for bt in bt_list:
                assert bt.shape[:2] == shape_expected
                np.testing.assert_array_almost_equal(bt[:, :, 0], bt_expected)
Tests residuals with quantile metrics from expected probabilistic or quantile historical forecasts.
darts/tests/models/forecasting/test_residuals.py