21template<
class SparseModelType>
26 "Invalid query Type.");
30template<
class SparseModelType>
32 bool result = this->checkAchievability();
37template<
class SparseModelType>
38bool SparseCbAchievabilityQuery<SparseModelType>::checkAchievability() {
39 STORM_LOG_INFO(
"Building constraint system to check achievability.");
42 initializeConstraintSystem();
43 STORM_LOG_INFO(
"Constraint system consists of " << expectedChoiceVariables.size() <<
" + " << bottomStateVariables.size() <<
" variables");
44 addObjectiveConstraints();
45 swInitialization.stop();
52 STORM_LOG_STATISTICS(
"Building the constraintsystem took " << swInitialization <<
" seconds and checking the SMT formula took " << swCheck
67 STORM_LOG_THROW(
false, storm::exceptions::UnexpectedException,
"SMT solver yielded an unexpected result.");
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.");
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)));
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)));
93 for (
auto& var : expectedChoiceVariables) {
94 solver->add(var.getExpression() >= zero);
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());
103 solver->add(bottomStateSum == one);
106 storm::storage::SparseMatrix<ValueType> backwardsTransitions = this->preprocessedModel->getTransitionMatrix().transpose();
107 auto bottomStateVariableIt = bottomStateVariables.begin();
108 std::vector<storm::expressions::Expression> valueSummands;
109 for (uint_fast64_t state = 0; state < numStates; ++state) {
111 valueSummands.clear();
112 if (this->preprocessedModel->getInitialStates().get(state)) {
113 valueSummands.push_back(one);
115 for (
auto const& backwardsEntry : backwardsTransitions.
getRow(state)) {
116 valueSummands.push_back(this->expressionManager->rational(backwardsEntry.getValue()) *
117 expectedChoiceVariables[backwardsEntry.getColumn()].getExpression());
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]);
125 if (this->reward0EStates.get(state)) {
126 valueSummands.push_back(-(*bottomStateVariableIt));
127 ++bottomStateVariableIt;
131 STORM_LOG_ASSERT(bottomStateVariableIt == bottomStateVariables.end(),
"Unexpected bottom state variable.");
134template<
class SparseModelType>
135void SparseCbAchievabilityQuery<SparseModelType>::addObjectiveConstraints() {
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());
148 std::vector<storm::expressions::Expression> objectiveValues;
149 for (uint_fast64_t choice = 0; choice < rewards.size(); ++choice) {
151 objectiveValues.push_back(this->expressionManager->rational(rewards[choice]) * expectedChoiceVariables[choice].getExpression());
154 if (objectiveValues.empty()) {
160 storm::expressions::Expression threshold = this->expressionManager->rational(obj.formula->getThreshold().evaluateAsRational());
161 switch (obj.formula->getBound().comparisonType) {
163 solver->add(objValue > threshold);
166 solver->add(objValue >= threshold);
169 solver->add(objValue < threshold);
172 solver->add(objValue <= threshold);
175 STORM_LOG_THROW(
false, storm::exceptions::InvalidOperationException,
"One or more objectives have an invalid comparison type.");
182 return this->preprocessedModel->getRewardModel(rewardModelName).getTotalRewardVector(this->preprocessedModel->getTransitionMatrix());
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()
193 if (rewModel.hasStateRewards()) {
195 for (uint64_t markovianState : this->preprocessedModel->getMarkovianStates()) {
196 result[this->preprocessedModel->getTransitionMatrix().getRowGroupIndices()[markovianState]] +=
197 rewModel.getStateReward(markovianState) / this->preprocessedModel->getExitRate(markovianState);
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()
211 if (rewModel.hasStateRewards()) {
213 for (uint64_t markovianState : this->preprocessedModel->getMarkovianStates()) {
214 result[this->preprocessedModel->getTransitionMatrix().getRowGroupIndices()[markovianState]] +=
215 rewModel.getStateReward(markovianState) / this->preprocessedModel->getExitRate(markovianState);
223 std::string
const& rewardModelName)
const {
224 return this->preprocessedModel->getRewardModel(rewardModelName).getTotalRewardVector(this->preprocessedModel->getTransitionMatrix());