code: def get_silverkite_uncertainty_dict(
      uncertainty,
      simple_freq=SimpleTimeFrequencyEnum.DAY.name,
      coverage=None,
  ):
      """Returns an uncertainty_dict for
      `~greykite.algo.forecast.silverkite.forecast_silverkite.SilverkiteForecast.forecast`
      input parameter: uncertainty_dict.
  
      The logic is as follows:
  
          - If ``uncertainty`` is passed as dict:
              - If ``quantiles`` are not passed through ``uncertainty`` we fill them
                using `coverage`.
              - If ``coverage`` also missing or quantiles calculated
                in two ways (via ``uncertainty["params"]["quantiles"]`` and ``coverage``)
                do not match, we throw Exceptions
  
          - If ``uncertainty=="auto"``:
              - We provide defaults based on time frequency of data.
              - Specify ``uncertainty["params"]["quantiles"]`` based on
                ``coverage`` if provided, otherwise the default coverage is 0.95.
  
      Parameters
      ----------
      uncertainty : `str` or `dict` or None
          It specifies what method should be used for uncertainty.
          If a dict is passed then it is directly returned to be passed to
          `~greykite.algo.forecast.silverkite.forecast_silverkite.SilverkiteForecast.forecast` as `uncertainty_dict`.
  
          If "auto", it builds a generic dict depending on frequency.
              - For frequencies less than or equal to one day it sets
                `conditional_cols` to be ["dow_hr"].
              - Otherwise it sets the conditional_cols to be `None`
  
          If None and `coverage` is None, the upper/lower predictions are not returned
      simple_freq : `str`, optional
          SimpleTimeFrequencyEnum member that best matches the input data frequency
          according to `get_simple_time_frequency_from_period`
      coverage : `float` or None, optional
          Intended coverage of the prediction bands (0.0 to 1.0)
          If None and `uncertainty` is None, the upper/lower predictions are not returned
  
      Returns
      -------
      uncertainty : `dict` or None
          An uncertainty dict to be used as input to
          `~greykite.algo.forecast.silverkite.forecast_silverkite.SilverkiteForecast.forecast`.
          See that function's docstring for more details.
      """
      frequency = SimpleTimeFrequencyEnum[simple_freq].value
  
      # boolean to determine if freq is longer than one day
      freq_is_longer_than_day = (
          frequency.seconds_per_observation
          > SimpleTimeFrequencyEnum.DAY.value.seconds_per_observation
      )
  
      uncertainty_dict = None
  
      # if both `uncertainty` and `coverage` are None, we return None
      if uncertainty is None and coverage is None:
          return None
  
      # checking if coverage input is sensible
      if coverage is not None and (coverage < 0 or coverage > 1):
          raise ValueError("coverage must be between 0 and 1")
  
      # if only coverage is provided, consider uncertainty to be "auto"
      if coverage is not None and uncertainty is None:
          uncertainty = "auto"
  
      # The case where `uncertainty` is input as a dict
      # We check if quantiles are passed through `uncertainty`
      # If not, we use `coverage` to fill them in
      # If quantiles are passed in `uncertainty` and inferrable from `coverage`:
      # and they are inconsistent, we throw an Exception
      if isinstance(uncertainty, dict):
          uncertainty_dict = uncertainty
          # boolean to check if quantiles are passed through uncertainty
          try:
              quantiles_specified = (
                  uncertainty["params"]["quantiles"] is not None
              )
          except KeyError:
              quantiles_specified = False
          if "params" not in uncertainty_dict:
              uncertainty_dict["params"] = {}
  
          if quantiles_specified:
              quantiles = uncertainty["params"]["quantiles"]
              # If quantiles are specified, we do some sanity checks on their values:
              # We give warnings if more than two quantiles were passed
              # or if they are not symmetric i.e. first quantiles distance to zero
              # is not the same as last quantile distance to 1
              # We throw exceptions if quantiles are not increasing
              # or if `coverage` is also passed and inconsistent with `quantiles`
              if len(quantiles) > 2:
                  warnings.warn(
                      "More than two quantiles are passed in `uncertainty`."
                      " Confidence intervals will be based on"
                      " the first (lower limit) and last (upper limit) quantile",
                      Warning,
                  )
              coverage_via_uncertainty = quantiles[-1] - quantiles[0]
              if coverage_via_uncertainty <= 0:
                  raise ValueError(
                      "`quantiles` is expected to be an increasing sequence"
                      " of at least two elements."
                      f"These quantiles were passed: quantiles = {quantiles}"
                  )
              if round(quantiles[-1], 3) != round(1 - quantiles[0], 3):
                  warnings.warn(
                      "1 - (quantiles upper limit) is not equal to (quantiles lower limit)"
                      " (lack of symmetry)."
                      f" Asymmetric quantiles: {quantiles} were used.",
                      Warning,
                  )
              if coverage is not None:
                  # The case where quantiles are both provided through `uncertainty`
                  # and inferrable using `coverage`
                  # We check for conflict in coverage specification
                  if round(coverage_via_uncertainty, 3) != round(
                      coverage, 3
                  ):
                      raise ValueError(
                          "Coverage is specified/inferred both via `coverage` and via `uncertainty` input"
                          " and values do not match."
                          f" Coverage specified via `coverage`: {round(coverage, 3)}."
                          f" Coverage inferred via `uncertainty`: {round(coverage_via_uncertainty, 2)}."
                      )
          if not quantiles_specified:
              if coverage is None:
                  raise ValueError(
                      "`quantiles` are not specified in `uncertainty`"
                      " and `coverage` is not provided to infer them"
                  )
              else:
                  # The case where quantiles is not provided through `uncertainty`
                  # but coverage is passed
                  q1 = (1 - coverage) / 2
                  q2 = 1 - q1
                  uncertainty_dict["params"]["quantiles"] = [q1, q2]
  
      # The case where `uncertainty` is passed as "auto"
      # The auto case conditions data on `dow_hr` which represents day of week and hour
      # for data with frequency less than or equal to a day (e.g. hourly, daily)
      # note that for daily case this works too as dow_hr will only depend on dow
      if uncertainty == "auto":
          if not freq_is_longer_than_day:
              uncertainty_dict = {
                  "uncertainty_method": "simple_conditional_residuals",
                  "params": {
                      "conditional_cols": [
                          TimeFeaturesEnum.dow_hr.value
                      ],
                      "quantiles": [0.025, 0.975],
                      "quantile_estimation_method": "normal_fit",
                      "sample_size_thresh": 5,
                      "small_sample_size_method": "std_quantiles",
                      "small_sample_size_quantile": 0.98,
                  },
              }
          else:
              uncertainty_dict = {
                  "uncertainty_method": "simple_conditional_residuals",
                  "params": {
                      "conditional_cols": None,
                      "quantiles": [0.025, 0.975],
                      "quantile_estimation_method": "normal_fit",
                      "sample_size_thresh": 5,
                      "small_sample_size_method": "std_quantiles",
                      "small_sample_size_quantile": 0.98,
                  },
              }
          # if coverage is provided the quantiles are overridden in auto
          # we do not give warnings as it is the auto case and
          # user expects using the coverage provided
          if coverage is not None:
              q1 = (1 - coverage) / 2
              q2 = 1 - q1
              uncertainty_dict["params"]["quantiles"] = [q1, q2]
  
      return uncertainty_dict
  
file_path: greykite/greykite/algo/forecast/silverkite/forecast_silverkite_helper.py
imports: import math
  import warnings
  from typing import List
  from typing import Optional
  import pandas
  from greykite.common.constants import TimeFeaturesEnum
  from greykite.common.enums import SimpleTimeFrequencyEnum
  from greykite.common.features.timeseries_features import build_time_features_df
  from greykite.common.features.timeseries_features import get_default_origin_for_time_vars
label_desc: Use image node_id 3 for calling a global function with example usage: get_silverkite_uncertainty_dict(uncertainty, simple_freq, coverage) and returns: uncertainty_dict, None