a
    ¹}ÂhMõ  ã                   @   s|   d dl Z d dlZd dlmZ d dlZd dlmZ d dlm	Z	m
Z
 d dlmZ dZdd„ ZG d	d
„ d
ejƒZG dd„ dƒZdS )é    N)ÚTimer)Úcp_model)ÚSBCSolvationModelÚRareFlag)Ú	new_printTc                    s   ‡ fdd„}t r|S ˆ S )z*Wrapper function to log the execution timec                     sD   t   ¡ }ˆ | i |¤Ž}tt   ¡ | dƒ}tdˆ j› d|› dƒ |S )Né   zProcessing time z: z seconds)ÚtimeÚroundÚprintÚ__name__)ÚargsÚkwargsÚstartÚresultÚseconds©Úfunc© úOC:\Users\Administrator\Downloads\futplus_django\sbc\solvation_maker\optimize.pyÚwrapper   s
    zruntime.<locals>.wrapper)ÚLOG_RUNTIME)r   r   r   r   r   Úruntime   s    r   c                       sB   e Zd ZdZedœ‡ fdd„Zdd„ Zdd„ Z‡ fd	d
„Z‡  Z	S )ÚObjectiveEarlyStoppingz?Stop the search if the objective remains the same for X seconds©Útimer_limitc                    s   t ƒ  ¡  || _d | _d S ©N)ÚsuperÚ__init__Ú_timer_limitÚ_timer)Úselfr   ©Ú	__class__r   r   r      s    
zObjectiveEarlyStopping.__init__c                 C   s   |   ¡  dS )zCThis is called everytime a solution with better objective is found.N)Ú_reset_timer©r    r   r   r   Úon_solution_callback    s    z+ObjectiveEarlyStopping.on_solution_callbackc                 C   s.   | j r| j  ¡  t| j| jƒ| _ | j  ¡  d S r   )r   Úcancelr   r   Ú
StopSearchr   r$   r   r   r   r#   $   s    
z#ObjectiveEarlyStopping._reset_timerc                    s   t | j› dƒ tƒ  ¡  d S )Nz+ seconds without improvement in objective. )r
   r   r   r'   r$   r!   r   r   r'   *   s    z!ObjectiveEarlyStopping.StopSearch)
r   Ú
__module__Ú__qualname__Ú__doc__Úintr   r%   r#   r'   Ú__classcell__r   r   r!   r   r      s
   r   c                   @   s‚  e Zd Zdd„ Zedœdd„Zdd„ Zedd	„ ƒZed
