19using BaseExpression = storm::expressions::BaseExpression;
20using BinaryRelationExpression = storm::expressions::BinaryRelationExpression;
22using Form = storm::expressions::LinearCoefficientVisitor<CoefficientType>::VariableCoefficients;
23using VariablesByName = std::map<std::string, RationalFunctionRegion::VariableType>;
29 RegionWitness minimizingPoint;
30 RegionWitness maximizingPoint;
34Extremes computeExtremes(Form
const& form, VariablesByName
const& variables,
RationalFunctionRegion const& region) {
35 std::set<RationalFunctionRegion::VariableType> increasing;
36 std::set<RationalFunctionRegion::VariableType> decreasing;
37 for (
auto const& [variable, coefficient] : form) {
40 RegionWitness minimizingPoint(region.getPoint(storm::solver::OptimizationDirection::Minimize, increasing, decreasing));
41 RegionWitness maximizingPoint(region.getPoint(storm::solver::OptimizationDirection::Maximize, increasing, decreasing));
45 for (
auto const& [variable, coefficient] : form) {
46 value += coefficient * point.at(variables.at(variable.getName()));
50 return Extremes{
evaluate(minimizingPoint),
evaluate(maximizingPoint), std::move(minimizingPoint), std::move(maximizingPoint)};
56 std::optional<RegionWitness> witness;
60SingleVerdict checkAffineConstraint(RelationType relation, Extremes
const& extremes) {
63 bool satisfiedThroughout;
65 case RelationType::Less:
66 satisfiedThroughout = extremes.maximum <
zero;
68 case RelationType::LessOrEqual:
69 satisfiedThroughout = extremes.maximum <=
zero;
71 case RelationType::Greater:
72 satisfiedThroughout = extremes.minimum >
zero;
74 case RelationType::GreaterOrEqual:
75 satisfiedThroughout = extremes.minimum >=
zero;
77 case RelationType::Equal:
78 satisfiedThroughout = extremes.minimum >=
zero && extremes.maximum <=
zero;
80 case RelationType::NotEqual:
81 satisfiedThroughout = extremes.maximum <
zero || extremes.minimum >
zero;
84 return SingleVerdict{};
87 if (satisfiedThroughout) {
88 return SingleVerdict{ConstraintVerdict::Sat, std::nullopt};
92 case RelationType::Less:
93 case RelationType::LessOrEqual:
94 return SingleVerdict{ConstraintVerdict::Unsat, extremes.maximizingPoint};
95 case RelationType::Greater:
96 case RelationType::GreaterOrEqual:
97 return SingleVerdict{ConstraintVerdict::Unsat, extremes.minimizingPoint};
98 case RelationType::Equal:
100 if (extremes.maximum != zero) {
101 return SingleVerdict{ConstraintVerdict::Unsat, extremes.maximizingPoint};
103 return SingleVerdict{ConstraintVerdict::Unsat, extremes.minimizingPoint};
104 case RelationType::NotEqual: {
105 if (extremes.minimum == zero) {
106 return SingleVerdict{ConstraintVerdict::Unsat, extremes.minimizingPoint};
108 if (extremes.maximum == zero) {
109 return SingleVerdict{ConstraintVerdict::Unsat, extremes.maximizingPoint};
112 CoefficientType const t = extremes.minimum / (extremes.minimum - extremes.maximum);
114 for (
auto const& [variable, value] : extremes.minimizingPoint) {
115 witness.emplace(variable, value + t * (extremes.maximizingPoint.at(variable) - value));
117 return SingleVerdict{ConstraintVerdict::Unsat, std::move(witness)};
120 return SingleVerdict{};
128 for (
auto const& [variable, value] : witness) {
129 out << (first ?
"" :
", ") << variable.name() <<
" = " << value;
138 return checkConstraints(this->collector.getWellformedConstraints(), region,
"well-formedness");
143 auto constraints = this->collector.getWellformedConstraints();
144 auto const& graphPreservingConstraints = this->collector.getGraphPreservingConstraints();
145 constraints.insert(constraints.end(), graphPreservingConstraints.begin(), graphPreservingConstraints.end());
160 VariablesByName variables;
162 variables.emplace(variable.name(), variable);
165 bool violated =
false;
166 bool undecided =
false;
169 BaseExpression
const& baseExpression = constraint.getBaseExpression();
171 SingleVerdict singleVerdict;
172 if (baseExpression.isBooleanLiteralExpression()) {
174 if (baseExpression.asBooleanLiteralExpression().getValue()) {
175 singleVerdict = SingleVerdict{ConstraintVerdict::Sat, std::nullopt};
179 }
else if (baseExpression.isBinaryRelationExpression()) {
180 BinaryRelationExpression
const& relationExpression = baseExpression.asBinaryRelationExpression();
184 if (form.has_value() && rhs.has_value()) {
186 *form -= std::move(*rhs);
188 for (
auto const& [variable, coefficient] : *form) {
189 STORM_LOG_THROW(variables.count(variable.getName()) != 0, storm::exceptions::InvalidArgumentException,
190 "Cannot check " << label <<
" constraint '" << constraint.toString()
191 <<
"' over the given region, because it constrains the variable '" << variable.getName()
192 <<
"', which is not part of the region. Please provide a region covering all constrained variables.");
195 Extremes
const extremes = computeExtremes(*form, variables, region);
196 singleVerdict = checkAffineConstraint(relationExpression.getRelationType(), extremes);
200 switch (singleVerdict.verdict) {
201 case ConstraintVerdict::Sat:
203 case ConstraintVerdict::Unsat:
206 result.
witness = singleVerdict.witness;
210 case ConstraintVerdict::Unknown:
218 result.
verdict = ConstraintVerdict::Unsat;
219 }
else if (undecided) {
220 result.
verdict = ConstraintVerdict::Unknown;
222 result.
verdict = ConstraintVerdict::Sat;
Class to collect constraints on parametric Markov chains.
std::vector< storm::expressions::Expression > ConstraintSet
The type of the collected constraints.
Computes the coefficients of a linear expression.
std::optional< VariableCoefficients > tryGetLinearCoefficients(Expression const &expression)
As getLinearCoefficients, but returns std::nullopt instead of throwing if the expression is not linea...
bool isWellDefined(RationalFunctionRegion const ®ion) const
Returns true iff all well-formedness constraints were proven to hold throughout the region.
RegionCheckResult checkGraphPreservation(RationalFunctionRegion const ®ion) const
Checks the graph-preserving constraints together with the well-formedness constraints,...
RegionConstraintChecker(storm::analysis::ConstraintCollector const &collector)
static RegionCheckResult checkConstraints(storm::analysis::ConstraintCollector::ConstraintSet const &constraints, RationalFunctionRegion const ®ion, std::string const &label)
Checks an arbitrary constraint set over a region.
bool isGraphPreserving(RationalFunctionRegion const ®ion) const
Returns true iff all graph-preserving and well-formedness constraints were proven to hold throughout ...
RegionCheckResult checkWellformedness(RationalFunctionRegion const ®ion) const
std::set< VariableType > const & getVariables() const
Valuation getCenterPoint() const
Returns the center point of this region.
#define STORM_LOG_THROW(cond, exception, message)
RelationType
An enum type specifying the different relations applicable.
storm::storage::ParameterRegion< storm::RationalFunction > RationalFunctionRegion
storm::solver::SmtSolver::CheckResult ConstraintVerdict
Tri-state outcome of a check: Sat means the constraint holds on the whole region, Unsat means it is v...
RationalFunctionRegion::CoefficientType CoefficientType
std::ostream & operator<<(std::ostream &stream, GraphPreservationStatus status)
double evaluate(storm::RationalFunction const &function, Valuation< storm::RationalFunction > const &valuation)
std::optional< RegionWitness > witness
A point at which a constraint is violated.
bool holdsThroughout() const
std::vector< storm::expressions::Expression > undecidedConstraints
All constraints that could not be decided.
ConstraintVerdict verdict
std::optional< storm::expressions::Expression > violatedConstraint
The constraint violated at the witness.
A point of a parameter region, mapping the variables to exact values.