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: Recursively remove clients of a variable.
  
  This is the main method to remove variables or `Apply` nodes from
  a `FunctionGraph`.
  
  This will remove `var` from the `FunctionGraph` if it doesn't have any
  clients remaining. If it has an owner and all the outputs of the owner
  have no clients, it will also be removed.
  
  Parameters
  ----------
  var
      The clients of `var` that will be removed.
  client_to_remove
      A ``(node, i)`` pair such that ``node.inputs[i]`` will no longer be
      `var` in this `FunctionGraph`.
  remove_if_empty
      When ``True``, if `var`'s `Apply` node is removed, remove the
      entry for `var` in `self.clients`.
docstr_tok: ["Recursively","remove","clients","of","a","variable",".","This","is","the","main","method","to","remove","variables","or","`","Apply","`","nodes","from","a","`","FunctionGraph","`",".","This","will","remove","`","var","`","from","the","`","FunctionGraph","`","if","it","does","n't","have","any","clients","remaining",".","If","it","has","an","owner","and","all","the","outputs","of","the","owner","have","no","clients",",","it","will","also","be","removed",".","Parameters","--","--","--","--","--","var","The","clients","of","`","var","`","that","will","be","removed",".","client_to_remove","A","``","(","node",",","i",")","``","pair","such","that","``","node.inputs","[","i","]","``","will","no","longer","be","`","var","`","in","this","`","FunctionGraph","`",".","remove_if_empty","When","``","True","``",",","if","`","var","`","'s","`","Apply","`","node","is","removed",",","remove","the","entry","for","`","var","`","in","`","self.clients","`","."]
code: def remove_client(
      self,
      var: Variable,
      client_to_remove: ClientType,
      reason: Optional[str] = None,
      remove_if_empty: bool = False,
  ) -> None:
      """Recursively remove clients of a variable.
  
      This is the main method to remove variables or `Apply` nodes from
      a `FunctionGraph`.
  
      This will remove `var` from the `FunctionGraph` if it doesn't have any
      clients remaining. If it has an owner and all the outputs of the owner
      have no clients, it will also be removed.
  
      Parameters
      ----------
      var
          The clients of `var` that will be removed.
      client_to_remove
          A ``(node, i)`` pair such that ``node.inputs[i]`` will no longer be
          `var` in this `FunctionGraph`.
      remove_if_empty
          When ``True``, if `var`'s `Apply` node is removed, remove the
          entry for `var` in `self.clients`.
  
      """
  
      removal_stack = [(var, client_to_remove)]
      while removal_stack:
          var, client_to_remove = removal_stack.pop()
  
          try:
              var_clients = self.clients[var]
              var_clients.remove(client_to_remove)
          except ValueError:
              # In this case, the original `var` could've been removed from
              # the current `var`'s client list before this call.
              # There's nothing inherently wrong with that, so we continue as
              # if it were removed here.
              var_clients = None
  
          if var_clients:
              continue
  
          # Now, `var` has no more clients, so check if we need to remove it
          # and its `Apply` node
          if not var.owner:
              self.variables.remove(var)
          else:
              apply_node = var.owner
              if not any(
                  output
                  for output in apply_node.outputs
                  if self.clients[output]
              ):
                  # The `Apply` node is not used and is not an output, so we
                  # remove it and its outputs
                  if not hasattr(apply_node.tag, "removed_by"):
                      apply_node.tag.removed_by = []
  
                  apply_node.tag.removed_by.append(str(reason))
  
                  self.apply_nodes.remove(apply_node)
  
                  self.variables.difference_update(apply_node.outputs)
  
                  self.execute_callbacks("on_prune", apply_node, reason)
  
                  for i, in_var in enumerate(apply_node.inputs):
                      removal_stack.append((in_var, (apply_node, i)))
  
                  if remove_if_empty:
                      del self.clients[var]
  
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 7 for calling the FunctionGraph obj's underlying member method code with example usage: obj.remove_client(var, client_to_remove, reason, remove_if_empty) without return types