
    &`i`                     P   d Z ddlZddlZddlZddlZddlmZ ddlmZ ddl	m
Z
mZmZmZmZ ddlZddlmZ ddlmZmZmZ ddlmZ dd	lmZ dd
lmZmZmZmZmZm Z  ddl!m"Z" ddl#m$Z$m%Z%m&Z&m'Z'm(Z( ddl)m*Z*  ej+        e,          Z-eZ.ee         Z/ G d d          Z0 G d d          Z1 G d d          Z2deeef         deee3f         dee         fdZ4dee         deee3f         deeef         de3dedee         de
e.e/e5gee0         f         dee         eee3f         eee3f         ffdZ6	 d2deeef         deee3f         ded e3d!ee         de
e.e/e5gee0         f         d"e7deee3f         ee         ffd#Z8ded!ee         d$edeee7e3e9e9f                  fd%Z:ded!ee         d&e5d$efd'Z;	 d2dee         d(ee         d"e7dee         ee         ffd)Z<d*ed!ede7fd+Z=d*ed!eddfd,Z>d-ej?        d.eddfd/Z@d0ee         deee         eee                  f         fd1ZAdS )3au  Implements multi-node-type autoscaling.

This file implements an autoscaling algorithm that is aware of multiple node
types (e.g., example-multi-node-type.yaml). The Ray autoscaler will pass in
a vector of resource shape demands, and the resource demand scheduler will
return a list of node types that can satisfy the demands given constraints
(i.e., reverse bin packing).
    N)abstractmethod)partial)CallableDictListOptionalTuple)PlacementGroupTableData)AUTOSCALER_CONSERVE_GPU_NODES&AUTOSCALER_UPSCALING_INITIAL_NUM_NODES!AUTOSCALER_UTILIZATION_SCORER_KEY)load_function_or_class)NodeAvailabilitySummary)NodeIDNodeIPNodeTypeNodeTypeConfigDictResourceDictis_placement_group_resource)NodeProvider)NODE_KIND_HEADNODE_KIND_UNMANAGEDNODE_KIND_WORKERTAG_RAY_NODE_KINDTAG_RAY_USER_NODE_TYPE)PlacementStrategyc                       e Zd ZdZedd defd            Zedd dd defd            Zdd dd defdZdd dd defdZ	dd dd defd	Z
d
S )UtilizationScorea  This fancy class just defines the `UtilizationScore` protocol to be
    some type that is a "totally ordered set" (i.e. things that can be sorted).

    What we're really trying to express is

    ```
    UtilizationScore = TypeVar("UtilizationScore", bound=Comparable["UtilizationScore"])
    ```

    but Comparable isn't a real type and, and a bound with a type argument
    can't be enforced (f-bounded polymorphism with contravariance). See Guido's
    comment for more details: https://github.com/python/typing/issues/59.

    This isn't just a `float`. In the case of the default scorer, it's a
    `Tuple[float, float]` which is quite difficult to map to a single number.

    otherreturnc                     d S N selfr   s     /home/jaya/work/projects/VOICE-AGENT/VIET/agent-env/lib/python3.11/site-packages/ray/autoscaler/_private/resource_demand_scheduler.py__eq__zUtilizationScore.__eq__H           r%   c                     d S r"   r#   r$   s     r&   __lt__zUtilizationScore.__lt__L   r(   r)   c                     | |k      o| |k    S r"   r#   r$   s     r&   __gt__zUtilizationScore.__gt__P   s    5L 3dem3r)   c                     | |k     p| |k    S r"   r#   r$   s     r&   __le__zUtilizationScore.__le__S   s    e|,tu},r)   c                     | |k      S r"   r#   r$   s     r&   __ge__zUtilizationScore.__ge__V   s    %<r)   N)__name__
__module____qualname____doc__r   boolr'   r+   r-   r/   r1   r#   r)   r&   r   r   5   s        $ . 4    ^ ' 0B t    ^4' 40B 4t 4 4 4 4-' -0B -t - - - - '  0B  t            r)   r   c            	       2    e Zd Zdedededee         fdZdS )UtilizationScorernode_resourcesresource_demandsnode_availability_summaryr    c                    d S r"   r#   )r9   r:   r;   s      r&   __call__zUtilizationScorer.__call__[   s	     	r)   N)	r2   r3   r4   NodeResourcesResourceDemandsr   r   r   r=   r#   r)   r&   r8   r8   Z   sR        %) $;	
 
