class_docstr: `FunctionMaker` is the class to `create` `Function` instances.
  
  This class has the fgraph, the rewriter, and the linker. When
  copying a `Function`, there is no need to duplicate the
  `FunctionMaker` instance. Deepcopy still copies both, which can
  variable in re-compilation.
  
  Parameters
  ----------
  inputs : list of SymbolicInput instances
  outputs : list of SymbolicOutput instances
      Outputs may also be a single Variable (not a list), in which case the
      functions produced by FunctionMaker will return their output value
      directly.
  mode : Mode instance
      Telling FunctionMaker how to rewrite and link. None means to use the
      `config.mode`.
  accept_inplace : bool
      True iff it is acceptable to have inplace operations in the graph from
      the inputs to the outputs.
  on_unused_input : {'raise', 'warn', 'ignore', None}
      What to do if a variable in the 'inputs' list is not used in the graph.
      Possible values are:
      - 'raise': raise an error
      - 'warn': log a warning
      - 'ignore': do not do anything
      - None: Use the value in the PyTensor flags on_unused_input.
  name : str
      An optional name for this function. If used, the profile mode will
      print the time spent in this function.
docstr: Create a function.
  
  Parameters
  ----------
  input_storage
      A list matching the inputs list and providing default values if the
      default for an input is None, then that input is a required input.
      For an input with an update, the default acts as initialization.
docstr_tok: ["Create","a","function",".","Parameters","--","--","--","--","--","input_storage","A","list","matching","the","inputs","list","and","providing","default","values","if","the","default","for","an","input","is","None",",","then","that","input","is","a","required","input",".","For","an","input","with","an","update",",","the","default","acts","as","initialization","."]
code: def create(self, input_storage=None, storage_map=None):
      """
      Create a function.
  
      Parameters
      ----------
      input_storage
          A list matching the inputs list and providing default values if the
          default for an input is None, then that input is a required input.
          For an input with an update, the default acts as initialization.
      """
  
      if input_storage is None:
          input_storage = [None] * len(self.inputs)
      # list of independent one-element lists, will be passed to the linker
      input_storage_lists = []
      defaults = []
  
      # The following loop is to fill in the input_storage_lists and
      # defaults lists.
      assert len(self.indices) == len(input_storage)
      for i, (
          (input, indices, subinputs),
          input_storage_i,
      ) in enumerate(zip(self.indices, input_storage)):
          # Replace any default value given as a variable by its
          # container.  Note that this makes sense only in the
          # context of shared variables, but for now we avoid
          # dealing directly with them to avoid dependency on the
          # shared variables work-in-progress repository.
          if isinstance(input_storage_i, Variable):
              input_storage_i = input_storage_i.container
  
          if isinstance(input_storage_i, Container):
              # If the default is a Container, this means we want to
              # share the same storage. This is done by appending
              # input_storage_i.storage to input_storage_lists.
              if indices is not None:
                  raise TypeError(
                      "Cannot take a Container instance as "
                      "default for a SymbolicInputKit."
                  )
              input_storage_lists.append(input_storage_i.storage)
  
              storage = input_storage[i].storage[0]
  
          else:
              # Normal case: one new, independent storage unit
              input_storage_lists.append([input_storage_i])
  
              storage = input_storage_i
  
          required = self.required[i]
          refeed = self.refeed[i]
          # sanity check-- if an input is required it should not
          # need to be refed
          assert not (required and refeed)
  
          # shared variables need neither be input by the user nor refed
          if input.shared:
              assert not required
              assert not refeed
              storage = None
  
          # if an input is required, it never need be refed
          if required:
              storage = None
  
          # make sure that we only store a value if we actually need it
          if storage is not None:
              assert refeed or not required
  
          defaults.append((required, refeed, storage))
  
      # Get a function instance
      start_linker = time.perf_counter()
      start_import_time = pytensor.link.c.cmodule.import_time
  
      with config.change_flags(
          traceback__limit=config.traceback__compile_limit
      ):
          _fn, _i, _o = self.linker.make_thunk(
              input_storage=input_storage_lists, storage_map=storage_map
          )
  
      end_linker = time.perf_counter()
  
      linker_time = end_linker - start_linker
      pytensor.compile.profiling.total_time_linker += linker_time
      _logger.debug(f"Linker took {linker_time:f} seconds")
      if self.profile:
          self.profile.linker_time += linker_time
          _fn.time_thunks = self.profile.flag_time_thunks
          import_time = (
              pytensor.link.c.cmodule.import_time - start_import_time
          )
          self.profile.import_time += import_time
  
      fn = self.function_builder(
          _fn,
          _i,
          _o,
          self.indices,
          self.outputs,
          defaults,
          self.unpack_single,
          self.return_none,
          self.output_keys,
          self,
          name=self.name,
      )
  
      fn.profile = self.profile
      return fn
  
imports: import copy
  import copyreg
  import logging
  import time
  import warnings
  from itertools import chain
  from typing import TYPE_CHECKING, Optional
  import numpy
  import pytensor
  import pytensor.compile.profiling
  from pytensor.compile.io import In, SymbolicInput, SymbolicOutput
  from pytensor.compile.ops import deep_copy_op, view_op
  from pytensor.configdefaults import config
  from pytensor.graph.basic import Constant, Variable, ancestors, clone_get_equiv, graph_inputs
  from pytensor.graph.destroyhandler import DestroyHandler
  from pytensor.graph.features import AlreadyThere, Feature, PreserveVariableAttributes
  from pytensor.graph.fg import FunctionGraph
  from pytensor.graph.op import HasInnerGraph
  from pytensor.graph.utils import InconsistencyError, get_variable_trace_string
  from pytensor.link.basic import Container
  from pytensor.link.utils import raise_with_op
label_desc: Use image node_id 6 for calling the FunctionMaker obj's underlying member method code with example usage: obj.create(input_storage, storage_map) and returns: fn