Browse Source

added state-set abstractor as a means to, e.g., derive the initial states BDD

Former-commit-id: 34257c7196
tempestpy_adaptions
dehnert 9 years ago
parent
commit
75632f932d
  1. 25
      src/storage/prism/menu_games/AbstractCommand.cpp
  2. 29
      src/storage/prism/menu_games/AbstractCommand.h
  3. 4
      src/storage/prism/menu_games/AbstractModule.cpp
  4. 8
      src/storage/prism/menu_games/AbstractModule.h
  5. 50
      src/storage/prism/menu_games/AbstractProgram.cpp
  6. 11
      src/storage/prism/menu_games/AbstractProgram.h
  7. 17
      src/storage/prism/menu_games/AbstractionDdInformation.cpp
  8. 11
      src/storage/prism/menu_games/AbstractionDdInformation.h
  9. 2
      src/storage/prism/menu_games/AbstractionExpressionInformation.cpp
  10. 9
      src/storage/prism/menu_games/AbstractionExpressionInformation.h
  11. 114
      src/storage/prism/menu_games/StateSetAbstractor.cpp
  12. 117
      src/storage/prism/menu_games/StateSetAbstractor.h
  13. 7
      src/storage/prism/menu_games/VariablePartition.cpp

25
src/storage/prism/menu_games/AbstractCommand.cpp

