class_docstr: Finish-to-start evaluation order of thunks.
  
  This supports lazy evaluation of subtrees and partial computations of
  graphs when only some inputs have changed.
  
  At a pseudo-code level, the basic idea is as follows:
  
  .. code-block:: python
  
      def recursively_evaluate(var):
          if var is up to date:
              return
          if var.owner.inputs are up to date:
              update var
              return
          for input in var.owner.inputs:
              recursively_evaluate(var)
  
      for output in outputs:
          recursively_evaluate(output)
  
  
  The actual logic is more complex to support intermediate garbage
  collection, lazily-evaluated nodes, and better speed.
class_docstr_tok: ["Finish-to-start","evaluation","order","of","thunks",".","This","supports","lazy","evaluation","of","subtrees","and","partial","computations","of","graphs","when","only","some","inputs","have","changed",".","At","a","pseudo-code","level",",","the","basic","idea","is","as","follows",":","..","code-block",":",":","python","def","recursively_evaluate","(","var",")",":","if","var","is","up","to","date",":","return","if","var.owner.inputs","are","up","to","date",":","update","var","return","for","input","in","var.owner.inputs",":","recursively_evaluate","(","var",")","for","output","in","outputs",":","recursively_evaluate","(","output",")","The","actual","logic","is","more","complex","to","support","intermediate","garbage","collection",",","lazily-evaluated","nodes",",","and","better","speed","."]
docstr: Run the thunk corresponding to Apply instance `node`.
  
  Calls self.callback if it is defined.
docstr_tok: ["Run","the","thunk","corresponding","to","Apply","instance","`","node","`",".","Calls","self.callback","if","it","is","defined","."]
code: def run_thunk_of_node(self, node):
      """
      Run the thunk corresponding to Apply instance `node`.
  
      Calls self.callback if it is defined.
  
      """
      idx = self.node_idx[node]
      t0 = time.perf_counter()
      rval = self.thunks[idx]()
      self.node_executed_order.append(node)
  
      # Some thunks on some computers run faster than the granularity
      # of the time.perf_counter clock.
      # Profile output looks buggy if a node has run but takes 0 time.
      # (and profile code might hide real bugs if it rounds up 0)
      dt = max(time.perf_counter() - t0, 1e-10)
      if self.callback is not None:
          self.callback(
              node=node,
              thunk=self.thunks[idx],
              storage_map=self.storage_map,
              compute_map=self.compute_map,
          )
      return rval, dt
  
imports: import platform
  import sys
  import time
  import warnings
  from abc import ABC, abstractmethod
  from collections import defaultdict
  from collections.abc import Sequence
  from itertools import zip_longest
  from typing import TYPE_CHECKING, Any, Optional
  from pytensor.configdefaults import config
  from pytensor.graph.basic import Apply, Constant, Variable
  from pytensor.link.basic import Container, LocalLinker
  from pytensor.link.c.exceptions import MissingGXX
  from pytensor.link.utils import gc_helper, get_destroy_dependencies, map_storage, raise_with_op
label_desc: Use image node_id 2 for calling the Stack obj's underlying member method code with example usage: obj.run_thunk_of_node(node) and returns: rval,  dt