diff --git a/cudd/cudd/cuddTable.c b/cudd/cudd/cuddTable.c index 8ee039c6..6afe70c6 100644 --- a/cudd/cudd/cuddTable.c +++ b/cudd/cudd/cuddTable.c @@ -1464,7 +1464,12 @@ cuddUniqueInterZdd( /** - * Truncate a double value to 10^-10 precision. + * Helper function: Truncate a double value to approximately + * 10^-10 precision (with rounding). + * + * This is used in cuddUnqiueConstant and cuddRehash to generate a + * canonical double value for the hash lookup, ensuring that values that + * are close will be hashed to the same bucket. */ static double truncateDoubleConstant(double value) { @@ -1524,15 +1529,42 @@ cuddUniqueConst( cuddAdjust(value); /* for the case of crippled infinities */ + if (ddAbs(value) < unique->epsilon) { - value = 0.0; - } - /* this is the old version: - split.value = value; - */ - // this is the new version... - // (round off before doing hash function to ensure - // close valued constants are in the same table) + value = 0.0; + } + + /* PRISM-specific behaviour: + * To keep the number of distinct constants with very close double value low, + * we would like to identify constants where + * ddEqualVal(value, existing_constant, unique->epsilon) + * is true, i.e., where the values differ by less than the CUDD epsilon parameter. + * + * However, as the lookup in the unique table is performed via a hashtable, we have + * to ensure that all constants that are close are hashed into the same bucket + * in the hash table. + * + * This is achieved by performing the hashtable lookup not on the value itself, but + * on a truncated/rounded version, i.e., where the precision has been reduced such + * that it is ensured that all constants within the epsilon range are hashed to + * the same value. + * + * The procedure is then: + * 1) Lookup the bucket (pos) using the truncated value (split.value) + * 2) In the linked list of the bucket, search for an exact match + * or a close match + * 3) If there is no match, insert the value. + * + * To ensure that the uniqueness for the constants is not violated, during + * rehashing of the unique table for the constants, the truncation has to be + * applied as well (see cuddRehash, case for i == CUDD_CONST_INDEX). + */ + + // this is the original, CUDD version (without truncation): + // split.value = value; + + // PRISM version: + // use truncated value for hash lookup split.value = truncateDoubleConstant(value); pos = ddHash(split.bits[0], split.bits[1], unique->constants.shift); @@ -1721,8 +1753,14 @@ cuddRehash( node = oldnodelist[j]; while (node != NULL) { next = node->next; - split.value = cuddV(node); - split.value = truncateDoubleConstant(split.value); + + // original CUDD version: + // split.value = cuddV(node); + + // PRISM version: we have to truncate the value for the hash lookup + // (see corresponding comment in cuddUniqueConstant) + split.value = truncateDoubleConstant(cuddV(node)); + pos = ddHash(split.bits[0], split.bits[1], shift); node->next = nodelist[pos]; nodelist[pos] = node;