d„ ƒZ	edd„ ƒZ
edd„ ƒZedd„ ƒZedd„ ƒZedd„ ƒZedd„ ƒZedd„ ƒZedd„ ƒZedd„ ƒZedd„ ƒZed d!„ ƒZed"d#„ ƒZed$d%„ ƒZed&d'„ ƒZed(d)„ ƒZed*d+„ ƒZed,d-„ ƒZed.d/„ ƒZed0d1„ ƒZed2d3„ ƒZed4d5„ ƒZed6d7„ ƒZed8d9„ ƒZ d:d;„ Z!ed<d=„ ƒZ"e#j$d>œd?d@„Z%dAdB„ Z&dCS )DÚSolvationCorec                 C   s   g d¢g d¢g d¢g d¢g d¢g d¢g d¢g d¢g d	¢g d
¢g d¢g d¢g d¢g d¢g d¢g d¢g d¢g d¢g d¢g d¢g d¢g d¢g d¢g d¢g d¢g d¢g d¢g d¢g d¢g d¢dœ| _ g d¢g d ¢g d!¢g d"¢g d#¢g d$¢g d%¢g d&¢g d'¢g d(¢g d)¢g d*¢g d+¢g d,¢g d-¢g d.¢g d/¢g d0¢g d1¢g d2¢g d3¢g d4¢g d5¢g d6¢g d7¢g d8¢g d9¢g d9¢g d:¢g d;¢d<œ| _d=d>d?d@dAdBœ| _dCdDdEdFdGdBœ| _d S )HN)ÚGKÚCBr/   r/   ÚLMÚCMÚCDMr1   ÚRMÚSTr4   )r.   r/   r/   r/   r0   r1   r1   r3   ÚCAMr4   r4   )r.   r/   r/   r/   r0   r1   r1   r3   r5   r4   r5   )r.   r/   r/   r/   r2   r2   r0   r5   r3   r4   r4   )r.   r/   r/   r/   r0   r1   r1   r3   ÚLWr4   ÚRW)r.   ÚLBr/   r/   ÚRBr2   r0   r5   r3   r4   r4   )r.   r8   r/   r/   r9   r2   r1   r5   r1   r4   r4   )r.   r8   r/   r/   r9   r2   r0   r1   r3   r4   r4   )r.   r8   r/   r/   r9   r2   r0   r1   r1   r3   r4   )r.   r8   r/   r/   r9   r2   r2   r5   r6   r4   r7   )r.   r8   r/   r/   r9   r2   r2   r5   r5   r5   r4   )r.   r8   r/   r/   r9   r2   r2   r5   r0   r4   r3   )r.   r8   r/   r/   r9   r2   r2   r5   r5   r4   r4   )r.   r8   r/   r/   r9   r1   r1   r6   r4   r4   r7   )r.   r/   r/   r8   r9   r1   r1   r1   r5   r4   r4   )r.   r8   r/   r/   r9   r1   r1   r1   r5   r4   r5   )r.   r8   r/   r/   r9   r1   r1   r1   r6   r4   r7   )r.   r8   r/   r/   r9   r1   r2   r1   r6   r4   r7   )r.   r8   r/   r/   r9   r2   r2   r1   r6   r4   r7   )r.   r8   r/   r/   r9   r1   r1   r5   r6   r4   r7   )r.   r8   r/   r/   r9   r1   r1   r0   r5   r3   r4   )r.   r8   r/   r/   r9   r0   r1   r1   r3   r4   r4   )r.   r8   r/   r/   r9   r0   r2   r2   r3   r4   r4   )r.   r/   r/   r8   r9   r1   r0   r5   r5   r3   r4   )r.   r/   r/   r8   r9   r1   r0   r1   r1   r3   r4   )r.   r8   r/   r/   r/   r9   r1   r1   r5   r4   r4   )r.   r8   r/   r/   r/   r9   r1   r1   r6   r4   r7   )r.   r8   r/   r/   r/   r9   r1   r2   r1   r4   r4   )r.   r8   r/   r/   r/   r9   r1   r1   r0   r3   r4   )ú3-1-4-2ú3-4-1-2ú3-4-2-1ú3-5-2ú3-4-3ú	4-1-2-1-2ú4-1-2-1-2[2]ú4-1-3-2ú4-1-4-1ú4-2-1-3ú4-2-3-1ú
4-2-3-1[2]ú4-2-2-2ú4-2-4ú4-3-1-2ú4-3-2-1ú4-3-3ú4-3-3[2]ú4-3-3[3]ú4-3-3[4]ú
4-4-1-1[2]ú4-4-2ú4-4-2[2]ú4-5-1ú4-5-1[2]ú5-2-1-2ú5-2-2-1ú5-2-3ú5-3-2ú5-4-1)r.   r/   r/   r/   r2   r3   r1   r1   r0   r4   r4   )r.   r/   r/   r/   r3   r1   r1   r0   r5   r4   r4   )r.   r/   r/   r/   r3   r1   r1   r0   r5   r5   r4   )r.   r/   r/   r/   r3   r1   r1   r0   r7   r4   r6   )r.   r/   r/   r/   r2   r2   r3   r0   r5   r4   r4   )r.   r9   r/   r/   r8   r2   r3   r0   r5   r4   r4   )r.   r9   r/   r/   r8   r2   r1   r1   r5   r4   r4   )r.   r9   r/   r/   r8   r2   r3   r1   r0   r4   r4   )r.   r9   r/   r/   r8   r2   r3   r1   r1   r0   r4   )r.   r9   r/   r/   r8   r2   r2   r5   r7   r4   r6   )r.   r9   r/   r/   r8   r2   r2   r5   r5   r4   r4   )r.   r9   r/   r/   r8   r2   r2   r5   r5   r5   r4   )r.   r9   r/   r/   r8   r2   r2   r3   r0   r5   r4   )r.   r9   r/   r/   r8   r1   r1   r7   r4   r4   r6   )r.   r9   r/   r/   r8   r1   r1   r1   r5   r4   r4   )r.   r9   r/   r/   r8   r1   r1   r1   r5   r5   r4   )r.   r9   r/   r/   r8   r1   r1   r1   r7   r4   r6   )r.   r9   r/   r/   r8   r2   r1   r1   r7   r4   r6   )r.   r9   r/   r/   r8   r2   r2   r1   r7   r4   r6   )r.   r9   r/   r/   r8   r1   r1   r5   r7   r4   r6   )r.   r9   r/   r/   r8   r3   r1   r1   r0   r5   r4   )r.   r9   r/   r/   r8   r3   r1   r1   r0   r4   r4   )r.   r9   r/   r/   r8   r2   r2   r3   r0   r4   r4   )r.   r9   r/   r/   r8   r3   r1   r0   r5   r5   r4   )r.   r9   r/   r/   r8   r3   r1   r1   r1   r0   r4   )r.   r9   r/   r/   r/   r8   r1   r1   r5   r4   r4   )r.   r9   r/   r/   r/   r8   r1   r1   r7   r4   r6   )r.   r9   r/   r/   r/   r8   r2   r1   r1   r4   r4   )r.   r9   r/   r/   r/   r8   r3   r1   r1   r0   r4   )r:   r;   r<   r>   r=   r?   r@   rA   rB   rC   rF   rD   rE   rG   rH   rI   rJ   rK   rL   rM   rN   rO   rP   rQ   rR   rS   rT   rU   rV   rW   z“UNKNOWN: The status of the model is still unknown. A search limit has been reached before any of the statuses below could be determined.(more time)zMMODEL_INVALID: The given CpModelProto didn't pass the validation step.(error)z{FEASIBLE: A feasible solution has been found. But the search was stopped before we could prove optimality.(solved not best)z?INFEASIBLE: The problem has been proven infeasible.(cant solve)zBOPTIMAL: An optimal feasible solution has been found.(solved best))r   é   r   é   é   zUNKNOWN: (more time)zMODEL_INVALID: (error)zFEASIBLE: (solved not best)zINFEASIBLE: (cant solve)zOPTIMAL: (solved best))Úformation_dictÚformation_dict_2Ústatus_dictÚstatus_short_dictr$   r   r   r   r   1   s”    ß%à$ûûzSolvationCore.__init__)Úsolvation_modelc                 C   sz  |j | _|j| _| jdk r²d| _| j |j ¡ ¡ }|jrPdd„ |j d¡D ƒ}nt	|j
jjdddƒ}g }t|ƒD ]\}}||v rr| || ¡ qr| j d|i¡ | j d|i¡ |j| _|jrÐt |j¡| _ng | _|jrìt |j¡| _ng | _|j| _|j| _|j| _|j| _ |j!| _"|j#| _$|j%| _&t	t'j(j)dd	jd
ddƒ| _*g | _+g | _,|j-rxt |j-¡| _+t |j.¡| _,|j/| _0|j1| _2g | _3|j4r¤t |j4¡| _3g | _5g | _6|j7rÔt |j7¡| _5t |j8¡| _6|j9| _:|j;| _<g | _=|j>r t |j>¡| _=g | _?g | _@|jAr0t |jA¡| _?t |jB¡| _@|jC| _D|jE| _Fg | _G|jHr\t |jH¡| _Gg | _Ig | _J|jKrŒt |jK¡| _It |jL¡| _Jg | _Mg | _N|jOr¼t |jO¡| _Mt |jP¡| _Ng | _Qg | _R|jSrìt |jS¡| _Qt |jT¡| _R|jU| _Vg | _Wg | _X|jYr$t |jY¡| _Wt |jZ¡| _X|j[| _\|j]| _^d| __g | _`|jarVt |ja¡| _`|jb| _cd | _dd| _ed | _fd | _gd S )Né   Úspecialc                 S   s   g | ]}t |ƒ‘qS r   )r+   )Ú.0Úiier   r   r   Ú
<listcomp>‘   ó    z0SolvationCore.set_conditions.<locals>.<listcomp>ú,ÚpositionT)Úflat)Úconsidered_rareÚrare_idÚratingiX  )hÚ	formationÚ	FORMATIONÚnum_playersÚNUM_PLAYERSr\   ÚgetÚcopyÚrequired_positionsÚsplitÚlistÚsbc_typeÚsbctarget_setÚvalues_listÚ	enumerateÚappendr[   ÚupdateÚplayers_in_positionÚPLAYERS_IN_POSITIONÚfix_playersÚastÚliteral_evalÚFIX_PLAYERSÚremove_playersÚREMOVE_PLAYERSÚminimize_max_costÚMINIMIZE_MAX_COSTÚmaximize_total_costÚMAXIMIZE_TOTAL_COSTÚuse_preferred_positionÚUSE_PREFERRED_POSITIONÚuse_alternate_positionsÚUSE_ALTERNATE_POSITIONSÚuse_all_duplicatesÚUSE_ALL_DUPLICATESÚuse_at_least_half_duplicatesÚUSE_AT_LEAST_HALF_DUPLICATESÚuse_at_least_one_duplicateÚUSE_AT_LEAST_ONE_DUPLICATEr   ÚobjectsÚfilterÚCONSIDER_AS_RAREÚCLUBÚNUM_CLUBÚclubÚnum_clubÚmax_num_clubÚMAX_NUM_CLUBÚmin_num_clubÚMIN_NUM_CLUBÚNUM_UNIQUE_CLUBÚnum_unique_clubÚLEAGUEÚ
NUM_LEAGUEÚleagueÚ
num_leagueÚmax_num_leagueÚMAX_NUM_LEAGUEÚmin_num_leagueÚMIN_NUM_LEAGUEÚNUM_UNIQUE_LEAGUEÚnum_unique_leagueÚCOUNTRYÚNUM_COUNTRYÚcountryÚnum_countryÚmax_num_countryÚMAX_NUM_COUNTRYÚmin_num_countryÚMIN_NUM_COUNTRYÚNUM_UNIQUE_COUNTRYÚnum_unique_countryÚRARITY_1ÚNUM_RARITY_1Úrarity_1Únum_rarity_1ÚRARITY_2ÚNUM_RARITY_2Úrarity_2Únum_rarity_2ÚGROUP_RARITYÚNUM_GROUP_RARITYÚgroup_rarityÚnum_group_rarityÚsquad_ratingÚSQUAD_RATINGÚMIN_OVERALLÚNUM_MIN_OVERALLÚmin_overallÚnum_min_overallÚ	chemistryÚ	CHEMISTRYÚchem_per_playerÚCHEM_PER_PLAYERÚMINIMIZE_OBJECTIVEÚUNIQUE_QUALITYÚuniq_qualityÚmin_rating_playersÚMIN_RATING_PLAYERSÚfifa_accountÚmax_time_in_secondsÚsolve_status_textÚsolve_status_short_text)r    r_   rl   Zcorrect_posZnew_formationÚindÚeer   r   r   Úset_conditionsˆ   sº    
ÿzSolvationCore.set_conditionsc                    s:   t |ƒ}|| j ‰ t ‡ fdd„|D ƒƒ}t|| ƒ| j S )zRhttps://www.reddit.com/r/EASportsFC/comments/5osq7k/new_overall_rating_figured_outc                 3   s   | ]}t |ˆ  d ƒV  qdS )r   N)Úmax)rb   Úrat©Úavg_ratr   r   Ú	<genexpr>?  re   z2SolvationCore.calc_squad_rating.<locals>.<genexpr>)Úsumro   r	   )r    rk   Zrat_sumÚexcessr   rÖ   r   Úcalc_squad_rating;  s    
zSolvationCore.calc_squad_ratingc                    s–  |d |d |d |d f\}}}}g }	g }
i i i i i i i i dœ}t |ƒD ]d}|	 ˆ  d|› ¡¡ |
 ˆ  ddd|› ¡¡ |d  |d |j|df  g ¡|	| g |d |d |j|df  < |d	  |d	 |j|d	f  g ¡|	| g |d	 |d	 |j|d	f  < |d
  |d
 |j|d
