class_docstr: Class for event segmentation of continuous fMRI data
  
  Parameters
  ----------
  n_events: int
      Number of segments to learn
  
  step_var: Callable[[int], float] : default 4 * (0.98 ** (step - 1))
      The Gaussian variance to use during fitting, as a function of the
      number of steps. Should decrease slowly over time.
  
  n_iter: int, default: 500
      Maximum number of steps to run during fitting
  
  event_chains: ndarray with length = n_events
      Array with unique value for each separate chain of events, each linked
      in the order they appear in the array
  
  split_merge: bool, default: False
      Determines whether merge/split proposals are used during fitting with
      fit(). This can improve fitting performance when events are highly
      uneven in size, but requires additional time
  
  split_merge_proposals: int, default: 1
      Number of merges and splits to consider at each step. Computation time
      scales as O(proposals^2) so this should usually be a small value
  
  Attributes
  ----------
  p_start, p_end: length n_events+1 ndarray
      initial and final prior distributions over events
  
  P: n_events+1 by n_events+1 ndarray
      HMM transition matrix
  
  ll_ : ndarray with length = number of training datasets
      Log-likelihood for training datasets over the course of training
  
  segments_:  list of (time by event) ndarrays
      Learned (soft) segmentation for training datasets
  
  event_var_ : float
      Gaussian variance at the end of learning
  
  event_pat_ : voxel by event ndarray
      Learned mean patterns for each event
class_docstr_tok: ["Class","for","event","segmentation","of","continuous","fMRI","data","Parameters","--","--","--","--","--","n_events",":","int","Number","of","segments","to","learn","step_var",":","Callable","[","[","int","]",",","float","]",":","default","4","*","(","0.98","*","*","(","step","-","1",")",")","The","Gaussian","variance","to","use","during","fitting",",","as","a","function","of","the","number","of","steps",".","Should","decrease","slowly","over","time",".","n_iter",":","int",",","default",":","500","Maximum","number","of","steps","to","run","during","fitting","event_chains",":","ndarray","with","length","=","n_events","Array","with","unique","value","for","each","separate","chain","of","events",",","each","linked","in","the","order","they","appear","in","the","array","split_merge",":","bool",",","default",":","False","Determines","whether","merge\/split","proposals","are","used","during","fitting","with","fit","(",")",".","This","can","improve","fitting","performance","when","events","are","highly","uneven","in","size",",","but","requires","additional","time","split_merge_proposals",":","int",",","default",":","1","Number","of","merges","and","splits","to","consider","at","each","step",".","Computation","time","scales","as","O","(","proposals^2",")","so","this","should","usually","be","a","small","value","Attributes","--","--","--","--","--","p_start",",","p_end",":","length","n_events+1","ndarray","initial","and","final","prior","distributions","over","events","P",":","n_events+1","by","n_events+1","ndarray","HMM","transition","matrix","ll_",":","ndarray","with","length","=","number","of","training","datasets","Log-likelihood","for","training","datasets","over","the","course","of","training","segments_",":","list","of","(","time","by","event",")","ndarrays","Learned","(","soft",")","segmentation","for","training","datasets","event_var_",":","float","Gaussian","variance","at","the","end","of","learning","event_pat_",":","voxel","by","event","ndarray","Learned","mean","patterns","for","each","event"]
docstr: Runs forward-backward algorithm on observation log probs
  
  Given the log probability of each timepoint being generated by
  each event, run the HMM forward-backward algorithm to find the
  probability that each timepoint belongs to each event (based on the
  transition priors in p_start, p_end, and P)
  
  See https://en.wikipedia.org/wiki/Forward-backward_algorithm for
  mathematical details
  
  Parameters
  ----------
  logprob : time by event ndarray
      Log probability of each timepoint under each event Gaussian
  
  Returns
  -------
  log_gamma : time by event ndarray
      Log probability of each timepoint belonging to each event
  
  ll : float
      Log-likelihood of fit
