9#ifdef STORM_HAVE_SYLVAN
10#include "sylvan_cache.h"
15namespace bisimulation {
17#ifdef STORM_HAVE_SYLVAN
18static const uint64_t NO_ELEMENT_MARKER = -1ull;
22 std::set<storm::expressions::Variable>
const& stateVariables,
25 InternalSignatureRefinerOptions
const& options)
27 blockVariable(blockVariable),
28 stateVariables(stateVariables),
29 nondeterminismVariables(nondeterminismVariables),
30 nonBlockVariables(nonBlockVariables),
32 numberOfBlockVariables(
manager.getMetaVariable(blockVariable).getNumberOfDdVariables()),
33 blockCube(
manager.getMetaVariable(blockVariable).getCube()),
34 nextFreeBlockIndex(0),
35 numberOfRefinements(0),
36 currentCapacity(1ull << 20),
38 table.resize(3 * currentCapacity, NO_ELEMENT_MARKER);
41template<
typename ValueType>
42InternalSignatureRefiner<storm::dd::DdType::Sylvan, ValueType>::InternalSignatureRefiner(
46 :
storm::dd::bisimulation::InternalSylvanSignatureRefinerBase(
manager, blockVariable, stateVariables, nondeterminismVariables, nonBlockVariables, options) {
50template<
typename ValueType>
51Partition<storm::dd::DdType::Sylvan, ValueType> InternalSignatureRefiner<storm::dd::DdType::Sylvan, ValueType>::refine(
52 Partition<storm::dd::DdType::Sylvan, ValueType>
const& oldPartition, Signature<storm::dd::DdType::Sylvan, ValueType>
const& signature) {
53 std::pair<storm::dd::Bdd<storm::dd::DdType::Sylvan>, boost::optional<storm::dd::Bdd<storm::dd::DdType::Sylvan>>> newPartitionDds =
54 refine(oldPartition, signature.getSignatureAdd());
55 ++numberOfRefinements;
57 return oldPartition.replacePartition(newPartitionDds.first, nextFreeBlockIndex, nextFreeBlockIndex, newPartitionDds.second);
60template<
typename ValueType>
61void InternalSignatureRefiner<storm::dd::DdType::Sylvan, ValueType>::clearCaches() {
62 for (
auto& e : this->table) {
63 e = NO_ELEMENT_MARKER;
65 for (
auto& e : this->signatures) {
70template<
typename ValueType>
71std::pair<storm::dd::Bdd<storm::dd::DdType::Sylvan>, boost::optional<storm::dd::Bdd<storm::dd::DdType::Sylvan>>>
72InternalSignatureRefiner<storm::dd::DdType::Sylvan, ValueType>::refine(Partition<storm::dd::DdType::Sylvan, ValueType>
const& oldPartition,
74 STORM_LOG_ASSERT(oldPartition.storedAsBdd(),
"Expecting partition to be stored as BDD for Sylvan.");
76 nextFreeBlockIndex = options.reuseBlockNumbers ? oldPartition.getNextFreeBlockIndex() : 0;
77 signatures.resize(nextFreeBlockIndex);
80 std::pair<BDD, BDD> result(0, 0);
82 RUN(sylvan_refine_partition, signatureAdd.
getInternalAdd().getSylvanMtbdd().GetMTBDD(), oldPartition.asBdd().getInternalBdd().getSylvanBdd().GetBDD(),
88 oldPartition.asBdd().getContainedMetaVariables());
90 boost::optional<storm::dd::Bdd<storm::dd::DdType::Sylvan>> optionalChangedBdd;
91 if (options.createChangedStates && result.second != 0) {
94 optionalChangedBdd = changedBdd;
98 return std::make_pair(newPartitionBdd, optionalChangedBdd);
102static uint64_t sylvan_hash(uint64_t a, uint64_t b) {
103 const uint64_t prime = 1099511628211;
104 uint64_t hash = 14695981039346656037LLU;
105 hash = (hash ^ (a >> 32));
106 hash = (hash ^ a) * prime;
107 hash = (hash ^ b) * prime;
108 return hash ^ (hash >> 32);
123#pragma clang diagnostic push
124#pragma clang diagnostic ignored "-Wc99-extensions"
125#pragma GCC diagnostic push
126#pragma GCC diagnostic ignored "-Wpedantic"
128VOID_TASK_3(sylvan_rehash,
size_t, first,
size_t, count, InternalSylvanSignatureRefinerBase*, refiner) {
130 SPAWN(sylvan_rehash, first, count / 2, refiner);
131 CALL(sylvan_rehash, first + count / 2, count - count / 2, refiner);
137 uint64_t* old_ptr = refiner->oldTable.data() + first * 3;
138 uint64_t a = old_ptr[0];
139 uint64_t b = old_ptr[1];
140 uint64_t c = old_ptr[2];
142 uint64_t hash = sylvan_hash(a, b);
143 uint64_t pos = hash % refiner->currentCapacity;
145 volatile uint64_t* ptr = 0;
147 ptr = refiner->table.data() + pos * 3;
149 if (cas(ptr, 0, a)) {
156 if (pos >= refiner->currentCapacity)
164VOID_TASK_1(sylvan_grow_it, InternalSylvanSignatureRefinerBase*, refiner) {
165 refiner->oldTable = std::move(refiner->table);
167 uint64_t oldCapacity = refiner->currentCapacity;
168 refiner->currentCapacity <<= 1;
169 refiner->table = std::vector<uint64_t>(3 * refiner->currentCapacity, NO_ELEMENT_MARKER);
171 CALL(sylvan_rehash, 0, oldCapacity, refiner);
173 refiner->oldTable.clear();
176VOID_TASK_1(sylvan_grow, InternalSylvanSignatureRefinerBase*, refiner) {
177 if (cas(&refiner->resizeFlag, 0, 1)) {
178 NEWFRAME(sylvan_grow_it, refiner);
179 refiner->resizeFlag = 0;
182 while (ATOMIC_READ(lace_newframe.t) == 0) {
184 lace_yield(__lace_worker, __lace_dq_head);
188static uint64_t sylvan_search_or_insert(uint64_t sig, uint64_t previous_block, InternalSylvanSignatureRefinerBase* refiner) {
189 uint64_t hash = sylvan_hash(sig, previous_block);
190 uint64_t pos = hash % refiner->currentCapacity;
192 volatile uint64_t* ptr = 0;
196 ptr = refiner->table.data() + pos * 3;
199 while ((b = ptr[1]) == NO_ELEMENT_MARKER)
continue;
200 if (b == previous_block) {
201 while ((c = ptr[2]) == NO_ELEMENT_MARKER)
continue;
204 }
else if (a == NO_ELEMENT_MARKER) {
205 if (cas(ptr, NO_ELEMENT_MARKER, sig)) {
206 ptr[2] = __sync_fetch_and_add(&refiner->nextFreeBlockIndex, 1);
208 ptr[1] = previous_block;
215 if (pos >= refiner->currentCapacity)
218 return NO_ELEMENT_MARKER;
222TASK_1(uint64_t, sylvan_decode_block, BDD, block) {
225 while (block != sylvan_true) {
226 BDD b_low = sylvan_low(block);
227 if (b_low == sylvan_false) {
229 block = sylvan_high(block);
238TASK_3(BDD, sylvan_encode_block, BDD, vars, uint64_t, numberOfVariables, uint64_t, blockIndex) {
239 std::vector<uint8_t> e(numberOfVariables);
240 for (uint64_t i = 0;
i < numberOfVariables; ++
i) {
241 e[
i] = blockIndex & 1 ? 1 : 0;
244 return sylvan_cube(vars, e.data());
247TASK_3(BDD, sylvan_assign_block, BDD, sig, BDD, previous_block, InternalSylvanSignatureRefinerBase*, refiner) {
248 assert(previous_block != mtbdd_false);
253 if (sig == sylvan_false) {
258 if (refiner->options.reuseBlockNumbers) {
260 assert(previous_block != sylvan_false);
261 const uint64_t p_b = CALL(sylvan_decode_block, previous_block);
262 assert(p_b < refiner->signatures.size());
265 BDD cur = *(
volatile BDD*)&refiner->signatures[p_b];
267 return previous_block;
270 if (cas(&refiner->signatures[p_b], 0, sig))
271 return previous_block;
277 while ((c = sylvan_search_or_insert(sig, previous_block, refiner)) == NO_ELEMENT_MARKER) {
278 CALL(sylvan_grow, refiner);
281 return CALL(sylvan_encode_block, refiner->blockCube.getInternalBdd().getSylvanBdd().GetBDD(), refiner->numberOfBlockVariables, c);
284TASK_5(BDD, sylvan_refine_partition, BDD, dd, BDD, previous_partition, BDD, nondetvars, BDD, vars, InternalSylvanSignatureRefinerBase*, refiner) {
289 if (previous_partition == sylvan_false) {
294 if (sylvan_set_isempty(vars)) {
296 if (cache_get(dd | (256LL << 42), vars, previous_partition | (refiner->numberOfRefinements << 40), &result))
298 result = CALL(sylvan_assign_block, dd, previous_partition, refiner);
299 cache_put(dd | (256LL << 42), vars, previous_partition | (refiner->numberOfRefinements << 40), result);
308 BDDVAR dd_var = sylvan_isconst(dd) ? 0xffffffff : sylvan_var(dd);
309 BDDVAR pp_var = sylvan_var(previous_partition);
310 BDDVAR vars_var = sylvan_var(vars);
311 BDDVAR nondetvars_var = sylvan_isconst(nondetvars) ? 0xffffffff : sylvan_var(nondetvars);
312 bool nondet = nondetvars_var == vars_var;
313 uint64_t offset = (nondet || !refiner->options.shiftStateVariables) ? 0 : 1;
315 while (vars_var < dd_var && vars_var + offset < pp_var) {
316 vars = sylvan_set_next(vars);
318 nondetvars = sylvan_set_next(nondetvars);
320 if (sylvan_set_isempty(vars))
321 return CALL(sylvan_refine_partition, dd, previous_partition, nondetvars, vars, refiner);
322 vars_var = sylvan_var(vars);
324 nondetvars_var = sylvan_isconst(nondetvars) ? 0xffffffff : sylvan_var(nondetvars);
325 nondet = nondetvars_var == vars_var;
326 offset = (nondet || !refiner->options.shiftStateVariables) ? 0 : 1;
332 if (cache_get(dd | (256LL << 42), vars, previous_partition | (refiner->numberOfRefinements << 40), &result)) {
338 if (vars_var == dd_var) {
339 dd_low = sylvan_low(dd);
340 dd_high = sylvan_high(dd);
342 dd_low = dd_high = dd;
346 if (vars_var + offset == pp_var) {
347 pp_low = sylvan_low(previous_partition);
348 pp_high = sylvan_high(previous_partition);
350 pp_low = pp_high = previous_partition;
354 BDD next_vars = sylvan_set_next(vars);
355 BDD next_nondetvars = nondet ? sylvan_set_next(nondetvars) : nondetvars;
356 bdd_refs_spawn(SPAWN(sylvan_refine_partition, dd_low, pp_low, next_nondetvars, next_vars, refiner));
357 BDD high = bdd_refs_push(CALL(sylvan_refine_partition, dd_high, pp_high, next_nondetvars, next_vars, refiner));
358 BDD low = bdd_refs_sync(SYNC(sylvan_refine_partition));
362 result = sylvan_makenode(vars_var + offset, low, high);
365 cache_put(dd | (256LL << 42), vars, previous_partition | (refiner->numberOfRefinements << 40), result);
369#pragma GCC diagnostic pop
370#pragma clang diagnostic pop
375 std::set<storm::expressions::Variable>
const& stateVariables,
380 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
381 "version of Storm with Sylvan support.");
384template<
typename ValueType>
391 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
392 "version of Storm with Sylvan support.");
395template<
typename ValueType>
399 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
400 "version of Storm with Sylvan support.");
InternalAdd< LibraryType, ValueType > const & getInternalAdd() const
Retrieves the internal ADD.
InternalBdd< LibraryType > const & getInternalBdd() const
Retrieves the internal BDD.
InternalSylvanSignatureRefinerBase(storm::dd::DdManager< storm::dd::DdType::Sylvan > const &manager, storm::expressions::Variable const &blockVariable, std::set< storm::expressions::Variable > const &stateVariables, storm::dd::Bdd< storm::dd::DdType::Sylvan > const &nondeterminismVariables, storm::dd::Bdd< storm::dd::DdType::Sylvan > const &nonBlockVariables, InternalSignatureRefinerOptions const &options)
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
std::pair< storm::RationalNumber, storm::RationalNumber > count(std::vector< storm::storage::BitVector > const &origSets, std::vector< storm::storage::BitVector > const &intersects, std::vector< storm::storage::BitVector > const &intersectsInfo, storm::RationalNumber val, bool plus, uint64_t remdepth)
SettingsManager const & manager()
Retrieves the settings manager.