Storm 1.11.1.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
MonotonicityChecker.cpp
Go to the documentation of this file.
2
5
6namespace storm {
7namespace analysis {
8template<typename ValueType>
12
13template<typename ValueType>
15 std::shared_ptr<Order> const& order, uint_fast64_t state, VariableType const& var, storage::ParameterRegion<ValueType> const& region) {
16 // Create + fill Vector containing the Monotonicity of the transitions to the succs
17 auto row = matrix.getRow(state);
18 // Ignore if all entries are constant
19 bool ignore = true;
20
21 std::vector<uint_fast64_t> succs;
22 std::vector<Monotonicity> succsMonUnsorted;
23 std::vector<uint_fast64_t> statesIncr;
24 std::vector<uint_fast64_t> statesDecr;
25 bool checkAllow = true;
26 for (auto entry : row) {
27 auto succState = entry.getColumn();
28 auto mon = checkTransitionMonRes(entry.getValue(), var, region);
29 succsMonUnsorted.push_back(mon);
30 succs.push_back(succState);
31 ignore &= entry.getValue().isConstant();
32 if (mon == Monotonicity::Incr) {
33 statesIncr.push_back(succState);
34 } else if (mon == Monotonicity::Decr) {
35 statesDecr.push_back(succState);
36 } else if (mon == Monotonicity::Not) {
37 checkAllow = false;
38 }
39 }
40 if (ignore) {
41 return Monotonicity::Constant;
42 }
43 auto succsSorted = order->sortStates(&succs);
44
45 uint_fast64_t succSize = succs.size();
46 if (succsSorted[succSize - 1] == matrix.getColumnCount()) {
47 // Maybe we can still do something
48 // If one is decreasing and all others increasing, and this one is above all others or vice versa
49 if (checkAllow) {
50 if (statesIncr.size() == 1 && statesDecr.size() > 1) {
51 auto comp = order->allAboveBelow(statesDecr, statesIncr.back());
52 if (comp.first) {
53 // All decreasing states are above the increasing state, therefore decreasing
54 return Monotonicity::Decr;
55 } else if (comp.second) {
56 // All decreasing states are below the increasing state, therefore increasing
57 return Monotonicity::Incr;
58 }
59 } else if (statesDecr.size() == 1 && statesIncr.size() > 1) {
60 auto comp = order->allAboveBelow(statesDecr, statesIncr.back());
61 if (comp.first) {
62 // All increasing states are below the decreasing state, therefore increasing
63 return Monotonicity::Incr;
64 } else if (comp.second) {
65 // All increasing states are above the decreasing state, therefore decreasing
66 return Monotonicity::Decr;
67 }
68 }
69 }
70
71 return Monotonicity::Unknown;
72 }
73
74 if (succSize == 2) {
75 // In this case we can ignore the last entry, as this will have a probability of 1 - the other
76 succSize = 1;
77 }
78
79 // First check as long as it stays constant and either incr or decr
80 bool allowedToSwap = true;
81 Monotonicity localMonotonicity = Monotonicity::Constant;
82 uint_fast64_t index = 0;
83 while (index < succSize && localMonotonicity == Monotonicity::Constant) {
84 auto itr = std::find(succs.begin(), succs.end(), succsSorted[index]);
85 auto newIndex = std::distance(succs.begin(), itr);
86 auto transitionMon = succsMonUnsorted[newIndex];
87 localMonotonicity = transitionMon;
88 if (transitionMon == Monotonicity::Not && succSize != 1) {
89 localMonotonicity = Monotonicity::Unknown;
90 }
91 index++;
92 }
93
94 while (index < succSize && localMonotonicity != Monotonicity::Not && localMonotonicity != Monotonicity::Unknown) {
95 // We get here as soon as we have seen incr/decr once
96 auto itr = std::find(succs.begin(), succs.end(), succsSorted[index]);
97 auto newIndex = std::distance(succs.begin(), itr);
98 auto transitionMon = succsMonUnsorted[newIndex];
99
100 if (transitionMon == Monotonicity::Not || transitionMon == Monotonicity::Unknown) {
101 return Monotonicity::Unknown;
102 }
103 if (allowedToSwap) {
104 // So far we have only seen constant and either incr or decr, but not both
105 if (transitionMon != Monotonicity::Constant && transitionMon != localMonotonicity) {
106 allowedToSwap = false;
107 }
108 } else if (!allowedToSwap) {
109 // So we have been at the point where we changed from incr to decr (or decr to incr)
110 if (transitionMon == localMonotonicity || transitionMon == Monotonicity::Not || transitionMon == Monotonicity::Unknown) {
111 localMonotonicity = Monotonicity::Unknown;
112 }
113 }
114 index++;
115 }
116 return localMonotonicity;
117}
118
119template<typename ValueType>
120std::pair<bool, bool> MonotonicityChecker<ValueType>::checkDerivative(ValueType const& derivative, storage::ParameterRegion<ValueType> const& reg) {
121 if (derivative.isZero()) {
122 return std::pair<bool, bool>(true, true);
123 }
124 if (derivative.isConstant()) {
125 bool monIncr = derivative.constantPart() >= 0;
126 bool monDecr = derivative.constantPart() <= 0;
127 return std::pair<bool, bool>(monIncr, monDecr);
128 }
129 bool monIncr = false;
130 bool monDecr = false;
131
132 std::shared_ptr<utility::solver::SmtSolverFactory> smtSolverFactory = std::make_shared<utility::solver::MathsatSmtSolverFactory>();
133 std::shared_ptr<expressions::ExpressionManager> manager(new expressions::ExpressionManager());
134 solver::Z3SmtSolver s(*manager);
135 std::set<VariableType> variables = derivative.gatherVariables();
136
137 expressions::Expression exprBounds = manager->boolean(true);
138 for (auto const& variable : variables) {
139 auto managerVariable = manager->declareRationalVariable(variable.name());
140 auto lb = utility::convertNumber<RationalNumber>(reg.getLowerBoundary(variable));
141 auto ub = utility::convertNumber<RationalNumber>(reg.getUpperBoundary(variable));
142 exprBounds = exprBounds && manager->rational(lb) <= managerVariable && managerVariable <= manager->rational(ub);
143 }
144
146
147 // < 0, so not monotone increasing. If this is unsat, then it should be monotone increasing.
148 expressions::Expression exprToCheck = converter.toExpression(derivative) < manager->rational(0);
149 s.add(exprBounds);
150 s.add(exprToCheck);
152
153 // > 0, so not monotone decreasing. If this is unsat it should be monotone decreasing.
154 exprToCheck = converter.toExpression(derivative) > manager->rational(0);
155 s.reset();
156 s.add(exprBounds);
157 s.add(exprToCheck);
159
160 STORM_LOG_ASSERT(!(monIncr && monDecr), "Error analyzing " << derivative);
161
162 return std::pair<bool, bool>(monIncr, monDecr);
163}
164
165/*** Private methods ***/
166template<typename ValueType>
168 ValueType function, typename MonotonicityChecker<ValueType>::VariableType param, typename MonotonicityChecker<ValueType>::Region region) {
169 std::pair<bool, bool> res = MonotonicityChecker<ValueType>::checkDerivative(getDerivative(function, param), region);
170 if (res.first && !res.second) {
171 return Monotonicity::Incr;
172 } else if (!res.first && res.second) {
173 return Monotonicity::Decr;
174 } else if (res.first && res.second) {
175 return Monotonicity::Constant;
176 } else {
177 return Monotonicity::Not;
178 }
179}
180
181template<typename ValueType>
182ValueType& MonotonicityChecker<ValueType>::getDerivative(ValueType function, typename MonotonicityChecker<ValueType>::VariableType var) {
183 auto& derivativeMap = derivatives[function];
184 if (derivativeMap.find(var) == derivativeMap.end()) {
185 derivativeMap[var] = function.derivative(var);
186 }
187 return derivativeMap[var];
188}
189
190template class MonotonicityChecker<RationalFunction>;
191} // namespace analysis
192} // namespace storm
MonotonicityChecker(storage::SparseMatrix< ValueType > const &matrix)
Constructs a new MonotonicityChecker object.
utility::parametric::VariableType< ValueType >::type VariableType
static std::pair< bool, bool > checkDerivative(ValueType const &derivative, storage::ParameterRegion< ValueType > const &reg)
Checks if a derivative >=0 or/and <=0.
Monotonicity checkLocalMonotonicity(std::shared_ptr< Order > const &order, uint_fast64_t state, VariableType const &var, storage::ParameterRegion< ValueType > const &region)
Checks for local monotonicity at the given state.
This class is responsible for managing a set of typed variables and all expressions using these varia...
virtual void add(storm::expressions::Expression const &assertion) override
Adds an assertion to the solver's stack.
virtual void reset() override
Removes all assertions from the solver's stack.
virtual CheckResult check() override
Checks whether the conjunction of assertions that are currently on the solver's stack is satisfiable.
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.
const_rows getRow(index_type row) const
Returns an object representing the given row.
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
MonotonicityKind
The results of monotonicity checking for a single Parameter Region.
SFTBDDChecker::ValueType ValueType