class_docstr: A `FunctionGraph` represents a subgraph bound by a set of input variables and
  a set of output variables, ie a subgraph that specifies an PyTensor function.
  The inputs list should contain all the inputs on which the outputs depend.
  `Variable`\s of type `Constant` are not counted as inputs.
  
  The `FunctionGraph` supports the replace operation which allows to replace
  a variable in the subgraph by another, e.g. replace ``(x + x).out`` by
  ``(2 * x).out``. This is the basis for optimization in PyTensor.
  
  This class is also responsible for verifying that a graph is valid
  (ie, all the dtypes and broadcast patterns are compatible with the
  way the `Variable`\s are used) and for tracking the `Variable`\s with
  a :attr:`FunctionGraph.clients` ``dict`` that specifies which `Apply` nodes
  use the `Variable`.  The :attr:`FunctionGraph.clients` field, combined with
  the :attr:`Variable.owner` and each :attr:`Apply.inputs`, allows the graph
  to be traversed in both directions.
  
  It can also be extended with new features using
  :meth:`FunctionGraph.attach_feature`.  See `Feature` for event types and
  documentation.  Extra features allow the `FunctionGraph` to verify new
  properties of a graph as it is optimized.
  
  The constructor creates a `FunctionGraph` which operates on the subgraph
  bound by the inputs and outputs sets.
  
  This class keeps lists for the inputs and outputs and modifies them
  in-place.
docstr: Check the integrity of nodes in the graph.
docstr_tok: ["Check","the","integrity","of","nodes","in","the","graph","."]
code: def check_integrity(self) -> None:
      """Check the integrity of nodes in the graph."""
      nodes = set(applys_between(self.inputs, self.outputs))
      if self.apply_nodes != nodes:
          nodes_missing = nodes.difference(self.apply_nodes)
          nodes_excess = self.apply_nodes.difference(nodes)
          raise Exception(
              f"The following nodes are inappropriately cached:\nmissing: {nodes_missing}\nin excess: {nodes_excess}"
          )
      for node in nodes:
          for i, variable in enumerate(node.inputs):
              clients = self.clients[variable]
              if (node, i) not in clients:
                  raise Exception(
                      f"Inconsistent clients list {(node, i)} in {clients}"
                  )
      variables = set(vars_between(self.inputs, self.outputs))
      if set(self.variables) != variables:
          vars_missing = variables.difference(self.variables)
          vars_excess = self.variables.difference(variables)
          raise Exception(
              f"The following variables are inappropriately cached:\nmissing: {vars_missing}\nin excess: {vars_excess}"
          )
      for variable in variables:
          if (
              variable.owner is None
              and variable not in self.inputs
              and not isinstance(variable, AtomicVariable)
          ):
              raise Exception(f"Undeclared input: {variable}")
          for cl_node, i in self.clients[variable]:
              if cl_node == "output":
                  if self.outputs[i] is not variable:
                      raise Exception(
                          f"Inconsistent clients list: {variable}, {self.outputs[i]}"
                      )
                  continue
  
              assert isinstance(cl_node, Apply)
  
              if cl_node not in nodes:
                  raise Exception(
                      f"Client not in FunctionGraph: {variable}, {(cl_node, i)}"
                  )
              if cl_node.inputs[i] is not variable:
                  raise Exception(
                      f"Inconsistent clients list: {variable}, {cl_node.inputs[i]}"
                  )
  
imports: import time
  from collections import OrderedDict
  from collections.abc import Iterable, Sequence
  from typing import TYPE_CHECKING, Any, Literal, Optional, Union, cast
  import pytensor
  from pytensor.configdefaults import config
  from pytensor.graph.basic import Apply, AtomicVariable, Variable, applys_between, clone_get_equiv, graph_inputs, io_toposort, vars_between
  from pytensor.graph.basic import as_string
  from pytensor.graph.features import AlreadyThere, Feature, ReplaceValidate
  from pytensor.graph.utils import MetaObject, MissingInputError, TestValueError
  from pytensor.misc.ordered_set import OrderedSet
label_desc: Use image node_id 23 for calling the FunctionGraph obj's underlying member method code with example usage: obj.check_integrity() without return types