docstr: A function to simulate future series.
  If the fitted model supports uncertainty e.g. via ``uncertainty_dict``,
  errors are incorporated into the simulations.
  
  Parameters
  ----------
  fut_df : `pandas.DataFrame`
      The data frame which includes the timestamps
      for prediction and any regressors.
  trained_model : `dict`
      A fitted silverkite model which is the output of ``self.forecast``.
  simulation_num : `int`
      The number of simulated series,
      (each of which have the same number of rows as ``fut_df``)
      to be stacked up row-wise. This number must be larger than zero.
  past_df : `pandas.DataFrame`, optional
      A data frame with past values if autoregressive methods are called
      via ``autoreg_dict`` parameter of ``greykite.algo.forecast.silverkite.SilverkiteForecast.py``.
  new_external_regressor_df: `pandas.DataFrame`, optional
      Contains the regressors not already included in ``fut_df``.
  include_err : `bool`, optional, default None
      Boolean to determine if errors are to be incorporated in the simulations.
      If None, it will be set to True if uncertainty is passed to the model and
      otherwise will be set to False.
  
  Returns
  -------
  result: `dict`
      A dictionary with follwing items
  
      - "fut_df_sim" : `pandas.DataFrame`
          Row-wise concatenation of dataframes each being the same as
          input dataframe (``fut_df``) with an added column for the response
          and a new column: "sim_label" to differentiate various simulations.
          The row number of the returned dataframe is:
              ``simulation_num`` times the row number of ``fut_df``.
          If ``value_col`` already appears in ``fut_df``, it will be over-written.
      - "x_mat": `pandas.DataFrame`
          ``simulation_num`` copies of design matrix of the predictive machine-learning model
          concatenated. An extra index column ("original_row_index")  is also added
          for aggregation when needed.
          Note that the all copies will be the same except for the case where
          auto-regression is utilized.
code: def simulate_multi(
      self,
      fut_df,
      trained_model,
      simulation_num=10,
      past_df=None,
      new_external_regressor_df=None,
      include_err=None,
  ):
      """A function to simulate future series.
      If the fitted model supports uncertainty e.g. via ``uncertainty_dict``,
      errors are incorporated into the simulations.
  
      Parameters
      ----------
      fut_df : `pandas.DataFrame`
          The data frame which includes the timestamps
          for prediction and any regressors.
      trained_model : `dict`
          A fitted silverkite model which is the output of ``self.forecast``.
      simulation_num : `int`
          The number of simulated series,
          (each of which have the same number of rows as ``fut_df``)
          to be stacked up row-wise. This number must be larger than zero.
      past_df : `pandas.DataFrame`, optional
          A data frame with past values if autoregressive methods are called
          via ``autoreg_dict`` parameter of ``greykite.algo.forecast.silverkite.SilverkiteForecast.py``.
      new_external_regressor_df: `pandas.DataFrame`, optional
          Contains the regressors not already included in ``fut_df``.
      include_err : `bool`, optional, default None
          Boolean to determine if errors are to be incorporated in the simulations.
          If None, it will be set to True if uncertainty is passed to the model and
          otherwise will be set to False.
  
      Returns
      -------
      result: `dict`
          A dictionary with follwing items
  
          - "fut_df_sim" : `pandas.DataFrame`
              Row-wise concatenation of dataframes each being the same as
              input dataframe (``fut_df``) with an added column for the response
              and a new column: "sim_label" to differentiate various simulations.
              The row number of the returned dataframe is:
                  ``simulation_num`` times the row number of ``fut_df``.
              If ``value_col`` already appears in ``fut_df``, it will be over-written.
          - "x_mat": `pandas.DataFrame`
              ``simulation_num`` copies of design matrix of the predictive machine-learning model
              concatenated. An extra index column ("original_row_index")  is also added
              for aggregation when needed.
              Note that the all copies will be the same except for the case where
              auto-regression is utilized.
      """
      assert (
          simulation_num > 0
      ), "simulation number has to be a natural number."
  
      if include_err is None:
          include_err = trained_model["uncertainty_dict"] is not None
  
      if trained_model["uncertainty_dict"] is None and include_err:
          raise ValueError(
              "`include_err=True` was passed. "
              "However model does not support uncertainty. "
              "To support uncertainty pass `uncertainty_dict` to the model."
          )
  
      value_col = trained_model["value_col"]
      fut_df = fut_df.reset_index(
          drop=True
      )  # reset_index returns a copy
  
      fut_df = self.__build_silverkite_features(
          df=fut_df,
          time_col=trained_model["time_col"],
          origin_for_time_vars=trained_model["origin_for_time_vars"],
          daily_event_df_dict=trained_model["daily_event_df_dict"],
          daily_event_neighbor_impact=trained_model[
              "daily_event_neighbor_impact"
          ],
          daily_event_shifted_effect=trained_model[
              "daily_event_shifted_effect"
          ],
          changepoint_values=trained_model["changepoint_values"],
          continuous_time_col=trained_model["continuous_time_col"],
          growth_func=trained_model["growth_func"],
          fs_func=trained_model["fs_func"],
          seasonality_changepoint_result=trained_model[
              "seasonality_changepoint_result"
          ],
          changepoint_dates=trained_model["trend_changepoint_dates"],
      )
  
      if new_external_regressor_df is not None:
          new_external_regressor_df = (
              new_external_regressor_df.reset_index(drop=True)
          )
          fut_df = pd.concat(
              [fut_df, new_external_regressor_df], axis=1
          )
  
      def one_sim_func(label):
          """Creates one simulation and labels it with ``label`` in an added
          column : "sim_label"
          """
          sim_res = self.simulate(
              fut_df=fut_df,
              trained_model=trained_model,
              past_df=past_df,
              new_external_regressor_df=None,
              include_err=include_err,
              time_features_ready=True,
              regressors_ready=True,
          )
          sim_df = sim_res["sim_df"]
          x_mat = sim_res["x_mat"]
          sim_df["sim_label"] = label
          # ``x_mat`` does not necessarily have an index column.
          # We keep track of the original index, to be able to aggregate
          # across simulations later.
          x_mat["original_row_index"] = range(len(fut_df))
  
          return {"sim_df": sim_df, "x_mat": x_mat}
  
      sim_res_list = [one_sim_func(i) for i in range(simulation_num)]
      sim_df_list = [
          sim_res_list[i]["sim_df"] for i in range(simulation_num)
      ]
      x_mat_list = [
          sim_res_list[i]["x_mat"] for i in range(simulation_num)
      ]
  
      sim_df = pd.concat(
          sim_df_list,
          axis=0,
          ignore_index=True,  # The index does not matter as we simply want to stack up the data
          sort=False,
      )
      sim_df[value_col] = sim_df[value_col].astype(float)
  
      x_mat = pd.concat(
          x_mat_list,
          axis=0,
          ignore_index=True,  # The index does not matter as we simply want to stack up the data
          sort=False,
      )
      sim_df[value_col] = sim_df[value_col].astype(float)
  
      assert len(sim_df) == len(fut_df) * simulation_num
      assert len(x_mat) == len(fut_df) * simulation_num
  
      return {"sim_df": sim_df, "x_mat": x_mat}
  
