"""Validation functionality for constraints."""fromcollections.abcimportCollectionfromitertoolsimportcombinationsfrombaybe.constraints.baseimportConstraintfrombaybe.constraints.continuousimportContinuousCardinalityConstraintfrombaybe.constraints.discreteimport(DiscreteDependenciesConstraint,)frombaybe.parameters.baseimportParameter
[docs]defvalidate_constraints(# noqa: DOC101, DOC103constraints:Collection[Constraint],parameters:Collection[Parameter])->None:"""Assert that a given collection of constraints is valid. Raises: ValueError: If there is more than one :class:`baybe.constraints.discrete.DiscreteDependenciesConstraint` declared. ValueError: If any two continuous cardinality constraints have an overlapping parameter set. ValueError: If any constraint contains an invalid parameter name. ValueError: If any continuous constraint includes a discrete parameter. ValueError: If any discrete constraint includes a continuous parameter. ValueError: If any discrete constraint that is valid only for numerical discrete parameters includes non-numerical discrete parameters. """ifsum(isinstance(itm,DiscreteDependenciesConstraint)foritminconstraints)>1:raiseValueError(f"There is only one {DiscreteDependenciesConstraint.__name__} allowed. "f"Please specify all dependencies in one single constraint.")validate_cardinality_constraints_are_nonoverlapping([conforconinconstraintsifisinstance(con,ContinuousCardinalityConstraint)])param_names_all=[p.nameforpinparameters]param_names_discrete=[p.nameforpinparametersifp.is_discrete]param_names_continuous=[p.nameforpinparametersifp.is_continuous]param_names_non_numerical=[p.nameforpinparametersifnotp.is_numerical]forconstraintinconstraints:ifnotall(pinparam_names_allforpinconstraint.parameters):raiseValueError(f"You are trying to create a constraint with at least one parameter "f"name that does not exist in the list of defined parameters. "f"Parameter list of the affected constraint: {constraint.parameters}")ifconstraint.is_continuousandany(pinparam_names_discreteforpinconstraint.parameters):raiseValueError(f"You are trying to initialize a continuous constraint over a "f"parameter that is discrete. Parameter list of the affected "f"constraint: {constraint.parameters}")ifconstraint.is_discreteandany(pinparam_names_continuousforpinconstraint.parameters):raiseValueError(f"You are trying to initialize a discrete constraint over a parameter "f"that is continuous. Parameter list of the affected constraint: "f"{constraint.parameters}")ifconstraint.numerical_onlyandany(pinparam_names_non_numericalforpinconstraint.parameters):raiseValueError(f"You are trying to initialize a constraint of type "f"'{constraint.__class__.__name__}', which is valid only for numerical "f"discrete parameters, over a non-numerical parameter. "f"Parameter list of the affected constraint: {constraint.parameters}.")
[docs]defvalidate_cardinality_constraints_are_nonoverlapping(constraints:Collection[ContinuousCardinalityConstraint],)->None:"""Validate that cardinality constraints are non-overlapping. Args: constraints: A collection of continuous cardinality constraints. Raises: ValueError: If any two continuous cardinality constraints have an overlapping parameter set. """forc1,c2incombinations(constraints,2):if(s1:=set(c1.parameters)).intersection(s2:=set(c2.parameters)):raiseValueError(f"Constraints of type `{ContinuousCardinalityConstraint.__name__}` "f"cannot share the same parameters. Found the following overlapping "f"parameter sets: {s1}, {s2}.")