11from enum import Enum
2+ from typing import Any
23from typing_extensions import Self
34from pydantic import BaseModel , RootModel , ConfigDict , model_validator
45
@@ -98,7 +99,7 @@ class Implementation(Thing):
9899 description : str
99100 links : list [Link ] | None = None
100101 language : str | None = None
101- evaluation_time : str | None = None
102+ evaluation_time : set [ str ] | None = None
102103 requirements : str | list [str ] | None = None
103104
104105
@@ -118,6 +119,7 @@ class ProblemLike(Thing):
118119 can_evaluate_objectives_independently : YesNoSome | None = None
119120 modality : set [str ] | None = None
120121 fidelity_levels : set [int ] | None = None
122+ evaluation_time : set [str ] | None = None
121123 code_examples : set [str ] | None = None
122124 source : set [str ] | None = None
123125
@@ -152,35 +154,32 @@ def _check_id_references(self, ids, type: OPLType) -> None:
152154 else :
153155 raise ValueError (f"Missing { type .name } with id '{ id } '" )
154156
155- # For a given suite, make sure the fidelty_levels property contains
156- # the fidelity_levels of all problems in the suite.
157- def _fixup_suite_fidelity (self , suite : Suite ):
158- if suite .problems :
159- if not suite .fidelity_levels :
160- suite .fidelity_levels = set ()
161- for pid in suite .problems :
162- problem = self .root [pid ]
163- assert isinstance (problem , Problem )
164- if problem .fidelity_levels :
165- suite .fidelity_levels .update (problem .fidelity_levels )
166-
167- return suite
168-
169- def _fixup_suite_variables (self , suite : Suite ):
170- if not suite .problems :
157+ def _percolate_set (self , thing : Any , children : set | None , property : str ):
158+ """Propagate some `property` from child objects to the parent by calculating the union of all the child property sets.
159+
160+ This is useful to propagate properties like `variables`, `constraints`, etc. from problems up to the suite.
161+ """
162+ if children is None :
171163 return
172164
173- if suite .variables is None :
174- suite .variables = set ()
175- for pid in suite .problems :
176- problem = self .root [pid ]
177- assert isinstance (problem , Problem )
178- if problem .variables is not None :
179- suite .variables .update (problem .variables )
165+ if getattr (thing , property , None ) is None :
166+ setattr (thing , property , set ())
167+ thing_set = getattr (thing , property )
168+
169+ for child_id in children :
170+ child = self .root [child_id ]
171+ child_set = getattr (child , property , None )
172+ if child_set is not None :
173+ thing_set .update (child_set )
180174
181175 @model_validator (mode = "after" )
182176 def _validate (self ) -> Self :
183- # Make sure all problems referenced in suites exists
177+ # First check and fixup all problems
178+ for id , thing in self .root .items ():
179+ if isinstance (thing , Problem ) and thing .implementations :
180+ self ._percolate_set (thing , thing .implementations , "evaluation_time" )
181+
182+ # Then check and fixup all suites because changes from the problems need to propagate to the suites
184183 for id , thing in self .root .items ():
185184 if isinstance (thing , Suite ) and thing .problems :
186185 for problem_id in thing .problems :
@@ -192,7 +191,12 @@ def _validate(self) -> Self:
192191 raise ValueError (
193192 f"Suite { id } references problem with id '{ problem_id } ' but id is a { self .root [problem_id ].type .name } ."
194193 )
195- self ._fixup_suite_fidelity (thing )
194+
195+ self ._percolate_set (thing , thing .problems , "fidelity_levels" )
196+ self ._percolate_set (thing , thing .problems , "variables" )
197+ self ._percolate_set (thing , thing .problems , "constraints" )
198+ self ._percolate_set (thing , thing .problems , "evaluation_time" )
199+
196200 return self
197201
198202
0 commit comments