f  g ¡|	| g |d
 |d
 |j|d
f  < |d  |d |j|df  g ¡|	| g |d |d |j|df  < |d  |d |j|df  g ¡|	| g |d |d |j|df  < |d  |d |j|df  g ¡|	| g |d |d |j|df  < |d  |d |j|df  g ¡|	| g |d |d |j|df  < |d  |d |j|df  g ¡|	| g |d |d |j|df  < qJ‡ fdd„t |ƒD ƒ}‡ fdd„t |ƒD ƒ}‡ fdd„t |ƒD ƒ}‡ fdd„t |ƒD ƒ}‡ fdd„t |ƒD ƒ}‡ fdd„t |ƒD ƒ}‡ fdd„t |ƒD ƒ}‡ fdd„t |ƒD ƒ}‡ fdd„t |ƒD ƒ}ˆ |	|
||||||||||fS )zCreate the relevant variablesr   rX   r   rY   ©ÚClubÚLeagueÚCountryÚPositionÚRatingÚColorÚRarityÚNameÚplayerÚchemrÝ   rÞ   rß   rà   rá   râ   rã   rä   c                    s    g | ]}ˆ   d dd|› ¡‘qS )r   rY   Úz_club©Ú	NewIntVar©rb   Úi©Úmodelr   r   rd   ^  re   z,SolvationCore.create_var.<locals>.<listcomp>c                    s    g | ]}ˆ   d dd|› ¡‘qS )r   rY   Úz_leaguerè   rê   rì   r   r   rd   _  re   c                    s    g | ]}ˆ   d dd|› ¡‘qS )r   rY   Úz_nationrè   rê   rì   r   r   rd   `  re   c                    s$   g | ]‰ ‡ ‡fd d„t dƒD ƒ‘qS )c                    s    g | ]}ˆ  d ˆ › |› ¡‘qS )Úb_c©Ú
NewBoolVarrê   ©Újrí   r   r   rd   c  re   ú7SolvationCore.create_var.<locals>.<listcomp>.<listcomp>rZ   ©Úrange©rb   rì   ©rô   r   rd   c  re   c                    s$   g | ]‰ ‡ ‡fd d„t dƒD ƒ‘qS )c                    s    g | ]}ˆ  d ˆ › |› ¡‘qS )Úb_lrñ   rê   ró   r   r   rd   d  re   rõ   rZ   rö   rø   rì   rù   r   rd   d  re   c                    s$   g | ]‰ ‡ ‡fd d„t dƒD ƒ‘qS )c                    s    g | ]}ˆ  d ˆ › |› ¡‘qS )Úb_nrñ   rê   ró   r   r   rd   e  re   rõ   rZ   rö   rø   rì   rù   r   rd   e  re   c                    s   g | ]}ˆ   d |› ¡‘qS )Úclub_rñ   rê   rì   r   r   rd   i  re   c                    s   g | ]}ˆ   d |› ¡‘qS )Zcountry_rñ   rê   rì   r   r   rd   j  re   c                    s   g | ]}ˆ   d |› ¡‘qS )Zleague_rñ   rê   rì   r   r   rd   k  re   )r÷   ry   rò   ré   rp   Úat)r    rí   ÚdfÚmap_idxÚnum_cntsrn   Ú	num_clubsr¡   r«   rå   ræ   Úplayers_groupedrë   rç   rî   rï   rð   rú   rû   r–   rª   r    r   rì   r   Ú
create_varC  s6    $þFFFFFFFHzSolvationCore.create_varc                 C   sÚ   |  tj |¡| jk¡ |d  ¡ D ]\}}|  tj |¡dk¡ q$| jdkrÖ| j| j }	i }
|	D ]}|	 	|¡|
|< qb|
 ¡ D ]V\}}|d  
|¡du r¦td|› ƒ‚|d  
|d | g ¡}|  tj |¡|k¡ q~|S )z!Create some essential constraintsrä   rX   Trà   Nzposition not found )ÚAddr   Ú
LinearExprÚSumro   Úitemsr|   r\   rm   Úcountrp   ÚKeyError)r    rþ   rí   rå   rÿ   r  r   ÚidxÚexprÚformation_listÚcntÚposÚnumr   r   r   Úcreate_basic_constraintsn  s    
z&SolvationCore.create_basic_constraintsc              
   C   sš   t | jƒD ]Š\}}g }	|D ]F}
z |	|d  |d |
 g ¡7 }	W q ty^   td|
› ƒ Y q0 q|	g krxtd|› ƒ‚| tj 	|	¡| j
| k¡ q
|S )zCreate country constraint (>=)rß   zcountry not found zcountries not found )rx   r¨   rp   r	  r
   Ú	Exceptionr  r   r  r  r©   )r    rþ   rí   rå   rÿ   r  r   rë   Znation_listr  Únationr   r   r   Úcreate_country_constraint†  s     z'SolvationCore.create_country_constraintc              
   C   sš   t | jƒD ]Š\}}g }	|D ]F}
z |	|d  |d |
 g ¡7 }	W q ty^   td|
› ƒ Y q0 q|	g krxtd|› ƒ‚| tj |	¡| j	| k¡ q
|S )zCreate league constraint (>=)rÞ   zleague not found zleagues not found )
rx   rž   rp   r	  r
   r  r   r  r  rŸ   )r    rþ   rí   rå   rÿ   r  r   rë   Zleague_listr  r    r   r   r   Úcreate_league_constraint•  s     z&SolvationCore.create_league_constraintc              
   C   sš   t | jƒD ]Š\}}g }	|D ]F}
z |	|d  |d |
 g ¡7 }	W q ty^   td|
› ƒ Y q0 q|	g krxtd|› ƒ‚| tj |	¡| j	| k¡ q
|S )zCreate club constraint (>=)rÝ   zclub not found zclubs not found )
rx   r”   rp   r	  r
   r  r   r  r  r•   )r    rþ   rí   rå   rÿ   r  r   rë   Z	club_listr  r–   r   r   r   Úcreate_club_constraint¤  s     z$SolvationCore.create_club_constraintc                    sp   t | jƒD ]`\}}t||d |d k|d |d k@  jƒ}	‡ fdd„|	D ƒ}
