def cnf_1bitmultiplier(cnf: Formula, a: Variable, b: Variable) -> Variable: #according to wolfie: CNF | (¬a ∨ ¬b ∨ d) ∧ (a ∨ ¬d) ∧ (b ∨ ¬d) d = cnf.new_var() cnf.add([~a, ~b, d]) cnf.add([a, ~d]) cnf.add([b, ~d]) return d
def cnf_constant(cnf: Formula, n: List[Variable], c: int) -> None: for i in range(len(n)): b = c & 1 c >>= 1 if b: cnf.add([n[i]]) else: cnf.add([~n[i]]) if c > 0: print("WARNING: overflow in cnf_constant!")
def commander_variable(cnf: Formula, group: List[Variable]) -> Variable: at_most_one(cnf, group) var = cnf.new_var() # var <=> (a or b or c ...) for i in range(len(group)): cnf.add([~group[i], var]) clause = group[:] clause.append(~var) cnf.add(clause) return var
def one_of_k_commander(cnf: Formula, varlist: List[Variable], group_size: int) -> None: at_least_one(cnf, varlist) length = len(varlist) if length == 1: cnf.add([varlist[0]]) return assert (length % group_size == 0) treevars = [] #type: List[Variable] for i in range(int(length / group_size)): idx = group_size * i group = varlist[idx:idx + group_size] treevar = commander_variable(cnf, group) treevars.append(treevar) one_of_k_commander(cnf, treevars, group_size)
def cnf_odd2(cnf: Formula, a: List[Variable], b: List[Variable], c: List[Variable]) -> None: x = a[0] y = c[0] z = b[0] cnf.add([~x, ~y, ~z]) cnf.add([x, y]) cnf.add([x, z]) cnf.add([y, z])
def cnf_1bitequal(cnf: Formula, a: Variable, b: Variable) -> None: cnf.add([a, ~b]) cnf.add([~a, b])
def cnf_1bitadder(cnf: Formula, a: Variable, b: Variable, c: Variable) -> Tuple[Variable, Variable]: res = cnf.new_var() res_carry = cnf.new_var() # (d|a|~b|~c)&(d|~a|b|~c)&(d|~a|~b|c)&(d|~a|~b|~c)&(~d|a|b|c)&(~d|a|b|~c)&(~d|a|~b|c)&(~d|~a|b|c) cnf.add([res_carry, a, ~b, ~c]) cnf.add([res_carry, ~a, b, ~c]) cnf.add([res_carry, ~a, ~b, c]) cnf.add([res_carry, ~a, ~b, ~c]) cnf.add([~res_carry, a, b, c]) cnf.add([~res_carry, a, b, ~c]) cnf.add([~res_carry, a, ~b, c]) cnf.add([~res_carry, ~a, b, c]) # (d|a|b|~c)&(d|a|~b|c)&(d|~a|b|c)&(d|~a|~b|~c)&(~d|a|b|c)&(~d|a|~b|~c)&(~d|~a|b|~c)&(~d|~a|~b|c) cnf.add([res, a, b, ~c]) cnf.add([res, a, ~b, c]) cnf.add([res, ~a, b, c]) cnf.add([res, ~a, ~b, ~c]) cnf.add([~res, a, b, c]) cnf.add([~res, a, ~b, ~c]) cnf.add([~res, ~a, b, ~c]) cnf.add([~res, ~a, ~b, c]) return res, res_carry
def cnf_div4(cnf: Formula, a: List[Variable], b: List[Variable], c: List[Variable]) -> None: x = a[0] y = a[1] z = b[0] w = b[1] p = c[0] q = c[1] cnf.add([~x, ~z]) cnf.add([~x, ~w]) cnf.add([~x, ~p]) cnf.add([~x, ~q]) cnf.add([~y, ~z]) cnf.add([~y, ~w]) cnf.add([~y, ~p]) cnf.add([~y, ~q]) cnf.add([~z, ~p]) cnf.add([~z, ~q]) cnf.add([~w, ~p]) cnf.add([~w, ~q])
def cnf_1div16(cnf: Formula, a: List[Variable]) -> None: cnf.add([~a[0]]) cnf.add([~a[1]]) cnf.add([~a[2]]) cnf.add([~a[3]])
c2 = cnf_square(cnf, c) d2 = cnf_square(cnf, d) e2 = cnf_square(cnf, e) f2 = cnf_square(cnf, f) g2 = cnf_square(cnf, g) a2b2 = cnf_add(cnf, a2, b2) a2c2 = cnf_add(cnf, a2, c2) b2c2 = cnf_add(cnf, b2, c2) a2b2c2 = cnf_add(cnf, a2b2, c2) #ensure a, b, c != 0 cnf.add(a) cnf.add(b) cnf.add(c) # add the system of equations cnf_equal(cnf, a2b2, d2) cnf_equal(cnf, a2c2, e2) cnf_equal(cnf, b2c2, f2) cnf_equal(cnf, a2b2c2, g2) #enforce euclid's formula on the triples cnf_enforce_pyth_trip(cnf, a, b, d, True) cnf_enforce_pyth_trip(cnf, a, c, e, False) cnf_enforce_pyth_trip(cnf, b, c, f, True)