9#ifdef STORM_HAVE_SYLVAN
10#include "sylvan_cache.h"
17#ifdef STORM_HAVE_SYLVAN
18#pragma GCC diagnostic push
19#pragma GCC diagnostic ignored "-Wpedantic"
20#pragma clang diagnostic push
21#pragma clang diagnostic ignored "-Watomic-implicit-seq-cst"
22#pragma clang diagnostic ignored "-Wextra-semi-stmt"
23#pragma clang diagnostic ignored "-Wused-but-marked-unused"
24#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
26static const uint64_t NO_ELEMENT_MARKER = -1ull;
29 storm::expressions::Variable
const& blockVariable,
30 std::set<storm::expressions::Variable>
const& stateVariables,
31 storm::dd::Bdd<storm::dd::DdType::Sylvan>
const& nondeterminismVariables,
32 storm::dd::Bdd<storm::dd::DdType::Sylvan>
const& nonBlockVariables,
35 blockVariable(blockVariable),
36 stateVariables(stateVariables),
37 nondeterminismVariables(nondeterminismVariables),
38 nonBlockVariables(nonBlockVariables),
40 numberOfBlockVariables(
manager.getMetaVariable(blockVariable).getNumberOfDdVariables()),
41 blockCube(
manager.getMetaVariable(blockVariable).getCube()),
42 nextFreeBlockIndex(0),
43 numberOfRefinements(0),
44 currentCapacity(1ull << 20),
46 table.resize(3 * currentCapacity, NO_ELEMENT_MARKER);
49template<
typename ValueType>
50InternalSignatureRefiner<storm::dd::DdType::Sylvan, ValueType>::InternalSignatureRefiner(
54 :
storm::dd::bisimulation::InternalSylvanSignatureRefinerBase(
manager, blockVariable, stateVariables, nondeterminismVariables, nonBlockVariables, options) {
58template<
typename ValueType>
59Partition<storm::dd::DdType::Sylvan, ValueType> InternalSignatureRefiner<storm::dd::DdType::Sylvan, ValueType>::refine(
60 Partition<storm::dd::DdType::Sylvan, ValueType>
const& oldPartition, Signature<storm::dd::DdType::Sylvan, ValueType>
const& signature) {
61 std::pair<storm::dd::Bdd<storm::dd::DdType::Sylvan>, boost::optional<storm::dd::Bdd<storm::dd::DdType::Sylvan>>> newPartitionDds =
62 refine(oldPartition, signature.getSignatureAdd());
63 ++numberOfRefinements;
65 return oldPartition.replacePartition(newPartitionDds.first, nextFreeBlockIndex, nextFreeBlockIndex, newPartitionDds.second);
68template<
typename ValueType>
69void InternalSignatureRefiner<storm::dd::DdType::Sylvan, ValueType>::clearCaches() {
70 for (
auto& e : this->table) {
71 e = NO_ELEMENT_MARKER;
73 for (
auto& e : this->signatures) {
78template<
typename ValueType>
79std::pair<storm::dd::Bdd<storm::dd::DdType::Sylvan>, boost::optional<storm::dd::Bdd<storm::dd::DdType::Sylvan>>>
80InternalSignatureRefiner<storm::dd::DdType::Sylvan, ValueType>::refine(Partition<storm::dd::DdType::Sylvan, ValueType>
const& oldPartition,
82 STORM_LOG_ASSERT(oldPartition.storedAsBdd(),
"Expecting partition to be stored as BDD for Sylvan.");
84 nextFreeBlockIndex = options.reuseBlockNumbers ? oldPartition.getNextFreeBlockIndex() : 0;
85 signatures.resize(nextFreeBlockIndex);
88 std::pair<BDD, BDD> result(0, 0);
90 RUN(sylvan_refine_partition, signatureAdd.
getInternalAdd().getSylvanMtbdd().GetMTBDD(), oldPartition.asBdd().getInternalBdd().getSylvanBdd().GetBDD(),
96 oldPartition.asBdd().getContainedMetaVariables());
98 boost::optional<storm::dd::Bdd<storm::dd::DdType::Sylvan>> optionalChangedBdd;
99 if (options.createChangedStates && result.second != 0) {
102 optionalChangedBdd = changedBdd;
106 return std::make_pair(newPartitionBdd, optionalChangedBdd);
110static uint64_t sylvan_hash(uint64_t a, uint64_t b) {
111 const uint64_t prime = 1099511628211;
112 uint64_t hash = 14695981039346656037LLU;
113 hash = (hash ^ (a >> 32));
114 hash = (hash ^ a) * prime;
115 hash = (hash ^ b) * prime;
116 return hash ^ (hash >> 32);
130VOID_TASK_3(sylvan_rehash,
size_t, first,
size_t, count, InternalSylvanSignatureRefinerBase*, refiner) {
132 SPAWN(sylvan_rehash, first, count / 2, refiner);
133 CALL(sylvan_rehash, first + count / 2, count - count / 2, refiner);
139 uint64_t* old_ptr = refiner->oldTable.data() + first * 3;
140 uint64_t a = old_ptr[0];
141 uint64_t b = old_ptr[1];
142 uint64_t c = old_ptr[2];
144 uint64_t hash = sylvan_hash(a, b);
145 uint64_t pos = hash % refiner->currentCapacity;
147 volatile uint64_t* ptr =
nullptr;
149 ptr = refiner->table.data() + pos * 3;
151 if (cas(ptr, 0, a)) {
158 if (pos >= refiner->currentCapacity) {
167VOID_TASK_1(sylvan_grow_it, InternalSylvanSignatureRefinerBase*, refiner) {
168 refiner->oldTable = std::move(refiner->table);
170 uint64_t oldCapacity = refiner->currentCapacity;
171 refiner->currentCapacity <<= 1;
172 refiner->table = std::vector<uint64_t>(3 * refiner->currentCapacity, NO_ELEMENT_MARKER);
174 CALL(sylvan_rehash, 0, oldCapacity, refiner);
176 refiner->oldTable.clear();
179VOID_TASK_1(sylvan_grow, InternalSylvanSignatureRefinerBase*, refiner) {
180 if (cas(&refiner->resizeFlag, 0, 1)) {
181 NEWFRAME(sylvan_grow_it, refiner);
182 refiner->resizeFlag = 0;
185 while (ATOMIC_READ(lace_newframe.t) ==
nullptr) {
187 lace_yield(__lace_worker, __lace_dq_head);
191static uint64_t sylvan_search_or_insert(uint64_t sig, uint64_t previous_block, InternalSylvanSignatureRefinerBase* refiner) {
192 uint64_t hash = sylvan_hash(sig, previous_block);
193 uint64_t pos = hash % refiner->currentCapacity;
195 volatile uint64_t* ptr =
nullptr;
199 ptr = refiner->table.data() + pos * 3;
202 while ((b = ptr[1]) == NO_ELEMENT_MARKER) {
205 if (b == previous_block) {
206 while ((c = ptr[2]) == NO_ELEMENT_MARKER) {
211 }
else if (a == NO_ELEMENT_MARKER) {
212 if (cas(ptr, NO_ELEMENT_MARKER, sig)) {
213 ptr[2] = __sync_fetch_and_add(&refiner->nextFreeBlockIndex, 1);
215 ptr[1] = previous_block;
222 if (pos >= refiner->currentCapacity) {
225 if (++count >= 128) {
226 return NO_ELEMENT_MARKER;
231TASK_1(uint64_t, sylvan_decode_block, BDD, block) {
234 while (block != sylvan_true) {
235 BDD b_low = sylvan_low(block);
236 if (b_low == sylvan_false) {
238 block = sylvan_high(block);
247TASK_3(BDD, sylvan_encode_block, BDD, vars, uint64_t, numberOfVariables, uint64_t, blockIndex) {
248 std::vector<uint8_t> e(numberOfVariables);
249 for (uint64_t i = 0;
i < numberOfVariables; ++
i) {
250 e[
i] = blockIndex & 1 ? 1 : 0;
253 return sylvan_cube(vars, e.data());
256TASK_3(BDD, sylvan_assign_block, BDD, sig, BDD, previous_block, InternalSylvanSignatureRefinerBase*, refiner) {
257 STORM_LOG_ASSERT(previous_block != mtbdd_false,
"Incorrect call: previous_block is mtbdd_false.");
262 if (sig == sylvan_false) {
267 if (refiner->options.reuseBlockNumbers) {
269 STORM_LOG_ASSERT(previous_block != sylvan_false,
"Previous_block is sylvan_false.");
270 const uint64_t p_b = CALL(sylvan_decode_block, previous_block);
271 STORM_LOG_ASSERT(p_b < refiner->signatures.size(),
"Block index out of range.");
274 BDD cur = *(
volatile BDD*)&refiner->signatures[p_b];
276 return previous_block;
281 if (cas(&refiner->signatures[p_b], 0, sig)) {
282 return previous_block;
289 while ((c = sylvan_search_or_insert(sig, previous_block, refiner)) == NO_ELEMENT_MARKER) {
290 CALL(sylvan_grow, refiner);
293 return CALL(sylvan_encode_block, refiner->blockCube.getInternalBdd().getSylvanBdd().GetBDD(), refiner->numberOfBlockVariables, c);
296TASK_5(BDD, sylvan_refine_partition, BDD, dd, BDD, previous_partition, BDD, nondetvars, BDD, vars, InternalSylvanSignatureRefinerBase*, refiner) {
301 if (previous_partition == sylvan_false) {
306 if (sylvan_set_isempty(vars)) {
308 if (cache_get(dd | (256LL << 42), vars, previous_partition | (refiner->numberOfRefinements << 40), &result)) {
311 result = CALL(sylvan_assign_block, dd, previous_partition, refiner);
312 cache_put(dd | (256LL << 42), vars, previous_partition | (refiner->numberOfRefinements << 40), result);
321 BDDVAR dd_var = sylvan_isconst(dd) ? 0xffffffff : sylvan_var(dd);
322 BDDVAR pp_var = sylvan_var(previous_partition);
323 BDDVAR vars_var = sylvan_var(vars);
324 BDDVAR nondetvars_var = sylvan_isconst(nondetvars) ? 0xffffffff : sylvan_var(nondetvars);
325 bool nondet = nondetvars_var == vars_var;
326 uint64_t offset = (nondet || !refiner->options.shiftStateVariables) ? 0 : 1;
328 while (vars_var < dd_var && vars_var + offset < pp_var) {
329 vars = sylvan_set_next(vars);
331 nondetvars = sylvan_set_next(nondetvars);
333 if (sylvan_set_isempty(vars)) {
334 return CALL(sylvan_refine_partition, dd, previous_partition, nondetvars, vars, refiner);
336 vars_var = sylvan_var(vars);
338 nondetvars_var = sylvan_isconst(nondetvars) ? 0xffffffff : sylvan_var(nondetvars);
339 nondet = nondetvars_var == vars_var;
340 offset = (nondet || !refiner->options.shiftStateVariables) ? 0 : 1;
346 if (cache_get(dd | (256LL << 42), vars, previous_partition | (refiner->numberOfRefinements << 40), &result)) {
352 if (vars_var == dd_var) {
353 dd_low = sylvan_low(dd);
354 dd_high = sylvan_high(dd);
356 dd_low = dd_high = dd;
360 if (vars_var + offset == pp_var) {
361 pp_low = sylvan_low(previous_partition);
362 pp_high = sylvan_high(previous_partition);
364 pp_low = pp_high = previous_partition;
368 BDD next_vars = sylvan_set_next(vars);
369 BDD next_nondetvars = nondet ? sylvan_set_next(nondetvars) : nondetvars;
370 bdd_refs_spawn(SPAWN(sylvan_refine_partition, dd_low, pp_low, next_nondetvars, next_vars, refiner));
371 BDD high = bdd_refs_push(CALL(sylvan_refine_partition, dd_high, pp_high, next_nondetvars, next_vars, refiner));
372 BDD low = bdd_refs_sync(SYNC(sylvan_refine_partition));
376 result = sylvan_makenode(vars_var + offset, low, high);
379 cache_put(dd | (256LL << 42), vars, previous_partition | (refiner->numberOfRefinements << 40), result);
383#pragma clang diagnostic pop
384#pragma GCC diagnostic pop
389 std::set<storm::expressions::Variable>
const& stateVariables,
394 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
395 "version of Storm with Sylvan support.");
398template<
typename ValueType>
405 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
406 "version of Storm with Sylvan support.");
409template<
typename ValueType>
413 "This version of Storm was compiled without support for Sylvan. Yet, a method was called that requires this support. Please choose a "
414 "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.
InternalSignatureRefiner(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)
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.