"	#     r)   r8   c                      e Zd Zdedeeef         dedededdfdZ	d	e
e         deee
e         f         fd
Z	 d(dedeeef         dedededdfdZdedefdZd	e
e         deeef         de
e         deeef         de
e         deeef         de
e         dedeeef         e
e         ffdZd	e
e         deeef         fdZdeeef         de
e         de
e         deeef         deeef         deeef         deeef         fdZde
e         de
e         deeef         eeef         ffdZd	e
e         d eeef         deeef         de
e         eeef         ffd!Zd"e
e
e                  d#e
e         d$eeef         d%eeegee         f         fd&Z d	e
e         d eeef         deeef         defd'Z!dS ))ResourceDemandSchedulerprovider
node_typesmax_workershead_node_typeupscaling_speedr    Nc                    || _         t          j        |          | _        t	                      | _        || _        || _        || _        t          j
                            t          d          }t          |          | _        d S )NzMray.autoscaler._private.resource_demand_scheduler._default_utilization_scorer)rB   copydeepcopyrC   setnode_resource_updatedrD   rE   rF   osenvirongetr   r   utilization_scorer)r%   rB   rC   rD   rE   rF   utilization_scorer_strs          r&   __init__z ResourceDemandScheduler.__init__e   s|     !-
33%(UU"&,.!#-+"
 "

 6L"6
 6
r)   nodesc                     dg }}|D ]`}| j                             |          }|t                   t          k    r|}5|t                   t          k    r|                    |           a||fS )zReturns the head node's id and the list of all worker node ids,
        given a list `nodes` of all node ids in the cluster.
        N)rB   	node_tagsr   r   r   append)r%   rR   head_id
worker_idsnodetagss         r&   _get_head_and_workersz-ResourceDemandScheduler._get_head_and_workers}   s{     #B 	( 	(D=**400D%&.88'(,<<<!!$'''
""r)      c                     || _         t          j        |          | _        t	                      | _        || _        || _        || _        dS )zUpdates the class state variables.

        For legacy yamls, it merges previous state and new state to make sure
        inferered resources are not lost.
        N)	rB   rH   rI   rC   rJ   rK   rD   rE   rF   )r%   rB   rC   rD   rE   rF   s         r&   reset_configz$ResourceDemandScheduler.reset_config   sF     !-
33%(UU"&,.r)   bundlec                     | j                                         D ]G\  }}|                    dd          }|d         }|| j        k    s|dk    rt	          ||          r dS HdS )NrD   r   	resourcesTF)rC   itemsrN   rE   _fits)r%   r^   	node_typeconfigmax_of_typer9   s         r&   is_feasiblez#ResourceDemandScheduler.is_feasible   s{    !%!6!6!8!8 	 	Iv **]A66K#K0NT000K!OOJ JO ttur)   launching_nodesr:   unused_resources_by_ippending_placement_groupsmax_resources_by_ipensure_min_cluster_sizer;   c	           	      
   t          | j        |          }	|                     ||           |                     |||          \  }
}t                              d                    |
                     t                              d                    |                     t          |
|| j        | j	        | j
        ||	          \  }
}}t                              d|            t          |          \  }}||z   }|                     ||
||	          \  }
}t          |
|          \  }}| j	        dz   t          |                                          z
  }t!          | j        || j
        |||	          \  }fd| j        D             }t          |
|          \  }}t                              d                    |                     t                              d	                    |                     t!          | j        || j
        |||	          \  }}t                              d
                    |                     i }| j        D ]Q}|                    |d                              |d          z   |                    |d          z   }|dk    r|||<   R|                     ||                                ||||          }t                              d                    |                     ||fS )a  Given resource demands, return node types to add to the cluster.

        This method:
            (1) calculates the resources present in the cluster by:
                - computing available resources for each existing node
                - counting the number of nodes per node type
                - including both running and launching nodes
            (2) calculates the remaining nodes to add to respect min_workers
                constraint per node type.
            (3) for each strict spread placement group, reserve space on
                available nodes and launch new nodes if necessary.
            (4) calculates the unfulfilled resource bundles.
            (5) calculates which nodes need to be launched to fulfill all
                the bundle requests, subject to max_worker constraints.

        Args:
            nodes: List of existing nodes in the cluster.
            launching_nodes: Summary of node types currently being launched.
            resource_demands: Vector of resource demands from the scheduler.
            unused_resources_by_ip: Mapping from ip to available resources.
            pending_placement_groups: Placement group demands.
            max_resources_by_ip: Mapping from ip to static node resources.
            ensure_min_cluster_size: Try to ensure the cluster can fit at least
                this set of resources. This differs from resources_demands in
                that we don't take into account existing usage.

            node_availability_summary: A snapshot of the current
                NodeAvailabilitySummary.

        Returns:
            Dict of count to add for each node type, and residual of resources
            that still cannot be fulfilled.
        r;   zCluster resources: {}zNode counts: {}rO   zPlacement group demands: r[   c                 l    i | ]0}|                     |d                                |d           z   1S )r   )rN   ).0rc   !pg_demands_nodes_max_launch_limitspread_pg_nodes_to_adds     r&   
<dictcomp>z?ResourceDemandScheduler.get_nodes_to_launch.<locals>.<dictcomp>'  sW     ,
 ,
 ,
  -11)Q??/33IqAAB,
 ,
 ,
r)   zResource demands: {}zUnfulfilled demands: {}zFinal unfulfilled: {}r   zNode requests: {})r   rO   #_update_node_resources_from_runtimecalculate_node_resourcesloggerdebugformat_add_min_workers_nodesrC   rD   rE   $placement_groups_to_resource_demandsreserve_and_allocate_spreadget_bin_pack_residualsumvaluesget_nodes_forrN   )_get_concurrent_resource_demand_to_launchkeys)r%   rR   rg   r:   rh   ri   rj   rk   r;   rO   r9   node_type_countsadjusted_min_workersplacement_group_demand_vectorstrict_spreads$unfulfilled_placement_groups_demands_
max_to_add placement_groups_nodes_max_limitunfulfillednodes_to_add_based_on_demandfinal_unfulfilledtotal_nodes_to_addrc   nodes_to_addrq   rr   s                            @@r&   get_nodes_to_launchz+ResourceDemandScheduler.get_nodes_to_launch   s   X %#?X
 
 
 	008KLLL
 ,0+H+H?$:,
 ,
(( 	,33NCCDDD&--.>??@@@ #O#1
 
 
		
  	K1IKKLLL& 11IJJ	
)
 9;KK ,,	
 
		
" 3H)3
 3
/,a
 %)C0@0G0G0I0I,J,JJ
/<O010
 0
 0
,)1,
 ,
 ,
 ,
 ,
 "_,
 ,
 ,
( /~?OPPQ+223CDDEEE.55kBBCCC:GO1;
 ;
 ;
7$&7 	,334EFFGGG   	= 	=I$((A66(,,Y::;.229a@@A 
 a0<"9- "KK"'')) ,
 
 	(//0BCCDDD!#444r)   c                 p   t          | j                  t          | j                  k    }|sdS |D ]}| j                            |          }t
          |vr'|t
                   }|| j        v s	|| j        vrG| j                            |          }|                    |          }|rt          j	        |          }| j        |                             di           }	dD ]}
|
|v r||
         |	|
<   |	| j        |         d<   |t                   }|t          k    r| j                            |           dS )a
  Update static node type resources with runtime resources

        This will update the cached static node type resources with the runtime
        resources. Because we can not know the exact autofilled memory or
        object_store_memory from config file.
        Nr`   )CPUGPUmemory)lenrC   rK   rB   rT   r   internal_iprN   rH   rI   r   r   add)r%   rR   rj   need_updatenode_idrY   rc   ipruntime_resourcesr`   key	node_kinds               r&   rt   z;ResourceDemandScheduler._update_node_resources_from_runtimeV  sd    $/**c$2L.M.MM 	F  	>  	>G=**733D%T1134IT777DO33 **733B 3 7 7 ; ;  >$(M2C$D$D! OI6::;KK	3 @ @C///):3)?	#:C	*;7 !23	 000 .229===A 	>  	>r)   	to_launchconnected_nodesnon_terminated_nodespending_launches_nodesr   placement_group_nodesc                    i }|                      ||          \  }}	|D ]}
t          t          t          | j        t          ||
         d          z                      }|                    |
d          |	|
         z   }t          ||z
  |                    |
d          |                    |
d          z             }|dk    rt          |||
                   ||
<   |S )a$  Updates the max concurrent resources to launch for each node type.

        Given the current nodes that should be launched, the non terminated
        nodes (running and pending) and the pending to be launched nodes. This
        method calculates the maximum number of nodes to launch concurrently
        for each node type as follows:
            1) Calculates the running nodes.
            2) Calculates the pending nodes and gets the launching nodes.
            3) Limits the total number of pending + currently-launching +
               to-be-launched nodes to:
                   max(
                       5,
                       self.upscaling_speed * max(running_nodes[node_type], 1)
                   ).

        Args:
            to_launch: List of number of nodes to launch based on resource
                demand for every node type.
            connected_nodes: Running nodes (from LoadMetrics).
            non_terminated_nodes: Non terminated nodes (pending/running).
            pending_launches_nodes: Nodes that are in the launch queue.
            adjusted_min_workers: Nodes to launch to satisfy
                min_workers and request_resources(). This overrides the launch
                limits since the user is hinting to immediately scale up to
                this size.
            placement_group_nodes: Nodes to launch for placement groups.
                This overrides the launch concurrency limits.
        Returns:
            Dict[NodeType, int]: Maximum number of nodes to launch for each
                node type.
        r[   r   )#_separate_running_and_pending_nodesmaxr   intrF   rN   min)r%   r   r   r   r   r   r   updated_nodes_to_launchrunning_nodespending_nodesrc   max_allowed_pending_nodestotal_pending_nodesupper_bounds                 r&   r   zAResourceDemandScheduler._get_concurrent_resource_demand_to_launch  s   P #%'+'O'O (
 (
$} # 	 	I ),6D(3}Y/G+K+KKLL) )%
 '**9a88=;SS   ),?? %((A66'++Iq99:	 K Q589!56 6'	2 '&r)   c                 V   t          j        t                    }t          j        t                    }|D ]q}| j                            |          }t
          |v rL|t
                   }| j                            |          }||v r||xx         dz  cc<   a||xx         dz  cc<   r||fS )z?Splits connected and non terminated nodes to pending & running.r[   )collectionsdefaultdictr   rB   rT   r   r   )	r%   r   r   r   r   r   rY   rc   node_ips	            r&   r   z;ResourceDemandScheduler._separate_running_and_pending_nodes  s     $/44#/44+ 	2 	2G=**733D%-- !78	-33G<<o--!),,,1,,,,!),,,1,,,m++r)   r   c                     g t          j        t                    d fd	}|D ]m} j                            |          }t
          |v rH|t
                   } j                            |          }|                    |          }	 |||	           n|                                D ]"\  }}
t          |
          D ]} ||           #fS )a  Returns node resource list and node type counts.

        Counts the running nodes, pending nodes.
        Args:
             nodes: Existing nodes.
             pending_nodes: Pending nodes.
        Returns:
             node_resources: a list of running + pending resources.
                 E.g., [{"CPU": 4}, {"GPU": 2}].
             node_type_counts: running + pending workers per node type.
        Nc                 J   | j         vr8t                              d|  dj          dt           dt           d	           d S t          j        j         |          d                   }|t          j        |          }                    |           | xx         dz  cc<   d S )NzMissing entry for node_type z in cluster config: z under entry available_node_types. This node's resources will be ignored. If you are using an unmanaged node, manually set the z	 tag to "z." in your cloud provider's management console.r`   r[   )rC   rv   errorr   r   rH   rI   rU   )rc   available_resources	availabler9   r   r%   s      r&   add_nodezBResourceDemandScheduler.calculate_node_resources.<locals>.add_node  s    // *9 * *'+* *  1	* *
 ,* * *   tdoi&@&MNNI #. M*=>>	!!),,,Y'''1,'''''r)   r"   )
