Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
SparseCbAchievabilityQuery.cpp
Go to the documentation of this file.
2
16
17namespace storm {
18namespace modelchecker {
19namespace multiobjective {
20
21template<class SparseModelType>
29
30template<class SparseModelType>
31std::unique_ptr<CheckResult> SparseCbAchievabilityQuery<SparseModelType>::check(Environment const& env) {
32 bool result = this->checkAchievability();
33
34 return std::unique_ptr<CheckResult>(new ExplicitQualitativeCheckResult<ValueType>(this->originalModel.getInitialStates().getNextSetIndex(0), result));
35}
36
37template<class SparseModelType>
38bool SparseCbAchievabilityQuery<SparseModelType>::checkAchievability() {
39 STORM_LOG_INFO("Building constraint system to check achievability.");
40 // this->preprocessedModel->writeDotToStream(std::cout);
41 storm::utility::Stopwatch swInitialization(true);
42 initializeConstraintSystem();
43 STORM_LOG_INFO("Constraint system consists of " << expectedChoiceVariables.size() << " + " << bottomStateVariables.size() << " variables");
44 addObjectiveConstraints();
45 swInitialization.stop();
46
47 storm::utility::Stopwatch swCheck(true);
48 STORM_LOG_INFO("Invoking SMT Solver.");
50 swCheck.stop();
51
52 STORM_LOG_STATISTICS("Building the constraintsystem took " << swInitialization << " seconds and checking the SMT formula took " << swCheck
53 << " seconds.\n");
54
55 switch (result) {
57 // std::cout << "\nSatisfying assignment: \n" << solver->getModelAsValuation().toString(true) << '\n';
58 return true;
60 // std::cout << "\nUnsatisfiability core: {\n";
61 // for (auto const& expr : solver->getUnsatCore()) {
62 // std::cout << "\t " << expr << '\n';
63 // }
64 // std::cout << "}\n";
65 return false;
66 default:
67 STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "SMT solver yielded an unexpected result.");
68 }
69
70 return false;
71}
72
73template<class SparseModelType>
74void SparseCbAchievabilityQuery<SparseModelType>::initializeConstraintSystem() {
75 uint_fast64_t numStates = this->preprocessedModel->getNumberOfStates();
76 uint_fast64_t numChoices = this->preprocessedModel->getNumberOfChoices();
77 uint_fast64_t numBottomStates = this->reward0EStates.getNumberOfSetBits();
78 STORM_LOG_THROW(numBottomStates > 0, storm::exceptions::UnexpectedException, "No bottom states in the preprocessed model.");
79 storm::expressions::Expression zero = this->expressionManager->rational(storm::utility::zero<ValueType>());
80 storm::expressions::Expression one = this->expressionManager->rational(storm::utility::one<ValueType>());
81
82 // Declare the variables for the choices and bottom states
83 expectedChoiceVariables.reserve(numChoices);
84 for (uint_fast64_t choice = 0; choice < numChoices; ++choice) {
85 expectedChoiceVariables.push_back(this->expressionManager->declareRationalVariable("y" + std::to_string(choice)));
86 }
87 bottomStateVariables.reserve(numBottomStates);
88 for (uint_fast64_t bottomState = 0; bottomState < numBottomStates; ++bottomState) {
89 bottomStateVariables.push_back(this->expressionManager->declareRationalVariable("z" + std::to_string(bottomState)));
90 }
91
92 // assert that the values are greater zero and that the bottom state values sum up to one
93 for (auto& var : expectedChoiceVariables) {
94 solver->add(var.getExpression() >= zero);
95 }
96 std::vector<storm::expressions::Expression> bottomStateVarsAsExpression;
97 bottomStateVarsAsExpression.reserve(bottomStateVariables.size());
98 for (auto& var : bottomStateVariables) {
99 solver->add(var.getExpression() >= zero);
100 bottomStateVarsAsExpression.push_back(var.getExpression());
101 }
102 auto bottomStateSum = storm::expressions::sum(bottomStateVarsAsExpression).simplify();
103 solver->add(bottomStateSum == one);
104
105 // assert that the "incoming" value of each state equals the "outgoing" value
106 storm::storage::SparseMatrix<ValueType> backwardsTransitions = this->preprocessedModel->getTransitionMatrix().transpose();
107 auto bottomStateVariableIt = bottomStateVariables.begin();
108 std::vector<storm::expressions::Expression> valueSummands; // initialization here to avoid re-allocations
109 for (uint_fast64_t state = 0; state < numStates; ++state) {
110 // get the "incomming" value
111 valueSummands.clear();
112 if (this->preprocessedModel->getInitialStates().get(state)) {
113 valueSummands.push_back(one);
114 }
115 for (auto const& backwardsEntry : backwardsTransitions.getRow(state)) {
116 valueSummands.push_back(this->expressionManager->rational(backwardsEntry.getValue()) *
117 expectedChoiceVariables[backwardsEntry.getColumn()].getExpression());
118 }
119
120 // subtract the "outgoing" value
121 for (uint_fast64_t choice = this->preprocessedModel->getTransitionMatrix().getRowGroupIndices()[state];
122 choice < this->preprocessedModel->getTransitionMatrix().getRowGroupIndices()[state + 1]; ++choice) {
123 valueSummands.push_back(-expectedChoiceVariables[choice]);
124 }
125 if (this->reward0EStates.get(state)) {
126 valueSummands.push_back(-(*bottomStateVariableIt));
127 ++bottomStateVariableIt;
128 }
129 solver->add(storm::expressions::sum(valueSummands) == zero);
130 }
131 STORM_LOG_ASSERT(bottomStateVariableIt == bottomStateVariables.end(), "Unexpected bottom state variable.");
132}
133
134template<class SparseModelType>
135void SparseCbAchievabilityQuery<SparseModelType>::addObjectiveConstraints() {
136 storm::expressions::Expression zero = this->expressionManager->rational(storm::utility::zero<ValueType>());
137 for (Objective<ValueType> const& obj : this->objectives) {
138 STORM_LOG_THROW(obj.formula->isRewardOperatorFormula() && obj.formula->getSubformula().isTotalRewardFormula(),
139 storm::exceptions::InvalidOperationException,
140 "Constraint-based solver only supports total-reward objectives. Got " << *obj.formula << " instead.");
141 STORM_LOG_THROW(obj.formula->hasBound(), storm::exceptions::InvalidOperationException,
142 "Invoked achievability query but no bound was specified for at least one objective.");
143 STORM_LOG_THROW(obj.formula->asRewardOperatorFormula().hasRewardModelName(), storm::exceptions::InvalidOperationException,
144 "Expected reward operator with a reward model name. Got " << *obj.formula << " instead.");
145 std::vector<ValueType> rewards = getActionBasedExpectedRewards(obj.formula->asRewardOperatorFormula().getRewardModelName());
146
147 // Get the sum of all objective values
148 std::vector<storm::expressions::Expression> objectiveValues;
149 for (uint_fast64_t choice = 0; choice < rewards.size(); ++choice) {
150 if (!storm::utility::isZero(rewards[choice])) {
151 objectiveValues.push_back(this->expressionManager->rational(rewards[choice]) * expectedChoiceVariables[choice].getExpression());
152 }
153 }
154 if (objectiveValues.empty()) {
155 objectiveValues.push_back(this->expressionManager->rational(storm::utility::zero<storm::RationalNumber>()));
156 }
157 auto objValue = storm::expressions::sum(objectiveValues).simplify();
158
159 // We need to actually evaluate the threshold as rational number. Otherwise a threshold like '<=16/9' might be considered as 1 due to integer division
160 storm::expressions::Expression threshold = this->expressionManager->rational(obj.formula->getThreshold().evaluateAsRational());
161 switch (obj.formula->getBound().comparisonType) {
163 solver->add(objValue > threshold);
164 break;
166 solver->add(objValue >= threshold);
167 break;
169 solver->add(objValue < threshold);
170 break;
172 solver->add(objValue <= threshold);
173 break;
174 default:
175 STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "One or more objectives have an invalid comparison type.");
176 }
177 }
178}
179
180template<>
181std::vector<double> SparseCbAchievabilityQuery<storm::models::sparse::Mdp<double>>::getActionBasedExpectedRewards(std::string const& rewardModelName) const {
182 return this->preprocessedModel->getRewardModel(rewardModelName).getTotalRewardVector(this->preprocessedModel->getTransitionMatrix());
183}
184
185template<>
186std::vector<double> SparseCbAchievabilityQuery<storm::models::sparse::MarkovAutomaton<double>>::getActionBasedExpectedRewards(
187 std::string const& rewardModelName) const {
188 auto const& rewModel = this->preprocessedModel->getRewardModel(rewardModelName);
189 STORM_LOG_ASSERT(!rewModel.hasTransitionRewards(), "Preprocessed Reward model has transition rewards which is not expected.");
190 std::vector<double> result = rewModel.hasStateActionRewards()
191 ? rewModel.getStateActionRewardVector()
192 : std::vector<double>(this->preprocessedModel->getNumberOfChoices(), storm::utility::zero<ValueType>());
193 if (rewModel.hasStateRewards()) {
194 // Note that state rewards are earned over time and thus play no role for probabilistic states
195 for (uint64_t markovianState : this->preprocessedModel->getMarkovianStates()) {
196 result[this->preprocessedModel->getTransitionMatrix().getRowGroupIndices()[markovianState]] +=
197 rewModel.getStateReward(markovianState) / this->preprocessedModel->getExitRate(markovianState);
198 }
199 }
200 return result;
201}
202
203template<>
204std::vector<storm::RationalNumber> SparseCbAchievabilityQuery<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>::getActionBasedExpectedRewards(
205 std::string const& rewardModelName) const {
206 auto const& rewModel = this->preprocessedModel->getRewardModel(rewardModelName);
207 STORM_LOG_ASSERT(!rewModel.hasTransitionRewards(), "Preprocessed Reward model has transition rewards which is not expected.");
208 std::vector<storm::RationalNumber> result =
209 rewModel.hasStateActionRewards() ? rewModel.getStateActionRewardVector()
210 : std::vector<storm::RationalNumber>(this->preprocessedModel->getNumberOfChoices(), storm::utility::zero<ValueType>());
211 if (rewModel.hasStateRewards()) {
212 // Note that state rewards are earned over time and thus play no role for probabilistic states
213 for (uint64_t markovianState : this->preprocessedModel->getMarkovianStates()) {
214 result[this->preprocessedModel->getTransitionMatrix().getRowGroupIndices()[markovianState]] +=
215 rewModel.getStateReward(markovianState) / this->preprocessedModel->getExitRate(markovianState);
216 }
217 }
218 return result;
219}
220
221template<>
222std::vector<storm::RationalNumber> SparseCbAchievabilityQuery<storm::models::sparse::Mdp<storm::RationalNumber>>::getActionBasedExpectedRewards(
223 std::string const& rewardModelName) const {
224 return this->preprocessedModel->getRewardModel(rewardModelName).getTotalRewardVector(this->preprocessedModel->getTransitionMatrix());
225}
226
229
232} // namespace multiobjective
233} // namespace modelchecker
234} // namespace storm
Expression simplify() const
Simplifies the expression according to some basic rules.
SparseCbAchievabilityQuery(preprocessing::SparseMultiObjectivePreprocessorResult< SparseModelType > const &preprocessorResult)
virtual std::unique_ptr< CheckResult > check(Environment const &env) override
std::shared_ptr< storm::expressions::ExpressionManager > expressionManager
SparseCbQuery(preprocessing::SparseMultiObjectivePreprocessorResult< SparseModelType > const &preprocessorResult)
CheckResult
possible check results
Definition SmtSolver.h:24
const_rows getRow(index_type row) const
Returns an object representing the given row.
A class that provides convenience operations to display run times.
Definition Stopwatch.h:13
virtual std::unique_ptr< storm::solver::SmtSolver > create(storm::expressions::ExpressionManager &manager) const
Creates a new SMT solver instance.
Definition solver.cpp:159
#define STORM_LOG_INFO(message)
Definition logging.h:27
#define STORM_LOG_STATISTICS(message)
Definition logging.h:41
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:28
Expression sum(std::vector< storm::expressions::Expression > const &expressions)
bool isZero(ValueType const &a)
Definition constants.cpp:42
ValueType zero()
Definition constants.cpp:24
ValueType one()
Definition constants.cpp:19