|
|
@ -3,11 +3,50 @@ |
|
|
|
//
|
|
|
|
|
|
|
|
#include "MonotonicityChecker.h"
|
|
|
|
#include "storm-pars/analysis/AssumptionMaker.h"
|
|
|
|
#include "storm-pars/analysis/AssumptionChecker.h"
|
|
|
|
#include "storm-pars/analysis/Lattice.h"
|
|
|
|
#include "storm-pars/analysis/LatticeExtender.h"
|
|
|
|
|
|
|
|
#include "storm/exceptions/NotSupportedException.h"
|
|
|
|
#include "storm/exceptions/UnexpectedException.h"
|
|
|
|
#include "storm/exceptions/UnexpectedException.h"
|
|
|
|
#include "storm/exceptions/InvalidOperationException.h"
|
|
|
|
|
|
|
|
#include "storm/utility/Stopwatch.h"
|
|
|
|
#include "storm/models/ModelType.h"
|
|
|
|
|
|
|
|
#include "storm/modelchecker/results/CheckResult.h"
|
|
|
|
#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h"
|
|
|
|
|
|
|
|
|
|
|
|
namespace storm { |
|
|
|
namespace analysis { |
|
|
|
template <typename ValueType> |
|
|
|
MonotonicityChecker<ValueType>::MonotonicityChecker(std::shared_ptr<storm::models::ModelBase> model, std::vector<std::shared_ptr<storm::logic::Formula const>> formulas, bool validate) { |
|
|
|
this->model = model; |
|
|
|
this->formulas = formulas; |
|
|
|
this->validate = validate; |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ValueType> |
|
|
|
std::map<storm::analysis::Lattice*, std::map<carl::Variable, std::pair<bool, bool>>> MonotonicityChecker<ValueType>::checkMonotonicity() { |
|
|
|
bool maybeMonotone = true; |
|
|
|
if (model->isOfType(storm::models::ModelType::Dtmc)) { |
|
|
|
auto dtmcModel = model->as<storm::models::sparse::Dtmc<ValueType>>(); |
|
|
|
maybeMonotone = checkOnSamples(dtmcModel,3); |
|
|
|
} //TODO mdp
|
|
|
|
if (maybeMonotone) { |
|
|
|
auto map = createLattice(); |
|
|
|
std::shared_ptr<storm::models::sparse::Model<ValueType>> sparseModel = model->as<storm::models::sparse::Model<ValueType>>(); |
|
|
|
auto matrix = sparseModel->getTransitionMatrix(); |
|
|
|
return checkMonotonicity(map, matrix); |
|
|
|
} else { |
|
|
|
std::map<storm::analysis::Lattice*, std::map<carl::Variable, std::pair<bool, bool>>> result; |
|
|
|
std::cout << "Not monotone" << std::endl; |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ValueType> |
|
|
|
std::map<storm::analysis::Lattice*, std::map<carl::Variable, std::pair<bool, bool>>> MonotonicityChecker<ValueType>::checkMonotonicity(std::map<storm::analysis::Lattice*, std::vector<std::shared_ptr<storm::expressions::BinaryRelationExpression>>> map, storm::storage::SparseMatrix<ValueType> matrix) { |
|
|
|
auto i = 0; |
|
|
@ -65,6 +104,33 @@ namespace storm { |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ValueType> |
|
|
|
std::map<storm::analysis::Lattice*, std::vector<std::shared_ptr<storm::expressions::BinaryRelationExpression>>> MonotonicityChecker<ValueType>::createLattice() { |
|
|
|
// Transform to Lattices
|
|
|
|
storm::utility::Stopwatch latticeWatch(true); |
|
|
|
std::shared_ptr<storm::models::sparse::Model<ValueType>> sparseModel = model->as<storm::models::sparse::Model<ValueType>>(); |
|
|
|
storm::analysis::LatticeExtender<ValueType> *extender = new storm::analysis::LatticeExtender<ValueType>(sparseModel); |
|
|
|
std::tuple<storm::analysis::Lattice*, uint_fast64_t, uint_fast64_t> criticalTuple = extender->toLattice(formulas); |
|
|
|
std::map<storm::analysis::Lattice*, std::vector<std::shared_ptr<storm::expressions::BinaryRelationExpression>>> result; |
|
|
|
if (model->isOfType(storm::models::ModelType::Dtmc)) { |
|
|
|
auto dtmcModel = model->as<storm::models::sparse::Dtmc<ValueType>>(); |
|
|
|
auto assumptionChecker = storm::analysis::AssumptionChecker<ValueType>(formulas[0], dtmcModel, 3); |
|
|
|
auto assumptionMaker = storm::analysis::AssumptionMaker<ValueType>(extender, &assumptionChecker, sparseModel->getNumberOfStates(), validate); |
|
|
|
result = assumptionMaker.makeAssumptions(std::get<0>(criticalTuple), std::get<1>(criticalTuple), std::get<2>(criticalTuple)); |
|
|
|
} else if (model->isOfType(storm::models::ModelType::Dtmc)) { |
|
|
|
auto mdpModel = model->as<storm::models::sparse::Mdp<ValueType>>(); |
|
|
|
auto assumptionChecker = storm::analysis::AssumptionChecker<ValueType>(formulas[0], mdpModel, 3); |
|
|
|
auto assumptionMaker = storm::analysis::AssumptionMaker<ValueType>(extender, &assumptionChecker, sparseModel->getNumberOfStates(), validate); |
|
|
|
result = assumptionMaker.makeAssumptions(std::get<0>(criticalTuple), std::get<1>(criticalTuple), std::get<2>(criticalTuple)); |
|
|
|
} else { |
|
|
|
STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Unable to perform monotonicity analysis on the provided model type."); |
|
|
|
} |
|
|
|
|
|
|
|
latticeWatch.stop(); |
|
|
|
STORM_PRINT(std::endl << "Time for lattice creation: " << latticeWatch << "." << std::endl << std::endl); |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ValueType> |
|
|
|
std::map<carl::Variable, std::pair<bool, bool>> MonotonicityChecker<ValueType>::analyseMonotonicity(uint_fast64_t j, storm::analysis::Lattice* lattice, storm::storage::SparseMatrix<ValueType> matrix) { |
|
|
|
std::map<carl::Variable, std::pair<bool, bool>> varsMonotone; |
|
|
@ -163,6 +229,58 @@ namespace storm { |
|
|
|
return varsMonotone; |
|
|
|
} |
|
|
|
|
|
|
|
template <typename ValueType> |
|
|
|
bool MonotonicityChecker<ValueType>::checkOnSamples(std::shared_ptr<storm::models::sparse::Dtmc<ValueType>> model, uint_fast64_t numberOfSamples) { |
|
|
|
bool monDecr = true; |
|
|
|
bool monIncr = true; |
|
|
|
|
|
|
|
auto instantiator = storm::utility::ModelInstantiator<storm::models::sparse::Dtmc<ValueType>, storm::models::sparse::Dtmc<double>>(*model); |
|
|
|
auto matrix = model->getTransitionMatrix(); |
|
|
|
std::set<storm::RationalFunctionVariable> variables = storm::models::sparse::getProbabilityParameters(*model); |
|
|
|
double previous = -1; |
|
|
|
for (auto i = 0; i < numberOfSamples; ++i) { |
|
|
|
auto valuation = storm::utility::parametric::Valuation<ValueType>(); |
|
|
|
for (auto itr = variables.begin(); itr != variables.end(); ++itr) { |
|
|
|
// TODO: Type
|
|
|
|
auto val = std::pair<storm::RationalFunctionVariable, storm::RationalFunctionCoefficient>((*itr), storm::utility::convertNumber<storm::RationalFunctionCoefficient>(boost::lexical_cast<std::string>((i+1)/(double (numberOfSamples + 1))))); |
|
|
|
valuation.insert(val); |
|
|
|
} |
|
|
|
storm::models::sparse::Dtmc<double> sampleModel = instantiator.instantiate(valuation); |
|
|
|
auto checker = storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<double>>(sampleModel); |
|
|
|
std::unique_ptr<storm::modelchecker::CheckResult> checkResult; |
|
|
|
auto formula = formulas[0]; |
|
|
|
if (formula->isProbabilityOperatorFormula() && |
|
|
|
formula->asProbabilityOperatorFormula().getSubformula().isUntilFormula()) { |
|
|
|
const storm::modelchecker::CheckTask<storm::logic::UntilFormula, double> checkTask = storm::modelchecker::CheckTask<storm::logic::UntilFormula, double>( |
|
|
|
(*formula).asProbabilityOperatorFormula().getSubformula().asUntilFormula()); |
|
|
|
checkResult = checker.computeUntilProbabilities(Environment(), checkTask); |
|
|
|
} else if (formula->isProbabilityOperatorFormula() && |
|
|
|
formula->asProbabilityOperatorFormula().getSubformula().isEventuallyFormula()) { |
|
|
|
const storm::modelchecker::CheckTask<storm::logic::EventuallyFormula, double> checkTask = storm::modelchecker::CheckTask<storm::logic::EventuallyFormula, double>( |
|
|
|
(*formula).asProbabilityOperatorFormula().getSubformula().asEventuallyFormula()); |
|
|
|
checkResult = checker.computeReachabilityProbabilities(Environment(), checkTask); |
|
|
|
} else { |
|
|
|
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, |
|
|
|
"Expecting until or eventually formula"); |
|
|
|
} |
|
|
|
auto quantitativeResult = checkResult->asExplicitQuantitativeCheckResult<double>(); |
|
|
|
std::vector<double> values = quantitativeResult.getValueVector(); |
|
|
|
auto initialStates = model->getInitialStates(); |
|
|
|
double initial = 0; |
|
|
|
for (auto i = initialStates.getNextSetIndex(0); i < model->getNumberOfStates(); i = initialStates.getNextSetIndex(i+1)) { |
|
|
|
initial += values[i]; |
|
|
|
} |
|
|
|
if (previous != -1) { |
|
|
|
monDecr &= previous >= initial; |
|
|
|
monIncr &= previous <= initial; |
|
|
|
} |
|
|
|
previous = initial; |
|
|
|
} |
|
|
|
|
|
|
|
bool result = monDecr || monIncr; |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
template class MonotonicityChecker<storm::RationalFunction>; |
|
|
|
} |
|
|
|
} |