Browse Source

Monotonicity Checking on Region

tempestpy_adaptions
Jip Spel 5 years ago
parent
commit
13f44ab7ea
  1. 9
      src/storm-pars-cli/storm-pars.cpp
  2. 30
      src/storm-pars/analysis/AssumptionChecker.cpp
  3. 5
      src/storm-pars/analysis/AssumptionChecker.h
  4. 1
      src/storm-pars/analysis/LatticeExtender.h
  5. 32
      src/storm-pars/analysis/MonotonicityChecker.cpp
  6. 14
      src/storm-pars/analysis/MonotonicityChecker.h
  7. 20
      src/storm-pars/storage/ParameterRegion.cpp
  8. 2
      src/storm-pars/storage/ParameterRegion.h
  9. 101
      src/test/storm-pars/analysis/AssumptionCheckerTest.cpp
  10. 24
      src/test/storm-pars/analysis/AssumptionMakerTest.cpp
  11. 81
      src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp

9
src/storm-pars-cli/storm-pars.cpp

@ -652,7 +652,7 @@ namespace storm {
}
if (monSettings.isSccEliminationSet()) {
if (model && monSettings.isSccEliminationSet()) {
storm::utility::Stopwatch eliminationWatch(true);
// TODO: check for correct Model type
STORM_PRINT("Applying scc elimination" << std::endl);
@ -720,12 +720,15 @@ namespace storm {
std::vector<std::shared_ptr<storm::logic::Formula const>> formulas = storm::api::extractFormulasFromProperties(input.properties);
// Monotonicity
storm::utility::Stopwatch monotonicityWatch(true);
auto monotonicityChecker = storm::analysis::MonotonicityChecker<ValueType>(model, formulas, monSettings.isValidateAssumptionsSet(), monSettings.getNumberOfSamples(), monSettings.getMonotonicityAnalysisPrecision());
std::vector<storm::storage::ParameterRegion<ValueType>> regions = parseRegions<ValueType>(model);
STORM_LOG_THROW(regions.size() > 1, storm::exceptions::InvalidArgumentException, "Monotonicity analysis only allowed on single region");
storm::analysis::MonotonicityChecker<ValueType> monotonicityChecker = storm::analysis::MonotonicityChecker<ValueType>(model, formulas, regions, monSettings.isValidateAssumptionsSet(), monSettings.getNumberOfSamples(), monSettings.getMonotonicityAnalysisPrecision());
monotonicityChecker.checkMonotonicity();
monotonicityWatch.stop();
STORM_PRINT(std::endl << "Total time for monotonicity checking: " << monotonicityWatch << "." << std::endl
<< std::endl);
return;
return;
}
std::vector<storm::storage::ParameterRegion<ValueType>> regions = parseRegions<ValueType>(model);

30
src/storm-pars/analysis/AssumptionChecker.cpp

@ -20,9 +20,10 @@
namespace storm {
namespace analysis {
template <typename ValueType>
AssumptionChecker<ValueType>::AssumptionChecker(std::shared_ptr<logic::Formula const> formula, std::shared_ptr<models::sparse::Dtmc<ValueType>> model, uint_fast64_t numberOfSamples) {
AssumptionChecker<ValueType>::AssumptionChecker(std::shared_ptr<logic::Formula const> formula, std::shared_ptr<models::sparse::Dtmc<ValueType>> model, storm::storage::ParameterRegion<ValueType> region, uint_fast64_t numberOfSamples) {
this->formula = formula;
this->matrix = model->getTransitionMatrix();
this->region = region;
// Create sample points
auto instantiator = utility::ModelInstantiator<models::sparse::Dtmc<ValueType>, models::sparse::Dtmc<double>>(*model);
@ -31,9 +32,15 @@ namespace storm {
for (auto i = 0; i < numberOfSamples; ++i) {
auto valuation = utility::parametric::Valuation<ValueType>();
for (auto itr = variables.begin(); itr != variables.end(); ++itr) {
// Creates samples between 0 and 1, 1/(#samples+2), 2/(#samples+2), ..., (#samples+1)/(#samples+2)
auto val = std::pair<typename utility::parametric::VariableType<ValueType>::type, typename utility::parametric::CoefficientType<ValueType>::type>((*itr), utility::convertNumber<typename utility::parametric::CoefficientType<ValueType>::type>(boost::lexical_cast<std::string>((i+1)/(double (numberOfSamples + 2)))));
// TODO: samplen over de region
for (auto var: variables) {
auto lb = region.getLowerBoundary(var.name());
auto ub = region.getUpperBoundary(var.name());
// Creates samples between lb and ub, that is: lb, lb + (ub-lb)/(#samples -1), lb + 2* (ub-lb)/(#samples -1), ..., ub
auto val =
std::pair<typename utility::parametric::VariableType<ValueType>::type, typename utility::parametric::CoefficientType<ValueType>::type>
(var,utility::convertNumber<typename utility::parametric::CoefficientType<ValueType>::type>(lb + i*(ub-lb)/(numberOfSamples-1)));
valuation.insert(val);
}
models::sparse::Dtmc<double> sampleModel = instantiator.instantiate(valuation);
@ -61,6 +68,7 @@ namespace storm {
template <typename ValueType>
AssumptionChecker<ValueType>::AssumptionChecker(std::shared_ptr<logic::Formula const> formula, std::shared_ptr<models::sparse::Mdp<ValueType>> model, uint_fast64_t numberOfSamples) {
STORM_LOG_THROW(false, exceptions::NotImplementedException, "Assumption checking for mdps not yet implemented");
this->formula = formula;
this->matrix = model->getTransitionMatrix();
@ -166,8 +174,10 @@ namespace storm {
&& lattice->compare(state1succ1->getColumn(), state1succ2->getColumn()) != Lattice::NodeComparison::UNKNOWN) {
// The assumption should be the greater assumption
// If the result is unknown, we cannot compare, also SMTSolver will not help
result = validateAssumptionFunction(lattice, state1succ1, state1succ2, state2succ1,
state2succ2);
result = validateAssumptionSMTSolver(assumption, lattice);
// result = validateAssumptionFunction(lattice, state1succ1, state1succ2, state2succ1,
// state2succ2);
} else if (assumption->getRelationType() == expressions::BinaryRelationExpression::RelationType::Equal) {
// The assumption is equal, the successors are the same,
// so if the probability of reaching the successors is the same, we have a valid assumption
@ -216,7 +226,7 @@ namespace storm {
// This will give the smallest result
std::map<typename utility::parametric::VariableType<ValueType>::type, typename utility::parametric::CoefficientType<ValueType>::type> substitutions;
for (auto var : vars) {
auto monotonicity = MonotonicityChecker<ValueType>::checkDerivative(prob.derivative(var));
auto monotonicity = MonotonicityChecker<ValueType>::checkDerivative(prob.derivative(var), region);
if (monotonicity.first) {
// monotone increasing
substitutions[var] = 0;
@ -301,7 +311,7 @@ namespace storm {
} else {
assert (assumption->getRelationType() ==
expressions::BinaryRelationExpression::RelationType::Equal);
exprToCheck = expr1 > expr2;
exprToCheck = expr1 != expr2 ;
}
auto variables = manager->getVariables();
@ -313,7 +323,9 @@ namespace storm {
exprBounds = exprBounds && manager->rational(0) <= var && var <= manager->rational(1);
} else {
// the var is a parameter
exprBounds = exprBounds && manager->rational(0) < var && var < manager->rational(1);
auto lb = storm::utility::convertNumber<storm::RationalNumber>(region.getLowerBoundary(var.getName()));
auto ub = storm::utility::convertNumber<storm::RationalNumber>(region.getUpperBoundary(var.getName()));
exprBounds = exprBounds && manager->rational(lb) < var && var < manager->rational(ub);
}
}

5
src/storm-pars/analysis/AssumptionChecker.h

@ -6,6 +6,7 @@
#include "storm/models/sparse/Mdp.h"
#include "storm/environment/Environment.h"
#include "storm/storage/expressions/BinaryRelationExpression.h"
#include "storm-pars/storage/ParameterRegion.h"
#include "Lattice.h"
namespace storm {
@ -29,7 +30,7 @@ namespace storm {
* @param model The dtmc model to check the formula on.
* @param numberOfSamples Number of sample points.
*/
AssumptionChecker(std::shared_ptr<logic::Formula const> formula, std::shared_ptr<models::sparse::Dtmc<ValueType>> model, uint_fast64_t numberOfSamples);
AssumptionChecker(std::shared_ptr<logic::Formula const> formula, std::shared_ptr<models::sparse::Dtmc<ValueType>> model, storm::storage::ParameterRegion<ValueType> region, uint_fast64_t numberOfSamples);
/*!
* Constructs an AssumptionChecker based on the number of samples, for the given formula and model.
@ -81,6 +82,8 @@ namespace storm {
typename storage::SparseMatrix<ValueType>::iterator state2succ1,
typename storage::SparseMatrix<ValueType>::iterator state2succ2);
storm::storage::ParameterRegion<ValueType> region;
};
}
}

1
src/storm-pars/analysis/LatticeExtender.h

@ -6,6 +6,7 @@
#include "storm-pars/analysis/Lattice.h"
#include "storm/api/storm.h"
namespace storm {
namespace analysis {

32
src/storm-pars/analysis/MonotonicityChecker.cpp

@ -23,7 +23,7 @@
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, uint_fast64_t numberOfSamples, double const& precision) {
MonotonicityChecker<ValueType>::MonotonicityChecker(std::shared_ptr<storm::models::ModelBase> model, std::vector<std::shared_ptr<storm::logic::Formula const>> formulas, std::vector<storm::storage::ParameterRegion<ValueType>> regions, bool validate, uint_fast64_t numberOfSamples, double const& precision) {
assert (model != nullptr);
this->model = model;
this->formulas = formulas;
@ -46,6 +46,24 @@ namespace storm {
}
std::shared_ptr<storm::models::sparse::Model<ValueType>> sparseModel = model->as<storm::models::sparse::Model<ValueType>>();
if (regions.size() == 1) {
region = *(regions.begin());
} else {
assert (regions.size() == 0);
typename storm::storage::ParameterRegion<ValueType>::Valuation lowerBoundaries;
typename storm::storage::ParameterRegion<ValueType>::Valuation upperBoundaries;
std::set<typename storm::storage::ParameterRegion<ValueType>::VariableType> vars;
vars = storm::models::sparse::getProbabilityParameters(*sparseModel);
for (auto var : vars) {
typename storm::storage::ParameterRegion<ValueType>::CoefficientType lb = storm::utility::convertNumber<typename storm::storage::ParameterRegion<ValueType>::CoefficientType>(0 + precision);
typename storm::storage::ParameterRegion<ValueType>::CoefficientType ub = storm::utility::convertNumber<typename storm::storage::ParameterRegion<ValueType>::CoefficientType>(1 - precision);
lowerBoundaries.insert(std::make_pair(var, lb));
upperBoundaries.insert(std::make_pair(var, ub));
}
region = storm::storage::ParameterRegion<ValueType>(std::move(lowerBoundaries), std::move(upperBoundaries));
}
this->extender = new storm::analysis::LatticeExtender<ValueType>(sparseModel);
}
@ -173,7 +191,7 @@ namespace storm {
storm::analysis::AssumptionChecker<ValueType> *assumptionChecker;
if (model->isOfType(storm::models::ModelType::Dtmc)) {
auto dtmc = model->as<storm::models::sparse::Dtmc<ValueType>>();
assumptionChecker = new storm::analysis::AssumptionChecker<ValueType>(formulas[0], dtmc, 3);
assumptionChecker = new storm::analysis::AssumptionChecker<ValueType>(formulas[0], dtmc, region, 3);
} else if (model->isOfType(storm::models::ModelType::Mdp)) {
auto mdp = model->as<storm::models::sparse::Mdp<ValueType>>();
assumptionChecker = new storm::analysis::AssumptionChecker<ValueType>(formulas[0], mdp, 3);
@ -348,7 +366,7 @@ namespace storm {
// As the first state (itr2) is above the second state (itr3) it
// is sufficient to look at the derivative of itr2.
std::pair<bool, bool> mon2;
mon2 = checkDerivative(derivative2);
mon2 = checkDerivative(derivative2, region);
value->first &= mon2.first;
value->second &= mon2.second;
} else if (compare == Lattice::BELOW) {
@ -356,7 +374,7 @@ namespace storm {
// is sufficient to look at the derivative of itr3.
std::pair<bool, bool> mon3;
mon3 = checkDerivative(derivative3);
mon3 = checkDerivative(derivative3, region);
value->first &= mon3.first;
value->second &= mon3.second;
} else if (compare == Lattice::SAME) {
@ -381,7 +399,7 @@ namespace storm {
std::pair<bool, bool> *value = &varsMonotone.find(var)->second;
bool change = false;
for (auto const &i : sortedStates) {
auto res = checkDerivative(getDerivative(transitions[i], var));
auto res = checkDerivative(getDerivative(transitions[i], var), region);
change = change || (!(value->first && value->second) // they do not hold both
&& ((value->first && !res.first)
|| (value->second && !res.second)));
@ -466,7 +484,7 @@ namespace storm {
// As the first state (itr2) is above the second state (itr3) it
// is sufficient to look at the derivative of itr2.
std::pair<bool, bool> mon2;
mon2 = checkDerivative(derivative2);
mon2 = checkDerivative(derivative2, region);
value->first &= mon2.first;
value->second &= mon2.second;
} else if (compare == Lattice::BELOW) {
@ -474,7 +492,7 @@ namespace storm {
// is sufficient to look at the derivative of itr3.
std::pair<bool, bool> mon3;
mon3 = checkDerivative(derivative3);
mon3 = checkDerivative(derivative3, region);
value->first &= mon3.first;
value->second &= mon3.second;
} else if (compare == Lattice::SAME) {

14
src/storm-pars/analysis/MonotonicityChecker.h

@ -30,12 +30,13 @@ namespace storm {
* Constructor of MonotonicityChecker
* @param model the model considered
* @param formula the formula considered
* @param regions the regions to consider
* @param validate whether or not assumptions are to be validated
* @param numberOfSamples number of samples taken for monotonicity checking, default 0,
* if 0then no check on samples is executed
* if 0 then no check on samples is executed
* @param precision precision on which the samples are compared
*/
MonotonicityChecker(std::shared_ptr<storm::models::ModelBase> model, std::vector<std::shared_ptr<storm::logic::Formula const>> formulas, bool validate, uint_fast64_t numberOfSamples=0, double const& precision=0.000001);
MonotonicityChecker(std::shared_ptr<storm::models::ModelBase> model, std::vector<std::shared_ptr<storm::logic::Formula const>> formulas, std::vector<storm::storage::ParameterRegion<ValueType>> regions, bool validate, uint_fast64_t numberOfSamples=0, double const& precision=0.000001);
/*!
* Checks for model and formula as provided in constructor for monotonicity
@ -52,7 +53,7 @@ namespace storm {
* @param derivative The derivative you want to check
* @return pair of bools, >= 0 and <= 0
*/
static std::pair<bool, bool> checkDerivative(ValueType derivative) {
static std::pair<bool, bool> checkDerivative(ValueType derivative, storm::storage::ParameterRegion<ValueType> reg) {
bool monIncr = false;
bool monDecr = false;
@ -80,7 +81,9 @@ namespace storm {
storm::expressions::Expression exprBounds = manager->boolean(true);
auto managervars = manager->getVariables();
for (auto var : managervars) {
exprBounds = exprBounds && manager->rational(0) < var && var < manager->rational(1);
auto lb = storm::utility::convertNumber<storm::RationalNumber>(reg.getLowerBoundary(var.getName()));
auto ub = storm::utility::convertNumber<storm::RationalNumber>(reg.getUpperBoundary(var.getName()));
exprBounds = exprBounds && manager->rational(lb) < var && var < manager->rational(ub);
}
assert (s.check() == storm::solver::SmtSolver::CheckResult::Sat);
@ -112,7 +115,6 @@ namespace storm {
private:
std::map<storm::analysis::Lattice*, std::map<typename utility::parametric::VariableType<ValueType>::type, std::pair<bool, bool>>> checkMonotonicity(std::map<storm::analysis::Lattice*, std::vector<std::shared_ptr<storm::expressions::BinaryRelationExpression>>> map, storm::storage::SparseMatrix<ValueType> matrix);
//TODO: variabele type
std::map<typename utility::parametric::VariableType<ValueType>::type, std::pair<bool, bool>> analyseMonotonicity(uint_fast64_t i, Lattice* lattice, storm::storage::SparseMatrix<ValueType> matrix) ;
std::map<Lattice*, std::vector<std::shared_ptr<storm::expressions::BinaryRelationExpression>>> createLattice();
@ -144,6 +146,8 @@ namespace storm {
std::string filename = "monotonicity.txt";
double precision;
storm::storage::ParameterRegion<ValueType> region;
};
}
}

20
src/storm-pars/storage/ParameterRegion.cpp

@ -48,6 +48,16 @@ namespace storm {
return (*result).second;
}
template<typename ParametricType>
typename ParameterRegion<ParametricType>::CoefficientType const& ParameterRegion<ParametricType>::getLowerBoundary(const std::string varName) const {
for (auto itr = lowerBoundaries.begin(); itr != lowerBoundaries.end(); ++itr) {
if (itr->first.name().compare(varName) == 0) {
return (*itr).second;
}
}
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Tried to find a lower boundary for variableName " << varName << " which is not specified by this region");
}
template<typename ParametricType>
typename ParameterRegion<ParametricType>::CoefficientType const& ParameterRegion<ParametricType>::getUpperBoundary(VariableType const& variable) const {
auto const& result = upperBoundaries.find(variable);
@ -55,6 +65,16 @@ namespace storm {
return (*result).second;
}
template<typename ParametricType>
typename ParameterRegion<ParametricType>::CoefficientType const& ParameterRegion<ParametricType>::getUpperBoundary(const std::string varName) const {
for (auto itr = upperBoundaries.begin(); itr != upperBoundaries.end(); ++itr) {
if (itr->first.name().compare(varName) == 0) {
return (*itr).second;
}
}
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Tried to find an upper boundary for variableName " << varName << " which is not specified by this region");
}
template<typename ParametricType>
typename ParameterRegion<ParametricType>::Valuation const& ParameterRegion<ParametricType>::getUpperBoundaries() const {
return upperBoundaries;

2
src/storm-pars/storage/ParameterRegion.h

@ -24,7 +24,9 @@ namespace storm {
std::set<VariableType> const& getVariables() const;
CoefficientType const& getLowerBoundary(VariableType const& variable) const;
CoefficientType const& getLowerBoundary(const std::string varName) const;
CoefficientType const& getUpperBoundary(VariableType const& variable) const;
CoefficientType const& getUpperBoundary(const std::string varName) const;
Valuation const& getLowerBoundaries() const;
Valuation const& getUpperBoundaries() const;

101
src/test/storm-pars/analysis/AssumptionCheckerTest.cpp

@ -1,8 +1,3 @@
//
// Created by Jip Spel on 19.09.18.
//
// TODO: cleanup includes
#include "gtest/gtest.h"
#include "storm-config.h"
#include "test/storm_gtest.h"
@ -21,12 +16,16 @@
#include "storm-pars/analysis/Lattice.h"
#include "storm/storage/expressions/BinaryRelationExpression.h"
#include "storm-pars/transformer/SparseParametricDtmcSimplifier.h"
#include "storm-pars/storage/ParameterRegion.h"
#include "storm-pars/api/storm-pars.h"
#include "storm/api/storm.h"
#include "storm-parsers/api/storm-parsers.h"
#include "storm-pars/api/region.h"
TEST(AssumptionCheckerTest, Brp_no_bisimulation) {
std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm";
std::string formulaAsString = "P=? [F s=4 & i=N ]";
@ -47,7 +46,13 @@ TEST(AssumptionCheckerTest, Brp_no_bisimulation) {
ASSERT_EQ(dtmc->getNumberOfStates(), 193ull);
ASSERT_EQ(dtmc->getNumberOfTransitions(), 383ull);
auto checker = storm::analysis::AssumptionChecker<storm::RationalFunction>(formulas[0], dtmc, 3);
// Create the region
storm::storage::ParameterRegion<storm::RationalFunction>::Valuation lowerBoundaries;
storm::storage::ParameterRegion<storm::RationalFunction>::Valuation upperBoundaries;
auto vars = storm::models::sparse::getProbabilityParameters(*dtmc);
auto region = storm::api::parseRegion<storm::RationalFunction>("0.00001 <= pK <= 0.00001, 0.00001 <= pL <= 0.99999", vars);
auto checker = storm::analysis::AssumptionChecker<storm::RationalFunction>(formulas[0], dtmc, region, 3);
// Check on samples
auto expressionManager = std::make_shared<storm::expressions::ExpressionManager>(storm::expressions::ExpressionManager());
@ -126,7 +131,11 @@ TEST(AssumptionCheckerTest, Simple1) {
ASSERT_EQ(dtmc->getNumberOfStates(), 5);
ASSERT_EQ(dtmc->getNumberOfTransitions(), 8);
auto checker = storm::analysis::AssumptionChecker<storm::RationalFunction>(formulas[0], dtmc, 3);
// Create the region
auto vars = storm::models::sparse::getProbabilityParameters(*dtmc);
auto region = storm::api::parseRegion<storm::RationalFunction>("0.00001 <= p <= 0.99999", vars);
auto checker = storm::analysis::AssumptionChecker<storm::RationalFunction>(formulas[0], dtmc, region, 3);
auto expressionManager = std::make_shared<storm::expressions::ExpressionManager>(storm::expressions::ExpressionManager());
expressionManager->declareRationalVariable("1");
@ -174,7 +183,11 @@ TEST(AssumptionCheckerTest, Simple2) {
ASSERT_EQ(dtmc->getNumberOfStates(), 5);
ASSERT_EQ(dtmc->getNumberOfTransitions(), 8);
auto checker = storm::analysis::AssumptionChecker<storm::RationalFunction>(formulas[0], dtmc, 3);
// Create the region
auto vars = storm::models::sparse::getProbabilityParameters(*dtmc);
auto region = storm::api::parseRegion<storm::RationalFunction>("0.00001 <= p <= 0.99999", vars);
auto checker = storm::analysis::AssumptionChecker<storm::RationalFunction>(formulas[0], dtmc, region, 3);
auto expressionManager = std::make_shared<storm::expressions::ExpressionManager>(storm::expressions::ExpressionManager());
expressionManager->declareRationalVariable("1");
@ -234,7 +247,11 @@ TEST(AssumptionCheckerTest, Simple3) {
ASSERT_EQ(6, dtmc->getNumberOfStates());
ASSERT_EQ(12, dtmc->getNumberOfTransitions());
auto checker = storm::analysis::AssumptionChecker<storm::RationalFunction>(formulas[0], dtmc, 3);
// Create the region
auto vars = storm::models::sparse::getProbabilityParameters(*dtmc);
auto region = storm::api::parseRegion<storm::RationalFunction>("0.00001 <= p <= 0.99999", vars);
auto checker = storm::analysis::AssumptionChecker<storm::RationalFunction>(formulas[0], dtmc, region, 3);
auto expressionManager = std::make_shared<storm::expressions::ExpressionManager>(storm::expressions::ExpressionManager());
expressionManager->declareRationalVariable("1");
@ -278,4 +295,70 @@ TEST(AssumptionCheckerTest, Simple3) {
EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumptionSMTSolver(assumption, lattice));
}
TEST(AssumptionCheckerTest, Simple4) {
std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/simple4.pm";
std::string formulaAsString = "P=? [F s=3]";
std::string constantsAsString = ""; //e.g. pL=0.9,TOACK=0.5
// Program and formula
storm::prism::Program program = storm::api::parseProgram(programFile);
program = storm::utility::prism::preprocess(program, constantsAsString);
std::vector<std::shared_ptr<const storm::logic::Formula>> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program));
std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> model = storm::api::buildSparseModel<storm::RationalFunction>(program, formulas)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
std::shared_ptr<storm::models::sparse::Dtmc<storm::RationalFunction>> dtmc = model->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
auto simplifier = storm::transformer::SparseParametricDtmcSimplifier<storm::models::sparse::Dtmc<storm::RationalFunction>>(*dtmc);
ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
model = simplifier.getSimplifiedModel();
dtmc = model->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
ASSERT_EQ(dtmc->getNumberOfStates(), 5);
ASSERT_EQ(dtmc->getNumberOfTransitions(), 8);
// Create the region
auto vars = storm::models::sparse::getProbabilityParameters(*dtmc);
auto region = storm::api::parseRegion<storm::RationalFunction>("0.00001 <= p <= 0.4", vars);
auto checker = storm::analysis::AssumptionChecker<storm::RationalFunction>(formulas[0], dtmc, region, 3);
auto expressionManager = std::make_shared<storm::expressions::ExpressionManager>(storm::expressions::ExpressionManager());
expressionManager->declareRationalVariable("1");
expressionManager->declareRationalVariable("2");
// Lattice
storm::storage::BitVector above(5);
above.set(3);
storm::storage::BitVector below(5);
below.set(4);
storm::storage::BitVector initialMiddle(5);
auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 5);
auto assumption = std::make_shared<storm::expressions::BinaryRelationExpression>(
storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(),
expressionManager->getVariable("1").getExpression().getBaseExpressionPointer(),
expressionManager->getVariable("2").getExpression().getBaseExpressionPointer(),
storm::expressions::BinaryRelationExpression::RelationType::Greater));
EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption));
EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, lattice));
EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumptionSMTSolver(assumption, lattice));
assumption = std::make_shared<storm::expressions::BinaryRelationExpression>(
storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(),
expressionManager->getVariable("2").getExpression().getBaseExpressionPointer(),
expressionManager->getVariable("1").getExpression().getBaseExpressionPointer(),
storm::expressions::BinaryRelationExpression::RelationType::Greater));
EXPECT_EQ(storm::analysis::AssumptionStatus::UNKNOWN, checker.checkOnSamples(assumption));
EXPECT_EQ(storm::analysis::AssumptionStatus::VALID, checker.validateAssumption(assumption, lattice));
EXPECT_EQ(storm::analysis::AssumptionStatus::VALID, checker.validateAssumptionSMTSolver(assumption, lattice));
assumption = std::make_shared<storm::expressions::BinaryRelationExpression>(
storm::expressions::BinaryRelationExpression(*expressionManager, expressionManager->getBooleanType(),
expressionManager->getVariable("1").getExpression().getBaseExpressionPointer(),
expressionManager->getVariable("2").getExpression().getBaseExpressionPointer(),
storm::expressions::BinaryRelationExpression::RelationType::Equal));
EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.checkOnSamples(assumption));
EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumption(assumption, lattice));
EXPECT_EQ(storm::analysis::AssumptionStatus::INVALID, checker.validateAssumptionSMTSolver(assumption, lattice));
}

24
src/test/storm-pars/analysis/AssumptionMakerTest.cpp

@ -28,7 +28,6 @@
#include "storm-parsers/api/storm-parsers.h"
//TODO: voor als validate uit staat
TEST(AssumptionMakerTest, Brp_without_bisimulation) {
std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm";
std::string formulaAsString = "P=? [F s=4 & i=N ]";
@ -45,6 +44,10 @@ TEST(AssumptionMakerTest, Brp_without_bisimulation) {
model = simplifier.getSimplifiedModel();
dtmc = model->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
// Create the region
auto vars = storm::models::sparse::getProbabilityParameters(*dtmc);
auto region = storm::api::parseRegion<storm::RationalFunction>("0.00001 <= pK <= 0.999999, 0.00001 <= pL <= 0.999999", vars);
ASSERT_EQ(dtmc->getNumberOfStates(), 193ull);
ASSERT_EQ(dtmc->getNumberOfTransitions(), 383ull);
@ -53,7 +56,7 @@ TEST(AssumptionMakerTest, Brp_without_bisimulation) {
ASSERT_EQ(183, std::get<1>(criticalTuple));
ASSERT_EQ(186, std::get<2>(criticalTuple));
auto assumptionChecker = storm::analysis::AssumptionChecker<storm::RationalFunction>(formulas[0], dtmc, 3);
auto assumptionChecker = storm::analysis::AssumptionChecker<storm::RationalFunction>(formulas[0], dtmc, region, 3);
auto assumptionMaker = storm::analysis::AssumptionMaker<storm::RationalFunction>(&assumptionChecker, dtmc->getNumberOfStates(), true);
auto result = assumptionMaker.createAndCheckAssumption(std::get<1>(criticalTuple), std::get<2>(criticalTuple), std::get<0>(criticalTuple));
@ -111,6 +114,10 @@ TEST(AssumptionMakerTest, Brp_without_bisimulation_no_validation) {
model = simplifier.getSimplifiedModel();
dtmc = model->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
// Create the region
auto vars = storm::models::sparse::getProbabilityParameters(*dtmc);
auto region = storm::api::parseRegion<storm::RationalFunction>("0.00001 <= pK <= 0.999999, 0.00001 <= pL <= 0.999999", vars);
ASSERT_EQ(dtmc->getNumberOfStates(), 193ull);
ASSERT_EQ(dtmc->getNumberOfTransitions(), 383ull);
@ -119,7 +126,7 @@ TEST(AssumptionMakerTest, Brp_without_bisimulation_no_validation) {
ASSERT_EQ(183, std::get<1>(criticalTuple));
ASSERT_EQ(186, std::get<2>(criticalTuple));
auto assumptionChecker = storm::analysis::AssumptionChecker<storm::RationalFunction>(formulas[0], dtmc, 3);
auto assumptionChecker = storm::analysis::AssumptionChecker<storm::RationalFunction>(formulas[0], dtmc, region, 3);
// This one does not validate the assumptions!
auto assumptionMaker = storm::analysis::AssumptionMaker<storm::RationalFunction>(&assumptionChecker, dtmc->getNumberOfStates(), false);
auto result = assumptionMaker.createAndCheckAssumption(std::get<1>(criticalTuple), std::get<2>(criticalTuple), std::get<0>(criticalTuple));
@ -177,6 +184,10 @@ TEST(AssumptionMakerTest, Simple1) {
model = simplifier.getSimplifiedModel();
dtmc = model->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
// Create the region
auto vars = storm::models::sparse::getProbabilityParameters(*dtmc);
auto region = storm::api::parseRegion<storm::RationalFunction>("0.00001 <= p <= 0.999999", vars);
ASSERT_EQ(dtmc->getNumberOfStates(), 5);
ASSERT_EQ(dtmc->getNumberOfTransitions(), 8);
@ -188,7 +199,7 @@ TEST(AssumptionMakerTest, Simple1) {
auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 5);
auto assumptionChecker = storm::analysis::AssumptionChecker<storm::RationalFunction>(formulas[0], dtmc, 3);
auto assumptionChecker = storm::analysis::AssumptionChecker<storm::RationalFunction>(formulas[0], dtmc, region, 3);
auto assumptionMaker = storm::analysis::AssumptionMaker<storm::RationalFunction>(&assumptionChecker, dtmc->getNumberOfStates(), true);
auto result = assumptionMaker.createAndCheckAssumption(1, 2, lattice);
@ -244,6 +255,9 @@ TEST(AssumptionMakerTest, Simple2) {
ASSERT_TRUE(simplifier.simplify(*(formulas[0])));
model = simplifier.getSimplifiedModel();
dtmc = model->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
// Create the region
auto vars = storm::models::sparse::getProbabilityParameters(*dtmc);
auto region = storm::api::parseRegion<storm::RationalFunction>("0.00001 <= p <= 0.999999", vars);
ASSERT_EQ(dtmc->getNumberOfStates(), 5);
ASSERT_EQ(dtmc->getNumberOfTransitions(), 8);
@ -256,7 +270,7 @@ TEST(AssumptionMakerTest, Simple2) {
auto lattice = new storm::analysis::Lattice(&above, &below, &initialMiddle, 5);
auto assumptionChecker = storm::analysis::AssumptionChecker<storm::RationalFunction>(formulas[0], dtmc, 3);
auto assumptionChecker = storm::analysis::AssumptionChecker<storm::RationalFunction>(formulas[0], dtmc, region, 3);
auto assumptionMaker = storm::analysis::AssumptionMaker<storm::RationalFunction>(&assumptionChecker, dtmc->getNumberOfStates(), true);
auto result = assumptionMaker.createAndCheckAssumption(1, 2, lattice);

81
src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp

@ -27,55 +27,83 @@
#include "storm-parsers/api/storm-parsers.h"
TEST(MonotonicityCheckerTest, Derivative_checker) {
// Create the region
typename storm::storage::ParameterRegion<storm::RationalFunction>::Valuation lowerBoundaries;
typename storm::storage::ParameterRegion<storm::RationalFunction>::Valuation upperBoundaries;
auto region = storm::storage::ParameterRegion<storm::RationalFunction>(std::move(lowerBoundaries), std::move(upperBoundaries));
// Derivative 0
auto constFunction = storm::RationalFunction(0);
auto constFunctionRes = storm::analysis::MonotonicityChecker<storm::RationalFunction>::checkDerivative(constFunction);
auto constFunctionRes = storm::analysis::MonotonicityChecker<storm::RationalFunction>::checkDerivative(constFunction, region);
EXPECT_TRUE(constFunctionRes.first);
EXPECT_TRUE(constFunctionRes.second);
// Derivative 5
constFunction = storm::RationalFunction(5);
constFunctionRes = storm::analysis::MonotonicityChecker<storm::RationalFunction>::checkDerivative(constFunction);
constFunctionRes = storm::analysis::MonotonicityChecker<storm::RationalFunction>::checkDerivative(constFunction, region);
EXPECT_TRUE(constFunctionRes.first);
EXPECT_FALSE(constFunctionRes.second);
// Derivative -4
constFunction = storm::RationalFunction(storm::RationalFunction(1)-constFunction);
constFunctionRes = storm::analysis::MonotonicityChecker<storm::RationalFunction>::checkDerivative(constFunction);
constFunctionRes = storm::analysis::MonotonicityChecker<storm::RationalFunction>::checkDerivative(constFunction, region);
EXPECT_FALSE(constFunctionRes.first);
EXPECT_TRUE(constFunctionRes.second);
std::shared_ptr<storm::RawPolynomialCache> cache = std::make_shared<storm::RawPolynomialCache>();
carl::StringParser parser;
parser.setVariables({"p", "q"});
// Create the region
auto functionP = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial<storm::RationalFunctionCoefficient>("p"), cache));
auto functionQ = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial<storm::RationalFunctionCoefficient>("q"), cache));
auto varsP = functionP.gatherVariables();
auto varsQ = functionQ.gatherVariables();
storm::utility::parametric::Valuation<storm::RationalFunction> lowerBoundaries2;
storm::utility::parametric::Valuation<storm::RationalFunction> upperBoundaries2;
for (auto var : varsP) {
typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType lb = storm::utility::convertNumber<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(0 + 0.000001);
typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType ub = storm::utility::convertNumber<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(1 - 0.000001);
lowerBoundaries2.emplace(std::make_pair(var, lb));
upperBoundaries2.emplace(std::make_pair(var, ub));
}
for (auto var : varsQ) {
typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType lb = storm::utility::convertNumber<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(0 + 0.000001);
typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType ub = storm::utility::convertNumber<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(1 - 0.000001);
lowerBoundaries2.emplace(std::make_pair(var, lb));
upperBoundaries2.emplace(std::make_pair(var, ub));
}
region = storm::storage::ParameterRegion<storm::RationalFunction>(std::move(lowerBoundaries2), std::move(upperBoundaries2));
// Derivative p
auto function = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial<storm::RationalFunctionCoefficient>("p"), cache));
auto functionRes = storm::analysis::MonotonicityChecker<storm::RationalFunction>::checkDerivative(function);
auto function = functionP;
auto functionRes = storm::analysis::MonotonicityChecker<storm::RationalFunction>::checkDerivative(function, region);
EXPECT_TRUE(functionRes.first);
EXPECT_FALSE(functionRes.second);
// Derivative 1-p
auto functionDecr = storm::RationalFunction(storm::RationalFunction(1)-function);
auto functionDecrRes = storm::analysis::MonotonicityChecker<storm::RationalFunction>::checkDerivative(functionDecr);
auto functionDecrRes = storm::analysis::MonotonicityChecker<storm::RationalFunction>::checkDerivative(functionDecr, region);
EXPECT_TRUE(functionDecrRes.first);
EXPECT_FALSE(functionDecrRes.second);
// Derivative 1-2p
auto functionNonMonotonic = storm::RationalFunction(storm::RationalFunction(1)-storm::RationalFunction(2)*function);
auto functionNonMonotonicRes = storm::analysis::MonotonicityChecker<storm::RationalFunction>::checkDerivative(functionNonMonotonic);
auto functionNonMonotonicRes = storm::analysis::MonotonicityChecker<storm::RationalFunction>::checkDerivative(functionNonMonotonic, region);
EXPECT_FALSE(functionNonMonotonicRes.first);
EXPECT_FALSE(functionNonMonotonicRes.second);
// Derivative -p
functionDecr = storm::RationalFunction(storm::RationalFunction(0)-function);
functionDecrRes = storm::analysis::MonotonicityChecker<storm::RationalFunction>::checkDerivative(functionDecr);
functionDecrRes = storm::analysis::MonotonicityChecker<storm::RationalFunction>::checkDerivative(functionDecr, region);
EXPECT_FALSE(functionDecrRes.first);
EXPECT_TRUE(functionDecrRes.second);
// Derivative p*q
function = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial<storm::RationalFunctionCoefficient>("p"), cache))
* storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial<storm::RationalFunctionCoefficient>("q"), cache)) ;
functionRes = storm::analysis::MonotonicityChecker<storm::RationalFunction>::checkDerivative(function);
function = functionP * functionQ ;
functionRes = storm::analysis::MonotonicityChecker<storm::RationalFunction>::checkDerivative(function, region);
EXPECT_TRUE(functionRes.first);
EXPECT_FALSE(functionRes.second);
}
@ -103,10 +131,24 @@ TEST(MonotonicityCheckerTest, Brp_with_bisimulation_no_samples) {
dtmc = storm::api::performBisimulationMinimization<storm::RationalFunction>(model, formulas, bisimType)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
// Create the region
typename storm::storage::ParameterRegion<storm::RationalFunction>::Valuation lowerBoundaries;
typename storm::storage::ParameterRegion<storm::RationalFunction>::Valuation upperBoundaries;
std::set<typename storm::storage::ParameterRegion<storm::RationalFunction>::VariableType> vars = storm::models::sparse::getProbabilityParameters(*dtmc);
for (auto var : vars) {
typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType lb = storm::utility::convertNumber<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(0 + 0.000001);
typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType ub = storm::utility::convertNumber<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(1 - 0.000001);
lowerBoundaries.emplace(std::make_pair(var, lb));
upperBoundaries.emplace(std::make_pair(var, ub));
}
auto region = storm::storage::ParameterRegion<storm::RationalFunction>(std::move(lowerBoundaries), std::move(upperBoundaries));
std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
ASSERT_EQ(dtmc->getNumberOfStates(), 99ull);
ASSERT_EQ(dtmc->getNumberOfTransitions(), 195ull);
storm::analysis::MonotonicityChecker<storm::RationalFunction> monotonicityChecker = storm::analysis::MonotonicityChecker<storm::RationalFunction>(dtmc, formulas, true);
storm::analysis::MonotonicityChecker<storm::RationalFunction> monotonicityChecker = storm::analysis::MonotonicityChecker<storm::RationalFunction>(dtmc, formulas, regions, true);
auto result = monotonicityChecker.checkMonotonicity();
EXPECT_EQ(1, result.size());
EXPECT_EQ(2, result.begin()->second.size());
@ -138,10 +180,23 @@ TEST(MonotonicityCheckerTest, Brp_with_bisimulation_samples) {
dtmc = storm::api::performBisimulationMinimization<storm::RationalFunction>(model, formulas, bisimType)->as<storm::models::sparse::Dtmc<storm::RationalFunction>>();
// Create the region
typename storm::storage::ParameterRegion<storm::RationalFunction>::Valuation lowerBoundaries;
typename storm::storage::ParameterRegion<storm::RationalFunction>::Valuation upperBoundaries;
std::set<typename storm::storage::ParameterRegion<storm::RationalFunction>::VariableType> vars = storm::models::sparse::getProbabilityParameters(*dtmc);
for (auto var : vars) {
typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType lb = storm::utility::convertNumber<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(0 + 0.000001);
typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType ub = storm::utility::convertNumber<typename storm::storage::ParameterRegion<storm::RationalFunction>::CoefficientType>(1 - 0.000001);
lowerBoundaries.emplace(std::make_pair(var, lb));
upperBoundaries.emplace(std::make_pair(var, ub));
}
auto region = storm::storage::ParameterRegion<storm::RationalFunction>(std::move(lowerBoundaries), std::move(upperBoundaries));
std::vector<storm::storage::ParameterRegion<storm::RationalFunction>> regions = {region};
ASSERT_EQ(dtmc->getNumberOfStates(), 99ull);
ASSERT_EQ(dtmc->getNumberOfTransitions(), 195ull);
storm::analysis::MonotonicityChecker<storm::RationalFunction> monotonicityChecker = storm::analysis::MonotonicityChecker<storm::RationalFunction>(dtmc, formulas, true, 50);
auto monotonicityChecker = storm::analysis::MonotonicityChecker<storm::RationalFunction>(dtmc, formulas, regions, true, 50);
auto result = monotonicityChecker.checkMonotonicity();
EXPECT_EQ(1, result.size());
EXPECT_EQ(2, result.begin()->second.size());

Loading…
Cancel
Save