r   r   r   rB   rT   r   r   rN   ra   range)r%   rR   r   rh   r   r   rY   rc   r   r   countr   r9   r   s   `           @@r&   ru   z0ResourceDemandScheduler.calculate_node_resources  s   $ &2377	- 	- 	- 	- 	- 	- 	- 	-2  	9 	9G=**733D%-- !78	]..w77&<&@&@&D&D#$7888 - 3 3 5 5 	$ 	$Iu5\\ $ $####$ ///r)   r   r9   r   rO   c           
         t          j        t                    }|D ]}t          ||d          \  }}| j        dz   t          |                                          z
  }	t          | j        || j	        |	||d          \  }
}t          | j        |
          }t          ||d          \  }}|r.t                              d                    |                     t          ||
           t          ||
           ||z   }|||fS )a  For each strict spread, attempt to reserve as much space as possible
        on the node, then allocate new nodes for the unfulfilled portion.

        Args:
            strict_spreads (List[List[ResourceDict]]): A list of placement
                groups which must be spread out.
            node_resources (List[ResourceDict]): Available node resources in
                the cluster.
            node_type_counts (Dict[NodeType, int]): The amount of each type of
                node pending or in the cluster.
            utilization_scorer: A function that, given a node
                type, its resources, and resource demands, returns what its
                utilization would be.

        Returns:
            Dict[NodeType, int]: Nodes to add.
            List[ResourceDict]: The updated node_resources after the method.
            Dict[NodeType, int]: The updated node_type_counts.

        T)strict_spreadr[   )rO   r   z-Unfulfilled strict spread placement group: {})r   r   r   r|   rD   r}   r~   r   rC   rE   #_node_type_counts_to_node_resourcesrv   rw   rx   _inplace_add)r%   r   r9   r   rO   to_addbundlesr   updated_node_resourcesr   r   r   new_node_resourcesincluding_reserveds                 r&   r{   z3ResourceDemandScheduler.reserve_and_allocate_spread  sT   : (--%  	I  	IG 3Ht3 3 3/K/ )A-4D4K4K4M4M0N0NNJ( ##5"  LIq "E" "
 /D"Kt/ / /+K+  CJJ7SS   )9555+++36HHNN~'777r)   c                 
   |                      |||          \  }}d}|                                D ]Q\  }}|d                    ||          z  }|                    |          r|d                    ||                   z  }R|S )NzWorker node types:z

 - {}: {}z ({} pending))ru   ra   rx   rN   )	r%   rR   r   rh   r9   r   outrc   r   s	            r&   debug_stringz$ResourceDemandScheduler.debug_string]  s     ,0+H+H="8,
 ,
(( # 0 6 6 8 8 	H 	HIu=''	5999C  ++ H--mI.FGGG
r)   )r[   )"r2   r3   r4   r   r   r   r   r   floatrQ   r   r   r	   rZ   r]   r   r6   rf   r   r
   r   r   rt   r   r   strru   r   r>   r?   r   r   r{   r   r#   r)   r&   rA   rA   d   s        

 #556
 	

 !
 
 

 
 
 
0#4< #E&$v,BV<W # # # #& "#/ // #556/ 	/
 !/ / 
/ / / /(, 4    l5F|l5 hm,l5 |,	l5
 !%V\%9 :l5 #''>"?l5 "&,"67l5 "&l!3l5 $;l5 x}
tL1	2l5 l5 l5 l5\->&\->8<V\=Q8R-> -> -> ->^E'#&E' fE' #6l	E'
 !%Xs] 3E' #8S=1E'  $HcM2E' 
hm	E' E' E' E'N,"6l, f, x}
tHcM2	3	, , , ,(:0F|:0 FCK(:0 !%S,%6 7	:0
 |
d8S=1	2:0 :0 :0 :0x?8T,/0?8 \*?8 x}-	?8
 %O,h7G.HH
?8 ?8 ?8 ?8BF| FCK( !%S,%6 7	
 
     r)   rA   rC   r   r    c                      g }|                                 D ]$\  }| fdt          |          D             z  }%|S )z?Converts a node_type_counts dict into a list of node_resources.c                 P    g | ]"}         d                                           #S r`   )rH   rp   r   rc   rC   s     r&   
