Storm 1.11.1.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
OrderBasedMonotonicityBackend.cpp
Go to the documentation of this file.
2
7
9
10namespace storm::modelchecker {
11
12namespace detail {
13
14template<typename ParametricType, typename ConstantType>
15std::shared_ptr<storm::analysis::Order> extendOrder(storm::analysis::OrderExtender<ParametricType, ConstantType>& orderExtender,
16 std::shared_ptr<storm::analysis::Order> order, storm::storage::ParameterRegion<ParametricType> region) {
17 auto [orderPtr, unknState1, unknState2] = orderExtender.extendOrder(order, region);
18 order = orderPtr;
19 if (unknState1 != order->getNumberOfStates()) {
20 orderExtender.setUnknownStates(order, unknState1, unknState2);
21 }
22 return order;
23}
24
25template<typename ParametricType, typename ConstantType>
27 storm::storage::ParameterRegion<ParametricType> const& region, std::shared_ptr<storm::analysis::Order> const& order,
31 auto state = order->getNextDoneState(-1);
32 auto const& variablesAtState = parameterLifter.getOccurringVariablesAtState(); // TODO: this might be possible via the OrderExtender as well
33 while (state != order->getNumberOfStates()) {
34 if (localMonotonicityResult.getMonotonicity(state) == nullptr) {
35 auto variables = variablesAtState[state];
36 if (variables.size() == 0 || order->isBottomState(state) || order->isTopState(state)) {
37 localMonotonicityResult.setConstant(state);
38 } else {
39 for (auto const& var : variables) {
40 auto monotonicity = localMonotonicityResult.getMonotonicity(state, var);
41 if (!storm::analysis::isMonotone(monotonicity)) {
42 monotonicity = monotonicityChecker.checkLocalMonotonicity(order, state, var, region);
43 if (storm::analysis::isMonotone(monotonicity)) {
44 localMonotonicityResult.setMonotonicity(state, var, monotonicity);
45 } else {
46 // TODO: Skip for now?
47 }
48 }
49 }
50 }
51 }
52 state = order->getNextDoneState(state);
53 }
54 auto const& statesAtVariable = parameterLifter.getOccuringStatesAtVariable();
55 bool allDone = true;
56 for (auto const& entry : statesAtVariable) {
57 auto states = entry.second;
58 auto var = entry.first;
59 bool done = true;
60 for (auto const& state : states) {
61 done &= order->contains(state) && localMonotonicityResult.getMonotonicity(state, var) != storm::analysis::MonotonicityKind::Unknown;
62 if (!done) {
63 break;
64 }
65 }
66
67 allDone &= done;
68 if (done) {
69 localMonotonicityResult.getGlobalMonotonicityResult()->setDoneForVar(var);
70 }
71 }
72 if (allDone) {
73 localMonotonicityResult.setDone();
74 while (order->existsNextState()) {
75 // Simply add the states we couldn't add sofar between =) and =( as we could find local monotonicity for all parametric states
76 order->add(order->getNextStateNumber().second);
77 }
78 assert(order->getDoneBuilding());
79 }
80}
81} // namespace detail
82
83template<typename ParametricType, typename ConstantType>
85 : useOnlyGlobal(useOnlyGlobal), useBounds(useBounds) {
86 // Intentioanlly left empty
87}
88
89template<typename ParametricType, typename ConstantType>
93
94template<typename ParametricType, typename ConstantType>
98
99template<typename ParametricType, typename ConstantType>
102 if (useBounds) {
103 STORM_LOG_ASSERT(plaBoundFunction, "PLA bound function not registered.");
104 orderExtender->setMaxValuesInit(plaBoundFunction(env, region, storm::solver::OptimizationDirection::Maximize));
105 orderExtender->setMaxValuesInit(plaBoundFunction(env, region, storm::solver::OptimizationDirection::Minimize));
106 }
108 annotation.stateOrder = detail::extendOrder(*this->orderExtender, nullptr, region.region);
109 annotation.localMonotonicityResult = std::make_shared<storm::analysis::LocalMonotonicityResult<VariableType>>(annotation.stateOrder->getNumberOfStates());
110
111 for (auto& [var, kind] : this->globallyKnownMonotonicityInformation) {
112 if (kind == MonotonicityKind::Incr || kind == MonotonicityKind::Constant)
113 annotation.localMonotonicityResult->setMonotoneIncreasing(var);
114 else if (kind == MonotonicityKind::Decr)
115 annotation.localMonotonicityResult->setMonotoneDecreasing(var);
116 }
117
118 detail::extendLocalMonotonicityResult(region.region, annotation.stateOrder, *annotation.localMonotonicityResult, *this->monotonicityChecker,
119 *this->parameterLifterRef);
120 region.monotonicityAnnotation.data = annotation;
121}
122
123template<typename ParametricType, typename ConstantType>
125 auto annotation = region.monotonicityAnnotation.getOrderBasedMonotonicityAnnotation();
126 STORM_LOG_ASSERT(annotation.has_value(), "Order-based monotonicity annotation must be present.");
127 // Find out if we need to copy the order as it might be shared among subregions.
128 // Copy order only if it will potentially change and if it is shared with another region
129 bool const changeOrder = !annotation->stateOrder->getDoneBuilding() && orderExtender->isHope(annotation->stateOrder);
130 if (changeOrder && annotation->stateOrder.use_count() > 1) {
131 // TODO: orderExtender currently uses shared_ptr<Order> which likely interferes with the use_count() > 1 check above
132 // TODO: Make sure that only annotated regions own the order
133 auto newOrder = annotation->stateOrder->copy();
134 orderExtender->setUnknownStates(annotation->stateOrder, newOrder);
135 orderExtender->copyMinMax(annotation->stateOrder, newOrder);
136 annotation->stateOrder = newOrder;
137 }
138 if (changeOrder) {
139 detail::extendOrder(*this->orderExtender, annotation->stateOrder, region.region);
140 }
141 // Similarly handle local monotonicity result
142 bool const changeLocalMonotonicity = changeOrder && !annotation->localMonotonicityResult->isDone();
143 if (changeLocalMonotonicity && annotation->localMonotonicityResult.use_count() > 1) {
144 // TODO: Make sure that only annotated regions own the localMonotonicityResult
145 annotation->localMonotonicityResult = annotation->localMonotonicityResult->copy();
146 }
147 if (changeLocalMonotonicity) {
148 detail::extendLocalMonotonicityResult(region.region, annotation->stateOrder, *annotation->localMonotonicityResult, *this->monotonicityChecker,
149 *this->parameterLifterRef);
150 }
151}
152
153template<typename ParametricType, typename ConstantType>
156 auto annotation = region.monotonicityAnnotation.getOrderBasedMonotonicityAnnotation();
157 STORM_LOG_ASSERT(annotation.has_value(), "Order-based monotonicity annotation must be present.");
158 if (useBounds && !annotation->stateOrder->getDoneBuilding()) {
159 STORM_LOG_ASSERT(plaBoundFunction, "PLA bound function not registered.");
160 // TODO: Can re-use bounds from performed PLA call before splitting is triggered. Maybe allow some caching in the PLA checker?
161 orderExtender->setMinMaxValues(annotation->stateOrder, plaBoundFunction(env, region, storm::solver::OptimizationDirection::Minimize),
162 plaBoundFunction(env, region, storm::solver::OptimizationDirection::Maximize));
163 }
164}
165
166template<typename ParametricType, typename ConstantType>
167std::map<typename OrderBasedMonotonicityBackend<ParametricType, ConstantType>::VariableType,
170 // TODO: Old implementation had checkForPossibleMonotonicity to determine this based on samples. Consider re-adding that.
171 // https://github.com/moves-rwth/storm/blob/5c89b2d1051b3abdbb8659101d60331c680b7050/src/storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.cpp#L622
172 // For now, we just do this based on known global monotonicity.
174}
175
176template<typename ParametricType, typename ConstantType>
178 storm::storage::SparseMatrix<ParametricType> const& parametricTransitionMatrix) {
179 monotonicityChecker = storm::analysis::MonotonicityChecker<ParametricType>(parametricTransitionMatrix);
180}
181
182template<typename ParametricType, typename ConstantType>
183void OrderBasedMonotonicityBackend<ParametricType, ConstantType>::initializeOrderExtender(
184 storm::storage::BitVector const& topStates, storm::storage::BitVector const& bottomStates,
185 storm::storage::SparseMatrix<ParametricType> const& parametricTransitionMatrix) {
186 orderExtender = storm::analysis::OrderExtender<ParametricType, ConstantType>(topStates, bottomStates, parametricTransitionMatrix);
187}
188
189template<typename ParametricType, typename ConstantType>
190void OrderBasedMonotonicityBackend<ParametricType, ConstantType>::registerParameterLifterReference(
192 this->parameterLifterRef.reset(parameterLifter);
193}
194
195template<typename ParametricType, typename ConstantType>
196void OrderBasedMonotonicityBackend<ParametricType, ConstantType>::registerPLABoundFunction(
197 std::function<std::vector<ConstantType>(storm::Environment const&, AnnotatedRegion<ParametricType>&, storm::OptimizationDirection)> fun) {
198 this->plaBoundFunction = fun;
199}
200
201template<typename ParametricType, typename ConstantType>
202storm::storage::BitVector OrderBasedMonotonicityBackend<ParametricType, ConstantType>::getChoicesToFixForPLASolver(
203 AnnotatedRegion<ParametricType> const& region, storm::OptimizationDirection dir, std::vector<uint64_t>& schedulerChoices) {
204 if (useOnlyGlobal) {
205 return {};
206 }
207 STORM_LOG_ASSERT(parameterLifterRef.has_value(), "Parameter lifter reference not initialized.");
208
209 auto monotonicityAnnotation = region.monotonicityAnnotation.getOrderBasedMonotonicityAnnotation();
210 STORM_LOG_ASSERT(monotonicityAnnotation.has_value() && monotonicityAnnotation->localMonotonicityResult != nullptr,
211 "Order-based monotonicity annotation must be present.");
212 auto const& localMonotonicityResult = *monotonicityAnnotation->localMonotonicityResult;
213
214 storm::storage::BitVector result(schedulerChoices.size(), false);
215
216 auto const& occurringVariables = parameterLifterRef->getOccurringVariablesAtState();
217 for (uint64_t state = 0; state < parameterLifterRef->getRowGroupCount(); ++state) {
218 auto oldStateNumber = parameterLifterRef->getOriginalStateNumber(state);
219 auto const& variables = occurringVariables.at(oldStateNumber);
220 // point at which we start with rows for this state
221
222 STORM_LOG_THROW(variables.size() <= 1, storm::exceptions::NotImplementedException,
223 "Using localMonRes not yet implemented for states with 2 or more variables, please run without --use-monotonicity");
224
225 bool allMonotone = true;
226 for (auto var : variables) {
227 auto const monotonicity = localMonotonicityResult.getMonotonicity(oldStateNumber, var);
228
229 bool const fixToLowerBound =
230 monotonicity == MonotonicityKind::Constant || monotonicity == (storm::solver::minimize(dir) ? MonotonicityKind::Incr : MonotonicityKind::Decr);
231 bool const fixToUpperBound =
232 monotonicity == MonotonicityKind::Constant || monotonicity == (storm::solver::maximize(dir) ? MonotonicityKind::Incr : MonotonicityKind::Decr);
233 if (fixToLowerBound || fixToUpperBound) {
234 // TODO: Setting the lower/upper bounded choices like this is fragile and should be replaced by a more robust solution
235 schedulerChoices[state] = fixToLowerBound ? 0 : 1;
236 } else {
237 allMonotone = false;
238 }
239 }
240 if (allMonotone) {
241 result.set(state);
242 }
243 }
244 return result;
245}
246
247template class OrderBasedMonotonicityBackend<storm::RationalFunction, double>;
248template class OrderBasedMonotonicityBackend<storm::RationalFunction, storm::RationalNumber>;
249
250} // namespace storm::modelchecker
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.
std::tuple< std::shared_ptr< Order >, uint_fast64_t, uint_fast64_t > extendOrder(std::shared_ptr< Order > order, storm::storage::ParameterRegion< ValueType > region, std::shared_ptr< MonotonicityResult< VariableType > > monRes=nullptr, std::shared_ptr< expressions::BinaryRelationExpression > assumption=nullptr)
Extends the order for the given region.
void setUnknownStates(std::shared_ptr< Order > order, uint_fast64_t state1, uint_fast64_t state2)
virtual std::map< VariableType, MonotonicityKind > getOptimisticMonotonicityApproximation(AnnotatedRegion< ParametricType > const &region)
Returns an optimistic approximation of the monotonicity of the parameters in this region.
OrderBasedMonotonicityBackend(bool useOnlyGlobal=false, bool useBounds=false)
virtual void initializeMonotonicity(storm::Environment const &env, AnnotatedRegion< ParametricType > &region) override
Initializes the monotonicity information for the given region.
virtual bool recommendModelSimplifications() const override
Returns whether additional model simplifications are recommended when using this backend.
virtual bool requiresInteractionWithRegionModelChecker() const override
Returns true, since a region model checker needs to implement specific methods to properly use this b...
typename MonotonicityBackend< ParametricType >::MonotonicityKind MonotonicityKind
virtual std::map< VariableType, MonotonicityKind > getOptimisticMonotonicityApproximation(AnnotatedRegion< ParametricType > const &region) override
Returns an optimistic approximation of the monotonicity of the parameters in this region.
virtual void updateMonotonicity(storm::Environment const &env, AnnotatedRegion< ParametricType > &region) override
Updates the monotonicity information for the given region.
virtual void updateMonotonicityBeforeSplitting(storm::Environment const &env, AnnotatedRegion< ParametricType > &region) override
Updates the monotonicity information for the given region right before splitting it.
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
storm::utility::parametric::VariableType< ParametricType >::type VariableType
A class that holds a possibly non-square matrix in the compressed row storage format.
This class lifts parameter choices to nondeterminism: For each row in the given matrix that considerd...
std::map< VariableType, std::set< uint_fast64_t > > const & getOccuringStatesAtVariable() const
std::vector< std::set< VariableType > > const & getOccurringVariablesAtState() const
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
@ Unknown
the monotonicity result is unknown
bool isMonotone(MonotonicityKind kind)
void extendLocalMonotonicityResult(storm::storage::ParameterRegion< ParametricType > const &region, std::shared_ptr< storm::analysis::Order > const &order, storm::analysis::LocalMonotonicityResult< typename storm::storage::ParameterRegion< ParametricType >::VariableType > &localMonotonicityResult, storm::analysis::MonotonicityChecker< ParametricType > &monotonicityChecker, storm::transformer::ParameterLifter< ParametricType, ConstantType > const &parameterLifter)
std::shared_ptr< storm::analysis::Order > extendOrder(storm::analysis::OrderExtender< ParametricType, ConstantType > &orderExtender, std::shared_ptr< storm::analysis::Order > order, storm::storage::ParameterRegion< ParametricType > region)
bool constexpr maximize(OptimizationDirection d)
bool constexpr minimize(OptimizationDirection d)
storm::modelchecker::MonotonicityAnnotation< ParametricType > monotonicityAnnotation
Whether the result is known through monotonicity.
Region const region
The subregions of this region.
std::shared_ptr< storm::analysis::LocalMonotonicityResult< VariableType > > localMonotonicityResult