class_docstr: Declarative representation of a finitary sum-product operation.
  
  After normalization via the :func:`~funsor.terms.normalize` interpretation
  contractions will canonically order their terms by type::
  
      Delta, Number, Tensor, Gaussian
class_docstr_tok: ["Declarative","representation","of","a","finitary","sum-product","operation",".","After","normalization","via","the",":","func",":","`","~funsor.terms.normalize","`","interpretation","contractions","will","canonically","order","their","terms","by","type",":",":","Delta",",","Number",",","Tensor",",","Gaussian"]
code: def __init__(self, red_op, bin_op, reduced_vars, terms):
      terms = (terms,) if isinstance(terms, Funsor) else terms
      assert isinstance(red_op, AssociativeOp)
      assert isinstance(bin_op, AssociativeOp)
      assert all(isinstance(v, Funsor) for v in terms)
      assert isinstance(reduced_vars, frozenset)
      assert all(isinstance(v, Variable) for v in reduced_vars)
      assert isinstance(terms, tuple) and len(terms) > 0
  
      assert not (
          isinstance(red_op, NullOp) and isinstance(bin_op, NullOp)
      )
      if isinstance(red_op, NullOp):
          assert not reduced_vars
      elif isinstance(bin_op, NullOp):
          assert len(terms) == 1
      else:
          assert reduced_vars and len(terms) > 1
          assert (red_op, bin_op) in DISTRIBUTIVE_OPS
  
      fresh = frozenset()
      bound = {v.name: v.output for v in reduced_vars}
      inputs = OrderedDict()
      for v in terms:
          inputs.update(
              (k, d) for k, d in v.inputs.items() if k not in bound
          )
  
      if bin_op is ops.null:
          output = terms[0].output
      else:
          output = reduce(
              lambda lhs, rhs: find_domain(bin_op, lhs, rhs),
              [v.output for v in reversed(terms)],
          )
      super(Contraction, self).__init__(inputs, output, fresh, bound)
      self.red_op = red_op
      self.bin_op = bin_op
      self.terms = terms
      self.reduced_vars = reduced_vars
  
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 1 to create a new Contraction object from inherited base classes: Funsor with example: obj = Contraction(red_op, bin_op, reduced_vars, terms)