@ -11,13 +11,14 @@
#include "src/storage/prism/Command.h" #include "src/storage/prism/Command.h"
#include "src/storage/prism/Update.h" #include "src/storage/prism/Update.h"
#include "src/utility/solver.h"
#include "src/utility/macros.h" #include "src/utility/macros.h"
namespace storm { namespace storm {
namespace prism { namespace prism {
namespace menu_games { namespace menu_games {
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>
AbstractCommand<DdType, ValueType>::AbstractCommand(storm::prism::Command const& command, AbstractionExpressionInformation const& expressionInformation, AbstractionDdInformation<DdType, ValueType> const& ddInformation, storm::utility::solver::SmtSolverFactory const& smtSolverFactory) : smtSolver(smtSolverFactory.create(expressionInformation.expressionManager)), expressionInformation(expressionInformation), ddInformation(ddInformation), command(command), variablePartition(expressionInformation.variables), relevantPredicatesAndVariables(), cachedDd(std::make_pair(ddInformation.manager->getBddZero(), 0)), decisionVariables() {
AbstractCommand<DdType, ValueType>::AbstractCommand(storm::prism::Command const& command, AbstractionExpressionInformation const& expressionInformation, AbstractionDdInformation<DdType, ValueType> const& ddInformation, storm::utility::solver::SmtSolverFactory const& smtSolverFactory) : smtSolver(smtSolverFactory.create(expressionInformation.manager)), expressionInformation(expressionInformation), ddInformation(ddInformation), command(command), variablePartition(expressionInformation.variables), relevantPredicatesAndVariables(), cachedDd(std::make_pair(ddInformation.manager->getBddZero(), 0)), decisionVariables() {
// Make the second component of relevant predicates have the right size. // Make the second component of relevant predicates have the right size.
relevantPredicatesAndVariables.second.resize(command.getNumberOfUpdates()); relevantPredicatesAndVariables.second.resize(command.getNumberOfUpdates());
@ -98,7 +99,7 @@ namespace storm {
resultBdd &= computeMissingSourceStateIdentities(); resultBdd &= computeMissingSourceStateIdentities();
resultBdd &= ddInformation.manager->getEncoding(ddInformation.commandDdVariable, command.get().getGlobalIndex()); resultBdd &= ddInformation.manager->getEncoding(ddInformation.commandDdVariable, command.get().getGlobalIndex());
// Cache the result before returning it.
// Cache the result.
cachedDd = std::make_pair(resultBdd, numberOfVariablesNeeded); cachedDd = std::make_pair(resultBdd, numberOfVariablesNeeded);
} }
@ -158,26 +159,10 @@ namespace storm {
return false; return false;
} }
template <storm::dd::DdType DdType, typename ValueType>
std::vector<std::pair<storm::expressions::Variable, uint_fast64_t>> AbstractCommand<DdType, ValueType>::declareNewVariables(std::vector<std::pair<storm::expressions::Variable, uint_fast64_t>> const& oldRelevantPredicates, std::set<uint_fast64_t> const& newRelevantPredicates) {
std::vector<std::pair<storm::expressions::Variable, uint_fast64_t>> result;
auto oldIt = oldRelevantPredicates.begin();
auto oldIte = oldRelevantPredicates.end();
for (auto newIt = newRelevantPredicates.begin(), newIte = newRelevantPredicates.end(); newIt != newIte; ++newIt) {
// If the new variable does not yet exist as a source variable, we create it now.
if (oldIt == oldIte || oldIt->second != *newIt) {
result.push_back(std::make_pair(expressionInformation.expressionManager.declareFreshBooleanVariable(), *newIt));
}
}
return result;
}
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>
void AbstractCommand<DdType, ValueType>::addMissingPredicates(std::pair<std::set<uint_fast64_t>, std::vector<std::set<uint_fast64_t>>> const& newRelevantPredicates) { void AbstractCommand<DdType, ValueType>::addMissingPredicates(std::pair<std::set<uint_fast64_t>, std::vector<std::set<uint_fast64_t>>> const& newRelevantPredicates) {
// Determine and add new relevant source predicates. // Determine and add new relevant source predicates.
std::vector<std::pair<storm::expressions::Variable, uint_fast64_t>> newSourceVariables = declareNewVariables(relevantPredicatesAndVariables.first, newRelevantPredicates.first);
std::vector<std::pair<storm::expressions::Variable, uint_fast64_t>> newSourceVariables = AbstractionDdInformation<DdType, ValueType>::declareNewVariables(expressionInformation.manager, relevantPredicatesAndVariables.first, newRelevantPredicates.first);
for (auto const& element : newSourceVariables) { for (auto const& element : newSourceVariables) {
smtSolver->add(storm::expressions::iff(element.first, expressionInformation.predicates[element.second])); smtSolver->add(storm::expressions::iff(element.first, expressionInformation.predicates[element.second]));
decisionVariables.push_back(element.first); decisionVariables.push_back(element.first);
@ -189,7 +174,7 @@ namespace storm {
// Do the same for every update. // Do the same for every update.
for (uint_fast64_t index = 0; index < command.get().getNumberOfUpdates(); ++index) { for (uint_fast64_t index = 0; index < command.get().getNumberOfUpdates(); ++index) {
std::vector<std::pair<storm::expressions::Variable, uint_fast64_t>> newSuccessorVariables = declareNewVariables(relevantPredicatesAndVariables.second[index], newRelevantPredicates.second[index]);
std::vector<std::pair<storm::expressions::Variable, uint_fast64_t>> newSuccessorVariables = AbstractionDdInformation<DdType, ValueType>::declareNewVariables(expressionInformation.manager, relevantPredicatesAndVariables.second[index], newRelevantPredicates.second[index]);
for (auto const& element : newSuccessorVariables) { for (auto const& element : newSuccessorVariables) {
smtSolver->add(storm::expressions::iff(element.first, expressionInformation.predicates[element.second].substitute(command.get().getUpdate(index).getAsVariableToExpressionMap()))); smtSolver->add(storm::expressions::iff(element.first, expressionInformation.predicates[element.second].substitute(command.get().getUpdate(index).getAsVariableToExpressionMap())));
decisionVariables.push_back(element.first); decisionVariables.push_back(element.first);

29
src/storage/prism/menu_games/AbstractCommand.h

@ -12,9 +12,22 @@
#include "src/storage/expressions/Expression.h" #include "src/storage/expressions/Expression.h"
#include "src/solver/SmtSolver.h" #include "src/solver/SmtSolver.h"
#include "src/utility/solver.h"
namespace storm { namespace storm {
namespace utility {
namespace solver {
class SmtSolverFactory;
}
}
namespace dd {
template <storm::dd::DdType DdType>
class Bdd;
template <storm::dd::DdType DdType>
class Add;
}
namespace prism { namespace prism {
// Forward-declare concrete command and assignment classes. // Forward-declare concrete command and assignment classes.
class Command; class Command;
@ -22,9 +35,9 @@ namespace storm {
namespace menu_games { namespace menu_games {
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>
class AbstractionDdInformation;
struct AbstractionDdInformation;
class AbstractionExpressionInformation;
struct AbstractionExpressionInformation;
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>
class AbstractCommand { class AbstractCommand {
@ -86,15 +99,7 @@ namespace storm {
* @param newRelevantPredicates The new relevant predicates. * @param newRelevantPredicates The new relevant predicates.
*/ */
bool relevantPredicatesChanged(std::pair<std::set<uint_fast64_t>, std::vector<std::set<uint_fast64_t>>> const& newRelevantPredicates) const; bool relevantPredicatesChanged(std::pair<std::set<uint_fast64_t>, std::vector<std::set<uint_fast64_t>>> const& newRelevantPredicates) const;
/*!
* Declares variables for the predicates that were added.
*
* @param oldRelevantPredicates The old relevant predicates (and the corresponding variables).
* @return Pairs of variable and predicate (indices) for the new relevant predicates.
*/
std::vector<std::pair<storm::expressions::Variable, uint_fast64_t>> declareNewVariables(std::vector<std::pair<storm::expressions::Variable, uint_fast64_t>> const& oldRelevantPredicates, std::set<uint_fast64_t> const& newRelevantPredicates);
/*! /*!
* Takes the new relevant predicates and creates the appropriate variables and assertions for the ones * Takes the new relevant predicates and creates the appropriate variables and assertions for the ones
* that are currently missing. * that are currently missing.

4
src/storage/prism/menu_games/AbstractModule.cpp

@ -29,7 +29,7 @@ namespace storm {
} }
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>
storm::dd::Bdd<DdType> AbstractModule<DdType, ValueType>::getAbstractBdd() {
std::pair<storm::dd::Bdd<DdType>, uint_fast64_t> AbstractModule<DdType, ValueType>::getAbstractBdd() {
// First, we retrieve the abstractions of all commands. // First, we retrieve the abstractions of all commands.
std::vector<std::pair<storm::dd::Bdd<DdType>, uint_fast64_t>> commandDdsAndUsedOptionVariableCounts; std::vector<std::pair<storm::dd::Bdd<DdType>, uint_fast64_t>> commandDdsAndUsedOptionVariableCounts;
uint_fast64_t maximalNumberOfUsedOptionVariables = 0; uint_fast64_t maximalNumberOfUsedOptionVariables = 0;
@ -44,7 +44,7 @@ namespace storm {
for (auto const& commandDd : commandDdsAndUsedOptionVariableCounts) { for (auto const& commandDd : commandDdsAndUsedOptionVariableCounts) {
result |= commandDd.first && ddInformation.getMissingOptionVariableCube(commandDd.second, maximalNumberOfUsedOptionVariables); result |= commandDd.first && ddInformation.getMissingOptionVariableCube(commandDd.second, maximalNumberOfUsedOptionVariables);
} }
return result;
return std::make_pair(result, maximalNumberOfUsedOptionVariables);
} }
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>

8
src/storage/prism/menu_games/AbstractModule.h

@ -16,9 +16,9 @@ namespace storm {
namespace menu_games { namespace menu_games {
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>
class AbstractionDdInformation;
struct AbstractionDdInformation;
class AbstractionExpressionInformation;
struct AbstractionExpressionInformation;
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>
class AbstractModule { class AbstractModule {
@ -43,9 +43,9 @@ namespace storm {
/*! /*!
* Computes the abstraction of the module wrt. to the current set of predicates. * Computes the abstraction of the module wrt. to the current set of predicates.
* *
* @return The abstraction of the module in the form of a BDD.
* @return The abstraction of the module in the form of a BDD together with how many option variables were used.
*/ */
storm::dd::Bdd<DdType> getAbstractBdd();
std::pair<storm::dd::Bdd<DdType>, uint_fast64_t> getAbstractBdd();
/*! /*!
* Retrieves an ADD that maps the encodings of commands and their updates to their probabilities. * Retrieves an ADD that maps the encodings of commands and their updates to their probabilities.

50
src/storage/prism/menu_games/AbstractProgram.cpp

@ -14,7 +14,7 @@ namespace storm {
namespace menu_games { namespace menu_games {
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>
AbstractProgram<DdType, ValueType>::AbstractProgram(storm::expressions::ExpressionManager& expressionManager, storm::prism::Program const& program, std::vector<storm::expressions::Expression> const& initialPredicates, std::unique_ptr<storm::utility::solver::SmtSolverFactory>&& smtSolverFactory, bool addAllGuards) : smtSolverFactory(std::move(smtSolverFactory)), ddInformation(std::make_shared<storm::dd::DdManager<DdType>>()), expressionInformation(expressionManager, initialPredicates, program.getAllExpressionVariables(), program.getAllRangeExpressions()), modules(), program(program) {
AbstractProgram<DdType, ValueType>::AbstractProgram(storm::expressions::ExpressionManager& expressionManager, storm::prism::Program const& program, std::vector<storm::expressions::Expression> const& initialPredicates, std::unique_ptr<storm::utility::solver::SmtSolverFactory>&& smtSolverFactory, bool addAllGuards) : smtSolverFactory(std::move(smtSolverFactory)), ddInformation(std::make_shared<storm::dd::DdManager<DdType>>()), expressionInformation(expressionManager, initialPredicates, program.getAllExpressionVariables(), program.getAllRangeExpressions()), modules(), program(program), initialStateAbstractor(expressionInformation, ddInformation, *this->smtSolverFactory) {
// For now, we assume that there is a single module. If the program has more than one module, it needs // 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. // to be flattened before the procedure.
@ -59,14 +59,51 @@ namespace storm {
modules.emplace_back(module, expressionInformation, ddInformation, *this->smtSolverFactory); modules.emplace_back(module, expressionInformation, ddInformation, *this->smtSolverFactory);
} }
// Add the initial state expression to the initial state abstractor.
initialStateAbstractor.addPredicate(program.getInitialConstruct().getInitialStatesExpression());
// Finally, retrieve the command-update probability ADD, so we can multiply it with the abstraction BDD later. // Finally, retrieve the command-update probability ADD, so we can multiply it with the abstraction BDD later.
commandUpdateProbabilitiesAdd = modules.front().getCommandUpdateProbabilitiesAdd(); commandUpdateProbabilitiesAdd = modules.front().getCommandUpdateProbabilitiesAdd();
} }
template <storm::dd::DdType DdType, typename ValueType>
void AbstractProgram<DdType, ValueType>::refine(std::vector<storm::expressions::Expression> const& predicates) {
// Add the predicates to the global list of predicates.
uint_fast64_t firstNewPredicateIndex = expressionInformation.predicates.size();
expressionInformation.predicates.insert(expressionInformation.predicates.end(), predicates.begin(), predicates.end());
// Create a list of indices of the predicates, so we can refine the abstract modules and the state set abstractors.
std::vector<uint_fast64_t> newPredicateIndices;
for (uint_fast64_t index = firstNewPredicateIndex; expressionInformation.predicates.size(); ++index) {
newPredicateIndices.push_back(index);
}
// Refine all abstract modules.
for (auto& module : modules) {
module.refine(newPredicateIndices);
}
// Refine initial state abstractor.
initialStateAbstractor.refine(newPredicateIndices);
}
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>
storm::dd::Add<DdType> AbstractProgram<DdType, ValueType>::getAbstractAdd() { storm::dd::Add<DdType> AbstractProgram<DdType, ValueType>::getAbstractAdd() {
// As long as there is only one module, we build its game representation and return it.
return modules.front().getAbstractBdd().toAdd() * commandUpdateProbabilitiesAdd;
// As long as there is only one module, we only build its game representation.
std::pair<storm::dd::Bdd<DdType>, uint_fast64_t> gameBdd = modules.front().getAbstractBdd();
// Construct a set of all unnecessary variables, so we can abstract from it.
std::set<storm::expressions::Variable> variablesToAbstract = {ddInformation.commandDdVariable, ddInformation.updateDdVariable};
for (uint_fast64_t index = 0; index < gameBdd.second; ++index) {
variablesToAbstract.insert(ddInformation.optionDdVariables[index].first);
}
// Do a reachability analysis on the raw transition relation.
storm::dd::Bdd<DdType> transitionRelation = gameBdd.first.existsAbstract(variablesToAbstract);
storm::dd::Bdd<DdType> reachableStates = this->getReachableStates(initialStateAbstractor.getAbstractStates(), transitionRelation);
// Construct the final game by cutting away the transitions of unreachable states.
return (gameBdd.first && reachableStates).toAdd() * commandUpdateProbabilitiesAdd;
} }
template <storm::dd::DdType DdType, typename ValueType> template <storm::dd::DdType DdType, typename ValueType>
@ -74,9 +111,14 @@ namespace storm {
storm::dd::Bdd<storm::dd::DdType::CUDD> frontier = initialStates; storm::dd::Bdd<storm::dd::DdType::CUDD> frontier = initialStates;
storm::dd::Bdd<storm::dd::DdType::CUDD> reachableStates = initialStates; storm::dd::Bdd<storm::dd::DdType::CUDD> reachableStates = initialStates;
uint_fast64_t reachabilityIteration = 0;
while (!frontier.isZero()) { while (!frontier.isZero()) {
frontier = frontier.andExists(transitionRelation, ddInformation.successorVariables);
++reachabilityIteration;
frontier = frontier.andExists(transitionRelation, ddInformation.sourceVariables);
frontier = frontier.swapVariables(ddInformation.predicateDdVariables);
frontier &= !reachableStates;
reachableStates |= frontier; reachableStates |= frontier;
STORM_LOG_TRACE("Iteration " << reachabilityIteration << " of reachability analysis.");
} }
return reachableStates; return reachableStates;

11
src/storage/prism/menu_games/AbstractProgram.h

@ -5,6 +5,7 @@
#include "src/storage/prism/menu_games/AbstractionDdInformation.h" #include "src/storage/prism/menu_games/AbstractionDdInformation.h"
#include "src/storage/prism/menu_games/AbstractionExpressionInformation.h" #include "src/storage/prism/menu_games/AbstractionExpressionInformation.h"
#include "src/storage/prism/menu_games/StateSetAbstractor.h"
#include "src/storage/prism/menu_games/AbstractModule.h" #include "src/storage/prism/menu_games/AbstractModule.h"
#include "src/storage/expressions/Expression.h" #include "src/storage/expressions/Expression.h"
@ -43,6 +44,13 @@ namespace storm {
*/ */
storm::dd::Add<DdType> getAbstractAdd(); storm::dd::Add<DdType> getAbstractAdd();
/*!
* Refines the abstract module with the given predicates.
*
* @param predicates The new predicates.
*/
void refine(std::vector<storm::expressions::Expression> const& predicates);
private: private:
/*! /*!
* Computes the reachable states of the transition relation. * Computes the reachable states of the transition relation.
@ -69,6 +77,9 @@ namespace storm {
// The concrete program this abstract program refers to. // The concrete program this abstract program refers to.
std::reference_wrapper<Program const> program; std::reference_wrapper<Program const> program;
// A state-set abstractor used to determine the initial states of the abstraction.
StateSetAbstractor<DdType, ValueType> initialStateAbstractor;
// An ADD characterizing the probabilities of commands and their updates. // An ADD characterizing the probabilities of commands and their updates.
storm::dd::Add<DdType> commandUpdateProbabilitiesAdd; storm::dd::Add<DdType> commandUpdateProbabilitiesAdd;
}; };

17
src/storage/prism/menu_games/AbstractionDdInformation.cpp

@ -2,6 +2,7 @@
#include <sstream> #include <sstream>
#include "src/storage/expressions/ExpressionManager.h"
#include "src/storage/expressions/Expression.h" #include "src/storage/expressions/Expression.h"
#include "src/storage/dd/CuddDdManager.h" #include "src/storage/dd/CuddDdManager.h"
@ -54,6 +55,22 @@ namespace storm {
return result; return result;
} }
template <storm::dd::DdType DdType, typename ValueType>
std::vector<std::pair<storm::expressions::Variable, uint_fast64_t>> AbstractionDdInformation<DdType, ValueType>::declareNewVariables(storm::expressions::ExpressionManager& manager, std::vector<std::pair<storm::expressions::Variable, uint_fast64_t>> const& oldRelevantPredicates, std::set<uint_fast64_t> const& newRelevantPredicates) {
std::vector<std::pair<storm::expressions::Variable, uint_fast64_t>> result;
auto oldIt = oldRelevantPredicates.begin();
auto oldIte = oldRelevantPredicates.end();
for (auto newIt = newRelevantPredicates.begin(), newIte = newRelevantPredicates.end(); newIt != newIte; ++newIt) {
// If the new variable does not yet exist as a source variable, we create it now.
if (oldIt == oldIte || oldIt->second != *newIt) {
result.push_back(std::make_pair(manager.declareFreshBooleanVariable(), *newIt));
}
}
return result;
}
template struct AbstractionDdInformation<storm::dd::DdType::CUDD, double>; template struct AbstractionDdInformation<storm::dd::DdType::CUDD, double>;
} }

11
src/storage/prism/menu_games/AbstractionDdInformation.h

@ -60,6 +60,17 @@ namespace storm {
*/ */
storm::dd::Bdd<DdType> getMissingOptionVariableCube(uint_fast64_t lastUsed, uint_fast64_t lastToBe) const; storm::dd::Bdd<DdType> getMissingOptionVariableCube(uint_fast64_t lastUsed, uint_fast64_t lastToBe) const;
/*!
* Examines the old and new relevant predicates and declares decision variables for the missing relevant
* predicates.
*
* @param manager The manager in which to declare the decision variable.
* @param oldRelevantPredicates The previously relevant predicates.
* @param newRelevantPredicates The new relevant predicates.
* @return Pairs of decision variables and their index for the missing predicates.
*/
static std::vector<std::pair<storm::expressions::Variable, uint_fast64_t>> declareNewVariables(storm::expressions::ExpressionManager& manager, std::vector<std::pair<storm::expressions::Variable, uint_fast64_t>> const& oldRelevantPredicates, std::set<uint_fast64_t> const& newRelevantPredicates);
// The manager responsible for the DDs. // The manager responsible for the DDs.
std::shared_ptr<storm::dd::DdManager<DdType>> manager; std::shared_ptr<storm::dd::DdManager<DdType>> manager;

2
src/storage/prism/menu_games/AbstractionExpressionInformation.cpp

@ -7,7 +7,7 @@ namespace storm {
namespace prism { namespace prism {
namespace menu_games { namespace menu_games {
AbstractionExpressionInformation::AbstractionExpressionInformation(storm::expressions::ExpressionManager& expressionManager, std::vector<storm::expressions::Expression> const& predicates, std::set<storm::expressions::Variable> const& variables, std::vector<storm::expressions::Expression> const& rangeExpressions) : expressionManager(expressionManager), predicates(predicates), variables(variables), rangeExpressions(rangeExpressions) {
AbstractionExpressionInformation::AbstractionExpressionInformation(storm::expressions::ExpressionManager& manager, std::vector<storm::expressions::Expression> const& predicates, std::set<storm::expressions::Variable> const& variables, std::vector<storm::expressions::Expression> const& rangeExpressions) : manager(manager), predicates(predicates), variables(variables), rangeExpressions(rangeExpressions) {
// Intentionally left empty. // Intentionally left empty.
} }

9
src/storage/prism/menu_games/AbstractionExpressionInformation.h

@ -19,12 +19,15 @@ namespace storm {
/*! /*!
* Creates an expression information object with the given expression manager. * Creates an expression information object with the given expression manager.
* *
* @param expressionManager The expression manager to use.
* @param manager The expression manager to use.
* @param predicates The initial set of predicates.
* @param variables The variables.
* @param rangeExpressions A set of expressions that enforce the variable bounds.
*/ */
AbstractionExpressionInformation(storm::expressions::ExpressionManager& expressionManager, std::vector<storm::expressions::Expression> const& predicates = std::vector<storm::expressions::Expression>(), std::set<storm::expressions::Variable> const& variables = std::set<storm::expressions::Variable>(), std::vector<storm::expressions::Expression> const& rangeExpressions = std::vector<storm::expressions::Expression>());
AbstractionExpressionInformation(storm::expressions::ExpressionManager& manager, std::vector<storm::expressions::Expression> const& predicates = std::vector<storm::expressions::Expression>(), std::set<storm::expressions::Variable> const& variables = std::set<storm::expressions::Variable>(), std::vector<storm::expressions::Expression> const& rangeExpressions = std::vector<storm::expressions::Expression>());
// The manager responsible for the expressions of the program and the SMT solvers. // The manager responsible for the expressions of the program and the SMT solvers.
storm::expressions::ExpressionManager& expressionManager;
storm::expressions::ExpressionManager& manager;
// The current set of predicates used in the abstraction. // The current set of predicates used in the abstraction.
std::vector<storm::expressions::Expression> predicates; std::vector<storm::expressions::Expression> predicates;

114
src/storage/prism/menu_games/StateSetAbstractor.cpp

@ -0,0 +1,114 @@
#include "src/storage/prism/menu_games/StateSetAbstractor.h"
#include "src/storage/prism/menu_games/AbstractionExpressionInformation.h"
#include "src/storage/prism/menu_games/AbstractionDdInformation.h"
#include "src/storage/dd/CuddDdManager.h"
#include "src/utility/macros.h"
#include "src/utility/solver.h"
namespace storm {
namespace prism {
namespace menu_games {
template <storm::dd::DdType DdType, typename ValueType>
StateSetAbstractor<DdType, ValueType>::StateSetAbstractor(AbstractionExpressionInformation const& expressionInformation, AbstractionDdInformation<DdType, ValueType> const& ddInformation, storm::utility::solver::SmtSolverFactory const& smtSolverFactory) : smtSolver(smtSolverFactory.create(expressionInformation.manager)), expressionInformation(expressionInformation), ddInformation(ddInformation), variablePartition(expressionInformation.variables), relevantPredicatesAndVariables(), concretePredicateVariables(), cachedBdd(ddInformation.manager->getBddZero()) {
// Assert all range expressions to enforce legal variable values.
for (auto const& rangeExpression : expressionInformation.rangeExpressions) {
smtSolver->add(rangeExpression);
}
// Refine the command based on all initial predicates.
std::vector<uint_fast64_t> allPredicateIndices(expressionInformation.predicates.size());
for (auto index = 0; index < expressionInformation.predicates.size(); ++index) {
allPredicateIndices[index] = index;
}
this->refine(allPredicateIndices);
}
template <storm::dd::DdType DdType, typename ValueType>
void StateSetAbstractor<DdType, ValueType>::addPredicate(storm::expressions::Expression const& predicate) {
smtSolver->add(predicate);
// Extract the variables of the predicate, so we know which variables were used when abstracting.
std::set<storm::expressions::Variable> usedVariables = predicate.getVariables();
concretePredicateVariables.insert(usedVariables.begin(), usedVariables.end());
variablePartition.relate(usedVariables);
// Since the new predicate might have changed the abstractions, we need to recompute it.
this->refine();
}
template <storm::dd::DdType DdType, typename ValueType>
void StateSetAbstractor<DdType, ValueType>::addMissingPredicates(std::set<uint_fast64_t> const& newRelevantPredicateIndices) {
std::vector<std::pair<storm::expressions::Variable, uint_fast64_t>> newPredicateVariables = AbstractionDdInformation<DdType, ValueType>::declareNewVariables(expressionInformation.manager, relevantPredicatesAndVariables, newRelevantPredicateIndices);
for (auto const& element : newPredicateVariables) {
smtSolver->add(storm::expressions::iff(element.first, expressionInformation.predicates[element.second]));
decisionVariables.push_back(element.first);
}
relevantPredicatesAndVariables.insert(relevantPredicatesAndVariables.end(), newPredicateVariables.begin(), newPredicateVariables.end());
std::sort(relevantPredicatesAndVariables.begin(), relevantPredicatesAndVariables.end(), [] (std::pair<storm::expressions::Variable, uint_fast64_t> const& firstPair, std::pair<storm::expressions::Variable, uint_fast64_t> const& secondPair) { return firstPair.second < secondPair.second; } );
}
template <storm::dd::DdType DdType, typename ValueType>
void StateSetAbstractor<DdType, ValueType>::refine(std::vector<uint_fast64_t> const& newPredicates) {
// Make the partition aware of the new predicates, which may make more predicates relevant to the abstraction.
for (auto const& predicateIndex : newPredicates) {
variablePartition.addExpression(expressionInformation.predicates[predicateIndex]);
}
// Now check whether we need to recompute the cached BDD.
std::set<uint_fast64_t> newRelevantPredicateIndices = variablePartition.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 recomputeDd = newRelevantPredicateIndices.size() > relevantPredicatesAndVariables.size();
if (recomputeDd) {
// If we need to recompute the BDD, we start by introducing decision variables and the corresponding
// constraints in the SMT problem.
addMissingPredicates(newRelevantPredicateIndices);
// Finally recompute the cached BDD.
this->recomputeCachedBdd();
}
}
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 = ddInformation.manager->getBddOne();
for (auto const& variableIndexPair : relevantPredicatesAndVariables) {
if (model.getBooleanValue(variableIndexPair.first)) {
result &= ddInformation.predicateBdds[variableIndexPair.second].first;
} else {
result &= !ddInformation.predicateBdds[variableIndexPair.second].first;
}
}
return result;
}
template <storm::dd::DdType DdType, typename ValueType>
void StateSetAbstractor<DdType, ValueType>::recomputeCachedBdd() {
STORM_LOG_TRACE("Recomputing BDD for state set abstraction.");
storm::dd::Bdd<DdType> result = ddInformation.manager->getBddZero();
smtSolver->allSat(decisionVariables, [&result,this] (storm::solver::SmtSolver::ModelReference const& model) { result |= getStateBdd(model); return true; } );
cachedBdd = result;
}
template <storm::dd::DdType DdType, typename ValueType>
storm::dd::Bdd<DdType> StateSetAbstractor<DdType, ValueType>::getAbstractStates() const {
return cachedBdd;
}
template class StateSetAbstractor<storm::dd::DdType::CUDD, double>;
}
}
}

117
src/storage/prism/menu_games/StateSetAbstractor.h

@ -0,0 +1,117 @@
#ifndef STORM_STORAGE_PRISM_MENU_GAMES_STATESETABSTRACTOR_H_
#define STORM_STORAGE_PRISM_MENU_GAMES_STATESETABSTRACTOR_H_
#include <memory>
#include <set>
#include "src/storage/dd/DdType.h"
#include "src/solver/SmtSolver.h"
#include "src/storage/prism/menu_games/VariablePartition.h"
namespace storm {
namespace utility {
namespace solver {
class SmtSolverFactory;
}
}
namespace dd {
template <storm::dd::DdType DdType>
class Bdd;
template <storm::dd::DdType DdType>
class Add;
}
namespace prism {
namespace menu_games {
template <storm::dd::DdType DdType, typename ValueType>
class AbstractionDdInformation;
class AbstractionExpressionInformation;
template <storm::dd::DdType DdType, typename ValueType>
class StateSetAbstractor {
public:
/*!
* Creates a state set abstractor.
*
* @param expressionInformation The expression-related information including the manager and the predicates.
* @param ddInformation The DD-related information including the manager.
* @param smtSolverFactory A factory that can create new SMT solvers.
*/
StateSetAbstractor(AbstractionExpressionInformation const& expressionInformation, AbstractionDdInformation<DdType, ValueType> const& ddInformation, storm::utility::solver::SmtSolverFactory const& smtSolverFactory);
/*!
* Adds the given (concrete) predicate to the abstractor and therefore restricts the abstraction to
* abstract states that contain at least some states satisfying the predicate.
*/
void addPredicate(storm::expressions::Expression const& predicate);
/*!
* Refines the abstractor by making the given predicates new abstract predicates.
*
* @param newPredicateIndices The indices of the new predicates.
*/
void refine(std::vector<uint_fast64_t> const& newPredicateIndices = std::vector<uint_fast64_t>());
/*!
* Retrieves the set of abstract states matching all predicates added to this abstractor.
*
* @return The set of matching abstract states in the form of a BDD
*/
storm::dd::Bdd<DdType> getAbstractStates() const;
private:
/*!
* Creates decision variables and the corresponding constraints for the missing predicates.
*
* @param newRelevantPredicateIndices The set of all relevant predicate indices.
*/
void addMissingPredicates(std::set<uint_fast64_t> const& newRelevantPredicateIndices);
/*!
* Recomputes the cached BDD. This needs to be triggered if any relevant predicates change.
*/
void recomputeCachedBdd();
/*!
* Translates the given model to a state DD.
*
* @param model The model to translate.
* @return The state encoded as a DD.
*/
storm::dd::Bdd<DdType> getStateBdd(storm::solver::SmtSolver::ModelReference const& model) const;
// The SMT solver used for abstracting the set of states.
std::unique_ptr<storm::solver::SmtSolver> smtSolver;
// The expression-related information.
AbstractionExpressionInformation const& expressionInformation;
// The DD-related information.
AbstractionDdInformation<DdType, ValueType> const& ddInformation;
// The partition of the variables.
VariablePartition variablePartition;
// The set of relevant predicates and the corresponding decision variables.
std::vector<std::pair<storm::expressions::Variable, uint_fast64_t>> relevantPredicatesAndVariables;
// The set of all variables appearing in the concrete predicates.
std::set<storm::expressions::Variable> concretePredicateVariables;
// The set of all decision variables over which to perform the all-sat enumeration.
std::vector<storm::expressions::Variable> decisionVariables;
// The cached BDD representing the abstraction. This variable is written to in refinement steps (if work
// needed to be done).
storm::dd::Bdd<DdType> cachedBdd;
};
}
}
}
#endif /* STORM_STORAGE_PRISM_MENU_GAMES_STATESETABSTRACTOR_H_ */

7
src/storage/prism/menu_games/VariablePartition.cpp

@ -27,8 +27,13 @@ namespace storm {
for (auto const& variable : expressionVariables) { for (auto const& variable : expressionVariables) {
variableToExpressionsMapping[variable].insert(this->expressions.size()); variableToExpressionsMapping[variable].insert(this->expressions.size());
} }
// Add the expression to the block of the first variable. When relating the variables, the blocks will
// get merged (if necessary).
STORM_LOG_ASSERT(!expressionVariables.empty(), "Found no variables in expression.");
expressionBlocks[getBlockIndexOfVariable(*expressionVariables.begin())].insert(this->expressions.size());
// Add aexpression and relate all the appearing variables.
// Add expression and relate all the appearing variables.
this->expressions.push_back(expression); this->expressions.push_back(expression);
return this->relate(expressionVariables); return this->relate(expressionVariables);
} }

Loading…
Cancel
Save