<listcomp>z7_node_type_counts_to_node_resources.<locals>.<listcomp>x  s/    VVVAj+K8==??VVVr)   )ra   r   )rC   r   r`   r   rc   s   `   @r&   r   r   p  s]    
 I,2244 W W	5VVVVVuVVVV		r)   r9   rD   rE   rk   rO   c                    i }                                 D ]\  }|                    d          }	t          |                    dd          |                    dd                    }
|k    r|
dz   }
|	|
k     rB|
|	z
  |<   |
|<   |                     fdt	          |                   D                        |r|dz   t          |                                          z
  }g }|D ]7|                    fdt	          |                   D                        8t          ||          \  }}t          |||||          \  }}|D ]|                    d          }|dk    rg||                    d          z   |<   |                     fdt	          |          D                        ||                    d          z   |<   | ||fS )	a  Updates resource demands to respect the min_workers and
    request_resources() constraints.

    Args:
        node_resources: Resources of existing nodes already launched/pending.
        node_type_counts: Counts of existing nodes already launched/pending.
        node_types: Node types config.
        max_workers: global max_workers constaint.
        ensure_min_cluster_size: resource demands from request_resources().
        utilization_scorer: A function that, given a node
            type, its resources, and resource demands, returns what its
            utilization would be.

    Returns:
        node_resources: The updated node resources after adding min_workers
            and request_resources() constraints per node type.
        node_type_counts: The updated node counts after adding min_workers
            and request_resources() constraints per node type.
        total_nodes_to_add_dict: The nodes to add to respect min_workers and
            request_resources() constraints.
    r   min_workersrD   r[   c                 P    g | ]"}t          j                 d                    #S r   rH   rI   r   s     r&   r   z*_add_min_workers_nodes.<locals>.<listcomp>  =        M*Y"7"DEE  r)   c                 P    g | ]"}t          j                 d                    #S r   r   r   s     r&   r   z*_add_min_workers_nodes.<locals>.<listcomp>  r   r)   rn   c                 P    g | ]"}t          j                 d                    #S r   r   r   s     r&   r   z*_add_min_workers_nodes.<locals>.<listcomp>  s=        j&;K&HII  r)   )	ra   rN   r   extendr   r}   r~   r|   r   )r9   r   rC   rD   rE   rk   rO   total_nodes_to_add_dictrd   existingtargetr   max_node_resourcesresource_requests_unfulfilledr   nodes_to_add_request_resourcesr   rc   s     `              @r&   ry   ry   |  s   @ !'--//  	6#''	155VZZq116::mQ3O3OPP&&aZFf17(1B#I.*0Y'!!    "#:9#EFF      'M 1_s+;+B+B+D+D'E'EE
) 	 	I%%    "#3I#>??      ,A 7,
 ,
