class_docstr: Normalized delta distribution binding multiple variables.
  
  There are three syntaxes supported for constructing Deltas::
  
      Delta(((name1, (point1, log_density1)),
             (name2, (point2, log_density2)),
             (name3, (point3, log_density3))))
  
  or for a single name::
  
      Delta(name, point, log_density)
  
  or for default ``log_density == 0``::
  
      Delta(name, point)
  
  :param tuple terms: A tuple of tuples of the form
      ``(name, (point, log_density))``.
class_docstr_tok: ["Normalized","delta","distribution","binding","multiple","variables",".","There","are","three","syntaxes","supported","for","constructing","Deltas",":",":","Delta","(","(","(","name1",",","(","point1",",","log_density1",")",")",",","(","name2",",","(","point2",",","log_density2",")",")",",","(","name3",",","(","point3",",","log_density3",")",")",")",")","or","for","a","single","name",":",":","Delta","(","name",",","point",",","log_density",")","or","for","default","``","log_density","==","0","``",":",":","Delta","(","name",",","point",")",":","param","tuple","terms",":","A","tuple","of","tuples","of","the","form","``","(","name",",","(","point",",","log_density",")",")","``","."]
code: def eager_subs(self, subs):
      subs = OrderedDict(subs)
      new_terms = []
      log_densities = []
      for name, (point, log_density) in self.terms:
          if name in subs:
              value = subs[name]
              assert value.output == point.output
              if isinstance(value, Variable):
                  new_terms.append((value.name, (point, log_density)))
                  continue
  
              if not any(
                  d.dtype == "real"
                  for side in (value, point)
                  for d in side.inputs.values()
              ):
                  dtype = get_default_dtype()
                  is_equal = ops.astype((value == point).all(), dtype)
                  log_densities.append(is_equal.log() + log_density)
                  continue
  
              # Try to invert the substitution.
              soln = solve(value, point)
              if soln is None:
                  return None  # lazily substitute
              new_name, new_point, point_log_density = soln
              new_terms.append(
                  (
                      new_name,
                      (new_point, log_density + point_log_density),
                  )
              )
          else:
              new_terms.append((name, (point, log_density)))
  
      if not log_densities:
          return Delta(tuple(new_terms))
      elif not new_terms:
          return reduce(ops.add, log_densities)
      else:
          return Delta(tuple(new_terms)) + reduce(
              ops.add, log_densities
          )
  
imports: from collections import OrderedDict
  from functools import reduce
  from funsor.domains import Domain, Real
  from funsor.instrument import debug_logged
  from funsor.ops import AddOp, SubOp, TransformOp
  from funsor.registry import KeyedRegistry
  from funsor.terms import Align, Binary, Funsor, FunsorMeta, Independent, Lambda, Number, Unary, Variable, eager, to_funsor
  from funsor.util import get_default_dtype
  from .None import ops
label_desc: Use image node_id 3 for calling the Delta obj's underlying member method code with example usage: obj.eager_subs(subs) and returns: Delta, reduce, unknown, None