def subrange_exercise(mult, lb, ub): """Compare filter-based and more optimized subrange implementations Helper for tests, called with both small and larger multisets. """ m = MultisetPartitionTraverser() assert m.count_partitions(mult) == \ m.count_partitions_slow(mult) # Note - multiple traversals from the same # MultisetPartitionTraverser object cannot execute at the same # time, hence make several instances here. ma = MultisetPartitionTraverser() mc = MultisetPartitionTraverser() md = MultisetPartitionTraverser() # Several paths to compute just the size two partitions a_it = ma.enum_range(mult, lb, ub) b_it = part_range_filter(multiset_partitions_taocp(mult), lb, ub) c_it = part_range_filter(mc.enum_small(mult, ub), lb, sum(mult)) d_it = part_range_filter(md.enum_large(mult, lb), 0, ub) for sa, sb, sc, sd in zip_longest(a_it, b_it, c_it, d_it): assert compare_multiset_states(sa, sb) assert compare_multiset_states(sa, sc) assert compare_multiset_states(sa, sd)
def test_multiset_partitions_versions(): """Compares Knuth-based versions of multiset_partitions""" multiplicities = [5, 2, 2, 1] m = MultisetPartitionTraverser() for s1, s2 in zip_longest(m.enum_all(multiplicities), multiset_partitions_taocp(multiplicities)): assert compare_multiset_states(s1, s2)
def test_multiset_partitions_versions(): """Compares Knuth-based versions of multiset_partitions""" multiplicities = [5,2,2,1] m = MultisetPartitionTraverser() for s1, s2 in zip_longest(m.enum_all(multiplicities), multiset_partitions_taocp(multiplicities)): assert compare_multiset_states(s1, s2)
def to_NNF(expr): """ Generates the Negation Normal Form of any boolean expression in terms of AND, OR, and Literal objects. """ if isinstance(expr, Not): arg = expr.args[0] tmp = to_NNF(arg) # Strategy: negate the NNF of expr return ~tmp if isinstance(expr, Or): return OR(*[to_NNF(x) for x in Or.make_args(expr)]) if isinstance(expr, And): return AND(*[to_NNF(x) for x in And.make_args(expr)]) if isinstance(expr, Nand): tmp = AND(*[to_NNF(x) for x in expr.args]) return ~tmp if isinstance(expr, Nor): tmp = OR(*[to_NNF(x) for x in expr.args]) return ~tmp if isinstance(expr, Xor): cnfs = [] for i in range(0, len(expr.args) + 1, 2): for neg in combinations(expr.args, i): clause = [~to_NNF(s) if s in neg else to_NNF(s) for s in expr.args] cnfs.append(OR(*clause)) return AND(*cnfs) if isinstance(expr, Xnor): cnfs = [] for i in range(0, len(expr.args) + 1, 2): for neg in combinations(expr.args, i): clause = [~to_NNF(s) if s in neg else to_NNF(s) for s in expr.args] cnfs.append(OR(*clause)) return ~AND(*cnfs) if isinstance(expr, Implies): L, R = to_NNF(expr.args[0]), to_NNF(expr.args[1]) return OR(~L, R) if isinstance(expr, Equivalent): cnfs = [] for a, b in zip_longest(expr.args, expr.args[1:], fillvalue=expr.args[0]): a = to_NNF(a) b = to_NNF(b) cnfs.append(OR(~a, b)) return AND(*cnfs) if isinstance(expr, ITE): L = to_NNF(expr.args[0]) M = to_NNF(expr.args[1]) R = to_NNF(expr.args[2]) return AND(OR(~L, M), OR(L, R)) else: return Literal(expr)