def test_metric_quantiles_lpo(self, config):
        """Tests backtest with quantile and quantile interval metrics from expected probabilistic or quantile
        historical forecasts."""
        metric, lpo = config
        is_interval_metric = metric[0].__name__ == "miw"

        q = [0.05, 0.5, 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)
        hfc = TimeSeries.from_times_and_values(
            times=generate_index(start=y.start_time() + 10 * y.freq, length=10),
            values=np.random.random((10, 1, 100)),
        )
        hfc = hfc.stack(hfc + 1.0)
        y = [y, y]
        if lpo:
            hfc = [hfc, hfc]
        else:
            hfc = [[hfc, hfc], [hfc]]

        metric_kwargs = [{"component_reduction": np.median}]
        if not is_interval_metric:
            metric_kwargs[0]["q"] = q
        else:
            metric_kwargs[0]["q_interval"] = q_interval
        if len(metric) > 1:
            # give metric specific kwargs
            metric_kwargs2 = {
                "component_reduction": np.median,
                "time_reduction": np.mean,
            }
            if not is_interval_metric:
                metric_kwargs2["q"] = q
            else:
                metric_kwargs2["q_interval"] = q_interval
            metric_kwargs.append(metric_kwargs2)

        model = NaiveDrift()

        bts = model.backtest(
            series=y,
            historical_forecasts=hfc,
            metric=metric,
            last_points_only=lpo,
            reduction=None,
            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]
        q_kwargs = {"q": q} if not is_interval_metric else {"q_interval": q_interval}
        bt_expected = metric[0](
            y[0], hfc_single, component_reduction=np.median, **q_kwargs
        )
        shape_expected = (len(q),)
        if len(metric) > 1:
            bt_expected = np.concatenate([bt_expected[:, None]] * 2, axis=1)
            shape_expected += (len(metric),)
        for bt_list in bts:
            for bt in bt_list:
                assert bt.shape == shape_expected
                np.testing.assert_array_almost_equal(bt, bt_expected)

        bts = model.backtest(
            series=y,
            historical_forecasts=hfc,
            metric=metric,
            last_points_only=lpo,
            reduction=np.mean,
            metric_kwargs=metric_kwargs,
        )
        assert isinstance(bts, list) and len(bts) == 2
        for bt in bts:
            assert bt.shape == shape_expected
            np.testing.assert_array_almost_equal(bt, bt_expected)

        def time_reduced_metric(*args, **kwargs):
            metric_f = metrics.iw if is_interval_metric else metrics.ae
            return metric_f(*args, **kwargs, time_reduction=np.mean)

        # check that single kwargs can be used for all metrics if params are supported
        metric = [metric[0], time_reduced_metric]
        bts = model.backtest(
            series=y,
            historical_forecasts=hfc,
            metric=metric,
            last_points_only=lpo,
            reduction=None,
            metric_kwargs=metric_kwargs[0],
        )
        assert isinstance(bts, list) and len(bts) == 2
        if lpo:
            bts = [[bt] for bt in bts]
        # `ae` / `miw` with time and component reduction is equal to `mae` / `miw` with component reduction
        bt_expected = metric[0](
            y[0], hfc_single, component_reduction=np.median, **q_kwargs
        )
        bt_expected = np.concatenate([bt_expected[:, None]] * 2, axis=1)
        shape_expected = (len(q), len(metric))
        for bt_list in bts:
            for bt in bt_list:
                assert bt.shape == shape_expected
                np.testing.assert_array_almost_equal(bt, bt_expected)

        bts = model.backtest(
            series=y,
            historical_forecasts=hfc,
            metric=metric,
            last_points_only=lpo,
            reduction=np.mean,
            metric_kwargs=metric_kwargs[0],
        )
        assert isinstance(bts, list) and len(bts) == 2
        for bt in bts:
            assert bt.shape == shape_expected
            np.testing.assert_array_almost_equal(bt, bt_expected)

        # without component reduction
        metric_kwargs = {"component_reduction": None}
        if not is_interval_metric:
            metric_kwargs["q"] = q
        else:
            metric_kwargs["q_interval"] = q_interval
        bts = model.backtest(
            series=y,
            historical_forecasts=hfc,
            metric=metric,
            last_points_only=lpo,
            reduction=None,
            metric_kwargs=metric_kwargs,
        )
        assert isinstance(bts, list) and len(bts) == 2
        if lpo:
            bts = [[bt] for bt in bts]

        # `ae` / `iw` with time and no component reduction is equal to `mae` / `miw` without component reduction
        bt_expected = metric[0](y[0], hfc_single, **metric_kwargs)
        bt_expected = np.concatenate([bt_expected[:, None]] * 2, axis=1)
        shape_expected = (len(q) * y[0].width, len(metric))
        for bt_list in bts:
            for bt in bt_list:
                assert bt.shape == shape_expected
                np.testing.assert_array_almost_equal(bt, bt_expected)

        bts = model.backtest(
            series=y,
            historical_forecasts=hfc,
            metric=metric,
            last_points_only=lpo,
            reduction=np.mean,
            metric_kwargs=metric_kwargs,
        )
        assert isinstance(bts, list) and len(bts) == 2
        for bt in bts:
            assert bt.shape == shape_expected
            np.testing.assert_array_almost_equal(bt, bt_expected)
Tests backtest with quantile and quantile interval metrics from expected probabilistic or quantile
        historical forecasts.
darts/tests/models/forecasting/test_backtesting.py