Storm
A Modern Probabilistic Model Checker
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
StateSetAbstractor.cpp
Go to the documentation of this file.
2
4
6
9
10#include "storm-config.h"
12
13namespace storm::gbar {
14namespace abstraction {
15
16template<storm::dd::DdType DdType, typename ValueType>
18 std::vector<storm::expressions::Expression> const& statePredicates,
19 std::shared_ptr<storm::utility::solver::SmtSolverFactory> const& smtSolverFactory)
20 : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())),
21 abstractionInformation(abstractionInformation),
22 localExpressionInformation(abstractionInformation),
23 relevantPredicatesAndVariables(),
24 concretePredicateVariables(),
25 forceRecomputation(true),
26 cachedBdd(abstractionInformation.getDdManager().getBddOne()),
27 constraint(abstractionInformation.getDdManager().getBddOne()) {
28 for (auto const& constraint : abstractionInformation.getConstraints()) {
29 smtSolver->add(constraint);
30 }
31
32 // Assert all state predicates.
33 for (auto const& predicate : statePredicates) {
34 smtSolver->add(predicate);
35
36 // Extract the variables of the predicate, so we know which variables were used when abstracting.
37 std::set<storm::expressions::Variable> usedVariables = predicate.getVariables();
38 concretePredicateVariables.insert(usedVariables.begin(), usedVariables.end());
39 }
40 localExpressionInformation.relate(concretePredicateVariables);
41}
42
43template<storm::dd::DdType DdType, typename ValueType>
44void StateSetAbstractor<DdType, ValueType>::addMissingPredicates(std::set<uint_fast64_t> const& newRelevantPredicateIndices) {
45 std::vector<std::pair<storm::expressions::Variable, uint_fast64_t>> newPredicateVariables =
46 this->getAbstractionInformation().declareNewVariables(relevantPredicatesAndVariables, newRelevantPredicateIndices);
47
48 for (auto const& element : newPredicateVariables) {
49 smtSolver->add(storm::expressions::iff(element.first, this->getAbstractionInformation().getPredicateByIndex(element.second)));
50 decisionVariables.push_back(element.first);
51 }
52
53 relevantPredicatesAndVariables.insert(relevantPredicatesAndVariables.end(), newPredicateVariables.begin(), newPredicateVariables.end());
54 std::sort(relevantPredicatesAndVariables.begin(), relevantPredicatesAndVariables.end(),
55 [](std::pair<storm::expressions::Variable, uint_fast64_t> const& firstPair,
56 std::pair<storm::expressions::Variable, uint_fast64_t> const& secondPair) { return firstPair.second < secondPair.second; });
57}
58
59template<storm::dd::DdType DdType, typename ValueType>
60void StateSetAbstractor<DdType, ValueType>::refine(std::vector<uint_fast64_t> const& newPredicates) {
61 // Make the partition aware of the new predicates, which may make more predicates relevant to the abstraction.
62 for (auto const& predicateIndex : newPredicates) {
63 localExpressionInformation.addExpression(predicateIndex);
64 }
65
66 std::set<uint_fast64_t> newRelevantPredicateIndices = localExpressionInformation.getRelatedExpressions(concretePredicateVariables);
67
68 // Since the number of relevant predicates is monotonic, we can simply check for the size here.
69 STORM_LOG_ASSERT(newRelevantPredicateIndices.size() >= relevantPredicatesAndVariables.size(), "Illegal size of relevant predicates.");
70 if (newRelevantPredicateIndices.size() > relevantPredicatesAndVariables.size()) {
71 // Before adding the missing predicates, we need to remove the constraint BDD.
72 this->popConstraintBdd();
73
74 // If we need to recompute the BDD, we start by introducing decision variables and the corresponding
75 // constraints in the SMT problem.
76 addMissingPredicates(newRelevantPredicateIndices);
77
78 // Then re-add the constraint BDD.
79 this->pushConstraintBdd();
80 forceRecomputation = true;
81 }
82}
83
84template<storm::dd::DdType DdType, typename ValueType>
86 smtSolver->add(constraint);
87}
88
89template<storm::dd::DdType DdType, typename ValueType>
91 // If the constraint is different from the last one, we add it to the solver.
92 if (newConstraint != this->constraint) {
93 constraint = newConstraint;
94 this->pushConstraintBdd();
95 }
96}
97
98template<storm::dd::DdType DdType, typename ValueType>
100 storm::dd::Bdd<DdType> result = this->getAbstractionInformation().getDdManager().getBddOne();
101 for (auto const& variableIndexPair : relevantPredicatesAndVariables) {
102 if (model.getBooleanValue(variableIndexPair.first)) {
103 result &= this->getAbstractionInformation().encodePredicateAsSource(variableIndexPair.second);
104 } else {
105 result &= !this->getAbstractionInformation().encodePredicateAsSource(variableIndexPair.second);
106 }
107 }
108 return result;
109}
110
111template<storm::dd::DdType DdType, typename ValueType>
112void StateSetAbstractor<DdType, ValueType>::recomputeCachedBdd() {
113 STORM_LOG_TRACE("Recomputing BDD for state set abstraction.");
114
115 storm::dd::Bdd<DdType> result = this->getAbstractionInformation().getDdManager().getBddZero();
116 smtSolver->allSat(decisionVariables, [&result, this](storm::solver::SmtSolver::ModelReference const& model) {
117 result |= getStateBdd(model);
118 return true;
119 });
120
121 cachedBdd = result;
122}
123
124template<storm::dd::DdType DdType, typename ValueType>
125void StateSetAbstractor<DdType, ValueType>::popConstraintBdd() {
126 // If the last constraint was not the constant one BDD, we need to pop the constraint from the solver.
127 if (this->constraint.isOne()) {
128 return;
129 }
130 smtSolver->pop();
131}
132
133template<storm::dd::DdType DdType, typename ValueType>
134void StateSetAbstractor<DdType, ValueType>::pushConstraintBdd() {
135 if (this->constraint.isOne()) {
136 return;
137 }
138
139 // Create a new backtracking point before adding the constraint.
140 smtSolver->push();
141
142 // Create the constraint.
143 std::pair<std::vector<storm::expressions::Expression>, std::unordered_map<uint_fast64_t, storm::expressions::Variable>> result =
144 constraint.toExpression(this->getAbstractionInformation().getExpressionManager());
145
146 // Then add the constraint.
147 for (auto const& expression : result.first) {
148 smtSolver->add(expression);
149 }
150
151 // Finally associate the level variables with the predicates.
152 for (auto const& indexVariablePair : result.second) {
153 smtSolver->add(
154 storm::expressions::iff(indexVariablePair.second, this->getAbstractionInformation().getPredicateForDdVariableIndex(indexVariablePair.first)));
155 }
156}
157
158template<storm::dd::DdType DdType, typename ValueType>
160 if (forceRecomputation) {
161 this->recomputeCachedBdd();
162 }
163 return cachedBdd;
164}
165
166template<storm::dd::DdType DdType, typename ValueType>
168 return abstractionInformation.get();
169}
170
171template<storm::dd::DdType DdType, typename ValueType>
172AbstractionInformation<DdType> const& StateSetAbstractor<DdType, ValueType>::getAbstractionInformation() const {
173 return abstractionInformation.get();
174}
175
176template class StateSetAbstractor<storm::dd::DdType::CUDD, double>;
177template class StateSetAbstractor<storm::dd::DdType::Sylvan, double>;
178#ifdef STORM_HAVE_CARL
179template class StateSetAbstractor<storm::dd::DdType::Sylvan, storm::RationalNumber>;
180#endif
181} // namespace abstraction
182} // namespace storm::gbar
std::pair< std::vector< storm::expressions::Expression >, std::unordered_map< uint_fast64_t, storm::expressions::Variable > > toExpression(storm::expressions::ExpressionManager &manager) const
Translates the function the BDD is representing to a set of expressions that characterize the functio...
Definition Bdd.cpp:502
DdManager< LibraryType > & getDdManager() const
Retrieves the manager that is responsible for this DD.
Definition Dd.cpp:39
std::vector< storm::expressions::Expression > const & getConstraints() const
Retrieves a list of expressions that constrain the valid variable values.
void constrain(storm::expressions::Expression const &constraint)
Constrains the abstract states with the given expression.
void refine(std::vector< uint_fast64_t > const &newPredicateIndices)
Refines the abstractor by making the given predicates new abstract predicates.
storm::dd::Bdd< DdType > getAbstractStates()
Retrieves the set of abstract states matching all predicates added to this abstractor.
StateSetAbstractor(StateSetAbstractor const &other)=default
The base class for all model references.
Definition SmtSolver.h:31
virtual bool getBooleanValue(storm::expressions::Variable const &variable) const =0
#define STORM_LOG_TRACE(message)
Definition logging.h:17
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
Expression iff(Expression const &first, Expression const &second)