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