I am wondering as to how to efficiently encode the following subcircuit for a binary satisfiability solver (cnf, and optionally xor clauses, if this helps):
eq2 = sum(a, b, c, d, e, f, g, h) == 2
eq3 = sum(a, b, c, d, e, f, g, h) == 3
(All variables binary. That is, eq2
should be set if and only if exactly two of the eight input variables are set; eq3
should be set if and only if exactly 3 of the eight input variables are set.)
This subcircuit appears many times in the problem, so efficient encoding is important.
Things I have tried thus far:
- Just naively emit the $2^8$ miniterms for each. This is simple, but results in 512 clauses of 9 variables each. It also doesn't expose the structure of the problem to the sat solver.
- Generate the circuits
ge2 = or(and(a, b), and(a, c), ...)
/ge3 = or(and(a, b, c), and(a, b, d), ...)
/ge4 = or(and(a, b, c, d), and(a, b, c, e), ...)
/eq2 = and(ge2, ~ge3)
/eq3 = and(ge3, ~ge4)
. This, unfortunately, results in many clauses still. - Generate circuits implementing an adder-tree, and then
eq2 = and(~sum_3, ~sum_2, sum_1, ~sum_0)
andeq3 = and(~sum_3, ~sum_2, sum_1, sum_0)
. This works, however it unnecessarily constrains the solver (there's a lot of propagation that needs to be done even if the sum is >= 4, for instance), and prevents direct propagation between inputs (they may need to go all the way up the adder-tree and back).
Is there a better method of doing this that I'm missing?