code: def forward_algorithm(
      factors: List[Funsor],
      step: Dict[str, str],
  ) -> Tuple[Funsor, List[Funsor]]:
      """
      Calculate log marginal probability using the forward algorithm:
      Z = p(y[0:T])
  
      Transition and emission probabilities are given by init and trans factors:
      init = p(y[0], x[0])
      trans[t] = p(y[t], x[t] | x[t-1])
  
      Forward probabilities are computed inductively:
      alpha[t] = p(y[0:t], x[t])
      alpha[0] = init
      alpha[t+1] = alpha[t] @ trans[t+1]
      """
      step = OrderedDict(sorted(step.items()))
      drop = tuple("_drop_{}".format(i) for i in range(len(step)))
      prev_to_drop = dict(zip(step.keys(), drop))
      curr_to_drop = dict(zip(step.values(), drop))
      reduce_vars = frozenset(drop)
  
      # base case
      alpha = factors[0]
      alphas = [alpha]
      # inductive steps
      for trans in factors[1:]:
          alpha = (
              alpha(**curr_to_drop) + trans(**prev_to_drop)
          ).reduce(ops.logaddexp, reduce_vars)
          alphas.append(alpha)
      else:
          Z = alpha(**curr_to_drop).reduce(ops.logaddexp, reduce_vars)
      return Z
  
file_path: funsor/examples/forward_backward.py
imports: import argparse
  from collections import OrderedDict
  from typing import Dict, List, Tuple
  import funsor.ops
  from funsor import Funsor, Tensor
  from funsor.adjoint import AdjointTape
  from funsor.domains import Bint
  from funsor.testing import assert_close, random_tensor
label_desc: Use image node_id 1 for calling a global function with example usage: forward_algorithm(factors, step) and returns: Z