20template<
typename ValueType,
typename ConstantType>
22 std::vector<std::shared_ptr<logic::Formula const>> formulas,
24 double const& precision,
bool dotOutput)
25 : assumptionMaker(model->getTransitionMatrix()) {
29 this->formulas = formulas;
31 this->matrix = model->getTransitionMatrix();
32 this->dotOutput = dotOutput;
34 if (regions.size() == 1) {
35 this->region = *(regions.begin());
39 std::set<VariableType> vars;
41 for (
auto var : vars) {
44 lowerBoundaries.insert(std::make_pair(var, lb));
45 upperBoundaries.insert(std::make_pair(var, ub));
50 if (numberOfSamples > 2) {
59 if (numberOfSamples > 0) {
60 STORM_LOG_WARN(
"At least 3 sample points are needed to check for monotonicity on samples, not using samples for now");
67 for (uint_fast64_t i = 0; i < matrix.getRowCount(); ++i) {
68 std::set<VariableType> occurringVariables;
70 for (
auto& entry : matrix.getRow(i)) {
73 for (
auto& var : occurringVariables) {
74 occuringStatesAtVariable[var].push_back(i);
80template<
typename ValueType,
typename ConstantType>
81std::map<std::shared_ptr<Order>, std::pair<std::shared_ptr<MonotonicityResult<typename MonotonicityHelper<ValueType, ConstantType>::VariableType>>,
82 std::vector<std::shared_ptr<expressions::BinaryRelationExpression>>>>
86 this->extender->initializeMinMaxValues(region);
93 for (
auto itr : monResults) {
94 if (itr.first !=
nullptr) {
95 std::cout <<
"Number of done states: " << itr.first->getNumberOfDoneStates() <<
'\n';
98 for (
auto& entry : resultCheckOnSamples.getMonotonicityResult()) {
99 if (entry.second == Monotonicity::Not) {
100 itr.second.first->updateMonotonicityResult(entry.first, entry.second,
true);
104 std::string temp = itr.second.first->toString();
106 for (
auto& assumption : itr.second.second) {
110 outfile <<
"Assumptions: \n"
114 outfile << *assumption;
119 outfile <<
"No Assumptions\n";
121 outfile <<
"Monotonicity Result: \n"
122 <<
" " << temp <<
"\n\n";
125 if (monResults.size() == 0) {
126 outfile <<
"No monotonicity found, as the order is insufficient\n";
128 outfile <<
"Monotonicity Result on samples: " << resultCheckOnSamples.toString() <<
'\n';
134 STORM_LOG_WARN_COND(monResults.size() <= 10,
"Too many Reachability Orders. Dot Output will only be created for 10.");
136 auto orderItr = monResults.begin();
137 while (i < 10 && orderItr != monResults.end()) {
138 std::ofstream dotOutfile;
139 std::string name = dotOutfileName + std::to_string(i);
141 dotOutfile <<
"Assumptions:\n";
142 auto assumptionItr = orderItr->second.second.begin();
143 while (assumptionItr != orderItr->second.second.end()) {
144 dotOutfile << *assumptionItr <<
'\n';
149 orderItr->first->dotOutputToFile(dotOutfile);
158template<
typename ValueType,
typename ConstantType>
159std::shared_ptr<LocalMonotonicityResult<typename MonotonicityHelper<ValueType, ConstantType>::VariableType>>
162 for (uint_fast64_t state = 0; state < model->getNumberOfStates(); ++state) {
163 for (
auto& var : extender->getVariablesOccuringAtState()[state]) {
164 localMonRes.
setMonotonicity(state, var, extender->getMonotoncityChecker().checkLocalMonotonicity(order, state, var, region));
167 localMonRes.
setDone(order->getDoneBuilding());
168 return std::make_shared<LocalMonotonicityResult<VariableType>>(localMonRes);
172template<
typename ValueType,
typename ConstantType>
173void MonotonicityHelper<ValueType, ConstantType>::createOrder() {
175 std::tuple<std::shared_ptr<Order>, uint_fast64_t, uint_fast64_t> criticalTuple;
179 criticalTuple = extender->toOrder(region, monRes);
181 std::map<std::shared_ptr<Order>, std::vector<std::shared_ptr<expressions::BinaryRelationExpression>>> result;
183 auto val1 = std::get<1>(criticalTuple);
184 auto val2 = std::get<2>(criticalTuple);
185 auto numberOfStates = model->getNumberOfStates();
186 std::vector<std::shared_ptr<expressions::BinaryRelationExpression>> assumptions;
188 if (val1 == numberOfStates && val2 == numberOfStates) {
189 auto resAssumptionPair =
190 std::pair<std::shared_ptr<MonotonicityResult<VariableType>>, std::vector<std::shared_ptr<expressions::BinaryRelationExpression>>>(monRes,
193 std::pair<std::shared_ptr<Order>,
195 std::get<0>(criticalTuple), resAssumptionPair));
196 }
else if (val1 != numberOfStates && val2 != numberOfStates) {
197 extendOrderWithAssumptions(std::get<0>(criticalTuple), val1, val2, assumptions, monRes);
203template<
typename ValueType,
typename ConstantType>
204void MonotonicityHelper<ValueType, ConstantType>::extendOrderWithAssumptions(std::shared_ptr<Order> order, uint_fast64_t val1, uint_fast64_t val2,
205 std::vector<std::shared_ptr<expressions::BinaryRelationExpression>> assumptions,
207 std::map<std::shared_ptr<Order>, std::vector<std::shared_ptr<expressions::BinaryRelationExpression>>> result;
208 if (order->isInvalid()) {
213 auto numberOfStates = model->getNumberOfStates();
214 if (val1 == numberOfStates || val2 == numberOfStates) {
215 STORM_LOG_ASSERT(val1 == val2,
"Values should be equal when reaching numberOfStates.");
216 STORM_LOG_ASSERT(order->getNumberOfAddedStates() == order->getNumberOfStates(),
"Added states count mismatch.");
217 auto resAssumptionPair =
218 std::pair<std::shared_ptr<MonotonicityResult<VariableType>>, std::vector<std::shared_ptr<expressions::BinaryRelationExpression>>>(monRes,
221 std::pair<std::shared_ptr<Order>,
223 std::move(order), std::move(resAssumptionPair)));
226 STORM_LOG_INFO(
"Creating assumptions for " << val1 <<
" and " << val2 <<
". ");
227 auto newAssumptions = assumptionMaker.createAndCheckAssumptions(val1, val2, order, region);
228 STORM_LOG_ASSERT(newAssumptions.size() <= 3,
"Expected at most 3 assumptions.");
229 auto itr = newAssumptions.begin();
230 if (newAssumptions.size() == 0) {
232 for (
auto& entry : occuringStatesAtVariable) {
233 for (
auto& state : entry.second) {
234 extender->checkParOnStateMonRes(state, order, entry.first, monRes);
235 if (monRes->getMonotonicity(entry.first) == Monotonicity::Unknown) {
239 monRes->setDoneForVar(entry.first);
241 monResults.insert({order, {monRes, assumptions}});
242 STORM_LOG_INFO(
" None of the assumptions were valid, we stop exploring the current order");
244 STORM_LOG_INFO(
" Created " << newAssumptions.size() <<
" assumptions, we continue extending the current order");
247 while (itr != newAssumptions.end()) {
248 auto assumption = *itr;
251 if (itr != newAssumptions.end()) {
253 auto orderCopy = order->copy();
254 auto assumptionsCopy = std::vector<std::shared_ptr<expressions::BinaryRelationExpression>>(assumptions);
255 auto monResCopy = monRes->copy();
259 assumptionsCopy.push_back(std::move(assumption.first));
261 auto criticalTuple = extender->extendOrder(orderCopy, region, monResCopy, assumption.first);
262 extendOrderWithAssumptions(std::get<0>(criticalTuple), std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptionsCopy, monResCopy);
267 assumptions.push_back(std::move(assumption.first));
269 auto criticalTuple = extender->extendOrder(order, region, monRes, assumption.first);
270 extendOrderWithAssumptions(std::get<0>(criticalTuple), std::get<1>(criticalTuple), std::get<2>(criticalTuple), assumptions, monRes);
277template<
typename ValueType,
typename ConstantType>
278void MonotonicityHelper<ValueType, ConstantType>::checkMonotonicityOnSamples(std::shared_ptr<models::sparse::Dtmc<ValueType>> model,
279 uint_fast64_t numberOfSamples) {
282 auto instantiator = utility::ModelInstantiator<models::sparse::Dtmc<ValueType>, models::sparse::Dtmc<ConstantType>>(*model);
284 std::vector<std::vector<ConstantType>> samples;
286 for (
auto itr = variables.begin(); itr != variables.end(); ++itr) {
287 ConstantType previous = -1;
293 for (uint_fast64_t i = 0; (monDecr || monIncr) &&
i < numberOfSamples; ++
i) {
296 for (
auto itr2 = variables.begin(); itr2 != variables.end(); ++itr2) {
298 if ((*itr) == (*itr2)) {
299 auto lb = region.getLowerBoundary(itr->name());
300 auto ub = region.getUpperBoundary(itr->name());
304 auto lb = region.getLowerBoundary(itr2->name());
305 valuation[*itr2] = utility::convertNumber<typename utility::parametric::CoefficientType<ValueType>::type>(lb);
310 models::sparse::Dtmc<ConstantType> sampleModel = instantiator.instantiate(valuation);
311 auto checker = modelchecker::SparseDtmcPrctlModelChecker<models::sparse::Dtmc<ConstantType>>(sampleModel);
312 std::unique_ptr<modelchecker::CheckResult> checkResult;
313 auto formula = formulas[0];
314 if (formula->isProbabilityOperatorFormula() && formula->asProbabilityOperatorFormula().getSubformula().isUntilFormula()) {
315 const modelchecker::CheckTask<logic::UntilFormula, ConstantType> checkTask =
316 modelchecker::CheckTask<logic::UntilFormula, ConstantType>(formula->asProbabilityOperatorFormula().getSubformula().asUntilFormula());
317 checkResult = checker.computeUntilProbabilities(Environment(), checkTask);
318 }
else if (formula->isProbabilityOperatorFormula() && formula->asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()) {
319 const modelchecker::CheckTask<logic::EventuallyFormula, ConstantType> checkTask =
320 modelchecker::CheckTask<logic::EventuallyFormula, ConstantType>(
321 formula->asProbabilityOperatorFormula().getSubformula().asEventuallyFormula());
322 checkResult = checker.computeReachabilityProbabilities(Environment(), checkTask);
324 STORM_LOG_THROW(
false, exceptions::NotSupportedException,
"Expecting until or eventually formula.");
327 auto quantitativeResult = checkResult->asExplicitQuantitativeCheckResult<ConstantType>();
328 std::vector<ConstantType> values = quantitativeResult.getValueVector();
329 auto initialStates = model->getInitialStates();
330 ConstantType initial = 0;
332 for (
auto j = initialStates.getNextSetIndex(0); j < model->getNumberOfStates(); j = initialStates.getNextSetIndex(j + 1)) {
333 initial += values[j];
336 STORM_LOG_ASSERT(initial >= 0 - precision && initial <= 1 + precision,
"Initial value out of [0,1] range.");
337 ConstantType diff = previous - initial;
338 STORM_LOG_ASSERT(previous == -1 || (diff >= -1 - precision && diff <= 1 + precision),
"Diff out of [-1,1] range.");
340 if (previous != -1 && (diff > precision || diff < -precision)) {
341 monDecr &= diff > precision;
342 monIncr &= diff < -precision;
345 samples.push_back(std::move(values));
348 resultCheckOnSamples.addMonotonicityResult(*itr, res);
350 assumptionMaker.setSampleValues(std::move(samples));
353template<
typename ValueType,
typename ConstantType>
354void MonotonicityHelper<ValueType, ConstantType>::checkMonotonicityOnSamples(std::shared_ptr<models::sparse::Mdp<ValueType>> model,
355 uint_fast64_t numberOfSamples) {
356 STORM_LOG_THROW(
false, storm::exceptions::NotImplementedException,
"Checking monotonicity on samples not implemented for mdps.");
void setDone(bool done=true)
void setMonotonicity(uint_fast64_t state, VariableType var, Monotonicity mon)
Sets the local Monotonicity of a parameter at a given state.
std::map< std::shared_ptr< Order >, std::pair< std::shared_ptr< MonotonicityResult< VariableType > >, std::vector< std::shared_ptr< expressions::BinaryRelationExpression > > > > checkMonotonicityInBuild(std::ostream &outfile, bool usePLA=false, std::string dotOutfileName="dotOutput")
Builds Reachability Orders for the given model and simultaneously uses them to check for Monotonicity...
std::shared_ptr< LocalMonotonicityResult< VariableType > > createLocalMonotonicityResult(std::shared_ptr< Order > order, storage::ParameterRegion< ValueType > region)
Builds Reachability Orders for the given model and simultaneously uses them to check for Monotonicity...
MonotonicityHelper(std::shared_ptr< models::sparse::Model< ValueType > > model, std::vector< std::shared_ptr< logic::Formula const > > formulas, std::vector< storage::ParameterRegion< ValueType > > regions, uint_fast64_t numberOfSamples=0, double const &precision=0.000001, bool dotOutput=false)
Constructor of MonotonicityHelper.
This class represents a discrete-time Markov chain.
This class represents a (discrete-time) Markov decision process.
Base class for all sparse models.
storm::utility::parametric::CoefficientType< ParametricType >::type CoefficientType
storm::utility::parametric::Valuation< ParametricType > Valuation
A class that provides convenience operations to display run times.
void stop()
Stop stopwatch and add measured time to total time.
#define STORM_LOG_INFO(message)
#define STORM_LOG_WARN(message)
#define STORM_LOG_STATISTICS(message)
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_WARN_COND(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
@ Unknown
the monotonicity result is unknown
typename utility::parametric::VariableType< FunctionType >::type VariableType
void closeFile(std::ofstream &stream)
Close the given file after writing.
void openFile(std::string const &filepath, std::ofstream &filestream, bool append=false, bool silent=false)
Open the given file for writing.
std::set< storm::RationalFunctionVariable > getProbabilityParameters(Model< storm::RationalFunction > const &model)
Get all probability parameters occurring on transitions.
std::map< typename VariableType< FunctionType >::type, typename CoefficientType< FunctionType >::type > Valuation
void gatherOccurringVariables(FunctionType const &function, std::set< typename VariableType< FunctionType >::type > &variableSet)
Add all variables that occur in the given function to the the given set.
TargetType convertNumber(SourceType const &number)