diff --git a/src/storm-pars-cli/storm-pars.cpp b/src/storm-pars-cli/storm-pars.cpp index cd6a20712..03665fe25 100644 --- a/src/storm-pars-cli/storm-pars.cpp +++ b/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> formulas = storm::api::extractFormulasFromProperties(input.properties); // Monotonicity storm::utility::Stopwatch monotonicityWatch(true); - auto monotonicityChecker = storm::analysis::MonotonicityChecker(model, formulas, monSettings.isValidateAssumptionsSet(), monSettings.getNumberOfSamples(), monSettings.getMonotonicityAnalysisPrecision()); + std::vector> regions = parseRegions(model); + + STORM_LOG_THROW(regions.size() > 1, storm::exceptions::InvalidArgumentException, "Monotonicity analysis only allowed on single region"); + storm::analysis::MonotonicityChecker monotonicityChecker = storm::analysis::MonotonicityChecker(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> regions = parseRegions(model); diff --git a/src/storm-pars/analysis/AssumptionChecker.cpp b/src/storm-pars/analysis/AssumptionChecker.cpp index 3aca39f31..5fe86eff5 100644 --- a/src/storm-pars/analysis/AssumptionChecker.cpp +++ b/src/storm-pars/analysis/AssumptionChecker.cpp @@ -20,9 +20,10 @@ namespace storm { namespace analysis { template - AssumptionChecker::AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, uint_fast64_t numberOfSamples) { + AssumptionChecker::AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, storm::storage::ParameterRegion 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>(*model); @@ -31,9 +32,15 @@ namespace storm { for (auto i = 0; i < numberOfSamples; ++i) { auto valuation = utility::parametric::Valuation(); - 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::type, typename utility::parametric::CoefficientType::type>((*itr), utility::convertNumber::type>(boost::lexical_cast((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::type, typename utility::parametric::CoefficientType::type> + (var,utility::convertNumber::type>(lb + i*(ub-lb)/(numberOfSamples-1))); valuation.insert(val); } models::sparse::Dtmc sampleModel = instantiator.instantiate(valuation); @@ -61,6 +68,7 @@ namespace storm { template AssumptionChecker::AssumptionChecker(std::shared_ptr formula, std::shared_ptr> 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::type, typename utility::parametric::CoefficientType::type> substitutions; for (auto var : vars) { - auto monotonicity = MonotonicityChecker::checkDerivative(prob.derivative(var)); + auto monotonicity = MonotonicityChecker::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(region.getLowerBoundary(var.getName())); + auto ub = storm::utility::convertNumber(region.getUpperBoundary(var.getName())); + exprBounds = exprBounds && manager->rational(lb) < var && var < manager->rational(ub); } } diff --git a/src/storm-pars/analysis/AssumptionChecker.h b/src/storm-pars/analysis/AssumptionChecker.h index 3f98189ae..c1e58dd69 100644 --- a/src/storm-pars/analysis/AssumptionChecker.h +++ b/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 formula, std::shared_ptr> model, uint_fast64_t numberOfSamples); + AssumptionChecker(std::shared_ptr formula, std::shared_ptr> model, storm::storage::ParameterRegion 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::iterator state2succ1, typename storage::SparseMatrix::iterator state2succ2); + storm::storage::ParameterRegion region; + }; } } diff --git a/src/storm-pars/analysis/LatticeExtender.h b/src/storm-pars/analysis/LatticeExtender.h index 7497aa594..4899fdf46 100644 --- a/src/storm-pars/analysis/LatticeExtender.h +++ b/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 { diff --git a/src/storm-pars/analysis/MonotonicityChecker.cpp b/src/storm-pars/analysis/MonotonicityChecker.cpp index 93a70c46b..f451f7df7 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.cpp +++ b/src/storm-pars/analysis/MonotonicityChecker.cpp @@ -23,7 +23,7 @@ namespace storm { namespace analysis { template - MonotonicityChecker::MonotonicityChecker(std::shared_ptr model, std::vector> formulas, bool validate, uint_fast64_t numberOfSamples, double const& precision) { + MonotonicityChecker::MonotonicityChecker(std::shared_ptr model, std::vector> formulas, std::vector> 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> sparseModel = model->as>(); + + if (regions.size() == 1) { + region = *(regions.begin()); + } else { + assert (regions.size() == 0); + typename storm::storage::ParameterRegion::Valuation lowerBoundaries; + typename storm::storage::ParameterRegion::Valuation upperBoundaries; + std::set::VariableType> vars; + vars = storm::models::sparse::getProbabilityParameters(*sparseModel); + for (auto var : vars) { + typename storm::storage::ParameterRegion::CoefficientType lb = storm::utility::convertNumber::CoefficientType>(0 + precision); + typename storm::storage::ParameterRegion::CoefficientType ub = storm::utility::convertNumber::CoefficientType>(1 - precision); + lowerBoundaries.insert(std::make_pair(var, lb)); + upperBoundaries.insert(std::make_pair(var, ub)); + } + region = storm::storage::ParameterRegion(std::move(lowerBoundaries), std::move(upperBoundaries)); + } + this->extender = new storm::analysis::LatticeExtender(sparseModel); } @@ -173,7 +191,7 @@ namespace storm { storm::analysis::AssumptionChecker *assumptionChecker; if (model->isOfType(storm::models::ModelType::Dtmc)) { auto dtmc = model->as>(); - assumptionChecker = new storm::analysis::AssumptionChecker(formulas[0], dtmc, 3); + assumptionChecker = new storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); } else if (model->isOfType(storm::models::ModelType::Mdp)) { auto mdp = model->as>(); assumptionChecker = new storm::analysis::AssumptionChecker(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 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 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 *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 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 mon3; - mon3 = checkDerivative(derivative3); + mon3 = checkDerivative(derivative3, region); value->first &= mon3.first; value->second &= mon3.second; } else if (compare == Lattice::SAME) { diff --git a/src/storm-pars/analysis/MonotonicityChecker.h b/src/storm-pars/analysis/MonotonicityChecker.h index 5d6b60ba4..0ef738154 100644 --- a/src/storm-pars/analysis/MonotonicityChecker.h +++ b/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 model, std::vector> formulas, bool validate, uint_fast64_t numberOfSamples=0, double const& precision=0.000001); + MonotonicityChecker(std::shared_ptr model, std::vector> formulas, std::vector> 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 checkDerivative(ValueType derivative) { + static std::pair checkDerivative(ValueType derivative, storm::storage::ParameterRegion 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(reg.getLowerBoundary(var.getName())); + auto ub = storm::utility::convertNumber(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::type, std::pair>> checkMonotonicity(std::map>> map, storm::storage::SparseMatrix matrix); - //TODO: variabele type std::map::type, std::pair> analyseMonotonicity(uint_fast64_t i, Lattice* lattice, storm::storage::SparseMatrix matrix) ; std::map>> createLattice(); @@ -144,6 +146,8 @@ namespace storm { std::string filename = "monotonicity.txt"; double precision; + + storm::storage::ParameterRegion region; }; } } diff --git a/src/storm-pars/storage/ParameterRegion.cpp b/src/storm-pars/storage/ParameterRegion.cpp index 3d9e36c93..68d6e94dc 100644 --- a/src/storm-pars/storage/ParameterRegion.cpp +++ b/src/storm-pars/storage/ParameterRegion.cpp @@ -48,6 +48,16 @@ namespace storm { return (*result).second; } + template + typename ParameterRegion::CoefficientType const& ParameterRegion::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 ParameterRegion::CoefficientType const& ParameterRegion::getUpperBoundary(VariableType const& variable) const { auto const& result = upperBoundaries.find(variable); @@ -55,6 +65,16 @@ namespace storm { return (*result).second; } + template + typename ParameterRegion::CoefficientType const& ParameterRegion::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 ParameterRegion::Valuation const& ParameterRegion::getUpperBoundaries() const { return upperBoundaries; diff --git a/src/storm-pars/storage/ParameterRegion.h b/src/storm-pars/storage/ParameterRegion.h index bcdd86ccb..d4f3ce457 100644 --- a/src/storm-pars/storage/ParameterRegion.h +++ b/src/storm-pars/storage/ParameterRegion.h @@ -24,7 +24,9 @@ namespace storm { std::set 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; diff --git a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp b/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp index 93fc5955b..08e7319a6 100644 --- a/src/test/storm-pars/analysis/AssumptionCheckerTest.cpp +++ b/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(formulas[0], dtmc, 3); + // Create the region + storm::storage::ParameterRegion::Valuation lowerBoundaries; + storm::storage::ParameterRegion::Valuation upperBoundaries; + auto vars = storm::models::sparse::getProbabilityParameters(*dtmc); + auto region = storm::api::parseRegion("0.00001 <= pK <= 0.00001, 0.00001 <= pL <= 0.99999", vars); + + auto checker = storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); // Check on samples auto expressionManager = std::make_shared(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(formulas[0], dtmc, 3); + // Create the region + auto vars = storm::models::sparse::getProbabilityParameters(*dtmc); + auto region = storm::api::parseRegion("0.00001 <= p <= 0.99999", vars); + + auto checker = storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); auto expressionManager = std::make_shared(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(formulas[0], dtmc, 3); + // Create the region + auto vars = storm::models::sparse::getProbabilityParameters(*dtmc); + auto region = storm::api::parseRegion("0.00001 <= p <= 0.99999", vars); + + auto checker = storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); auto expressionManager = std::make_shared(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(formulas[0], dtmc, 3); + // Create the region + auto vars = storm::models::sparse::getProbabilityParameters(*dtmc); + auto region = storm::api::parseRegion("0.00001 <= p <= 0.99999", vars); + + auto checker = storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); auto expressionManager = std::make_shared(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> formulas = storm::api::extractFormulasFromProperties(storm::api::parsePropertiesForPrismProgram(formulaAsString, program)); + std::shared_ptr> model = storm::api::buildSparseModel(program, formulas)->as>(); + std::shared_ptr> dtmc = model->as>(); + auto simplifier = storm::transformer::SparseParametricDtmcSimplifier>(*dtmc); + ASSERT_TRUE(simplifier.simplify(*(formulas[0]))); + model = simplifier.getSimplifiedModel(); + dtmc = model->as>(); + + 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("0.00001 <= p <= 0.4", vars); + + auto checker = storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); + + auto expressionManager = std::make_shared(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(*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(*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(*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)); + + + +} diff --git a/src/test/storm-pars/analysis/AssumptionMakerTest.cpp b/src/test/storm-pars/analysis/AssumptionMakerTest.cpp index bcdac1227..71b7b1e7f 100644 --- a/src/test/storm-pars/analysis/AssumptionMakerTest.cpp +++ b/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>(); + // Create the region + auto vars = storm::models::sparse::getProbabilityParameters(*dtmc); + auto region = storm::api::parseRegion("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(formulas[0], dtmc, 3); + auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); auto assumptionMaker = storm::analysis::AssumptionMaker(&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>(); + // Create the region + auto vars = storm::models::sparse::getProbabilityParameters(*dtmc); + auto region = storm::api::parseRegion("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(formulas[0], dtmc, 3); + auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); // This one does not validate the assumptions! auto assumptionMaker = storm::analysis::AssumptionMaker(&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>(); + // Create the region + auto vars = storm::models::sparse::getProbabilityParameters(*dtmc); + auto region = storm::api::parseRegion("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(formulas[0], dtmc, 3); + auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); auto assumptionMaker = storm::analysis::AssumptionMaker(&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>(); + // Create the region + auto vars = storm::models::sparse::getProbabilityParameters(*dtmc); + auto region = storm::api::parseRegion("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(formulas[0], dtmc, 3); + auto assumptionChecker = storm::analysis::AssumptionChecker(formulas[0], dtmc, region, 3); auto assumptionMaker = storm::analysis::AssumptionMaker(&assumptionChecker, dtmc->getNumberOfStates(), true); auto result = assumptionMaker.createAndCheckAssumption(1, 2, lattice); diff --git a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp b/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp index 27ba61483..4dfc2e38b 100644 --- a/src/test/storm-pars/analysis/MonotonicityCheckerTest.cpp +++ b/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::Valuation lowerBoundaries; + typename storm::storage::ParameterRegion::Valuation upperBoundaries; + auto region = storm::storage::ParameterRegion(std::move(lowerBoundaries), std::move(upperBoundaries)); + // Derivative 0 auto constFunction = storm::RationalFunction(0); - auto constFunctionRes = storm::analysis::MonotonicityChecker::checkDerivative(constFunction); + auto constFunctionRes = storm::analysis::MonotonicityChecker::checkDerivative(constFunction, region); EXPECT_TRUE(constFunctionRes.first); EXPECT_TRUE(constFunctionRes.second); // Derivative 5 constFunction = storm::RationalFunction(5); - constFunctionRes = storm::analysis::MonotonicityChecker::checkDerivative(constFunction); + constFunctionRes = storm::analysis::MonotonicityChecker::checkDerivative(constFunction, region); EXPECT_TRUE(constFunctionRes.first); EXPECT_FALSE(constFunctionRes.second); // Derivative -4 constFunction = storm::RationalFunction(storm::RationalFunction(1)-constFunction); - constFunctionRes = storm::analysis::MonotonicityChecker::checkDerivative(constFunction); + constFunctionRes = storm::analysis::MonotonicityChecker::checkDerivative(constFunction, region); EXPECT_FALSE(constFunctionRes.first); EXPECT_TRUE(constFunctionRes.second); std::shared_ptr cache = std::make_shared(); carl::StringParser parser; parser.setVariables({"p", "q"}); + + // Create the region + auto functionP = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial("p"), cache)); + auto functionQ = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial("q"), cache)); + + auto varsP = functionP.gatherVariables(); + auto varsQ = functionQ.gatherVariables(); + storm::utility::parametric::Valuation lowerBoundaries2; + storm::utility::parametric::Valuation upperBoundaries2; + for (auto var : varsP) { + typename storm::storage::ParameterRegion::CoefficientType lb = storm::utility::convertNumber::CoefficientType>(0 + 0.000001); + typename storm::storage::ParameterRegion::CoefficientType ub = storm::utility::convertNumber::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::CoefficientType lb = storm::utility::convertNumber::CoefficientType>(0 + 0.000001); + typename storm::storage::ParameterRegion::CoefficientType ub = storm::utility::convertNumber::CoefficientType>(1 - 0.000001); + lowerBoundaries2.emplace(std::make_pair(var, lb)); + upperBoundaries2.emplace(std::make_pair(var, ub)); + } + region = storm::storage::ParameterRegion(std::move(lowerBoundaries2), std::move(upperBoundaries2)); + // Derivative p - auto function = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial("p"), cache)); - auto functionRes = storm::analysis::MonotonicityChecker::checkDerivative(function); + auto function = functionP; + auto functionRes = storm::analysis::MonotonicityChecker::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::checkDerivative(functionDecr); + auto functionDecrRes = storm::analysis::MonotonicityChecker::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::checkDerivative(functionNonMonotonic); + auto functionNonMonotonicRes = storm::analysis::MonotonicityChecker::checkDerivative(functionNonMonotonic, region); EXPECT_FALSE(functionNonMonotonicRes.first); EXPECT_FALSE(functionNonMonotonicRes.second); // Derivative -p functionDecr = storm::RationalFunction(storm::RationalFunction(0)-function); - functionDecrRes = storm::analysis::MonotonicityChecker::checkDerivative(functionDecr); + functionDecrRes = storm::analysis::MonotonicityChecker::checkDerivative(functionDecr, region); EXPECT_FALSE(functionDecrRes.first); EXPECT_TRUE(functionDecrRes.second); // Derivative p*q - function = storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial("p"), cache)) - * storm::RationalFunction(storm::Polynomial(parser.template parseMultivariatePolynomial("q"), cache)) ; - functionRes = storm::analysis::MonotonicityChecker::checkDerivative(function); + function = functionP * functionQ ; + functionRes = storm::analysis::MonotonicityChecker::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(model, formulas, bisimType)->as>(); + + // Create the region + typename storm::storage::ParameterRegion::Valuation lowerBoundaries; + typename storm::storage::ParameterRegion::Valuation upperBoundaries; + std::set::VariableType> vars = storm::models::sparse::getProbabilityParameters(*dtmc); + for (auto var : vars) { + typename storm::storage::ParameterRegion::CoefficientType lb = storm::utility::convertNumber::CoefficientType>(0 + 0.000001); + typename storm::storage::ParameterRegion::CoefficientType ub = storm::utility::convertNumber::CoefficientType>(1 - 0.000001); + lowerBoundaries.emplace(std::make_pair(var, lb)); + upperBoundaries.emplace(std::make_pair(var, ub)); + } + auto region = storm::storage::ParameterRegion(std::move(lowerBoundaries), std::move(upperBoundaries)); +std::vector> regions = {region}; + ASSERT_EQ(dtmc->getNumberOfStates(), 99ull); ASSERT_EQ(dtmc->getNumberOfTransitions(), 195ull); - storm::analysis::MonotonicityChecker monotonicityChecker = storm::analysis::MonotonicityChecker(dtmc, formulas, true); + storm::analysis::MonotonicityChecker monotonicityChecker = storm::analysis::MonotonicityChecker(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(model, formulas, bisimType)->as>(); + // Create the region + typename storm::storage::ParameterRegion::Valuation lowerBoundaries; + typename storm::storage::ParameterRegion::Valuation upperBoundaries; + std::set::VariableType> vars = storm::models::sparse::getProbabilityParameters(*dtmc); + for (auto var : vars) { + typename storm::storage::ParameterRegion::CoefficientType lb = storm::utility::convertNumber::CoefficientType>(0 + 0.000001); + typename storm::storage::ParameterRegion::CoefficientType ub = storm::utility::convertNumber::CoefficientType>(1 - 0.000001); + lowerBoundaries.emplace(std::make_pair(var, lb)); + upperBoundaries.emplace(std::make_pair(var, ub)); + } + auto region = storm::storage::ParameterRegion(std::move(lowerBoundaries), std::move(upperBoundaries)); + std::vector> regions = {region}; + ASSERT_EQ(dtmc->getNumberOfStates(), 99ull); ASSERT_EQ(dtmc->getNumberOfTransitions(), 195ull); - storm::analysis::MonotonicityChecker monotonicityChecker = storm::analysis::MonotonicityChecker(dtmc, formulas, true, 50); + auto monotonicityChecker = storm::analysis::MonotonicityChecker(dtmc, formulas, regions, true, 50); auto result = monotonicityChecker.checkMonotonicity(); EXPECT_EQ(1, result.size()); EXPECT_EQ(2, result.begin()->second.size());