class_docstr: Class that satisfies the `Linker` interface by acting as a `VM` factory.
  
  Parameters
  ----------
  allow_gc
      Force the virtual machine to clean up unnecessary references, in order
      to allow garbage collection on intermediate values during computation
      of a function.  If ``None``, use as default the value of the PyTensor
      flag `allow_gc`.
  use_cloop
      Use the C-based virtual machine if possible
  callback
      A callable object to call after each call to a thunk within the virtual
      machine.  It will be called with four arguments: ``node``, ``thunk``,
      ``storage_map``, and ``compute_map``.
  callback_input
      A callable object to call on each input to the graph (variables with no
      owner).  This includes constants and shared variables values.  It will
      be called with two arguments: ``var``, ``value``.
  lazy
      Useful only when `use_cloop` is False. When `lazy` is ``None``, use the
      PyTensor flag ``vm__lazy`` value. Then if we have a ``None`` (default) we
      auto detect if lazy evaluation is needed and use the appropriate
      version. If `lazy` is ``True`` or ``False``, we force the version used
      between `Loop` and `Stack`.
  c_thunks
      If ``None`` or ``True``, don't change the default. If ``False``, don't
      compile C code for the thunks.
  allow_partial_eval
      If ``True``, enforces usage of `Stack` or `CVM`, to allow for partial
      evaluation of functions (calculating a subset of outputs).
class_docstr_tok: ["Class","that","satisfies","the","`","Linker","`","interface","by","acting","as","a","`","VM","`","factory",".","Parameters","--","--","--","--","--","allow_gc","Force","the","virtual","machine","to","clean","up","unnecessary","references",",","in","order","to","allow","garbage","collection","on","intermediate","values","during","computation","of","a","function",".","If","``","None","``",",","use","as","default","the","value","of","the","PyTensor","flag","`","allow_gc","`",".","use_cloop","Use","the","C-based","virtual","machine","if","possible","callback","A","callable","object","to","call","after","each","call","to","a","thunk","within","the","virtual","machine",".","It","will","be","called","with","four","arguments",":","``","node","``",",","``","thunk","``",",","``","storage_map","``",",","and","``","compute_map","``",".","callback_input","A","callable","object","to","call","on","each","input","to","the","graph","(","variables","with","no","owner",")",".","This","includes","constants","and","shared","variables","values",".","It","will","be","called","with","two","arguments",":","``","var","``",",","``","value","``",".","lazy","Useful","only","when","`","use_cloop","`","is","False",".","When","`","lazy","`","is","``","None","``",",","use","the","PyTensor","flag","``","vm__lazy","``","value",".","Then","if","we","have","a","``","None","``","(","default",")","we","auto","detect","if","lazy","evaluation","is","needed","and","use","the","appropriate","version",".","If","`","lazy","`","is","``","True","``","or","``","False","``",",","we","force","the","version","used","between","`","Loop","`","and","`","Stack","`",".","c_thunks","If","``","None","``","or","``","True","``",",","do","n't","change","the","default",".","If","``","False","``",",","don't","compile","C","code","for","the","thunks",".","allow_partial_eval","If","``","True","``",",","enforces","usage","of","`","Stack","`","or","`","CVM","`",",","to","allow","for","partial","evaluation","of","functions","(","calculating","a","subset","of","outputs",")","."]
docstr: Check if fgraph is the first FunctionGraph that has ever been
  associated to self, else, create a new `VMLinker`
  associated to fgraph
  
  Parameters
  ----------
  fgraph
      A PerformLinker can have accepted one FunctionGraph instance
      at a time.
  
  no_recycling
  
      no_recycling is a list of storage (list of 1 element, the
      value corresponding to one variable). Those variable
      storage should not be reused after the call that created
      them.
  
      This happen for example for output of the graph that we
      give to the user. We don't want to reuse those object in
      case the user have kept it.
  
      `VMLinker` make sure this happen by setting the list
      element to None at the start of each call.
  
      Older Linker use not exactly the same mechanism. They will
      also modify the c code to don't look up the value in the
      storage. This cause duplicate c code compilation for the
      same op if they are in the middle of the graph or in the
      no_recycling. We don't want that, so compile all c code
      the same (middle of the graph vs output).
  
      TODO: change the logic to remove the reference at the end
      of the call instead of the start. This will request all VM
      implementation (Loop, Stack, CVM).__call__ to
      return the user outputs as Function.__call__ won't be able
      to find them anymore.
  
  Returns
  -------
  Self if fgraph is the first FunctionGraph that has ever been
  associated to self, else, a new `VMLinker` associated to fgraph.
