class_docstr: Base KTR model object with shared functionality for PyroVI method
  Parameters
  ----------
  level_knot_scale : float
      sigma for level; default to be .1
  level_segments : int
      the number of segments partitioned by the knots of level (trend)
  level_knot_distance : int
      the distance between every two knots of level (trend)
  level_knot_dates : array like
      list of pre-specified dates for the level knots
  seasonality : int, or list of int
      multiple seasonality
  seasonality_fs_order : int, or list of int
      fourier series order for seasonality
  seasonality_segments : int
      the number of segments partitioned by the knots of seasonality
  seasonal_initial_knot_scale : float
      scale parameter for seasonal regressors initial coefficient knots; default to be 1
  seasonal_knot_scale : float
      scale parameter for seasonal regressors drift of coefficient knots; default to be 0.1.
  regressor_col : array-like strings
      regressor columns
  regressor_sign : list
      list of signs with '=' for regular regressor, '+' for positive regressor, and '-' for negative regressor.
  regressor_init_knot_loc : list
      list of regressor knot pooling mean priors, default to be 0's
  regressor_init_knot_scale : list
      list of regressor knot pooling sigma's to control the pooling strength towards the grand mean of regressors;
      default to be 1.
  regressor_knot_scale : list
      list of regressor knot sigma priors; default to be 0.1.
  regression_segments : int
      the number of segments partitioned by the knots of regression
  regression_knot_distance : int
      the distance between every two knots of regression
  regression_knot_dates : array-like
      list of pre-specified dates for regression knots
  regression_rho : float
      sigma in the Gaussian kernel for the regression term
  degree of freedom : int
      degree of freedom for error t-distribution
  date_freq : str
      date frequency; if not supplied, pd.infer_freq will be used to imply the date frequency.
  coef_prior_list : list of dicts
      each dict in the list should have keys as
      'name', prior_start_tp_idx' (inclusive), KTRTimePointPriorKeys.PRIOR_END_TP_IDX.value (not inclusive),
      KTRTimePointPriorKeys.PRIOR_MEAN.value, KTRTimePointPriorKeys.PRIOR_SD.value, and KTRTimePointPriorKeys.PRIOR_REGRESSOR_COL.value
  residuals_scale_upper : float
  flat_multiplier : bool
      Default set as True. If False, we will adjust knot scale with a multiplier based on regressor volume
      around each knot; When True, set all multiplier as 1
  ktrlite_optim_args : dict
      the optimizing config for the ktrlite model (to fit level/seasonality). Default to be dict().
