Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
AssumptionChecker.cpp
Go to the documentation of this file.
2
13
14namespace storm {
15namespace analysis {
16template<typename ValueType, typename ConstantType>
18 this->matrix = matrix;
19 useSamples = false;
20}
21
22template<typename ValueType, typename ConstantType>
23void AssumptionChecker<ValueType, ConstantType>::initializeCheckingOnSamples(Environment const& env, std::shared_ptr<logic::Formula const> formula,
24 std::shared_ptr<models::sparse::Dtmc<ValueType>> model,
25 storage::ParameterRegion<ValueType> region, uint_fast64_t numberOfSamples) {
26 // Create sample points
28 auto matrix = model->getTransitionMatrix();
29 std::set<VariableType> variables = models::sparse::getProbabilityParameters(*model);
30
31 for (uint_fast64_t i = 0; i < numberOfSamples; ++i) {
33 for (auto var : variables) {
34 auto lb = region.getLowerBoundary(var.name());
35 auto ub = region.getUpperBoundary(var.name());
36 // Creates samples between lb and ub, that is: lb, lb + (ub-lb)/(#samples -1), lb + 2* (ub-lb)/(#samples -1), ..., ub
37 auto val = std::pair<VariableType, CoefficientType>(var, (lb + utility::convertNumber<CoefficientType>(i / (numberOfSamples - 1)) * (ub - lb)));
38 valuation.insert(val);
39 }
40 models::sparse::Dtmc<ConstantType> sampleModel = instantiator.instantiate(valuation);
42 std::unique_ptr<modelchecker::CheckResult> checkResult;
43 if (formula->isProbabilityOperatorFormula() && formula->asProbabilityOperatorFormula().getSubformula().isUntilFormula()) {
45 modelchecker::CheckTask<logic::UntilFormula, ConstantType>(formula->asProbabilityOperatorFormula().getSubformula().asUntilFormula());
46 checkResult = checker.computeUntilProbabilities(env, checkTask);
47 } else if (formula->isProbabilityOperatorFormula() && formula->asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()) {
49 modelchecker::CheckTask<logic::EventuallyFormula, ConstantType>(formula->asProbabilityOperatorFormula().getSubformula().asEventuallyFormula());
50 checkResult = checker.computeReachabilityProbabilities(env, checkTask);
51 } else {
52 STORM_LOG_THROW_UNCONDITIONALLY(exceptions::NotSupportedException, "Expecting until or eventually formula");
53 }
54 auto const& quantitativeResult = checkResult->asExplicitQuantitativeCheckResult<ConstantType>();
55 std::vector<ConstantType> values = quantitativeResult.getFiniteValueVector();
56 samples.push_back(values);
57 }
58 useSamples = true;
59}
60
61template<typename ValueType, typename ConstantType>
62void AssumptionChecker<ValueType, ConstantType>::setSampleValues(std::vector<std::vector<ConstantType>> samples) {
63 this->samples = samples;
64 useSamples = true;
65}
66
67template<typename ValueType, typename ConstantType>
68AssumptionChecker<ValueType, ConstantType>::AssumptionChecker(std::shared_ptr<logic::Formula const> formula,
69 std::shared_ptr<models::sparse::Mdp<ValueType>> model, uint_fast64_t numberOfSamples) {
70 STORM_LOG_THROW_UNCONDITIONALLY(exceptions::NotSupportedException, "Assumption checking for mdps not yet implemented");
71}
72
73template<typename ValueType, typename ConstantType>
76 std::vector<ConstantType> const minValues,
77 std::vector<ConstantType> const maxValues) const {
78 // First check if based on sample points the assumption can be discharged
80 if (useSamples) {
81 result = checkOnSamples(assumption);
82 }
83 STORM_LOG_ASSERT(result != AssumptionStatus::VALID, "Sample-based checking should never conclude VALID by itself.");
84
85 if (minValues.size() != 0 && maxValues.size() == minValues.size()) {
86 auto const val1 = assumption.state1;
87 auto const val2 = assumption.state2;
88 if (assumption.relation == AssumptionRelation::Greater) {
89 if (minValues[val1] > maxValues[val2]) {
91 } else if (minValues[val1] == maxValues[val2] && minValues[val1] == maxValues[val1] && minValues[val2] == maxValues[val2]) {
93 } else if (minValues[val2] > maxValues[val1]) {
95 }
96 } else {
97 if (minValues[val1] == maxValues[val2] && minValues[val1] == maxValues[val1] && minValues[val2] == maxValues[val2]) {
99 } else if (minValues[val1] > maxValues[val2]) {
101 } else if (minValues[val2] > maxValues[val1]) {
103 }
104 }
105 }
106
107 if (result == AssumptionStatus::UNKNOWN) {
108 // If result from sample checking was unknown, the assumption might hold
109 result = validateAssumptionSMTSolver(assumption, order, region, minValues, maxValues);
110 }
111 return result;
112}
113
114template<typename ValueType, typename ConstantType>
115AssumptionStatus AssumptionChecker<ValueType, ConstantType>::checkOnSamples(Assumption const& assumption) const {
116 auto result = AssumptionStatus::UNKNOWN;
117 for (auto const& values : samples) {
118 bool holds = assumption.relation == AssumptionRelation::Greater ? values[assumption.state1] > values[assumption.state2]
119 : values[assumption.state1] == values[assumption.state2];
120 if (!holds) {
122 break;
123 }
124 }
125 return result;
126}
127
128template<typename ValueType, typename ConstantType>
129AssumptionStatus AssumptionChecker<ValueType, ConstantType>::validateAssumptionSMTSolver(Assumption const& assumption, std::shared_ptr<Order> order,
130 storage::ParameterRegion<ValueType> region,
131 std::vector<ConstantType> const minValues,
132 std::vector<ConstantType> const maxValues) const {
133 std::shared_ptr<expressions::ExpressionManager> manager(new expressions::ExpressionManager());
135 uint_fast64_t val1 = assumption.state1;
136 uint_fast64_t val2 = assumption.state2;
137 auto row1 = matrix.getRow(val1);
138 auto row2 = matrix.getRow(val2);
139
140 bool orderKnown = true;
141 // if the state with number val1 (val2) occurs in the successors of the state with number val2 (val1) we need to add val1 == expr1 (val2 == expr2) to the
142 // bounds
143 bool addVar1 = false;
144 bool addVar2 = false;
145 // Check if the order between the different successors is known
146 // Also start creating expression for order of states
147 auto exprOrderSucc = manager->boolean(true);
148 std::set<expressions::Variable> stateVariables;
149 std::set<expressions::Variable> topVariables;
150 std::set<expressions::Variable> bottomVariables;
151 for (auto itr1 = row1.begin(); orderKnown && itr1 != row1.end(); ++itr1) {
152 addVar2 |= itr1->getColumn() == val2;
153 auto varname1 = "s" + std::to_string(itr1->getColumn());
154 if (!manager->hasVariable(varname1)) {
155 if (order->isTopState(itr1->getColumn())) {
156 topVariables.insert(manager->declareRationalVariable(varname1));
157 } else if (order->isBottomState(itr1->getColumn())) {
158 bottomVariables.insert(manager->declareRationalVariable(varname1));
159 } else {
160 stateVariables.insert(manager->declareRationalVariable(varname1));
161 }
162 }
163
164 for (auto itr2 = row2.begin(); orderKnown && itr2 != row2.end(); ++itr2) {
165 addVar1 |= itr2->getColumn() == val1;
166 if (itr1->getColumn() != itr2->getColumn()) {
167 auto varname2 = "s" + std::to_string(itr2->getColumn());
168 if (!manager->hasVariable(varname2)) {
169 if (order->isTopState(itr2->getColumn())) {
170 topVariables.insert(manager->declareRationalVariable(varname2));
171 } else if (order->isBottomState(itr2->getColumn())) {
172 bottomVariables.insert(manager->declareRationalVariable(varname2));
173 } else {
174 stateVariables.insert(manager->declareRationalVariable(varname2));
175 }
176 }
177 auto comp = order->compare(itr1->getColumn(), itr2->getColumn());
178 if (minValues.size() > 0 && maxValues.size() == minValues.size() && comp == Order::NodeComparison::UNKNOWN) {
179 // Couldn't add relation between varname1 and varname2 but maybe we can based on min/max values;
180 if (minValues[itr2->getColumn()] > maxValues[itr1->getColumn()]) {
181 if (!order->contains(itr1->getColumn())) {
182 order->add(itr1->getColumn());
183 order->addStateToHandle(itr1->getColumn());
184 }
185 if (!order->contains(itr2->getColumn())) {
186 order->add(itr2->getColumn());
187 order->addStateToHandle(itr2->getColumn());
188 }
189 order->addRelation(itr2->getColumn(), itr1->getColumn());
191 } else if (minValues[itr1->getColumn()] > maxValues[itr2->getColumn()]) {
192 if (!order->contains(itr1->getColumn())) {
193 order->add(itr1->getColumn());
194 order->addStateToHandle(itr1->getColumn());
195 }
196 if (!order->contains(itr2->getColumn())) {
197 order->add(itr2->getColumn());
198 order->addStateToHandle(itr2->getColumn());
199 }
200 order->addRelation(itr1->getColumn(), itr2->getColumn());
202 }
203 }
204 if (comp == Order::NodeComparison::ABOVE) {
205 exprOrderSucc = exprOrderSucc && !(manager->getVariable(varname1) <= manager->getVariable(varname2));
206 } else if (comp == Order::NodeComparison::BELOW) {
207 exprOrderSucc = exprOrderSucc && !(manager->getVariable(varname1) >= manager->getVariable(varname2));
208 } else if (comp == Order::NodeComparison::SAME) {
209 exprOrderSucc = exprOrderSucc && (manager->getVariable(varname1) >= manager->getVariable(varname2)) &&
210 (manager->getVariable(varname1) <= manager->getVariable(varname2));
211 } else {
212 orderKnown = false;
213 }
214 }
215 }
216 }
217
218 if (orderKnown) {
219 solver::Z3SmtSolver s(*manager);
220 auto valueTypeToExpression = expressions::RationalFunctionToExpression<ValueType>(manager);
221 expressions::Expression expr1 = manager->rational(0);
222 for (auto itr1 = row1.begin(); itr1 != row1.end(); ++itr1) {
223 expr1 = expr1 + (valueTypeToExpression.toExpression(itr1->getValue()) * manager->getVariable("s" + std::to_string(itr1->getColumn())));
224 }
225
226 expressions::Expression expr2 = manager->rational(0);
227 for (auto itr2 = row2.begin(); itr2 != row2.end(); ++itr2) {
228 expr2 = expr2 + (valueTypeToExpression.toExpression(itr2->getValue()) * manager->getVariable("s" + std::to_string(itr2->getColumn())));
229 }
230
231 // Create expression for the assumption based on the relation to successors
232 // It is the negation of actual assumption
233
234 expressions::Expression exprToCheck;
235 if (assumption.relation == AssumptionRelation::Greater) {
236 exprToCheck = expr1 <= expr2;
237 } else {
238 exprToCheck = expr1 != expr2;
239 }
240
241 auto variables = manager->getVariables();
242 // Bounds for the state probabilities and parameters
243 expressions::Expression exprBounds = manager->boolean(true);
244 if (addVar1) {
245 exprBounds = exprBounds && (manager->getVariable("s" + std::to_string(val1)) == expr1);
246 }
247 if (addVar2) {
248 exprBounds = exprBounds && (manager->getVariable("s" + std::to_string(val2)) == expr2);
249 }
250 for (auto var : variables) {
251 if (find(stateVariables.begin(), stateVariables.end(), var) != stateVariables.end()) {
252 // the var is a state
253 if (minValues.size() > 0 && maxValues.size() == minValues.size()) {
254 std::string test = var.getName();
255 auto val = std::stoi(test.substr(1, test.size() - 1));
256 exprBounds = exprBounds && manager->rational(minValues[val]) <= var && var <= manager->rational(maxValues[val]);
257 } else {
258 exprBounds = exprBounds && manager->rational(0) <= var && var <= manager->rational(1);
259 }
260 } else if (find(topVariables.begin(), topVariables.end(), var) != topVariables.end()) {
261 // the var is =)
262 exprBounds = exprBounds && var == manager->rational(1);
263 } else if (find(bottomVariables.begin(), bottomVariables.end(), var) != bottomVariables.end()) {
264 // the var is =(
265 exprBounds = exprBounds && var == manager->rational(0);
266 } else {
267 // the var is a parameter
268 auto lb = utility::convertNumber<RationalNumber>(region.getLowerBoundary(var.getName()));
269 auto ub = utility::convertNumber<RationalNumber>(region.getUpperBoundary(var.getName()));
270 exprBounds = exprBounds && manager->rational(lb) < var && var < manager->rational(ub);
271 }
272 }
273
274 s.add(exprOrderSucc);
275 s.add(exprBounds);
276 s.setTimeout(100);
277 // assert that sorting of successors in the order and the bounds on the expression are at least satisfiable
278 // when this is not the case, the order is invalid
279 // however, it could be that the sat solver didn't finish in time, in that case we just continue.
280 if (s.check() == solver::SmtSolver::CheckResult::Unsat) {
282 }
283
284 s.add(exprToCheck);
285 auto smtRes = s.check();
287 // If there is no thing satisfying the negation we are safe.
289 } else if (smtRes == solver::SmtSolver::CheckResult::Sat) {
291 }
292 }
293 return result;
294}
295
296template<typename ValueType, typename ConstantType>
299 std::vector<ConstantType> vals;
300 return validateAssumption(assumption, order, region, vals, vals);
301}
302
305} // namespace analysis
306} // namespace storm
AssumptionChecker(storage::SparseMatrix< ValueType > matrix)
Constructs an AssumptionChecker.
void initializeCheckingOnSamples(Environment const &env, 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.
AssumptionStatus validateAssumption(Assumption const &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.
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, SolutionType > const &checkTask) override
This class represents a discrete-time Markov chain.
Definition Dtmc.h:16
This class represents a (discrete-time) Markov decision process.
Definition Mdp.h:16
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_UNCONDITIONALLY(exception, message)
Definition macros.h:48
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
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:732
SettingsManager const & manager()
Retrieves the settings manager.
std::map< typename VariableType< FunctionType >::type, typename CoefficientType< FunctionType >::type > Valuation
Definition parametric.h:43
TargetType convertNumber(SourceType const &number)
A candidate relation between two states of a reachability order: either state1 > state2 (Greater) or ...
Definition Assumption.h:20
AssumptionRelation relation
Definition Assumption.h:23