code: def map_variables(replacer, graphs, additional_inputs=[]):
      """Construct new graphs based on 'graphs' with some variables replaced
      according to 'replacer'.
  
      :param replacer: function that takes a variable and returns its
           replacement.
      :param graphs: an iterable of graphs in which to replace variables
      :param additional_inputs: an iterable of graph inputs not used in any
           of 'graphs' but possibly used in the graphs returned by `replacer`
      :return: the new graphs, in the same order as 'graphs'
  
      Example:
  
      .. code-block:: python
  
          tag = "replaceme"
  
          a = tensor.scalar("a")
          b = tensor.scalar("b")
          c = tensor.scalar("c")
  
          ab = a + b
          ab.tag.replacement = a * b
  
          u = ab + c
          v, = map_variables(lambda graph:
              return getattr(graph.tag, "replacement", graph),
              [u])
  
          # v is now equal to a * b + c
      """
  
      # wrap replacer to avoid replacing things we just put there.
      graphs_seen = set()
  
      def wrapped_replacer(graph):
          if graph in graphs_seen:
              return graph
          else:
              new_graph = replacer(graph)
              graphs_seen.add(new_graph)
              return new_graph
  
      graphs = list(graphs)
      inputs_ = list(
          set(gof.graph.inputs(graphs) + list(additional_inputs))
      )
  
      # perform any desired replacement of input variables.  these
      # aren't replaced by the local optimizer approach because they are
      # not outputs of any Apply node.
      new_inputs = list(map(wrapped_replacer, inputs_))
      replacements = [
          (input_, new_input)
          for input_, new_input in zip(inputs_, new_inputs)
          if new_input is not input_
      ]
      graphs = clone(graphs, share_inputs=True, replace=replacements)
      inputs_ = list(
          set(gof.graph.inputs(graphs) + list(additional_inputs))
      )
  
      # clone cached constants or FunctionGraph will complain.  this has
      # to occur in a separate pass from the replacement above because
      # both may suggest different replacements for the same variables.
      # since the replacements introduced above may involve cached
      # constants, the replacement of said constants has to come after.
      cached_constants = [
          x for x in inputs_ if getattr(x, "cached", False)
      ]
      copied_constants = clone(cached_constants, share_inputs=False)
      replacements = list(zip(cached_constants, copied_constants))
      inputs_ = list(set(inputs_) - set(cached_constants)) + list(
          copied_constants
      )
      graphs = clone(graphs, share_inputs=True, replace=replacements)
  
      fg = gof.fg.FunctionGraph(inputs_, graphs, clone=False)
  
      nodes_seen = set()
  
      @gof.opt.local_optimizer(None)
      def local_transform(node):
          if node in nodes_seen:
              return False
  
          # importing Scan into module scope would be circular
          from theano.scan_module.scan_op import Scan
          from theano.compile import OpFromGraph
  
          if isinstance(node.op, (Scan, OpFromGraph)):
              # recurse on the inner graph
              (
                  new_inner_inputs,
                  new_outer_inputs,
                  new_inner_outputs,
              ) = _map_variables_inner(
                  wrapped_replacer,
                  inner_inputs=node.op.inputs,
                  outer_inputs=node.inputs,
                  inner_outputs=node.op.outputs,
                  containing_op=node.op,
              )
              # reinstantiate the op
              if isinstance(node.op, Scan):
                  new_op = Scan(
                      new_inner_inputs,
                      new_inner_outputs,
                      node.op.info,
                      # FIXME: infer this someday?
                      typeConstructor=None,
                  )
              elif isinstance(node.op, OpFromGraph):
                  new_op = OpFromGraph(
                      new_inner_inputs,
                      new_inner_outputs,
                      **node.op.kwargs,
                  )
              # make a new node to replace the old one
              new_node = new_op.make_node(*new_outer_inputs)
              nodes_seen.add(new_node)
              return new_node.outputs
          else:
              nodes_seen.add(node)
              return list(map(wrapped_replacer, node.outputs))
  
      topo_transform = gof.opt.TopoOptimizer(
          local_transform, "out_to_in"
      )
      topo_transform.optimize(fg)
  
      new_graphs = fg.outputs
      fg.disown()
      return new_graphs
  
imports: from __future__ import absolute_import, print_function, division
  import copy
  import logging
  import warnings
  from collections import OrderedDict
  import numpy
  import theano
  from theano.compat import izip
  from six import string_types, iteritems
  from six.moves import xrange
  from theano.compile.pfunc import rebuild_collect_shared
  from theano import gof, compat
  from theano import tensor, scalar
  from theano.tensor.basic import get_scalar_constant_value
label_desc: Use image node_id 5 for calling a global function with example usage: map_variables(replacer, graphs, additional_inputs) and returns: new_graphs, graph, new_graph, False, new_node, list