Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
OrderBasedMonotonicityBackend.cpp
Go to the documentation of this file.
2
10
11namespace storm::modelchecker {
12
13namespace detail {
14
15template<typename ParametricType, typename ConstantType>
16std::shared_ptr<storm::analysis::Order> extendOrder(storm::analysis::OrderExtender<ParametricType, ConstantType>& orderExtender,
17 std::shared_ptr<storm::analysis::Order> order, storm::storage::ParameterRegion<ParametricType> region) {
18 auto [orderPtr, unknState1, unknState2] = orderExtender.extendOrder(order, region);
19 order = orderPtr;
20 // An inconsistent order carries the same "done" sentinel as a successfully built one, so the
21 // sentinel alone must not be trusted. Refuse to derive monotonicity from a contradictory order.
22 STORM_LOG_THROW(!order->isInvalid(), storm::exceptions::InvalidStateException, "Order-based monotonicity analysis produced an inconsistent order.");
23 if (unknState1 != order->getNumberOfStates()) {
24 orderExtender.setUnknownStates(order, unknState1, unknState2);
25 }
26 return order;
27}
28
29template<typename ParametricType, typename ConstantType>
31 storm::storage::ParameterRegion<ParametricType> const& region, std::shared_ptr<storm::analysis::Order> const& order,
35 auto state = order->getNextDoneState(-1);
36 auto const& variablesAtState = parameterLifter.getOccurringVariablesAtState(); // TODO: this might be possible via the OrderExtender as well
37 while (state != order->getNumberOfStates()) {
38 if (localMonotonicityResult.getMonotonicity(state) == nullptr) {
39 auto variables = variablesAtState[state];
40 if (variables.size() == 0 || order->isBottomState(state) || order->isTopState(state)) {
41 localMonotonicityResult.setConstant(state);
42 } else {
43 for (auto const& var : variables) {
44 auto monotonicity = localMonotonicityResult.getMonotonicity(state, var);
45 if (!storm::analysis::isMonotone(monotonicity)) {
46 monotonicity = monotonicityChecker.checkLocalMonotonicity(order, state, var, region);
47 if (storm::analysis::isMonotone(monotonicity)) {
48 localMonotonicityResult.setMonotonicity(state, var, monotonicity);
49 } else {
50 // TODO: Skip for now?
51 }
52 }
53 }
54 }
55 }
56 state = order->getNextDoneState(state);
57 }
58 auto const& statesAtVariable = parameterLifter.getOccuringStatesAtVariable();
59 bool allDone = true;
60 for (auto const& entry : statesAtVariable) {
61 auto states = entry.second;
62 auto var = entry.first;
63 bool done = true;
64 for (auto const& state : states) {
65 done &= order->contains(state) && localMonotonicityResult.getMonotonicity(state, var) != storm::analysis::MonotonicityKind::Unknown;
66 if (!done) {
67 break;
68 }
69 }
70
71 allDone &= done;
72 if (done) {
73 localMonotonicityResult.getGlobalMonotonicityResult()->setDoneForVar(var);
74 }
75 }
76 if (allDone) {
77 localMonotonicityResult.setDone();
78 while (order->existsNextState()) {
79 // Simply add the states we couldn't add sofar between =) and =( as we could find local monotonicity for all parametric states
80 order->add(order->getNextStateNumber().second);
81 }
82 STORM_LOG_ASSERT(order->getDoneBuilding(), "Order should be done building.");
83 }
84}
85} // namespace detail
86
87template<typename ParametricType, typename ConstantType>
89 : useOnlyGlobal(useOnlyGlobal), useBounds(useBounds) {
90 // Intentioanlly left empty
91}
92
93template<typename ParametricType, typename ConstantType>
97
98template<typename ParametricType, typename ConstantType>
102
103template<typename ParametricType, typename ConstantType>
106 if (useBounds) {
107 STORM_LOG_ASSERT(plaBoundFunction, "PLA bound function not registered.");
108 orderExtender->setMaxValuesInit(plaBoundFunction(env, region, storm::solver::OptimizationDirection::Maximize));
109 orderExtender->setMinValuesInit(plaBoundFunction(env, region, storm::solver::OptimizationDirection::Minimize));
110 }
112 annotation.stateOrder = detail::extendOrder(*this->orderExtender, nullptr, region.region);
113 annotation.localMonotonicityResult = std::make_shared<storm::analysis::LocalMonotonicityResult<VariableType>>(annotation.stateOrder->getNumberOfStates());
114
115 for (auto& [var, kind] : this->globallyKnownMonotonicityInformation) {
116 if (kind == MonotonicityKind::Incr || kind == MonotonicityKind::Constant) {
117 annotation.localMonotonicityResult->setMonotoneIncreasing(var);
118 } else if (kind == MonotonicityKind::Decr) {
119 annotation.localMonotonicityResult->setMonotoneDecreasing(var);
120 }
121 }
122
123 detail::extendLocalMonotonicityResult(region.region, annotation.stateOrder, *annotation.localMonotonicityResult, *this->monotonicityChecker,
124 *this->parameterLifterRef);
125 region.monotonicityAnnotation.data = annotation;
126}
127
128template<typename ParametricType, typename ConstantType>
130 auto annotation = region.monotonicityAnnotation.getOrderBasedMonotonicityAnnotation();
131 STORM_LOG_ASSERT(annotation.has_value(), "Order-based monotonicity annotation must be present.");
132 // Find out if we need to copy the order as it might be shared among subregions.
133 // Copy order only if it will potentially change and if it is shared with another region
134 bool const changeOrder = !annotation->stateOrder->getDoneBuilding() && orderExtender->isHope(annotation->stateOrder);
135 if (changeOrder && annotation->stateOrder.use_count() > 1) {
136 // TODO: Make sure that only annotated regions own the order
137 auto newOrder = annotation->stateOrder->copy();
138 orderExtender->copyContext(annotation->stateOrder, newOrder);
139 annotation->stateOrder = newOrder;
140 }
141 if (changeOrder) {
142 detail::extendOrder(*this->orderExtender, annotation->stateOrder, region.region);
143 }
144 // Similarly handle local monotonicity result
145 bool const changeLocalMonotonicity = changeOrder && !annotation->localMonotonicityResult->isDone();
146 if (changeLocalMonotonicity && annotation->localMonotonicityResult.use_count() > 1) {
147 // TODO: Make sure that only annotated regions own the localMonotonicityResult
148 annotation->localMonotonicityResult = annotation->localMonotonicityResult->copy();
149 }
150 if (changeLocalMonotonicity) {
151 detail::extendLocalMonotonicityResult(region.region, annotation->stateOrder, *annotation->localMonotonicityResult, *this->monotonicityChecker,
152 *this->parameterLifterRef);
153 }
154}
155
156template<typename ParametricType, typename ConstantType>
159 auto annotation = region.monotonicityAnnotation.getOrderBasedMonotonicityAnnotation();
160 STORM_LOG_ASSERT(annotation.has_value(), "Order-based monotonicity annotation must be present.");
161 if (useBounds && !annotation->stateOrder->getDoneBuilding()) {
162 STORM_LOG_ASSERT(plaBoundFunction, "PLA bound function not registered.");
163 // TODO: Can re-use bounds from performed PLA call before splitting is triggered. Maybe allow some caching in the PLA checker?
164 orderExtender->setMinMaxValues(annotation->stateOrder, plaBoundFunction(env, region, storm::solver::OptimizationDirection::Minimize),
165 plaBoundFunction(env, region, storm::solver::OptimizationDirection::Maximize));
166 }
167}
168
169template<typename ParametricType, typename ConstantType>
170std::map<typename OrderBasedMonotonicityBackend<ParametricType, ConstantType>::VariableType,
173 // TODO: Old implementation had checkForPossibleMonotonicity to determine this based on samples. Consider re-adding that.
174 // https://github.com/stormchecker/storm/blob/5c89b2d1051b3abdbb8659101d60331c680b7050/src/storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.cpp#L622
175 // For now, we just do this based on known global monotonicity.
177}
178
179template<typename ParametricType, typename ConstantType>
180void OrderBasedMonotonicityBackend<ParametricType, ConstantType>::initializeMonotonicityChecker(
181 storm::storage::SparseMatrix<ParametricType> const& parametricTransitionMatrix) {
182 monotonicityChecker = storm::analysis::MonotonicityChecker<ParametricType>(parametricTransitionMatrix);
183}
184
185template<typename ParametricType, typename ConstantType>
186void OrderBasedMonotonicityBackend<ParametricType, ConstantType>::initializeOrderExtender(
187 storm::storage::BitVector const& topStates, storm::storage::BitVector const& bottomStates,
188 storm::storage::SparseMatrix<ParametricType> const& parametricTransitionMatrix) {
189 orderExtender = storm::analysis::OrderExtender<ParametricType, ConstantType>(topStates, bottomStates, parametricTransitionMatrix);
190}
191
192template<typename ParametricType, typename ConstantType>
193void OrderBasedMonotonicityBackend<ParametricType, ConstantType>::registerParameterLifterReference(
195 this->parameterLifterRef.reset(parameterLifter);
196}
197
198template<typename ParametricType, typename ConstantType>
199void OrderBasedMonotonicityBackend<ParametricType, ConstantType>::registerPLABoundFunction(
200 std::function<std::vector<ConstantType>(storm::Environment const&, AnnotatedRegion<ParametricType>&, storm::OptimizationDirection)> fun) {
201 this->plaBoundFunction = fun;
202}
203
204template<typename ParametricType, typename ConstantType>
205storm::storage::BitVector OrderBasedMonotonicityBackend<ParametricType, ConstantType>::getChoicesToFixForPLASolver(
206 AnnotatedRegion<ParametricType> const& region, storm::OptimizationDirection dir, std::vector<uint64_t>& schedulerChoices) {
207 if (useOnlyGlobal) {
208 return {};
209 }
210 STORM_LOG_ASSERT(parameterLifterRef.has_value(), "Parameter lifter reference not initialized.");
211
212 auto monotonicityAnnotation = region.monotonicityAnnotation.getOrderBasedMonotonicityAnnotation();
213 STORM_LOG_ASSERT(monotonicityAnnotation.has_value() && monotonicityAnnotation->localMonotonicityResult != nullptr,
214 "Order-based monotonicity annotation must be present.");
215 auto const& localMonotonicityResult = *monotonicityAnnotation->localMonotonicityResult;
216
217 storm::storage::BitVector result(schedulerChoices.size(), false);
218
219 auto const& occurringVariables = parameterLifterRef->getOccurringVariablesAtState();
220 for (uint64_t state = 0; state < parameterLifterRef->getRowGroupCount(); ++state) {
221 auto oldStateNumber = parameterLifterRef->getOriginalStateNumber(state);
222 auto const& variables = occurringVariables.at(oldStateNumber);
223 // point at which we start with rows for this state
224
225 STORM_LOG_THROW(variables.size() <= 1, storm::exceptions::NotImplementedException,
226 "Using localMonRes not yet implemented for states with 2 or more variables, please run without --use-monotonicity.");
227
228 bool allMonotone = true;
229 for (auto var : variables) {
230 auto const monotonicity = localMonotonicityResult.getMonotonicity(oldStateNumber, var);
231
232 bool const fixToLowerBound =
233 monotonicity == MonotonicityKind::Constant || monotonicity == (storm::solver::minimize(dir) ? MonotonicityKind::Incr : MonotonicityKind::Decr);
234 bool const fixToUpperBound =
235 monotonicity == MonotonicityKind::Constant || monotonicity == (storm::solver::maximize(dir) ? MonotonicityKind::Incr : MonotonicityKind::Decr);
236 if (fixToLowerBound || fixToUpperBound) {
237 // TODO: Setting the lower/upper bounded choices like this is fragile and should be replaced by a more robust solution
238 schedulerChoices[state] = fixToLowerBound ? 0 : 1;
239 } else {
240 allMonotone = false;
241 }
242 }
243 if (allMonotone) {
244 result.set(state);
245 }
246 }
247 return result;
248}
249
252
253} // 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::optional< Assumption > assumption=std::nullopt)
Extends the order for the given region.
void setUnknownStates(std::shared_ptr< Order > order, uint_fast64_t state1, uint_fast64_t state2)
std::map< VariableType, MonotonicityKind > globallyKnownMonotonicityInformation
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:9
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:39
@ 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)
solver::OptimizationDirection OptimizationDirection
std::shared_ptr< storm::analysis::LocalMonotonicityResult< VariableType > > localMonotonicityResult