code: def normalize_contraction_generic_tuple(
      red_op, bin_op, reduced_vars, terms
  ):
      if not reduced_vars and red_op is not ops.null:
          return Contraction(ops.null, bin_op, reduced_vars, *terms)
  
      if len(terms) == 1 and bin_op is not ops.null:
          return Contraction(red_op, ops.null, reduced_vars, *terms)
  
      if red_op is ops.null and bin_op is ops.null:
          return terms[0]
  
      if red_op is bin_op:
          new_terms = tuple(
              v.reduce(red_op, reduced_vars) for v in terms
          )
          return Contraction(red_op, bin_op, frozenset(), *new_terms)
  
      if bin_op in ops.UNITS and any(
          isinstance(t, Number) and t.data == ops.UNITS[bin_op]
          for t in terms
      ):
          new_terms = tuple(
              t
              for t in terms
              if not (
                  isinstance(t, Number) and t.data == ops.UNITS[bin_op]
              )
          )
          if not new_terms:  # everything was a unit
              new_terms = (terms[0],)
          return Contraction(red_op, bin_op, reduced_vars, *new_terms)
  
      for i, v in enumerate(terms):
          if not isinstance(v, Contraction):
              continue
  
          # fuse operations without distributing
          if (v.red_op is ops.null and bin_op is v.bin_op) or (
              bin_op is ops.null and v.red_op in (red_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,
              )
  
      # nothing more to do, reflect
      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 18 for calling a global function with example usage: normalize_contraction_generic_tuple(red_op, bin_op, reduced_vars, terms) and returns: None, Contraction, Contraction, terms, Contraction, Contraction, Contraction