You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
206 lines
12 KiB
206 lines
12 KiB
//
|
|
// Created by Jip Spel on 20.09.18.
|
|
//
|
|
|
|
#include "gtest/gtest.h"
|
|
#include "storm-config.h"
|
|
#include "test/storm_gtest.h"
|
|
#include "storm-pars/analysis/MonotonicityChecker.h"
|
|
#include "storm/storage/expressions/BinaryRelationExpression.h"
|
|
#include "storm/storage/SparseMatrix.h"
|
|
#include "storm/adapters/RationalFunctionAdapter.h"
|
|
|
|
#include "storm-parsers/parser/FormulaParser.h"
|
|
#include "storm/logic/Formulas.h"
|
|
#include "storm/models/sparse/StandardRewardModel.h"
|
|
#include "storm/modelchecker/prctl/SparseDtmcPrctlModelChecker.h"
|
|
#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h"
|
|
#include "storm-parsers/parser/AutoParser.h"
|
|
#include "storm-parsers/parser/PrismParser.h"
|
|
#include "storm/storage/expressions/ExpressionManager.h"
|
|
#include "storm/api/builder.h"
|
|
|
|
#include "storm-pars/transformer/SparseParametricDtmcSimplifier.h"
|
|
|
|
#include "storm-pars/api/storm-pars.h"
|
|
#include "storm/api/storm.h"
|
|
|
|
#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, region);
|
|
EXPECT_TRUE(constFunctionRes.first);
|
|
EXPECT_TRUE(constFunctionRes.second);
|
|
|
|
// Derivative 5
|
|
constFunction = storm::RationalFunction(5);
|
|
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, 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 = 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, 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, 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, region);
|
|
EXPECT_FALSE(functionDecrRes.first);
|
|
EXPECT_TRUE(functionDecrRes.second);
|
|
|
|
// Derivative p*q
|
|
function = functionP * functionQ ;
|
|
functionRes = storm::analysis::MonotonicityChecker<storm::RationalFunction>::checkDerivative(function, region);
|
|
EXPECT_TRUE(functionRes.first);
|
|
EXPECT_FALSE(functionRes.second);
|
|
}
|
|
|
|
TEST(MonotonicityCheckerTest, Brp_with_bisimulation_no_samples) {
|
|
std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm";
|
|
std::string formulaAsString = "P=? [true U s=4 & i=N ]";
|
|
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();
|
|
|
|
// Apply bisimulation
|
|
storm::storage::BisimulationType bisimType = storm::storage::BisimulationType::Strong;
|
|
if (storm::settings::getModule<storm::settings::modules::BisimulationSettings>().isWeakBisimulationSet()) {
|
|
bisimType = storm::storage::BisimulationType::Weak;
|
|
}
|
|
|
|
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, regions, true);
|
|
auto result = monotonicityChecker.checkMonotonicity();
|
|
EXPECT_EQ(1ul, result.size());
|
|
EXPECT_EQ(2ul, result.begin()->second.size());
|
|
auto monotone = result.begin()->second.begin();
|
|
EXPECT_EQ(true, monotone->second.first);
|
|
EXPECT_EQ(false, monotone->second.second);
|
|
}
|
|
|
|
TEST(MonotonicityCheckerTest, Brp_with_bisimulation_samples) {
|
|
std::string programFile = STORM_TEST_RESOURCES_DIR "/pdtmc/brp16_2.pm";
|
|
std::string formulaAsString = "P=? [true U s=4 & i=N ]";
|
|
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();
|
|
|
|
// Apply bisimulation
|
|
storm::storage::BisimulationType bisimType = storm::storage::BisimulationType::Strong;
|
|
if (storm::settings::getModule<storm::settings::modules::BisimulationSettings>().isWeakBisimulationSet()) {
|
|
bisimType = storm::storage::BisimulationType::Weak;
|
|
}
|
|
|
|
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);
|
|
|
|
auto monotonicityChecker = storm::analysis::MonotonicityChecker<storm::RationalFunction>(dtmc, formulas, regions, true, 50);
|
|
auto result = monotonicityChecker.checkMonotonicity();
|
|
EXPECT_EQ(1ul, result.size());
|
|
EXPECT_EQ(2ul, result.begin()->second.size());
|
|
auto monotone = result.begin()->second.begin();
|
|
EXPECT_EQ(true, monotone->second.first);
|
|
EXPECT_EQ(false, monotone->second.second);
|
|
}
|