code: def predict_sequence(self, X, A, pi, inference='smoothing'):
          
          obsll = self.predict_proba(X)
          T, S = obsll.shape
          alpha = np.zeros((T, S))
  
          alpha[0, :] = pi
          for t in range(1, T):
              alpha[t, :] = np.dot(alpha[t-1, :], A)
              for s in range(S):
                  alpha[t, s] *= obsll[t, s]
              alpha[t, :] = alpha[t, :]/sum(alpha[t, :])
  
          if inference == 'filtering':
              return alpha
          else:
              beta = np.zeros((T, S))
              gamma = np.zeros((T, S))
              beta[T-1, :] = np.ones(S)
              for t in range(T-2, -1, -1):
                  for i in range(S):
                      for j in range(S):
                          beta[t, i] += A[i, j]*obsll[t+1, j]*beta[t+1, j]
                  beta[t, :] = beta[t, :]/sum(beta[t, :])
  
              for t in range(T):
                  gamma[t, :] = alpha[t, :]*beta[t, :]
                  gamma[t, :] = gamma[t, :]/sum(gamma[t, :])
  
              return gamma
docs: Calculate class probabilities for a sequence of data.
  
          Parameters
          ----------
          X : array
              Test data, of dimension N times d (rows are time frames, columns
              are data dimensions)
          A : class transition matrix, where A[i,j] contains p(y_t=j|y_{t-1}=i)
          pi : vector of initial class probabilities
          inference : can be 'smoothing' or 'filtering'.
  
          Returns:
          -------
          y_prob : array
              An array of dimension N times n_inlier_classes+1, containing
              the probabilities of each row of X being one of the inlier
              classes, or the outlier class (last column).