Browse Source

more work on MDP bisimulation

main
dehnert 8 years ago
parent
commit
f3ebfaa90f
  1. 2
      src/storm/api/bisimulation.h
  2. 11
      src/storm/models/ModelBase.h
  3. 4
      src/storm/models/symbolic/Model.cpp
  4. 4
      src/storm/models/symbolic/Model.h
  5. 21
      src/storm/storage/dd/BisimulationDecomposition.cpp
  6. 6
      src/storm/storage/dd/BisimulationDecomposition.h
  7. 28
      src/storm/storage/dd/bisimulation/MdpPartitionRefiner.cpp
  8. 11
      src/storm/storage/dd/bisimulation/MdpPartitionRefiner.h
  9. 39
      src/storm/storage/dd/bisimulation/Partition.cpp
  10. 8
      src/storm/storage/dd/bisimulation/Partition.h
  11. 86
      src/storm/storage/dd/bisimulation/PartitionRefiner.cpp
  12. 4
      src/storm/storage/dd/bisimulation/PartitionRefiner.h
  13. 28
      src/storm/storage/dd/bisimulation/QuotientExtractor.cpp
  14. 11
      src/storm/storage/dd/bisimulation/QuotientExtractor.h
  15. 2
      src/storm/storage/dd/bisimulation/SignatureRefiner.cpp
  16. 9
      src/storm/storage/dd/bisimulation/SignatureRefiner.h

2
src/storm/api/bisimulation.h

