Browse Source

more work on refiners that deal with nondeterminism variables

main
dehnert 8 years ago
parent
commit
472eaffabc
  1. 255
      src/storm/storage/dd/bisimulation/SignatureRefiner.cpp
  2. 2
      src/storm/storage/dd/bisimulation/SignatureRefiner.h

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

@ -10,6 +10,7 @@
#include "storm/utility/macros.h" #include "storm/utility/macros.h"
#include "storm/exceptions/InvalidSettingsException.h" #include "storm/exceptions/InvalidSettingsException.h"
#include "storm/exceptions/NotImplementedException.h" #include "storm/exceptions/NotImplementedException.h"
#include "storm/exceptions/InvalidArgumentException.h"
#include "storm/settings/SettingsManager.h" #include "storm/settings/SettingsManager.h"
#include "storm/settings/modules/BisimulationSettings.h" #include "storm/settings/modules/BisimulationSettings.h"
@ -79,7 +80,7 @@ namespace storm {
template<typename ValueType> template<typename ValueType>
class InternalSignatureRefiner<storm::dd::DdType::CUDD, ValueType> { class InternalSignatureRefiner<storm::dd::DdType::CUDD, ValueType> {
public: public:
InternalSignatureRefiner(storm::dd::DdManager<storm::dd::DdType::CUDD> const& manager, storm::expressions::Variable const& blockVariable, uint64_t lastStateLevel) : manager(manager), internalDdManager(manager.getInternalDdManager()), blockVariable(blockVariable), lastStateLevel(lastStateLevel), nextFreeBlockIndex(0), numberOfRefinements(0), lastNumberOfVisitedNodes(10000), signatureCache(lastNumberOfVisitedNodes), reuseBlocksCache(lastNumberOfVisitedNodes) {
InternalSignatureRefiner(storm::dd::DdManager<storm::dd::DdType::CUDD> const& manager, storm::expressions::Variable const& blockVariable, storm::dd::Bdd<storm::dd::DdType::CUDD> const& nondeterminismVariables, storm::dd::Bdd<storm::dd::DdType::CUDD> const& nonBlockVariables) : manager(manager), internalDdManager(manager.getInternalDdManager()), blockVariable(blockVariable), nondeterminismVariables(nondeterminismVariables), nonBlockVariables(nonBlockVariables), nextFreeBlockIndex(0), numberOfRefinements(0), lastNumberOfVisitedNodes(10000), signatureCache(lastNumberOfVisitedNodes), reuseBlocksCache(lastNumberOfVisitedNodes) {
// Intentionally left empty. // Intentionally left empty.
} }
@ -98,17 +99,21 @@ namespace storm {
reuseBlocksCache.clear(); reuseBlocksCache.clear();
nextFreeBlockIndex = oldPartition.getNextFreeBlockIndex(); nextFreeBlockIndex = oldPartition.getNextFreeBlockIndex();
internalDdManager.debugCheck();
// Perform the actual recursive refinement step. // Perform the actual recursive refinement step.
DdNodePtr result = refine(oldPartition.asAdd().getInternalAdd().getCuddDdNode(), signatureAdd.getInternalAdd().getCuddDdNode());
DdNodePtr result = refine(oldPartition.asAdd().getInternalAdd().getCuddDdNode(), signatureAdd.getInternalAdd().getCuddDdNode(), nondeterminismVariables.getInternalBdd().getCuddDdNode(), nonBlockVariables.getInternalBdd().getCuddDdNode());
// Construct resulting ADD from the obtained node and the meta information. // Construct resulting ADD from the obtained node and the meta information.
storm::dd::InternalAdd<storm::dd::DdType::CUDD, ValueType> internalNewPartitionAdd(&internalDdManager, cudd::ADD(internalDdManager.getCuddManager(), result)); storm::dd::InternalAdd<storm::dd::DdType::CUDD, ValueType> internalNewPartitionAdd(&internalDdManager, cudd::ADD(internalDdManager.getCuddManager(), result));
storm::dd::Add<storm::dd::DdType::CUDD, ValueType> newPartitionAdd(oldPartition.asAdd().getDdManager(), internalNewPartitionAdd, oldPartition.asAdd().getContainedMetaVariables()); storm::dd::Add<storm::dd::DdType::CUDD, ValueType> newPartitionAdd(oldPartition.asAdd().getDdManager(), internalNewPartitionAdd, oldPartition.asAdd().getContainedMetaVariables());
internalDdManager.debugCheck();
return newPartitionAdd; return newPartitionAdd;
} }
DdNodePtr refine(DdNode* partitionNode, DdNode* signatureNode) {
DdNodePtr refine(DdNode* partitionNode, DdNode* signatureNode, DdNode* nondeterminismVariablesNode, DdNode* nonBlockVariablesNode) {
::DdManager* ddman = internalDdManager.getCuddManager().getManager(); ::DdManager* ddman = internalDdManager.getCuddManager().getManager();
// If we arrived at the constant zero node, then this was an illegal state encoding (we require // If we arrived at the constant zero node, then this was an illegal state encoding (we require
@ -118,44 +123,65 @@ namespace storm {
} }
// Check the cache whether we have seen the same node before. // Check the cache whether we have seen the same node before.
std::unique_ptr<DdNode*>& sigCacheEntrySmartPtr = signatureCache[std::make_pair(signatureNode, partitionNode)];
if (sigCacheEntrySmartPtr) {
auto nodePair = std::make_pair(signatureNode, partitionNode);
auto it = signatureCache.find(nodePair);
if (it != signatureCache.end()) {
// If so, we return the corresponding result. // If so, we return the corresponding result.
return *sigCacheEntrySmartPtr;
return it->second;
} }
DdNode** newEntryPtr = new DdNode*;
sigCacheEntrySmartPtr.reset(newEntryPtr);
// If there are no more non-block variables, we hit the signature.
if (Cudd_IsConstant(nonBlockVariablesNode)) {
// If this is the first time (in this traversal) that we encounter this signature, we check
// whether we can assign the old block number to it.
auto& reuseEntry = reuseBlocksCache[partitionNode];
if (!reuseEntry.isReused()) {
reuseEntry.setReused();
signatureCache[nodePair] = partitionNode;
return partitionNode;
} else {
DdNode* result;
{
storm::dd::Add<storm::dd::DdType::CUDD, ValueType> blockEncoding = manager.getEncoding(blockVariable, nextFreeBlockIndex, false).template toAdd<ValueType>();
++nextFreeBlockIndex;
result = blockEncoding.getInternalAdd().getCuddDdNode();
Cudd_Ref(result);
}
signatureCache[nodePair] = result;
Cudd_Deref(result);
return result;
}
} else {
// If there are more variables that belong to the non-block part of the encoding, we need to recursively descend.
// Determine the levels in the DDs.
uint64_t partitionVariable = Cudd_NodeReadIndex(partitionNode) - 1;
uint64_t signatureVariable = Cudd_NodeReadIndex(signatureNode);
uint64_t partitionLevel = Cudd_ReadPerm(ddman, partitionVariable);
uint64_t signatureLevel = Cudd_ReadPerm(ddman, signatureVariable);
uint64_t topLevel = std::min(partitionLevel, signatureLevel);
uint64_t topVariable = topLevel == partitionLevel ? partitionVariable : signatureVariable;
// Check whether the top variable is still within the state encoding.
if (topLevel <= lastStateLevel) {
// Determine subresults by recursive descent.
DdNodePtr thenResult;
DdNodePtr elseResult;
if (partitionLevel < signatureLevel) {
thenResult = refine(Cudd_T(partitionNode), signatureNode);
Cudd_Ref(thenResult);
elseResult = refine(Cudd_E(partitionNode), signatureNode);
Cudd_Ref(elseResult);
} else if (partitionLevel > signatureLevel) {
thenResult = refine(partitionNode, Cudd_T(signatureNode));
Cudd_Ref(thenResult);
elseResult = refine(partitionNode, Cudd_E(signatureNode));
Cudd_Ref(elseResult);
// Remember an offset that indicates whether the top variable is a nondeterminism variable or not.
short offset = 1;
if (!Cudd_IsConstant(nondeterminismVariablesNode) && Cudd_NodeReadIndex(nondeterminismVariablesNode) == Cudd_NodeReadIndex(nonBlockVariablesNode)) {
offset = 0;
}
DdNode* partitionThen;
DdNode* partitionElse;
if (Cudd_NodeReadIndex(partitionNode) - offset == Cudd_NodeReadIndex(nonBlockVariablesNode)) {
partitionThen = Cudd_T(partitionNode);
partitionElse = Cudd_E(partitionNode);
} else { } else {
thenResult = refine(Cudd_T(partitionNode), Cudd_T(signatureNode));
partitionThen = partitionElse = partitionNode;
}
DdNode* signatureThen;
DdNode* signatureElse;
if (Cudd_NodeReadIndex(signatureNode) == Cudd_NodeReadIndex(nonBlockVariablesNode)) {
signatureThen = Cudd_T(signatureNode);
signatureElse = Cudd_E(signatureNode);
} else {
signatureThen = signatureElse = signatureNode;
}
DdNode* thenResult = refine(partitionThen, signatureThen, offset == 0 ? Cudd_T(nondeterminismVariablesNode) : nondeterminismVariablesNode, Cudd_T(nonBlockVariablesNode));
Cudd_Ref(thenResult); Cudd_Ref(thenResult);
elseResult = refine(Cudd_E(partitionNode), Cudd_E(signatureNode));
DdNode* elseResult = refine(partitionElse, signatureElse, offset == 0 ? Cudd_T(nondeterminismVariablesNode) : nondeterminismVariablesNode, Cudd_T(nonBlockVariablesNode));
Cudd_Ref(elseResult); Cudd_Ref(elseResult);
}
DdNode* result; DdNode* result;
if (thenResult == elseResult) { if (thenResult == elseResult) {
@ -164,7 +190,7 @@ namespace storm {
result = thenResult; result = thenResult;
} else { } else {
// Get the node to connect the subresults. // Get the node to connect the subresults.
DdNode* var = Cudd_addIthVar(ddman, topVariable + 1);
DdNode* var = Cudd_addIthVar(ddman, Cudd_NodeReadIndex(nonBlockVariablesNode) + offset);
Cudd_Ref(var); Cudd_Ref(var);
result = Cudd_addIte(ddman, var, thenResult, elseResult); result = Cudd_addIte(ddman, var, thenResult, elseResult);
Cudd_Ref(result); Cudd_Ref(result);
@ -174,33 +200,10 @@ namespace storm {
} }
// Store the result in the cache. // Store the result in the cache.
*newEntryPtr = result;
signatureCache[nodePair] = result;
Cudd_Deref(result); Cudd_Deref(result);
return result; return result;
} else {
// If we are not within the state encoding any more, we hit the signature itself.
// If this is the first time (in this traversal) that we encounter this signature, we check
// whether we can assign the old block number to it.
auto& reuseEntry = reuseBlocksCache[partitionNode];
if (!reuseEntry.isReused()) {
reuseEntry.setReused();
*newEntryPtr = partitionNode;
return partitionNode;
} else {
DdNode* result;
{
storm::dd::Add<storm::dd::DdType::CUDD, ValueType> blockEncoding = manager.getEncoding(blockVariable, nextFreeBlockIndex, false).template toAdd<ValueType>();
++nextFreeBlockIndex;
result = blockEncoding.getInternalAdd().getCuddDdNode();
Cudd_Ref(result);
}
*newEntryPtr = result;
Cudd_Deref(result);
return result;
}
} }
} }
@ -208,8 +211,9 @@ namespace storm {
storm::dd::InternalDdManager<storm::dd::DdType::CUDD> const& internalDdManager; storm::dd::InternalDdManager<storm::dd::DdType::CUDD> const& internalDdManager;
storm::expressions::Variable const& blockVariable; storm::expressions::Variable const& blockVariable;
// The last level that belongs to the state encoding in the DDs.
uint64_t lastStateLevel;
// The cubes representing all non-block and all nondeterminism variables, respectively.
storm::dd::Bdd<storm::dd::DdType::CUDD> nondeterminismVariables;
storm::dd::Bdd<storm::dd::DdType::CUDD> nonBlockVariables;
// The current number of blocks of the new partition. // The current number of blocks of the new partition.
uint64_t nextFreeBlockIndex; uint64_t nextFreeBlockIndex;
@ -221,7 +225,7 @@ namespace storm {
uint64_t lastNumberOfVisitedNodes; uint64_t lastNumberOfVisitedNodes;
// The cache used to identify states with identical signature. // The cache used to identify states with identical signature.
spp::sparse_hash_map<std::pair<DdNode const*, DdNode const*>, std::unique_ptr<DdNode*>, CuddPointerPairHash> signatureCache;
spp::sparse_hash_map<std::pair<DdNode const*, DdNode const*>, DdNode*, CuddPointerPairHash> signatureCache;
// The cache used to identify which old block numbers have already been reused. // The cache used to identify which old block numbers have already been reused.
spp::sparse_hash_map<DdNode const*, ReuseWrapper> reuseBlocksCache; spp::sparse_hash_map<DdNode const*, ReuseWrapper> reuseBlocksCache;
@ -230,7 +234,7 @@ namespace storm {
template<typename ValueType> template<typename ValueType>
class InternalSignatureRefiner<storm::dd::DdType::Sylvan, ValueType> { class InternalSignatureRefiner<storm::dd::DdType::Sylvan, ValueType> {
public: public:
InternalSignatureRefiner(storm::dd::DdManager<storm::dd::DdType::Sylvan> const& manager, storm::expressions::Variable const& blockVariable, uint64_t lastStateLevel) : manager(manager), internalDdManager(manager.getInternalDdManager()), blockVariable(blockVariable), numberOfBlockVariables(manager.getMetaVariable(blockVariable).getNumberOfDdVariables()), blockCube(manager.getMetaVariable(blockVariable).getCube()), lastStateLevel(lastStateLevel), nextFreeBlockIndex(0), numberOfRefinements(0), signatureCache() {
InternalSignatureRefiner(storm::dd::DdManager<storm::dd::DdType::Sylvan> const& manager, storm::expressions::Variable const& blockVariable, storm::dd::Bdd<storm::dd::DdType::Sylvan> const& nondeterminismVariables, storm::dd::Bdd<storm::dd::DdType::Sylvan> const& nonBlockVariables) : manager(manager), internalDdManager(manager.getInternalDdManager()), blockVariable(blockVariable), nondeterminismVariables(nondeterminismVariables), nonBlockVariables(nonBlockVariables), numberOfBlockVariables(manager.getMetaVariable(blockVariable).getNumberOfDdVariables()), blockCube(manager.getMetaVariable(blockVariable).getCube()), nextFreeBlockIndex(0), numberOfRefinements(0), signatureCache() {
// Perform garbage collection to clean up stuff not needed anymore. // Perform garbage collection to clean up stuff not needed anymore.
LACE_ME; LACE_ME;
sylvan_gc(); sylvan_gc();
@ -270,7 +274,7 @@ namespace storm {
// totalMakeNodeTime = std::chrono::high_resolution_clock::duration(0); // totalMakeNodeTime = std::chrono::high_resolution_clock::duration(0);
// Perform the actual recursive refinement step. // Perform the actual recursive refinement step.
BDD result = refine(oldPartition.asBdd().getInternalBdd().getSylvanBdd().GetBDD(), signatureAdd.getInternalAdd().getSylvanMtbdd().GetMTBDD());
BDD result = refine(oldPartition.asBdd().getInternalBdd().getSylvanBdd().GetBDD(), signatureAdd.getInternalAdd().getSylvanMtbdd().GetMTBDD(), nondeterminismVariables.getInternalBdd().getSylvanBdd().GetBDD(), nonBlockVariables.getInternalBdd().getSylvanBdd().GetBDD());
// Construct resulting BDD from the obtained node and the meta information. // Construct resulting BDD from the obtained node and the meta information.
storm::dd::InternalBdd<storm::dd::DdType::Sylvan> internalNewPartitionBdd(&internalDdManager, sylvan::Bdd(result)); storm::dd::InternalBdd<storm::dd::DdType::Sylvan> internalNewPartitionBdd(&internalDdManager, sylvan::Bdd(result));
@ -300,7 +304,7 @@ namespace storm {
return sylvan_cube(blockCube.getInternalBdd().getSylvanBdd().GetBDD(), e.data()); return sylvan_cube(blockCube.getInternalBdd().getSylvanBdd().GetBDD(), e.data());
} }
BDD refine(BDD partitionNode, MTBDD signatureNode) {
BDD refine(BDD partitionNode, MTBDD signatureNode, BDD nondeterminismVariablesNode, BDD nonBlockVariablesNode) {
LACE_ME; LACE_ME;
// If we arrived at the constant zero node, then this was an illegal state encoding (we require // If we arrived at the constant zero node, then this was an illegal state encoding (we require
@ -332,54 +336,11 @@ namespace storm {
sylvan_gc_test(); sylvan_gc_test();
// Determine levels in the DDs.
// start = std::chrono::high_resolution_clock::now();
BDDVAR signatureVariable = sylvan_isconst(signatureNode) ? 0xffffffff : sylvan_var(signatureNode);
BDDVAR partitionVariable = sylvan_var(partitionNode) - 1;
BDDVAR topVariable = std::min(signatureVariable, partitionVariable);
// end = std::chrono::high_resolution_clock::now();
// totalLevelLookupTime += end - start;
// Check whether the top variable is still within the state encoding.
if (topVariable <= lastStateLevel) {
// Determine subresults by recursive descent.
BDD thenResult;
BDD elseResult;
if (partitionVariable < signatureVariable) {
elseResult = refine(sylvan_low(partitionNode), signatureNode);
thenResult = refine(sylvan_high(partitionNode), signatureNode);
} else if (partitionVariable > signatureVariable) {
elseResult = refine(partitionNode, sylvan_low(signatureNode));
thenResult = refine(partitionNode, sylvan_high(signatureNode));
} else {
elseResult = refine(sylvan_low(partitionNode), sylvan_low(signatureNode));
thenResult = refine(sylvan_high(partitionNode), sylvan_high(signatureNode));
}
BDD result;
if (thenResult == elseResult) {
result = thenResult;
} else {
// Get the node to connect the subresults.
// start = std::chrono::high_resolution_clock::now();
result = sylvan_makenode(topVariable + 1, elseResult, thenResult);
// end = std::chrono::high_resolution_clock::now();
// totalMakeNodeTime += end - start;
}
// Store the result in the cache.
// start = std::chrono::high_resolution_clock::now();
*newEntryPtr = result;
// end = std::chrono::high_resolution_clock::now();
// totalSignatureCacheStoreTime += end - start;
return result;
} else {
// If we are not within the state encoding any more, we hit the signature itself.
// If there are no more non-block variables, we hit the signature.
if (sylvan_isconst(nonBlockVariablesNode)) {
// If this is the first time (in this traversal) that we encounter this signature, we check // If this is the first time (in this traversal) that we encounter this signature, we check
// whether we can assign the old block number to it. // whether we can assign the old block number to it.
// start = std::chrono::high_resolution_clock::now(); // start = std::chrono::high_resolution_clock::now();
auto& reuseBlockEntry = reuseBlocksCache[partitionNode]; auto& reuseBlockEntry = reuseBlocksCache[partitionNode];
// end = std::chrono::high_resolution_clock::now(); // end = std::chrono::high_resolution_clock::now();
@ -404,6 +365,54 @@ namespace storm {
// totalSignatureCacheStoreTime += end - start; // totalSignatureCacheStoreTime += end - start;
return result; return result;
} }
} else {
// If there are more variables that belong to the non-block part of the encoding, we need to recursively descend.
// Remember an offset that indicates whether the top variable is a nondeterminism variable or not.
short offset = 1;
if (!sylvan_isconst(nondeterminismVariablesNode) && sylvan_var(nondeterminismVariablesNode) == sylvan_var(nonBlockVariablesNode)) {
offset = 0;
}
BDD partitionThen;
BDD partitionElse;
if (sylvan_var(partitionNode) - offset == sylvan_var(nonBlockVariablesNode)) {
partitionThen = sylvan_high(partitionNode);
partitionElse = sylvan_low(partitionNode);
} else {
partitionThen = partitionElse = partitionNode;
}
MTBDD signatureThen;
MTBDD signatureElse;
if (sylvan_var(signatureNode) == sylvan_var(nonBlockVariablesNode)) {
signatureThen = sylvan_high(signatureNode);
signatureElse = sylvan_low(signatureNode);
} else {
signatureThen = signatureElse = signatureNode;
}
BDD thenResult = refine(partitionThen, signatureThen, offset == 0 ? sylvan_high(nondeterminismVariablesNode) : nondeterminismVariablesNode, sylvan_high(nonBlockVariablesNode));
BDD elseResult = refine(partitionElse, signatureElse, offset == 0 ? sylvan_high(nondeterminismVariablesNode) : nondeterminismVariablesNode, sylvan_high(nonBlockVariablesNode));
BDD result;
if (thenResult == elseResult) {
result = thenResult;
} else {
// Get the node to connect the subresults.
// start = std::chrono::high_resolution_clock::now();
result = sylvan_makenode(sylvan_var(nonBlockVariablesNode) + offset, elseResult, thenResult);
// end = std::chrono::high_resolution_clock::now();
// totalMakeNodeTime += end - start;
}
// Store the result in the cache.
// start = std::chrono::high_resolution_clock::now();
*newEntryPtr = result;
// end = std::chrono::high_resolution_clock::now();
// totalSignatureCacheStoreTime += end - start;
return result;
} }
} }
@ -411,13 +420,13 @@ namespace storm {
storm::dd::InternalDdManager<storm::dd::DdType::Sylvan> const& internalDdManager; storm::dd::InternalDdManager<storm::dd::DdType::Sylvan> const& internalDdManager;
storm::expressions::Variable const& blockVariable; storm::expressions::Variable const& blockVariable;
storm::dd::Bdd<storm::dd::DdType::Sylvan> nondeterminismVariables;
storm::dd::Bdd<storm::dd::DdType::Sylvan> nonBlockVariables;
uint64_t numberOfBlockVariables; uint64_t numberOfBlockVariables;
storm::dd::Bdd<storm::dd::DdType::Sylvan> blockCube; storm::dd::Bdd<storm::dd::DdType::Sylvan> blockCube;
// The last level that belongs to the state encoding in the DDs.
uint64_t lastStateLevel;
// The current number of blocks of the new partition. // The current number of blocks of the new partition.
uint64_t nextFreeBlockIndex; uint64_t nextFreeBlockIndex;
@ -444,13 +453,21 @@ namespace storm {
}; };
template<storm::dd::DdType DdType, typename ValueType> 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) {
uint64_t lastStateLevel = 0;
for (auto const& stateVariable : stateVariables) {
lastStateLevel = std::max(lastStateLevel, manager.getMetaVariable(stateVariable).getHighestLevel());
SignatureRefiner<DdType, ValueType>::SignatureRefiner(storm::dd::DdManager<DdType> const& manager, storm::expressions::Variable const& blockVariable, std::set<storm::expressions::Variable> const& stateVariables, std::set<storm::expressions::Variable> const& nondeterminismVariables) : manager(&manager), stateVariables(stateVariables) {
storm::dd::Bdd<DdType> nonBlockVariablesCube = manager.getBddOne();
storm::dd::Bdd<DdType> nondeterminismVariablesCube = manager.getBddOne();
for (auto const& var : nondeterminismVariables) {
auto cube = manager.getMetaVariable(var).getCube();
nonBlockVariablesCube &= cube;
nondeterminismVariablesCube &= cube;
}
for (auto const& var : stateVariables) {
auto cube = manager.getMetaVariable(var).getCube();
nonBlockVariablesCube &= cube;
} }
internalRefiner = std::make_unique<InternalSignatureRefiner<DdType, ValueType>>(manager, blockVariable, lastStateLevel);
internalRefiner = std::make_unique<InternalSignatureRefiner<DdType, ValueType>>(manager, blockVariable, nondeterminismVariablesCube, nonBlockVariablesCube);
} }
template<storm::dd::DdType DdType, typename ValueType> template<storm::dd::DdType DdType, typename ValueType>

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

@ -18,7 +18,7 @@ namespace storm {
class SignatureRefiner { class SignatureRefiner {
public: public:
SignatureRefiner() = default; SignatureRefiner() = default;
SignatureRefiner(storm::dd::DdManager<DdType> const& manager, storm::expressions::Variable const& blockVariable, std::set<storm::expressions::Variable> const& stateVariables);
SignatureRefiner(storm::dd::DdManager<DdType> const& manager, storm::expressions::Variable const& blockVariable, std::set<storm::expressions::Variable> const& stateVariables, std::set<storm::expressions::Variable> const& nondeterminismVariables = std::set<storm::expressions::Variable>());
~SignatureRefiner(); ~SignatureRefiner();

Loading…
Cancel
Save