Browse Source

added option of splitting to predicate synthesis, added equivalence checker, fixed bug that caused some commands not to be abstracted

tempestpy_adaptions
dehnert 8 years ago
parent
commit
633f4293e3
  1. 17
      src/storm/abstraction/prism/AbstractCommand.cpp
  2. 3
      src/storm/abstraction/prism/AbstractCommand.h
  3. 79
      src/storm/abstraction/prism/AbstractProgram.cpp
  4. 16
      src/storm/abstraction/prism/AbstractProgram.h
  5. 8
      src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp
  6. 95
      src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp
  7. 6
      src/storm/settings/modules/AbstractionSettings.cpp
  8. 8
      src/storm/settings/modules/AbstractionSettings.h
  9. 23
      src/storm/storage/expressions/EquivalenceChecker.cpp
  10. 28
      src/storm/storage/expressions/EquivalenceChecker.h
  11. 14
      src/storm/storage/expressions/Expression.h
  12. 80
      src/storm/storage/expressions/PredicateSplitter.cpp
  13. 31
      src/storm/storage/expressions/PredicateSplitter.h
  14. 6
      src/storm/utility/graph.cpp
  15. 12
      src/test/abstraction/PrismMenuGameTest.cpp

17
src/storm/abstraction/prism/AbstractCommand.cpp

