code: def _get_historical_forecastable_time_index(
      model,
      series: TimeSeries,
      forecast_horizon: int,
      overlap_end: bool,
      past_covariates: Optional[TimeSeries] = None,
      future_covariates: Optional[TimeSeries] = None,
      is_training: Optional[bool] = False,
      reduce_to_bounds: bool = False,
  ) -> Union[
      pd.DatetimeIndex,
      pd.RangeIndex,
      Tuple[int, int],
      Tuple[pd.Timestamp, pd.Timestamp],
      None,
  ]:
      """
      Private function that returns the largest time_index representing the subset of each timestamps
      for which historical forecasts can be made, given the model's properties, the training series
      and the covariates.
          - If ``None`` is returned, there is no point where a forecast can be made.
  
          - If ``is_training=False``, it returns the time_index subset of predictable timestamps.
  
          - If ``is_training=True``, it returns the time_index subset of trainable timestamps. A trainable
          timestamp is a timestamp that has a training sample of length at least ``self.training_sample_length``
              preceding it.
  
      Additionally, it accounts for auto-regression (forecast_horizon > model.output_chunk_length , and overlap_end.
          - In case of auto-regression, we have to step back the last possible predictable/trainable time step if the
            covariates are too short
          - In case overlap_end=False, the latest possible predictable/trainable time step is shifted back if a
            prediction starting from that point would go beyond the end of `series`.
  
  
      Parameters
      ----------
      series
          A target series.
      forecast_horizon
          The forecast horizon for the predictions.
      overlap_end
          Whether the returned forecasts can go beyond the series' end or not.
      past_covariates
          Optionally, a past covariates.
      future_covariates
          Optionally, a future covariates.
      is_training
          Whether the returned time_index should be taking into account the training.
      reduce_to_bounds
          Whether to only return the minimum and maximum historical forecastable index
  
      Returns
      -------
      Union[pd.DatetimeIndex, pd.RangeIndex, Tuple[int, int], Tuple[pd.Timestamp, pd.Timestamp], None]
          The longest time_index that can be used for historical forecasting, either as a range or a tuple.
  
      Examples
      --------
      >>> model = LinearRegressionModel(lags=3, output_chunk_length=2)
      >>> model.fit(train_series)
      >>> series = TimeSeries.from_times_and_values(pd.date_range('2000-01-01', '2000-01-10'), np.arange(10))
      >>> model._get_historical_forecastable_time_index(series=series, is_training=False, forecast_horizon=1)
      DatetimeIndex(
              ['2000-01-04', '2000-01-05', '2000-01-06', '2000-01-07', '2000-01-08', '2000-01-09', '2000-01-10'],
              dtype='datetime64[ns]', freq='D'
      )
      >>> model._get_historical_forecastable_time_index(series=series, is_training=True)
      DatetimeIndex(['2000-01-06', '2000-01-08', '2000-01-09', '2000-01-10'], dtype='datetime64[ns]', freq='D')
      >>> model = NBEATSModel(input_chunk_length=3, output_chunk_length=3)
      >>> model.fit(train_series, train_past_covariates)
      >>> series = TimeSeries.from_times_and_values(pd.date_range('2000-10-01', '2000-10-09'), np.arange(8))
      >>> past_covariates = TimeSeries.from_times_and_values(
      >>>     pd.date_range('2000-10-03', '2000-10-20'),
      >>>     np.arange(18)
      >>> )
      >>> model._get_historical_forecastable_time_index(
      >>>     series=series,
      >>>     past_covariates=past_covariates,
      >>>     is_training=False,
      >>>     forecast_horizon=1,
      >>> )
      DatetimeIndex(['2000-10-06', '2000-10-07', '2000-10-08', '2000-10-09'], dtype='datetime64[ns]', freq='D')
      >>>  # Only one point is trainable; it corresponds to the first point after we reach a common subset of
      >>> # timestamps of training_sample_length length.
      >>> model._get_historical_forecastable_time_index(
      >>>     series=series,
      >>>     past_covariates=past_covariates,
      >>>     is_training=True,
      >>> )
      DatetimeIndex(['2000-10-09'], dtype='datetime64[ns]', freq='D')
      """
  
      (
          min_target_lag,
          max_target_lag,
          min_past_cov_lag,
          max_past_cov_lag,
          min_future_cov_lag,
          max_future_cov_lag,
      ) = model.extreme_lags
  
      # max_target_lag < 0 are local models which can predict for n (horizon) -> infinity (no auto-regression)
      is_autoregression = (
          max_target_lag >= 0 and forecast_horizon > max_target_lag + 1
      )
  
      if min_target_lag is None:
          min_target_lag = 0
  
      # longest possible time index for target
      if is_training:
          start = (
              series.start_time()
              + (max_target_lag - min_target_lag + 1) * series.freq
          )
      else:
          start = series.start_time() - min_target_lag * series.freq
      end = series.end_time() + 1 * series.freq
  
      intersect_ = (start, end)
  
      # longest possible time index for past covariates
      if (min_past_cov_lag is not None) and (
          past_covariates is not None
      ):
          if is_training:
              start_pc = (
                  past_covariates.start_time()
                  - (min_past_cov_lag - max_target_lag - 1)
                  * past_covariates.freq
              )
          else:
              start_pc = (
                  past_covariates.start_time()
                  - min_past_cov_lag * past_covariates.freq
              )
  
          shift_pc_end = max_past_cov_lag
          if is_autoregression:
              # we step back in case of auto-regression
              shift_pc_end += forecast_horizon - (max_target_lag + 1)
          end_pc = (
              past_covariates.end_time()
              - shift_pc_end * past_covariates.freq
          )
  
          intersect_ = (
              max([intersect_[0], start_pc]),
              min([intersect_[1], end_pc]),
          )
  
      # longest possible time index for future covariates
      if (min_future_cov_lag is not None) and (
          future_covariates is not None
      ):
          if is_training:
              start_fc = (
                  future_covariates.start_time()
                  - (min_future_cov_lag - max_target_lag - 1)
                  * future_covariates.freq
              )
          else:
              start_fc = (
                  future_covariates.start_time()
                  - min_future_cov_lag * future_covariates.freq
              )
  
          shift_fc_end = max_future_cov_lag
          if is_autoregression:
              # we step back in case of auto-regression
              shift_fc_end += forecast_horizon - (max_target_lag + 1)
          end_fc = (
              future_covariates.end_time()
              - shift_fc_end * future_covariates.freq
          )
  
          intersect_ = (
              max([intersect_[0], start_fc]),
              min([intersect_[1], end_fc]),
          )
  
      # overlap_end = True -> predictions must not go beyond end of target series
      if (
          not overlap_end
          and intersect_[1] + (forecast_horizon - 1) * series.freq
          > series.end_time()
      ):
          intersect_ = (
              intersect_[0],
              end - forecast_horizon * series.freq,
          )
  
      # end comes before the start
      if intersect_[1] < intersect_[0]:
          return None
  
      # if RegressionModel is not multi_models, it looks further in the past
      is_multi_models = getattr(model, "multi_models", None)
      if is_multi_models is not None and not is_multi_models:
          intersect_ = (
              intersect_[0]
              + (model.output_chunk_length - 1) * series.freq,
              intersect_[1],
          )
  
      # generate an index
      if not reduce_to_bounds:
          intersect_ = generate_index(
              start=intersect_[0], end=intersect_[1], freq=series.freq
          )
  
      return intersect_ if len(intersect_) > 0 else None
  
imports: from types import SimpleNamespace
  from typing import Any, Callable, Dict, Optional, Sequence, Set, Tuple, Union
  import inspect
  import numpy
  import pandas
  from numpy.typing import ArrayLike
  from darts.logging import get_logger, raise_if_not, raise_log
  from darts.timeseries import TimeSeries
  from darts.utils.timeseries_generation import generate_index
  from darts.utils.utils import series2seq
label_desc: Use image node_id 5 for calling a global function with example usage: _get_historical_forecastable_time_index(model, series, forecast_horizon, overlap_end, past_covariates, future_covariates, is_training, reduce_to_bounds) and returns: unknown, None