def test_weighted_leq(self) : opb="""\ * #variable= 5 #constraint= 1 * -1 x1 -2 x2 -3 x3 +1 x4 +2 x5 >= -2; """ F=CNF() F.add_linear(1,"a",2,"b",3,"c",-1,"d",-2,"e","<=",2) self.assertCnfEqualsOPB(F,opb)
def test_weighted_gt(self) : opb="""\ * #variable= 5 #constraint= 1 * +1 x1 +2 x2 +3 x3 -1 x4 -2 x5 >= 3; """ F=CNF() F.add_linear(1,"a",2,"b",3,"c",-1,"d",-2,"e",">",2) self.assertCnfEqualsOPB(F,opb)
def test_weighted_leq(self): opb = """\ * #variable= 5 #constraint= 1 * -1 x1 -2 x2 -3 x3 +1 x4 +2 x5 >= -2; """ F = CNF() F.add_linear(1, "a", 2, "b", 3, "c", -1, "d", -2, "e", "<=", 2) self.assertCnfEqualsOPB(F, opb)
def test_weighted_gt(self): opb = """\ * #variable= 5 #constraint= 1 * +1 x1 +2 x2 +3 x3 -1 x4 -2 x5 >= 3; """ F = CNF() F.add_linear(1, "a", 2, "b", 3, "c", -1, "d", -2, "e", ">", 2) self.assertCnfEqualsOPB(F, opb)
def TseitinFormula(graph, charges=None, encoding=None): """Build a Tseitin formula based on the input graph. Odd charge is put on the first vertex by default, unless other vertices are is specified in input. Arguments: - `graph`: input graph - `charges': odd or even charge for each vertex """ V = enumerate_vertices(graph) if charges == None: charges = [1] + [0] * (len(V) - 1) # odd charge on first vertex else: charges = [bool(c) for c in charges] # map to boolean if len(charges) < len(V): charges = charges + [0] * (len(V) - len(charges) ) # pad with even charges # init formula tse = CNF() edgename = {} for (u, v) in sorted(graph.edges(), key=sorted): edgename[(u, v)] = "E_{{{0},{1}}}".format(u, v) edgename[(v, u)] = "E_{{{0},{1}}}".format(u, v) tse.add_variable(edgename[(u, v)]) tse.mode_strict() # add constraints for v, charge in zip(V, charges): # produce all clauses and save half of them names = [edgename[(u, v)] for u in neighbors(graph, v)] if encoding == None: tse.add_parity(names, charge) else: def toArgs(listOfTuples, operator, degree): return list(sum(listOfTuples, ())) + [operator, degree] terms = list(map(lambda x: (1, x), names)) w = len(terms) k = w // 2 if encoding == "extendedPBAnyHelper": for i in range(k): helper = ("xor_helper", i, v) tse.add_variable(helper) terms.append((2, helper)) elif encoding == "extendedPBOneHelper": helpers = list() for i in range(k): helper = ("xor_helper", i, v) helpers.append(helper) tse.add_variable(helper) terms.append(((i + 1) * 2, helper)) tse.add_linear(*toArgs([(1, x) for x in helpers], "<=", 1)) elif encoding == "extendedPBExpHelper": for i in range(math.ceil(math.log(k, 2)) + 1): helper = ("xor_helper", i, v) tse.add_variable(helper) terms.append((2**i * 2, helper)) else: raise ValueError("Invalid encoding '%s'" % encoding) degree = 2 * k + (charge % 2) tse.add_linear(*toArgs(terms, "==", degree)) return tse
class XorCard(): """ Formula encoding Ax = b mod 2 and 1^Tx >= k for random A in R^mxn,b^m Personal Note: according to Kuldeep Meel these have various interesting applications for this kind of benchmarks. There will be a publication in SAT 2019 about this kind of formula. """ def __init__(self, m, n, k, eq, encoding): self.m = m self.n = n self.k = k self.eq = eq self.encoding = encoding self.numXor = 0 def x(self, i): return "x_%i"%(i) def h(self, i,j): return "h_(%i,%i)"%(i,j) def addXor(self, terms, value): w = len(terms) k = w // 2 if k > 0: if self.encoding == "extendedPBAnyHelper": for i in range(k): helper = ("xor_helper", i, self.numXor) self.f.add_variable(helper) terms.append((2, helper)) elif self.encoding == "extendedPBOneHelper": helpers = list() for i in range(k): helper = ("xor_helper", i, self.numXor) helpers.append(helper) self.f.add_variable(helper) terms.append(((i+1)*2, helper)) self.f.add_linear(*toArgs([(1, x) for x in helpers], "<=", 1)) elif self.encoding == "extendedPBExpHelper": for i in range(math.ceil(math.log(k, 2)) + 1): helper = ("xor_helper", i, self.numXor) self.f.add_variable(helper) terms.append((2**i * 2, helper)) else: raise ValueError("Invalid encoding '%s'" % encoding) degree = 2 * k + (value % 2) self.f.add_linear(*toArgs(terms, "==", degree)) self.numXor += 1 def __call__(self): mn = self.m * self.n A = [0, 1] * (mn // 2) + [0] * (mn % 2) random.shuffle(A) A = [[A[i * self.n + j] for j in range(self.n)] for i in range(self.m)] b = [0, 1] * (self.m // 2) + [0] * (self.m % 2) self.f = CNF() terms = [(-1, self.x(i)) for i in range(self.n)] if self.eq: self.f.add_linear(*toArgs(terms, "==", -self.k)) else: self.f.add_linear(*toArgs(terms, ">=", -self.k)) for i in range(self.m): terms = [(1, self.x(j)) for j in range(self.n) if A[i][j] == 1] if len(terms) > 0: self.addXor(terms, b[i]) return self.f
def test_bogus(self) : F=CNF() with self.assertRaises(ValueError): F.add_linear(1,"a",2,"b",3,"c",-1,"d",-2,"e","??",2)
def test_bogus(self): F = CNF() with self.assertRaises(ValueError): F.add_linear(1, "a", 2, "b", 3, "c", -1, "d", -2, "e", "??", 2)