code: def partial_unroll(
      factors, eliminate=frozenset(), plate_to_step=dict()
  ):
      """
      Performs partial unrolling of plated factor graphs to standard factor graphs.
      Only plates with history={0, 1} are supported.
  
      For plates (history=0) unrolling operation appends ``_{i}`` suffix
      to variable names for index ``i`` in the plate (e.g., "x"->"x_0" for i=0).
      For markov dimensions (history=1) unrolling operation renames the suffixes
      ``var_prev`` to ``var_{i}`` and ``var_curr`` to ``var_{i+1}`` for index ``i``
      (e.g., "x_prev"->"x_0" and "x_curr"->"x_1" for i=0).
      Markov vars are assumed to have names that follow ``var_suffix`` formatting
      and specifically ``var_0`` for the initial factor (e.g.,
      ``("x_0", "x_prev", "x_curr")`` for history=1).
  
      :param factors: A collection of funsors.
      :type factors: tuple or list
      :param frozenset eliminate: A set of free variables to unroll,
          including both sum variables and product variable.
      :param dict plate_to_step: A dict mapping markov dimensions to
          ``step`` collections that contain ordered sequences of Markov variable names
          (e.g., ``{"time": frozenset({("x_0", "x_prev", "x_curr")})}``).
          Plates are passed with an empty ``step``.
      :return: a list of partially unrolled Funsors,
          a frozenset of partially unrolled variable names,
          and a frozenset of remaining plates.
      """
      assert isinstance(factors, (tuple, list))
      assert all(isinstance(f, Funsor) for f in factors)
      assert isinstance(eliminate, frozenset)
      assert isinstance(plate_to_step, dict)
      assert all(
          len(set(var.split("_")[0] for var in chain)) == 1
          and chain[0].endswith("_0")
          for step in plate_to_step.values()
          if step
          for chain in step
      )
      # process plate_to_step
      plate_to_step = plate_to_step.copy()
      for key, step in plate_to_step.items():
          # make a dict step e.g. {"x_prev": "x_curr"}; specific to history = 1
          plate_to_step[key] = {s[1]: s[2] for s in step}
  
      plates = frozenset(plate_to_step.keys())
      sum_vars = eliminate - plates
      unrolled_plates = {
          k: v for (k, v) in plate_to_step.items() if k in eliminate
      }
      remaining_plates = {
          k: v for (k, v) in plate_to_step.items() if k not in eliminate
      }
  
      var_to_ordinal = {}
      for f in factors:
          ordinal = plates.intersection(f.inputs)
          for var in set(f.inputs) - plates:
              var_to_ordinal[var] = (
                  var_to_ordinal.get(var, ordinal) & ordinal
              )
  
      # first unroll plates with history=1 and highest ordinal
      # then unroll plates with history=0
      plate_to_order = {}
      for plate, step in unrolled_plates.items():
          if step:
              plate_to_order[plate] = max(
                  len(var_to_ordinal[s]) for s in step
              )
          else:
              plate_to_order[plate] = 0
  
      # unroll one plate at a time
      for plate in sorted(
          unrolled_plates.keys(),
          key=lambda p: plate_to_order[p],
          reverse=True,
      ):
          step = unrolled_plates[plate]
          factors, var_to_ordinal, sum_vars = _unroll_plate(
              factors, var_to_ordinal, sum_vars, plate, step
          )
  
      return factors, sum_vars, remaining_plates
  
imports: import re
  from collections import OrderedDict, defaultdict
  from functools import reduce
  from math import gcd
  import funsor
  import funsor.ops
  from funsor.cnf import Contraction
  from funsor.domains import Bint, Reals
  from funsor.interpreter import gensym
  from funsor.ops import PRODUCT_TO_POWER, UNITS, AssociativeOp
  from funsor.terms import Cat, Funsor, FunsorMeta, Number, Slice, Stack, Subs, Variable, eager, substitute, to_funsor
  from funsor.util import quote
label_desc: Use image node_id 3 for calling a global function with example usage: partial_unroll(factors, eliminate, plate_to_step) and returns: factors,  sum_vars,  remaining_plates