class_docstr: Bayesian online change point detection algorithm described by
  `Adams & MacKay (2007) <https://arxiv.org/abs/0710.3742>`__.
  At a high level, this algorithm models the observed data using Bayesian conjugate priors. If an observed value
  deviates too much from the current posterior distribution, it is likely a change point, and we should start
  modeling the time series from that point forwards with a freshly initialized Bayesian conjugate prior.
  
  The ``get_anomaly_score()`` method returns a z-score corresponding to the probability of each point being
  a change point. The ``forecast()`` method returns the predicted values (and standard error) of the underlying
  piecewise model on the relevant data.
class_docstr_tok: ["Bayesian","online","change","point","detection","algorithm","described","by","`","Adams","&","MacKay","(","2007",")","<","https",":","\/\/arxiv.org\/abs\/0710.3742",">","`","__",".","At","a","high","level",",","this","algorithm","models","the","observed","data","using","Bayesian","conjugate","priors",".","If","an","observed","value","deviates","too","much","from","the","current","posterior","distribution",",","it","is","likely","a","change","point",",","and","we","should","start","modeling","the","time","series","from","that","point","forwards","with","a","freshly","initialized","Bayesian","conjugate","prior",".","The","``","get_anomaly_score","(",")","``","method","returns","a","z-score","corresponding","to","the","probability","of","each","point","being","a","change","point",".","The","``","forecast","(",")","``","method","returns","the","predicted","values","(","and","standard","error",")","of","the","underlying","piecewise","model","on","the","relevant","data","."]
code: def _forecast(
      self,
      time_stamps: List[int],
      time_series_prev: pd.DataFrame = None,
      return_prev=False,
  ) -> Tuple[pd.DataFrame, pd.DataFrame]:
      time_stamps = to_pd_datetime(time_stamps)
      if return_prev and time_series_prev is not None:
          time_stamps = time_series_prev.index.union(time_stamps)
  
      # Initialize output accumulators
      pred_full, err_full = None, None
  
      # Split the time stamps based on which model piece should be used
      j = 0
      i = bisect.bisect_left(
          [t0 for t0, model in self.pw_model],
          time_stamps[j],
          hi=len(self.pw_model) - 1,
      )
      for i, (t0, posterior) in enumerate(self.pw_model[i:], i):
          # Stop forecasting if we've finished with all the input timestamps
          if j >= len(time_stamps):
              break
  
          # If this is the last piece, use it to forecast the rest of the timestamps
          if i == len(self.pw_model) - 1:
              pred, err = posterior.forecast(time_stamps[j:])
  
          # Otherwise, predict until the next piece takes over
          else:
              t_next = self.pw_model[i + 1][0]
              j_next = bisect.bisect_left(time_stamps, t_next)
              pred, err = posterior.forecast(time_stamps[j:j_next])
              j = j_next
  
          # Accumulate results
          pred_full = pred if pred_full is None else pred_full + pred
          err_full = err if err_full is None else err_full + err
  
      pred = pred_full.univariates[
          pred_full.names[self.target_seq_index]
      ].to_pd()
      err = err_full.univariates[
          err_full.names[self.target_seq_index]
      ].to_pd()
      pred[pred.isna() | np.isinf(pred)] = 0
      err[err.isna() | np.isinf(err)] = 0
  
      return pd.DataFrame(pred), pd.DataFrame(err)
  
imports: import bisect
  import copy
  from enum import Enum
  import logging
  from typing import List, Tuple, Union
  import warnings
  import numpy
  import pandas
  import scipy.sparse
  from scipy.special import logsumexp
  from scipy.stats import norm
  from tqdm import tqdm
  from merlion.models.anomaly.base import NoCalibrationDetectorConfig, DetectorBase
  from merlion.models.anomaly.forecast_based.base import ForecastingDetectorBase
  from merlion.models.forecast.base import ForecasterConfig
  from merlion.plot import Figure
  from merlion.post_process.threshold import AggregateAlarms
  from merlion.utils.conj_priors import ConjPrior, MVNormInvWishart, BayesianMVLinReg
  from merlion.utils.time_series import TimeSeries, UnivariateTimeSeries, to_pd_datetime
label_desc: Use image node_id 17 for calling the BOCPD obj's underlying member method code with example usage: obj._forecast(time_stamps, time_series_prev, return_prev) and returns: pd,  pd