code: def std_fgraph(
      input_specs: list[SymbolicInput],
      output_specs: list[SymbolicOutput],
      accept_inplace: bool = False,
      fgraph: Optional[FunctionGraph] = None,
      features: list[type[Feature]] = [PreserveVariableAttributes],
      force_clone=False,
  ) -> tuple[FunctionGraph, list[SymbolicOutput]]:
      """Make or set up `FunctionGraph` corresponding to the input specs and the output specs.
  
      Any `SymbolicInput` in the `input_specs`, if its `update` field is not
      ``None``, will add an output corresponding to that update to the
      `FunctionGraph`. The return value is the `FunctionGraph` as well as a list
      of `SymbolicOutput` instances corresponding to the updates.
  
      If `accept_inplace` is ``False``, the graph will be checked for in-place
      operations and an exception will be raised if it has any. If
      `accept_inplace` is ``True``, a `DestroyHandler` will be added to the
      `FunctionGraph` if there are any in-place operations.
  
      If `fgraph` is ``None``, the returned `FunctionGraph` is a clone of the
      graph between the provided inputs and outputs.
  
      """
      # Extract the updates and the mapping between update outputs and the
      # updated inputs
      updates = []
      update_mapping = {}
      out_idx = len(output_specs)
      for idx, input_spec in enumerate(input_specs):
          if input_spec.update:
              updates.append(input_spec.update)
              update_mapping[out_idx] = idx
              out_idx += 1
  
      found_updates = []
      if fgraph and fgraph.update_mapping is None:
          fgraph.update_mapping = update_mapping
          for update in updates:
              fgraph.add_output(update, reason="std_fgraph")
  
          found_updates.extend(map(SymbolicOutput, updates))
      elif fgraph is None:
          input_vars = []
  
          # If one of the inputs is non-atomic (i.e. has a non-`None` `Variable.owner`),
          # then we need to create/clone the graph starting at these inputs.
          # The result will be atomic versions of the given inputs connected to
          # the same outputs.
          # Otherwise, when all the inputs are already atomic, there's no need to
          # clone the graph.
          clone = force_clone
          for spec in input_specs:
              input_vars.append(spec.variable)
              clone |= spec.variable.owner is not None
  
          fgraph = FunctionGraph(
              input_vars,
              [spec.variable for spec in output_specs] + updates,
              update_mapping=update_mapping,
              clone=clone,
          )
  
          found_updates.extend(map(SymbolicOutput, updates))
  
      for node in fgraph.apply_nodes:
          if node.op.destroy_map:
              if not accept_inplace:
                  raise TypeError(
                      f"Graph must not contain inplace operations: {node}"
                  )
              else:
                  fgraph.attach_feature(DestroyHandler())
                  break
  
      # We need to protect all immutable inputs from inplace operations.
      fgraph.attach_feature(
          Supervisor(
              input
              for spec, input in zip(input_specs, fgraph.inputs)
              if not (
                  spec.mutable
                  or (
                      hasattr(fgraph, "destroyers")
                      and fgraph.has_destroyers([input])
                  )
              )
          )
      )
  
      # If named nodes are replaced, keep the name
      for feature in features:
          fgraph.attach_feature(feature())
  
      return fgraph, found_updates
  
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 5 for calling a global function with example usage: std_fgraph(input_specs, output_specs, accept_inplace, fgraph, features, force_clone) and returns: fgraph,  found_updates