class_docstr_tok: ["Base","KTR","model","object","with","shared","functionality","for","PyroVI","method","Parameters","--","--","--","--","--","level_knot_scale",":","float","sigma","for","level",";","default","to","be",".1","level_segments",":","int","the","number","of","segments","partitioned","by","the","knots","of","level","(","trend",")","level_knot_distance",":","int","the","distance","between","every","two","knots","of","level","(","trend",")","level_knot_dates",":","array","like","list","of","pre-specified","dates","for","the","level","knots","seasonality",":","int",",","or","list","of","int","multiple","seasonality","seasonality_fs_order",":","int",",","or","list","of","int","fourier","series","order","for","seasonality","seasonality_segments",":","int","the","number","of","segments","partitioned","by","the","knots","of","seasonality","seasonal_initial_knot_scale",":","float","scale","parameter","for","seasonal","regressors","initial","coefficient","knots",";","default","to","be","1","seasonal_knot_scale",":","float","scale","parameter","for","seasonal","regressors","drift","of","coefficient","knots",";","default","to","be","0.1.","regressor_col",":","array-like","strings","regressor","columns","regressor_sign",":","list","list","of","signs","with","'=","'","for","regular","regressor",",","'+","'","for","positive","regressor",",","and","'-","'","for","negative","regressor",".","regressor_init_knot_loc",":","list","list","of","regressor","knot","pooling","mean","priors",",","default","to","be","0's","regressor_init_knot_scale",":","list","list","of","regressor","knot","pooling","sigma","'s","to","control","the","pooling","strength","towards","the","grand","mean","of","regressors",";","default","to","be","1.","regressor_knot_scale",":","list","list","of","regressor","knot","sigma","priors",";","default","to","be","0.1.","regression_segments",":","int","the","number","of","segments","partitioned","by","the","knots","of","regression","regression_knot_distance",":","int","the","distance","between","every","two","knots","of","regression","regression_knot_dates",":","array-like","list","of","pre-specified","dates","for","regression","knots","regression_rho",":","float","sigma","in","the","Gaussian","kernel","for","the","regression","term","degree","of","freedom",":","int","degree","of","freedom","for","error","t-distribution","date_freq",":","str","date","frequency",";","if","not","supplied",",","pd.infer_freq","will","be","used","to","imply","the","date","frequency",".","coef_prior_list",":","list","of","dicts","each","dict","in","the","list","should","have","keys","as","'name","'",",","prior_start_tp_idx","'","(","inclusive",")",",","KTRTimePointPriorKeys.PRIOR_END_TP_IDX.value","(","not","inclusive",")",",","KTRTimePointPriorKeys.PRIOR_MEAN.value",",","KTRTimePointPriorKeys.PRIOR_SD.value",",","and","KTRTimePointPriorKeys.PRIOR_REGRESSOR_COL.value","residuals_scale_upper",":","float","flat_multiplier",":","bool","Default","set","as","True",".","If","False",",","we","will","adjust","knot","scale","with","a","multiplier","based","on","regressor","volume","around","each","knot",";","When","True",",","set","all","multiplier","as","1","ktrlite_optim_args",":","dict","the","optimizing","config","for","the","ktrlite","model","(","to","fit","level\/seasonality",")",".","Default","to","be","dict","(",")","."]
docstr: internal function to provide coefficient matrix given a date array
  Args
  ----
  posteriors : dict
      posterior samples
  date_array : array like
      array of date stamp
  coefficient_method : str
      either "smooth" or "empirical". when "empirical" is used, curves are sampled/aggregated directly
      from beta posteriors; when "smooth" is used, first extract sampled/aggregated posteriors of knots
      then beta.
      this mainly impacts the aggregated estimation method; full bayesian should not be impacted.
