Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
AssumptionChecker.cpp
Go to the documentation of this file.
1#include "AssumptionChecker.h"
3
15
16namespace storm {
17namespace analysis {
18template<typename ValueType, typename ConstantType>
20 this->matrix = matrix;
21 useSamples = false;
22}
23
24template<typename ValueType, typename ConstantType>
25void AssumptionChecker<ValueType, ConstantType>::initializeCheckingOnSamples(std::shared_ptr<logic::Formula const> formula,
26 std::shared_ptr<models::sparse::Dtmc<ValueType>> model,
27 storage::ParameterRegion<ValueType> region, uint_fast64_t numberOfSamples) {
28 // Create sample points
30 auto matrix = model->getTransitionMatrix();
31 std::set<VariableType> variables = models::sparse::getProbabilityParameters(*model);
32
33 for (uint_fast64_t i = 0; i < numberOfSamples; ++i) {
35 for (auto var : variables) {
36 auto lb = region.getLowerBoundary(var.name());
37 auto ub = region.getUpperBoundary(var.name());
38 // Creates samples between lb and ub, that is: lb, lb + (ub-lb)/(#samples -1), lb + 2* (ub-lb)/(#samples -1), ..., ub
39 auto val = std::pair<VariableType, CoefficientType>(var, (lb + utility::convertNumber<CoefficientType>(i / (numberOfSamples - 1)) * (ub - lb)));
40 valuation.insert(val);
41 }
42 models::sparse::Dtmc<ConstantType> sampleModel = instantiator.instantiate(valuation);
44 std::unique_ptr<modelchecker::CheckResult> checkResult;
45 if (formula->isProbabilityOperatorFormula() && formula->asProbabilityOperatorFormula().getSubformula().isUntilFormula()) {
47 modelchecker::CheckTask<logic::UntilFormula, ConstantType>((*formula).asProbabilityOperatorFormula().getSubformula().asUntilFormula());
48 checkResult = checker.computeUntilProbabilities(Environment(), checkTask);
49 } else if (formula->isProbabilityOperatorFormula() && formula->asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()) {
51 (*formula).asProbabilityOperatorFormula().getSubformula().asEventuallyFormula());
52 checkResult = checker.computeReachabilityProbabilities(Environment(), checkTask);
53 } else {
54 STORM_LOG_THROW(false, exceptions::NotSupportedException, "Expecting until or eventually formula");
55 }
56 auto quantitativeResult = checkResult->asExplicitQuantitativeCheckResult<ConstantType>();
57 std::vector<ConstantType> values = quantitativeResult.getValueVector();
58 samples.push_back(values);
59 }
60 useSamples = true;
61}
62
63template<typename ValueType, typename ConstantType>
64void AssumptionChecker<ValueType, ConstantType>::setSampleValues(std::vector<std::vector<ConstantType>> samples) {
65 this->samples = samples;
66 useSamples = true;
67}
68
69template<typename ValueType, typename ConstantType>
70AssumptionChecker<ValueType, ConstantType>::AssumptionChecker(std::shared_ptr<logic::Formula const> formula,
71 std::shared_ptr<models::sparse::Mdp<ValueType>> model, uint_fast64_t numberOfSamples) {
72 STORM_LOG_THROW(false, exceptions::NotSupportedException, "Assumption checking for mdps not yet implemented");
73}
74
75template<typename ValueType, typename ConstantType>
77 std::shared_ptr<expressions::BinaryRelationExpression> assumption,
78 std::shared_ptr<Order> order, storage::ParameterRegion<ValueType> region,
79 std::vector<ConstantType> const minValues,
80 std::vector<ConstantType> const maxValues) const {
81 // First check if based on sample points the assumption can be discharged
82 assert(val1 == std::stoull(assumption->getFirstOperand()->asVariableExpression().getVariableName()));
83 assert(val2 == std::stoull(assumption->getSecondOperand()->asVariableExpression().getVariableName()));
85 if (useSamples) {
86 result = checkOnSamples(assumption);
87 }
88 assert(result != AssumptionStatus::VALID);
89
90 if (minValues.size() != 0) {
91 if (assumption->getRelationType() == expressions::RelationType::Greater) {
92 if (minValues[val1] > maxValues[val2]) {
94 } else if (minValues[val1] == maxValues[val2] && minValues[val1] == maxValues[val1] && minValues[val2] == maxValues[val2]) {
96 } else if (minValues[val2] > maxValues[val1]) {
98 }
99 } else {
100 if (minValues[val1] == maxValues[val2] && minValues[val1] == maxValues[val1] && minValues[val2] == maxValues[val2]) {
102 } else if (minValues[val1] > maxValues[val2]) {
104 } else if (minValues[val2] > maxValues[val1]) {
106 }
107 }
108 }
109
110 if (result == AssumptionStatus::UNKNOWN) {
111 // If result from sample checking was unknown, the assumption might hold
112 std::set<expressions::Variable> vars = std::set<expressions::Variable>({});
113 assumption->gatherVariables(vars);
114
116 assumption->getRelationType() == expressions::RelationType::Greater || assumption->getRelationType() == expressions::RelationType::Equal,
117 exceptions::NotSupportedException, "Only Greater Or Equal assumptions supported");
118 result = validateAssumptionSMTSolver(val1, val2, assumption, order, region, minValues, maxValues);
119 }
120 return result;
121}
122
123template<typename ValueType, typename ConstantType>
124AssumptionStatus AssumptionChecker<ValueType, ConstantType>::checkOnSamples(std::shared_ptr<expressions::BinaryRelationExpression> assumption) const {
125 auto result = AssumptionStatus::UNKNOWN;
126 std::set<expressions::Variable> vars = std::set<expressions::Variable>({});
127 assumption->gatherVariables(vars);
128 for (auto values : samples) {
129 auto valuation = expressions::SimpleValuation(assumption->getManager().getSharedPointer());
130 for (auto var : vars) {
131 auto index = std::stoi(var.getName());
132 valuation.setRationalValue(var, utility::convertNumber<double>(values[index]));
133 }
134
135 assert(assumption->hasBooleanType());
136 if (!assumption->evaluateAsBool(&valuation)) {
138 break;
139 }
140 }
141 return result;
142}
143
144template<typename ValueType, typename ConstantType>
145AssumptionStatus AssumptionChecker<ValueType, ConstantType>::validateAssumptionSMTSolver(
146 uint_fast64_t val1, uint_fast64_t val2, std::shared_ptr<expressions::BinaryRelationExpression> assumption, std::shared_ptr<Order> order,
147 storage::ParameterRegion<ValueType> region, std::vector<ConstantType> const minValues, std::vector<ConstantType> const maxValues) const {
148 std::shared_ptr<utility::solver::SmtSolverFactory> smtSolverFactory = std::make_shared<utility::solver::MathsatSmtSolverFactory>();
149 std::shared_ptr<expressions::ExpressionManager> manager(new expressions::ExpressionManager());
151 auto var1 = assumption->getFirstOperand()->asVariableExpression().getVariableName();
152 auto var2 = assumption->getSecondOperand()->asVariableExpression().getVariableName();
153 auto row1 = matrix.getRow(val1);
154 auto row2 = matrix.getRow(val2);
155
156 bool orderKnown = true;
157 // if the state with number var1 (var2) occurs in the successors of the state with number var2 (var1) we need to add var1 == expr1 (var2 == expr2) to the
158 // bounds
159 bool addVar1 = false;
160 bool addVar2 = false;
161 // Check if the order between the different successors is known
162 // Also start creating expression for order of states
163 auto exprOrderSucc = manager->boolean(true);
164 std::set<expressions::Variable> stateVariables;
165 std::set<expressions::Variable> topVariables;
166 std::set<expressions::Variable> bottomVariables;
167 for (auto itr1 = row1.begin(); orderKnown && itr1 != row1.end(); ++itr1) {
168 addVar2 |= std::to_string(itr1->getColumn()) == var2;
169 auto varname1 = "s" + std::to_string(itr1->getColumn());
170 if (!manager->hasVariable(varname1)) {
171 if (order->isTopState(itr1->getColumn())) {
172 topVariables.insert(manager->declareRationalVariable(varname1));
173 } else if (order->isBottomState(itr1->getColumn())) {
174 bottomVariables.insert(manager->declareRationalVariable(varname1));
175 } else {
176 stateVariables.insert(manager->declareRationalVariable(varname1));
177 }
178 }
179
180 for (auto itr2 = row2.begin(); orderKnown && itr2 != row2.end(); ++itr2) {
181 addVar1 |= std::to_string(itr2->getColumn()) == var1;
182 if (itr1->getColumn() != itr2->getColumn()) {
183 auto varname2 = "s" + std::to_string(itr2->getColumn());
184 if (!manager->hasVariable(varname2)) {
185 if (order->isTopState(itr2->getColumn())) {
186 topVariables.insert(manager->declareRationalVariable(varname2));
187 } else if (order->isBottomState(itr2->getColumn())) {
188 bottomVariables.insert(manager->declareRationalVariable(varname2));
189 } else {
190 stateVariables.insert(manager->declareRationalVariable(varname2));
191 }
192 }
193 auto comp = order->compare(itr1->getColumn(), itr2->getColumn());
194 if (minValues.size() > 0 && comp == Order::NodeComparison::UNKNOWN) {
195 // Couldn't add relation between varname1 and varname2 but maybe we can based on min/max values;
196 if (minValues[itr2->getColumn()] > maxValues[itr1->getColumn()]) {
197 if (!order->contains(itr1->getColumn())) {
198 order->add(itr1->getColumn());
199 order->addStateToHandle(itr1->getColumn());
200 }
201 if (!order->contains(itr2->getColumn())) {
202 order->add(itr2->getColumn());
203 order->addStateToHandle(itr2->getColumn());
204 }
205 order->addRelation(itr2->getColumn(), itr1->getColumn());
207 } else if (minValues[itr1->getColumn()] > maxValues[itr2->getColumn()]) {
208 if (!order->contains(itr1->getColumn())) {
209 order->add(itr1->getColumn());
210 order->addStateToHandle(itr1->getColumn());
211 }
212 if (!order->contains(itr2->getColumn())) {
213 order->add(itr2->getColumn());
214 order->addStateToHandle(itr2->getColumn());
215 }
216 order->addRelation(itr1->getColumn(), itr2->getColumn());
218 }
219 }
220 if (comp == Order::NodeComparison::ABOVE) {
221 exprOrderSucc = exprOrderSucc && !(manager->getVariable(varname1) <= manager->getVariable(varname2));
222 } else if (comp == Order::NodeComparison::BELOW) {
223 exprOrderSucc = exprOrderSucc && !(manager->getVariable(varname1) >= manager->getVariable(varname2));
224 } else if (comp == Order::NodeComparison::SAME) {
225 exprOrderSucc = exprOrderSucc && (manager->getVariable(varname1) >= manager->getVariable(varname2)) &&
226 (manager->getVariable(varname1) <= manager->getVariable(varname2));
227 } else {
228 orderKnown = false;
229 }
230 }
231 }
232 }
233
234 if (orderKnown) {
235 solver::Z3SmtSolver s(*manager);
236 auto valueTypeToExpression = expressions::RationalFunctionToExpression<ValueType>(manager);
237 expressions::Expression expr1 = manager->rational(0);
238 for (auto itr1 = row1.begin(); itr1 != row1.end(); ++itr1) {
239 expr1 = expr1 + (valueTypeToExpression.toExpression(itr1->getValue()) * manager->getVariable("s" + std::to_string(itr1->getColumn())));
240 }
241
242 expressions::Expression expr2 = manager->rational(0);
243 for (auto itr2 = row2.begin(); itr2 != row2.end(); ++itr2) {
244 expr2 = expr2 + (valueTypeToExpression.toExpression(itr2->getValue()) * manager->getVariable("s" + std::to_string(itr2->getColumn())));
245 }
246
247 // Create expression for the assumption based on the relation to successors
248 // It is the negation of actual assumption
249
250 expressions::Expression exprToCheck;
251 if (assumption->getRelationType() == expressions::RelationType::Greater) {
252 exprToCheck = expr1 <= expr2;
253 } else {
254 assert(assumption->getRelationType() == expressions::RelationType::Equal);
255 exprToCheck = expr1 != expr2;
256 }
257
258 auto variables = manager->getVariables();
259 // Bounds for the state probabilities and parameters
260 expressions::Expression exprBounds = manager->boolean(true);
261 if (addVar1) {
262 exprBounds = exprBounds && (manager->getVariable("s" + var1) == expr1);
263 }
264 if (addVar2) {
265 exprBounds = exprBounds && (manager->getVariable("s" + var2) == expr2);
266 }
267 for (auto var : variables) {
268 if (find(stateVariables.begin(), stateVariables.end(), var) != stateVariables.end()) {
269 // the var is a state
270 if (minValues.size() > 0) {
271 std::string test = var.getName();
272 auto val = std::stoi(test.substr(1, test.size() - 1));
273 exprBounds = exprBounds && manager->rational(minValues[val]) <= var && var <= manager->rational(maxValues[val]);
274 } else {
275 exprBounds = exprBounds && manager->rational(0) <= var && var <= manager->rational(1);
276 }
277 } else if (find(topVariables.begin(), topVariables.end(), var) != topVariables.end()) {
278 // the var is =)
279 exprBounds = exprBounds && var == manager->rational(1);
280 } else if (find(bottomVariables.begin(), bottomVariables.end(), var) != bottomVariables.end()) {
281 // the var is =(
282 exprBounds = exprBounds && var == manager->rational(0);
283 } else {
284 // the var is a parameter
285 auto lb = utility::convertNumber<RationalNumber>(region.getLowerBoundary(var.getName()));
286 auto ub = utility::convertNumber<RationalNumber>(region.getUpperBoundary(var.getName()));
287 exprBounds = exprBounds && manager->rational(lb) < var && var < manager->rational(ub);
288 }
289 }
290
291 s.add(exprOrderSucc);
292 s.add(exprBounds);
293 s.setTimeout(100);
294 // assert that sorting of successors in the order and the bounds on the expression are at least satisfiable
295 // when this is not the case, the order is invalid
296 // however, it could be that the sat solver didn't finish in time, in that case we just continue.
297 if (s.check() == solver::SmtSolver::CheckResult::Unsat) {
299 }
300 assert(s.check() != solver::SmtSolver::CheckResult::Unsat);
301
302 s.add(exprToCheck);
303 auto smtRes = s.check();
305 // If there is no thing satisfying the negation we are safe.
307 } else if (smtRes == solver::SmtSolver::CheckResult::Sat) {
309 }
310 }
311 return result;
312}
313
314template<typename ValueType, typename ConstantType>
315AssumptionStatus AssumptionChecker<ValueType, ConstantType>::validateAssumption(std::shared_ptr<expressions::BinaryRelationExpression> assumption,
316 std::shared_ptr<Order> order,
318 auto var1 = std::stoi(assumption->getFirstOperand()->asVariableExpression().getVariableName());
319 auto var2 = std::stoi(assumption->getSecondOperand()->asVariableExpression().getVariableName());
320 std::vector<ConstantType> vals;
321 return validateAssumption(var1, var2, assumption, order, region, vals, vals);
322}
323
326} // namespace analysis
327} // namespace storm
AssumptionChecker(storage::SparseMatrix< ValueType > matrix)
Constructs an AssumptionChecker.
AssumptionStatus validateAssumption(uint_fast64_t val1, uint_fast64_t val2, std::shared_ptr< expressions::BinaryRelationExpression > assumption, std::shared_ptr< Order > order, storage::ParameterRegion< ValueType > region, std::vector< ConstantType > const minValues, std::vector< ConstantType > const maxValue) const
Tries to validate an assumption based on the order and underlying transition matrix.
void setSampleValues(std::vector< std::vector< ConstantType > > samples)
Sets the sample values to the given vector and useSamples to true.
void initializeCheckingOnSamples(std::shared_ptr< logic::Formula const > formula, std::shared_ptr< models::sparse::Dtmc< ValueType > > model, storage::ParameterRegion< ValueType > region, uint_fast64_t numberOfSamples)
Initializes the given number of sample points for a given model, formula and region.
A simple implementation of the valuation interface.
virtual std::unique_ptr< CheckResult > computeReachabilityProbabilities(Environment const &env, CheckTask< storm::logic::EventuallyFormula, SolutionType > const &checkTask)
virtual std::unique_ptr< CheckResult > computeUntilProbabilities(Environment const &env, CheckTask< storm::logic::UntilFormula, ValueType > const &checkTask) override
This class represents a discrete-time Markov chain.
Definition Dtmc.h:14
This class represents a (discrete-time) Markov decision process.
Definition Mdp.h:14
CoefficientType const & getLowerBoundary(VariableType const &variable) const
CoefficientType const & getUpperBoundary(VariableType const &variable) const
A class that holds a possibly non-square matrix in the compressed row storage format.
This class allows efficient instantiation of the given parametric model.
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
AssumptionStatus
Constants for status of assumption.
std::set< storm::RationalFunctionVariable > getProbabilityParameters(Model< storm::RationalFunction > const &model)
Get all probability parameters occurring on transitions.
Definition Model.cpp:703
SettingsManager const & manager()
Retrieves the settings manager.
std::map< typename VariableType< FunctionType >::type, typename CoefficientType< FunctionType >::type > Valuation
Definition parametric.h:41
LabParser.cpp.
Definition cli.cpp:18