imports: import re
  import warnings
  from typing import Type
  import numpy
  import pandas
  from pandas.plotting import register_matplotlib_converters
  from pandas.tseries.frequencies import to_offset
  from greykite.algo.changepoint.adalasso.changepoint_detector import get_changepoints_dict
  from greykite.algo.changepoint.adalasso.changepoint_detector import get_seasonality_changepoints
  from greykite.algo.changepoint.adalasso.changepoints_utils import build_seasonality_feature_df_from_detection_result
  from greykite.algo.changepoint.adalasso.changepoints_utils import get_seasonality_changepoint_df_cols
  from greykite.algo.common.ml_models import fit_ml_model_with_evaluation
  from greykite.algo.common.ml_models import predict_ml
  from greykite.algo.common.ml_models import predict_ml_with_uncertainty
  from greykite.algo.forecast.silverkite.constants.silverkite_constant import default_silverkite_constant
  from greykite.algo.forecast.silverkite.constants.silverkite_seasonality import SilverkiteSeasonalityEnum
  from greykite.algo.forecast.silverkite.constants.silverkite_seasonality import SilverkiteSeasonalityEnumMixin
  from greykite.algo.forecast.silverkite.forecast_silverkite_helper import get_fourier_feature_col_names
  from greykite.algo.forecast.silverkite.forecast_silverkite_helper import get_similar_lag
  from greykite.common.constants import CHANGEPOINT_COL_PREFIX
  from greykite.common.constants import ERR_STD_COL
  from greykite.common.constants import QUANTILE_SUMMARY_COL
  from greykite.common.constants import SEASONALITY_REGEX
  from greykite.common.constants import TimeFeaturesEnum
  from greykite.common.enums import TimeEnum
  from greykite.common.features.timeseries_features import add_daily_events
  from greykite.common.features.timeseries_features import add_time_features_df
  from greykite.common.features.timeseries_features import fourier_series_multi_fcn
  from greykite.common.features.timeseries_features import get_changepoint_dates_from_changepoints_dict
  from greykite.common.features.timeseries_features import get_changepoint_features
  from greykite.common.features.timeseries_features import get_changepoint_features_and_values_from_config
  from greykite.common.features.timeseries_features import get_default_origin_for_time_vars
  from greykite.common.features.timeseries_lags import build_autoreg_df
  from greykite.common.features.timeseries_lags import build_autoreg_df_multi
  from greykite.common.logging import LoggingLevelEnum
  from greykite.common.logging import log_message
  from greykite.common.python_utils import get_pattern_cols
  from greykite.common.python_utils import unique_elements_in_list
  from greykite.common.time_properties import describe_timeseries
  from greykite.common.time_properties import fill_missing_dates
  from greykite.common.time_properties import min_gap_in_seconds
  from greykite.common.time_properties_forecast import get_default_horizon_from_period
label_desc: Use image node_id 6 for calling the SilverkiteForecast obj's underlying member method code with example usage: obj.simulate_multi(fut_df, trained_model, simulation_num, past_df, new_external_regressor_df, include_err) and returns: dict, dict