class_docstr: A abstraction of a node that can be scheduled on by the resource scheduler.
  
  A scheduling node is expected to be used as:
  
      node  = SchedulingNode.from_node_config(node_config)
      remaining, score = node.try_schedule(requests)
  
      .... do something with the score ....
  
  NOTE:
      One could also extend the scheduling behavior by overriding `try_schedule`
class_docstr_tok: ["A","abstraction","of","a","node","that","can","be","scheduled","on","by","the","resource","scheduler",".","A","scheduling","node","is","expected","to","be","used","as",":","node","=","SchedulingNode.from_node_config","(","node_config",")","remaining",",","score","=","node.try_schedule","(","requests",")","....","do","something","with","the","score","....","NOTE",":","One","could","also","extend","the","scheduling","behavior","by","overriding","`","try_schedule","`"]
docstr: Compute the utilization score for this node with respect to the current resource
  request being scheduled.
  
  A "higher" score means that this node is more suitable for scheduling the
  current scheduled resource requests.
  
  The score is a tuple of 4 values:
      1. Whether this node is a GPU node and the current resource request has
          GPU requirements:
              0: if this node is a GPU node and the current resource request
              placed onto the node has no GPU requirements.
              1: if this node is not a GPU node or the current resource request
              placed onto the node has GPU requirements.
      2. The number of resource types being scheduled.
      3. The minimum utilization rate across all resource types.
      4. The average utilization rate across all resource types.
  
  NOTE:
      This function is adapted from  _resource_based_utilization_scorer from
      autoscaler v1.
  
  TODO(rickyx,jjyao):  We should also consider node labels for
      scoring. For example, if a node has a label that matches the affinity
      label of the resource request, we should give it a higher score.
  
  TODO(rickyx): add pluggable scoring functions here.
  
  Returns:
      A utilization score for this node.
docstr_tok: ["Compute","the","utilization","score","for","this","node","with","respect","to","the","current","resource","request","being","scheduled",".","A","``","higher","''","score","means","that","this","node","is","more","suitable","for","scheduling","the","current","scheduled","resource","requests",".","The","score","is","a","tuple","of","4","values",":","1",".","Whether","this","node","is","a","GPU","node","and","the","current","resource","request","has","GPU","requirements",":","0",":","if","this","node","is","a","GPU","node","and","the","current","resource","request","placed","onto","the","node","has","no","GPU","requirements",".","1",":","if","this","node","is","not","a","GPU","node","or","the","current","resource","request","placed","onto","the","node","has","GPU","requirements",".","2",".","The","number","of","resource","types","being","scheduled",".","3",".","The","minimum","utilization","rate","across","all","resource","types",".","4",".","The","average","utilization","rate","across","all","resource","types",".","NOTE",":","This","function","is","adapted","from","_resource_based_utilization_scorer","from","autoscaler","v1",".","TODO","(","rickyx",",","jjyao",")",":","We","should","also","consider","node","labels","for","scoring",".","For","example",",","if","a","node","has","a","label","that","matches","the","affinity","label","of","the","resource","request",",","we","should","give","it","a","higher","score",".","TODO","(","rickyx",")",":","add","pluggable","scoring","functions","here",".","Returns",":","A","utilization","score","for","this","node","."]
code: def _compute_score(self) -> UtilizationScore:
      """
      Compute the utilization score for this node with respect to the current resource
      request being scheduled.
  
      A "higher" score means that this node is more suitable for scheduling the
      current scheduled resource requests.
  
      The score is a tuple of 4 values:
          1. Whether this node is a GPU node and the current resource request has
              GPU requirements:
                  0: if this node is a GPU node and the current resource request
                  placed onto the node has no GPU requirements.
                  1: if this node is not a GPU node or the current resource request
                  placed onto the node has GPU requirements.
          2. The number of resource types being scheduled.
          3. The minimum utilization rate across all resource types.
          4. The average utilization rate across all resource types.
  
      NOTE:
          This function is adapted from  _resource_based_utilization_scorer from
          autoscaler v1.
  
      TODO(rickyx,jjyao):  We should also consider node labels for
          scoring. For example, if a node has a label that matches the affinity
          label of the resource request, we should give it a higher score.
  
      TODO(rickyx): add pluggable scoring functions here.
  
      Returns:
          A utilization score for this node.
      """
      pass
  
imports: import copy
  import logging
  from abc import ABC, abstractmethod
  from collections import defaultdict
  from dataclasses import dataclass, field
  from enum import Enum
  from typing import Dict, List, Optional, Tuple
  from google.protobuf.json_format import MessageToDict
  from ray.autoscaler._private.resource_demand_scheduler import UtilizationScore
  from ray.autoscaler.v2.instance_manager.config import NodeTypeConfig
  from ray.autoscaler.v2.schema import NodeType
  from ray.autoscaler.v2.utils import is_pending, resource_requests_by_count
  from ray.core.generated.autoscaler_pb2 import ClusterResourceConstraint, GangResourceRequest, NodeState, ResourceRequest, ResourceRequestByCount
  from ray.core.generated.instance_manager_pb2 import Instance
label_desc: Use image node_id 3 for calling the SchedulingNode obj's underlying member method code with example usage: obj._compute_score() without return types