| tj |
¡| j| k¡ q
|S )zeCreate constraint for gold TOTW, gold Rare, gold Non Rare,
           silver TOTW, etc (>=).
        râ   r   rã   rX   c                    s   g | ]}ˆ | ‘qS r   r   ©rb   rô   ©rå   r   r   rd   º  re   z<SolvationCore.create_rarity_1_constraint.<locals>.<listcomp>)	rx   r²   rt   Úindexr  r   r  r  r³   )r    rþ   rí   rå   rÿ   r  r   rë   ÚrarityÚidxesr  r   r  r   Úcreate_rarity_1_constraint³  s
    *z(SolvationCore.create_rarity_1_constraintc              	   C   s–  t | jƒD ]„\}}g }	|d dv rF|d  |d  |d d¡g ¡}	n´|d dkr€| jD ]$}
|	|d  |d  |
d¡g ¡7 }	qXnz|d dkrÚtt|d  ¡  ¡ ƒt| jƒ ƒ}|D ]$}
|	|d  |d  |
d¡g ¡7 }	q²n |d  |d  |d d¡g ¡}	|d d	kr&| t	j
 |	¡| j| k¡ q
|d d
krR| t	j
 |	¡| j| k¡ q
|d dkr~| t	j
 |	¡| j| k¡ q
td|d › ƒ‚q
|S )úI[Rare, Common, TOTW, Gold, Silver, Bronze ... etc] , (>=) ,  (<=) , (==).r   )ÚGoldÚSilverÚBronzerâ   éÿÿÿÿZRarerã   ZCommonrX   ÚMinÚMaxÚExactlyú-Min or Max or Exactly not defined for rarity )rx   r¶   rp   r“   rt   ÚsetÚuniqueÚtolistr  r   r  r  r·   r	  )r    rþ   rí   rå   rÿ   r  r   rë   Úrarity_typer  r  Zcommon_raritiesr   r   r   Úcreate_rarity_2_constraint¾  s(    "
$"$ z(SolvationCore.create_rarity_2_constraintc           
      C   sÈ   t | jƒD ]¸\}}|d  |d  |d d¡g ¡}	|d dkr\| tj |	¡| j| k¡ q
|d dkr†| tj |	¡| j| k¡ q
|d dkr°| tj |	¡| j| k¡ q
td|d › ƒ‚q
|S )	r  rã   r   r   rX   r!  r"  r#  r$  )	rx   rº   rp   r  r   r  r  r»   r	  )
r    rþ   rí   rå   rÿ   r  r   rë   r(  r  r   r   r   Úcreate_group_rarity_constraintÚ  s     z,SolvationCore.create_group_rarity_constraintc                 C   s0   |d   ¡ }| tj ||¡| j| j k¡ |S )z2Squad Rating: Min XX (>=) based on average rating.rá   )r'  r  r   r  ÚWeightedSumr¿   ro   )r    rþ   rí   rå   rÿ   r  r   rk   r   r   r   Ú create_squad_rating_constraint_1é  s     z.SolvationCore.create_squad_rating_constraint_1c           
         s¶   |d }|d   ¡ }tj ˆ|¡‰ td|d  ¡ |d  ¡  ˆjd  ƒ‰‡‡fdd„t|ƒD ƒ‰‡ ‡‡‡‡fdd„t|ƒD ƒ tj 	ˆ¡}	ˆ 