(%q -:)1-
 -
 -
)& 8 	M 	MI9==iKKLa.:=M=Q=Qq> > / + %%    !&|!4!4     !#:#>#>y!#L#LL ( +-DDDr)   Fexisting_nodesr   r`   r   c                    t          j        t                    }|rt          |                                          |k     rg }| D ]}	| |	                             dd          }
||	k    r|
dz   }
|                    |	d          |                    |	d          z   |
k    r[| |	         d         }|r |||d         g|	          }n ||||	          }||                    ||	f           |s8t          d |D                       st          	                    d| d           nt          |d	
          }|d         d         }||xx         dz  cc<   |r|dd         }nP| |         d         }t          |g|          \  }}t          |          t          |          k     sJ ||f            |}|r&t          |                                          |k     ||fS )a  Determine nodes to add given resource demands and constraints.

    Args:
        node_types: node types config.
        existing_nodes: counts of existing nodes already launched.
            This sets constraints on the number of new nodes to add.
        max_to_add: global constraint on nodes to add.
        resources: resource demands to fulfill.
        strict_spread: If true, each element in `resources` must be placed on a
            different node.
        utilization_scorer: A function that, given a node
            type, its resources, and resource demands, returns what its
            utilization would be.

    Returns:
        Dict of count to add for each node type, and residual of resources
        that still cannot be fulfilled.
    rD   r   r[   r`   Nc              3   >   K   | ]}|D ]}t          |          V  d S r"   )r   )rp   resources_dictresources      r&   	<genexpr>z get_nodes_for.<locals>.<genexpr>  sU        " .   ,H55      r)   zBThe autoscaler could not find a node type to satisfy the request: z:. Please specify a node type with the necessary resources.T)reverse)r   r   r   r}   r~   rN   rU   anyrv   warningsortedr|   r   )rC   r   rE   r   r`   rO   r   r   utilization_scoresrc   max_workers_of_node_typer9   scorebest_node_typeallocated_resourceresidualr   s                    r&   r   r     st   : )4(?(D(DL
 -!L//1122Z??# 	> 	>I'1)'<'@'@PQ'R'R$**+Ca+G(""9a00<3C3CIq3Q3QQ+, , '	2;?N Q +*>IaL>9UU**>9iPP "))5)*<=== " 	  &/     	
 , ), , ,  
 #$6EEE+A.q1^$$$)$$$ 	!!!""II!+N!;K!H/1C0DiPPKHax==3y>>111Ix3H111 I[  -!L//1122Z??^ ""r)   r;   c                   t          j        |           }g }t                      }|D ]l}|                                D ] \  }}|dk    r|                    |           !t          ||          r%|                    |           t          ||           m|sd S g }	d}
|                                 D ]>\  }}|dk     r||v r|
dz  }
|||         z
  |z  }|	                    ||dz  z             ?|	sd S d}t          r/d| v o| d         dk    }t          d |D                       }|r|sd}||
