|
|
@ -17,6 +17,11 @@ |
|
|
|
#include "storm/settings/modules/CoreSettings.h"
|
|
|
|
#include "storm/logic/Formulas.h"
|
|
|
|
#include "storm/exceptions/UncheckedRequirementException.h"
|
|
|
|
#include "storm/solver/Multiplier.h"
|
|
|
|
#include "storm/storage/SparseMatrix.h"
|
|
|
|
#include "storm/utility/graph.h"
|
|
|
|
#include "storm/storage/MaximalEndComponentDecomposition.h"
|
|
|
|
#include "storm/modelchecker/rpatl/helper/internal/SoundGameViHelper.h"
|
|
|
|
|
|
|
|
namespace { |
|
|
|
|
|
|
@ -114,6 +119,7 @@ namespace { |
|
|
|
std::vector<storm::modelchecker::CheckTask<storm::logic::Formula, ValueType>> getTasks(std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas) const { |
|
|
|
std::vector<storm::modelchecker::CheckTask<storm::logic::Formula, ValueType>> result; |
|
|
|
for (auto const& f : formulas) { |
|
|
|
std::cout << *f << std::endl; |
|
|
|
result.emplace_back(*f); |
|
|
|
} |
|
|
|
return result; |
|
|
@ -345,5 +351,152 @@ namespace { |
|
|
|
EXPECT_NEAR(this->parseNumber("1"), this->getQuantitativeResultAtInitialState(model, result), this->precision()); |
|
|
|
} |
|
|
|
|
|
|
|
TYPED_TEST(SmgRpatlModelCheckerTest, Deflate) { |
|
|
|
typedef double ValueType; |
|
|
|
std::string formulasString = " <<maxP>> Pmax=? [F (s=2)]"; |
|
|
|
|
|
|
|
auto modelFormulas = this->buildModelFormulas(STORM_TEST_RESOURCES_DIR "/smg/example_smg.nm", formulasString); |
|
|
|
auto model = std::move(modelFormulas.first); |
|
|
|
auto tasks = this->getTasks(modelFormulas.second); |
|
|
|
auto checker = this->createModelChecker(model); |
|
|
|
std::unique_ptr<storm::modelchecker::CheckResult> result; |
|
|
|
auto transitionMatrix = model->getTransitionMatrix(); |
|
|
|
|
|
|
|
|
|
|
|
auto formulas = std::move(modelFormulas.second); |
|
|
|
|
|
|
|
storm::logic::GameFormula const& gameFormula = formulas[0]->asGameFormula(); |
|
|
|
|
|
|
|
storm::modelchecker::CheckTask<storm::logic::GameFormula, ValueType> checkTask(gameFormula); |
|
|
|
|
|
|
|
storm::storage::BitVector statesOfCoalition = model->computeStatesOfCoalition(gameFormula.getCoalition()); |
|
|
|
statesOfCoalition.complement(); |
|
|
|
|
|
|
|
// TODO Fabian: get optimization direction
|
|
|
|
|
|
|
|
storm::storage::BitVector psiStates = checker->check(this->env(), gameFormula.getSubformula().asProbabilityOperatorFormula().getSubformula().asEventuallyFormula().getSubformula().asStateFormula())->asExplicitQualitativeCheckResult().getTruthValuesVector(); |
|
|
|
storm::storage::BitVector phiStates(model->getNumberOfStates(), true); |
|
|
|
|
|
|
|
storm::storage::SparseMatrix<ValueType> backwardTransitions = model->getBackwardTransitions(); |
|
|
|
storm::OptimizationDirection optimizationDirection = storm::OptimizationDirection::Maximize; |
|
|
|
auto minimizerStates = optimizationDirection == storm::OptimizationDirection::Maximize ? statesOfCoalition : ~statesOfCoalition; |
|
|
|
|
|
|
|
storm::modelchecker::helper::internal::SoundGameViHelper<ValueType> viHelper(transitionMatrix, backwardTransitions, statesOfCoalition, psiStates, optimizationDirection); |
|
|
|
viHelper.prepareSolversAndMultipliers(this->env()); |
|
|
|
|
|
|
|
std::vector<ValueType> xL = std::vector<ValueType>(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>()); |
|
|
|
for (size_t i = 0; i < xL.size(); i++) |
|
|
|
{ |
|
|
|
if (psiStates[i]) |
|
|
|
xL[i] = 1; |
|
|
|
} |
|
|
|
|
|
|
|
std::vector<ValueType> xU = std::vector<ValueType>(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>()); |
|
|
|
storm::storage::BitVector probGreater0 = storm::utility::graph::performProbGreater0(backwardTransitions, phiStates, psiStates); |
|
|
|
auto xU_begin = xU.begin(); |
|
|
|
std::for_each(xU.begin(), xU.end(), [&probGreater0, &xU_begin](ValueType &it) |
|
|
|
{ |
|
|
|
if (probGreater0[&it - &(*xU_begin)]) |
|
|
|
it = 1; |
|
|
|
}); |
|
|
|
|
|
|
|
// performValueIteration
|
|
|
|
std::vector<ValueType> _x1L = xL; |
|
|
|
std::vector<ValueType> _x2L = _x1L; |
|
|
|
|
|
|
|
std::vector<ValueType> _x1U = xU; |
|
|
|
std::vector<ValueType> _x2U = _x1U; |
|
|
|
|
|
|
|
// perform first iteration step
|
|
|
|
storm::storage::BitVector reducedMinimizerActions = {storm::storage::BitVector(transitionMatrix.getRowCount(), true)}; |
|
|
|
std::vector<ValueType> choiceValuesL = std::vector<ValueType>(transitionMatrix.getRowCount(), storm::utility::zero<ValueType>()); |
|
|
|
|
|
|
|
viHelper._multiplier->multiply(this->env(), _x2L, nullptr, choiceValuesL); |
|
|
|
|
|
|
|
viHelper.reduceChoiceValues(choiceValuesL, &reducedMinimizerActions, _x1L); |
|
|
|
|
|
|
|
|
|
|
|
// over approximation
|
|
|
|
std::vector<ValueType> choiceValuesU = std::vector<ValueType>(transitionMatrix.getRowCount(), storm::utility::zero<ValueType>()); |
|
|
|
|
|
|
|
viHelper._multiplier->multiply(this->env(), _x2U, nullptr, choiceValuesU); |
|
|
|
viHelper.reduceChoiceValues(choiceValuesU, nullptr, _x1U); |
|
|
|
|
|
|
|
storm::storage::SparseMatrix<ValueType> restrictedTransMatrix = transitionMatrix.restrictRows(reducedMinimizerActions); |
|
|
|
|
|
|
|
storm::storage::MaximalEndComponentDecomposition<ValueType> MSEC = storm::storage::MaximalEndComponentDecomposition<ValueType>(restrictedTransMatrix, backwardTransitions); |
|
|
|
|
|
|
|
// reducing the choiceValuesU
|
|
|
|
size_t i = 0; |
|
|
|
auto new_end = std::remove_if(choiceValuesU.begin(), choiceValuesU.end(), [&reducedMinimizerActions, &i](const auto& item) { |
|
|
|
bool ret = !(reducedMinimizerActions[i]); |
|
|
|
i++; |
|
|
|
return ret; |
|
|
|
}); |
|
|
|
choiceValuesU.erase(new_end, choiceValuesU.end()); |
|
|
|
|
|
|
|
// deflating the MSECs
|
|
|
|
viHelper.deflate(MSEC, restrictedTransMatrix, _x1U, choiceValuesU); |
|
|
|
|
|
|
|
xL = _x1L; |
|
|
|
xU = _x1U; |
|
|
|
|
|
|
|
EXPECT_NEAR(this->parseNumber("0"), xL[0], this->precision()); |
|
|
|
EXPECT_NEAR(this->parseNumber("0.333333"), xL[1], this->precision()); |
|
|
|
EXPECT_NEAR(this->parseNumber("1"), xL[2], this->precision()); |
|
|
|
EXPECT_NEAR(this->parseNumber("0"), xL[3], this->precision()); |
|
|
|
|
|
|
|
EXPECT_NEAR(this->parseNumber("0.666666"), xU[0], this->precision()); |
|
|
|
EXPECT_NEAR(this->parseNumber("0.666666"), xU[1], this->precision()); |
|
|
|
EXPECT_NEAR(this->parseNumber("1"), xU[2], this->precision()); |
|
|
|
EXPECT_NEAR(this->parseNumber("0"), xU[3], this->precision()); |
|
|
|
|
|
|
|
// second iteration step
|
|
|
|
|
|
|
|
reducedMinimizerActions = {storm::storage::BitVector(transitionMatrix.getRowCount(), true)}; |
|
|
|
choiceValuesL = std::vector<ValueType>(transitionMatrix.getRowCount(), storm::utility::zero<ValueType>()); |
|
|
|
|
|
|
|
viHelper._multiplier->multiply(this->env(), _x1L, nullptr, choiceValuesL); |
|
|
|
|
|
|
|
viHelper.reduceChoiceValues(choiceValuesL, &reducedMinimizerActions, _x2L); |
|
|
|
|
|
|
|
|
|
|
|
// over approximation
|
|
|
|
choiceValuesU = std::vector<ValueType>(transitionMatrix.getRowCount(), storm::utility::zero<ValueType>()); |
|
|
|
|
|
|
|
viHelper._multiplier->multiply(this->env(), _x1U, nullptr, choiceValuesU); |
|
|
|
viHelper.reduceChoiceValues(choiceValuesU, nullptr, _x2U); |
|
|
|
|
|
|
|
restrictedTransMatrix = transitionMatrix.restrictRows(reducedMinimizerActions); |
|
|
|
|
|
|
|
MSEC = storm::storage::MaximalEndComponentDecomposition<ValueType>(restrictedTransMatrix, backwardTransitions); |
|
|
|
|
|
|
|
// reducing the choiceValuesU
|
|
|
|
i = 0; |
|
|
|
new_end = std::remove_if(choiceValuesU.begin(), choiceValuesU.end(), [&reducedMinimizerActions, &i](const auto& item) { |
|
|
|
bool ret = !(reducedMinimizerActions[i]); |
|
|
|
i++; |
|
|
|
return ret; |
|
|
|
}); |
|
|
|
choiceValuesU.erase(new_end, choiceValuesU.end()); |
|
|
|
|
|
|
|
// deflating the MSECs
|
|
|
|
viHelper.deflate(MSEC, restrictedTransMatrix, _x2U, choiceValuesU); |
|
|
|
|
|
|
|
xL = _x2L; |
|
|
|
xU = _x2U; |
|
|
|
|
|
|
|
EXPECT_NEAR(this->parseNumber("0.333333"), xL[0], this->precision()); |
|
|
|
EXPECT_NEAR(this->parseNumber("0.444444"), xL[1], this->precision()); |
|
|
|
EXPECT_NEAR(this->parseNumber("1"), xL[2], this->precision()); |
|
|
|
EXPECT_NEAR(this->parseNumber("0"), xL[3], this->precision()); |
|
|
|
|
|
|
|
EXPECT_NEAR(this->parseNumber("0.555555"), xU[0], this->precision()); |
|
|
|
EXPECT_NEAR(this->parseNumber("0.555555"), xU[1], this->precision()); |
|
|
|
EXPECT_NEAR(this->parseNumber("1"), xU[2], this->precision()); |
|
|
|
EXPECT_NEAR(this->parseNumber("0"), xU[3], this->precision()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// TODO: create more test cases (files)
|
|
|
|
} |