code: def eager_contraction_generic_recursive(
      red_op, bin_op, reduced_vars, terms
  ):
      # Count the number of terms in which each variable is reduced.
      counts = Counter()
      for term in terms:
          counts.update(reduced_vars & term.input_vars)
  
      # push down leaf reductions
      terms = list(terms)
      leaf_reduced = False
      reduced_once = frozenset(
          v for v, count in counts.items() if count == 1
      )
      if reduced_once:
          for i, term in enumerate(terms):
              unique_vars = reduced_once & term.input_vars
              if unique_vars:
                  result = term.reduce(red_op, unique_vars)
                  if result is not normalize.interpret(
                      Contraction,
                      red_op,
                      ops.null,
                      unique_vars,
                      (term,),
                  ):
                      terms[i] = result
                      reduced_vars -= unique_vars
                      leaf_reduced = True
      if leaf_reduced:
          return Contraction(red_op, bin_op, reduced_vars, *terms)
  
      # exploit associativity to recursively evaluate this contraction
      # a bit expensive, but handles interpreter-imposed directionality constraints
      terms = tuple(terms)
      reduced_twice = frozenset(
          v for v, count in counts.items() if count == 2
      )
      for i, lhs in enumerate(terms[0:-1]):
          for j_, rhs in enumerate(terms[i + 1 :]):
              j = i + j_ + 1
              unique_vars = reduced_twice.intersection(
                  lhs.input_vars, rhs.input_vars
              )
              result = Contraction(
                  red_op, bin_op, unique_vars, lhs, rhs
              )
              if result is not normalize.interpret(
                  Contraction, red_op, bin_op, unique_vars, (lhs, rhs)
              ):  # did we make progress?
                  # pick the first evaluable pair
                  reduced_vars -= unique_vars
                  new_terms = (
                      terms[:i]
                      + (result,)
                      + terms[i + 1 : j]
                      + terms[j + 1 :]
                  )
                  return Contraction(
                      red_op, bin_op, reduced_vars, *new_terms
                  )
  
      return None
  
imports: import functools
  import itertools
  from collections import Counter, OrderedDict, defaultdict
  from functools import reduce
  from typing import Tuple, Union
  import opt_einsum
  import funsor
  import funsor.ops
  from funsor.affine import affine_inputs
  from funsor.delta import Delta
  from funsor.domains import find_domain
  from funsor.gaussian import Gaussian
  from funsor.interpretations import eager, normalize, reflect
  from funsor.interpreter import children
  from funsor.ops import DISTRIBUTIVE_OPS, AssociativeOp, NullOp
  from funsor.tensor import Tensor
  from funsor.terms import _INFIX, Align, Binary, Funsor, Number, Reduce, Subs, Unary, Variable, to_funsor
  from funsor.typing import Variadic
  from funsor.util import broadcast_shape, get_backend, quote
label_desc: Use image node_id 5 for calling a global function with example usage: eager_contraction_generic_recursive(red_op, bin_op, reduced_vars, terms) and returns: None, Contraction, Contraction