Browse Source

fixed some bugs and started on quantitative refinement

Former-commit-id: 31259ad299
tempestpy_adaptions
dehnert 8 years ago
parent
commit
f45b7f9171
  1. 4
      resources/3rdparty/cudd-3.0.0/cudd/cuddAddAbs.c
  2. 2
      resources/3rdparty/include_cudd.cmake
  3. 3
      src/abstraction/StateSetAbstractor.cpp
  4. 11
      src/abstraction/prism/AbstractCommand.cpp
  5. 4
      src/abstraction/prism/AbstractModule.cpp
  6. 2
      src/abstraction/prism/AbstractProgram.cpp
  7. 4
      src/abstraction/prism/GameBddResult.cpp
  8. 3
      src/abstraction/prism/GameBddResult.h
  9. 80
      src/modelchecker/abstraction/GameBasedMdpModelChecker.cpp
  10. 5
      src/models/symbolic/Model.cpp
  11. 7
      src/models/symbolic/Model.h
  12. 2
      src/solver/OptimizationDirection.cpp
  13. 61
      src/solver/SymbolicGameSolver.cpp
  14. 4
      src/solver/SymbolicGameSolver.h
  15. 6
      src/storage/dd/cudd/InternalCuddAdd.cpp

4
resources/3rdparty/cudd-3.0.0/cudd/cuddAddAbs.c

