code: def compute_nodes_to_run(
      node_map: OrderedDict[str, node_proto_view.NodeProtoView],
      from_node_ids: Collection[str],
      to_node_ids: Collection[str],
      skip_node_ids: Collection[str],
  ) -> Set[str]:
      """Returns the set of nodes between from_node_ids and to_node_ids."""
      ancestors_of_to_nodes = _traverse(
          node_map, _Direction.UPSTREAM, to_node_ids
      )
      descendents_of_from_nodes = _traverse(
          node_map, _Direction.DOWNSTREAM, from_node_ids
      )
      nodes_considered_to_run = ancestors_of_to_nodes.intersection(
          descendents_of_from_nodes
      )
      nodes_to_run = _traverse(
          node_map,
          _Direction.DOWNSTREAM,
          nodes_considered_to_run - set(skip_node_ids),
      )
      return nodes_considered_to_run.intersection(nodes_to_run)
  
imports: import collections
  import concurrent.futures
  import enum
  from typing import Collection, Dict, Final, List, Mapping, Optional, OrderedDict, Sequence, Set, Tuple
  import uuid
  from absl import logging
  from tfx.dsl.compiler import compiler_utils
  from tfx.dsl.compiler import constants
  from tfx.orchestration import metadata
  from tfx.orchestration import node_proto_view
  from tfx.orchestration.portable import execution_publish_utils
  from tfx.orchestration.portable.mlmd import context_lib
  from tfx.orchestration.portable.mlmd import execution_lib
  from tfx.proto.orchestration import pipeline_pb2
  from ml_metadata.proto import metadata_store_pb2
label_desc: Use image node_id 15 for calling a global function with example usage: compute_nodes_to_run(node_map, from_node_ids, to_node_ids, skip_node_ids) and returns: nodes_considered_to_run