code: def vectorize_graph(
      outputs: Union[Variable, Sequence[Variable]],
      replace: Mapping[Variable, Variable],
  ) -> Union[Variable, Sequence[Variable]]:
      """Vectorize outputs graph given mapping from old variables to expanded counterparts version.
  
      Expanded dimensions must be on the left. Behavior is similar to the functional `numpy.vectorize`.
  
      Examples
      --------
      .. code-block:: python
  
          import pytensor
          import pytensor.tensor as pt
  
          from pytensor.graph import vectorize_graph
  
          # Original graph
          x = pt.vector("x")
          y = pt.exp(x) / pt.sum(pt.exp(x))
  
          # Vectorized graph
          new_x = pt.matrix("new_x")
          new_y = vectorize_graph(y, replace={x: new_x})
  
          fn = pytensor.function([new_x], new_y)
          fn([[0, 1, 2], [2, 1, 0]])
          # array([[0.09003057, 0.24472847, 0.66524096],
          #        [0.66524096, 0.24472847, 0.09003057]])
  
  
      .. code-block:: python
  
          import pytensor
          import pytensor.tensor as pt
  
          from pytensor.graph import vectorize_graph
  
          # Original graph
          x = pt.vector("x")
          y1 = x[0]
          y2 = x[-1]
  
          # Vectorized graph
          new_x = pt.matrix("new_x")
          [new_y1, new_y2] = vectorize_graph([y1, y2], replace={x: new_x})
  
          fn = pytensor.function([new_x], [new_y1, new_y2])
          fn([[-10, 0, 10], [-11, 0, 11]])
          # [array([-10., -11.]), array([10., 11.])]
  
      """
      if isinstance(outputs, Sequence):
          seq_outputs = outputs
      else:
          seq_outputs = [outputs]
  
      inputs = truncated_graph_inputs(
          seq_outputs, ancestors_to_include=replace.keys()
      )
      new_inputs = [replace.get(inp, inp) for inp in inputs]
  
      vect_vars = dict(zip(inputs, new_inputs))
      for node in io_toposort(inputs, seq_outputs):
          vect_inputs = [vect_vars.get(inp, inp) for inp in node.inputs]
          vect_node = vectorize_node(node, *vect_inputs)
          for output, vect_output in zip(
              node.outputs, vect_node.outputs
          ):
              if output in vect_vars:
                  # This can happen when some outputs of a multi-output node are given a replacement,
                  # while some of the remaining outputs are still needed in the graph.
                  # We make sure we don't overwrite the provided replacement with the newly vectorized output
                  continue
              vect_vars[output] = vect_output
  
      seq_vect_outputs = [vect_vars[out] for out in seq_outputs]
  
      if isinstance(outputs, Sequence):
          return seq_vect_outputs
      else:
          [vect_output] = seq_vect_outputs
          return vect_output
  
imports: import warnings
  from collections.abc import Iterable, Mapping, Sequence
  from functools import partial, singledispatch
  from typing import Optional, Union, cast, overload
  from pytensor.graph.basic import Apply, Constant, Variable, io_toposort, truncated_graph_inputs
  from pytensor.graph.fg import FunctionGraph
  from pytensor.graph.op import Op
label_desc: Use image node_id 13 for calling a global function with example usage: vectorize_graph(outputs, replace) and returns: seq_vect_outputs, vect_output