code: def partial_sum_product(
      sum_op,
      prod_op,
      factors,
      eliminate=frozenset(),
      plates=frozenset(),
      pedantic=False,
      pow_op=None,
      plate_to_scale=None,  # dict
  ):
      """
      Performs partial sum-product contraction of a collection of factors.
  
      :return: a list of partially contracted Funsors.
      :rtype: list
      """
      assert callable(sum_op)
      assert callable(prod_op)
      assert isinstance(factors, (tuple, list))
      assert all(isinstance(f, Funsor) for f in factors)
      assert isinstance(eliminate, frozenset)
      assert isinstance(plates, frozenset)
  
      if plate_to_scale:
          if pow_op is None:
              pow_op = PRODUCT_TO_POWER[prod_op]
  
      if pedantic:
          var_to_errors = defaultdict(lambda: eliminate)
          for f in factors:
              ordinal = plates.intersection(f.inputs)
              for var in set(f.inputs) - plates - eliminate:
                  var_to_errors[var] &= ordinal
          for var, errors in var_to_errors.items():
              for plate in errors:
                  raise ValueError(
                      f"Cannot eliminate plate {plate} containing preserved var {var}"
                  )
  
      plates &= eliminate
      sum_vars = eliminate - plates
      var_to_ordinal = {}
      ordinal_to_factors = defaultdict(list)
      for f in factors:
          ordinal = plates.intersection(f.inputs)
          ordinal_to_factors[ordinal].append(f)
          for var in sum_vars.intersection(f.inputs):
              var_to_ordinal[var] = (
                  var_to_ordinal.get(var, ordinal) & ordinal
              )
  
      ordinal_to_vars = defaultdict(set)
      for var, ordinal in var_to_ordinal.items():
          ordinal_to_vars[ordinal].add(var)
  
      results = []
  
      while ordinal_to_factors:
          leaf = max(ordinal_to_factors, key=len)  # CHOICE
          leaf_factors = ordinal_to_factors.pop(leaf)
          leaf_reduce_vars = ordinal_to_vars[leaf]
          for group_factors, group_vars in _partition(
              leaf_factors, leaf_reduce_vars
          ):  # CHOICE
              f = reduce(prod_op, group_factors).reduce(
                  sum_op, group_vars & eliminate
              )
              remaining_sum_vars = sum_vars.intersection(f.inputs)
              if not remaining_sum_vars:
                  f = f.reduce(prod_op, leaf & eliminate)
                  if plate_to_scale:
                      f_scales = [
                          plate_to_scale[plate]
                          for plate in leaf & eliminate
                          if plate in plate_to_scale
                      ]
                      if f_scales:
                          scale = reduce(ops.mul, f_scales)
                          f = pow_op(f, scale)
                  results.append(f)
              else:
                  new_plates = frozenset().union(
                      *(var_to_ordinal[v] for v in remaining_sum_vars)
                  )
                  if new_plates == leaf:
                      # Choose the smallest plate to eliminate.
                      plate = min(
                          (f.inputs[plate].size, plate)
                          for plate in leaf & eliminate
                      )[-1]
                      new_plates = leaf - {plate}
                      plate_shape = (f.inputs[plate].size,)
                      subs = {}
                      for v in remaining_sum_vars:
                          if plate in var_to_ordinal[v]:
                              if f.inputs[v].dtype != "real":
                                  raise ValueError("intractable!")
                              v_ = Variable(
                                  gensym(v),
                                  Reals[
                                      plate_shape + f.inputs[v].shape
                                  ],
                              )
                              v_ordinal = var_to_ordinal[v] - {plate}
                              var_to_ordinal[v_.name] = v_ordinal
                              ordinal_to_vars[v_ordinal].add(v_.name)
                              sum_vars = sum_vars - {v} | {v_.name}
                              eliminate = eliminate - {v} | {v_.name}
                              subs[v] = v_[plate]
                      # This will only work for terms implementing substituting
                      # {var1: ops.getitem(var2, var3)}, e.g. Gaussian but not Tensor.
                      f = f(**subs)
                      for o, gs in list(ordinal_to_factors.items()):
                          if plate not in o:
                              assert all(
                                  set(g.inputs).isdisjoint(subs)
                                  for g in gs
                              )
                              continue  # nothing to do below
                          remaining = []
                          for g in gs:
                              if set(subs).intersection(g.inputs):
                                  g = g(**subs)
                                  assert all(
                                      plate not in var_to_ordinal[u]
                                      for u in g.inputs
                                      if u in sum_vars
                                  )
                                  g = g.reduce(prod_op, plate)
                                  ordinal_to_factors[
                                      o - {plate}
                                  ].append(g)
                              else:
                                  remaining.append(g)
                          ordinal_to_factors[o] = remaining
                  reduced_plates = leaf - new_plates
                  assert reduced_plates.issubset(eliminate)
                  f = f.reduce(prod_op, reduced_plates)
                  if plate_to_scale:
                      f_scales = [
                          plate_to_scale[plate]
                          for plate in reduced_plates
                          if plate in plate_to_scale
                      ]
                      if f_scales:
                          scale = reduce(ops.mul, f_scales)
                          f = pow_op(f, scale)
                  ordinal_to_factors[new_plates].append(f)
  
      return results
  
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 4 for calling a global function with example usage: partial_sum_product(sum_op, prod_op, factors, eliminate, plates, pedantic, pow_op, plate_to_scale) and returns: results