ˆ ˆj |	 ˆjˆj ˆj k¡ ˆS )z§Squad Rating: Min XX (>=) based on
        https://www.reddit.com/r/EASportsFC/comments/5osq7k/new_overall_rating_figured_out.
        Probably more accurate.
        r   rá   é–   rX   c                    s    g | ]}ˆ  d ˆ d|› ¡‘qS )r   rÚ   rè   rê   )Úmax_gap_bw_ratingrí   r   r   rd   ý  re   zBSolvationCore.create_squad_rating_constraint_2.<locals>.<listcomp>c                    s6   g | ].\}}ˆ  ˆ| ˆ| | ˆj ˆ  d g¡‘qS )r   )ÚAddMaxEqualityro   )rb   rë   rÕ   )r×   rÚ   rí   rå   r    r   r   rd   þ  re   )r'  r   r  r+  ÚminrÔ   ro   r÷   rx   r  r  r¿   )
r    rþ   rí   rå   rÿ   r  r   rn   rk   Ú
sum_excessr   )r×   rÚ   r.  rí   rå   r    r   Ú create_squad_rating_constraint_2ð  s    (&z.SolvationCore.create_squad_rating_constraint_2c                    s~  |d   ¡  ¡ }i }g }	|D ]f}
|d |
 }|d  |g ¡}ˆ  d| jd|› ¡||< |	 || |
 ¡ ˆ  || tj 	|¡k¡ qtj 	|	¡}‡ fdd„t
t|ƒƒD ƒ}|D ]˜}
|d |
 }|
| j ||  }g }|D ]H}|d | }ˆ  ddd|› ¡}ˆ  ||| || | ¡ | |¡ qØtj 	|¡}ˆ  || || dg¡ q®tj 	|¡}ˆ  || j | | j| j | j k¡ ˆ S )a[  Squad Rating: Min XX (>=).
        Another way to model 'create_squad_rating_constraint_2'.
        This significantly speeds up the model creation time and for some reason
        the solver converges noticeably faster to a good solution, even without a rating filter
        when tested on a single constraint like Squad Rating: Min XX.
        rá   r   ÚRc                    s    g | ]}ˆ   d dd|› ¡‘qS )r   iÜ  rÚ   rè   rê   rì   r   r   rd     re   zBSolvationCore.create_squad_rating_constraint_3.<locals>.<listcomp>i˜:  Útemp)r&  r'  rp   ré   ro   ry   r  r   r  r  r÷   ÚlenÚAddMultiplicationEqualityr/  r¿   )r    rþ   rí   rå   rÿ   r  r   Zrat_listr3  Zrat_exprrÕ   Zrat_idxr  r×   rÚ   ÚlhsZ
rat_expr_1Zrat_1Z	rat_idx_1r4  Úrhsr1  r   rì   r   Ú create_squad_rating_constraint_3  s2    &z.SolvationCore.create_squad_rating_constraint_3c                 C   s‚   |d   ¡ }t| jƒD ]f\}}	g }
t|	|d ƒD ].}||d vrBq0|
|d  |d | g ¡7 }
q0| tj |
¡| j	| k¡ q|S )zMinimum OVR of XX : Min X (>=)rá   rX   )
rÔ   rx   rÀ   r÷   rp   r  r   r  r  rÁ   )r    rþ   rí   rå   rÿ   r  r   Z
MAX_RATINGrë   rk   r  rÕ   r   r   r   Úcreate_min_overall_constraint&  s    z+SolvationCore.create_min_overall_constraintc           0         s   |	d |	d |	d |	d f\}}}}|
d |
d |
d |
d f\}}}}| j | j }g }i i  ‰}g }t|ƒD ]ð}|j|df |j|df |j|df |j|df f\}}}}| ˆ d	|› ¡¡ || ˆ|| < |||| < ||v rÈ| jd
kr
ˆ || dk¡ |j|df dv r2ˆ || dk¡ n”|||  |||   |||   }ˆ d|› ¡} ˆ |dk¡ | ¡ ˆ |dk¡ |  	¡ ¡ ˆ || |k¡ | ¡ ˆ || dk¡ |  	¡ ¡ n$ˆ || dk¡ ˆ || dk¡ ˆ || | j
k¡ || ¡ ˆ d|› ¡‰ˆ ˆ|| || ¡ ˆ ddd|› ¡}!ˆ |!ˆ|| ¡ | |!¡ qng }"t|ƒD ]Ž‰ ˆ |vr€qn|d  |ˆ  g ¡}#|"|#7 }"| jdkrn‡ ‡fdd„tt|#ƒƒD ƒ‰‡‡‡fdd„t|#ƒD ƒ ˆ tj ˆ¡| ˆ ¡k¡ qnddgddgddgd| jgg}$t|ƒD ]2}%|d  |%g ¡}#tt|#ƒt|"ƒ@ ƒ}&g }'t|&ƒD ]z\}}(|j||( df dv r~qZˆ d|› ¡})ˆ |)|(ˆ|( ¡ |j||( df dkrÈ|' d|) ¡ n
|' |)¡ qZtj |'¡}tdƒD ]\}*|$|* d |$|* d  }+},ˆ ||+|,¡ ||% |* ¡ ˆ ||% |*k¡ ||% |* ¡ qêˆ ||% ¡ q$ddgddgddgd| jgg}-|d  |
d  dd¡g ¡}.t|ƒD ]}%|d  |%g ¡}#|#|.7 }#tt|#ƒt|"ƒ@ ƒ}&g }'t|&ƒD ]^\}}(ˆ d|› ¡})ˆ |)|(ˆ|( ¡ |j||( df dv r,|' d|) ¡ n
|' |)¡ qÚtj |'¡}tdƒD ]\}*|-|* d |-|* d  }+},ˆ ||+|,¡ ||% |* ¡ ˆ ||% |*k¡ ||% |* ¡ qNˆ ||% ¡ qœddgddgddgd| jgg}/t|ƒD ]}%|d  |%g ¡}#tt|#ƒt|"ƒ@ ƒ}&g }'t|&ƒD ]^\}}(ˆ d |› ¡})ˆ |)|(ˆ|( ¡ |j||( df d!v rl|' d|) ¡ n
|' |)¡ qtj |'¡}tdƒD ]\}*|/|* d |/|* d  }+},ˆ ||+|,¡ ||% |* ¡ ˆ ||% |*k¡ ||% |* ¡ qŽˆ ||% ¡ qäˆ tj |¡| jk¡ ˆ||fS )"z]Optimize Chemistry (>=)
        (https://www.rockpapershotgun.com/fifa-23-chemistry)
        r   rX   r   rY   rÝ   rÞ   rß   rà   Ú_posTrã   )ÚIconÚbÚplay_posÚ	chem_exprFc                    s    g | ]}ˆ  d ˆ › |› ¡‘qS )r>  rñ   rê   )ÚPosrí   r   r   rd   o  re   z=SolvationCore.create_chemistry_constraint.<locals>.<listcomp>c                    s&   g | ]\}}ˆ  ˆ| |ˆ | ¡‘qS r   )r6  )rb   rë   Úp)Úm_posrí   r>  r   r   rd   p  re   rZ   é   é   )r<  ú	UT HeroesZt_var_cÚRadioactiveé   é   r<  r   Zt_var_l)rE  rF  Zt_var_n)r<  rF  )r[   rm   r÷   rý   ry   rò   r|   r  ÚOnlyEnforceIfÚNotrÇ   r6  ré   r%  rp   r5  rx   r   r  r  r  ro   rt   ZAddLinearConstraintZAddExactlyOnerÅ   )0r    rþ   rí   ræ   rç   rî   rï   rå   r  r   rÿ   rð   rú   rû   rn   r  r¡   r«   Z	club_dictZleague_dictZcountry_dictZpos_dictr  r  Zm_idxr?  rë   Zp_clubZp_leagueZp_nationZp_posZsum_exprr=  Zplayer_chem_exprZpos_exprZt_exprZclub_bucketrô   Zt_expr_1r  rA  Zt_varr
  ÚlbZubZleague_bucketZ