@ -1,5 +1,7 @@
#include "storm/abstraction/prism/AbstractCommand.h"
#include <chrono>
#include <boost/iterator/transform_iterator.hpp>
#include "storm/abstraction/AbstractionInformation.h"
@ -40,11 +42,11 @@ namespace storm {
for (uint_fast64_t index = 0; index < abstractionInformation.getNumberOfPredicates(); ++index) {
allPredicateIndices[index] = index;
}
this->refine(allPredicateIndices);
this->refine(allPredicateIndices, true);
}
template <storm::dd::DdType DdType, typename ValueType>
void AbstractCommand<DdType, ValueType>::refine(std::vector<uint_fast64_t> const& predicates) {
void AbstractCommand<DdType, ValueType>::refine(std::vector<uint_fast64_t> const& predicates, bool forceRecomputation) {
// Add all predicates to the variable partition.
for (auto predicateIndex : predicates) {
localExpressionInformation.addExpression(this->getAbstractionInformation().getPredicateByIndex(predicateIndex), predicateIndex);
@ -57,7 +59,7 @@ namespace storm {
std::pair<std::set<uint_fast64_t>, std::vector<std::set<uint_fast64_t>>> newRelevantPredicates = this->computeRelevantPredicates();
// If the DD does not need recomputation, we can return the cached result.
bool recomputeDd = this->relevantPredicatesChanged(newRelevantPredicates);
bool recomputeDd = forceRecomputation || this->relevantPredicatesChanged(newRelevantPredicates);
if (!recomputeDd) {
// If the new predicates are unrelated to the BDD of this command, we need to multiply their identities.
cachedDd.bdd &= computeMissingGlobalIdentities();
@ -76,11 +78,14 @@ namespace storm {
template <storm::dd::DdType DdType, typename ValueType>
void AbstractCommand<DdType, ValueType>::recomputeCachedBdd() {
STORM_LOG_TRACE("Recomputing BDD for command " << command.get());
auto start = std::chrono::high_resolution_clock::now();
// Create a mapping from source state DDs to their distributions.
std::unordered_map<storm::dd::Bdd<DdType>, std::vector<storm::dd::Bdd<DdType>>> sourceToDistributionsMap;
smtSolver->allSat(decisionVariables, [&sourceToDistributionsMap,this] (storm::solver::SmtSolver::ModelReference const& model) {
uint64_t numberOfSolutions = 0;
smtSolver->allSat(decisionVariables, [&sourceToDistributionsMap,this,&numberOfSolutions] (storm::solver::SmtSolver::ModelReference const& model) {
sourceToDistributionsMap[getSourceStateBdd(model)].push_back(getDistributionBdd(model));
++numberOfSolutions;
return true;
});
@ -127,6 +132,9 @@ namespace storm {
// Cache the result.
cachedDd = GameBddResult<DdType>(resultBdd, numberOfVariablesNeeded);
auto end = std::chrono::high_resolution_clock::now();
STORM_LOG_TRACE("Enumerated " << numberOfSolutions << " solutions in " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms.");
}
template <storm::dd::DdType DdType, typename ValueType>
@ -309,6 +317,7 @@ namespace storm {
template <storm::dd::DdType DdType, typename ValueType>
BottomStateResult<DdType> AbstractCommand<DdType, ValueType>::getBottomStateTransitions(storm::dd::Bdd<DdType> const& reachableStates, uint_fast64_t numberOfPlayer2Variables) {
STORM_LOG_TRACE("Computing bottom state transitions of command " << command.get());
BottomStateResult<DdType> result(this->getAbstractionInformation().getDdManager().getBddZero(), this->getAbstractionInformation().getDdManager().getBddZero());
// If the guard of this command is a predicate, there are not bottom states/transitions.

3
src/storm/abstraction/prism/AbstractCommand.h

@ -65,8 +65,9 @@ namespace storm {
* Refines the abstract command with the given predicates.
*
* @param predicates The new predicates.
* @param forceRecomputation If set, the BDD is recomputed even if the relevant predicates have not changed.
*/
void refine(std::vector<uint_fast64_t> const& predicates);
void refine(std::vector<uint_fast64_t> const& predicates, bool forceRecomputation = false);
/*!
* Computes the abstraction of the command wrt. to the current set of predicates.

79
src/storm/abstraction/prism/AbstractProgram.cpp

@ -20,8 +20,6 @@
#include "storm-config.h"
#include "storm/adapters/CarlAdapter.h"
//#define LOCAL_DEBUG
namespace storm {
namespace abstraction {
namespace prism {
@ -30,8 +28,8 @@ namespace storm {
AbstractProgram<DdType, ValueType>::AbstractProgram(storm::prism::Program const& program,
std::vector<storm::expressions::Expression> const& initialPredicates,
std::shared_ptr<storm::utility::solver::SmtSolverFactory> const& smtSolverFactory,
bool addAllGuards)
: program(program), smtSolverFactory(smtSolverFactory), abstractionInformation(program.getManager()), modules(), initialStateAbstractor(abstractionInformation, program.getAllExpressionVariables(), {program.getInitialConstruct().getInitialStatesExpression()}, this->smtSolverFactory), addedAllGuards(addAllGuards), currentGame(nullptr) {
bool addAllGuards, bool splitPredicates)
: program(program), smtSolverFactory(smtSolverFactory), abstractionInformation(program.getManager()), modules(), initialStateAbstractor(abstractionInformation, program.getAllExpressionVariables(), {program.getInitialStatesExpression()}, this->smtSolverFactory), splitPredicates(splitPredicates), splitter(), equivalenceChecker(smtSolverFactory->create(abstractionInformation.getExpressionManager()), abstractionInformation.getExpressionManager().boolean(true)), addedAllGuards(addAllGuards), currentGame(nullptr) {
// For now, we assume that there is a single module. If the program has more than one module, it needs
// to be flattened before the procedure.
@ -66,42 +64,62 @@ namespace storm {
// odds are that it's impossible to treat such models in any event.
abstractionInformation.createEncodingVariables(static_cast<uint_fast64_t>(std::ceil(std::log2(totalNumberOfCommands))), 100, static_cast<uint_fast64_t>(std::ceil(std::log2(maximalUpdateCount))));
// Now that we have created all other DD variables, we create the DD variables for the predicates.
std::vector<uint_fast64_t> allPredicateIndices;
if (addAllGuards) {
for (auto const& guard : allGuards) {
allPredicateIndices.push_back(abstractionInformation.addPredicate(guard));
}
}
for (auto const& predicate : initialPredicates) {
allPredicateIndices.push_back(abstractionInformation.addPredicate(predicate));
}
// For each module of the concrete program, we create an abstract counterpart.
for (auto const& module : program.getModules()) {
this->modules.emplace_back(module, abstractionInformation, this->smtSolverFactory, addAllGuards);
}
// Refine the initial state abstractors using the initial predicates.
initialStateAbstractor.refine(allPredicateIndices);
// Retrieve the command-update probability ADD, so we can multiply it with the abstraction BDD later.
commandUpdateProbabilitiesAdd = modules.front().getCommandUpdateProbabilitiesAdd();
// Finally, we build the game the first time.
currentGame = buildGame();
// Now that we have created all other DD variables, we create the DD variables for the predicates.
std::vector<std::pair<storm::expressions::Expression, bool>> allPredicates;
for (auto const& predicate : initialPredicates) {
allPredicates.push_back(std::make_pair(predicate, false));
}
if (addAllGuards) {
for (auto const& guard : allGuards) {
allPredicates.push_back(std::make_pair(guard, true));
}
}
// Finally, refine using the all predicates and build game as a by-product.
this->refine(allPredicates);
}
template <storm::dd::DdType DdType, typename ValueType>
void AbstractProgram<DdType, ValueType>::refine(std::vector<storm::expressions::Expression> const& predicates) {
void AbstractProgram<DdType, ValueType>::refine(std::vector<std::pair<storm::expressions::Expression, bool>> const& predicates) {
STORM_LOG_THROW(!predicates.empty(), storm::exceptions::InvalidArgumentException, "Cannot refine without predicates.");
// Add the predicates to the global list of predicates.
std::vector<uint_fast64_t> newPredicateIndices;
for (auto const& predicate : predicates) {
for (auto const& predicateAllowSplitPair : predicates) {
storm::expressions::Expression const& predicate = predicateAllowSplitPair.first;
bool allowSplit = predicateAllowSplitPair.second;
STORM_LOG_THROW(predicate.hasBooleanType(), storm::exceptions::InvalidArgumentException, "Expecting a predicate of type bool.");
uint_fast64_t newPredicateIndex = abstractionInformation.addPredicate(predicate);
newPredicateIndices.push_back(newPredicateIndex);
if (allowSplit && splitPredicates) {
// Split the predicates.
std::vector<storm::expressions::Expression> atoms = splitter.split(predicate);
// Check which of the atoms are redundant in the sense that they are equivalent to a predicate we already have.
for (auto const& atom : atoms) {
bool addAtom = true;
for (auto const& oldPredicate : abstractionInformation.getPredicates()) {
if (equivalenceChecker.areEquivalent(atom, oldPredicate)) {
addAtom = false;
break;
}
}
if (addAtom) {
uint_fast64_t newPredicateIndex = abstractionInformation.addPredicate(atom);
newPredicateIndices.push_back(newPredicateIndex);
}
}
} else {
uint_fast64_t newPredicateIndex = abstractionInformation.addPredicate(predicate);
newPredicateIndices.push_back(newPredicateIndex);
}
}
// Refine all abstract modules.
@ -183,8 +201,8 @@ namespace storm {
STORM_LOG_TRACE("One of the successors is a bottom state, taking a guard as a new predicate.");
abstractCommand.notifyGuardIsPredicate();
storm::expressions::Expression newPredicate = concreteCommand.getGuardExpression();
STORM_LOG_TRACE("Derived new predicate: " << newPredicate);
this->refine({newPredicate});
STORM_LOG_DEBUG("Derived new predicate: " << newPredicate);
this->refine({std::make_pair(newPredicate, true)});
} else {
STORM_LOG_TRACE("No bottom state successor. Deriving a new predicate using weakest precondition.");
@ -231,6 +249,7 @@ namespace storm {
for (uint_fast64_t predicateIndex = 0; predicateIndex < lowerIt->second.size(); ++predicateIndex) {
if (lowerIt->second.get(predicateIndex) != upperIt->second.get(predicateIndex)) {
// Now we know the point of the deviation (command, update, predicate).
std::cout << "pred: " << abstractionInformation.getPredicateByIndex(predicateIndex) << " and update " << concreteCommand.getUpdate(updateIndex) << std::endl;
newPredicate = abstractionInformation.getPredicateByIndex(predicateIndex).substitute(concreteCommand.getUpdate(updateIndex).getAsVariableToExpressionMap()).simplify();
break;
}
@ -239,9 +258,9 @@ namespace storm {
}
STORM_LOG_ASSERT(newPredicate.isInitialized(), "Could not derive new predicate as there is no deviation.");
STORM_LOG_TRACE("Derived new predicate: " << newPredicate);
STORM_LOG_DEBUG("Derived new predicate: " << newPredicate);
this->refine({newPredicate});
this->refine({std::make_pair(newPredicate, true)});
}
STORM_LOG_TRACE("Current set of predicates:");
@ -299,7 +318,9 @@ namespace storm {
}
// Construct the transition matrix by cutting away the transitions of unreachable states.
storm::dd::Add<DdType, ValueType> transitionMatrix = (game.bdd && reachableStates).template toAdd<ValueType>() * commandUpdateProbabilitiesAdd + deadlockTransitions;
storm::dd::Add<DdType, ValueType> transitionMatrix = (game.bdd && reachableStates).template toAdd<ValueType>();
transitionMatrix *= commandUpdateProbabilitiesAdd;
transitionMatrix += deadlockTransitions;
// Extend the current game information with the 'non-bottom' tag before potentially adding bottom state transitions.
transitionMatrix *= (abstractionInformation.getBottomStateBdd(true, true) && abstractionInformation.getBottomStateBdd(false, true)).template toAdd<ValueType>();

16
src/storm/abstraction/prism/AbstractProgram.h

@ -9,6 +9,8 @@
#include "storm/storage/dd/Add.h"
#include "storm/storage/expressions/Expression.h"
#include "storm/storage/expressions/PredicateSplitter.h"
#include "storm/storage/expressions/EquivalenceChecker.h"
namespace storm {
namespace utility {
@ -43,8 +45,9 @@ namespace storm {
* @param initialPredicates The initial set of predicates.
* @param smtSolverFactory A factory that is to be used for creating new SMT solvers.
* @param addAllGuards A flag that indicates whether all guards of the program should be added to the initial set of predicates.
* @param splitPredicates A flag that indicates whether the predicates are to be split into atoms before being added.
*/
AbstractProgram(storm::prism::Program const& program, std::vector<storm::expressions::Expression> const& initialPredicates, std::shared_ptr<storm::utility::solver::SmtSolverFactory> const& smtSolverFactory = std::make_shared<storm::utility::solver::MathsatSmtSolverFactory>(), bool addAllGuards = false);
AbstractProgram(storm::prism::Program const& program, std::vector<storm::expressions::Expression> const& initialPredicates, std::shared_ptr<storm::utility::solver::SmtSolverFactory> const& smtSolverFactory = std::make_shared<storm::utility::solver::MathsatSmtSolverFactory>(), bool addAllGuards = false, bool splitPredicates = false);
AbstractProgram(AbstractProgram const&) = default;
AbstractProgram& operator=(AbstractProgram const&) = default;
@ -72,7 +75,7 @@ namespace storm {
*
* @param predicates The new predicates.
*/
void refine(std::vector<storm::expressions::Expression> const& predicates);
void refine(std::vector<std::pair<storm::expressions::Expression, bool>> const& predicates);
/*!
* Refines the abstract program using the pivot state, and player 1 choice. The refinement guarantees that
@ -125,6 +128,15 @@ namespace storm {
// A state-set abstractor used to determine the initial states of the abstraction.
StateSetAbstractor<DdType, ValueType> initialStateAbstractor;
// A flag indicating whether predicates are to be split into atoms or not.
bool splitPredicates;
// An object that can be used for splitting predicates.
storm::expressions::PredicateSplitter splitter;
// An object that can be used to determine whether predicates are equivalent.
storm::expressions::EquivalenceChecker equivalenceChecker;
// A flag that stores whether all guards were added (which is relevant for determining the bottom states).
bool addedAllGuards;

8
src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp

@ -10,7 +10,7 @@ namespace storm {
namespace prism {
template <storm::dd::DdType DdType, typename ValueType>
PrismMenuGameAbstractor<DdType, ValueType>::PrismMenuGameAbstractor(storm::prism::Program const& program, std::vector<storm::expressions::Expression> const& initialPredicates, std::shared_ptr<storm::utility::solver::SmtSolverFactory> const& smtSolverFactory) : abstractProgram(program, initialPredicates, smtSolverFactory, storm::settings::getModule<storm::settings::modules::AbstractionSettings>().isAddAllGuardsSet()) {
PrismMenuGameAbstractor<DdType, ValueType>::PrismMenuGameAbstractor(storm::prism::Program const& program, std::vector<storm::expressions::Expression> const& initialPredicates, std::shared_ptr<storm::utility::solver::SmtSolverFactory> const& smtSolverFactory) : abstractProgram(program, initialPredicates, smtSolverFactory, storm::settings::getModule<storm::settings::modules::AbstractionSettings>().isAddAllGuardsSet(), storm::settings::getModule<storm::settings::modules::AbstractionSettings>().isSplitPredicatesSet()) {
// Intentionally left empty.
}
@ -21,7 +21,11 @@ namespace storm {
template <storm::dd::DdType DdType, typename ValueType>
void PrismMenuGameAbstractor<DdType, ValueType>::refine(std::vector<storm::expressions::Expression> const& predicates) {
abstractProgram.refine(predicates);
std::vector<std::pair<storm::expressions::Expression, bool>> predicatesWithFlags;
for (auto const& predicate : predicates) {
predicatesWithFlags.emplace_back(predicate, true);
}
abstractProgram.refine(predicatesWithFlags);
}
template <storm::dd::DdType DdType, typename ValueType>

95
src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp

@ -263,7 +263,10 @@ namespace storm {
bool lowerChoicesDifferent = !lowerChoice1.exclusiveOr(lowerChoice2).isZero();
if (lowerChoicesDifferent) {
STORM_LOG_TRACE("Refining based on lower choice.");
auto refinementStart = std::chrono::high_resolution_clock::now();
abstractor.refine(pivotState, (pivotState && minPlayer1Strategy).existsAbstract(game.getRowVariables()), lowerChoice1, lowerChoice2);
auto refinementEnd = std::chrono::high_resolution_clock::now();
STORM_LOG_TRACE("Refinement completed in " << std::chrono::duration_cast<std::chrono::milliseconds>(refinementEnd - refinementStart).count() << "ms.");
return true;
} else {
storm::dd::Bdd<Type> upperChoice = pivotState && game.getExtendedTransitionMatrix().toBdd() && maxPlayer1Strategy;
@ -273,7 +276,10 @@ namespace storm {
bool upperChoicesDifferent = !upperChoice1.exclusiveOr(upperChoice2).isZero();
if (upperChoicesDifferent) {
STORM_LOG_TRACE("Refining based on upper choice.");
auto refinementStart = std::chrono::high_resolution_clock::now();
abstractor.refine(pivotState, (pivotState && maxPlayer1Strategy).existsAbstract(game.getRowVariables()), upperChoice1, upperChoice2);
auto refinementEnd = std::chrono::high_resolution_clock::now();
STORM_LOG_TRACE("Refinement completed in " << std::chrono::duration_cast<std::chrono::milliseconds>(refinementEnd - refinementStart).count() << "ms.");
return true;
} else {
STORM_LOG_ASSERT(false, "Did not find choices from which to derive predicates.");
@ -309,11 +315,6 @@ namespace storm {
// Start with constructing the player 2 states that have a (min) and a (max) strategy.
// TODO: necessary?
storm::dd::Bdd<Type> constraint = minStrategyPair.second.existsAbstract(game.getPlayer2Variables()) && maxStrategyPair.second.existsAbstract(game.getPlayer2Variables());
// (minStrategyPair.first && pivotStates).template toAdd<ValueType>().exportToDot("piv_min_pl1.dot");
// (maxStrategyPair.first && pivotStates).template toAdd<ValueType>().exportToDot("piv_max_pl1.dot");
// (minStrategyPair.second && pivotStates).template toAdd<ValueType>().exportToDot("piv_min_pl2.dot");
// (maxStrategyPair.second && pivotStates).template toAdd<ValueType>().exportToDot("piv_max_pl2.dot");
// Now construct all player 2 choices that actually exist and differ in the min and max case.
constraint &= minPlayer2Strategy.exclusiveOr(maxPlayer2Strategy);
@ -326,55 +327,20 @@ namespace storm {
// Now that we have the pivot state candidates, we need to pick one.
storm::dd::Bdd<Type> pivotState = pickPivotState<Type>(game.getInitialStates(), reachableTransitions, game.getRowVariables(), game.getColumnVariables(), pivotStates);
// storm::dd::Add<Type, ValueType> pivotStateLower = pivotState.template toAdd<ValueType>() * minResult;
// storm::dd::Add<Type, ValueType> pivotStateUpper = pivotState.template toAdd<ValueType>() * maxResult;
// storm::dd::Bdd<Type> pivotStateIsMinProb0 = pivotState && prob01.min.first.getPlayer1States();
// storm::dd::Bdd<Type> pivotStateIsMaxProb0 = pivotState && prob01.max.first.getPlayer1States();
// storm::dd::Bdd<Type> pivotStateLowerStrategies = pivotState && prob01.min.first.getPlayer1Strategy() && prob01.min.first.getPlayer2Strategy();
// storm::dd::Bdd<Type> pivotStateUpperStrategies = pivotState && prob01.max.first.getPlayer1Strategy() && prob01.max.first.getPlayer2Strategy();
// storm::dd::Bdd<Type> pivotStateLowerPl1Strategy = pivotState && prob01.min.first.getPlayer1Strategy();
// storm::dd::Bdd<Type> pivotStateUpperPl1Strategy = pivotState && prob01.max.first.getPlayer1Strategy();
// storm::dd::Bdd<Type> pivotStateLowerPl2Strategy = pivotState && prob01.min.first.getPlayer2Strategy();
// storm::dd::Bdd<Type> pivotStateUpperPl2Strategy = pivotState && prob01.max.first.getPlayer2Strategy();
//
// minResult.exportToDot("minresult.dot");
// maxResult.exportToDot("maxresult.dot");
// pivotState.template toAdd<ValueType>().exportToDot("pivot.dot");
// pivotStateLower.exportToDot("pivot_lower.dot");
// pivotStateUpper.exportToDot("pivot_upper.dot");
// pivotStateIsMinProb0.template toAdd<ValueType>().exportToDot("pivot_is_minprob0.dot");
// pivotStateIsMaxProb0.template toAdd<ValueType>().exportToDot("pivot_is_maxprob0.dot");
// pivotStateLowerStrategies.template toAdd<ValueType>().exportToDot("pivot_lower_strats.dot");
// pivotStateUpperStrategies.template toAdd<ValueType>().exportToDot("pivot_upper_strats.dot");
// pivotStateLowerPl1Strategy.template toAdd<ValueType>().exportToDot("pivot_lower_pl1_strat.dot");
// pivotStateUpperPl1Strategy.template toAdd<ValueType>().exportToDot("pivot_upper_pl1_strat.dot");
// pivotStateLowerPl2Strategy.template toAdd<ValueType>().exportToDot("pivot_lower_pl2_strat.dot");
// pivotStateUpperPl2Strategy.template toAdd<ValueType>().exportToDot("pivot_upper_pl2_strat.dot");
// Compute the lower and the upper choice for the pivot state.
std::set<storm::expressions::Variable> variablesToAbstract = game.getNondeterminismVariables();
variablesToAbstract.insert(game.getRowVariables().begin(), game.getRowVariables().end());
storm::dd::Bdd<Type> lowerChoice = pivotState && game.getExtendedTransitionMatrix().toBdd() && minPlayer1Strategy;
// (pivotState && minStrategyPair.first).template toAdd<ValueType>().exportToDot("pl1_choice_in_pivot.dot");
// (pivotState && minStrategyPair.first && maxStrategyPair.second).template toAdd<ValueType>().exportToDot("pl1and2_choice_in_pivot.dot");
// (pivotState && maxStrategyPair.second).template toAdd<ValueType>().exportToDot("pl2_choice_in_pivot.dot");
storm::dd::Bdd<Type> lowerChoice1 = (lowerChoice && minPlayer2Strategy).existsAbstract(variablesToAbstract);
// lowerChoice.template toAdd<ValueType>().exportToDot("lower.dot");
// maxStrategyPair.second.template toAdd<ValueType>().exportToDot("max_strat.dot");
storm::dd::Bdd<Type> lowerChoice2 = (lowerChoice && maxPlayer2Strategy).existsAbstract(variablesToAbstract);
// lowerChoice2.template toAdd<ValueType>().exportToDot("tmp_lower.dot");
// lowerChoice2 = lowerChoice2.existsAbstract(variablesToAbstract);
#ifdef LOCAL_DEBUG
lowerChoice.template toAdd<ValueType>().exportToDot("ref_lower.dot");
lowerChoice1.template toAdd<ValueType>().exportToDot("ref_lower1.dot");
lowerChoice2.template toAdd<ValueType>().exportToDot("ref_lower2.dot");
#endif
bool lowerChoicesDifferent = !lowerChoice1.exclusiveOr(lowerChoice2).isZero();
if (lowerChoicesDifferent) {
STORM_LOG_TRACE("Refining based on lower choice.");
auto refinementStart = std::chrono::high_resolution_clock::now();
abstractor.refine(pivotState, (pivotState && minPlayer1Strategy).existsAbstract(game.getRowVariables()), lowerChoice1, lowerChoice2);
auto refinementEnd = std::chrono::high_resolution_clock::now();
STORM_LOG_TRACE("Refinement completed in " << std::chrono::duration_cast<std::chrono::milliseconds>(refinementEnd - refinementStart).count() << "ms.");
} else {
storm::dd::Bdd<Type> upperChoice = pivotState && game.getExtendedTransitionMatrix().toBdd() && maxPlayer1Strategy;
storm::dd::Bdd<Type> upperChoice1 = (upperChoice && minPlayer2Strategy).existsAbstract(variablesToAbstract);
@ -383,7 +349,10 @@ namespace storm {
bool upperChoicesDifferent = !upperChoice1.exclusiveOr(upperChoice2).isZero();
if (upperChoicesDifferent) {
STORM_LOG_TRACE("Refining based on upper choice.");
auto refinementStart = std::chrono::high_resolution_clock::now();
abstractor.refine(pivotState, (pivotState && maxPlayer1Strategy).existsAbstract(game.getRowVariables()), upperChoice1, upperChoice2);
auto refinementEnd = std::chrono::high_resolution_clock::now();
STORM_LOG_TRACE("Refinement completed in " << std::chrono::duration_cast<std::chrono::milliseconds>(refinementEnd - refinementStart).count() << "ms.");
} else {
STORM_LOG_ASSERT(false, "Did not find choices from which to derive predicates.");
}
@ -462,6 +431,7 @@ namespace storm {
storm::abstraction::prism::PrismMenuGameAbstractor<Type, ValueType> abstractor(preprocessedProgram, initialPredicates, smtSolverFactory);
for (uint_fast64_t iterations = 0; iterations < 10000; ++iterations) {
auto iterationStart = std::chrono::high_resolution_clock::now();
STORM_LOG_TRACE("Starting iteration " << iterations << ".");
// 1. build initial abstraction based on the the constraint expression (if not 'true') and the target state expression.
@ -479,10 +449,11 @@ namespace storm {
targetStates |= game.getBottomStates();
}
#ifdef LOCAL_DEBUG
abstractor.exportToDot("game" + std::to_string(iterations) + ".dot", targetStates, game.getManager().getBddOne());
#endif
// #ifdef LOCAL_DEBUG
// abstractor.exportToDot("game" + std::to_string(iterations) + ".dot", targetStates, game.getManager().getBddOne());
// #endif
auto qualitativeStart = std::chrono::high_resolution_clock::now();
prob01.min = computeProb01States(player1Direction, storm::OptimizationDirection::Minimize, game, transitionMatrixBdd, game.getStates(constraintExpression), targetStates);
std::unique_ptr<CheckResult> result = checkForResultAfterQualitativeCheck<Type, ValueType>(checkTask, storm::OptimizationDirection::Minimize, game.getInitialStates(), prob01.min.first.getPlayer1States(), prob01.min.second.getPlayer1States());
if (result) {
@ -517,15 +488,19 @@ namespace storm {
}
STORM_LOG_DEBUG("Obtained qualitative bounds [0, 1] on the actual value for the initial states.");
// If we get here, the initial states were all identified as prob0/1 states, but the value (0 or 1)
// depends on whether player 2 is minimizing or maximizing. Therefore, we need to find a place to refine.
qualitativeRefinement = refineAfterQualitativeCheck(abstractor, game, prob01, transitionMatrixBdd);
}
auto qualitativeEnd = std::chrono::high_resolution_clock::now();
STORM_LOG_DEBUG("Qualitative step completed in " << std::chrono::duration_cast<std::chrono::milliseconds>(qualitativeEnd - qualitativeStart).count() << "ms.");
if (!qualitativeRefinement) {
// At this point, we know that we cannot answer the query without further numeric computation.
STORM_LOG_TRACE("Starting numerical solution step.");
auto quantitativeStart = std::chrono::high_resolution_clock::now();
// Prepare some storage that we use on-demand during the quantitative solving step.
storm::dd::Add<Type, ValueType> minResult = prob01.min.second.getPlayer1States().template toAdd<ValueType>();
@ -539,6 +514,7 @@ namespace storm {
// the result right away.
ValueType minValue = storm::utility::zero<ValueType>();
MaybeStateResult<Type, ValueType> minMaybeStateResult(game.getManager().template getAddZero<ValueType>(), game.getManager().getBddZero(), game.getManager().getBddZero());
auto minStart = std::chrono::high_resolution_clock::now();
if (!maybeMin.isZero()) {
minMaybeStateResult = solveMaybeStates(player1Direction, storm::OptimizationDirection::Minimize, game, maybeMin, prob01.min.second.getPlayer1States());
minMaybeStateResult.player1Strategy &= game.getReachableStates();
@ -549,7 +525,8 @@ namespace storm {
STORM_LOG_ASSERT(initialStateMin.getNonZeroCount() <= 1, "Wrong number of results for initial states. Expected <= 1, but got " << initialStateMin.getNonZeroCount() << ".");
minValue = initialStateMin.getMax();
}
STORM_LOG_TRACE("Obtained quantitative lower bound " << minValue << ".");
auto minEnd = std::chrono::high_resolution_clock::now();
STORM_LOG_TRACE("Obtained quantitative lower bound " << minValue << " in " << std::chrono::duration_cast<std::chrono::milliseconds>(minEnd - minStart).count() << "ms.");
minMaybeStateResult.player1Strategy = combinedMinPlayer1QualitativeStrategies.existsAbstract(game.getPlayer1Variables()).ite(combinedMinPlayer1QualitativeStrategies, minMaybeStateResult.player1Strategy);
minMaybeStateResult.player2Strategy = combinedMinPlayer2QualitativeStrategies.existsAbstract(game.getPlayer2Variables()).ite(combinedMinPlayer2QualitativeStrategies, minMaybeStateResult.player2Strategy);
@ -566,6 +543,7 @@ namespace storm {
// Likewise, the maximal value after qualitative checking can only be 1. If it was 0, we could have
// given the result right awy.
ValueType maxValue = storm::utility::one<ValueType>();
auto maxStart = std::chrono::high_resolution_clock::now();
MaybeStateResult<Type, ValueType> maxMaybeStateResult(game.getManager().template getAddZero<ValueType>(), game.getManager().getBddZero(), game.getManager().getBddZero());
if (!maybeMax.isZero()) {
maxMaybeStateResult = solveMaybeStates(player1Direction, storm::OptimizationDirection::Maximize, game, maybeMax, prob01.max.second.getPlayer1States(), boost::make_optional(minMaybeStateResult));
@ -578,7 +556,8 @@ namespace storm {
STORM_LOG_ASSERT(initialStateMax.getNonZeroCount() == 1, "Wrong number of results for initial states. Expected 1, but got " << initialStateMax.getNonZeroCount() << ".");
maxValue = initialStateMax.getMax();
}
STORM_LOG_TRACE("Obtained quantitative upper bound " << maxValue << ".");
auto maxEnd = std::chrono::high_resolution_clock::now();
STORM_LOG_TRACE("Obtained quantitative upper bound " << maxValue << " in " << std::chrono::duration_cast<std::chrono::milliseconds>(maxEnd - maxStart).count() << "ms.");
maxMaybeStateResult.player1Strategy = combinedMaxPlayer1QualitativeStrategies.existsAbstract(game.getPlayer1Variables()).ite(combinedMaxPlayer1QualitativeStrategies, maxMaybeStateResult.player1Strategy);
maxMaybeStateResult.player2Strategy = combinedMaxPlayer2QualitativeStrategies.existsAbstract(game.getPlayer2Variables()).ite(combinedMaxPlayer2QualitativeStrategies, maxMaybeStateResult.player2Strategy);
@ -589,7 +568,8 @@ namespace storm {
return result;
}
STORM_LOG_DEBUG("Obtained quantitative bounds [" << minValue << ", " << maxValue << "] on the actual value for the initial states.");
auto quantitativeEnd = std::chrono::high_resolution_clock::now();
STORM_LOG_DEBUG("Obtained quantitative bounds [" << minValue << ", " << maxValue << "] on the actual value for the initial states in " << std::chrono::duration_cast<std::chrono::milliseconds>(quantitativeEnd - quantitativeStart).count() << "ms.");
result = checkForResultAfterQuantitativeCheck<ValueType>(checkTask, minValue, maxValue);
if (result) {
@ -608,19 +588,12 @@ namespace storm {
// Check whether the strategies coincide over the reachable parts.
storm::dd::Bdd<Type> tmp = game.getTransitionMatrix().toBdd() && (minMaybeStateResult.player1Strategy || maxMaybeStateResult.player1Strategy) && (minMaybeStateResult.player2Strategy || maxMaybeStateResult.player2Strategy);
storm::dd::Bdd<Type> commonReach = storm::utility::dd::computeReachableStates(game.getInitialStates(), tmp.existsAbstract(game.getNondeterminismVariables()), game.getRowVariables(), game.getColumnVariables());
//std::cout << "diff one? " << ((commonReach && minMaybeStateResult.player1Strategy) != (commonReach && maxMaybeStateResult.player1Strategy)) << std::endl;
//std::cout << "diff one? " << ((commonReach && minMaybeStateResult.player2Strategy) != (commonReach && maxMaybeStateResult.player2Strategy)) << std::endl;
STORM_LOG_ASSERT((commonReach && minMaybeStateResult.player1Strategy) != (commonReach && maxMaybeStateResult.player1Strategy) || (commonReach && minMaybeStateResult.player2Strategy) != (commonReach && maxMaybeStateResult.player2Strategy), "The strategies fully coincide.");
#ifdef LOCAL_DEBUG
abstractor.exportToDot("lowerlower" + std::to_string(iterations) + ".dot", targetStates, minMaybeStateResult.player1Strategy && minMaybeStateResult.player2Strategy);
abstractor.exportToDot("upperupper" + std::to_string(iterations) + ".dot", targetStates, maxMaybeStateResult.player1Strategy && maxMaybeStateResult.player2Strategy);
abstractor.exportToDot("common" + std::to_string(iterations) + ".dot", targetStates, (minMaybeStateResult.player1Strategy || maxMaybeStateResult.player1Strategy) && minMaybeStateResult.player2Strategy && maxMaybeStateResult.player2Strategy);
abstractor.exportToDot("both" + std::to_string(iterations) + ".dot", targetStates, (minMaybeStateResult.player1Strategy || maxMaybeStateResult.player1Strategy) && (minMaybeStateResult.player2Strategy || maxMaybeStateResult.player2Strategy));
#endif
refineAfterQuantitativeCheck(abstractor, game, minResult, maxResult, prob01, std::make_pair(minMaybeStateResult.player1Strategy, minMaybeStateResult.player2Strategy), std::make_pair(maxMaybeStateResult.player1Strategy, maxMaybeStateResult.player2Strategy), transitionMatrixBdd);
}
auto iterationEnd = std::chrono::high_resolution_clock::now();
STORM_LOG_DEBUG("Iteration " << iterations << " took " << std::chrono::duration_cast<std::chrono::milliseconds>(iterationEnd - iterationStart).count() << "ms.");
}
STORM_LOG_ASSERT(false, "This point must not be reached.");
@ -630,8 +603,6 @@ namespace storm {
template<storm::dd::DdType Type, typename ModelType>
std::pair<storm::utility::graph::GameProb01Result<Type>, storm::utility::graph::GameProb01Result<Type>> GameBasedMdpModelChecker<Type, ModelType>::computeProb01States(storm::OptimizationDirection player1Direction, storm::OptimizationDirection player2Direction, storm::abstraction::MenuGame<Type, ValueType> const& game, storm::dd::Bdd<Type> const& transitionMatrixBdd, storm::dd::Bdd<Type> const& constraintStates, storm::dd::Bdd<Type> const& targetStates) {
// Compute the states with probability 0/1.
// storm::utility::graph::GameProb01Result<Type> prob0 = storm::utility::graph::performProb0(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, player2Direction, player2Direction == storm::OptimizationDirection::Minimize, player2Direction == storm::OptimizationDirection::Minimize);
// storm::utility::graph::GameProb01Result<Type> prob1 = storm::utility::graph::performProb1(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, player2Direction, player2Direction == storm::OptimizationDirection::Maximize, player2Direction == storm::OptimizationDirection::Maximize);
storm::utility::graph::GameProb01Result<Type> prob0 = storm::utility::graph::performProb0(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, player2Direction, true, true);
storm::utility::graph::GameProb01Result<Type> prob1 = storm::utility::graph::performProb1(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, player2Direction, true, true);

6
src/storm/settings/modules/AbstractionSettings.cpp

@ -9,14 +9,20 @@ namespace storm {
const std::string AbstractionSettings::moduleName = "abstraction";
const std::string AbstractionSettings::addAllGuardsOptionName = "allguards";
const std::string AbstractionSettings::splitPredicatesOptionName = "split-preds";
AbstractionSettings::AbstractionSettings() : ModuleSettings(moduleName) {
this->addOption(storm::settings::OptionBuilder(moduleName, addAllGuardsOptionName, true, "Sets whether all guards are added as initial predicates.").build());
this->addOption(storm::settings::OptionBuilder(moduleName, splitPredicatesOptionName, true, "Sets whether the predicates are split into atoms before they are added.").build());
}
bool AbstractionSettings::isAddAllGuardsSet() const {
return this->getOption(addAllGuardsOptionName).getHasOptionBeenSet();
}
bool AbstractionSettings::isSplitPredicatesSet() const {
return this->getOption(splitPredicatesOptionName).getHasOptionBeenSet();
}
}
}

8
src/storm/settings/modules/AbstractionSettings.h

@ -22,11 +22,19 @@ namespace storm {
* @return True iff the option was set.
*/
bool isAddAllGuardsSet() const;
/*!
* Retrieves whether the option to split predicates to atoms was set.
*
* @return True iff the option was set.
*/
bool isSplitPredicatesSet() const;
const static std::string moduleName;
private:
const static std::string addAllGuardsOptionName;
const static std::string splitPredicatesOptionName;
};
}

23
src/storm/storage/expressions/EquivalenceChecker.cpp

@ -0,0 +1,23 @@
#include "storm/storage/expressions/EquivalenceChecker.h"
#include "storm/solver/SmtSolver.h"
#include "storm/storage/expressions/Expression.h"
namespace storm {
namespace expressions {
EquivalenceChecker::EquivalenceChecker(std::unique_ptr<storm::solver::SmtSolver>&& smtSolver, storm::expressions::Expression const& constraint) : smtSolver(std::move(smtSolver)) {
this->smtSolver->add(constraint);
}
bool EquivalenceChecker::areEquivalent(storm::expressions::Expression const& first, storm::expressions::Expression const& second) {
this->smtSolver->push();
this->smtSolver->add((first && !second) || (!first && second));
bool equivalent = smtSolver->check() == storm::solver::SmtSolver::CheckResult::Unsat;
this->smtSolver->pop();
return equivalent;
}
}
}

28
src/storm/storage/expressions/EquivalenceChecker.h

@ -0,0 +1,28 @@
#pragma once
#include <memory>
#include "storm/solver/SmtSolver.h"
namespace storm {
namespace expressions {
class Expression;
class EquivalenceChecker {
public:
/*!
* Creates an equivalence checker with the given solver and constraint.
*
* @param smtSolver The solver to use.
* @param constraint An additional constraint. Must be satisfiable.
*/
EquivalenceChecker(std::unique_ptr<storm::solver::SmtSolver>&& smtSolver, storm::expressions::Expression const& constraint);
bool areEquivalent(storm::expressions::Expression const& first, storm::expressions::Expression const& second);
private:
std::unique_ptr<storm::solver::SmtSolver> smtSolver;
};
}
}

14
src/storm/storage/expressions/Expression.h

@ -66,6 +66,13 @@ namespace storm {
*/
Expression(Variable const& variable);
/*!
* Creates an expression with the given underlying base expression.
*
* @param expressionPtr A pointer to the underlying base expression.
*/
Expression(std::shared_ptr<BaseExpression const> const& expressionPtr);
// Instantiate constructors and assignments with their default implementations.
Expression(Expression const& other) = default;
Expression& operator=(Expression const& other) = default;
@ -332,13 +339,6 @@ namespace storm {
friend std::ostream& operator<<(std::ostream& stream, Expression const& expression);
private:
/*!
* Creates an expression with the given underlying base expression.
*
* @param expressionPtr A pointer to the underlying base expression.
*/
Expression(std::shared_ptr<BaseExpression const> const& expressionPtr);
// A pointer to the underlying base expression.
std::shared_ptr<BaseExpression const> expressionPtr;
};

80
src/storm/storage/expressions/PredicateSplitter.cpp

@ -0,0 +1,80 @@
#include "storm/storage/expressions/PredicateSplitter.h"
#include "storm/storage/expressions/Expression.h"
#include "storm/storage/expressions/Expressions.h"
#include "storm/utility/macros.h"
#include "storm/exceptions/InvalidArgumentException.h"
namespace storm {
namespace expressions {
std::vector<storm::expressions::Expression> PredicateSplitter::split(storm::expressions::Expression const& expression) {
STORM_LOG_THROW(expression.hasBooleanType(), storm::exceptions::InvalidArgumentException, "Expected predicate of boolean type.");
// Gather all atoms.
atomicExpressions.clear();
expression.accept(*this, boost::none);
// Remove all boolean literals from the atoms.
std::vector<storm::expressions::Expression> atomsToKeep;
for (auto const& atom : atomicExpressions) {
if (!atom.isTrue() && !atom.isFalse()) {
atomsToKeep.push_back(atom);
}
}
atomicExpressions = std::move(atomsToKeep);
return atomicExpressions;
}
boost::any PredicateSplitter::visit(IfThenElseExpression const& expression, boost::any const&) {
atomicExpressions.push_back(expression.shared_from_this());
return boost::any();
}
boost::any PredicateSplitter::visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) {
expression.getFirstOperand()->accept(*this, data);
expression.getSecondOperand()->accept(*this, data);
return boost::any();
}
boost::any PredicateSplitter::visit(BinaryNumericalFunctionExpression const&, boost::any const&) {
return boost::any();
}
boost::any PredicateSplitter::visit(BinaryRelationExpression const& expression, boost::any const&) {
atomicExpressions.push_back(expression.shared_from_this());
return boost::any();
}
boost::any PredicateSplitter::visit(VariableExpression const& expression, boost::any const&) {
if (expression.hasBooleanType()) {
atomicExpressions.push_back(expression.shared_from_this());
}
return boost::any();
}
boost::any PredicateSplitter::visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) {
expression.getOperand()->accept(*this, data);
return boost::any();
}
boost::any PredicateSplitter::visit(UnaryNumericalFunctionExpression const&, boost::any const&) {
return boost::any();
}
boost::any PredicateSplitter::visit(BooleanLiteralExpression const&, boost::any const&) {
return boost::any();
}
boost::any PredicateSplitter::visit(IntegerLiteralExpression const&, boost::any const&) {
return boost::any();
}
boost::any PredicateSplitter::visit(RationalLiteralExpression const&, boost::any const&) {
return boost::any();
}
}
}

31
src/storm/storage/expressions/PredicateSplitter.h

@ -0,0 +1,31 @@
#pragma once
#include <vector>
#include "storm/storage/expressions/ExpressionVisitor.h"
namespace storm {
namespace expressions {
class Expression;
class PredicateSplitter : public ExpressionVisitor {
public:
std::vector<storm::expressions::Expression> split(storm::expressions::Expression const& expression);
virtual boost::any visit(IfThenElseExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BinaryRelationExpression const& expression, boost::any const& data) override;
virtual boost::any visit(VariableExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryBooleanFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(UnaryNumericalFunctionExpression const& expression, boost::any const& data) override;
virtual boost::any visit(BooleanLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(IntegerLiteralExpression const& expression, boost::any const& data) override;
virtual boost::any visit(RationalLiteralExpression const& expression, boost::any const& data) override;
private:
std::vector<storm::expressions::Expression> atomicExpressions;
};
}
}

6
src/storm/utility/graph.cpp

@ -929,7 +929,7 @@ namespace storm {
// The solution sets.
storm::dd::Bdd<Type> player1States = psiStates;
storm::dd::Bdd<Type> player2States = model.getManager().getBddZero();
bool done = false;
uint_fast64_t iterations = 0;
while (!done) {
@ -960,18 +960,14 @@ namespace storm {
}
// Since we have determined the complements of the desired sets, we need to complement it now.
player1States.template toAdd<ValueType>().exportToDot("not_pl1_prob0.dot");
(!player1States).template toAdd<ValueType>().exportToDot("pl1_negated_prob0.dot");
player1States = !player1States && model.getReachableStates();
player2States = !player2States && model.getReachableStates();
// Determine all transitions between prob0 states.
storm::dd::Bdd<Type> transitionsBetweenProb0States = player2States && (transitionMatrix && player1States.swapVariables(model.getRowColumnMetaVariablePairs()));
player1States.template toAdd<ValueType>().exportToDot("pl1_prob0.dot");
// Determine the distributions that have only successors that are prob0 states.
storm::dd::Bdd<Type> onlyProb0Successors = (transitionsBetweenProb0States || model.getIllegalSuccessorMask()).universalAbstract(model.getColumnVariables());
onlyProb0Successors.template toAdd<ValueType>().exportToDot("only_prob0.dot");
boost::optional<storm::dd::Bdd<Type>> player2StrategyBdd;
if (producePlayer2Strategy) {

12
src/test/abstraction/PrismMenuGameTest.cpp

@ -434,7 +434,7 @@ TEST(PrismMenuGame, TwoDiceAbstractionTest_Sylvan) {
}
TEST(PrismMenuGame, TwoDiceAbstractionAndRefinementTest_Cudd) {
storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/builder/two_dice.nm");
storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/mdp/two_dice.nm");
program = program.substituteConstants();
program = program.flattenModules(std::make_shared<storm::utility::solver::MathsatSmtSolverFactory>());
@ -456,7 +456,7 @@ TEST(PrismMenuGame, TwoDiceAbstractionAndRefinementTest_Cudd) {
}
TEST(PrismMenuGame, TwoDiceAbstractionAndRefinementTest_Sylvan) {
storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/builder/two_dice.nm");
storm::prism::Program program = storm::parser::PrismParser::parse(STORM_TEST_RESOURCES_DIR "/mdp/two_dice.nm");
program = program.substituteConstants();
program = program.flattenModules(std::make_shared<storm::utility::solver::MathsatSmtSolverFactory>());
@ -595,7 +595,7 @@ TEST(PrismMenuGame, WlanAbstractionTest_Cudd) {
storm::abstraction::MenuGame<storm::dd::DdType::CUDD, double> game = abstractProgram.getAbstractGame();
EXPECT_EQ(1335, game.getNumberOfTransitions());
EXPECT_EQ(1379, game.getNumberOfTransitions());
EXPECT_EQ(12, game.getNumberOfStates());
EXPECT_EQ(8, game.getBottomStates().getNonZeroCount());
}
@ -616,7 +616,7 @@ TEST(PrismMenuGame, WlanAbstractionTest_Sylvan) {
storm::abstraction::MenuGame<storm::dd::DdType::Sylvan, double> game = abstractProgram.getAbstractGame();
EXPECT_EQ(1335, game.getNumberOfTransitions());
EXPECT_EQ(1379, game.getNumberOfTransitions());
EXPECT_EQ(12, game.getNumberOfStates());
EXPECT_EQ(8, game.getBottomStates().getNonZeroCount());
}
@ -639,7 +639,7 @@ TEST(PrismMenuGame, WlanAbstractionAndRefinementTest_Cudd) {
storm::abstraction::MenuGame<storm::dd::DdType::CUDD, double> game = abstractProgram.getAbstractGame();
EXPECT_EQ(2656, game.getNumberOfTransitions());
EXPECT_EQ(2744, game.getNumberOfTransitions());
EXPECT_EQ(24, game.getNumberOfStates());
EXPECT_EQ(16, game.getBottomStates().getNonZeroCount());
}
@ -662,7 +662,7 @@ TEST(PrismMenuGame, WlanAbstractionAndRefinementTest_Sylvan) {
storm::abstraction::MenuGame<storm::dd::DdType::Sylvan, double> game = abstractProgram.getAbstractGame();
EXPECT_EQ(2656, game.getNumberOfTransitions());
EXPECT_EQ(2744, game.getNumberOfTransitions());
EXPECT_EQ(24, game.getNumberOfStates());
EXPECT_EQ(16, game.getBottomStates().getNonZeroCount());
}

Loading…
Cancel
Save