t          |	          t          t          |	                    t          |	          z  fS )Nr   r[      Tr   c              3      K   | ]}d |v V  	dS )r   Nr#   )rp   rs     r&   r   z5_resource_based_utilization_scorer.<locals>.<genexpr>R  s&      99!5A:999999r)   F)rH   rI   rJ   ra   r   rb   rU   _inplace_subtractr   r   r   r   r}   r   )r9   r`   r;   	remainingfittableresource_typesr   kvutil_by_resourcesnum_matching_resource_typesutilgpu_okis_gpu_nodeany_gpu_tasks                  r&   "_resource_based_utilization_scorerr   )  s    n--IHUUN , ,GGII 	& 	&DAq1uu""1%%%A 	,OOAi+++ t"#$$&& 	0 	01q55 '1,'IaL A%  dAg////  t F$ ~-K.2G!2K99y99999 	| 	F 	#c#$$%%,=(>(>> r)   rc   c                &    t          | ||          S )Nrm   )r   )r9   r`   rc   r;   s       r&   _default_utilization_scorerr   c  s#     .	=V   r)   r:   c                    g }t          j        |           }t                      }t          |d d          D ]}d}d}t	          t          |                    D ]:}	|	|v r||	         }t          ||          rd}|r|                    |	            n;|r|rt          ||           r|	                    |           ||fS )a6  Return a subset of resource_demands that cannot fit in the cluster.

    TODO(ekl): this currently does not guarantee the resources will be packed
    correctly by the Ray scheduler. This is only possible once the Ray backend
    supports a placement groups API.

    Args:
        node_resources (List[ResourceDict]): List of resources per node.
        resource_demands (List[ResourceDict]): List of resource bundles that
            need to be bin packed onto the nodes.
        strict_spread: If true, each element in resource_demands must be
            placed on a different entry in `node_resources`.

    Returns:
        List[ResourceDict]: the residual list resources that do not fit.
        List[ResourceDict]: The updated node_resources after the method. The order of the list elements remains unchanged.
    c                     t          |                                           t          |                                           t          |                                           fS r"   )r   r~   r}   r   ra   )demands    r&   <lambda>z'get_bin_pack_residual.<locals>.<lambda>  sB        6<<>>""
 r)   T)r   r   FN)