icons_exprZcountry_bucketr   )r@  rB  rí   r>  r   Úcreate_chemistry_constraint3  sÂ    $$
<
$
 $$$z)SolvationCore.create_chemistry_constraintc           
      C   sB   |d }t |ƒD ],}|d  |g ¡}	| tj |	¡| jk¡ q|S )z>Same Club Count: Max X / Max X Players from the Same Club (<=)rX   rÝ   )r÷   rp   r  r   r  r  r™   )
r    rþ   rí   rå   rÿ   r  r   r  rë   r  r   r   r   Úcreate_max_club_constraint½  s
    z(SolvationCore.create_max_club_constraintc           
      C   sB   |d }t |ƒD ],}|d  |g ¡}	| tj |	¡| jk¡ q|S )zBSame League Count: Max X / Max X Players from the Same League (<=)r   rÞ   )r÷   rp   r  r   r  r  r£   )
r    rþ   rí   rå   rÿ   r  r   r¡   rë   r  r   r   r   Úcreate_max_league_constraintÆ  s
    z*SolvationCore.create_max_league_constraintc           
      C   sB   |d }t |ƒD ],}|d  |g ¡}	| tj |	¡| jk¡ q|S )zBSame Nation Count: Max X / Max X Players from the Same Nation (<=)rY   rß   )r÷   rp   r  r   r  r  r­   )
r    rþ   rí   rå   rÿ   r  r   r«   rë   r  r   r   r   Úcreate_max_country_constraintÏ  s
    z+SolvationCore.create_max_country_constraintc                    s’   |d }‡ fdd„t |ƒD ƒ}t |ƒD ]\}	|d  |	g ¡}
ˆ  tj |
¡| jk¡ ||	 ¡ ˆ  tj |
¡| jk ¡ ||	  ¡ ¡ q&ˆ  	|¡ ˆ S )z>Same Club Count: Min X / Min X Players from the Same Club (>=)rX   c                    s   g | ]}ˆ   d |› ¡‘qS )ÚB_Crñ   rê   rì   r   r   rd   Ü  re   z<SolvationCore.create_min_club_constraint.<locals>.<listcomp>rÝ   )
r÷   rp   r  r   r  r  r›   rI  rJ  ÚAddAtLeastOne)r    rþ   rí   rå   rÿ   r  r   r  rP  rë   r  r   rì   r   Úcreate_min_club_constraintØ  s    "(
z(SolvationCore.create_min_club_constraintc                    s’   |d }‡ fdd„t |ƒD ƒ}t |ƒD ]\}	|d  |	g ¡}
ˆ  tj |
¡| jk¡ ||	 ¡ ˆ  tj |
¡| jk ¡ ||	  ¡ ¡ q&ˆ  	|¡ ˆ S )zBSame League Count: Min X / Min X Players from the Same League (>=)r   c                    s   g | ]}ˆ   d |› ¡‘qS )ÚB_Lrñ   rê   rì   r   r   rd   è  re   z>SolvationCore.create_min_league_constraint.<locals>.<listcomp>rÞ   )
r÷   rp   r  r   r  r  r¥   rI  rJ  rQ  )r    rþ   rí   rå   rÿ   r  r   r¡   rS  rë   r  r   rì   r   Úcreate_min_league_constraintä  s    "(
z*SolvationCore.create_min_league_constraintc                    s’   |d }‡ fdd„t |ƒD ƒ}t |ƒD ]\}	|d  |	g ¡}
ˆ  tj |
¡| jk¡ ||	 ¡ ˆ  tj |
¡| jk ¡ ||	  ¡ ¡ q&ˆ  	|¡ ˆ S )zBSame Nation Count: Min X / Min X Players from the Same Nation (>=)rY   c                    s   g | ]}ˆ   d |› ¡‘qS )ÚB_Nrñ   rê   rì   r   r   rd   ô  re   z?SolvationCore.create_min_country_constraint.<locals>.<listcomp>rß   )
r÷   rp   r  r   r  r  r¯   rI  rJ  rQ  )r    rþ   rí   rå   rÿ   r  r   r«   rU  rë   r  r   rì   r   Úcreate_min_country_constraintð  s    "(
z+SolvationCore.create_min_country_constraintc                 C   sú   |d }t |ƒD ]X}	|d  |	g ¡}
| tj |
¡dk¡ ||	 ¡ | tj |
¡dk¡ ||	  ¡ ¡ q| jd dkr–| tj |¡| jd k¡ n`| jd dkrÂ| tj |¡| jd k¡ n4| jd dkrî| tj |¡| jd k¡ nt	dƒ |S )zClubs: Max / Min / Exactly XrX   rÝ   r   r!  r"  r#  z+**Couldn't create unique_club_constraint!**)
r÷   rp   r  r   r  r  rI  rJ  rœ   r
   )r    rþ   rí   rå   r–   rÿ   r  r   r  rë   r  r   r   r   Úcreate_unique_club_constraintü  s     &z+SolvationCore.create_unique_club_constraintc                 C   sú   |d }t |ƒD ]X}	|d  |	g ¡}
| tj |
¡dk¡ ||	 ¡ | tj |
¡dk¡ ||	  ¡ ¡ q| jd dkr–| tj |¡| jd k¡ n`| jd dkrÂ| tj |¡| jd k¡ n4| jd dkrî| tj |¡| jd k¡ nt	dƒ |S )	zLeagues: Max / Min / Exactly Xr   rÞ   rX   r   r!  r"  r#  z-**Couldn't create unique_league_constraint!**)
r÷   rp   r  r   r  r  rI  rJ  r¦   r
   )r    rþ   rí   rå   r    rÿ   r  r   r¡   rë   r  r   r   r   Úcreate_unique_league_constraint  s     &z-SolvationCore.create_unique_league_constraintc                 C   sú   |d }t |ƒD ]X}	|d  |	g ¡}