docstr_tok: ["Runs","forward-backward","algorithm","on","observation","log","probs","Given","the","log","probability","of","each","timepoint","being","generated","by","each","event",",","run","the","HMM","forward-backward","algorithm","to","find","the","probability","that","each","timepoint","belongs","to","each","event","(","based","on","the","transition","priors","in","p_start",",","p_end",",","and","P",")","See","https",":","\/\/en.wikipedia.org\/wiki\/Forward-backward_algorithm","for","mathematical","details","Parameters","--","--","--","--","--","logprob",":","time","by","event","ndarray","Log","probability","of","each","timepoint","under","each","event","Gaussian","Returns","--","--","--","-","log_gamma",":","time","by","event","ndarray","Log","probability","of","each","timepoint","belonging","to","each","event","ll",":","float","Log-likelihood","of","fit"]
code: def _forward_backward(self, logprob):
      """Runs forward-backward algorithm on observation log probs
  
      Given the log probability of each timepoint being generated by
      each event, run the HMM forward-backward algorithm to find the
      probability that each timepoint belongs to each event (based on the
      transition priors in p_start, p_end, and P)
  
      See https://en.wikipedia.org/wiki/Forward-backward_algorithm for
      mathematical details
  
      Parameters
      ----------
      logprob : time by event ndarray
          Log probability of each timepoint under each event Gaussian
  
      Returns
      -------
      log_gamma : time by event ndarray
          Log probability of each timepoint belonging to each event
  
      ll : float
          Log-likelihood of fit
      """
      logprob = copy.copy(logprob)
      t = logprob.shape[0]
      logprob = np.hstack((logprob, float("-inf") * np.ones((t, 1))))
  
      # Initialize variables
      log_scale = np.zeros(t)
      log_alpha = np.zeros((t, self.n_events + 1))
      log_beta = np.zeros((t, self.n_events + 1))
  
      # Set up transition matrix, with final sink state
      self.p_start = np.zeros(self.n_events + 1)
      self.p_end = np.zeros(self.n_events + 1)
      self.P = np.zeros((self.n_events + 1, self.n_events + 1))
      label_ind = np.unique(self.event_chains, return_inverse=True)[1]
      n_chains = np.max(label_ind) + 1
  
      # For each chain of events, link them together and then to sink state
      for c in range(n_chains):
          chain_ind = np.nonzero(label_ind == c)[0]
          self.p_start[chain_ind[0]] = 1 / n_chains
          self.p_end[chain_ind[-1]] = 1 / n_chains
  
          p_trans = (len(chain_ind) - 1) / t
          if p_trans >= 1:
              raise ValueError("Too few timepoints")
          for i in range(len(chain_ind)):
              self.P[chain_ind[i], chain_ind[i]] = 1 - p_trans
              if i < len(chain_ind) - 1:
                  self.P[chain_ind[i], chain_ind[i + 1]] = p_trans
              else:
                  self.P[chain_ind[i], -1] = p_trans
      self.P[-1, -1] = 1
  
      # Forward pass
      for i in range(t):
          if i == 0:
              log_alpha[0, :] = self._log(self.p_start) + logprob[0, :]
          else:
              log_alpha[i, :] = (
                  self._log(np.exp(log_alpha[i - 1, :]).dot(self.P))
                  + logprob[i, :]
              )
  
          log_scale[i] = np.logaddexp.reduce(log_alpha[i, :])
          log_alpha[i] -= log_scale[i]
  
      # Backward pass
      log_beta[-1, :] = self._log(self.p_end) - log_scale[-1]
      for i in reversed(range(t - 1)):
          obs_weighted = log_beta[i + 1, :] + logprob[i + 1, :]
          offset = np.max(obs_weighted)
          log_beta[i, :] = (
              offset
              + self._log(np.exp(obs_weighted - offset).dot(self.P.T))
              - log_scale[i]
          )
  
      # Combine and normalize
      log_gamma = log_alpha + log_beta
      log_gamma -= np.logaddexp.reduce(log_gamma, axis=1, keepdims=True)
  
      ll = np.sum(log_scale[: (t - 1)]) + np.logaddexp.reduce(
          log_alpha[-1, :] + log_scale[-1] + self._log(self.p_end)
      )
  
      log_gamma = log_gamma[:, :-1]
  
      return log_gamma, ll
  
imports: import numpy
  from scipy import stats
  import logging
  import copy
  from sklearn.base import BaseEstimator
  from sklearn.utils.validation import check_is_fitted, check_array
  from sklearn.exceptions import NotFittedError
  import itertools
  from .None import _utils
label_desc: Use image node_id 6 for calling the EventSegment obj's underlying member method code with example usage: obj._forward_backward(logprob) and returns: log_gamma,  ll