@@ -108,6 +108,9 @@ class PodiumStep(BaseModel):
108108 abstained : int
109109 timeout : int
110110 memout : int
111+ par2score : float_6dig
112+ par2scoreBase : float_6dig | None
113+ eligibleForWinning : bool
111114
112115
113116class PodiumDivision (BaseModel ):
@@ -149,6 +152,7 @@ class PodiumStepOverallScore(BaseModel):
149152 contribution : float_6dig # nn_D * log10 N_D
150153 division : str
151154 tieBreakTimeScore : float_6dig
155+ eligibleForWinning : bool
152156
153157
154158class PodiumBestOverall (BaseModel ):
@@ -240,25 +244,37 @@ class Podium(RootModel):
240244 root : PodiumDivision | PodiumCrossDivision | PodiumSummaryResults = Field (..., discriminator = "layout" )
241245
242246
243- def podium_steps (config : defs .Config , podium : List [dict [str , Any ]] | None ) -> List [PodiumStep ]:
247+ def podium_steps (config : defs .Config , podium : List [dict [str , Any ]] | None , scoring : str ) -> List [PodiumStep ]:
248+ def par2 (s : dict [str , Any ]) -> Any :
249+ if scoring == smtcomp .scoring .Kind .seq .name :
250+ return s ["cpu_time_score" ] + 2 * config .cpuCores * config .timelimit_s * s ["unsolved" ]
251+ elif scoring == smtcomp .scoring .Kind .twentyfour .name :
252+ return s ["wallclock_time_score" ] + 2 * 24 * s ["unsolved" ]
253+ else :
254+ return s ["wallclock_time_score" ] + 2 * config .timelimit_s * s ["unsolved" ]
255+
244256 if podium is None :
245257 return []
246258 else :
247259 podiums = []
248- non_competitive = []
260+ base_solvers = []
249261 for s in podium :
250- cscore = s ["correctly_solved_score" ]
251- delta = 0
252- derived_solver = defs .Config .baseSolverMap2025 .get (s ["solver" ], "" )
253- if derived_solver != "" :
254- for sprime in podium :
255- if sprime ["solver" ] == defs .Config .baseSolverMap2025 .get (s ["solver" ], "" ):
256- delta = cscore - sprime ["correctly_solved_score" ]
257- break
262+ base = None
263+ for sprime in podium :
264+ if sprime ["solver" ] == s ["solver" ] + "-base" :
265+ base = sprime
266+ break
267+
268+ solver_par2 = par2 (s )
269+ base_par2 = None if base is None else par2 (base )
270+ eligible = s ["solver" ] in config .competitive_solvers and (
271+ base_par2 is None or solver_par2 <= 0.9 * base_par2
272+ )
273+ delta = 0 if base is None else s ["correctly_solved_score" ] - base ["correctly_solved_score" ]
258274
259275 ps = PodiumStep (
260276 name = s ["solver" ],
261- baseSolver = derived_solver ,
277+ baseSolver = base [ "solver" ] if base is not None else "" ,
262278 deltaBaseSolver = delta ,
263279 competing = "yes" if s ["solver" ] in config .competitive_solvers else "no" ,
264280 errorScore = s ["error_score" ],
@@ -272,29 +288,32 @@ def podium_steps(config: defs.Config, podium: List[dict[str, Any]] | None) -> Li
272288 abstained = s ["abstained" ],
273289 timeout = s ["timeout" ],
274290 memout = s ["memout" ],
291+ par2score = solver_par2 ,
292+ par2scoreBase = base_par2 ,
293+ eligibleForWinning = eligible ,
275294 )
276295
277- if not s ["solver" ] in config . competitive_solvers :
278- non_competitive .append (ps )
296+ if s ["solver" ]. endswith ( "-base" ) :
297+ base_solvers .append (ps )
279298 else :
280299 podiums .append (ps )
281300
282- return podiums + non_competitive
301+ return podiums + base_solvers
283302
284303
285304def make_podium (
286305 config : defs .Config , d : dict [str , Any ], for_division : bool , track : defs .Track , results : pl .LazyFrame
287306) -> PodiumDivision :
288- def get_winner (l : List [dict [ str , str ] ] | None ) -> str :
307+ def get_winner (l : List [PodiumStep ] | None ) -> str :
289308 if l is None or not l :
290309 return "-"
291310
292- l = [e for e in l if e [ "solver" ] in config . competitive_solvers ]
311+ l = [s for s in l if s . eligibleForWinning ]
293312
294- if l is None or not l or l [0 ][ "correctly_solved_score" ] == 0 :
313+ if l is None or not l or l [0 ]. correctScore == 0 :
295314 return "-"
296315 else :
297- return l [0 ][ "solver" ]
316+ return l [0 ]. name
298317
299318 def is_competitive_division (results : pl .LazyFrame , division : int , for_division : bool ) -> bool :
300319 """
@@ -312,7 +331,7 @@ def is_competitive_division(results: pl.LazyFrame, division: int, for_division:
312331 )
313332
314333 # Avoid solvers of the same solver family under the assumption
315- # of the following format: <solver-family>-<suffix> (holds for SMT-COMP 2025)
334+ # of the following format: <solver-family>-<suffix> (holds for SMT-COMP 2025/26 )
316335 # TODO: improve this criterion in the future
317336 return len (set ([sol .split ("-" )[0 ].lower () for sol in solvers ])) >= 2
318337
@@ -325,15 +344,25 @@ def is_competitive_division(results: pl.LazyFrame, division: int, for_division:
325344 competitive_division = is_competitive_division (results , d ["logic" ], for_division )
326345 logics = dict ()
327346
347+ steps : dict [str , List [Any ]] = {}
348+
328349 if (track == defs .Track .Cloud ) | (track == defs .Track .Parallel ):
329- winner_seq = "-"
330- steps_seq = []
350+ steps [smtcomp .scoring .Kind .seq .name ] = []
331351 else :
332- winner_seq = get_winner (d [smtcomp .scoring .Kind .seq .name ])
333- steps_seq = podium_steps (config , d [smtcomp .scoring .Kind .seq .name ])
352+ steps [smtcomp .scoring .Kind .seq .name ] = podium_steps (
353+ config , d [smtcomp .scoring .Kind .seq .name ], smtcomp .scoring .Kind .seq .name
354+ )
355+
356+ for score in (
357+ smtcomp .scoring .Kind .par .name ,
358+ smtcomp .scoring .Kind .sat .name ,
359+ smtcomp .scoring .Kind .unsat .name ,
360+ smtcomp .scoring .Kind .twentyfour .name ,
361+ ):
362+ steps [score ] = podium_steps (config , d [score ], score )
334363
335364 return PodiumDivision (
336- resultdate = "2025-08-11 " ,
365+ resultdate = "2026-07-25 " ,
337366 year = config .current_year ,
338367 divisions = f"divisions_{ config .current_year } " ,
339368 is_competitive = competitive_division ,
@@ -345,16 +374,16 @@ def is_competitive_division(results: pl.LazyFrame, division: int, for_division:
345374 time_limit = config .timelimit_s ,
346375 mem_limit = config .memlimit_M ,
347376 logics = dict (sorted (logics .items ())),
348- winner_seq = winner_seq ,
349- winner_par = get_winner (d [smtcomp .scoring .Kind .par .name ]),
350- winner_sat = get_winner (d [smtcomp .scoring .Kind .sat .name ]),
351- winner_unsat = get_winner (d [smtcomp .scoring .Kind .unsat .name ]),
352- winner_24s = get_winner (d [smtcomp .scoring .Kind .twentyfour .name ]),
353- sequential = steps_seq ,
354- parallel = podium_steps ( config , d [smtcomp .scoring .Kind .par .name ]) ,
355- sat = podium_steps ( config , d [smtcomp .scoring .Kind .sat .name ]) ,
356- unsat = podium_steps ( config , d [smtcomp .scoring .Kind .unsat .name ]) ,
357- twentyfour = podium_steps ( config , d [smtcomp .scoring .Kind .twentyfour .name ]) ,
377+ winner_seq = get_winner ( steps [ smtcomp . scoring . Kind . seq . name ]) ,
378+ winner_par = get_winner (steps [smtcomp .scoring .Kind .par .name ]),
379+ winner_sat = get_winner (steps [smtcomp .scoring .Kind .sat .name ]),
380+ winner_unsat = get_winner (steps [smtcomp .scoring .Kind .unsat .name ]),
381+ winner_24s = get_winner (steps [smtcomp .scoring .Kind .twentyfour .name ]),
382+ sequential = steps [ smtcomp . scoring . Kind . seq . name ] ,
383+ parallel = steps [smtcomp .scoring .Kind .par .name ],
384+ sat = steps [smtcomp .scoring .Kind .sat .name ],
385+ unsat = steps [smtcomp .scoring .Kind .unsat .name ],
386+ twentyfour = steps [smtcomp .scoring .Kind .twentyfour .name ],
358387 )
359388
360389
@@ -521,7 +550,7 @@ def get_winner(l: List[PodiumStepBiggestLead] | None) -> str:
521550 winner_seq = get_winner (sequential )
522551
523552 return PodiumBiggestLead (
524- resultdate = "2025-08-11 " ,
553+ resultdate = "2026-07-25 " ,
525554 year = config .current_year ,
526555 track = track ,
527556 results = f"results_{ config .current_year } " ,
@@ -567,6 +596,7 @@ def normalized_correctness_score(
567596 contribution = nn_D * (math .log10 (N_D ) if N_D > 0 else 0 ),
568597 tieBreakTimeScore = sol_in_div .CPUScore if k == smtcomp .scoring .Kind .seq else sol_in_div .WallScore ,
569598 division = division ,
599+ eligibleForWinning = sol_in_div .eligibleForWinning ,
570600 )
571601 )
572602 podiumSteps = sorted (podiumSteps , key = lambda x : (x .contribution , x .tieBreakTimeScore ), reverse = True )
@@ -619,11 +649,19 @@ def get_winner(
619649 if l is None or not l :
620650 return ("-" , 0.0 )
621651 else :
622- podium : DefaultDict [str , Dict [str , float ]] = defaultdict (lambda : {"score" : 0.0 , "tie_break_time" : 0.0 })
652+ podium : DefaultDict [str , Dict [str , Any ]] = defaultdict (
653+ lambda : {"score" : 0.0 , "tie_break_time" : 0.0 , "eligibleForWinning" : False }
654+ )
623655 for entry in l :
624656 podium [entry .name ]["score" ] += entry .contribution
625657 podium [entry .name ]["tie_break_time" ] += entry .tieBreakTimeScore
626- winner , winner_data = max (podium .items (), key = lambda item : (item [1 ]["score" ], - item [1 ]["tie_break_time" ]))
658+ podium [entry .name ]["eligibleForWinning" ] = (
659+ podium [entry .name ]["eligibleForWinning" ] or entry .eligibleForWinning
660+ )
661+ winner , winner_data = max (
662+ filter (lambda i : i [1 ]["eligibleForWinning" ], podium .items ()),
663+ key = lambda item : (item [1 ]["score" ], - item [1 ]["tie_break_time" ]),
664+ )
627665 return (winner , winner_data ["score" ])
628666
629667 sequential = normalized_correctness_score (data , scores , track , smtcomp .scoring .Kind .seq )
@@ -639,7 +677,7 @@ def get_winner(
639677 winner_seq = get_winner (sequential , scores , data , track )
640678
641679 return PodiumBestOverall (
642- resultdate = "2025-08-11 " ,
680+ resultdate = "2026-07-25 " ,
643681 year = config .current_year ,
644682 track = track ,
645683 results = f"results_{ config .current_year } " ,
@@ -737,7 +775,7 @@ def timeScore(vws_step: PodiumStep) -> float:
737775 steps_seq = ld [smtcomp .scoring .Kind .seq ]
738776
739777 return PodiumLargestContribution (
740- resultdate = "2025-08-11 " ,
778+ resultdate = "2026-07-25 " ,
741779 year = config .current_year ,
742780 track = track ,
743781 results = f"results_{ config .current_year } " ,
@@ -786,7 +824,7 @@ def largest_contribution(config: defs.Config, scores: pl.LazyFrame, track: defs.
786824 virtual_datas = sq_generate_datas (config , virtual_scores , for_division , track )
787825
788826 # For each solver Compute virtual solver without the solver
789- solvers = scores .select ("division" , "solver" ).unique ()
827+ solvers = scores .select ("division" , "solver" ).unique (). filter ( pl . col ( "solver" ). is_in ( config . competitive_solvers ))
790828 virtual_without_solver_scores = (
791829 intersect (scores .rename ({"solver" : "other_solver" }), solvers , on = ["division" ])
792830 .filter (pl .col ("solver" ) != pl .col ("other_solver" ))
0 commit comments