code: def infer_types_from_signature(program, sig, backend):
      """Infers the variable types of a given program.
  
      Args:
        program: `instructions.Program` whose types to infer.
        sig: A `list` of (patterns of) `instructions.TensorType` aligned with
          `program.vars_in`.
        backend: Backend implementation.
  
      Returns:
        typed: `instructions.Program` with types inferred.
  
      Raises:
        ValueError: If some types still remain incomplete after inference.
      """
      # We start from whatever types are pre-specified (i.e. program counter).
      inferred_types = dict(program.var_defs)
      _merge_vars(program.vars_in, sig, inferred_types, backend)
      log_debug("after inputs: {}".format(inferred_types))
      snapshot = {}
      while snapshot != inferred_types:  # Until stationary, iterate.
          snapshot = dict(inferred_types)
          visited = set()
  
          _process_graph(
              program.graph, visited, inferred_types, backend
          )
      log_debug("after inference: {}".format(inferred_types))
  
      for varname, vm_type in six.iteritems(inferred_types):
          if not _is_determined(vm_type):
              raise ValueError(
                  "Incomplete type inference for variable {}".format(
                      varname
                  )
              )
  
      return program.replace(var_defs=inferred_types)
  
file_path: probability/tensorflow_probability/python/experimental/auto_batching/type_inference.py
imports: import contextlib
  import functools
  from absl import logging
  import six
  from tensorflow_probability.python.experimental.auto_batching import instructions
label_desc: Use image node_id 11 for calling a global function with example usage: infer_types_from_signature(program, sig, backend) and returns: program