rH   rI   rJ   r   r   r   rb   r   r   rU   )
r9   r:   r   r   rR   usedr   foundrX   is
             r&   r|   r|   o  s   . K M.))E55D
 
 

    ' ' s5zz"" 		 		ADyy8DT6""    HHQKKK  	'T 	'dF++++v&&&&r)   rX   c                     |                                 D ]H\  }}||                     ||                    t          j        j                  rdnd          k    r dS IdS )Ng      ?        FT)ra   rN   
startswithray_rayletIMPLICIT_RESOURCE_PREFIXrX   r`   r   r   s       r&   rb   rb     sr    !!  1 txxall3;#GHHQssc
 
 
 
 55
 4r)   c                 ,   |                                 D ]~\  }}|dk    r|| vr5|                    t          j        j                  sJ || f            d| |<   || v sJ || f            | |xx         |z  cc<   | |         dk    sJ | ||f            d S )Nr   r[   r  )ra   r  r  r  r	  r
  s       r&   r   r     s    !! 
, 
,166 D==<< DEEPP4yPPEDGDyyy1d)yyyQ1Aw#~~~a|~~~~
, 
,r)   abc                 Z    |                                 D ]\  }}| |xx         |z  cc<   dS )zWGenerically adds values in `b` to `a`.
    a[k] should be defined for all k in b.keys()N)ra   )r  r  r   r   s       r&   r   r     s@     		  1	!	 r)   ri   c                    g }g }| D ]?}g }|j         D ]5}|j        dk    r|                    t          |j                             6|j        t          j        k    s|j        t          j        k    r|	                    |           |j        t          j
        k    r^t          j        t                    }|D ],}|                                D ]\  }}	||xx         |	z  cc<   -|                    |           |j        t          j        k    r|                    |           !t                               d| d           A||fS )a  Preprocess placement group requests into regular resource demand vectors
    when possible. The policy is:
        * STRICT_PACK - Convert to a single bundle.
        * PACK - Flatten into a resource demand vector.
        * STRICT_SPREAD - Cannot be converted.
        * SPREAD - Flatten into a resource demand vector.

    Args:
        pending_placement_groups (List[PlacementGroupData]): List of
            PlacementGroupLoad's.

    Returns:
        List[ResourceDict]: The placement groups which were converted to a
            resource demand vector.
        List[List[ResourceDict]]: The placement groups which should be strictly
            spread.
    r)   z&Unknown placement group request type: zI. Please file a bug report https://github.com/ray-project/ray/issues/new.)r   r   rU   dictunit_resourcesstrategyr   PACKSPREADr   STRICT_PACKr   r   r   ra   STRICT_SPREADrv   r   )
ri   resource_demand_vectorunconvertedplacement_groupshapesr^   combinedshapelabelquantitys
             r&   rz   rz     s   (  K3  %- 	7 	7F~$$MM$v4556666 $(9(>>>'+<+CCC"))&1111%):)FFF".u55H 0 0',{{}} 0 0OE8UOOOx/OOOO0"))(3333%):)HHHv&&&&LLB B B B   
 ";..r)   )F)Br5   r   rH   loggingrL   abcr   	functoolsr   typingr   r   r   r   r	   r  ray._private.gcs_utilsr
   !ray.autoscaler._private.constantsr   r   r   ray.autoscaler._private.loaderr   :ray.autoscaler._private.node_provider_availability_trackerr   ray.autoscaler._private.utilr   r   r   r   r   r   ray.autoscaler.node_providerr   ray.autoscaler.tagsr   r   r   r   r   ray.core.generated.common_pb2r   	getLoggerr2   rv   r>   r?   r   r8   rA   r   r   r   ry   r6   r   r   r   r   r|   rb   r   r   r   rz   r#   r)   r&   <module>r,     s          				             8 8 8 8 8 8 8 8 8 8 8 8 8 8 



 : : : : : :         
 B A A A A A                     6 5 5 5 5 5              < ; ; ; ; ;		8	$	$|$"  "  "  "  "  "  "  " J       I I I I I I I IX	X112	8S=)	 
,	 	 	 	YE&YE8S=)YE X112YE 	YE
 YE ",/YE !	-x8H/IIYE <$x}-tHcM/BCYE YE YE YEJ  N# N#X112N#3'N# N# 	N#
 L!N# !	-x8H/IIN# N# 8S=4-.N# N# N# N#b7 7L!7  7	7
 eD#ue+,-7 7 7 7t	 	L!	 	
  7	 	 	 	  ; ;&;<(; ; <$|,-	; ; ; ;|  $    ,L ,\ ,d , , , ,K+      1/"#:;1/
4tD$67781/ 1/ 1/ 1/ 1/ 1/r)   