code: def _get_regression_coefs_matrix(
      self,
      training_meta,
      posteriors,
      coefficient_method="smooth",
      date_array=None,
  ):
      """internal function to provide coefficient matrix given a date array
      Args
      ----
      posteriors : dict
          posterior samples
      date_array : array like
          array of date stamp
      coefficient_method : str
          either "smooth" or "empirical". when "empirical" is used, curves are sampled/aggregated directly
          from beta posteriors; when "smooth" is used, first extract sampled/aggregated posteriors of knots
          then beta.
          this mainly impacts the aggregated estimation method; full bayesian should not be impacted.
      """
      num_of_observations = training_meta[
          TrainingMetaKeys.NUM_OF_OBS.value
      ]
      training_start = training_meta[TrainingMetaKeys.START.value]
      training_end = training_meta[TrainingMetaKeys.END.value]
      train_date_array = training_meta[
          TrainingMetaKeys.DATE_ARRAY.value
      ]
  
      if (
          self._num_of_regular_regressors
          + self._num_of_positive_regressors
          + self._num_of_negative_regressors
          == 0
      ):
          return None
  
      # if date_array not specified, coefficients in the training period will be retrieved
      if date_array is None:
          if coefficient_method == "smooth":
              coef_knots = posteriors.get(
                  RegressionSamplingParameters.COEFFICIENTS_KNOT.value
              )
              if len(self._regressor_col) == 1:
                  coef_knots = np.expand_dims(coef_knots, 1)
              # only 1 knot for 0 segments
              if self.regression_segments == 0:
                  coef_knots = np.expand_dims(coef_knots, -1)
  
              # result in batch x time step x regressor size shape
              regressor_betas = np.matmul(
                  coef_knots,
                  self._kernel_coefficients.transpose((1, 0)),
              )
  
              # if len(self._regressor_col) == 1:
              #     regressor_betas = np.expand_dims(regressor_betas, 0)
              regressor_betas = regressor_betas.transpose((0, 2, 1))
          elif coefficient_method == "empirical":
              regressor_betas = posteriors.get(
                  RegressionSamplingParameters.COEFFICIENTS.value
              )
          else:
              raise IllegalArgument(
                  "Wrong coefficient_method:{}".format(
                      coefficient_method
                  )
              )
      else:
          date_array = pd.to_datetime(date_array).values
          output_len = len(date_array)
          train_len = num_of_observations
          # some validation of date array
          if not is_ordered_datetime(date_array):
              raise IllegalArgument(
                  "Datetime index must be ordered and not repeat"
              )
          prediction_start = date_array[0]
  
          if prediction_start < training_start:
              raise PredictionException(
                  "Prediction start must be after training start."
              )
  
          # If we cannot find a match of prediction range, assume prediction starts right after train end
          if prediction_start > training_end:
              # time index for prediction start
              start = train_len
              coef_repeats = [0] * (start - 1) + [output_len]
          else:
              # time index for prediction start
              start = pd.Index(train_date_array).get_loc(
                  prediction_start
              )
              if output_len <= train_len - start:
                  coef_repeats = (
                      [0] * start
                      + [1] * output_len
                      + [0] * (train_len - start - output_len)
                  )
              else:
                  coef_repeats = (
                      [0] * start
                      + [1] * (train_len - start - 1)
                      + [output_len - train_len + start + 1]
                  )
          new_tp = (
              np.arange(start + 1, start + output_len + 1)
              / num_of_observations
          )
  
          if coefficient_method == "smooth":
              kernel_coefficients = gauss_kernel(
                  new_tp,
                  self._knots_tp_coefficients,
                  rho=self.regression_rho,
              )
  
              coef_knots = posteriors.get(
                  RegressionSamplingParameters.COEFFICIENTS_KNOT.value
              )
              if len(self._regressor_col) == 1:
                  coef_knots = np.expand_dims(coef_knots, 1)
              # only 1 knot for 0 segments
              if self.regression_segments == 0:
                  coef_knots = np.expand_dims(coef_knots, -1)
  
              regressor_betas = np.matmul(
                  coef_knots, kernel_coefficients.transpose((1, 0))
              )
              if len(regressor_betas.shape) == 2:
                  regressor_betas = np.expand_dims(regressor_betas, 0)
              regressor_betas = regressor_betas.transpose((0, 2, 1))
          elif coefficient_method == "empirical":
              regressor_betas = posteriors.get(
                  RegressionSamplingParameters.COEFFICIENTS.value
              )
              regressor_betas = np.repeat(
                  regressor_betas, repeats=coef_repeats, axis=1
              )
          else:
              raise IllegalArgument(
                  "Wrong coefficient_method:{}".format(
                      coefficient_method
                  )
              )
  
      return regressor_betas
  
imports: from orbit.models.ktrlite import KTRLite
  import pandas
  import numpy
  import math
  from scipy.stats import nct
  from enum import Enum
  import torch
  import matplotlib.pyplot
  from copy import deepcopy
  from ..constants.constants import KTRTimePointPriorKeys, PredictMethod, TrainingMetaKeys, PredictionMetaKeys
  from ..exceptions import IllegalArgument, ModelException, PredictionException
  from ..utils.general import is_ordered_datetime
  from ..utils.kernels import gauss_kernel, sandwich_kernel
  from ..utils.features import make_seasonal_regressors
  from .model_template import ModelTemplate
  from ..estimators.pyro_estimator import PyroEstimatorSVI
  from ..models import KTRLite
  from orbit.constants.palette import OrbitPalette
  from ..utils.knots import get_knot_idx, get_knot_dates
  from ..utils.plot import orbit_style_decorator
label_desc: Use image node_id 20 for calling the KTRModel obj's underlying member method code with example usage: obj._get_regression_coefs_matrix(training_meta, posteriors, coefficient_method, date_array) and returns: regressor_betas, None