Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
OrderBasedMonotonicityBackend.cpp
Go to the documentation of this file.
2
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 STORM_LOG_ASSERT(order->getDoneBuilding(), "Order should be done building.");
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
119 detail::extendLocalMonotonicityResult(region.region, annotation.stateOrder, *annotation.localMonotonicityResult, *this->monotonicityChecker,
120 *this->parameterLifterRef);
121 region.monotonicityAnnotation.data = annotation;
122}
123
124template<typename ParametricType, typename ConstantType>
126 auto annotation = region.monotonicityAnnotation.getOrderBasedMonotonicityAnnotation();
127 STORM_LOG_ASSERT(annotation.has_value(), "Order-based monotonicity annotation must be present.");
128 // Find out if we need to copy the order as it might be shared among subregions.
129 // Copy order only if it will potentially change and if it is shared with another region
130 bool const changeOrder = !annotation->stateOrder->getDoneBuilding() && orderExtender->isHope(annotation->stateOrder);
131 if (changeOrder && annotation->stateOrder.use_count() > 1) {
132 // TODO: orderExtender currently uses shared_ptr<Order> which likely interferes with the use_count() > 1 check above
133 // TODO: Make sure that only annotated regions own the order
134 auto newOrder = annotation->stateOrder->copy();
135 orderExtender->setUnknownStates(annotation->stateOrder, newOrder);
136 orderExtender->copyMinMax(annotation->stateOrder, newOrder);
137 annotation->stateOrder = newOrder;
138 }
139 if (changeOrder) {
140 detail::extendOrder(*this->orderExtender, annotation->stateOrder, region.region);
141 }
142 // Similarly handle local monotonicity result
143 bool const changeLocalMonotonicity = changeOrder && !annotation->localMonotonicityResult->isDone();
144 if (changeLocalMonotonicity && annotation->localMonotonicityResult.use_count() > 1) {
145 // TODO: Make sure that only annotated regions own the localMonotonicityResult
146 annotation->localMonotonicityResult = annotation->localMonotonicityResult->copy();
147 }
148 if (changeLocalMonotonicity) {
149 detail::extendLocalMonotonicityResult(region.region, annotation->stateOrder, *annotation->localMonotonicityResult, *this->monotonicityChecker,
150 *this->parameterLifterRef);
151 }
152}
153
154template<typename ParametricType, typename ConstantType>
157 auto annotation = region.monotonicityAnnotation.getOrderBasedMonotonicityAnnotation();
158 STORM_LOG_ASSERT(annotation.has_value(), "Order-based monotonicity annotation must be present.");
159 if (useBounds && !annotation->stateOrder->getDoneBuilding()) {
160 STORM_LOG_ASSERT(plaBoundFunction, "PLA bound function not registered.");
161 // TODO: Can re-use bounds from performed PLA call before splitting is triggered. Maybe allow some caching in the PLA checker?
162 orderExtender->setMinMaxValues(annotation->stateOrder, plaBoundFunction(env, region, storm::solver::OptimizationDirection::Minimize),
163 plaBoundFunction(env, region, storm::solver::OptimizationDirection::Maximize));
164 }
165}
166
167template<typename ParametricType, typename ConstantType>
168std::map<typename OrderBasedMonotonicityBackend<ParametricType, ConstantType>::VariableType,
171 // TODO: Old implementation had checkForPossibleMonotonicity to determine this based on samples. Consider re-adding that.
172 // https://github.com/stormchecker/storm/blob/5c89b2d1051b3abdbb8659101d60331c680b7050/src/storm-pars/modelchecker/region/SparseParameterLiftingModelChecker.cpp#L622
173 // For now, we just do this based on known global monotonicity.
175}
176
177template<typename ParametricType, typename ConstantType>
178void OrderBasedMonotonicityBackend<ParametricType, ConstantType>::initializeMonotonicityChecker(
179 storm::storage::SparseMatrix<ParametricType> const& parametricTransitionMatrix) {
180 monotonicityChecker = storm::analysis::MonotonicityChecker<ParametricType>(parametricTransitionMatrix);
181}
182
183template<typename ParametricType, typename ConstantType>
184void OrderBasedMonotonicityBackend<ParametricType, ConstantType>::initializeOrderExtender(
185 storm::storage::BitVector const& topStates, storm::storage::BitVector const& bottomStates,
186 storm::storage::SparseMatrix<ParametricType> const& parametricTransitionMatrix) {
187 orderExtender = storm::analysis::OrderExtender<ParametricType, ConstantType>(topStates, bottomStates, parametricTransitionMatrix);
188}
189
190template<typename ParametricType, typename ConstantType>
191void OrderBasedMonotonicityBackend<ParametricType, ConstantType>::registerParameterLifterReference(
193 this->parameterLifterRef.reset(parameterLifter);
194}
195
196template<typename ParametricType, typename ConstantType>
197void OrderBasedMonotonicityBackend<ParametricType, ConstantType>::registerPLABoundFunction(
198 std::function<std::vector<ConstantType>(storm::Environment const&, AnnotatedRegion<ParametricType>&, storm::OptimizationDirection)> fun) {
199 this->plaBoundFunction = fun;
200}
201
202template<typename ParametricType, typename ConstantType>
203storm::storage::BitVector OrderBasedMonotonicityBackend<ParametricType, ConstantType>::getChoicesToFixForPLASolver(
204 AnnotatedRegion<ParametricType> const& region, storm::OptimizationDirection dir, std::vector<uint64_t>& schedulerChoices) {
205 if (useOnlyGlobal) {
206 return {};
207 }
208 STORM_LOG_ASSERT(parameterLifterRef.has_value(), "Parameter lifter reference not initialized.");
209
210 auto monotonicityAnnotation = region.monotonicityAnnotation.getOrderBasedMonotonicityAnnotation();
211 STORM_LOG_ASSERT(monotonicityAnnotation.has_value() && monotonicityAnnotation->localMonotonicityResult != nullptr,
212 "Order-based monotonicity annotation must be present.");
213 auto const& localMonotonicityResult = *monotonicityAnnotation->localMonotonicityResult;
214
215 storm::storage::BitVector result(schedulerChoices.size(), false);
216
217 auto const& occurringVariables = parameterLifterRef->getOccurringVariablesAtState();
218 for (uint64_t state = 0; state < parameterLifterRef->getRowGroupCount(); ++state) {
219 auto oldStateNumber = parameterLifterRef->getOriginalStateNumber(state);
220 auto const& variables = occurringVariables.at(oldStateNumber);
221 // point at which we start with rows for this state
222
223 STORM_LOG_THROW(variables.size() <= 1, storm::exceptions::NotImplementedException,
224 "Using localMonRes not yet implemented for states with 2 or more variables, please run without --use-monotonicity.");
225
226 bool allMonotone = true;
227 for (auto var : variables) {
228 auto const monotonicity = localMonotonicityResult.getMonotonicity(oldStateNumber, var);
229
230 bool const fixToLowerBound =
231 monotonicity == MonotonicityKind::Constant || monotonicity == (storm::solver::minimize(dir) ? MonotonicityKind::Incr : MonotonicityKind::Decr);
232 bool const fixToUpperBound =
233 monotonicity == MonotonicityKind::Constant || monotonicity == (storm::solver::maximize(dir) ? MonotonicityKind::Incr : MonotonicityKind::Decr);
234 if (fixToLowerBound || fixToUpperBound) {
235 // TODO: Setting the lower/upper bounded choices like this is fragile and should be replaced by a more robust solution
236 schedulerChoices[state] = fixToLowerBound ? 0 : 1;
237 } else {
238 allMonotone = false;
239 }
240 }
241 if (allMonotone) {
242 result.set(state);
243 }
244 }
245 return result;
246}
247
250
251} // 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)
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:28
@ 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