code: def gc_helper(node_list: list[Apply]):
      """
      Return the set of Variable instances which are computed by node_list.
      Parameters
      ----------
      node_list
          List of Apply instances in program execution order.
  
      Returns
      -------
      2-tuple
          FIRST, the set of Variable instances which are computed by node_list,
          and SECOND a dictionary that maps each Variable instance to the last
          node to use Variable as an input.
  
      Extended Summary
      ----------------
      This is used to allow garbage collection within graphs.
  
      It ignores view_map and destroy_map. This isn't needed as python
      have reference count. In PyTensor gc, we should not take into
      account view_map and destroy_map as if the thunk decided to create
      a new output, we would delay uselessly its gc by Python.
  
      """
      # for freeing memory
      last_user = {}
      computed = set()
      for node in node_list:
          for input in node.inputs:
              last_user[input] = node
          for output in node.outputs:
              computed.add(output)
      return computed, last_user
  
imports: import builtins
  import io
  import re
  import sys
  import traceback
  import warnings
  from collections import Counter, defaultdict
  from collections.abc import Iterable, Sequence
  from keyword import iskeyword
  from operator import itemgetter
  from tempfile import NamedTemporaryFile
  from textwrap import dedent, indent
  from typing import TYPE_CHECKING, Any, Callable, NoReturn, Optional, TextIO, TypeVar, Union, cast
  import numpy
  from pytensor import config, utils
  from pytensor.graph.basic import Apply, Constant, Variable
  from pytensor.graph.fg import FunctionGraph
label_desc: Use image node_id 3 for calling a global function with example usage: gc_helper(node_list) and returns: computed,  last_user