class_docstr: Transition model for pattern tracking with a HMM.
  
  Add transitions with the given probability between the individual
  transition models. These transition models must correspond to the state
  spaces forming a :class:`MultiPatternStateSpace`.
  
  Parameters
  ----------
  transition_models : list
      List with :class:`TransitionModel` instances.
  transition_prob : numpy array or float, optional
      Probabilities to change the pattern at pattern boundaries. If an array
      is given, the first dimension corresponds to the origin pattern, the
      second to the destination pattern. If a single value is given, a
      uniform transition distribution to all other patterns is assumed. Set
      to None to stay within the same pattern.
class_docstr_tok: ["Transition","model","for","pattern","tracking","with","a","HMM",".","Add","transitions","with","the","given","probability","between","the","individual","transition","models",".","These","transition","models","must","correspond","to","the","state","spaces","forming","a",":","class",":","`","MultiPatternStateSpace","`",".","Parameters","--","--","--","--","--","transition_models",":","list","List","with",":","class",":","`","TransitionModel","`","instances",".","transition_prob",":","numpy","array","or","float",",","optional","Probabilities","to","change","the","pattern","at","pattern","boundaries",".","If","an","array","is","given",",","the","first","dimension","corresponds","to","the","origin","pattern",",","the","second","to","the","destination","pattern",".","If","a","single","value","is","given",",","a","uniform","transition","distribution","to","all","other","patterns","is","assumed",".","Set","to","None","to","stay","within","the","same","pattern","."]
code: def __init__(self, transition_models, transition_prob=None):
      # save attributes
      self.transition_models = transition_models
      self.transition_prob = transition_prob
      num_patterns = len(transition_models)
      # first stack all transition models
      first_states = []
      last_states = []
      for p, tm in enumerate(self.transition_models):
          # set/update the probabilities, states and pointers
          offset = 0
          if p == 0:
              # for the first pattern, just use the TM arrays
              states = tm.states
              pointers = tm.pointers
              probabilities = tm.probabilities
          else:
              # for all consecutive patterns, stack the TM arrays after
              # applying an offset
              # Note: len(pointers) = len(states) + 1, because of the CSR
              #       format of the TM (please see ml.hmm.TransitionModel)
              offset = len(pointers) - 1
              # states: offset = length of the pointers - 1
              states = np.hstack(
                  (states, tm.states + len(pointers) - 1)
              )
              # pointers: offset = current maximum of the pointers
              #           start = tm.pointers[1:]
              pointers = np.hstack(
                  (pointers, tm.pointers[1:] + max(pointers))
              )
              # probabilities: just stack them
              probabilities = np.hstack(
                  (probabilities, tm.probabilities)
              )
          # save the first/last states
          first_states.append(tm.state_space.first_states[0] + offset)
          last_states.append(tm.state_space.last_states[-1] + offset)
      # retrieve a dense representation in order to add transitions
      # TODO: operate directly on the sparse representation?
      states, prev_states, probabilities = self.make_dense(
          states, pointers, probabilities
      )
      # translate float transition_prob value to transition_prob matrix
      if isinstance(transition_prob, float) and transition_prob:
          # create a pattern transition probability matrix
          self.transition_prob = np.ones((num_patterns, num_patterns))
          # if there is more than 1 pattern, create transitions between them
          if num_patterns > 1:
              # transition to other patterns
              self.transition_prob *= transition_prob / (
                  num_patterns - 1
              )
              # transition to same pattern
              diag = np.diag_indices_from(self.transition_prob)
              self.transition_prob[diag] = 1.0 - transition_prob
      else:
          self.transition_prob = transition_prob
      # update/add transitions between patterns
      if self.transition_prob is not None and num_patterns > 1:
          new_states = []
          new_prev_states = []
          new_probabilities = []
          for p in range(num_patterns):
              # indices of states/prev_states/probabilities
              idx = np.logical_and(
                  np.in1d(prev_states, last_states[p]),
                  np.in1d(states, first_states[p]),
              )
              # transition probability
              prob = probabilities[idx]
              # update transitions to same pattern with new probability
              probabilities[idx] *= self.transition_prob[p, p]
              # distribute that part among all other patterns
              for p_ in np.setdiff1d(range(num_patterns), p):
                  idx_ = np.logical_and(
                      np.in1d(prev_states, last_states[p_]),
                      np.in1d(states, first_states[p_]),
                  )
                  # make sure idx and idx_ have same length
                  if len(np.nonzero(idx)[0]) != len(
                      np.nonzero(idx_)[0]
                  ):
                      raise ValueError(
                          "Cannot add transition between "
                          "patterns with different number of "
                          "entering/exiting states."
                      )
                  # use idx for the states and idx_ for prev_states
                  new_states.extend(states[idx])
                  new_prev_states.extend(prev_states[idx_])
                  new_probabilities.extend(
                      prob * self.transition_prob[p, p_]
                  )
          # extend the arrays by these new transitions
          states = np.append(states, new_states)
          prev_states = np.append(prev_states, new_prev_states)
          probabilities = np.append(probabilities, new_probabilities)
      # make the transitions sparse
      transitions = self.make_sparse(states, prev_states, probabilities)
      # instantiate a TransitionModel
      super(MultiPatternTransitionModel, self).__init__(*transitions)
  
imports: from __future__ import absolute_import, division, print_function
  import numpy
  from madmom.ml.hmm import ObservationModel, TransitionModel
label_desc: Use image node_id 1 to create a new MultiPatternTransitionModel object from inherited base classes: TransitionModel with example: obj = MultiPatternTransitionModel(transition_models, transition_prob)