| tj |
¡dk¡ ||	 ¡ | tj |
¡dk¡ ||	  ¡ ¡ q| jd dkr–| tj |¡| jd k¡ n`| jd dkrÂ| tj |¡| jd k¡ n4| jd dkrî| tj |¡| jd k¡ nt	dƒ |S )	zNations: Max / Min / Exactly XrY   rß   rX   r   r!  r"  r#  z.**Couldn't create unique_country_constraint!**)
r÷   rp   r  r   r  r  rI  rJ  r°   r
   )r    rþ   rí   rå   rª   rÿ   r  r   r«   rë   r  r   r   r   Ú create_unique_country_constraint   s     &z.SolvationCore.create_unique_country_constraintc                    s¤   t ||d dk jƒ}|s&tdƒ |S ‡ fdd„|D ƒ}tj |¡}| jrf| |t| j	t
|ƒƒk¡ n:| jrŒ| d| t| j	t
|ƒƒk¡ n| jr | |dk¡ |S )NÚIsDuplicateTz**No Duplicates Found!**c                    s   g | ]}ˆ | ‘qS r   r   r  r  r   r   rd   8  re   z7SolvationCore.prioritize_duplicates.<locals>.<listcomp>r   rX   )rt   r  r
   r   r  r  rŒ   r  r0  ro   r5  rŽ   r   )r    rþ   rí   rå   Z	dup_idxesÚ
duplicatesZdup_exprr   r  r   Úprioritize_duplicates2  s     z#SolvationCore.prioritize_duplicatesc                    sŒ   | j s
|S g }| j D ]V}t||d |d k jƒ}|sB| |¡ q‡ fdd„|D ƒ}| tj |¡dk¡ q|rˆtd|› dƒ tdƒ |S )	z*Fix specific players and optimize the restÚOriginal_Idxr   c                    s   g | ]}ˆ | ‘qS r   r   r  r  r   r   rd   M  re   z-SolvationCore.fix_players.<locals>.<listcomp>rX   z2**Couldn't fix the following players with Row_ID: z**z+**They may have already been filtered out**)	r€   rt   r  ry   r  r   r  r  r
   )r    rþ   rí   rå   Zmissing_playersr
  r  Zplayers_to_fixr   r  r   r}   B  s    

zSolvationCore.fix_playersc                    sð   |d   ¡ ‰ |d   ¡ }| jrptdƒ | d|d  ¡ d¡}‡ ‡fdd„ttˆ ƒƒD ƒ}| ||¡ | |¡ n|| j	r”tdƒ | 
tj ˆˆ ¡¡ nX| jd	kr¼td
ƒ | tj ˆˆ ¡¡ n0| jdkrätdƒ | tj ˆ|¡¡ ntdƒ‚|S )zySet objective based on player cost.
        The default behaviour of the solver is to minimize the overall cost.
        ÚCostrá   z**MINIMIZE_MAX_COST**r   Úmax_costc                    s   g | ]}ˆ| ˆ |  ‘qS r   r   rê   ©Úcostrå   r   r   rd   `  re   z/SolvationCore.set_objective.<locals>.<listcomp>z**MAXIMIZE_TOTAL_COST**ra  z**MINIMIZE_TOTAL_COST**rk   z**MINIMIZE_TOTAL_RATE**zSet MINIMIZE_OBJECTIVE)r'  r„   r
   ré   rÔ   r÷   r5  r/  ZMinimizer†   ZMaximizer   r  r+  rÈ   r  )r    rþ   rí   rå   rk   r_  Z	play_costr   r`  r   Úset_objectiveV  s&    

zSolvationCore.set_objectivec                 C   s.   i }||   ¡ }t|ƒD ]\}}|||< q|S )zMap fields to a unique index)r&  rx   )r    rþ   ÚcolÚdZ
unique_colrë   Úvalr   r   r   Úget_dictq  s
    
zSolvationCore.get_dictc                 C   sÐ  |j d |j ¡ |j ¡ |j ¡ g}i }g d¢}|D ]}|  ||¡||< q4t ¡ }|  ||||¡\}}}}	}
}}}}}}}}|  	||||||¡}| j
rª|  ||||||¡}| jrÄ|  ||||||¡}| jrÞ|  ||||||¡}| jrú|  |||||||¡}| jr|  ||||||¡}| jr2|  ||||||¡}| jrN|  ||||||¡}| jrl|  |||||||¡}| jrˆ|  ||||||¡}| jr¤|  ||||||¡}| jrÀ|  ||||||¡}| j rÞ|  !|||||||¡}| j"rú|  #||||||¡}| j$r|  %||||||¡}| j&r2|  '||||||¡}| j(rN|  )||||||¡}| j*rj|  +||||||¡}| j,s‚| j-s‚| j.r|  /|||¡}|  0||||	|
||||||||¡\}}}| j1rÎ|  2|||¡}|  3|||¡}|d  4| j5¡ 6¡ | j5 }d}|| j(k r:d|› d| j(› }| j7r.t8| j7|ƒ nt9|ƒ d}t6|d  4| j5¡ƒ}|| j(| j5 k r‚| j7rvt8| j7dƒ nt9dƒ d}|r¤| j:| | _;| j<| | _=g S t9dƒ t >¡ }d	|j?_@| jA|j?_Ad
|j?_Bd|j?_C| D|tEdd¡}| j:| | _;| j<| | _=| j7r"t8| j7d|d| j:| ƒ n t9d|ƒ t9| j:| ƒ t9dƒ g }|dksZ|dkrÌd|d< d|d< tF|d ƒD ]T}| G|| ¡dkrv| H|¡ | G|| ¡|jI|df< | G|| ¡|jI|df< qv|S )z1Optimize SBC using Constraint Integer Programmingr   rÜ   rá   z.Problem is infeasible: max possible rating is z, but required is rY   z3Impossible to meet SQUAD_RATING with given players.zSolve Startedé*   TrH  é<   r   zsbc solver status : z - z	status : Ú
r   rZ   Z	ChemistryÚIs_PosrX   )JÚshaperÝ   ÚnuniquerÞ   rß   rf  r   ZCpModelr  r  r”   r  r™   rM  r›   rR  rœ   rW  rž   r  r£   rN  r¥   rT  r¦   rX  r¨   r  r­   rO  r¯   rV  r°   rY  r²   r  r¶   r)  rº   r*  r¿   r9  rÀ   r:  rŒ   rŽ   r   r\  rL  r€   r}   rb  Únlargestro   rÙ   rÍ   r   r
   r]   rÏ   r^   rÐ   ZCpSolverÚ
parametersZrandom_seedrÎ   Zlog_search_progressZnum_search_workersZSolver   r÷   ÚValuery   Úloc)r    rþ   r   rÿ   ÚfieldsÚfieldrí   rå   ræ   rç   rî   rï   rð   rú   rû   r–   rª   r    r  r  r?  Zmax_possible_ratingZ
pre_statusÚ
error_textZtotal_minimum_ratingÚsolverÚstatusÚfinal_playersrë   r   r   r   rt  y  s´    $*(


zSolvationCore.solver©rþ   c                    sÜ  ˆ j ddddœd‰ ˆ d  dd„ ¡ˆ d	< ˆ  d
d	ˆ  d	¡¡ | jr*| jd dkrt| jd dv rrˆ ˆ d	 dk ‰ n¶| jd dkrú| jd dv r®ˆ ˆ d	 dkˆ d	 dkB  ‰ nJ| jd dv rÚˆ ˆ d	 dkˆ d	 dkB  ‰ n| jd dv røˆ ˆ d	 dk ‰ n0| jd dkr*| jd dv r*ˆ ˆ d	 dk ‰ | jrÖ| jsÖˆ d | jd k}| jrnˆ d  dd„ | jD ƒ¡nd}| j	r”ˆ d  dd„ | j	D ƒ¡nd}| j
rºˆ d  dd„ | j
D ƒ¡nd}||B |B }ˆ ||B  ‰ | jr‡ fdd„| jD ƒ| _ˆ j| jdd | jr2ˆ j dd id‰ ˆ  dd ˆ  d ¡¡ n‚| jrŽˆ jdgdd!‰ ˆ j d"d id‰ ˆ  dd ˆ  d ¡¡ ˆ d  j d#¡ˆ d < ˆ  d ¡‰ n&| jr´ˆ d$ j d#¡ˆ d$< ˆ  d$¡‰ ˆ jˆ d%< ˆ jdd& d'd'd(d)œ¡‰ ˆ S )*Nrß   rÝ   r^  )ÚNationÚTeamÚExternalPrice)Úcolumnsrá   c                 S   s,   | dk rdS d|   kr dkr(n ndS dS )NéA   r  éJ   r  r  r   )Úxr   r   r   Ú<lambda>  re   z1SolvationCore.preprocess_data_3.<locals>.<lambda>râ   r   r   r  rX   )r"  r#  r  )r!  r  )r"  )r#  )r!  r#  rZ   c                 S   s   g | ]}|D ]}|‘qqS r   r   ©rb   ÚsublistÚitemr   r   r   rd   ?  re   z3SolvationCore.preprocess_data_3.<locals>.<listcomp>FrÞ   c                 S   s   g | ]}|D ]}|‘qqS r   r   r€  r   r   r   rd   A  re   c                 S   s   g | ]}|D ]}|‘qqS r   r   r€  r   r   r   rd   C  re   c                    s"   g | ]}|d  ˆ j v r|d  ‘qS )r   )r  )rb   r
  rw  r   r   rd   S  re   T)ÚinplaceÚPreferredPositionrà   )ÚaxisÚAlternatePositionsrf   ÚRarityGroupr]  )ÚdropÚint32Ústr)rá   r^  rã   )ÚrenameÚapplyÚinsertÚpoprÉ   r¿   rÌ   r¨   Úisinrž   r”   r‚   rˆ  rˆ   rŠ   rŠ  rs   Úexploderº   r  Úreset_indexÚastype)r    rþ   Zrating_conditionZcountry_conditionZleague_conditionZclub_conditionZspecial_conditionr   rw  r   Úpreprocess_data_3  sr    ÿÿÿÿÿÿÿÿÿ

zSolvationCore.preprocess_data_3c                 O   s    | j rt| j |ƒ nt|ƒ d S r   )rÍ   r   r
   )r    Zlog_callbackr   r   r   r   r   Úlog_new_printf  s    zSolvationCore.log_new_printN)'r   r(   r)   r   r   rÓ   rÛ   r   r  r  r  r  r  r  r)  r*  r,  r2  r9  r:  rL  rM  rN  rO  rR  rT  rV  rW  rX  rY  r\  r}   rb  rf  rt  ÚpdÚ	DataFramer“  r”  r   r   r   r   r-   0   sz   W 4
*










"

 













 "Kr-   )r~   r   Ú	threadingr   Úpandasr•  Zortools.sat.pythonr   Ú
sbc.modelsr   r   Úutils.realy_public_methodsr   r   r   ZCpSolverSolutionCallbackr   r-   r   r   r   r   Ú<module>   s   