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