code: def _resource_based_utilization_scorer(
      node_resources: ResourceDict,
      resources: List[ResourceDict],
      *,
      node_availability_summary: NodeAvailabilitySummary,
  ) -> Optional[Tuple[bool, int, float, float]]:
      remaining = copy.deepcopy(node_resources)
      fittable = []
      resource_types = set()
      for r in resources:
          for k, v in r.items():
              if v > 0:
                  resource_types.add(k)
          if _fits(remaining, r):
              fittable.append(r)
              _inplace_subtract(remaining, r)
      if not fittable:
          return None
  
      util_by_resources = []
      num_matching_resource_types = 0
      for k, v in node_resources.items():
          # Don't divide by zero.
          if v < 1:
              # Could test v == 0 on the nose, but v < 1 feels safer.
              # (Note that node resources are integers.)
              continue
          if k in resource_types:
              num_matching_resource_types += 1
          util = (v - remaining[k]) / v
          util_by_resources.append(v * (util**3))
  
      # Could happen if node_resources has only zero values.
      if not util_by_resources:
          return None
  
      # Prefer not to launch a GPU node if there aren't any GPU requirements in the
      # resource bundle.
      gpu_ok = True
      if AUTOSCALER_CONSERVE_GPU_NODES:
          is_gpu_node = (
              "GPU" in node_resources and node_resources["GPU"] > 0
          )
          any_gpu_task = any("GPU" in r for r in resources)
          if is_gpu_node and not any_gpu_task:
              gpu_ok = False
  
      # Prioritize avoiding gpu nodes for non-gpu workloads first,
      # then prioritize matching multiple resource types,
      # then prioritize using all resources,
      # then prioritize overall balance of multiple resources.
      return (
          gpu_ok,
          num_matching_resource_types,
          min(util_by_resources),
          # util_by_resources should be non empty
          float(sum(util_by_resources)) / len(util_by_resources),
      )
  
imports: import collections
  import copy
  import logging
  import os
  from abc import abstractmethod
  from functools import partial
  from typing import Callable, Dict, List, Optional, Tuple
  import ray
  from ray._private.gcs_utils import PlacementGroupTableData
  from ray.autoscaler._private.constants import AUTOSCALER_CONSERVE_GPU_NODES, AUTOSCALER_UTILIZATION_SCORER_KEY
  from ray.autoscaler._private.loader import load_function_or_class
  from ray.autoscaler._private.node_provider_availability_tracker import NodeAvailabilitySummary
  from ray.autoscaler._private.util import NodeID, NodeIP, NodeType, NodeTypeConfigDict, ResourceDict, is_placement_group_resource
  from ray.autoscaler.node_provider import NodeProvider
  from ray.autoscaler.tags import NODE_KIND_HEAD, NODE_KIND_UNMANAGED, NODE_KIND_WORKER, TAG_RAY_NODE_KIND, TAG_RAY_USER_NODE_TYPE
  from ray.core.generated.common_pb2 import PlacementStrategy
label_desc: Use image node_id 4 for calling a global function with example usage: _resource_based_utilization_scorer(node_resources, resources) and returns: gpu_ok,  num_matching_resource_types,  min,  unknown, None, None