code: def construct_nominal_fgraph(
      inputs: Sequence[Variable], outputs: Sequence[Variable]
  ) -> tuple[
      FunctionGraph,
      Sequence[Variable],
      dict[Variable, Variable],
      dict[Variable, Variable],
  ]:
      """Construct an inner-`FunctionGraph` with ordered nominal inputs."""
      dummy_inputs = []
      for n, inp in enumerate(inputs):
          if (
              not isinstance(inp, Variable)
              or isinstance(inp, Constant)
              or isinstance(inp, SharedVariable)
          ):
              raise TypeError(
                  f"Inputs and outputs must be non-Constant/shared Variable instances; got {inp}"
              )
  
          dummy_inputs.append(inp.type())
  
      dummy_shared_inputs = []
      shared_inputs = []
      for var in graph_inputs(outputs, inputs):
          if isinstance(var, SharedVariable):
              # To correctly support shared variables the inner-graph should
              # not see them; otherwise, there will be problems with
              # gradients.
              # That's why we collect the shared variables and replace them
              # with dummies.
              shared_inputs.append(var)
              dummy_shared_inputs.append(var.type())
          elif var not in inputs and not isinstance(var, Constant):
              raise MissingInputError(
                  f"OpFromGraph is missing an input: {var}"
              )
  
      replacements = dict(
          zip(
              inputs + shared_inputs, dummy_inputs + dummy_shared_inputs
          )
      )
  
      new = rebuild_collect_shared(
          cast(Sequence[Variable], outputs),
          inputs=inputs + shared_inputs,
          replace=replacements,
          copy_inputs_over=False,
      )
      (
          local_inputs,
          local_outputs,
          (clone_d, update_d, update_expr, new_shared_inputs),
      ) = new
  
      assert len(local_inputs) == len(inputs) + len(shared_inputs)
      assert len(local_outputs) == len(outputs)
      assert not update_d
      assert not update_expr
      assert not new_shared_inputs
  
      fgraph = FunctionGraph(local_inputs, local_outputs, clone=False)
  
      # The inputs need to be `NominalVariable`s so that we can merge
      # inner-graphs
      nominal_local_inputs = tuple(
          NominalVariable(n, var.type)
          for n, var in enumerate(local_inputs)
      )
  
      fgraph.replace_all(zip(local_inputs, nominal_local_inputs))
  
      for i, inp in enumerate(fgraph.inputs):
          nom_inp = nominal_local_inputs[i]
          fgraph.inputs[i] = nom_inp
          fgraph.clients.pop(inp, None)
          fgraph.add_input(nom_inp)
  
      return fgraph, shared_inputs, update_d, update_expr
  
imports: from collections import OrderedDict
  from collections.abc import Sequence
  from copy import copy
  from functools import partial
  from typing import Optional, cast
  import pytensor.tensor
  from pytensor import function
  from pytensor.compile.function.pfunc import rebuild_collect_shared
  from pytensor.compile.mode import optdb
  from pytensor.compile.sharedvalue import SharedVariable
  from pytensor.configdefaults import config
  from pytensor.gradient import DisconnectedType, Rop, grad
  from pytensor.graph.basic import Apply, Constant, NominalVariable, Variable, graph_inputs, io_connection_pattern
  from pytensor.graph.fg import FunctionGraph
  from pytensor.graph.null_type import NullType
  from pytensor.graph.op import HasInnerGraph, Op
  from pytensor.graph.replace import clone_replace
  from pytensor.graph.rewriting.basic import in2out, node_rewriter
  from pytensor.graph.utils import MissingInputError
  from pytensor.tensor.rewriting.shape import ShapeFeature
label_desc: Use image node_id 2 for calling a global function with example usage: construct_nominal_fgraph(inputs, outputs) and returns: fgraph,  shared_inputs,  update_d,  update_expr