"""Base classes for all parameters."""from__future__importannotationsfromabcimportABC,abstractmethodfromfunctoolsimportcached_property,partialfromtypingimportTYPE_CHECKING,Any,ClassVarimportpandasaspdfromattrsimportdefine,fieldfromattrs.validatorsimportinstance_of,min_lenfromcattrs.genimportoverridefrombaybe.parameters.enumimportParameterEncodingfrombaybe.serializationimport(SerialMixin,converter,get_base_structure_hook,unstructure_base,)ifTYPE_CHECKING:frombaybe.searchspace.continuousimportSubspaceContinuousfrombaybe.searchspace.coreimportSearchSpacefrombaybe.searchspace.discreteimportSubspaceDiscrete# TODO: Reactive slots in all classes once cached_property is supported:# https://github.com/python-attrs/attrs/issues/164
[docs]@define(frozen=True,slots=False)classParameter(ABC,SerialMixin):"""Abstract base class for all parameters. Stores information about the type, range, constraints, etc. and handles in-range checks, transformations etc. """# class variablesis_numerical:ClassVar[bool]"""Class variable encoding whether this parameter is numeric."""# object variablesname:str=field(validator=(instance_of(str),min_len(1)))"""The name of the parameter"""
[docs]@abstractmethoddefis_in_range(self,item:Any)->bool:"""Return whether an item is within the parameter range. Args: item: The item to be checked. Returns: ``True`` if the item is within the parameter range, ``False`` otherwise. """
[docs]@abstractmethoddefsummary(self)->dict:"""Return a custom summarization of the parameter."""
def__str__(self)->str:returnstr(self.summary())@propertydefis_continuous(self)->bool:"""Boolean indicating if this is a continuous parameter."""returnisinstance(self,ContinuousParameter)@propertydefis_discrete(self)->bool:"""Boolean indicating if this is a discrete parameter."""returnisinstance(self,DiscreteParameter)
[docs]defto_searchspace(self)->SearchSpace:"""Create a one-dimensional search space from the parameter."""frombaybe.searchspace.coreimportSearchSpacereturnSearchSpace.from_parameter(self)
[docs]@define(frozen=True,slots=False)classDiscreteParameter(Parameter,ABC):"""Abstract class for discrete parameters."""# TODO [15280]: needs to be refactored# class variablesencoding:ParameterEncoding|None=field(init=False,default=None)"""An optional encoding for the parameter."""@property@abstractmethoddefvalues(self)->tuple:"""The values the parameter can take."""@cached_property@abstractmethoddefcomp_df(self)->pd.DataFrame:"""Return the computational representation of the parameter."""
[docs]defto_subspace(self)->SubspaceDiscrete:"""Create a one-dimensional search space from the parameter."""frombaybe.searchspace.discreteimportSubspaceDiscretereturnSubspaceDiscrete.from_parameter(self)
[docs]defis_in_range(self,item:Any)->bool:# noqa: D102# See base class.returniteminself.values
[docs]deftransform(self,series:pd.Series,/)->pd.DataFrame:"""Transform parameter values from experimental to computational representation. Args: series: The parameter values to be transformed. Returns: The transformed parameter values. """ifself.encoding:# replace each label with the corresponding encodingtransformed=pd.merge(left=series.rename("Labels").to_frame(),left_on="Labels",right=self.comp_df,right_index=True,how="left",).drop(columns="Labels")else:transformed=series.to_frame()returntransformed
[docs]defsummary(self)->dict:# noqa: D102# See base class.param_dict=dict(Name=self.name,Type=self.__class__.__name__,Num_Values=len(self.values),Encoding=self.encoding,)returnparam_dict
[docs]@define(frozen=True,slots=False)classContinuousParameter(Parameter):"""Abstract class for continuous parameters."""
[docs]defto_subspace(self)->SubspaceContinuous:"""Create a one-dimensional search space from the parameter."""frombaybe.searchspace.continuousimportSubspaceContinuousreturnSubspaceContinuous.from_parameter(self)