[docs]@define(frozen=True,slots=False)classNumericalDiscreteParameter(DiscreteParameter):"""Parameter class for discrete numerical parameters (a.k.a. setpoints)."""# class variablesis_numerical:ClassVar[bool]=True# See base class.# object variables# NOTE: The parameter values are assumed to be sorted by the tolerance validator._values:tuple[float,...]=field(# FIXME[typing]: https://github.com/python-attrs/cattrs/issues/111converter=lambdax:sorted(cattrs.structure(x,tuple[float,...])),# type: ignore# FIXME[typing]: https://github.com/python-attrs/attrs/issues/1197validator=[min_len(2),validate_unique_values,# type: ignorevalidate_is_finite,],)"""The values the parameter can take."""tolerance:float=field(default=0.0)"""The absolute tolerance used for deciding whether a value is in range. A tolerance larger than half the minimum distance between parameter values is not allowed because that could cause ambiguity when inputting data points later."""@tolerance.validatordef_validate_tolerance(# noqa: DOC101, DOC103self,_:Any,tolerance:float)->None:"""Validate that the given tolerance is safe. The tolerance is the allowed experimental uncertainty when reading in measured values. A tolerance larger than half the minimum distance between parameter values is not allowed because that could cause ambiguity when inputting data points later. Raises: ValueError: If the tolerance is not safe. """# For zero tolerance, the only left requirement is that all parameter values# are distinct, which is already ensured by the corresponding validator.iftolerance==0.0:returnmin_dist=np.diff(self._values).min()ifmin_dist==(eps:=np.nextafter(0,1)):raiseNumericalUnderflowError(f"The distance between any two parameter values must be at least "f"twice the size of the used floating point resolution of {eps}.")iftolerance>=(max_tol:=min_dist/2.0):raiseValueError(f"Parameter '{self.name}' is initialized with tolerance {tolerance} "f"but due to the given parameter values {self.values}, the specified "f"tolerance must be smaller than {max_tol} to avoid ambiguity.")@propertydefvalues(self)->tuple:# noqa: D102# See base class.returntuple(DTypeFloatNumpy(itm)foritminself._values)@cached_propertydefcomp_df(self)->pd.DataFrame:# noqa: D102# See base class.comp_df=pd.DataFrame({self.name:self.values},index=self.values,dtype=DTypeFloatNumpy)returncomp_df
[docs]defis_in_range(self,item:float)->bool:# noqa: D102# See base class.differences_acceptable=[np.abs(val-item)<=self.toleranceforvalinself.values]returnany(differences_acceptable)
[docs]@define(frozen=True,slots=False)classNumericalContinuousParameter(ContinuousParameter):"""Parameter class for continuous numerical parameters."""# class variablesis_numerical:ClassVar[bool]=True# See base class.# object variablesbounds:Interval=field(default=None,converter=convert_bounds)"""The bounds of the parameter."""@bounds.validatordef_validate_bounds(self,_:Any,value:Interval)->None:# noqa: DOC101, DOC103"""Validate bounds. Raises: InfiniteIntervalError: If the provided interval is not finite. """ifnotvalue.is_bounded:raiseInfiniteIntervalError(f"You are trying to initialize a parameter with an infinite range "f"of {value.to_tuple()}. Infinite intervals for parameters are "f"currently not supported.")ifvalue.is_degenerate:raiseValueError("The interval specified by the parameter bounds cannot be degenerate.")
[docs]defis_in_range(self,item:float)->bool:# noqa: D102# See base class.returnself.bounds.contains(item)
[docs]defsummary(self)->dict:# noqa: D102# See base class.param_dict=dict(Name=self.name,Type=self.__class__.__name__,Lower_Bound=self.bounds.lower,Upper_Bound=self.bounds.upper,)returnparam_dict