docstr_tok: ["Check","if","fgraph","is","the","first","FunctionGraph","that","has","ever","been","associated","to","self",",","else",",","create","a","new","`","VMLinker","`","associated","to","fgraph","Parameters","--","--","--","--","--","fgraph","A","PerformLinker","can","have","accepted","one","FunctionGraph","instance","at","a","time",".","no_recycling","no_recycling","is","a","list","of","storage","(","list","of","1","element",",","the","value","corresponding","to","one","variable",")",".","Those","variable","storage","should","not","be","reused","after","the","call","that","created","them",".","This","happen","for","example","for","output","of","the","graph","that","we","give","to","the","user",".","We","do","n't","want","to","reuse","those","object","in","case","the","user","have","kept","it",".","`","VMLinker","`","make","sure","this","happen","by","setting","the","list","element","to","None","at","the","start","of","each","call",".","Older","Linker","use","not","exactly","the","same","mechanism",".","They","will","also","modify","the","c","code","to","do","n't","look","up","the","value","in","the","storage",".","This","cause","duplicate","c","code","compilation","for","the","same","op","if","they","are","in","the","middle","of","the","graph","or","in","the","no_recycling",".","We","do","n't","want","that",",","so","compile","all","c","code","the","same","(","middle","of","the","graph","vs","output",")",".","TODO",":","change","the","logic","to","remove","the","reference","at","the","end","of","the","call","instead","of","the","start",".","This","will","request","all","VM","implementation","(","Loop",",","Stack",",","CVM",")",".__call__","to","return","the","user","outputs","as","Function.__call__","wo","n't","be","able","to","find","them","anymore",".","Returns","--","--","--","-","Self","if","fgraph","is","the","first","FunctionGraph","that","has","ever","been","associated","to","self",",","else",",","a","new","`","VMLinker","`","associated","to","fgraph","."]
code: def accept(self, fgraph, no_recycling=None, profile=None):
      """Check if fgraph is the first FunctionGraph that has ever been
      associated to self, else, create a new `VMLinker`
      associated to fgraph
  
      Parameters
      ----------
      fgraph
          A PerformLinker can have accepted one FunctionGraph instance
          at a time.
  
      no_recycling
  
          no_recycling is a list of storage (list of 1 element, the
          value corresponding to one variable). Those variable
          storage should not be reused after the call that created
          them.
  
          This happen for example for output of the graph that we
          give to the user. We don't want to reuse those object in
          case the user have kept it.
  
          `VMLinker` make sure this happen by setting the list
          element to None at the start of each call.
  
          Older Linker use not exactly the same mechanism. They will
          also modify the c code to don't look up the value in the
          storage. This cause duplicate c code compilation for the
          same op if they are in the middle of the graph or in the
          no_recycling. We don't want that, so compile all c code
          the same (middle of the graph vs output).
  
          TODO: change the logic to remove the reference at the end
          of the call instead of the start. This will request all VM
          implementation (Loop, Stack, CVM).__call__ to
          return the user outputs as Function.__call__ won't be able
          to find them anymore.
  
      Returns
      -------
      Self if fgraph is the first FunctionGraph that has ever been
      associated to self, else, a new `VMLinker` associated to fgraph.
  
      """
      if no_recycling is None:
          no_recycling = []
      if self.fgraph is not None and self.fgraph is not fgraph:
          # Build a new `VMLinker`, and call accept on that one.
          # Warning: make sure to forward the correct values of
          # all parameters to __init__ here.
          return type(self)(
              allow_gc=self.allow_gc,
              use_cloop=self.use_cloop,
              callback=self.callback,
              callback_input=self.callback_input,
              lazy=self.lazy,
              schedule=self.schedule,
              c_thunks=self.c_thunks,
              allow_partial_eval=self.allow_partial_eval,
          ).accept(fgraph, no_recycling, profile)
      self.fgraph = fgraph
      self.no_recycling = no_recycling
      self.profile = profile
  
      return self
  
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 VMLinker obj's underlying member method code with example usage: obj.accept(fgraph, no_recycling, profile) and returns: self, type