@ -57,7 +57,7 @@ namespace storm {
template <storm::dd::DdType DdType, typename ValueType>
typename std::enable_if<DdType == storm::dd::DdType::Sylvan || std::is_same<ValueType, double>::value, std::shared_ptr<storm::models::Model<ValueType>>>::type performBisimulationMinimization(std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, storm::storage::BisimulationType const& bisimulationType = storm::storage::BisimulationType::Strong, storm::dd::bisimulation::SignatureMode const& mode = storm::dd::bisimulation::SignatureMode::Eager) {
STORM_LOG_THROW(model->isOfType(storm::models::ModelType::Dtmc) || model->isOfType(storm::models::ModelType::Ctmc), storm::exceptions::NotSupportedException, "Symbolic bisimulation minimization is currently only available for DTMCs and CTMCs.");
STORM_LOG_THROW(model->isOfType(storm::models::ModelType::Dtmc) || model->isOfType(storm::models::ModelType::Ctmc) || model->isOfType(storm::models::ModelType::Mdp), storm::exceptions::NotSupportedException, "Symbolic bisimulation minimization is currently only available for DTMCs and CTMCs.");
STORM_LOG_THROW(bisimulationType == storm::storage::BisimulationType::Strong, storm::exceptions::NotSupportedException, "Currently only strong bisimulation is supported.");
storm::dd::BisimulationDecomposition<DdType, ValueType> decomposition(*model, formulas, bisimulationType);

11
src/storm/models/ModelBase.h

@ -38,6 +38,17 @@ namespace storm {
return std::dynamic_pointer_cast<ModelType>(this->shared_from_this());
}
/*!
* Casts the model into the model type given by the template parameter.
*
* @return A shared pointer of the requested type that points to the model if the cast succeeded and a null
* pointer otherwise.
*/
template <typename ModelType>
std::shared_ptr<ModelType const> as() const {
return std::dynamic_pointer_cast<ModelType const>(this->shared_from_this());
}
/*!
* @brief Return the actual type of the model.
*

4
src/storm/models/symbolic/Model.cpp

@ -7,10 +7,6 @@
#include "storm/adapters/AddExpressionAdapter.h"
#include "storm/storage/dd/DdManager.h"
#include "storm/storage/dd/Add.h"
#include "storm/storage/dd/Bdd.h"
#include "storm/models/symbolic/StandardRewardModel.h"
#include "storm/utility/macros.h"

4
src/storm/models/symbolic/Model.h

@ -9,6 +9,7 @@
#include "storm/storage/expressions/Expression.h"
#include "storm/storage/expressions/Variable.h"
#include "storm/storage/dd/DdType.h"
#include "storm/storage/dd/Add.h"
#include "storm/storage/dd/Bdd.h"
#include "storm/models/Model.h"
#include "storm/utility/OsDetection.h"
@ -22,9 +23,6 @@ namespace storm {
template<storm::dd::DdType Type>
class Dd;
template<storm::dd::DdType Type, typename ValueType>
class Add;
template<storm::dd::DdType Type>
class DdManager;

21
src/storm/storage/dd/BisimulationDecomposition.cpp

@ -1,10 +1,12 @@
#include "storm/storage/dd/BisimulationDecomposition.h"
#include "storm/storage/dd/bisimulation/Partition.h"
#include "storm/storage/dd/bisimulation/PartitionRefiner.h"
#include "storm/storage/dd/bisimulation/MdpPartitionRefiner.h"
#include "storm/storage/dd/bisimulation/QuotientExtractor.h"
#include "storm/models/symbolic/Model.h"
#include "storm/models/symbolic/Mdp.h"
#include "storm/utility/macros.h"
#include "storm/exceptions/InvalidOperationException.h"
@ -16,17 +18,26 @@ namespace storm {
using namespace bisimulation;
template <storm::dd::DdType DdType, typename ValueType>
BisimulationDecomposition<DdType, ValueType>::BisimulationDecomposition(storm::models::symbolic::Model<DdType, ValueType> const& model, storm::storage::BisimulationType const& bisimulationType) : BisimulationDecomposition(model, bisimulation::Partition<DdType, ValueType>::create(model, bisimulationType)) {
std::unique_ptr<PartitionRefiner<DdType, ValueType>> createRefiner(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& initialPartition) {
if (model.isOfType(storm::models::ModelType::Mdp)) {
return std::make_unique<MdpPartitionRefiner<DdType, ValueType>>(*model.template as<storm::models::symbolic::Mdp<DdType, ValueType>>(), initialPartition);
} else {
return std::make_unique<PartitionRefiner<DdType, ValueType>>(model, initialPartition);
}
}
template <storm::dd::DdType DdType, typename ValueType>
BisimulationDecomposition<DdType, ValueType>::BisimulationDecomposition(storm::models::symbolic::Model<DdType, ValueType> const& model, storm::storage::BisimulationType const& bisimulationType) : model(model), preservationInformation(model, bisimulationType), refiner(createRefiner(model, Partition<DdType, ValueType>::create(model, bisimulationType, preservationInformation))) {
// Intentionally left empty.
}
template <storm::dd::DdType DdType, typename ValueType>
BisimulationDecomposition<DdType, ValueType>::BisimulationDecomposition(storm::models::symbolic::Model<DdType, ValueType> const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, storm::storage::BisimulationType const& bisimulationType) : BisimulationDecomposition(model, bisimulation::Partition<DdType, ValueType>::create(model, formulas, bisimulationType)) {
BisimulationDecomposition<DdType, ValueType>::BisimulationDecomposition(storm::models::symbolic::Model<DdType, ValueType> const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, storm::storage::BisimulationType const& bisimulationType) : model(model), preservationInformation(model, formulas, bisimulationType), refiner(createRefiner(model, Partition<DdType, ValueType>::create(model, bisimulationType, preservationInformation))) {
// Intentionally left empty.
}
template <storm::dd::DdType DdType, typename ValueType>
BisimulationDecomposition<DdType, ValueType>::BisimulationDecomposition(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& initialPartition) : model(model), refiner(std::make_unique<PartitionRefiner<DdType, ValueType>>(model, initialPartition)) {
BisimulationDecomposition<DdType, ValueType>::BisimulationDecomposition(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& initialPartition, bisimulation::PreservationInformation<DdType, ValueType> const& preservationInformation) : model(model), preservationInformation(preservationInformation), refiner(createRefiner(model, initialPartition)) {
STORM_LOG_THROW(!model.hasRewardModel(), storm::exceptions::NotSupportedException, "Symbolic bisimulation currently does not support preserving rewards.");
}
@ -61,7 +72,7 @@ namespace storm {
STORM_LOG_TRACE("Starting quotient extraction.");
QuotientExtractor<DdType, ValueType> extractor;
std::shared_ptr<storm::models::Model<ValueType>> quotient = extractor.extract(model, refiner->getStatePartition());
std::shared_ptr<storm::models::Model<ValueType>> quotient = extractor.extract(model, refiner->getStatePartition(), preservationInformation);
STORM_LOG_TRACE("Quotient extraction done.");
return quotient;

6
src/storm/storage/dd/BisimulationDecomposition.h

@ -6,6 +6,7 @@
#include "storm/storage/dd/DdType.h"
#include "storm/storage/bisimulation/BisimulationType.h"
#include "storm/storage/dd/bisimulation/SignatureMode.h"
#include "storm/storage/dd/bisimulation/PreservationInformation.h"
#include "storm/logic/Formula.h"
@ -34,7 +35,7 @@ namespace storm {
public:
BisimulationDecomposition(storm::models::symbolic::Model<DdType, ValueType> const& model, storm::storage::BisimulationType const& bisimulationType);
BisimulationDecomposition(storm::models::symbolic::Model<DdType, ValueType> const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, storm::storage::BisimulationType const& bisimulationType);
BisimulationDecomposition(storm::models::symbolic::Model<DdType, ValueType> const& model, bisimulation::Partition<DdType, ValueType> const& initialPartition);
BisimulationDecomposition(storm::models::symbolic::Model<DdType, ValueType> const& model, bisimulation::Partition<DdType, ValueType> const& initialPartition, bisimulation::PreservationInformation<DdType, ValueType> const& preservationInformation);
~BisimulationDecomposition();
@ -52,6 +53,9 @@ namespace storm {
// The model for which to compute the bisimulation decomposition.
storm::models::symbolic::Model<DdType, ValueType> const& model;
// The object capturing what is preserved.
bisimulation::PreservationInformation<DdType, ValueType> preservationInformation;
// The refiner to use.
std::unique_ptr<bisimulation::PartitionRefiner<DdType, ValueType>> refiner;
};

28
src/storm/storage/dd/bisimulation/MdpPartitionRefiner.cpp

@ -1,22 +1,30 @@
#include "storm/storage/dd/bisimulation/MdpPartitionRefiner.h"
#include "storm/models/symbolic/Mdp.h"
namespace storm {
namespace dd {
namespace bisimulation {
template<storm::dd::DdType DdType, typename ValueType>
MdpPartitionRefiner<DdType, ValueType>::MdpPartitionRefiner(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& initialStatePartition) : PartitionRefiner<DdType, ValueType>(model, initialStatePartition) {
// Start by initializing the choice signature refiner.
std::set<storm::expressions::Variable> choiceSignatureVariables;
std::set_union(model.getRowMetaVariables().begin(), model.getRowMetaVariables().end(), model.getNondeterminismVariables().begin(), model.getNondeterminismVariables().end(), std::inserter(choiceSignatureVariables, choiceSignatureVariables.begin()));
choiceSignatureRefiner = SignatureRefiner<DdType, ValueType>(model.getManager(), this->statePartition.getBlockVariable(), choiceSignatureVariables);
MdpPartitionRefiner<DdType, ValueType>::MdpPartitionRefiner(storm::models::symbolic::Mdp<DdType, ValueType> const& mdp, Partition<DdType, ValueType> const& initialStatePartition) : PartitionRefiner<DdType, ValueType>(mdp, initialStatePartition), choicePartition(Partition<DdType, ValueType>::createTrivialChoicePartition(mdp, initialStatePartition.getBlockVariables())) {
// Create dummy choice partition that is refined to the right result in the first call to refine.
// Initialize the choice signature refiner.
std::set<storm::expressions::Variable> choiceSignatureVariables;
std::set_union(mdp.getRowVariables().begin(), mdp.getRowVariables().end(), mdp.getNondeterminismVariables().begin(), mdp.getNondeterminismVariables().end(), std::inserter(choiceSignatureVariables, choiceSignatureVariables.begin()));
choiceSignatureRefiner = SignatureRefiner<DdType, ValueType>(mdp.getManager(), this->statePartition.getBlockVariable(), choiceSignatureVariables);
}
template<storm::dd::DdType DdType, typename ValueType>
bool MdpPartitionRefiner<DdType, ValueType>::refine(bisimulation::SignatureMode const& mode) {
// Magic here.
Partition<DdType, ValueType> newChoicePartition = this->internalRefine(choiceSignatureRefiner, choicePartition, mode);
if (newChoicePartition == choicePartition) {
this->status = Status::FixedPoint;
return false;
} else {
return PartitionRefiner<DdType, ValueType>::refine(mode);
}
}
template<storm::dd::DdType DdType, typename ValueType>
@ -24,6 +32,12 @@ namespace storm {
return choicePartition;
}
template class MdpPartitionRefiner<storm::dd::DdType::CUDD, double>;
template class MdpPartitionRefiner<storm::dd::DdType::Sylvan, double>;
template class MdpPartitionRefiner<storm::dd::DdType::Sylvan, storm::RationalNumber>;
template class MdpPartitionRefiner<storm::dd::DdType::Sylvan, storm::RationalFunction>;
}
}
}

11
src/storm/storage/dd/bisimulation/MdpPartitionRefiner.h

@ -3,13 +3,20 @@
#include "storm/storage/dd/bisimulation/PartitionRefiner.h"
namespace storm {
namespace models {
namespace symbolic {
template <storm::dd::DdType DdType, typename ValueType>
class Mdp;
}
}
namespace dd {
namespace bisimulation {
template <storm::dd::DdType DdType, typename ValueType>
class MdpPartitionRefiner : public PartitionRefiner<DdType, ValueType> {
public:
MdpPartitionRefiner(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& initialStatePartition);
MdpPartitionRefiner(storm::models::symbolic::Mdp<DdType, ValueType> const& mdp, Partition<DdType, ValueType> const& initialStatePartition);
/*!
* Refines the partition.
@ -17,7 +24,7 @@ namespace storm {
* @param mode The signature mode to use.
* @return False iff the partition is stable and no refinement was actually performed.
*/
bool refine(bisimulation::SignatureMode const& mode = bisimulation::SignatureMode::Eager);
virtual bool refine(bisimulation::SignatureMode const& mode = bisimulation::SignatureMode::Eager) override;
/*!
* Retrieves the current choice partition in the refinement process.

39
src/storm/storage/dd/bisimulation/Partition.cpp

@ -8,6 +8,8 @@
#include "storm/logic/AtomicExpressionFormula.h"
#include "storm/logic/AtomicLabelFormula.h"
#include "storm/models/symbolic/Mdp.h"
#include "storm/settings/SettingsManager.h"
#include "storm/settings/modules/BisimulationSettings.h"
@ -19,6 +21,11 @@ namespace storm {
namespace dd {
namespace bisimulation {
template<storm::dd::DdType DdType, typename ValueType>
Partition<DdType, ValueType>::Partition() : nextFreeBlockIndex(0) {
// Intentionally left empty.
}
template<storm::dd::DdType DdType, typename ValueType>
Partition<DdType, ValueType>::Partition(storm::dd::Add<DdType, ValueType> const& partitionAdd, std::pair<storm::expressions::Variable, storm::expressions::Variable> const& blockVariables, uint64_t nextFreeBlockIndex) : partition(partitionAdd), blockVariables(blockVariables), nextFreeBlockIndex(nextFreeBlockIndex) {
// Intentionally left empty.
@ -45,7 +52,7 @@ namespace storm {
}
template<storm::dd::DdType DdType, typename ValueType>
Partition<DdType, ValueType> Partition<DdType, ValueType>::create(storm::models::symbolic::Model<DdType, ValueType> const& model, storm::storage::BisimulationType const& bisimulationType, PreservationInformation const& preservationInformation) {
Partition<DdType, ValueType> Partition<DdType, ValueType>::create(storm::models::symbolic::Model<DdType, ValueType> const& model, storm::storage::BisimulationType const& bisimulationType, PreservationInformation<DdType, ValueType> const& preservationInformation) {
std::vector<storm::expressions::Expression> expressionVector;
for (auto const& expression : preservationInformation.getExpressions()) {
@ -57,7 +64,6 @@ namespace storm {
template<storm::dd::DdType DdType, typename ValueType>
Partition<DdType, ValueType> Partition<DdType, ValueType>::create(storm::models::symbolic::Model<DdType, ValueType> const& model, std::vector<storm::expressions::Expression> const& expressions, storm::storage::BisimulationType const& bisimulationType) {
STORM_LOG_THROW(bisimulationType == storm::storage::BisimulationType::Strong, storm::exceptions::NotSupportedException, "Currently only strong bisimulation is supported.");
storm::dd::DdManager<DdType>& manager = model.getManager();
@ -72,6 +78,13 @@ namespace storm {
auto const& ddMetaVariable = manager.getMetaVariable(metaVariable);
numberOfDdVariables += ddMetaVariable.getNumberOfDdVariables();
}
if (model.getType() == storm::models::ModelType::Mdp) {
auto mdp = model.template as<storm::models::symbolic::Mdp<DdType, ValueType>>();
for (auto const& metaVariable : mdp->getNondeterminismVariables()) {
auto const& ddMetaVariable = manager.getMetaVariable(metaVariable);
numberOfDdVariables += ddMetaVariable.getNumberOfDdVariables();
}
}
std::pair<storm::expressions::Variable, storm::expressions::Variable> blockVariables = createBlockVariables(manager, numberOfDdVariables);
std::pair<storm::dd::Bdd<DdType>, uint64_t> partitionBddAndBlockCount = createPartitionBdd(manager, model, stateSets, blockVariables.first);
@ -84,6 +97,18 @@ namespace storm {
}
}
template<storm::dd::DdType DdType, typename ValueType>
Partition<DdType, ValueType> Partition<DdType, ValueType>::createTrivialChoicePartition(storm::models::symbolic::NondeterministicModel<DdType, ValueType> const& model, std::pair<storm::expressions::Variable, storm::expressions::Variable> const& blockVariables) {
storm::dd::Bdd<DdType> choicePartitionBdd = !model.getIllegalSuccessorMask() && model.getManager().getEncoding(blockVariables.first, 0, false);
// Store the partition as an ADD only in the case of CUDD.
if (DdType == storm::dd::DdType::CUDD) {
return Partition<DdType, ValueType>(choicePartitionBdd.template toAdd<ValueType>(), blockVariables, 1);
} else {
return Partition<DdType, ValueType>(choicePartitionBdd, blockVariables, 1);
}
}
template<storm::dd::DdType DdType, typename ValueType>
uint64_t Partition<DdType, ValueType>::getNumberOfStates() const {
return this->getStates().getNonZeroCount();
@ -123,6 +148,11 @@ namespace storm {
return boost::get<storm::dd::Bdd<DdType>>(partition);
}
template<storm::dd::DdType DdType, typename ValueType>
std::pair<storm::expressions::Variable, storm::expressions::Variable> const& Partition<DdType, ValueType>::getBlockVariables() const {
return blockVariables;
}
template<storm::dd::DdType DdType, typename ValueType>
storm::expressions::Variable const& Partition<DdType, ValueType>::getBlockVariable() const {
return blockVariables.first;
@ -147,11 +177,6 @@ namespace storm {
}
}
template<storm::dd::DdType DdType, typename ValueType>
PreservationInformation const& Partition<DdType, ValueType>::getPreservationInformation() const {
return *preservationInformation;
}
template<storm::dd::DdType DdType>
void enumerateBlocksRec(std::vector<storm::dd::Bdd<DdType>> const& stateSets, storm::dd::Bdd<DdType> const& currentStateSet, uint64_t offset, storm::expressions::Variable const& blockVariable, std::function<void (storm::dd::Bdd<DdType> const&)> const& callback) {
if (currentStateSet.isZero()) {

8
src/storm/storage/dd/bisimulation/Partition.h

@ -11,6 +11,7 @@
#include "storm/storage/bisimulation/BisimulationType.h"
#include "storm/models/symbolic/Model.h"
#include "storm/models/symbolic/NondeterministicModel.h"
namespace storm {
namespace logic {
@ -20,19 +21,21 @@ namespace storm {
namespace dd {
namespace bisimulation {
template<storm::dd::DdType DdType, typename ValueType>
class PreservationInformation;
template<storm::dd::DdType DdType, typename ValueType>
class Partition {
public:
Partition() = default;
Partition();
bool operator==(Partition<DdType, ValueType> const& other);
Partition<DdType, ValueType> replacePartition(storm::dd::Add<DdType, ValueType> const& newPartitionAdd, uint64_t nextFreeBlockIndex) const;
Partition<DdType, ValueType> replacePartition(storm::dd::Bdd<DdType> const& newPartitionBdd, uint64_t nextFreeBlockIndex) const;
static Partition create(storm::models::symbolic::Model<DdType, ValueType> const& model, storm::storage::BisimulationType const& bisimulationType, PreservationInformation const& preservationInformation);
static Partition create(storm::models::symbolic::Model<DdType, ValueType> const& model, storm::storage::BisimulationType const& bisimulationType, PreservationInformation<DdType, ValueType> const& preservationInformation);
static Partition createTrivialChoicePartition(storm::models::symbolic::NondeterministicModel<DdType, ValueType> const& model, std::pair<storm::expressions::Variable, storm::expressions::Variable> const& blockVariables);
uint64_t getNumberOfStates() const;
uint64_t getNumberOfBlocks() const;
@ -43,6 +46,7 @@ namespace storm {
storm::dd::Add<DdType, ValueType> const& asAdd() const;
storm::dd::Bdd<DdType> const& asBdd() const;
std::pair<storm::expressions::Variable, storm::expressions::Variable> const& getBlockVariables() const;
storm::expressions::Variable const& getBlockVariable() const;
storm::expressions::Variable const& getPrimedBlockVariable() const;

86
src/storm/storage/dd/bisimulation/PartitionRefiner.cpp

@ -10,44 +10,8 @@ namespace storm {
}
template <storm::dd::DdType DdType, typename ValueType>
bool PartitionRefiner<DdType, ValueType>::refine(bisimulation::SignatureMode const& mode) {
this->status = Status::InComputation;
this->signatureComputer.setSignatureMode(mode);
auto start = std::chrono::high_resolution_clock::now();
std::chrono::milliseconds::rep signatureTime = 0;
std::chrono::milliseconds::rep refinementTime = 0;
bool alreadyRefined = false;
uint64_t index = 0;
Partition<DdType, ValueType> newStatePartition;
auto signatureIterator = signatureComputer.compute(statePartition);
while (signatureIterator.hasNext() && !alreadyRefined) {
auto signatureStart = std::chrono::high_resolution_clock::now();
auto signature = signatureIterator.next();
auto signatureEnd = std::chrono::high_resolution_clock::now();
totalSignatureTime += (signatureEnd - signatureStart);
STORM_LOG_DEBUG("Signature " << refinements << "[" << index << "] DD has " << signature.getSignatureAdd().getNodeCount() << " nodes.");
auto refinementStart = std::chrono::high_resolution_clock::now();
newStatePartition = signatureRefiner.refine(statePartition, signature);
auto refinementEnd = std::chrono::high_resolution_clock::now();
totalRefinementTime += (refinementEnd - refinementStart);
signatureTime += std::chrono::duration_cast<std::chrono::milliseconds>(signatureEnd - signatureStart).count();
refinementTime = std::chrono::duration_cast<std::chrono::milliseconds>(refinementEnd - refinementStart).count();
// Potentially exit early in case we have refined the partition already.
if (newStatePartition.getNumberOfBlocks() > statePartition.getNumberOfBlocks()) {
alreadyRefined = true;
}
}
auto totalTimeInRefinement = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start).count();
++refinements;
STORM_LOG_DEBUG("Refinement " << refinements << " produced " << newStatePartition.getNumberOfBlocks() << " blocks and was completed in " << totalTimeInRefinement << "ms (signature: " << signatureTime << "ms, refinement: " << refinementTime << "ms).");
bool PartitionRefiner<DdType, ValueType>::refine(SignatureMode const& mode) {
Partition<DdType, ValueType> newStatePartition = this->internalRefine(signatureRefiner, statePartition, mode);
if (statePartition == newStatePartition) {
this->status = Status::FixedPoint;
return false;
@ -57,6 +21,52 @@ namespace storm {
}
}
template <storm::dd::DdType DdType, typename ValueType>
Partition<DdType, ValueType> PartitionRefiner<DdType, ValueType>::internalRefine(SignatureRefiner<DdType, ValueType>& signatureRefiner, Partition<DdType, ValueType> const& oldPartition, SignatureMode const& mode) {
auto start = std::chrono::high_resolution_clock::now();
if (this->status != Status::FixedPoint) {
this->status = Status::InComputation;
this->signatureComputer.setSignatureMode(mode);
std::chrono::milliseconds::rep signatureTime = 0;
std::chrono::milliseconds::rep refinementTime = 0;
bool refined = false;
uint64_t index = 0;
Partition<DdType, ValueType> newPartition;
auto signatureIterator = signatureComputer.compute(oldPartition);
while (signatureIterator.hasNext() && !refined) {
auto signatureStart = std::chrono::high_resolution_clock::now();
auto signature = signatureIterator.next();
auto signatureEnd = std::chrono::high_resolution_clock::now();
totalSignatureTime += (signatureEnd - signatureStart);
STORM_LOG_DEBUG("Signature " << refinements << "[" << index << "] DD has " << signature.getSignatureAdd().getNodeCount() << " nodes.");
auto refinementStart = std::chrono::high_resolution_clock::now();
newPartition = signatureRefiner.refine(statePartition, signature);
auto refinementEnd = std::chrono::high_resolution_clock::now();
totalRefinementTime += (refinementEnd - refinementStart);
signatureTime += std::chrono::duration_cast<std::chrono::milliseconds>(signatureEnd - signatureStart).count();
refinementTime = std::chrono::duration_cast<std::chrono::milliseconds>(refinementEnd - refinementStart).count();
// Potentially exit early in case we have refined the partition already.
if (newPartition.getNumberOfBlocks() > oldPartition.getNumberOfBlocks()) {
refined = true;
}
}
auto totalTimeInRefinement = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start).count();
++refinements;
STORM_LOG_DEBUG("Refinement " << refinements << " produced " << newPartition.getNumberOfBlocks() << " blocks and was completed in " << totalTimeInRefinement << "ms (signature: " << signatureTime << "ms, refinement: " << refinementTime << "ms).");
return newPartition;
} else {
return oldPartition;
}
}
template <storm::dd::DdType DdType, typename ValueType>
Partition<DdType, ValueType> const& PartitionRefiner<DdType, ValueType>::getStatePartition() const {
return statePartition;

4
src/storm/storage/dd/bisimulation/PartitionRefiner.h

@ -28,7 +28,7 @@ namespace storm {
* @param mode The signature mode to use.
* @return False iff the partition is stable and no refinement was actually performed.
*/
bool refine(bisimulation::SignatureMode const& mode = bisimulation::SignatureMode::Eager);
virtual bool refine(SignatureMode const& mode = SignatureMode::Eager);
/*!
* Retrieves the current state partition in the refinement process.
@ -41,6 +41,8 @@ namespace storm {
Status getStatus() const;
protected:
Partition<DdType, ValueType> internalRefine(SignatureRefiner<DdType, ValueType>& signatureRefiner, Partition<DdType, ValueType> const& oldPartition, SignatureMode const& mode = SignatureMode::Eager);
// The current status.
Status status;

28
src/storm/storage/dd/bisimulation/QuotientExtractor.cpp

@ -480,13 +480,13 @@ namespace storm {
}
template<storm::dd::DdType DdType, typename ValueType>
std::shared_ptr<storm::models::Model<ValueType>> QuotientExtractor<DdType, ValueType>::extract(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition) {
std::shared_ptr<storm::models::Model<ValueType>> QuotientExtractor<DdType, ValueType>::extract(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition, PreservationInformation<DdType, ValueType> const& preservationInformation) {
auto start = std::chrono::high_resolution_clock::now();
std::shared_ptr<storm::models::Model<ValueType>> result;
if (quotientFormat == storm::settings::modules::BisimulationSettings::QuotientFormat::Sparse) {
result = extractSparseQuotient(model, partition);
result = extractSparseQuotient(model, partition, preservationInformation);
} else {
result = extractDdQuotient(model, partition);
result = extractDdQuotient(model, partition, preservationInformation);
}
auto end = std::chrono::high_resolution_clock::now();
STORM_LOG_TRACE("Quotient extraction completed in " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms.");
@ -497,7 +497,7 @@ namespace storm {
}
template<storm::dd::DdType DdType, typename ValueType>
std::shared_ptr<storm::models::sparse::Model<ValueType>> QuotientExtractor<DdType, ValueType>::extractSparseQuotient(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition) {
std::shared_ptr<storm::models::sparse::Model<ValueType>> QuotientExtractor<DdType, ValueType>::extractSparseQuotient(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition, PreservationInformation<DdType, ValueType> const& preservationInformation) {
InternalSparseQuotientExtractor<DdType, ValueType> sparseExtractor(model.getManager(), model.getRowVariables());
auto states = partition.getStates().swapVariables(model.getRowColumnMetaVariablePairs());
@ -507,10 +507,10 @@ namespace storm {
quotientStateLabeling.addLabel("init", sparseExtractor.extractStates(model.getInitialStates(), partition));
quotientStateLabeling.addLabel("deadlock", sparseExtractor.extractStates(model.getDeadlockStates(), partition));
for (auto const& label : partition.getPreservationInformation().getLabels()) {
for (auto const& label : preservationInformation.getLabels()) {
quotientStateLabeling.addLabel(label, sparseExtractor.extractStates(model.getStates(label), partition));
}
for (auto const& expression : partition.getPreservationInformation().getExpressions()) {
for (auto const& expression : preservationInformation.getExpressions()) {
std::stringstream stream;
stream << expression;
std::string expressionAsString = stream.str();
@ -533,12 +533,12 @@ namespace storm {
}
template<storm::dd::DdType DdType, typename ValueType>
std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> QuotientExtractor<DdType, ValueType>::extractDdQuotient(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition) {
return extractQuotientUsingBlockVariables(model, partition);
std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> QuotientExtractor<DdType, ValueType>::extractDdQuotient(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition, PreservationInformation<DdType, ValueType> const& preservationInformation) {
return extractQuotientUsingBlockVariables(model, partition, preservationInformation);
}
template<storm::dd::DdType DdType, typename ValueType>
std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> QuotientExtractor<DdType, ValueType>::extractQuotientUsingBlockVariables(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition) {
std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> QuotientExtractor<DdType, ValueType>::extractQuotientUsingBlockVariables(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition, PreservationInformation<DdType, ValueType> const& preservationInformation) {
auto modelType = model.getType();
if (modelType == storm::models::ModelType::Dtmc || modelType == storm::models::ModelType::Ctmc) {
@ -568,10 +568,10 @@ namespace storm {
storm::dd::Bdd<DdType> deadlockStates = !quotientTransitionMatrixBdd.existsAbstract(blockPrimeVariableSet) && reachableStates;
std::map<std::string, storm::dd::Bdd<DdType>> preservedLabelBdds;
for (auto const& label : partition.getPreservationInformation().getLabels()) {
for (auto const& label : preservationInformation.getLabels()) {
preservedLabelBdds.emplace(label, (model.getStates(label) && partitionAsBddOverRowVariables).existsAbstract(model.getRowVariables()));
}
for (auto const& expression : partition.getPreservationInformation().getExpressions()) {
for (auto const& expression : preservationInformation.getExpressions()) {
std::stringstream stream;
stream << expression;
std::string expressionAsString = stream.str();
@ -597,7 +597,7 @@ namespace storm {
}
template<storm::dd::DdType DdType, typename ValueType>
std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> QuotientExtractor<DdType, ValueType>::extractQuotientUsingOriginalVariables(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition) {
std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> QuotientExtractor<DdType, ValueType>::extractQuotientUsingOriginalVariables(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition, PreservationInformation<DdType, ValueType> const& preservationInformation) {
auto modelType = model.getType();
if (modelType == storm::models::ModelType::Dtmc || modelType == storm::models::ModelType::Ctmc) {
@ -619,10 +619,10 @@ namespace storm {
storm::dd::Bdd<DdType> deadlockStates = !quotientTransitionMatrixBdd.existsAbstract(model.getColumnVariables()) && reachableStates;
std::map<std::string, storm::dd::Bdd<DdType>> preservedLabelBdds;
for (auto const& label : partition.getPreservationInformation().getLabels()) {
for (auto const& label : preservationInformation.getLabels()) {
preservedLabelBdds.emplace(label, (model.getStates(label) && partitionAsBddOverRowVariables).existsAbstract(model.getRowVariables()));
}
for (auto const& expression : partition.getPreservationInformation().getExpressions()) {
for (auto const& expression : preservationInformation.getExpressions()) {
std::stringstream stream;
stream << expression;
std::string expressionAsString = stream.str();

11
src/storm/storage/dd/bisimulation/QuotientExtractor.h

@ -8,6 +8,7 @@
#include "storm/models/sparse/Model.h"
#include "storm/storage/dd/bisimulation/Partition.h"
#include "storm/storage/dd/bisimulation/PreservationInformation.h"
#include "storm/settings/modules/BisimulationSettings.h"
@ -20,14 +21,14 @@ namespace storm {
public:
QuotientExtractor();
std::shared_ptr<storm::models::Model<ValueType>> extract(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition);
std::shared_ptr<storm::models::Model<ValueType>> extract(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition, PreservationInformation<DdType, ValueType> const& preservationInformation);
private:
std::shared_ptr<storm::models::sparse::Model<ValueType>> extractSparseQuotient(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition);
std::shared_ptr<storm::models::sparse::Model<ValueType>> extractSparseQuotient(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition, PreservationInformation<DdType, ValueType> const& preservationInformation);
std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> extractDdQuotient(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition);
std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> extractQuotientUsingBlockVariables(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition);
std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> extractQuotientUsingOriginalVariables(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition);
std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> extractDdQuotient(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition, PreservationInformation<DdType, ValueType> const& preservationInformation);
std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> extractQuotientUsingBlockVariables(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition, PreservationInformation<DdType, ValueType> const& preservationInformation);
std::shared_ptr<storm::models::symbolic::Model<DdType, ValueType>> extractQuotientUsingOriginalVariables(storm::models::symbolic::Model<DdType, ValueType> const& model, Partition<DdType, ValueType> const& partition, PreservationInformation<DdType, ValueType> const& preservationInformation);
bool useRepresentatives;
storm::settings::modules::BisimulationSettings::QuotientFormat quotientFormat;

2
src/storm/storage/dd/bisimulation/SignatureRefiner.cpp

@ -444,7 +444,7 @@ namespace storm {
};
template<storm::dd::DdType DdType, typename ValueType>
SignatureRefiner<DdType, ValueType>::SignatureRefiner(storm::dd::DdManager<DdType> const& manager, storm::expressions::Variable const& blockVariable, std::set<storm::expressions::Variable> const& stateVariables) : manager(manager), stateVariables(stateVariables) {
SignatureRefiner<DdType, ValueType>::SignatureRefiner(storm::dd::DdManager<DdType> const& manager, storm::expressions::Variable const& blockVariable, std::set<storm::expressions::Variable> const& stateVariables) : manager(&manager), stateVariables(stateVariables) {
uint64_t lastStateLevel = 0;
for (auto const& stateVariable : stateVariables) {
lastStateLevel = std::max(lastStateLevel, manager.getMetaVariable(stateVariable).getHighestLevel());

9
src/storm/storage/dd/bisimulation/SignatureRefiner.h

@ -1,5 +1,7 @@
#pragma once
#include <memory>
#include "storm/storage/dd/DdType.h"
#include "storm/storage/dd/bisimulation/Partition.h"
@ -15,6 +17,7 @@ namespace storm {
template<storm::dd::DdType DdType, typename ValueType>
class SignatureRefiner {
public:
SignatureRefiner() = default;
SignatureRefiner(storm::dd::DdManager<DdType> const& manager, storm::expressions::Variable const& blockVariable, std::set<storm::expressions::Variable> const& stateVariables);
~SignatureRefiner();
@ -23,13 +26,13 @@ namespace storm {
private:
// The manager responsible for the DDs.
storm::dd::DdManager<DdType> const& manager;
storm::dd::DdManager<DdType> const* manager;
// The variables encodin the states.
std::set<storm::expressions::Variable> const& stateVariables;
std::set<storm::expressions::Variable> stateVariables;
// The internal refiner.
std::unique_ptr<InternalSignatureRefiner<DdType, ValueType>> internalRefiner;
std::shared_ptr<InternalSignatureRefiner<DdType, ValueType>> internalRefiner;
};
}

Loading…
Cancel
Save