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 Theano 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 called
      '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
      theano 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/LoopGC 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","Theano","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","called","'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","theano","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\/LoopGC","and","Stack",".","c_thunks","If","None","or","True",",","do","n't","change","the","default",".","If","False",",","do","n'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",")","."]
code: def make_vm(
      self,
      nodes,
      thunks,
      input_storage,
      output_storage,
      storage_map,
      post_thunk_clear,
      computed,
      compute_map,
      updated_vars,
  ):
      pre_call_clear = [storage_map[v] for v in self.no_recycling]
  
      if (
          self.callback is not None
          or self.callback_input is not None
          or (
              (config.profile or config.print_global_stats)
              and config.profile_memory
          )
          or (self.allow_partial_eval and not self.use_cloop)
      ):
          if self.use_cloop and (
              self.callback is not None
              or self.callback_input is not None
          ):
              logger.warn(
                  "CVM does not support callback, using Stack VM."
              )
          if self.use_cloop and config.profile_memory:
              warnings.warn(
                  "CVM does not support memory profile, using Stack VM."
              )
          if not self.use_cloop and self.allow_partial_eval:
              warnings.warn(
                  "LoopGC does not support partial evaluation, "
                  "using Stack VM."
              )
          # Needed for allow_gc=True, profiling and storage_map reuse
          deps = self.compute_gc_dependencies(storage_map)
          vm = Stack(
              nodes,
              thunks,
              pre_call_clear,
              storage_map,
              compute_map,
              self.fgraph,
              self.allow_gc,
              len(updated_vars),
              dependencies=deps,
              callback=self.callback,
              callback_input=self.callback_input,
          )
      elif self.use_cloop:
          # create a map from nodes to ints and vars to ints
          nodes_idx = {}
          vars_idx = {}
          for i, node in enumerate(nodes):
              nodes_idx[node] = i
              for v in node.inputs + node.outputs:
                  vars_idx.setdefault(v, len(vars_idx))
          for v in self.fgraph.inputs + self.fgraph.outputs:
              vars_idx.setdefault(v, len(vars_idx))
  
          nodes_idx_inv = {}
          vars_idx_inv = {}
          for node, i in iteritems(nodes_idx):
              nodes_idx_inv[i] = node
          for var, i in iteritems(vars_idx):
              vars_idx_inv[i] = var
  
          # put storage_map and compute_map into a int-based scheme
          storage_map_list = [
              storage_map[vars_idx_inv[i]]
              for i in xrange(len(vars_idx_inv))
          ]
          compute_map_list = [
              compute_map[vars_idx_inv[i]]
              for i in xrange(len(vars_idx_inv))
          ]
          if nodes:
              assert type(storage_map_list[0]) is list
              assert type(compute_map_list[0]) is list
  
          # Needed for allow_gc=True, profiling and storage_map reuse
          dependency_map = self.compute_gc_dependencies(storage_map)
          dependency_map_list = [
              [vars_idx[d] for d in dependency_map[vars_idx_inv[i]]]
              for i in xrange(len(vars_idx_inv))
          ]
  
          # build the pointers to node inputs and offsets
          base_input_output_list = []
          node_n_inputs = []
          node_n_outputs = []
          node_input_offset = []
          node_output_offset = []
          for node in nodes:
              inputs_idx = [vars_idx[v] for v in node.inputs]
              outputs_idx = [vars_idx[v] for v in node.outputs]
              node_n_inputs.append(len(inputs_idx))
              node_n_outputs.append(len(outputs_idx))
              node_input_offset.append(len(base_input_output_list))
              base_input_output_list.extend(inputs_idx)
              node_output_offset.append(len(base_input_output_list))
              base_input_output_list.extend(outputs_idx)
  
          # build the var owner array
          var_owner = [None] * len(vars_idx)
          for var, i in iteritems(vars_idx):
              if var.owner:
                  var_owner[i] = nodes_idx[var.owner]
  
          is_lazy_list = [int(th.lazy) for th in thunks]
          output_vars = [vars_idx[v] for v in self.fgraph.outputs]
  
          # builds the list of prereqs induced by e.g. destroy_handler
          ords = self.fgraph.orderings()
          node_prereqs = []
          node_output_size = []
          for i, node in enumerate(nodes):
              node_output_size.append(0)
              prereq_var_idxs = []
              for prereq_node in ords.get(node, []):
                  prereq_var_idxs.extend(
                      [vars_idx[v] for v in prereq_node.outputs]
                  )
              prereq_var_idxs = list(set(prereq_var_idxs))
              prereq_var_idxs.sort()  # TODO: why sort?
              node_prereqs.append(prereq_var_idxs)
  
          # Builds the list of input storage to update (according to update
          # rules) when the outputs are computed.
          # They are in the same order as the second part of output_vars
          # (output_vars contains first the returned outputs, then the
          # values of the update expressions).
          update_storage = []
          update_in_from_out = {}
          for ivar, ovar in iteritems(updated_vars):
              update_in_from_out[vars_idx[ovar]] = vars_idx[ivar]
          for oidx in output_vars:
              if oidx in update_in_from_out:
                  update_storage.append(update_in_from_out[oidx])
  
          # PyPy has no sys.getrefcount, so ignore this check if not running
          # under CPython.
          if platform.python_implementation() == "CPython":
              c0 = sys.getrefcount(node_n_inputs)
  
          vm = CVM(
              nodes,
              thunks,
              pre_call_clear,
              allow_gc=self.allow_gc,
              call_counts=[0] * len(nodes),
              call_times=[0.0] * len(nodes),
              compute_map_list=compute_map_list,
              storage_map_list=storage_map_list,
              base_input_output_list=base_input_output_list,
              node_n_inputs=node_n_inputs,
              node_n_outputs=node_n_outputs,
              node_input_offset=node_input_offset,
              node_output_offset=node_output_offset,
              var_owner=var_owner,
              is_lazy_list=is_lazy_list,
              output_vars=output_vars,
              node_prereqs=node_prereqs,
              node_output_size=node_output_size,
              update_storage=update_storage,
              dependencies=dependency_map_list,
          )
  
          if platform.python_implementation() == "CPython":
              assert c0 == sys.getrefcount(node_n_inputs)
      else:
          lazy = self.lazy
          if lazy is None:
              lazy = config.vm.lazy
          if lazy is None:
              lazy = not all([(not th.lazy) for th in thunks])
          if not lazy:
              # there is no conditional in the graph
              if self.allow_gc:
                  vm = LoopGC(
                      nodes,
                      thunks,
                      pre_call_clear,
                      post_thunk_clear,
                  )
              else:
                  vm = Loop(
                      nodes,
                      thunks,
                      pre_call_clear,
                  )
          else:
              # Needed when allow_gc=True and profiling
              deps = self.compute_gc_dependencies(storage_map)
              vm = Stack(
                  nodes,
                  thunks,
                  pre_call_clear,
                  storage_map,
                  compute_map,
                  self.fgraph,
                  self.allow_gc,
                  len(updated_vars),
                  dependencies=deps,
              )
      return vm
  
imports: from __future__ import absolute_import, print_function, division
  from .None import link
  from collections import defaultdict
  import logging
  import sys
  import time
  import warnings
  import platform
  from theano.configparser import config, _config_var_list
  import theano.gof.cmodule
  from six import iteritems, itervalues
  from six.moves import xrange
label_desc: Use image node_id 5 for calling the VM_Linker obj's underlying member method code with example usage: obj.make_vm(nodes, thunks, input_storage, output_storage, storage_map, post_thunk_clear, computed, compute_map, updated_vars) and returns: vm