@ -1007,7 +1007,7 @@ cuddAddMinAbstractRepresentativeRecur(
return one;
}
if (cuddIsConstant(f)) {
res = cuddBddExistAbstractRepresentativeRecur(manager, f, cuddT(cube));
res = cuddAddMinAbstractRepresentativeRecur(manager, f, cuddT(cube));
if (res == NULL) {
return(NULL);
}
@ -1193,7 +1193,7 @@ cuddAddMaxAbstractRepresentativeRecur(
return one;
}
if (cuddIsConstant(f)) {
res = cuddBddExistAbstractRepresentativeRecur(manager, f, cuddT(cube));
res = cuddAddMaxAbstractRepresentativeRecur(manager, f, cuddT(cube));
if (res == NULL) {
return(NULL);
}

2
resources/3rdparty/include_cudd.cmake

@ -28,4 +28,4 @@ add_dependencies(resources cudd3)
message(STATUS "StoRM - Linking with CUDD ${CUDD_VERSION_STRING}")
#message("StoRM - CUDD include dir: ${CUDD_INCLUDE_DIR}")
include_directories(${CUDD_INCLUDE_DIR})
include_directories(${CUDD_INCLUDE_DIR})

3
src/abstraction/StateSetAbstractor.cpp

@ -65,7 +65,6 @@ namespace storm {
template <storm::dd::DdType DdType, typename ValueType>
storm::dd::Bdd<DdType> StateSetAbstractor<DdType, ValueType>::getStateBdd(storm::solver::SmtSolver::ModelReference const& model) const {
STORM_LOG_TRACE("Building source state BDD.");
storm::dd::Bdd<DdType> result = this->getAbstractionInformation().getDdManager().getBddOne();
for (auto const& variableIndexPair : relevantPredicatesAndVariables) {
if (model.getBooleanValue(variableIndexPair.first)) {
@ -81,8 +80,6 @@ namespace storm {
void StateSetAbstractor<DdType, ValueType>::recomputeCachedBdd() {
// Now check whether we need to recompute the cached BDD.
std::set<uint_fast64_t> newRelevantPredicateIndices = localExpressionInformation.getRelatedExpressions(concretePredicateVariables);
STORM_LOG_TRACE("Found " << newRelevantPredicateIndices.size() << " relevant predicates in abstractor.");
// Since the number of relevant predicates is monotonic, we can simply check for the size here.
STORM_LOG_ASSERT(newRelevantPredicateIndices.size() >= relevantPredicatesAndVariables.size(), "Illegal size of relevant predicates.");
bool recomputeBdd = newRelevantPredicateIndices.size() > relevantPredicatesAndVariables.size();

11
src/abstraction/prism/AbstractCommand.cpp

@ -21,7 +21,7 @@ namespace storm {
namespace abstraction {
namespace prism {
template <storm::dd::DdType DdType, typename ValueType>
AbstractCommand<DdType, ValueType>::AbstractCommand(storm::prism::Command const& command, AbstractionInformation<DdType>& abstractionInformation, std::shared_ptr<storm::utility::solver::SmtSolverFactory> const& smtSolverFactory, bool guardIsPredicate) : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())), abstractionInformation(abstractionInformation), command(command), localExpressionInformation(abstractionInformation.getVariables()), evaluator(abstractionInformation.getExpressionManager()), relevantPredicatesAndVariables(), cachedDd(abstractionInformation.getDdManager().getBddZero(), 0, 0), decisionVariables(), guardIsPredicate(guardIsPredicate), abstractGuard(abstractionInformation.getDdManager().getBddZero()), bottomStateAbstractor(abstractionInformation, abstractionInformation.getExpressionVariables(), {!command.getGuardExpression()}, smtSolverFactory) {
AbstractCommand<DdType, ValueType>::AbstractCommand(storm::prism::Command const& command, AbstractionInformation<DdType>& abstractionInformation, std::shared_ptr<storm::utility::solver::SmtSolverFactory> const& smtSolverFactory, bool guardIsPredicate) : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())), abstractionInformation(abstractionInformation), command(command), localExpressionInformation(abstractionInformation.getVariables()), evaluator(abstractionInformation.getExpressionManager()), relevantPredicatesAndVariables(), cachedDd(abstractionInformation.getDdManager().getBddZero(), 0), decisionVariables(), guardIsPredicate(guardIsPredicate), abstractGuard(abstractionInformation.getDdManager().getBddZero()), bottomStateAbstractor(abstractionInformation, abstractionInformation.getExpressionVariables(), {!command.getGuardExpression()}, smtSolverFactory) {
// Make the second component of relevant predicates have the right size.
relevantPredicatesAndVariables.second.resize(command.getNumberOfUpdates());
@ -109,8 +109,9 @@ namespace storm {
STORM_LOG_ASSERT(!sourceDistributionsPair.first.isZero(), "The source BDD must not be empty.");
STORM_LOG_ASSERT(!sourceDistributionsPair.second.empty(), "The distributions must not be empty.");
// We start with the distribution index of 1, becase 0 is reserved for a potential bottom choice.
uint_fast64_t distributionIndex = 1;
storm::dd::Bdd<DdType> allDistributions = this->getAbstractionInformation().getDdManager().getBddZero();
uint_fast64_t distributionIndex = 0;
for (auto const& distribution : sourceDistributionsPair.second) {
allDistributions |= distribution && this->getAbstractionInformation().encodePlayer2Choice(distributionIndex, numberOfVariablesNeeded);
++distributionIndex;
@ -126,7 +127,7 @@ namespace storm {
STORM_LOG_ASSERT(sourceToDistributionsMap.empty() || !resultBdd.isZero(), "The BDD must not be empty, if there were distributions.");
// Cache the result.
cachedDd = GameBddResult<DdType>(resultBdd, numberOfVariablesNeeded, maximalNumberOfChoices);
cachedDd = GameBddResult<DdType>(resultBdd, numberOfVariablesNeeded);
}
template <storm::dd::DdType DdType, typename ValueType>
@ -215,7 +216,6 @@ namespace storm {
template <storm::dd::DdType DdType, typename ValueType>
storm::dd::Bdd<DdType> AbstractCommand<DdType, ValueType>::getSourceStateBdd(storm::solver::SmtSolver::ModelReference const& model) const {
STORM_LOG_TRACE("Building source state BDD.");
storm::dd::Bdd<DdType> result = this->getAbstractionInformation().getDdManager().getBddOne();
for (auto const& variableIndexPair : relevantPredicatesAndVariables.first) {
if (model.getBooleanValue(variableIndexPair.first)) {
@ -231,7 +231,6 @@ namespace storm {
template <storm::dd::DdType DdType, typename ValueType>
storm::dd::Bdd<DdType> AbstractCommand<DdType, ValueType>::getDistributionBdd(storm::solver::SmtSolver::ModelReference const& model) const {
STORM_LOG_TRACE("Building distribution BDD.");
storm::dd::Bdd<DdType> result = this->getAbstractionInformation().getDdManager().getBddZero();
for (uint_fast64_t updateIndex = 0; updateIndex < command.get().getNumberOfUpdates(); ++updateIndex) {
@ -330,7 +329,7 @@ namespace storm {
result.states &= this->getAbstractionInformation().getBottomStateBdd(true, false);
// Add the command encoding and the next free player 2 encoding.
result.transitions &= this->getAbstractionInformation().encodePlayer1Choice(command.get().getGlobalIndex(), this->getAbstractionInformation().getPlayer1VariableCount()) && this->getAbstractionInformation().encodePlayer2Choice(cachedDd.nextFreePlayer2Index, numberOfPlayer2Variables) && this->getAbstractionInformation().encodeAux(0, 0, this->getAbstractionInformation().getAuxVariableCount());
result.transitions &= this->getAbstractionInformation().encodePlayer1Choice(command.get().getGlobalIndex(), this->getAbstractionInformation().getPlayer1VariableCount()) && this->getAbstractionInformation().encodePlayer2Choice(0, numberOfPlayer2Variables) && this->getAbstractionInformation().encodeAux(0, 0, this->getAbstractionInformation().getAuxVariableCount());
return result;
}

4
src/abstraction/prism/AbstractModule.cpp

@ -41,11 +41,9 @@ namespace storm {
// First, we retrieve the abstractions of all commands.
std::vector<GameBddResult<DdType>> commandDdsAndUsedOptionVariableCounts;
uint_fast64_t maximalNumberOfUsedOptionVariables = 0;
uint_fast64_t nextFreePlayer2Index = 0;
for (auto& command : commands) {
commandDdsAndUsedOptionVariableCounts.push_back(command.getAbstractBdd());
maximalNumberOfUsedOptionVariables = std::max(maximalNumberOfUsedOptionVariables, commandDdsAndUsedOptionVariableCounts.back().numberOfPlayer2Variables);
nextFreePlayer2Index = std::max(nextFreePlayer2Index, commandDdsAndUsedOptionVariableCounts.back().nextFreePlayer2Index);
}
// Then, we build the module BDD by adding the single command DDs. We need to make sure that all command
@ -54,7 +52,7 @@ namespace storm {
for (auto const& commandDd : commandDdsAndUsedOptionVariableCounts) {
result |= commandDd.bdd && this->getAbstractionInformation().getPlayer2ZeroCube(commandDd.numberOfPlayer2Variables, maximalNumberOfUsedOptionVariables);
}
return GameBddResult<DdType>(result, maximalNumberOfUsedOptionVariables, nextFreePlayer2Index);
return GameBddResult<DdType>(result, maximalNumberOfUsedOptionVariables);
}
template <storm::dd::DdType DdType, typename ValueType>

2
src/abstraction/prism/AbstractProgram.cpp

@ -180,7 +180,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).
newPredicate = abstractionInformation.getPredicateByIndex(predicateIndex).substitute(concreteCommand.getUpdate(updateIndex).getAsVariableToExpressionMap());
newPredicate = abstractionInformation.getPredicateByIndex(predicateIndex).substitute(concreteCommand.getUpdate(updateIndex).getAsVariableToExpressionMap()).simplify();
break;
}
}

4
src/abstraction/prism/GameBddResult.cpp

@ -5,12 +5,12 @@ namespace storm {
namespace prism {
template <storm::dd::DdType DdType>
GameBddResult<DdType>::GameBddResult() : bdd(), numberOfPlayer2Variables(0), nextFreePlayer2Index(0) {
GameBddResult<DdType>::GameBddResult() : bdd(), numberOfPlayer2Variables(0) {
// Intentionally left empty.
}
template <storm::dd::DdType DdType>
GameBddResult<DdType>::GameBddResult(storm::dd::Bdd<DdType> const& gameBdd, uint_fast64_t numberOfPlayer2Variables, uint_fast64_t nextFreePlayer2Index) : bdd(gameBdd), numberOfPlayer2Variables(numberOfPlayer2Variables), nextFreePlayer2Index(nextFreePlayer2Index) {
GameBddResult<DdType>::GameBddResult(storm::dd::Bdd<DdType> const& gameBdd, uint_fast64_t numberOfPlayer2Variables) : bdd(gameBdd), numberOfPlayer2Variables(numberOfPlayer2Variables) {
// Intentionally left empty.
}

3
src/abstraction/prism/GameBddResult.h

@ -9,11 +9,10 @@ namespace storm {
template <storm::dd::DdType DdType>
struct GameBddResult {
GameBddResult();
GameBddResult(storm::dd::Bdd<DdType> const& gameBdd, uint_fast64_t numberOfPlayer2Variables, uint_fast64_t nextFreePlayer2Index);
GameBddResult(storm::dd::Bdd<DdType> const& gameBdd, uint_fast64_t numberOfPlayer2Variables);
storm::dd::Bdd<DdType> bdd;
uint_fast64_t numberOfPlayer2Variables;
uint_fast64_t nextFreePlayer2Index;
};
}

80
src/modelchecker/abstraction/GameBasedMdpModelChecker.cpp

@ -195,18 +195,19 @@ namespace storm {
template<storm::dd::DdType Type, typename ValueType>
void refineAfterQualitativeCheck(storm::abstraction::prism::PrismMenuGameAbstractor<Type, ValueType>& abstractor, storm::abstraction::MenuGame<Type, ValueType> const& game, detail::GameProb01Result<Type> const& prob01, storm::dd::Bdd<Type> const& transitionMatrixBdd) {
storm::dd::Bdd<Type> transitionsInIntersection = (transitionMatrixBdd && prob01.min.first.getPlayer1Strategy() && prob01.min.first.getPlayer2Strategy() && prob01.max.second.getPlayer1Strategy() && prob01.max.second.getPlayer2Strategy()).existsAbstract(game.getNondeterminismVariables());
// First, we have to find the pivot state candidates. Start by constructing the reachable fragment of the
// state space *under both* strategy pairs.
storm::dd::Bdd<Type> pivotStates = storm::utility::dd::computeReachableStates(game.getInitialStates(), transitionsInIntersection, game.getRowVariables(), game.getColumnVariables());
// Then constrain this set by requiring that the two stratey pairs resolve the nondeterminism differently.
pivotStates &= (prob01.min.first.getPlayer1Strategy() && prob01.min.first.getPlayer2Strategy()).exclusiveOr(prob01.max.second.getPlayer1Strategy() && prob01.max.second.getPlayer2Strategy()).existsAbstract(game.getNondeterminismVariables());
// Build the fragment of states that is reachable by any combination of the player 1 and player 2 strategies.
storm::dd::Bdd<Type> reachableTransitions = prob01.min.first.getPlayer2Strategy() || prob01.max.second.getPlayer2Strategy();
reachableTransitions = (prob01.min.first.getPlayer1Strategy() && reachableTransitions) || (prob01.max.second.getPlayer1Strategy() && reachableTransitions);
reachableTransitions &= transitionMatrixBdd;
reachableTransitions = reachableTransitions.existsAbstract(game.getNondeterminismVariables());
storm::dd::Bdd<Type> pivotStates = storm::utility::dd::computeReachableStates(game.getInitialStates(), reachableTransitions, game.getRowVariables(), game.getColumnVariables());
// Then constrain these states by the requirement that for either the lower or upper player 1 choice the player 2 choices must be different.
pivotStates &= ((prob01.min.first.getPlayer1Strategy() || prob01.max.second.getPlayer1Strategy()) && (prob01.min.first.getPlayer2Strategy().exclusiveOr(prob01.max.second.getPlayer2Strategy()))).existsAbstract(game.getNondeterminismVariables());
STORM_LOG_ASSERT(!pivotStates.isZero(), "Unable to refine without pivot state candidates.");
// Now that we have the pivot state candidates, we need to pick one.
storm::dd::Bdd<Type> pivotState = pickPivotState<Type>(game.getInitialStates(), transitionsInIntersection, game.getRowVariables(), game.getColumnVariables(), pivotStates);
storm::dd::Bdd<Type> pivotState = pickPivotState<Type>(game.getInitialStates(), reachableTransitions, game.getRowVariables(), game.getColumnVariables(), pivotStates);
// Compute the lower and the upper choice for the pivot state.
std::set<storm::expressions::Variable> variablesToAbstract = game.getNondeterminismVariables();
@ -235,7 +236,22 @@ namespace storm {
}
template<storm::dd::DdType Type, typename ValueType>
storm::dd::Add<Type, ValueType> solveMaybeStates(storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::MenuGame<Type, ValueType> const& game, storm::dd::Bdd<Type> const& maybeStates, storm::dd::Bdd<Type> const& prob1States, boost::optional<storm::dd::Add<Type, ValueType>> startVector = boost::none) {
struct MaybeStateResult {
MaybeStateResult() = default;
MaybeStateResult(storm::dd::Add<Type, ValueType> const& values, storm::dd::Bdd<Type> const& player1Strategy, storm::dd::Bdd<Type> const& player2Strategy) : values(values), player1Strategy(player1Strategy), player2Strategy(player2Strategy) {
// Intentionally left empty.
}
storm::dd::Add<Type, ValueType> values;
storm::dd::Bdd<Type> player1Strategy;
storm::dd::Bdd<Type> player2Strategy;
};
template<storm::dd::DdType Type, typename ValueType>
MaybeStateResult<Type, ValueType> solveMaybeStates(storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::abstraction::MenuGame<Type, ValueType> const& game, storm::dd::Bdd<Type> const& maybeStates, storm::dd::Bdd<Type> const& prob1States, boost::optional<MaybeStateResult<Type, ValueType>> startInfo = boost::none) {
STORM_LOG_TRACE("Performing quantative solution step. Player 1: " << player1Direction << ", player 2: " << player2Direction << ".");
// Compute the ingredients of the equation system.
storm::dd::Add<Type, ValueType> maybeStatesAdd = maybeStates.template toAdd<ValueType>();
@ -248,14 +264,28 @@ namespace storm {
submatrix *= maybeStatesAdd.swapVariables(game.getRowColumnMetaVariablePairs());
// Cut the starting vector to the maybe states of this query.
if (startVector) {
startVector.get() *= maybeStatesAdd;
storm::dd::Add<Type, ValueType> startVector;
if (startInfo) {
startVector = startInfo.get().values * maybeStatesAdd;
} else {
startVector = game.getManager().template getAddZero<ValueType>();
}
// Create the solver and solve the equation system.
storm::utility::solver::SymbolicGameSolverFactory<Type, ValueType> solverFactory;
std::unique_ptr<storm::solver::SymbolicGameSolver<Type, ValueType>> solver = solverFactory.create(submatrix, maybeStates, game.getIllegalPlayer1Mask(), game.getIllegalPlayer2Mask(), game.getRowVariables(), game.getColumnVariables(), game.getRowColumnMetaVariablePairs(), game.getPlayer1Variables(), game.getPlayer2Variables());
return solver->solveGame(player1Direction, player2Direction, startVector ? startVector.get() : game.getManager().template getAddZero<ValueType>(), subvector);
solver->setGeneratePlayersStrategies(true);
auto values = solver->solveGame(player1Direction, player2Direction, startVector, subvector);
storm::dd::Bdd<Type> player1Strategy = solver->getPlayer1Strategy();
storm::dd::Bdd<Type> player2Strategy = solver->getPlayer2Strategy();
// If we were given a starting point, we fix the strategies now. That is, we only deviate from the
if (startInfo) {
player1Strategy = values.greater(startInfo.get().values).ite(player1Strategy, startInfo.get().player1Strategy);
player1Strategy = values.greater(startInfo.get().values).ite(player1Strategy, startInfo.get().player1Strategy);
}
return MaybeStateResult<Type, ValueType>(values, player1Strategy, player2Strategy);
}
template<storm::dd::DdType Type, typename ValueType>
@ -285,9 +315,8 @@ namespace storm {
}
storm::abstraction::prism::PrismMenuGameAbstractor<Type, ValueType> abstractor(preprocessedProgram, initialPredicates, smtSolverFactory);
for (uint_fast64_t iterations = 0; iterations < 10000; ++iterations) {
STORM_LOG_TRACE("Starting iteration " << iterations);
STORM_LOG_TRACE("Starting iteration " << iterations << ".");
abstractor.exportToDot("game" + std::to_string(iterations) + ".dot");
// 1. build initial abstraction based on the the constraint expression (if not 'true') and the target state expression.
@ -351,13 +380,16 @@ namespace storm {
storm::dd::Add<Type, ValueType> initialStatesAdd = game.getInitialStates().template toAdd<ValueType>();
ValueType minValue = (prob01.min.second.states && game.getInitialStates()) == game.getInitialStates() ? storm::utility::one<ValueType>() : storm::utility::zero<ValueType>();
MaybeStateResult<Type, ValueType> minMaybeStateResult;
if (!maybeMin.isZero()) {
minResult += solveMaybeStates(player1Direction, storm::OptimizationDirection::Minimize, game, maybeMin, prob01.min.second.states);
minMaybeStateResult = solveMaybeStates(player1Direction, storm::OptimizationDirection::Minimize, game, maybeMin, prob01.min.second.states);
minResult += minMaybeStateResult.values;
storm::dd::Add<Type, ValueType> initialStateMin = initialStatesAdd * minResult;
STORM_LOG_ASSERT(initialStateMin.getNonZeroCount() == 1, "Wrong number of results for initial states.");
// Here we can only require a non-zero count of *at most* one, because the result may actually be 0.
STORM_LOG_ASSERT(initialStateMin.getNonZeroCount() <= 1, "Wrong number of results for initial states.");
minValue = initialStateMin.getMax();
}
STORM_LOG_TRACE("Obtained quantitative lower bound " << minValue);
STORM_LOG_TRACE("Obtained quantitative lower bound " << minValue << ".");
// Check whether we can abort the computation because of the lower value.
result = checkForResultAfterQuantitativeCheck<ValueType>(checkTask, storm::OptimizationDirection::Minimize, minValue);
@ -366,13 +398,18 @@ namespace storm {
}
ValueType maxValue = (prob01.max.second.states && game.getInitialStates()) == game.getInitialStates() ? storm::utility::one<ValueType>() : storm::utility::zero<ValueType>();
MaybeStateResult<Type, ValueType> maxMaybeStateResult;
if (!maybeMax.isZero()) {
maxResult += solveMaybeStates(player1Direction, storm::OptimizationDirection::Maximize, game, maybeMax, prob01.max.second.states, boost::optional<storm::dd::Add<Type, ValueType>>(minResult));
// FIXME: fix strategy: only change if improved.
maxMaybeStateResult = solveMaybeStates(player1Direction, storm::OptimizationDirection::Maximize, game, maybeMax, prob01.max.second.states, boost::optional<MaybeStateResult<Type, ValueType>>(minMaybeStateResult));
maxResult += maxMaybeStateResult.values;
storm::dd::Add<Type, ValueType> initialStateMax = (initialStatesAdd * maxResult);
// Unlike in the min-case, we can require a non-zero count of 1 here, because if the max was in
// fact 0, the result would be 0, which would have been detected earlier by the graph algorithms.
STORM_LOG_ASSERT(initialStateMax.getNonZeroCount() == 1, "Wrong number of results for initial states.");
maxValue = initialStateMax.getMax();
}
STORM_LOG_TRACE("Obtained quantitative upper bound " << minValue);
STORM_LOG_TRACE("Obtained quantitative upper bound " << minValue << ".");
// Check whether we can abort the computation because of the upper value.
result = checkForResultAfterQuantitativeCheck<ValueType>(checkTask, storm::OptimizationDirection::Maximize, maxValue);
@ -386,6 +423,9 @@ namespace storm {
if (result) {
return result;
}
// If we arrived at this point, it means that we have all qualitative and quantitative information
// about the game, but we could not yet answer the query. In this case, we need to refine.
STORM_LOG_ASSERT(false, "Quantiative refinement not yet there. :)");
}

5
src/models/symbolic/Model.cpp

@ -57,6 +57,11 @@ namespace storm {
return *manager;
}
template<storm::dd::DdType Type, typename ValueType>
std::shared_ptr<storm::dd::DdManager<Type>> const& Model<Type, ValueType>::getManagerAsSharedPointer() const {
return manager;
}
template<storm::dd::DdType Type, typename ValueType>
storm::dd::Bdd<Type> const& Model<Type, ValueType>::getReachableStates() const {
return reachableStates;

7
src/models/symbolic/Model.h

@ -109,6 +109,13 @@ namespace storm {
* @return The manager responsible for the DDs that represent this model.
*/
storm::dd::DdManager<Type>& getManager();
/*!
* Retrieves the manager responsible for the DDs that represent this model.
*
* @return The manager responsible for the DDs that represent this model.
*/
std::shared_ptr<storm::dd::DdManager<Type>> const& getManagerAsSharedPointer() const;
/*!
* Retrieves the reachable states of the model.

2
src/solver/OptimizationDirection.cpp

@ -31,7 +31,7 @@ namespace storm {
}
std::ostream& operator<<(std::ostream& out, OptimizationDirection d) {
return d == OptimizationDirection::Minimize ? out << "Minimize" : out << "Maximize";
return d == OptimizationDirection::Minimize ? out << "minimize" : out << "maximize";
}
}
}

61
src/solver/SymbolicGameSolver.cpp

@ -20,17 +20,27 @@ namespace storm {
}
template<storm::dd::DdType Type, typename ValueType>
SymbolicGameSolver<Type, ValueType>::SymbolicGameSolver(storm::dd::Add<Type, ValueType> const& A, storm::dd::Bdd<Type> const& allRows, storm::dd::Bdd<Type> const& illegalPlayer1Mask, storm::dd::Bdd<Type> const& illegalPlayer2Mask, std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, std::vector<std::pair<storm::expressions::Variable, storm::expressions::Variable>> const& rowColumnMetaVariablePairs, std::set<storm::expressions::Variable> const& player1Variables, std::set<storm::expressions::Variable> const& player2Variables, double precision, uint_fast64_t maximalNumberOfIterations, bool relative) : AbstractGameSolver(precision, maximalNumberOfIterations, relative), A(A), allRows(allRows), illegalPlayer1Mask(illegalPlayer1Mask.template toAdd<ValueType>()), illegalPlayer2Mask(illegalPlayer2Mask.template toAdd<ValueType>()), rowMetaVariables(rowMetaVariables), columnMetaVariables(columnMetaVariables), rowColumnMetaVariablePairs(rowColumnMetaVariablePairs), player1Variables(player1Variables), player2Variables(player2Variables), generatePlayer1Strategy(false), generatePlayer2Strategy(false) {
SymbolicGameSolver<Type, ValueType>::SymbolicGameSolver(storm::dd::Add<Type, ValueType> const& A, storm::dd::Bdd<Type> const& allRows, storm::dd::Bdd<Type> const& illegalPlayer1Mask, storm::dd::Bdd<Type> const& illegalPlayer2Mask, std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, std::vector<std::pair<storm::expressions::Variable, storm::expressions::Variable>> const& rowColumnMetaVariablePairs, std::set<storm::expressions::Variable> const& player1Variables, std::set<storm::expressions::Variable> const& player2Variables, double precision, uint_fast64_t maximalNumberOfIterations, bool relative) : AbstractGameSolver(precision, maximalNumberOfIterations, relative), A(A), allRows(allRows), illegalPlayer1Mask(illegalPlayer1Mask.ite(A.getDdManager().getConstant(storm::utility::infinity<ValueType>()), A.getDdManager().template getAddZero<ValueType>())), illegalPlayer2Mask(illegalPlayer2Mask.ite(A.getDdManager().getConstant(storm::utility::infinity<ValueType>()), A.getDdManager().template getAddZero<ValueType>())), rowMetaVariables(rowMetaVariables), columnMetaVariables(columnMetaVariables), rowColumnMetaVariablePairs(rowColumnMetaVariablePairs), player1Variables(player1Variables), player2Variables(player2Variables), generatePlayer1Strategy(false), generatePlayer2Strategy(false) {
// Intentionally left empty.
}
template<storm::dd::DdType Type, typename ValueType>
storm::dd::Add<Type, ValueType> SymbolicGameSolver<Type, ValueType>::solveGame(OptimizationDirection player1Goal, OptimizationDirection player2Goal, storm::dd::Add<Type, ValueType> const& x, storm::dd::Add<Type, ValueType> const& b) const {
storm::dd::Add<Type, ValueType> SymbolicGameSolver<Type, ValueType>::solveGame(OptimizationDirection player1Goal, OptimizationDirection player2Goal, storm::dd::Add<Type, ValueType> const& x, storm::dd::Add<Type, ValueType> const& b) {
// Set up the environment.
storm::dd::Add<Type, ValueType> xCopy = x;
uint_fast64_t iterations = 0;
bool converged = false;
// Prepare some data storage in case we need to generate strategies.
if (generatePlayer1Strategy) {
player1Strategy = A.getDdManager().getBddZero();
}
boost::optional<storm::dd::Add<Type, ValueType>> previousPlayer2Values;
if (generatePlayer2Strategy) {
previousPlayer2Values = A.getDdManager().template getAddZero<ValueType>();
player2Strategy = A.getDdManager().getBddZero();
}
do {
// Compute tmp = A * x + b.
storm::dd::Add<Type, ValueType> xCopyAsColumn = xCopy.swapVariables(this->rowColumnMetaVariablePairs);
@ -39,15 +49,50 @@ namespace storm {
// Now abstract from player 2 and player 1 variables.
if (player2Goal == storm::OptimizationDirection::Maximize) {
tmp = tmp.maxAbstract(this->player2Variables);
storm::dd::Add<Type, ValueType> newValues = tmp.maxAbstract(this->player2Variables);
if (generatePlayer2Strategy) {
// Update only the choices that strictly improved the value.
storm::dd::Bdd<Type> maxChoices = tmp.maxAbstractRepresentative(this->player2Variables);
player2Strategy = newValues.greater(previousPlayer2Values.get()).ite(maxChoices, player2Strategy.get());
previousPlayer2Values = newValues;
}
tmp = newValues;
} else {
tmp = (tmp + illegalPlayer2Mask).minAbstract(this->player2Variables);
tmp = (tmp + illegalPlayer2Mask);
storm::dd::Add<Type, ValueType> newValues = tmp.minAbstract(this->player2Variables);
if (generatePlayer2Strategy) {
player2Strategy = tmp.minAbstractRepresentative(this->player2Variables);
}
tmp = newValues;
}
if (player1Goal == storm::OptimizationDirection::Maximize) {
tmp = tmp.maxAbstract(this->player1Variables);
tmp.exportToDot("pl1_val_" + std::to_string(iterations) + ".dot");
storm::dd::Add<Type, ValueType> newValues = tmp.maxAbstract(this->player1Variables);
newValues.exportToDot("pl1_valabs_" + std::to_string(iterations) + ".dot");
if (generatePlayer1Strategy) {
// Update only the choices that strictly improved the value.
storm::dd::Bdd<Type> maxChoices = tmp.maxAbstractRepresentative(this->player1Variables);
maxChoices.template toAdd<ValueType>().exportToDot("pl1_choices_" + std::to_string(iterations) + ".dot");
player1Strategy = newValues.greater(xCopy).ite(maxChoices, player1Strategy.get());
player1Strategy.get().template toAdd<ValueType>().exportToDot("pl1_" + std::to_string(iterations) + ".dot");
}
tmp = newValues;
} else {
tmp = (tmp + illegalPlayer1Mask).minAbstract(this->player1Variables);
tmp = (tmp + illegalPlayer1Mask);
storm::dd::Add<Type, ValueType> newValues = tmp.minAbstract(this->player1Variables);
if (generatePlayer1Strategy) {
player1Strategy = tmp.minAbstractRepresentative(this->player1Variables);
}
tmp = newValues;
}
// Now check if the process already converged within our precision.
@ -75,7 +120,7 @@ namespace storm {
}
template<storm::dd::DdType Type, typename ValueType>
void SymbolicGameSolver<Type, ValueType>::setGeneratePlayerStrategies(bool value) {
void SymbolicGameSolver<Type, ValueType>::setGeneratePlayersStrategies(bool value) {
setGeneratePlayer1Strategy(value);
setGeneratePlayer2Strategy(value);
}

4
src/solver/SymbolicGameSolver.h

@ -66,12 +66,12 @@ namespace storm {
* @param b The vector to add after matrix-vector multiplication.
* @return The solution vector.
*/
virtual storm::dd::Add<Type, ValueType> solveGame(OptimizationDirection player1Goal, OptimizationDirection player2Goal, storm::dd::Add<Type, ValueType> const& x, storm::dd::Add<Type, ValueType> const& b) const;
virtual storm::dd::Add<Type, ValueType> solveGame(OptimizationDirection player1Goal, OptimizationDirection player2Goal, storm::dd::Add<Type, ValueType> const& x, storm::dd::Add<Type, ValueType> const& b);
// Setters that enable the generation of the players' strategies.
void setGeneratePlayer1Strategy(bool value);
void setGeneratePlayer2Strategy(bool value);
void setGeneratePlayerStrategies(bool value);
void setGeneratePlayersStrategies(bool value);
// Getters to retrieve the players' strategies. Only legal if they were generated.
storm::dd::Bdd<Type> const& getPlayer1Strategy() const;

6
src/storage/dd/cudd/InternalCuddAdd.cpp

@ -149,8 +149,7 @@ namespace storm {
template<typename ValueType>
InternalBdd<DdType::CUDD> InternalAdd<DdType::CUDD, ValueType>::minAbstractRepresentative(InternalBdd<DdType::CUDD> const& cube) const {
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Not yet implemented: minAbstractRepresentative");
//return InternalAdd<DdType::CUDD, ValueType>(ddManager, this->getCuddAdd().MinAbstractRepresentative(cube.toAdd<ValueType>().getCuddAdd()));
return InternalBdd<DdType::CUDD>(ddManager, this->getCuddAdd().MinAbstractRepresentative(cube.toAdd<ValueType>().getCuddAdd()));
}
template<typename ValueType>
@ -165,8 +164,7 @@ namespace storm {
template<typename ValueType>
InternalBdd<DdType::CUDD> InternalAdd<DdType::CUDD, ValueType>::maxAbstractRepresentative(InternalBdd<DdType::CUDD> const& cube) const {
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Not yet implemented: maxAbstractRepresentative");
//return InternalAdd<DdType::CUDD, ValueType>(ddManager, this->getCuddAdd().MinAbstractRepresentative(cube.toAdd<ValueType>().getCuddAdd()));
return InternalBdd<DdType::CUDD>(ddManager, this->getCuddAdd().MaxAbstractRepresentative(cube.toAdd<ValueType>().getCuddAdd()));
}
template<typename ValueType>

Loading…
Cancel
Save