code: def unfold_contraction_generic_tuple(
      red_op, bin_op, reduced_vars, terms
  ):
      for i, v in enumerate(terms):
          if not isinstance(v, Contraction):
              continue
  
          if (
              v.red_op is ops.null
              and (v.bin_op, bin_op) in DISTRIBUTIVE_OPS
          ):
              # a * e * (b + c + d) -> (a * e * b) + (a * e * c) + (a * e * d)
              new_terms = tuple(
                  Contraction(
                      v.red_op,
                      bin_op,
                      v.reduced_vars,
                      *(terms[:i] + (vt,) + terms[i + 1 :]),
                  )
                  for vt in v.terms
              )
              return Contraction(
                  red_op, v.bin_op, reduced_vars, *new_terms
              )
  
          if (
              red_op in (v.red_op, ops.null)
              and (v.red_op, bin_op) in DISTRIBUTIVE_OPS
          ):
              new_terms = (
                  terms[:i]
                  + (
                      Contraction(
                          v.red_op, v.bin_op, frozenset(), *v.terms
                      ),
                  )
                  + terms[i + 1 :]
              )
              return Contraction(
                  v.red_op, bin_op, v.reduced_vars, *new_terms
              ).reduce(red_op, reduced_vars)
  
          if v.red_op in (red_op, ops.null) and bin_op in (
              v.bin_op,
              ops.null,
          ):
              red_op = v.red_op if red_op is ops.null else red_op
              bin_op = v.bin_op if bin_op is ops.null else bin_op
              new_terms = terms[:i] + v.terms + terms[i + 1 :]
              return Contraction(
                  red_op,
                  bin_op,
                  reduced_vars | v.reduced_vars,
                  *new_terms,
              )
  
      return None
  
file_path: funsor/funsor/optimizer.py
imports: import collections
  from opt_einsum.paths import greedy
  import funsor.interpreter
  from funsor.cnf import Contraction
  from funsor.interpretations import DispatchedInterpretation, PrioritizedInterpretation, eager, lazy, normalize_base
  from funsor.interpreter import get_interpretation
  from funsor.ops import DISTRIBUTIVE_OPS, AssociativeOp
  from funsor.terms import Funsor
  from funsor.typing import Variadic
  from .None import ops
label_desc: Use image node_id 1 for calling a global function with example usage: unfold_contraction_generic_tuple(red_op, bin_op, reduced_vars, terms) and returns: None, Contraction, Contraction, Contraction