def init(self, bootstrap_with): """ This method serves for initializing the hitting set solver with a given list of sets to hit. Concretely, the hitting set problem is encoded into partial MaxSAT as outlined above, which is then fed either to a MaxSAT solver or an MCS enumerator. :param bootstrap_with: input set of sets to hit :type bootstrap_with: iterable(iterable(obj)) """ # formula encoding the sets to hit formula = WCNF() # hard clauses for to_hit in bootstrap_with: to_hit = list(map(lambda obj: self.idpool.id(obj), to_hit)) formula.append(to_hit) # soft clauses for obj_id in six.iterkeys(self.idpool.id2obj): formula.append([-obj_id], weight=1) if self.htype == 'rc2': # using the RC2-A options from MaxSAT evaluation 2018 self.oracle = RC2(formula, solver=self.solver, adapt=False, exhaust=True, trim=5) elif self.htype == 'lbx': self.oracle = LBX(formula, solver_name=self.solver, use_cld=True) else: self.oracle = MCSls(formula, solver_name=self.solver, use_cld=True)
def genMinGraph(graph, num_colours=4, approx=False, required_cl=[], required_nodes=[]): cl, n_clM, cl_nM = getSAT(graph, num_colours) f = WCNF() for c in required_cl: f.append(c) for c in cl: f.append(c, weight=1) print("Created formula") if approx: required_cl = genApproxMinClauses(f) else: # Calculate MUS mu = MUSX(f, verbosity=2) required_cl = mu.compute() # Map back to graph req_nodes = set(required_nodes) [req_nodes.update(cl_nM[i - 1]) for i in required_cl] print("New graph size:", len(req_nodes)) # Create blacklist and delete bk_lst = [n for n in graph.G.nodes if n not in req_nodes] [graph.G.remove_node(i) for i in bk_lst]
def optimize(self, enc): """ Try to optimize the solution with a MaxSAT solver. """ # a dummy model (everything is deselected) model = [-v for v in range(enc.nv)] all_vars = set() # MaxSAT formula to work with formula = WCNF() # hard clauses for cl in enc.clauses: formula.append(cl) for j in range(1, self.nof_terms + 1): for r in range(1, self.nof_feats + 1): formula.append([-self.dvar1(j, r)], 1) formula.append([-self.dvar0(j, r)], 1) all_vars.add(self.dvar1(j, r)) all_vars.add(self.dvar0(j, r)) if self.options.approx: hitman = LBX(formula, use_cld=self.options.use_cld, solver_name=self.options.solver) hses = [] for i, hs in enumerate(hitman.enumerate()): hitman.block(hs) hses.append(hs) if i + 1 == self.options.approx: break hs = list( map(lambda v: -formula.soft[v - 1][0], min(hses, key=lambda x: len(x)))) hitman.delete() else: hitman = RC2(formula, solver=self.options.solver, adapt=True, exhaust=True, incr=False, minz=False, trim=self.options.trim) hs = list( filter(lambda v: v > 0 and v in all_vars, hitman.compute())) hitman.delete() # filling the model with the right values for e in hs: model[e - 1] = e return model
def init(self, bootstrap_with, weights=None): """ This method serves for initializing the hitting set solver with a given list of sets to hit. Concretely, the hitting set problem is encoded into partial MaxSAT as outlined above, which is then fed either to a MaxSAT solver or an MCS enumerator. An additional optional parameter is ``weights``, which can be used to specify non-unit weights for the target objects in the sets to hit. This only works if ``'sorted'`` enumeration of hitting sets is applied. :param bootstrap_with: input set of sets to hit :param weights: weights of the objects in case the problem is weighted :type bootstrap_with: iterable(iterable(obj)) :type weights: dict(obj) """ # formula encoding the sets to hit formula = WCNF() # hard clauses for to_hit in bootstrap_with: to_hit = list(map(lambda obj: self.idpool.id(obj), to_hit)) formula.append(to_hit) # soft clauses for obj_id in six.iterkeys(self.idpool.id2obj): formula.append( [-obj_id], weight=1 if not weights else weights[self.idpool.obj(obj_id)]) if self.htype == 'rc2': if not weights or min(weights.values()) == max(weights.values()): self.oracle = RC2(formula, solver=self.solver, adapt=self.adapt, exhaust=self.exhaust, minz=self.minz, trim=self.trim) else: self.oracle = RC2Stratified(formula, solver=self.solver, adapt=self.adapt, exhaust=self.exhaust, minz=self.minz, nohard=True, trim=self.trim) elif self.htype == 'lbx': self.oracle = LBX(formula, solver_name=self.solver, use_cld=self.usecld) else: self.oracle = MCSls(formula, solver_name=self.solver, use_cld=self.usecld)
def generate_musx_mus(contrastive_sat_rmp, J): wcnf = WCNF() for i in range(len(contrastive_sat_rmp.clauses)): if i in contrastive_sat_rmp.comparaison_to_clause[J]: wcnf.append(contrastive_sat_rmp.clauses[i]) else: wcnf.append(contrastive_sat_rmp.clauses[i], weight=1) musx = MUSX(wcnf, verbosity=0) mus = musx.compute() return mus
def get_MCS(KBa_s, KBa_h, q, seed, clauses_dict): # Compute minimal hitting set wcnf = WCNF() for c in KBa_s: if c not in seed: # don't add to the soft clauses those in the seed wcnf.append(c, weight=1) for c in KBa_h: wcnf.append(c) for c in seed: # add clauses in the seed as hard if any(isinstance(el, list) for el in c): for cs in c: wcnf.append(cs) else: wcnf.append(c) wcnf.extend(q.negate().clauses) lbx = LBX(wcnf, use_cld=True, solver_name='g3') # Compute mcs and return the clauses indexes mcs = lbx.compute() # Current mcs is computed w.r.t. the soft clauses excluding the seed. Below we find the corresponding indexes of these clauses in KBa_s temp_cl_lookup = create_clauses_lookup(wcnf.soft) clauses = get_clauses_from_index(mcs, temp_cl_lookup) mcs = get_index_from_clauses(clauses, clauses_dict) return mcs
def optimize(self, enc): """ Try to optimize the solution with a MaxSAT solver. """ # all d0 and d1 variables (for computing the complement --- MSS) all_vars = set([]) # MaxSAT formula to work with formula = WCNF() # hard clauses for cl in enc.clauses: formula.append(cl) for j in range(1, self.nof_terms + 1): for r in range(1, self.nof_feats + 1): formula.append([-self.dvar1(j, r)], 1) formula.append([-self.dvar0(j, r)], 1) all_vars.add(self.dvar1(j, r)) all_vars.add(self.dvar0(j, r)) if self.options.approx: hitman = LBX(formula, use_cld=self.options.use_cld, solver_name=self.options.solver) hses = [] for i, hs in enumerate(hitman.enumerate()): hitman.block(hs) hses.append(hs) if i + 1 == self.options.approx: break hs = list(map(lambda v: -formula.soft[v - 1][0], min(hses, key=lambda x: len(x)))) hitman.delete() else: hitman = RC2(formula, solver=self.options.solver, adapt=True, exhaust=True, incr=False, minz=False, trim=self.options.trim) hs = list(filter(lambda v: v > 0 and v in all_vars, hitman.compute())) hitman.delete() return sorted([-v for v in all_vars.difference(set(hs))])
def gen_constraint_conflict_courses(idpool: IDPool, id2varmap, courses: tCourses) -> WCNF: """ Generate a constraint that two conflicting courses can not share TAs""" wcnf = WCNF() conflict_courses = compute_conflict_courses(courses) for course in conflict_courses.keys(): for ccourse in conflict_courses[course]: for t in courses[course].tas_available: if t in courses[ccourse].tas_available: t1 = tuple((course, t)) t2 = tuple((ccourse, t)) id1 = idpool.id(t1) id2 = idpool.id(t2) if t1 not in id2varmap.keys(): id2varmap[t1] = id1 if t2 not in id2varmap.keys(): id2varmap[t2] = id2 wcnf.append([-id1, -id2]) return wcnf
def init(self, bootstrap_with, costs): """ This method serves for initializing the hitting set solver with a given list of sets to hit. Concretely, the hitting set problem is encoded into partial MaxSAT as outlined above, which is then fed either to a MaxSAT solver or an MCS enumerator. :param bootstrap_with: input set of sets to hit :type bootstrap_with: iterable(iterable(obj)) """ # formula encoding the sets to hit formula = WCNF() # hard clauses for to_hit in bootstrap_with: to_hit = list(map(lambda obj: self.idpool.id(obj), to_hit)) formula.append(to_hit) # soft clauses for obj_id in six.iterkeys(self.idpool.id2obj): # this is saying that not including a clause is given a weight of x # maxSAT is MAXIMISING the sum of satisfied soft clauses, so to minimise sum, # we want to weight *not* including something (hence the -obj_id) # this means words such as <PAD> should be given a *higher* weight, so the # solver decides that NOT including <PAD> is more worth it than not including # a more "meaningful" word cost = costs[obj_id - 1] formula.append([-obj_id], weight=cost) if self.htype == 'rc2': # using the RC2-A options from MaxSAT evaluation 2018 self.oracle = RC2(formula, solver=self.solver, adapt=False, exhaust=True, trim=5) elif self.htype == 'lbx': self.oracle = LBX(formula, solver_name=self.solver, use_cld=True) else: self.oracle = MCSls(formula, solver_name=self.solver, use_cld=True)
def generate_wcnfs(path, models_and_contexts): for i, elem in enumerate(models_and_contexts): model = elem["model"] contexts = elem["contexts"] wcnf = WCNF() for weight_clause in model: if weight_clause[0] == None: wcnf.append(tuple(weight_clause[1])) else: wcnf.append(tuple(weight_clause[1]), weight=weight_clause[0]) wcnf.to_file(path + f"_{i}.wcnf") for j, context in enumerate(contexts): wcnf_context = wcnf.copy() # print(context) for literals in context: wcnf_context.append((literals,)) wcnf_context.to_file(path + f"_{i}_context_{j}.wcnf")
def optimize(self, formula, model): """ Try to optimize the solution with a MaxSAT solver. """ MaxSAT = RC2Stratified if self.options.weighted else RC2 formula_new = WCNF() formula_new.extend(formula.hard) # hardening the soft clauses based on the model for j in range(1, self.nof_terms + 1): formula_new.append([model[self.unused(j)]]) for lb in self.labels: for q in self.samps[lb]: formula_new.append([model[self.miss(q + 1)]]) for j in range(1, self.nof_terms + 1): for r in range(1, self.nof_feats + 1): formula_new.append([-self.dvar1(j, r)], weight=1) formula_new.append([-self.dvar0(j, r)], weight=1) with MaxSAT( formula_new, solver=self.options.solver, adapt=self.options.am1, exhaust=self.options.exhaust, minz=self.options.minz, trim=self.options.trim, ) as rc2: model = rc2.compute() return model
def solve_weighted_max_sat(n: int, model: MaxSatModel, context: Clause, num_sol, prev_sol=[]): """ Solves a MaxSatModel and tries to return num_sol optimal solutions """ c = WCNF() c.nv = n for w, clause in model: # c.append(list(map(int, list(clause))), weight=w) if w != 0 and len(clause) > 0: c.append(list(map(int, list(clause))), weight=w) if context and len(context) > 0: # c.append(list(map(int, list(context))), weight=None) # c.append(list(map(int, list(context)))) c.hard.extend([[int(c)] for c in context]) s = RC2(c) sol = [] cst = -1 for m in s.enumerate(): # while len(m) < n: # m.append(len(m) + 1) if cst < 0: cst = s.cost # print(s.cost, cst, len(sol), num_sol) if s.cost > cst or len(sol) >= num_sol: break m = [v > 0 for v in m] if m not in prev_sol: sol.append(m) if len(sol) >= num_sol: break if num_sol == 1 and sol: return sol[0], cst return sol, cst
def correct_KB(KB1, KB2): Diff = [ list(x) for x in set(map(tuple, KB1.clauses)).difference( set(map(tuple, KB2.clauses))) ] KB2_s = [ list(x) for x in set(map(tuple, KB2.clauses)).difference( set(map(tuple, KB1.clauses))) ] KB2_h = [ list(x) for x in set(map(tuple, KB2.clauses)).intersection( set(map(tuple, KB1.clauses))) ] wcnf = WCNF() for c in KB2_s: wcnf.append(c, weight=1) for c in KB2_h: wcnf.append(c) for c in Diff: wcnf.append(c) lbx = LBX(wcnf, use_cld=True, solver_name='g3') # Compute mcs and return the clauses indexes mcs = lbx.compute() temp_cl_lookup = create_clauses_lookup(wcnf.soft) clauses = get_clauses_from_index(mcs, temp_cl_lookup) return clauses
def generate_contexts(model: MaxSatModel, num_context, num_constraints, num_vars, rng): wcnf = WCNF() for clauses in model: # print(clauses[1]) wcnf.append(tuple(clauses[1])) contexts = [] # n=0 for n in range(num_context): context = set() if num_constraints == 0: num_constraints = rng.randint(1, 2 * num_vars) literals = [] for i in range(1, 1 + num_vars): literals.append({i}) literals.append({-i}) # print(literals) indices = get_random_clauses(wcnf, rng, literals, num_constraints) for j in indices: context |= literals[j] contexts.append(context) # print(num_vars, contexts) # exit() return contexts
def get_MUS(KB, e, q): # Compute minimal unsatisfiable set wcnf2 = WCNF() for k in e: if any(isinstance(el, list) for el in k): for ks in k: wcnf2.append(ks, weight=1) else: wcnf2.append(k, weight=1) if KB: for c in KB.clauses: wcnf2.append(c, weight=1) wcnf2.extend((q.negate().clauses)) mmusx = MUSX(wcnf2, verbosity=0) mus = mmusx.compute() return [list(wcnf2.soft[m - 1]) for m in mus]
class RTSS: nOfTaxi = 0 newDemandSize = 0 capacityOfEachTaxi = [] noListOfPickDrop = [ ] # sorted (pair adjoining) future via points list of each taxi noListOfCarried = [] noListOfAcceptedPoint = [] currenTime = 10 deadlineList = [ ] # assume that all pick-up points have no deadline request deadlineOfNewDemand = [] cosTimeMatrices = [ ] # note that, the given symmetric cost time matrices have NOT been verified for any Euclidean axioms (such as triangle inequality) varID = 0 maxWidthOfNet = 0 conNet = [] rchNet = [] wcnf = None learntClause = [] # use for debug def __init__(self): self.nOfTaxi = 3 self.newDemandSize = 2 self.capacityOfEachTaxi = [3, 3, 3] self.noListOfPickDrop = [[1, -1], [1, -1, -2], [-3]] for i in range(len(self.noListOfPickDrop)): self.noListOfCarried.append(-1 * sum(self.noListOfPickDrop[i])) for i in range(len(self.noListOfPickDrop)): self.noListOfAcceptedPoint.append(len(self.noListOfPickDrop[i])) self.currenTime = 10 self.deadlineList = [[self.currenTime, 40], [self.currenTime, 30, 60], [20]] self.deadlineOfNewDemand = [self.currenTime, 90] self.cosTimeMatrices = [[[0, 13, 54, 21, 46], [13, 0, 29, 18, 64], [54, 29, 0, 37, 25], [21, 18, 37, 0, 34], [46, 64, 25, 34, 0]], [[0, 11, 38, 62, 19, 57], [11, 0, 27, 45, 36, 49], [38, 27, 0, 48, 65, 40], [62, 45, 48, 0, 21, 31], [19, 36, 65, 21, 0, 34], [57, 49, 40, 31, 34, 0]], [[0, 8, 28, 69], [8, 0, 31, 52], [28, 31, 0, 34], [69, 52, 34, 0]]] self.maxWidthOfNet = 3 + max(self.noListOfAcceptedPoint) self.conNet = [[[0] * self.maxWidthOfNet for i in range(self.maxWidthOfNet)] for j in range(self.nOfTaxi)] self.rchNet = [[[0] * self.maxWidthOfNet for i in range(self.maxWidthOfNet)] for j in range(self.nOfTaxi)] self.wcnf = WCNF() def newVarID(self): self.varID += 1 return self.varID def isRequiredVar(self, k, row, column): if row == 0 or row == column: return False elif row == 1 + self.noListOfAcceptedPoint[k] and column == 1 + row: return False elif row > 0 and row < self.noListOfAcceptedPoint[ k] and self.noListOfPickDrop[k][row - 1] > 0 and column == 1 + row: return False else: return True def genVarForConNet(self): for k in range(self.nOfTaxi): for i in range(3 + self.noListOfAcceptedPoint[k]): for j in range(3 + self.noListOfAcceptedPoint[k]): if self.isRequiredVar(k, i, j): self.conNet[k][i][j] = self.newVarID() def genVarForRchNet(self): for k in range(self.nOfTaxi): for i in range(1 + self.noListOfAcceptedPoint[k]): for j in range(1 + i, 3 + self.noListOfAcceptedPoint[k]): if self.isRequiredVar(k, i, j): self.rchNet[k][i][j] = self.newVarID() for j in range(1, self.noListOfAcceptedPoint[k]): for i in range(1 + j, 1 + self.noListOfAcceptedPoint[k]): if self.isRequiredVar(k, j, i): self.rchNet[k][i][j] = -1 * self.rchNet[k][j][i] else: self.rchNet[k][i][j] = self.newVarID() for i in range(1 + self.noListOfAcceptedPoint[k], 3 + self.noListOfAcceptedPoint[k]): for j in range(3 + self.noListOfAcceptedPoint[k]): if self.isRequiredVar(k, i, j): self.rchNet[k][i][j] = self.newVarID() def netPrinter(self, net): # function for debug for k in range(self.nOfTaxi): for i in range(3 + self.noListOfAcceptedPoint[k]): print(net[k][i][0:3 + self.noListOfAcceptedPoint[k]]) print('\n') def genSoftClause(self): for k in range(self.nOfTaxi): for i in range(3 + self.noListOfAcceptedPoint[k]): for j in range(3 + self.noListOfAcceptedPoint[k]): if self.isRequiredVar(k, i, j): self.wcnf.append([ (-1 * self.rchNet[k][2 + self.noListOfAcceptedPoint[k]][0]), (-1 * self.conNet[k][i][j]) ], weight=self.cosTimeMatrices[k][i][j]) def genHardClauseForImplicationRule(self): for k in range(self.nOfTaxi): for i in range(3 + self.noListOfAcceptedPoint[k]): for j in range(3 + self.noListOfAcceptedPoint[k]): if self.isRequiredVar( k, i, j) and (i > self.noListOfAcceptedPoint[k] or j != 0): self.wcnf.append([(-1 * self.conNet[k][i][j]), self.rchNet[k][i][j]]) def isTautologyVar(self, k, row, column): if column == 0 and row >= 1 and row <= self.noListOfAcceptedPoint[k]: return True else: return False def instinctLiteral(self, net, k, row, column, sign, isConNet): if sign and self.isRequiredVar(k, row, column): return net[k][row][column] elif isConNet and (not sign): return (-1 * net[k][row][column]) elif (not isConNet) and (not sign) and (not self.isTautologyVar( k, row, column)): return (-1 * net[k][row][column]) else: return 0 def genHardClauseForChainTransitionLaw(self): for k in range(self.nOfTaxi): for a in range(1 + self.noListOfAcceptedPoint[k]): for b in range(1 + a, 2 + self.noListOfAcceptedPoint[k]): for c in range(1 + b, 3 + self.noListOfAcceptedPoint[k]): # correspond to ¬rchNet[k][b][a] ∨ ¬rchNet[k][c][b] ∨ rchNet[k][c][a] if self.isRequiredVar(k, b, a) and self.isRequiredVar( k, c, b) and (not self.isTautologyVar(k, c, a)): literaList = [ self.instinctLiteral(self.rchNet, k, b, a, False, False), self.instinctLiteral(self.rchNet, k, c, b, False, False), self.instinctLiteral(self.rchNet, k, c, a, True, False) ] self.wcnf.append( filter(lambda elm: elm != 0, literaList)) #print(filter(lambda elm: elm != 0, literaList)) # correspond to ¬rchNet[k][b][a] ∨ ¬rchNet[k][c][b] ∨ ¬conNet[k][c][a] if self.isRequiredVar(k, b, a) and self.isRequiredVar( k, c, b) and self.isRequiredVar(k, c, a): literaList = [ self.instinctLiteral(self.rchNet, k, b, a, False, False), self.instinctLiteral(self.rchNet, k, c, b, False, False), self.instinctLiteral(self.conNet, k, c, a, False, True) ] self.wcnf.append( filter(lambda elm: elm != 0, literaList)) #print(filter(lambda elm: elm != 0, literaList)) # correspond to ¬rchNet[k][b][c] ∨ ¬rchNet[k][a][b] ∨ rchNet[k][a][c] if self.isRequiredVar(k, b, c) and self.isRequiredVar( k, a, b) and (not self.isTautologyVar(k, a, c)): literaList = [ self.instinctLiteral(self.rchNet, k, b, c, False, False), self.instinctLiteral(self.rchNet, k, a, b, False, False), self.instinctLiteral(self.rchNet, k, a, c, True, False) ] self.wcnf.append( filter(lambda elm: elm != 0, literaList)) #print(filter(lambda elm: elm != 0, literaList)) # correspond to ¬rchNet[k][b][c] ∨ ¬rchNet[k][a][b] ∨ ¬conNet[k][a][c] if self.isRequiredVar(k, b, c) and self.isRequiredVar( k, a, b) and self.isRequiredVar(k, a, c): literaList = [ self.instinctLiteral(self.rchNet, k, b, c, False, False), self.instinctLiteral(self.rchNet, k, a, b, False, False), self.instinctLiteral(self.conNet, k, a, c, False, True) ] self.wcnf.append( filter(lambda elm: elm != 0, literaList)) #print(filter(lambda elm: elm != 0, literaList)) # correspond to ¬rchNet[k][c][a] ∨ ¬rchNet[k][b][c] ∨ rchNet[k][b][a] if self.isRequiredVar(k, c, a) and self.isRequiredVar( k, b, c) and (not self.isTautologyVar(k, b, a)): literaList = [ self.instinctLiteral(self.rchNet, k, c, a, False, False), self.instinctLiteral(self.rchNet, k, b, c, False, False), self.instinctLiteral(self.rchNet, k, b, a, True, False) ] self.wcnf.append( filter(lambda elm: elm != 0, literaList)) #print(filter(lambda elm: elm != 0, literaList)) # correspond to ¬rchNet[k][c][a] ∨ ¬rchNet[k][b][c] ∨ ¬conNet[k][b][a] if self.isRequiredVar(k, c, a) and self.isRequiredVar( k, b, c) and self.isRequiredVar(k, b, a): literaList = [ self.instinctLiteral(self.rchNet, k, c, a, False, False), self.instinctLiteral(self.rchNet, k, b, c, False, False), self.instinctLiteral(self.conNet, k, b, a, False, True) ] self.wcnf.append( filter(lambda elm: elm != 0, literaList)) #print(filter(lambda elm: elm != 0, literaList)) # correspond to ¬rchNet[k][c][b] ∨ ¬rchNet[k][a][c] ∨ rchNet[k][a][b] if self.isRequiredVar(k, c, b) and self.isRequiredVar( k, a, c) and (not self.isTautologyVar(k, a, b)): literaList = [ self.instinctLiteral(self.rchNet, k, c, b, False, False), self.instinctLiteral(self.rchNet, k, a, c, False, False), self.instinctLiteral(self.rchNet, k, a, b, True, False) ] self.wcnf.append( filter(lambda elm: elm != 0, literaList)) #print(filter(lambda elm: elm != 0, literaList)) # correspond to ¬rchNet[k][c][b] ∨ ¬rchNet[k][a][c] ∨ ¬conNet[k][a][b] if self.isRequiredVar(k, c, b) and self.isRequiredVar( k, a, c) and self.isRequiredVar(k, a, b): literaList = [ self.instinctLiteral(self.rchNet, k, c, b, False, False), self.instinctLiteral(self.rchNet, k, a, c, False, False), self.instinctLiteral(self.conNet, k, a, b, False, True) ] self.wcnf.append( filter(lambda elm: elm != 0, literaList)) #print(filter(lambda elm: elm != 0, literaList)) if not (a >= 1 and c <= self.noListOfAcceptedPoint[k]): # correspond to ¬rchNet[k][a][b] ∨ ¬rchNet[k][c][a] ∨ rchNet[k][c][b] if self.isRequiredVar( k, a, b) and self.isRequiredVar( k, c, a) and (not self.isTautologyVar( k, c, b)): literaList = [ self.instinctLiteral( self.rchNet, k, a, b, False, False), self.instinctLiteral( self.rchNet, k, c, a, False, False), self.instinctLiteral( self.rchNet, k, c, b, True, False) ] self.wcnf.append( filter(lambda elm: elm != 0, literaList)) #print(filter(lambda elm: elm != 0, literaList)) # correspond to ¬rchNet[k][a][c] ∨ ¬rchNet[k][b][a] ∨ rchNet[k][b][c] if self.isRequiredVar( k, a, c) and self.isRequiredVar( k, b, a) and (not self.isTautologyVar( k, b, c)): literaList = [ self.instinctLiteral( self.rchNet, k, a, c, False, False), self.instinctLiteral( self.rchNet, k, b, a, False, False), self.instinctLiteral( self.rchNet, k, b, c, True, False) ] self.wcnf.append( filter(lambda elm: elm != 0, literaList)) #print(filter(lambda elm: elm != 0, literaList)) # correspond to ¬rchNet[k][a][b] ∨ ¬rchNet[k][c][a] ∨ ¬conNet[k][c][b] if self.isRequiredVar(k, a, b) and self.isRequiredVar( k, c, a) and self.isRequiredVar(k, c, b): literaList = [ self.instinctLiteral(self.rchNet, k, a, b, False, False), self.instinctLiteral(self.rchNet, k, c, a, False, False), self.instinctLiteral(self.conNet, k, c, b, False, True) ] self.wcnf.append( filter(lambda elm: elm != 0, literaList)) #print(filter(lambda elm: elm != 0, literaList)) # correspond to ¬rchNet[k][a][c] ∨ ¬rchNet[k][b][a] ∨ ¬conNet[k][b][c] if self.isRequiredVar(k, a, c) and self.isRequiredVar( k, b, a) and self.isRequiredVar(k, b, c): literaList = [ self.instinctLiteral(self.rchNet, k, a, c, False, False), self.instinctLiteral(self.rchNet, k, b, a, False, False), self.instinctLiteral(self.conNet, k, b, c, False, True) ] self.wcnf.append( filter(lambda elm: elm != 0, literaList)) #print(filter(lambda elm: elm != 0, literaList)) def genHardClauseForConfluenceLaw(self): for k in range(self.nOfTaxi): for a in range(1 + self.noListOfAcceptedPoint[k]): for b in range(1 + a, 2 + self.noListOfAcceptedPoint[k]): for c in range(1 + b, 3 + self.noListOfAcceptedPoint[k]): # correspond to ¬rchNet[k][a][b] ∨ ¬rchNet[k][a][c] ∨ rchNet[k][c][b] ∨ rchNet[k][b][c] if (not c <= self.noListOfAcceptedPoint[k] ) and self.isRequiredVar( k, a, b) and self.isRequiredVar(k, a, c) and ( not self.isTautologyVar(k, c, b)) and ( not self.isTautologyVar(k, b, c)): literaList = [ self.instinctLiteral(self.rchNet, k, a, b, False, False), self.instinctLiteral(self.rchNet, k, a, c, False, False), self.instinctLiteral(self.rchNet, k, c, b, True, False), self.instinctLiteral(self.rchNet, k, b, c, True, False) ] self.wcnf.append( filter(lambda elm: elm != 0, literaList)) #print(filter(lambda elm: elm != 0, literaList)) # correspond to ¬rchNet[k][b][a] ∨ ¬rchNet[k][b][c] ∨ rchNet[k][c][a] ∨ rchNet[k][a][c] if (not (a >= 1 and c <= self.noListOfAcceptedPoint[k]) ) and self.isRequiredVar( k, b, a) and self.isRequiredVar(k, b, c) and ( not self.isTautologyVar(k, c, a)) and ( not self.isTautologyVar(k, a, c)): literaList = [ self.instinctLiteral(self.rchNet, k, b, a, False, False), self.instinctLiteral(self.rchNet, k, b, c, False, False), self.instinctLiteral(self.rchNet, k, c, a, True, False), self.instinctLiteral(self.rchNet, k, a, c, True, False) ] self.wcnf.append( filter(lambda elm: elm != 0, literaList)) #print(filter(lambda elm: elm != 0, literaList)) # correspond to ¬rchNet[k][c][a] ∨ ¬rchNet[k][c][b] ∨ rchNet[k][b][a] ∨ rchNet[k][a][b] if (not (a >= 1 and b <= self.noListOfAcceptedPoint[k]) ) and self.isRequiredVar( k, c, a) and self.isRequiredVar(k, c, b) and ( not self.isTautologyVar(k, b, a)) and ( not self.isTautologyVar(k, a, b)): literaList = [ self.instinctLiteral(self.rchNet, k, c, a, False, False), self.instinctLiteral(self.rchNet, k, c, b, False, False), self.instinctLiteral(self.rchNet, k, b, a, True, False), self.instinctLiteral(self.rchNet, k, a, b, True, False) ] self.wcnf.append( filter(lambda elm: elm != 0, literaList)) #print(filter(lambda elm: elm != 0, literaList)) def genHardClauseForRamificationLaw(self): for k in range(self.nOfTaxi): for a in range(1 + self.noListOfAcceptedPoint[k]): for b in range(1 + a, 2 + self.noListOfAcceptedPoint[k]): for c in range(1 + b, 3 + self.noListOfAcceptedPoint[k]): # correspond to ¬rchNet[k][b][a] ∨ ¬rchNet[k][c][a] ∨ rchNet[k][c][b] ∨ rchNet[k][b][c] if (not c <= self.noListOfAcceptedPoint[k] ) and self.isRequiredVar( k, b, a) and self.isRequiredVar(k, c, a) and ( not self.isTautologyVar(k, c, b)) and ( not self.isTautologyVar(k, b, c)): literaList = [ self.instinctLiteral(self.rchNet, k, b, a, False, False), self.instinctLiteral(self.rchNet, k, c, a, False, False), self.instinctLiteral(self.rchNet, k, c, b, True, False), self.instinctLiteral(self.rchNet, k, b, c, True, False) ] self.wcnf.append( filter(lambda elm: elm != 0, literaList)) #print(filter(lambda elm: elm != 0, literaList)) # correspond to ¬rchNet[k][a][b] ∨ ¬rchNet[k][c][b] ∨ rchNet[k][c][a] ∨ rchNet[k][a][c] if (not (a >= 1 and c <= self.noListOfAcceptedPoint[k]) ) and self.isRequiredVar( k, a, b) and self.isRequiredVar(k, c, b) and ( not self.isTautologyVar(k, c, a)) and ( not self.isTautologyVar(k, a, c)): literaList = [ self.instinctLiteral(self.rchNet, k, a, b, False, False), self.instinctLiteral(self.rchNet, k, c, b, False, False), self.instinctLiteral(self.rchNet, k, c, a, True, False), self.instinctLiteral(self.rchNet, k, a, c, True, False) ] self.wcnf.append( filter(lambda elm: elm != 0, literaList)) #print(filter(lambda elm: elm != 0, literaList)) # correspond to ¬rchNet[k][a][c] ∨ ¬rchNet[k][b][c] ∨ rchNet[k][b][a] ∨ rchNet[k][a][b] if (not (a >= 1 and b <= self.noListOfAcceptedPoint[k]) ) and self.isRequiredVar( k, a, c) and self.isRequiredVar(k, b, c) and ( not self.isTautologyVar(k, b, a)) and ( not self.isTautologyVar(k, a, b)): literaList = [ self.instinctLiteral(self.rchNet, k, a, c, False, False), self.instinctLiteral(self.rchNet, k, b, c, False, False), self.instinctLiteral(self.rchNet, k, b, a, True, False), self.instinctLiteral(self.rchNet, k, a, b, True, False) ] self.wcnf.append( filter(lambda elm: elm != 0, literaList)) #print(filter(lambda elm: elm != 0, literaList)) def genHardClauseForAcyclicLaw(self): for k in range(self.nOfTaxi): for a in range(2 + self.noListOfAcceptedPoint[k]): for b in range(1 + a, 3 + self.noListOfAcceptedPoint[k]): # correspond to ¬rchNet[k][b][a] ∨ ¬rchNet[k][a][b] if (not (a >= 1 and b <= self.noListOfAcceptedPoint[k]) ) and self.isRequiredVar( k, b, a) and self.isRequiredVar(k, a, b): self.wcnf.append([(-1 * self.rchNet[k][b][a]), (-1 * self.rchNet[k][a][b])]) def atLeastOne(self, varList): self.wcnf.append(varList) def genHardClauseForEq6(self): for k in range(self.nOfTaxi): for i in range(1, 1 + self.noListOfAcceptedPoint[k]): varList = [] for j in range(0, 3 + self.noListOfAcceptedPoint[k]): if self.isRequiredVar(k, i, j): varList.append(self.conNet[k][i][j]) self.atLeastOne(varList) def genHardClauseForEq7(self): for k in range(self.nOfTaxi): for i in range(1, 1 + self.noListOfAcceptedPoint[k]): if self.noListOfPickDrop[k][i - 1] > 0: varList = [] for j in range(1, 3 + self.noListOfAcceptedPoint[k]): if self.isRequiredVar(k, j, i): varList.append(self.conNet[k][j][i]) self.atLeastOne(varList) def atMostOne(self, varList): for i in range(len(varList)): for j in range(1 + i, len(varList)): self.wcnf.append([(-1 * varList[i]), (-1 * varList[j])]) def exactlyOne(self, varList): self.atMostOne(varList) self.atLeastOne(varList) def genHardClauseForEq8(self): varList = [] for k in range(self.nOfTaxi): for i in range(3 + self.noListOfAcceptedPoint[k]): if self.isRequiredVar(k, 1 + self.noListOfAcceptedPoint[k], i): varList.append( self.conNet[k][1 + self.noListOfAcceptedPoint[k]][i]) self.exactlyOne(varList) def genHardClauseForEq9(self): varList = [] for k in range(self.nOfTaxi): for i in range(3 + self.noListOfAcceptedPoint[k]): if self.isRequiredVar(k, 2 + self.noListOfAcceptedPoint[k], i): varList.append( self.conNet[k][2 + self.noListOfAcceptedPoint[k]][i]) self.exactlyOne(varList) def genHardClauseForEq10(self): varList = [] for k in range(self.nOfTaxi): for i in range(1, 3 + self.noListOfAcceptedPoint[k]): if self.isRequiredVar(k, i, 1 + self.noListOfAcceptedPoint[k]): varList.append( self.conNet[k][i][1 + self.noListOfAcceptedPoint[k]]) self.exactlyOne(varList) def genHardClauseForEq11(self): varList = [] for k in range(self.nOfTaxi): for i in range(1, 3 + self.noListOfAcceptedPoint[k]): if self.isRequiredVar(k, i, 2 + self.noListOfAcceptedPoint[k]): varList.append( self.conNet[k][i][2 + self.noListOfAcceptedPoint[k]]) self.atMostOne(varList) def genHardClauseForEq12(self): for k in range(self.nOfTaxi): if self.noListOfAcceptedPoint[k] != 0: varList = [] for i in range(1, 3 + self.noListOfAcceptedPoint[k]): if self.isRequiredVar(k, i, 0): varList.append(self.conNet[k][i][0]) self.atLeastOne(varList) def genHardClauseForEq16(self): for k in range(self.nOfTaxi): for i in range(1, 1 + self.noListOfAcceptedPoint[k]): if self.noListOfPickDrop[k][i - 1] > 0: self.wcnf.append([self.rchNet[k][i + 1][i]]) def genHardClauseForEqs17And18(self): for k in range(self.nOfTaxi): self.wcnf.append([ (-1 * self.rchNet[k][1 + self.noListOfAcceptedPoint[k]][0]), self.rchNet[k][2 + self.noListOfAcceptedPoint[k]][ 1 + self.noListOfAcceptedPoint[k]] ]) self.wcnf.append([ (-1 * self.rchNet[k][2 + self.noListOfAcceptedPoint[k]][0]), self.rchNet[k][2 + self.noListOfAcceptedPoint[k]][ 1 + self.noListOfAcceptedPoint[k]] ]) def genHardClauseForEq19(self): varList = [] for k in range(self.nOfTaxi): varList.append(self.rchNet[k][2 + self.noListOfAcceptedPoint[k]][ 1 + self.noListOfAcceptedPoint[k]]) self.atMostOne(varList) def getLastVarIDinConNet(self): k = self.nOfTaxi - 1 row = 2 + self.noListOfAcceptedPoint[k] column = row - 1 return self.conNet[k][row][column] def fromTo(self, k, column): listOfCandidateMove = [] for row in range(1, 3 + self.noListOfAcceptedPoint[k]): listOfCandidateMove.append(self.conNet[k][row][column]) return listOfCandidateMove def decodeAllModels(self, model): listOfRoute = [] for k in range(self.nOfTaxi): listOFromTo = [0] listOfCandidateMove = self.fromTo(k, 0) while len(listOfCandidateMove) != 0: for i in range(len(listOfCandidateMove)): if listOfCandidateMove[i] in model: listOFromTo.append(1 + i) listOfCandidateMove = self.fromTo(k, 1 + i) break elif i == len(listOfCandidateMove) - 1: listOfCandidateMove = [] listOfRoute.append(listOFromTo) print(listOfRoute) return listOfRoute def decodeModel(self, model): for k in range(self.nOfTaxi): listOfCandidateMove = filter( lambda elm: elm != 0, self.conNet[k][1 + self.noListOfAcceptedPoint[k]]) for i in range(len(listOfCandidateMove)): if listOfCandidateMove[i] in model: return (k, self.decodeAllModels(model)[k]) def checkExCondition(self, taxID, route): isViolate = False sumDelay = 0 sumCarried = self.noListOfCarried[taxID] reasoNegation = [] exNoListOfPickDrop = [0] + self.noListOfPickDrop[taxID] + [ self.newDemandSize, -1 * self.newDemandSize ] exDeadlineList = [ self.currenTime ] + self.deadlineList[taxID] + self.deadlineOfNewDemand for i in range(len(route) - 1): reasoNegation.append(-1 * self.conNet[taxID][route[1 + i]][route[i]]) # checking for deadline contraints sumDelay += self.cosTimeMatrices[taxID][route[1 + i]][route[i]] if exNoListOfPickDrop[route[1 + i]] < 0: if sumDelay > (exDeadlineList[route[1 + i]] - self.currenTime): isViolate = True break elif exNoListOfPickDrop[route[1 + i]] > 0: if sumDelay < (exDeadlineList[route[1 + i]] - self.currenTime): isViolate = True break # checking for capacity constraints sumCarried += exNoListOfPickDrop[route[1 + i]] if sumCarried > self.capacityOfEachTaxi[taxID]: isViolate = True break return (isViolate, reasoNegation) def writExternalityFile(self): externalityFile = open('externality.txt', 'w') externalityFile.write('nOfTaxi %d' % self.nOfTaxi) externalityFile.write('\nnewDemandSize %d' % self.newDemandSize) externalityFile.write('\ncapacityOfEachTaxi') for i in range(len(self.capacityOfEachTaxi)): externalityFile.write(' %d' % self.capacityOfEachTaxi[i]) externalityFile.write('\nnoListOfCarried') for i in range(len(self.noListOfCarried)): externalityFile.write(' %d' % self.noListOfCarried[i]) externalityFile.write('\nnoListOfAcceptedPoint') for i in range(len(self.noListOfAcceptedPoint)): externalityFile.write(' %d' % self.noListOfAcceptedPoint[i]) externalityFile.write('\nnoListOfPickDrop') for i in range(len(self.noListOfPickDrop)): for j in range(len(self.noListOfPickDrop[i])): externalityFile.write(' %d' % self.noListOfPickDrop[i][j]) externalityFile.write('\ncurrenTime %d' % self.currenTime) externalityFile.write('\ndeadlineList') for i in range(len(self.deadlineList)): for j in range(len(self.deadlineList[i])): externalityFile.write(' %d' % self.deadlineList[i][j]) externalityFile.write( '\ndeadlineOfNewDemand %d %d' % (self.deadlineOfNewDemand[0], self.deadlineOfNewDemand[1])) externalityFile.close() def solveRTSS(self, rc2): unviolatedModel = None model = rc2.compute() while model != None: model = filter( lambda elm: (elm > 0 and elm <= self.getLastVarIDinConNet()), model) #print(model) taxID, route = self.decodeModel(model) print(taxID, route, rc2.cost) isViolate, reasoNegation = self.checkExCondition(taxID, route) #print('reNeg', reasoNegation) #print('violate', isViolate) if isViolate: rc2.add_clause(reasoNegation) self.learntClause.append(reasoNegation) model = rc2.compute() else: unviolatedModel = model break return unviolatedModel
def encode(self, label, nof_terms=1): """ Encode the problem of computing a DS of size nof_terms. """ self.nof_terms = nof_terms enc = WCNF() # all the hard clauses # # constraint 6 (relaxed with the unused variable) for j in range(1, self.nof_terms + 1): for r in range(1, self.nof_feats + 1): enc.append([-self.unused(j), self.svar(j, r)]) enc.append( [self.unused(j)] + [-self.svar(j, r) for r in range(1, self.nof_feats + 1)]) # sort unused rules for j in range(1, self.nof_terms): enc.append([-self.unused(j), self.unused(j + 1)]) # constraint 7 for j in range(1, self.nof_terms + 1): for r in range(1, self.nof_feats + 1): d0 = self.dvar0(j, r) p0 = [-self.svar(j, r), self.lvar(j, r)] enc.append([d0, -p0[0], -p0[1]]) enc.append([-d0, p0[0]]) enc.append([-d0, p0[1]]) d1 = self.dvar1(j, r) p1 = [-self.svar(j, r), -self.lvar(j, r)] enc.append([d1, -p1[0], -p1[1]]) enc.append([-d1, p1[0]]) enc.append([-d1, p1[1]]) # constraint 8 if len(self.labels) == 1: # distinguish one class from all the others other_labels = set(self.samps.keys()) else: # distinguish the classes under question only other_labels = set(self.labels) other_labels.remove(label) other_labels = sorted(other_labels) for j in range(1, self.nof_terms + 1): for lb in other_labels: for q in self.samps[lb]: cl = [self.unused(j), self.miss(q + 1)] # the clause is relaxed shift = 0 for r in range(1, self.nof_feats + 1): if r - 1 in self.data.vmiss[q]: # this feature is missing in q'th sample cl.append(-self.svar(j, r)) shift += 1 elif self.data.samps[q][r - 1 - shift] > 0: cl.append(self.dvar1(j, r)) else: cl.append(self.dvar0(j, r)) enc.append(cl) # constraint 9 for j in range(1, self.nof_terms + 1): for q in self.samps[label]: cr = self.crvar(j, q + 1) cl = [self.unused(j)] shift = 0 for r in range(1, self.nof_feats + 1): if r - 1 in self.data.vmiss[q]: # this feature is missing in q'th sample cl.append(-self.svar(j, r)) shift += 1 elif self.data.samps[q][r - 1 - shift] > 0: cl.append(self.dvar1(j, r)) else: cl.append(self.dvar0(j, r)) enc.append([cr] + cl) for l in cl: enc.append([-cr, -l]) # constraint 10 for q in self.samps[label]: enc.append( [self.miss(q + 1)] + [self.crvar(j, q + 1) for j in range(1, self.nof_terms + 1)]) # at most one value can be chosen for a feature for feats in six.itervalues(self.ffmap.dir): if len(feats) > 2: for j in range(1, self.nof_terms + 1): lits = [self.dvar0(j, r + 1) for r in feats] # atmost1 can be true onev = CardEnc.atmost(lits, top_id=enc.nv, encoding=self.options.enc) enc.extend(onev.clauses) # soft clauses # minimizing the number of literals used for j in range(1, self.nof_terms + 1): enc.append([self.unused(j)], weight=self.lambda_) # minimizing the number of missclassifications for lb in self.labels: for q in self.samps[lb]: enc.append([-self.miss(q + 1)], weight=self.data.wghts[q]) # there should be at least one rule for this class enc.append([-self.unused(1)]) # saving comments for j in range(1, self.nof_terms + 1): for r in range(1, self.nof_feats + 1): enc.comments.append('c s({0}, {1}) => v{2}'.format( j, r, self.svar(j, r))) enc.comments.append('c l({0}, {1}) => v{2}'.format( j, r, self.lvar(j, r))) enc.comments.append('c d0({0}, {1}) => v{2}'.format( j, r, self.dvar0(j, r))) enc.comments.append('c d1({0}, {1}) => v{2}'.format( j, r, self.dvar1(j, r))) for q in range(len(self.data.samps)): enc.comments.append('c cr({0}, {1}) => v{2}'.format( j, q + 1, self.crvar(j, q + 1))) for j in range(1, self.nof_terms + 1): enc.comments.append('c u({0}) => v{1}'.format(j, self.unused(j))) for lb in self.labels: for q in self.samps[lb]: enc.comments.append('c m({0}) => v{1}'.format( q + 1, self.miss(q + 1))) for n, f in zip(self.data.names[:-1], self.data.feats[:-1]): for v in f: if self.data.fvmap.dir[(n, v)] > 0: enc.comments.append('c {0} = {1} => positive'.format(n, v)) else: enc.comments.append('c {0} = {1} => negative'.format(n, v)) return enc
def encode(self, label, nof_lits=1): """ Encode the problem of computing a DS of size nof_lits. """ self.nof_lits = nof_lits self.nof_samps = len(self.data.samps) self.nof_labls = len(self.labels) if len(self.labels) == 1: # distinguish one class from all the others other_labels = set(self.samps.keys()) else: # distinguish the classes under question only other_labels = set(self.labels) other_labels.remove(label) other_labels = sorted(other_labels) for j in range(1, self.nof_lits + 1): for r in range(1, self.nof_feats + 2): self.feat(j, r) for j in range(1, self.nof_lits + 1): self.sign(j) for j in range(1, self.nof_lits + 1): self.leaf(j) enc = WCNF() # all the hard clauses # # exactly one feature per node (including class/label) for j in range(1, self.nof_lits + 1): feats = [self.feat(j, r) for r in range(1, self.nof_feats + 2)] + [self.unused(j)] one = CardEnc.equals(lits=feats, vpool=self.idpool, encoding=self.options.enc) enc.extend(one) # at most one class/label per node for j in range(1, self.nof_lits + 1): labels = [self.label(j, z) for z in self.labels] am1 = CardEnc.atmost(lits=labels, vpool=self.idpool, encoding=self.options.enc) enc.extend(am1) # the model is split, # i.e. we currently target only rules for this concrete class enc.append([self.label(j, label)]) # propagation of unused literals for j in range(1, self.nof_lits): enc.append([-self.unused(j), self.unused(j + 1)]) # leaf constraints # this disallows empty (default) rules and thus is disabled # enc.append([-self.leaf(1)]) # first node can't be a leaf # last leaf for j in range(1, self.nof_lits): enc.append([-self.unused(j + 1), self.unused(j), self.leaf(j)]) enc.append([self.leaf(self.nof_lits), self.unused(self.nof_lits)]) # everything is reachable at node 1 for lb in self.labels: for i in self.samps[lb]: enc.append([self.reached(1, i + 1)]) # reachability propagation for j in range(1, self.nof_lits): for lb in self.labels: for i in self.samps[lb]: aij = self.agree(j, i + 1) cl, shift = [], 0 for r in range(1, self.nof_feats + 1): if r - 1 in self.data.vmiss[i]: # this feature is missing in i'th sample shift += 1 else: # a = self.agree(j, i + 1, r) # node j agrees with sample i on feature r f = self.feat(j, r) # feature r decided in node j s = self.sign(j) # polarity of node j if self.data.samps[i][r - 1 - shift] > 0: a = self.sets1(j, r) if a > enc.nv: enc.extend([[-a, f], [-a, s], [a, -f, -s]]) else: a = self.sets0(j, r) if a > enc.nv: enc.extend([[-a, f], [-a, -s], [a, -f, s]]) cl.append(a) enc.append([-aij] + cl) for l in cl: enc.append([aij, -l]) cur = self.reached(j, i + 1) # node j is reachable for sample i new = self.reached(j + 1, i + 1) # node j + 1 reachable for sample i enc.append([-new, self.leaf(j), cur]) enc.append([-new, self.leaf(j), aij]) enc.append([ new, -self.leaf(j)]) enc.append([ new, -cur, -aij]) # correctness of leafs for j in range(1, self.nof_lits + 1): for lb in self.labels: for i in self.samps[lb]: enc.append([-self.leaf(j), -self.reached(j, i + 1), self.label(j, lb), self.miss(i + 1)]) # coverage constraints for i in self.samps[label]: cl = [self.miss(i + 1)] # here the clause is relaxed for j in range(1, self.nof_lits + 1): cvar = self.covered(j, i + 1) enc.append([-cvar, self.leaf(j)]) enc.append([-cvar, self.reached(j, i + 1)]) enc.append([cvar, -self.leaf(j), -self.reached(j, i + 1)]) cl.append(cvar) enc.append(cl) # soft clauses # minimizing the number of literals used for j in range(1, self.nof_lits + 1): # enc.append([self.unused(j)], weight=self.lambdas[label]) enc.append([self.unused(j)], weight=self.lambda_) # minimizing the number of missclassifications for lb in self.labels: for i in self.samps[lb]: enc.append([-self.miss(i + 1)], weight=self.data.wghts[i]) # there should be at least two literals in the decision set # since u_j variables are sorted, we know that they are u1 and u2 # enc.extend([[-self.unused(1)], [-self.unused(2)]]) # the previous constraints disallowed empty (default) rules # and so this one looks better enc.extend([[-self.unused(1)]]) # symmetry breaking if self.options.bsymm: self.add_bsymm(enc) for v, o in self.idpool.id2obj.items(): enc.comments.append('c {0} <=> {1}'.format(o, v)) return enc
def optimize(graph, num_colours=4, extract_MUS=False, required_cl=[], required_nodes=[], verbosity=0, shuffle=False): """ Use clever SAT things to reduce the number of nodes in the graph, while still maintaining it's UNSAT status. extract_MUS runs an additional optimization that will find a minimal graph, but it is more expensive. required_cl: provide additional clauses that won't be optimized away required_nodes: blacklist some nodes from removal. (Typically those in required_cl) verbosity: set logging level """ def maybeLog(s, th=1, nl=True): if verbosity >= th: print(s, end=('\n' if nl == True else '')) clauses, n_clM, cl_nM = getSAT(graph, num_colours) f = WCNF() for c in required_cl: f.append(c) for c in clauses: f.append(c, weight=1) maybeLog("Created formula") topv = f.nv # Number of vars in basic formula # Selectors for each node, each getting a new variable. # Note: graph.G.nodes may not be a contigous list after previous removal steps. sels = [i + topv for i in graph.G.nodes] # vmap = {} # Map to origional clause s = MapleChrono(bootstrap_with=f.hard) # Possibly load the graph nodes in in a random order. ixs = [i for i in range(0, len(clauses))] if shuffle: random.shuffle(ixs) # For each node, add the relevent clauses for i in ixs: clause = clauses[i] # Nodes involved in this clause nodes = cl_nM[i] # Assume node is enabled (as negative value). # Need both nodes in an edge on to care about rest of clause. s.add_clause(clause + [-(n + topv) for n in nodes]) if not s.solve(assumptions=sels): maybeLog("Core extraction\n") approx = s.get_core() if extract_MUS: # Perform additional refinement to get MUC. # Attempt to remove each node. i = 0 while i < len(approx): # Try ignoring nodes (setting variable to positive), # And seeing what happens... to_test = approx[:i] + approx[(i + 1):] sel, node = approx[i], approx[i] - topv maybeLog('c testing node: {0}'.format(node), nl=False) if s.solve(assumptions=to_test): maybeLog(' -> sat (keeping {0})'.format(node)) i += 1 else: maybeLog(' -> unsat (removing {0})'.format(node)) approx = to_test # Map back to node ixs, adding to passed required nodes. required_nodes = [x - topv for x in approx] + required_nodes # Create blacklist and delete from graph bk_lst = [n for n in graph.G.nodes if n not in required_nodes] print("Removing", len(bk_lst), "nodes.", len(required_nodes), "left.") [graph.G.remove_node(i) for i in bk_lst]
class MinimalSubset: def __init__(self): self.map_atoms = {} self.atoms_counter = 1 self.wcnf = WCNF() self.min_card = math.inf self.number_of_diagnoses = 0 self.time = 0 def add_soft(self, c): if self.map_atoms.get(c) is None: self.map_atoms[c] = self.atoms_counter self.atoms_counter += 1 self.wcnf.append([self.map_atoms[c]], weight=1) def create_dictionary(self, statement): atoms = statement.atoms() for letter in atoms: if self.map_atoms.get(str(letter)) is None: self.map_atoms[str(letter)] = self.atoms_counter self.atoms_counter = self.atoms_counter + 1 def convert_letters_to_integer(self, atom): key = atom.replace('~', '') int_value = self.map_atoms[key] if '~' in atom: return int_value * -1 return int_value def convert_integer_to_letters(self, integer): for k, v in self.map_atoms.items(): if v == abs(integer): if integer < 0: return '~' + k else: return k def convert_statement(self, statement): statement_cnf = str(statement) statement_cnf = statement_cnf.replace('(', "") statement_cnf = statement_cnf.replace(')', "") list_statements = statement_cnf.split('&') literals_list = [] res = [] for s in list_statements: literals_list.append(s.split('|')) for k in literals_list: clu = [] for x_temp in k: x_temp = x_temp.replace(" ", "") clu.append(self.convert_letters_to_integer(x_temp)) res.append(clu) self.wcnf.append(clu) return res def run_solver(self): start_time = time.time() with RC2(self.wcnf, solver='mc') as rc2: while True: ans = rc2.compute() if ans is None: print('break no answer') break ans = [self.convert_integer_to_letters(x) for x in ans] # print(ans) counter = 0 for x in ans: if x.startswith('~') and 'gate' in x: counter = counter + 1 rc2.add_clause( [abs(self.convert_letters_to_integer(x))]) if counter > 0 and self.min_card > counter: self.min_card = counter if self.min_card + 2 < counter: print('break min card:', self.min_card) print('number of comp: ', counter) break self.number_of_diagnoses = self.number_of_diagnoses + 1 current_time = time.time() if (current_time - start_time) / 60 >= 0.5: print('finish run') break self.time = current_time - start_time
from pysat.formula import WCNF from pysat.examples.rc2 import RC2 # clauses = [[1], [-1], [-2]] # clauses = [(-8, 2, -3), (1, 6, -19), (9, -15, 11), (4, -5, 16), (14, -17, -10), (-13, -7, 18), (-15, -8, -5), (13, 1, 2), (-20, 17, 12), (-10, -7, -14), (-9, 3, 18), (6, -19, -11), (12, -9, -7), (-11, 20, -10), (-2, -8, 5), (-18, 19, 3), (16, -1, 14), (-4, -15, -17), (-6, -20, 3), (-19, -15, 11), (-4, -18, 8), (-1, 9, 2), (-17, 14, 12), (-5, 13, 7), (14, 8, -6), (-13, -17, -15), (-11, -1, -5), (-9, 12, 18), (7, -16, 20), (19, 4, -3), (-11, 10, -8), (3, -9, -5), (-7, 13, 6), (17, -19, -4), (15, 14, -18), (-12, -1, 20), (10, -3, -16), (17, 12, 4), (7, 20, 1), (-18, 6, 14), (-5, 19, 8), (-9, -13, 15), (20, 18, 10), (5, -6, 15), (19, 1, -17), (4, -3, -13), (7, -11, -12), (8, 14, 16), (-7, 19, 3), (18, 2, -4), (8, 9, 10), (16, 5, -17), (1, 6, -20), (15, 11, 12), (18, 17, 13), (-3, 12, -2), (16, -10, 1), (15, 8, -9), (-20, -19, -5), (-6, 14, 7), (12, -4, -17), (8, -2, -9), (5, -11, -1), (16, -6, -20), (18, 7, -15), (14, -3, -13), (-8, 12, -3), (14, -19, -6), (-16, -5, 7), (-13, 10, -1), (17, 18, 11), (-4, -9, -2), (19, 3, 1), (-6, 2, -11), (5, -10, 8), (4, 7, -16), (20, 12, 13), (-18, -15, 17), (-11, 6, -16), (-15, -9, -13), (19, 4, -10), (-2, 12, 5), (18, 3, -8), (14, 17, 20), (17, 19, -16), (-1, 2, 10), (6, -14, 11), (-9, -4, -13), (15, -20, -7), (18, -5, 3), (1, -8, -9), (7, 2, 3), (-19, -6, 11), (-18, -4, -10), (-17, -20, -16), (5, -13, 12), (12, 14, -19), (-16, 1, -5), (7, 8, 18), (6, 15, 9)] # clauses = [(-17, 1, 3), (18, 14, 4), (2, -7, -12), (-6, 11, 20), (8, -9, -10), (16, 13, -19), (-16, -10, 1), (-18, -19, -13), (-20, 7, 3), (-15, 14, 8), (-17, -4, 2), (-12, 6, -11), (15, 13, 8), (-17, 16, -4), (20, -10, 5), (9, 12, -3), (-2, -11, 7), (-14, -6, -19), (19, -15, -11), (-7, 13, -1), (8, 6, 10), (14, -3, 5), (20, 2, 18), (12, 4, 9), (11, 19, 5), (8, -16, -12), (6, -18, -14), (2, -4, -7), (13, 10, 15), (-9, -20, 17), (9, -20, 10), (-17, 7, -6), (3, -8, 1), (5, 18, 2), (-15, -12, 16), (-14, -4, 11), (13, 7, -6), (9, 10, 8), (-12, 14, 4), (-11, -17, -20), (-15, -16, 5), (-18, 19, 1), (-13, -3, 8), (6, -2, 7), (11, 18, -20), (-5, -10, -16), (-12, 4, 9), (-1, -15, 14), (16, 18, -5), (10, 8, -17), (-6, 2, -19), (-1, -15, -3), (11, -12, 20), (-9, -4, 14), (18, 5, -20), (12, -10, 7), (3, 9, -14), (-15, 2, -16), (-17, 11, 4), (6, -13, -19), (-20, -16, 3), (-5, -7, 11), (-17, -13, 2), (-9, 8, -12), (15, -4, -19), (1, -6, 18), (-16, 7, 14), (5, 18, -10), (13, -6, 11), (-19, 4, -12), (-20, 8, 2), (1, -9, 17), (-8, -6, -2), (-5, 19, -4), (-7, -17, 3), (12, -1, -10), (-14, 16, -20), (-11, 18, 9), (-20, -17, 11), (-12, 3, -14), (19, 9, 13), (-18, -2, 6), (-5, -4, -1), (10, 15, -7), (4, -13, -3), (11, -12, 16), (-5, 17, 20), (1, -14, -10), (2, -6, 18), (-8, -15, 19), (17, -19, 1), (-16, 9, -5), (14, -13, -10), (-4, -8, 20), (12, 15, 6), (-11, 3, 18), (-18, 12, 1), (-5, -2, -4), (16, 11, -9), (-17, -6, 13)] # clauses = [(-4, -12, 8), (10, 18, -1), (-20, -5, -13), (15, 3, -7), (-14, -6, -11), (-2, -9, 16), (11, -4, 14), (-15, -7, -6), (-1, -18, -5), (8, -12, 16), (-20, -13, 3), (-10, -9, -19), (10, -19, -14), (-5, -12, -3), (11, -4, -20), (9, 17, 18), (-7, 16, 15), (13, -1, -2), (7, 8, -10), (18, -16, -2), (17, -19, 20), (-3, -6, 13), (11, -15, 1), (5, -14, -9), (-4, -9, -16), (-5, -3, 1), (-10, -19, 15), (-7, 17, -6), (12, -2, -11), (8, 13, -14), (10, -17, 15), (8, -9, -12), (11, -7, 18), (-6, 1, -16), (3, -2, -14), (-13, -5, -20), (-12, -14, -20), (7, 3, 2), (-6, 11, 9), (5, 18, 16), (4, 10, -13), (8, -1, 19), (15, -9, -8), (3, -6, 20), (7, -19, -13), (4, 18, -1), (-16, 10, 17), (11, -5, 2), (-20, -15, 3), (18, 11, -14), (-6, -19, 4), (-7, -17, -5), (-13, 10, 2), (-1, 9, 16), (-5, 12, -15), (10, 20, -17), (1, -18, -3), (-11, -13, 8), (14, 19, -16), (6, -7, 2), (-8, -12, -1), (-5, -14, 15), (-2, 11, 18), (-17, 6, 7), (-9, -20, -16), (13, -19, 4), (20, -9, -11), (18, 3, -15), (6, -19, 17), (-2, 7, -14), (-8, -5, -4), (-16, 10, -13), (-8, -1, 9), (11, -7, -4), (15, 19, 12), (2, 16, 3), (-14, 18, -17), (-6, 13, -20), (14, 5, 7), (4, -15, -1), (-19, -12, -10), (13, -9, -16), (-11, -6, 18), (2, 17, 20), (-9, 15, -12), (-4, 6, 10), (13, 18, -1), (-20, -3, -7), (2, -17, -11), (19, 5, 8), (19, 8, -10), (-18, -3, 20), (7, 4, 16), (15, 17, -9), (-1, 13, 14), (2, -11, -5), (-12, -1, -14), (20, -5, 7), (-2, -3, 6), (19, 9, -11)] # clauses = [(1, 2, 3), (-2, -1, 3), (1, -3, 2), (1, 2, -3), (1, -2, -3), (2, -3, 1), (-3, 1, -2), (-2, 3, -1), (-3, -1, -2), (-1, -2, 3), (2, -3, 1), (-1, -2, 3), (2, -1, -3), (-3, 1, 2), (2, 3, -1), (1, 3, -2), (3, -2, 1), (2, 3, 1), (-1, -3, -2), (-2, 3, 1), (-2, 1, 3), (1, 2, 3), (-3, 2, 1), (-3, -2, 1), (-1, 3, -2), (2, 3, -1), (-2, -3, 1), (-2, -1, 3), (-2, 1, 3), (-2, -3, -1), (2, -3, 1), (-1, -3, 2), (-1, 2, 3), (-3, -1, 2), (-2, 1, -3), (-1, -2, 3), (-2, -3, -1), (3, -1, 2), (-2, 3, 1), (-2, 1, -3), (2, -3, -1), (3, -2, -1), (-1, -3, -2), (-1, 2, 3), (-2, 1, 3), (1, -3, -2), (2, 1, -3), (-3, -1, 2), (-3, -2, 1), (-3, -1, -2), (2, 1, -3), (1, 3, 2), (1, -2, 3), (-3, 2, -1), (1, -2, 3), (-1, 2, -3), (-2, -1, 3), (-3, 1, -2), (-2, 3, 1), (-1, -2, -3), (2, 3, 1), (-2, 1, -3), (-2, -1, -3), (2, 1, -3), (-2, -1, 3), (1, 2, -3), (-1, -2, 3), (-3, -2, -1), (-2, -1, -3), (2, 3, 1), (1, -3, -2), (-1, 2, 3), (-1, -3, 2), (-1, -3, 2), (3, 1, 2), (-2, -1, 3), (3, -1, -2), (-1, -3, -2), (-1, 3, -2), (2, -3, -1), (1, 3, 2), (3, -1, -2), (2, 3, 1), (2, 1, -3), (2, -1, 3), (3, 2, 1), (-1, -3, 2), (-3, 2, 1), (-1, -3, -2), (-2, 3, -1), (2, -1, -3), (3, -1, 2), (-3, 2, 1), (3, -2, -1), (-1, -3, -2), (2, -1, -3), (-3, 2, -1), (-3, 2, 1), (-1, 3, 2), (-3, -2, 1)] # clauses = [(-6, -9, 5), (-8, 7, 10), (2, -4, -3), (-5, -4, -6), (9, 10, 2), (-3, 1, 7), (10, 9, 7), (1, -2, -4), (6, -3, -5), (7, -10, -9), (6, 2, -3), (1, 5, 4), (-6, -9, -1), (7, -8, -3), (-2, -4, 5), (9, 5, 8), (-7, 10, 1), (4, -2, -6), (10, 4, -5), (6, 3, -2), (1, 9, -8), (-4, -1, 6), (-10, 5, -2), (8, 7, 9), (-3, 7, -6), (-9, -5, -4), (-2, 8, -1), (-1, 8, 3), (6, -2, -7), (-10, 4, -5), (10, 3, -7), (4, 8, 1), (-9, -2, -5), (1, 6, 4), (3, -7, 8), (-5, 2, -10), (1, 3, -8), (-4, 2, 10), (-6, -5, -7), (-5, -4, -9), (-10, 2, -7), (3, -8, -1), (1, -2, -9), (-6, -7, -10), (4, 8, -3), (-1, -3, 9), (-5, 6, 10), (4, -2, 8), (-2, 1, 7), (-5, 6, -3), (10, 4, -8), (10, -4, -2), (-9, 5, 8), (7, -3, -6), (-7, 8, -2), (9, -10, 1), (6, 3, -5), (-9, 2, -5), (1, -4, -8), (-10, -3, -6), (4, -10, 9), (-7, -1, -6), (-5, 8, 2), (7, -6, 1), (4, -3, 5), (-9, -8, 10), (-4, -7, -3), (6, 5, 9), (-10, -8, -1), (-2, 1, 10), (3, 8, 9), (-5, -6, -7), (1, 3, -6), (4, -8, 10), (-7, 5, 2), (-8, -4, -3), (9, -10, 2), (-5, 7, -1), (-5, 6, -10), (8, -9, 4), (7, 1, 3), (7, 6, -1), (-3, 2, 8), (4, 9, 10), (2, -9, -10), (3, 1, -8), (-6, 7, -4), (5, -10, 1), (-4, 8, 2), (6, -3, -7), (-10, -7, 1), (-5, -3, 2), (9, -6, -4), (1, 2, 8), (9, -10, -3), (-7, 6, -4), (-4, 6, 5), (7, 1, 9), (-3, 8, -2), (-1, 3, -2), (-7, -6, -10), (-9, 5, -8), (-5, 6, 7), (-10, -8, -3), (9, 2, -1), (6, -4, -3), (-10, 8, -1), (9, 2, 5), (1, 10, 4), (2, -5, -8), (3, -9, 6), (9, 2, -4), (3, -5, 10), (7, -8, -1), (2, 6, -9), (8, 10, -7), (3, -4, -5), (-10, -9, 3), (1, -7, 4), (6, 5, 2), (3, -8, 7), (-9, -10, 6), (4, -2, 1), (10, 7, 3), (-4, -6, 2), (-8, -1, 9), (6, 8, -2), (-3, 4, 7), (5, 9, -10), (-3, 2, -9), (-1, 8, -4), (-7, -10, 6), (-7, -9, -5), (8, 4, 10), (-1, 3, -2), (4, 1, 7), (6, -5, -3), (-2, 10, 9), (-3, 4, 6), (-2, -10, -5), (-9, 7, -8), (-4, 1, -5), (10, 3, 8), (-6, -2, -9), (-7, -5, -1), (-2, 4, -9), (10, 3, -6), (6, -2, 4), (-8, -9, 3), (-7, -10, 1), (-10, 5, -9), (-1, 3, 2), (-6, 7, -4), (9, 6, 10), (-7, -2, -1), (-5, 4, 8), (-4, -5, 1), (-3, -6, -8), (7, -2, 9), (1, -9, -8), (-10, -2, 4), (3, -7, 5), (-7, 4, 9), (2, -5, -8), (3, -10, 6), (-7, -6, -5), (3, -10, -9), (-4, -1, -2), (6, -3, 5), (-1, -10, 9), (7, 2, -4), (-3, -6, -8), (-1, 7, -5), (-4, 2, 10), (9, -5, -10), (6, 1, 8), (3, -7, 4), (-6, -9, 1), (-10, -3, -7), (-8, -2, 4), (5, 3, -7), (-9, 8, -6), (2, -4, 10), (-8, 7, 6), (-3, 5, 1), (4, 9, 2), (10, -1, 5), (4, 8, -3), (-9, -2, -7), (-10, 5, -8), (1, 3, 7), (9, 2, -6), (-5, 10, -1), (-2, -4, -9), (3, 7, -6), (8, 10, -7), (-9, 5, 3), (-6, 2, -4), (7, 1, -4), (8, 6, 2), (-5, 10, -9), (-10, -6, -7), (2, -4, 8), (9, -3, 1), (9, 2, 8), (-10, 7, 1), (-3, 6, 5), (4, 7, -9), (5, -3, 6), (10, 2, 8), (5, -1, 8), (-2, 10, -3), (4, 9, 7), (-10, -9, -2), (-7, 4, -6), (3, -1, 5), (5, -10, -7), (6, -2, 4), (-3, -9, -8), (-4, 1, 7), (-9, -2, 3), (8, 5, -10), (-4, -10, 2), (-1, -3, -7), (-6, -8, -9), (-3, -6, 1), (-8, -9, 10), (-2, -4, 5), (5, -3, 9), (-2, -7, 10), (4, -1, -6), (-6, -10, -1), (-2, -7, -9), (5, 4, -3), (7, 2, -10), (9, -8, -4), (3, 1, -5), (3, 10, 6), (-7, -1, -8), (-4, -2, -9), (-7, -6, 2), (-10, 1, 8), (4, 9, -3), (-10, 1, 4), (-8, 9, -5), (-6, -7, 2), (-8, 9, -7), (3, -5, 10), (-1, -6, -2), (3, -1, 7), (-2, -8, 6), (-9, 10, -4), (-3, -10, -6), (-1, 4, 7), (8, -9, -5), (3, 1, 5), (-8, -2, 7), (9, -4, -10), (-2, 10, -1), (-3, 5, 7), (6, -4, 8), (1, -4, -8), (-10, 9, 2), (5, -7, 3), (2, -4, 8), (7, -9, 3), (-10, -6, -5), (-4, -10, -3), (1, 5, 7), (8, 9, -2), (-6, -4, -7), (-3, -8, -9), (-5, 10, -1), (-2, -3, -8), (10, 6, 5), (4, -9, -1), (-2, 1, 10), (8, 7, 6), (9, 5, -4), (6, -5, 9), (-8, 10, -4), (-3, -2, -7), (9, 5, -2), (4, 1, 7), (-8, 10, 3), (7, 9, -1), (-3, -2, 6), (-5, 4, -10), (-3, -2, 9), (4, 10, -1), (-5, -8, 6), (-9, 1, 10), (-2, -7, -8), (-4, -6, -5), (10, -5, 6), (8, 9, -3), (-1, 7, 2), (5, 7, 9), (6, 8, 4), (10, 3, -2), (5, -8, 2), (1, -7, 9), (-6, 10, -4), (-7, 1, 2), (9, -5, -8), (-3, -6, -4), (-9, -4, -7), (-2, 6, 5), (10, 1, 8), (-7, 9, 1), (10, 5, -4), (-6, 3, 8), (-3, 7, 2), (4, 6, 10), (5, 8, 9), (-2, -6, 8), (3, -4, -5), (-9, -10, -7), (-9, -1, 8), (5, -3, -7), (-10, -6, 2), (7, -10, 2), (-5, -9, 3), (4, -1, -6), (9, 7, 2), (-5, -4, 3), (6, 1, -8), (3, 4, 2), (-8, 7, -10), (-9, 1, 5), (-6, -2, 9), (-3, 10, -7), (-1, -8, 5), (9, 6, 4), (-3, 5, 2), (-1, -10, -7), (-7, -2, 4), (8, -9, 6), (10, -1, -5), (1, -9, -4), (3, -7, 8), (10, -2, 5), (6, 7, -10), (4, -5, 1), (9, -8, -3), (1, -10, -9), (8, -4, -3), (2, -7, -5), (6, 2, 8), (10, 4, -1), (9, 3, -7), (8, 3, -7), (4, -5, -9), (2, 6, 1), (-6, 2, -4), (-9, -8, 7), (-5, -3, -10), (10, 1, 7), (-5, -4, 9), (-2, -3, 6), (-8, -3, -4), (6, -9, -5), (-1, -2, 7), (-8, -4, -9), (6, 2, -3), (-10, 5, 7), (-10, 2, -5), (-4, 1, -8), (-7, -6, -9), (7, -1, -5), (-6, -2, 9), (-8, 4, 10), (-5, 1, 10), (3, 6, 4), (-9, -7, 2), (-7, 2, 1), (6, 10, 4), (5, -8, 3), (1, 5, 2), (-7, -10, 8), (-4, 9, -6), (10, 2, -8), (-4, 1, -3), (-6, -9, 5), (10, -3, 5), (-8, 6, -9), (-1, 4, -2), (-9, 10, 5), (-1, -2, -3), (-8, 6, -4), (5, 8, 7), (-9, 10, -3), (-1, 2, -6), (-8, 6, -5), (9, 3, -4), (1, -2, 10), (10, -9, -4), (1, 6, -7), (-5, 3, -2), (-3, -5, -4), (-6, -7, -10), (1, -8, 2), (6, -9, -8), (-3, 1, -7), (-5, -10, 2), (7, -10, 6), (-1, -8, -2), (-3, 9, 5), (9, -6, -5), (7, -10, -3), (-2, 1, 4), (4, -3, 7), (8, -10, -2), (-6, -9, 5), (-10, -8, 7), (4, -9, 5), (-3, -2, -6), (10, 6, -3), (4, 2, 1), (9, 5, 7), (-1, -3, -7), (-9, -6, 5), (-2, -8, -10), (10, 1, -6), (-4, 2, -9), (3, -8, 7), (-8, -1, -2), (-7, -6, 10), (-3, -5, -9), (-6, -1, 9), (-2, -4, -10), (-3, 7, -8), (-6, 8, 2), (-4, -5, -3), (-7, -10, 9), (-4, 5, 6), (-10, -8, 3), (9, -7, 1), (7, -1, 2), (-8, -5, 6), (4, 10, 9), (2, 7, 6), (-3, -1, 5), (9, 10, 4), (5, 8, -4), (-7, 9, 3), (1, 10, -2), (-1, -10, -4), (-5, -3, -2), (7, -8, -6), (-10, -7, 6), (5, 3, 4), (-1, 8, 9), (7, -5, 4), (8, 6, 9), (-10, -3, -2), (2, -9, -8), (-10, -3, 7), (5, -6, 4), (-7, 9, -5), (-6, -4, 2), (-10, -8, -3), (-3, -8, -10), (7, -5, -2), (4, -1, -6), (-9, -3, 2), (-8, 1, -5), (-10, 4, -7), (4, -3, 9), (-10, -7, 8), (-5, 2, -6), (4, -3, -8), (5, 9, 1), (-10, 2, -6), (5, -3, 4), (7, -9, 8), (-10, -6, 1), (6, 7, -2), (4, -5, -9), (8, -10, -3), (10, -1, 4), (5, -7, -8), (6, 9, -3), (-7, 8, 1), (4, 5, 9), (-3, 6, -10), (-5, 4, -2), (8, -7, 6), (-3, 10, -1), (-5, -10, 2), (-8, -9, 4), (-6, -1, 3), (-9, 8, 4), (2, -6, 7), (-1, -10, 5), (1, -10, -9), (-5, 2, 6), (8, -7, -4), (8, -5, 6), (-1, 2, 7)] # clauses = [(-6, -4, 7), (3, 9, -2), (10, -1, -8), (8, -1, -7), (-10, -5, 4), (6, 9, 3), (10, -6, 8), (7, -3, -4), (2, -5, 1), (-6, 9, -1), (-2, -4, -3), (7, -8, -5), (2, 10, -1), (-5, 8, 4), (-3, 9, 7), (-6, 3, 10), (8, 9, -7), (-2, -5, -4), (3, -7, -9), (-2, 10, -1), (-6, 4, 8), (6, 4, 5), (10, 9, -3), (8, -2, 1), (6, 9, -3), (1, -4, -2), (-8, -7, -10), (4, 5, 7), (3, 1, 10), (-2, -9, -6), (10, 2, 7), (-4, 6, -8), (5, -9, -1), (8, 10, 5), (3, 1, 4), (9, -2, -7), (-10, 1, 6), (2, -3, 7), (5, -9, -8), (3, 10, 4), (-7, 1, -8), (5, -2, -6), (-7, 3, -6), (10, 2, -4), (1, -5, -9), (-7, -10, 1), (9, 2, -6), (-3, 4, 5), (-5, -7, 6), (2, 4, 3), (10, 8, -1), (-1, -8, -2), (9, -3, 7), (6, -5, 4), (-3, 2, 6), (-5, -9, 1), (10, -8, -4), (8, 2, 7), (-1, 5, 6), (-9, -3, -10), (7, 2, -9), (10, 4, 6), (1, 5, 3), (-2, -5, -8), (-3, 1, -6), (4, -9, -7), (-7, 1, -8), (3, 5, 10), (6, -2, -4), (10, 3, 9), (-6, -5, -8), (-7, 1, 2), (2, -4, -7), (-9, 10, -3), (-8, -5, 1), (-1, -5, 6), (-9, 10, 3), (8, -4, 2), (-3, -9, -4), (10, -6, -1), (-2, 8, 5), (-2, -9, 1), (4, -3, 8), (6, -7, 5), (1, -3, -8), (4, 5, 9), (-7, 6, 2), (5, -6, -9), (3, 2, -7), (-8, 10, 4), (-8, 6, -4), (-3, -7, -1), (2, -10, 5), (2, -5, -7), (1, 6, 10), (9, 8, 4), (6, 4, 1), (-3, -10, 8), (7, 2, 5), (1, -10, 8), (9, -4, -6), (-2, 3, -5), (10, 7, -6), (-5, 1, 2), (-9, -8, 4), (-9, -8, 2), (-1, -3, -10), (6, -4, -7), (-10, -6, -1), (-8, 3, 7), (4, 9, -2), (-10, -8, 6), (-4, -5, 1), (-3, 7, 9), (8, 4, -6), (-5, -10, -2), (3, 9, -7), (-3, -7, 5), (6, -4, 8), (1, -10, 2), (2, -1, 4), (9, -6, 10), (-3, -7, 5), (6, 4, -1), (-8, -5, 3), (9, -7, -2), (10, 8, 9), (4, -5, -6), (-3, -7, 2), (-9, -2, -5), (10, -4, 6), (-1, 7, 8), (-2, -3, 6), (-9, -8, 5), (4, 7, -1), (-8, -5, -2), (3, 7, 9), (-1, 6, 4), (-7, -5, 1), (-8, 3, 2), (10, -6, 9), (-6, -9, -10), (1, -2, 4), (-3, 7, -5), (-10, 6, -3), (8, 9, 7), (2, -4, 5), (10, 7, -2), (3, -4, -5), (8, 9, -1), (-3, -6, 1), (-7, 2, -10), (4, 5, -9), (10, -4, -9), (7, 3, -5), (1, 2, -8), (-5, 4, 9), (-2, 6, -3), (7, 8, 1), (-6, -8, 3), (10, -7, -9), (-4, -1, 5), (2, 6, 3), (-1, -4, 5), (-10, -8, 9), (5, -2, -3), (-8, -7, 6), (10, 4, 1), (-7, -8, 1), (10, -9, -3), (6, -4, -5), (1, -10, -8), (-5, 9, -2), (3, -6, 7), (3, -9, -7), (-5, -6, 4), (-8, 2, 10), (2, -9, -1), (10, -3, -6), (5, -4, -7), (-2, 5, -4), (-1, 10, 8), (7, 6, 3), (-7, -5, 2), (-4, -3, -10), (6, 9, 8), (-2, -8, -5), (-6, 9, 10), (3, 7, -1), (-6, -2, -3), (10, 8, -1), (-7, 4, -9), (-3, 4, -5), (8, 6, 1), (-10, -9, -7), (-9, 5, -7), (-8, 3, 10), (-4, 2, 1), (5, -7, -8), (-3, -9, -1), (-6, 10, 4), (-2, 8, -7), (1, 9, -6), (3, 4, 5), (-2, 4, 6), (-5, -3, -8), (-1, -7, 9), (-3, -8, 9), (-2, 1, 7), (4, -10, -5), (4, 3, 1), (-7, -9, 6), (-2, -5, 8), (-2, 10, 3), (7, -5, 9), (-8, 6, 1), (2, 10, -3), (1, 4, -7), (8, 6, 5), (-6, -1, 3), (4, -5, -2), (8, 10, -9), (10, 2, 1), (-5, 3, 6), (8, -4, 9), (10, -2, 4), (-3, 9, 1), (8, -5, -6), (4, -9, -8), (7, 6, 1), (-10, 5, -2), (8, -10, 1), (2, 5, -9), (4, 6, 3), (-6, -9, -8), (-4, 10, -2), (-1, -3, -5), (2, -9, 1), (-3, 10, 6), (4, -5, 8), (1, -3, -6), (-2, 4, -9), (-10, -8, -5), (8, -10, -4), (-7, 1, -3), (-5, -9, -2), (7, -9, 6), (-4, 2, 8), (5, -3, 10), (-9, 7, 10), (-1, -8, 3), (2, 5, -4), (-8, -10, -9), (-4, 3, -6), (-7, 1, -2), (9, 3, -6), (10, 1, -2), (7, 5, -8), (-2, 10, 3), (-7, -1, -6), (-5, 9, 8), (8, -5, -7), (9, -2, 10), (-3, -6, 1), (-9, 1, 8), (2, 4, -10), (5, 6, 3), (3, -5, -8), (-6, -4, 10), (-1, 2, 9), (5, -2, 4), (-10, -9, 7), (8, 1, -6), (3, 2, 8), (7, -6, -5), (-1, 4, -9), (4, 8, -2), (7, 9, -1), (-3, -6, 10), (4, 10, -8), (-2, -3, -5), (-6, -7, 1), (4, 1, 5), (9, 6, -2), (-10, -8, 3), (-5, -6, 7), (-8, 2, -9), (3, 1, 10), (2, 7, 3), (8, -4, 10), (1, 5, 9), (-5, 7, 3), (8, 1, 4), (-10, -2, -6), (8, 6, 9), (-4, 7, -3), (1, -5, 2), (-3, -8, -4), (1, 9, 5), (-10, 7, -2), (-4, 6, 7), (-2, -10, -5), (9, 3, 8), (-4, -6, 2), (-5, 3, -1), (7, -10, 8), (4, -7, 8), (-2, -1, -9), (-5, 6, 3), (4, -5, 7), (-9, 2, -8), (-10, -3, -1), (1, -2, -9), (4, 5, 8), (-7, -6, 10), (8, -1, 9), (-5, 3, 10), (4, 2, 6), (10, -9, 6), (7, 4, 5), (8, 2, 3), (-7, 2, -4), (6, -9, 1), (-10, -5, 3), (-10, 7, -2), (-1, -6, -3), (-8, 5, 4), (7, 8, -3), (1, -6, -4), (5, 2, -10), (3, 4, 10), (-8, 5, 1), (-9, 6, 7), (-7, 10, -1), (-2, -5, 6), (3, -8, 4), (-4, 10, -7), (-1, -8, 2), (-6, -5, -9), (10, 9, -8), (-7, 4, -6), (1, -3, -5), (5, -3, -4), (-8, 9, -2), (-6, -10, -7), (6, -1, -7), (-8, -9, 5), (3, -2, 4), (1, -2, 7), (10, 3, -8), (-5, -6, 4), (-4, -7, -2), (-3, 5, -6), (1, -9, 10), (8, 5, -9), (-7, 6, -4), (-10, -3, 1), (6, 8, 5), (4, -10, -1), (7, -3, -2), (4, -2, -3), (7, 1, -8), (-6, -10, -9), (8, -7, -1), (6, -3, 2), (-9, -5, 10), (1, -8, -4), (-9, -7, -6), (2, -3, -5), (8, 10, 7), (-9, -4, -1), (-3, 2, -5), (-8, 4, -7), (10, -9, 6), (-5, -1, 3), (7, -1, 10), (-6, -9, 4), (2, 3, -8), (9, 3, -6), (-8, -4, 10), (1, 5, 2), (2, 7, -1), (-9, 3, 10), (-6, 8, -5), (4, 3, -6), (-8, -2, 1), (-10, -5, 7), (9, -8, 2), (4, 6, -5), (3, 7, -10), (9, 7, -8), (4, -1, 5), (10, -3, 6), (4, -5, 3), (-7, -2, -8), (6, -9, -10), (-5, 3, 8), (-2, -1, -9), (4, -10, -6), (7, 4, -2), (-5, -10, 3), (-9, 1, 6), (-7, -3, 2), (4, 1, 6), (9, -8, -5), (7, -5, 2), (3, 4, 10), (1, 8, -6), (-8, -9, -5), (4, 3, -1), (10, -7, 2), (8, -9, 3), (-4, 1, -10), (5, -6, 2), (-2, -6, 5), (-9, 8, 10), (-3, 7, 1), (5, 6, -7), (4, -8, -1), (3, -9, -2), (1, 8, 6), (-9, 2, -10), (-7, 5, 4), (-1, 8, 3), (5, 9, 10), (-2, 4, 7), (9, -3, -10), (2, -4, 8), (-6, 5, 7), (7, -2, 5), (4, -1, 3), (10, -9, -6), (-4, 1, -9), (5, 2, 7), (-10, -6, -8), (10, -9, -3), (1, 2, -5), (-4, 7, -8), (3, -8, -4), (-2, 7, -9), (-10, 6, -5), (-4, -5, 2), (-1, 8, -6), (-7, 10, 9), (-9, -7, 2), (1, 10, -5), (-3, 6, 8), (9, -7, -6), (2, 3, 1), (-4, -10, -8), (-4, 1, 9), (6, 3, -8), (7, -10, 2), (-2, 1, -6), (-10, -9, 3), (4, 8, 5), (-1, -7, 8), (-3, 4, -6), (10, 9, 2), (-10, 3, 7), (-2, 9, 1), (-8, -6, 5), (-10, -5, -3), (9, 7, 6), (-8, 1, -4), (-1, -5, 6), (-10, -2, 9), (7, 3, -4), (1, 2, 6), (5, 7, -3), (10, 8, 9), (3, 5, 9), (-4, 8, -2), (-1, -6, -10), (8, 7, -3), (-10, -2, 9), (5, 6, 1), (-9, 6, -8), (-3, 10, -5), (7, 2, 4), (2, 5, -6), (-7, 3, 1), (10, 8, -9), (1, 6, -10), (5, 4, 2), (-8, 7, -3), (-1, 3, 9), (-2, 10, -8), (-5, -4, -7), (-3, 10, -5), (7, -6, 9), (-2, -8, 4), (-5, 9, 8), (1, 6, -7), (-10, 3, -2), (-10, 5, -6), (-3, 8, 1), (-9, -7, -2), (-9, -3, -10), (-2, -8, -5)] # clauses = [(-3, -2, -1), (6, 10, 7), (5, 4, -8), (-9, -5, 2), (-7, -3, -6), (10, 4, 8), (4, -6, 3), (-5, -8, -1), (-9, -2, 10), (9, -7, 3), (2, -6, 5), (-10, -1, 4), (5, 1, -10), (-3, -9, -8), (-7, -2, -6), (9, 10, -7), (-3, 2, 1), (6, 4, 8), (2, 4, -5), (9, 6, -10), (-3, 8, 7), (2, -4, -6), (-5, 9, 8), (-1, -3, -10), (-2, -9, -5), (-8, -6, -4), (-7, -1, -3), (7, -2, 6), (-9, 8, 1), (-5, 4, -10), (-3, -9, 2), (-6, 4, -10), (-8, 1, 7), (8, -9, 4), (10, 6, -5), (-1, -2, -7), (5, -6, 4), (-9, 8, -7), (-3, -2, 10), (-3, -7, 5), (-6, -9, 1), (-10, -8, 2), (5, 2, 7), (8, -6, -9), (-4, 1, 3), (-10, -8, -4), (3, -6, 2), (-7, 5, 1), (-10, -7, 8), (-2, 6, -4), (-5, -9, -1), (3, -9, -4), (8, -7, -1), (6, 5, -10), (-2, -5, -8), (7, 6, -1), (-9, -4, 3), (-8, -7, 2), (10, -9, 3), (4, 6, 5), (9, 5, -2), (-4, 3, -1), (-10, 7, -6), (8, 1, -6), (10, 4, 2), (7, 5, 3), (6, -5, 10), (3, 9, -7), (2, -1, -4), (-1, 3, -4), (7, -8, 6), (2, 5, -9), (6, -1, 3), (10, -8, -5), (2, -4, -9), (4, 1, -2), (7, -10, -3), (-8, 9, -5), (4, 3, -7), (-9, -2, -10), (5, 8, -6), (-7, -3, 8), (-2, -1, -10), (-4, -9, -5), (-3, -4, 10), (8, -7, -1), (6, -5, -2), (7, 4, 10), (3, 1, 6), (-2, -9, 5), (-6, -10, 2), (5, 7, 4), (-3, 9, -1), (1, -5, 8), (-6, 4, 7), (-3, 10, -2), (6, 5, 8), (-9, 2, 4), (10, -1, -3), (10, 3, -5), (-6, 8, -9), (4, -7, 2), (-2, 6, 8), (7, -10, 1), (4, -3, -5), (5, 8, 1), (-6, -10, 9), (-4, 3, 7), (-4, -9, -1), (2, 5, -7), (10, 3, 6), (2, -9, -7), (6, -5, 3), (-1, 10, 4), (10, -3, -9), (-7, -2, 6), (1, 5, 8), (-2, -6, -9), (-3, 8, -7), (-10, 4, -5), (-5, -1, 3), (2, 9, 10), (-8, 4, -6), (-8, 10, -7), (-5, -2, -6), (3, 9, -1), (1, 7, 5), (6, -2, 8), (3, -9, -4), (-6, 8, 4), (1, 7, 9), (5, -2, -10), (-8, -6, 2), (7, -3, 5), (-9, 4, 10), (2, 10, 7), (8, 1, 6), (-3, -5, 4), (5, -4, -1), (7, -3, -8), (10, 6, 9), (10, -1, 5), (-4, -6, -3), (2, -9, 8), (-1, -5, 9), (-6, -2, 4), (-3, -7, -8), (-4, -9, -2), (10, 8, 3), (5, -1, -7), (1, -3, -4), (-6, 8, 9), (-5, -7, 2), (-7, -9, 8), (-10, -6, -3), (-5, 2, -4), (-5, 10, 3), (8, 7, 2), (4, 6, 9), (9, 7, -10), (-3, -5, -2), (-4, -1, 6), (5, 1, 3), (-8, -10, -9), (-2, -6, 7), (-6, 9, -7), (-2, -4, 3), (8, 5, 1), (4, 1, 10), (6, -3, 7), (-8, -2, -5), (3, -4, 5), (7, -2, 1), (-6, -9, -8), (-5, -8, -1), (-9, 4, -2), (7, -6, 3), (-5, -2, 7), (4, 10, -3), (8, -1, -6), (6, 2, 7), (-5, 10, -4), (-3, 8, -1), (7, -3, -5), (-4, -1, 10), (6, 2, -9), (-1, 9, 8), (10, -3, -7), (5, 4, -2), (8, -7, -10), (6, 9, 5), (2, 3, -1), (-3, -8, 7), (-1, -4, -9), (10, 5, -6), (-4, -9, -5), (-10, 8, 7), (1, -3, 6), (-10, 4, -8), (5, 9, 6), (-2, -3, -1), (-8, 2, 1), (5, 6, -4), (7, 9, 10), (4, -3, 10), (1, 8, 7), (6, -5, 9), (10, 8, 4), (-2, -5, 6), (-3, -7, 1), (6, 3, 1), (-10, 9, -5), (7, -4, -8), (6, -8, -5), (3, 4, -1), (2, 9, 7), (9, 10, -8), (2, 4, -3), (-5, -7, -1), (8, -4, -9), (3, -2, 7), (-5, -1, -6), (-3, -7, 10), (1, -9, 2), (4, 8, -6), (3, -10, 1), (-7, 9, -5), (-4, -2, -6), (6, 7, 2), (10, -9, 5), (-4, 3, 1), (-2, 7, -8), (3, 4, 9), (-1, -6, 5), (-7, 6, -10), (1, -5, -2), (9, 3, -8), (9, -10, 3), (1, -5, -6), (2, -8, 4), (7, 8, -4), (2, 1, -10), (6, 5, 9), (-4, -2, -10), (-1, 9, -5), (3, 7, -8), (-3, -10, -8), (-9, 7, 4), (-2, -5, 6), (3, 10, -5), (6, 8, -9), (-4, 7, -1), (-9, 8, 6), (-10, 4, 7), (-3, -5, -1), (8, -7, -6), (2, -5, -10), (-9, -3, 1), (-8, 2, -4), (6, -1, -7), (-5, -9, -10), (-8, -1, 9), (5, -2, -3), (-10, 6, -7), (3, 4, 7), (-2, 1, -10), (6, -9, -5), (5, 2, -6), (7, -3, 8), (-1, -10, 4), (7, -6, 8), (-10, 2, 5), (9, 4, -1), (9, 1, 8), (4, -6, -7), (10, -2, -5), (-1, 10, 2), (-7, -6, -4), (-5, 9, 8), (-9, 7, 2), (-3, -8, -1), (-5, 6, -10), (3, -4, 8), (1, -10, 5), (-7, 9, 2), (-3, 10, -1), (5, -2, -6), (-9, -7, -8), (-8, -7, -5), (4, 9, 1), (-10, 2, 6), (-3, 9, -7), (-8, -2, 10), (6, 5, -4), (-4, 2, 6), (10, 9, -8), (-5, 1, 3), (-4, 7, 6), (-10, 8, -9), (-5, -1, -2), (-4, -3, -9), (-7, 2, 10), (-6, 5, 8), (10, 1, 7), (-2, 5, 9), (-3, 8, 6), (10, 8, 4), (-5, 2, -6), (-1, -3, -7), (-6, -3, -9), (-1, -8, 10), (7, 4, -5), (-8, -5, -2), (-6, -7, 9), (-4, 10, -3), (6, -3, 7), (4, 2, 9), (-8, 5, -10), (5, 3, 7), (6, 10, 9), (-2, 8, -4), (8, -5, -10), (-2, -9, 1), (7, 4, -6), (-5, -7, 8), (-6, 3, -2), (9, 1, 10), (5, 2, -7), (4, -8, -9), (6, -3, 1), (6, 8, -10), (-4, -2, 1), (7, 5, 9), (-9, 2, 5), (-7, -8, 4), (1, -6, 3), (10, -8, 3), (-4, -2, -7), (9, 6, 1), (7, 6, 8), (9, 2, 3), (-10, -5, -1), (-9, -4, -8), (-10, 1, 6), (2, 7, 3), (-5, 10, 1), (3, -7, 2), (-9, -8, 4), (10, 3, 1), (-6, -9, -2), (-4, 8, 5), (10, 2, -7), (-9, 1, -6), (4, -3, -8), (-2, 7, -5), (-10, 1, 4), (3, -6, -9), (-3, -1, 7), (-6, 8, -9), (2, 4, -10), (-9, -6, -1), (-2, 4, 5), (-10, 8, 7), (-4, 6, -2), (7, 3, -8), (-1, 5, 10), (-2, 5, 6), (3, 8, 7), (1, -10, 9), (-1, 10, -6), (-4, 3, 7), (2, -5, 9), (8, 2, 4), (-6, 1, -9), (-7, -5, -3), (1, 8, 4), (-7, 9, -6), (-10, 2, -3), (-6, -1, 8), (2, -3, 9), (-4, 7, -5), (-6, -7, -3), (2, 10, 9), (5, -8, -1), (2, -4, 7), (-6, -3, 8), (-1, -10, 5), (4, 3, -10), (9, 1, -7), (5, 2, 8), (-7, 2, -5), (-10, 1, 3), (-4, -6, 8), (5, 7, 10), (6, -3, -4), (-2, 1, -9), (5, 4, -9), (-7, -2, -3), (-10, 1, -8), (-2, -8, 4), (5, -7, -1), (-9, -3, -6), (3, -7, 1), (9, 4, -6), (-2, 5, 8), (-2, 6, 5), (10, -8, -7), (-9, -4, 1), (-8, -4, 2), (-7, -9, 6), (10, -1, 5), (4, 7, -3), (-5, 10, 1), (8, 9, -6), (6, 9, -1), (2, -4, -5), (3, 10, 7), (-1, -5, -7), (-10, 3, 8), (6, 4, 9), (-7, -2, 4), (-8, 6, -10), (-5, -1, 9), (-7, -1, 9), (-6, 2, -5), (10, -4, 8), (10, 5, 1), (-8, 2, -7), (3, 6, -9), (-1, 2, -7), (-10, 9, 4), (-3, 8, 5), (-3, 7, 4), (8, 9, 2), (10, 5, -1), (9, -6, -1), (-2, 5, -8), (10, -7, 4), (-5, -8, -10), (-1, -3, 2), (4, -9, 6), (1, 4, 10), (8, 9, -3), (6, -7, 2), (4, -9, -1), (10, -6, 2), (7, -5, -3), (2, 10, 6), (-9, 1, 4), (-8, -5, 3), (2, 4, 5), (10, -9, -7), (6, -8, -1), (2, -8, -3), (-1, -4, -6), (10, 5, -9), (7, -6, -3), (-4, 10, -5), (-1, -2, 8), (3, -8, -7), (6, 2, 10), (-5, 1, -4), (10, -8, -2), (4, 6, -1), (-7, 3, 9), (-10, 4, 9), (-8, -2, 1), (6, -7, -3), (-4, -9, -5), (1, 2, -10), (7, 3, 6), (4, -5, 7), (1, 8, -10), (3, -6, -9), (-1, -9, -6), (-5, -10, -4), (3, 7, 8), (-6, 5, 9), (3, -1, -8), (-10, 7, -2), (-6, -5, 1), (2, 3, 10), (-9, -4, 8), (-3, 9, -7), (-8, 6, -2), (-1, -5, -4), (-2, -7, -9), (5, -8, 3), (-4, 6, -1), (4, 9, 3), (-10, -5, -6), (-2, 7, -1), (7, 10, -2), (3, 1, 4), (8, -6, 5), (8, 9, 1), (2, -10, 5), (3, -4, 7), (-2, -6, -5), (-1, 4, -3)] # clauses = [(-9, -36, 29), (26, -47, 34), (22, 33, -6), (32, -11, -8), (24, -27, -5), (45, -4, 46), (1, 28, -25), (39, -16, 15), (-20, 10, 13), (12, 43, 18), (40, 2, -23), (17, -21, 14), (41, 48, 38), (49, 35, -19), (-31, 3, -7), (30, -37, 44), (49, -47, -9), (-6, 2, 11), (39, -24, 14), (-30, -20, 41), (31, 28, 16), (42, -10, 15), (-5, 45, -29), (-46, 4, -18), (-8, 12, 3), (38, 44, -1), (-26, 22, 34), (7, -35, -17), (-32, -40, -27), (19, 50, -23), (43, 33, -37), (25, 21, 48), (8, 35, -30), (18, 34, -48), (-13, 29, 11), (-2, -6, -22), (17, 4, 37), (41, -23, -9), (10, 28, -45), (-1, -36, -25), (19, -47, 12), (24, -20, -50), (42, -49, 44), (-5, 38, -3), (-33, -27, -43), (-14, -26, -16), (40, -21, 15), (-7, 39, 46), (-27, 14, 30), (-45, -21, 15), (2, -13, -6), (-22, -25, -46), (-4, -17, 19), (26, -33, 38), (-12, 43, 48), (8, -41, 36), (31, -18, 49), (-39, 3, -29), (-11, -16, -40), (-42, -34, 5), (-32, 23, 35), (-28, 50, 9), (20, -24, 37), (-44, 10, -47), (32, -11, 20), (-37, -50, 38), (-10, -34, -19), (44, -18, 8), (-48, 4, 31), (-30, -43, 39), (2, 47, 33), (26, -7, 15), (-16, 45, -24), (-49, 5, -40), (14, -22, 12), (36, -46, 13), (-9, 17, -25), (-41, 3, 1), (35, 42, -23), (-29, 27, 6), (-7, -9, -35), (-43, 31, -14), (-24, -47, 19), (41, 40, -6), (33, -18, 46), (27, -22, -16), (21, -39, 12), (-28, 20, 11), (36, 30, 48), (-5, -25, -45), (-1, 2, 17), (-3, -49, -50), (-44, -13, 29), (-10, -8, 23), (37, 38, 26), (-32, 4, -34), (-27, 39, -24), (13, -28, 47), (-15, 37, 6), (-35, -3, -11), (8, -31, -18), (-25, -30, 46), (2, -29, 44), (1, 7, -12), (-17, 23, 4), (-49, -33, 34), (-48, -32, 16), (9, 50, -45), (5, 19, -43), (-20, 22, -14), (38, 36, 41), (-42, -26, -10), (-45, 7, 23), (28, 37, 21), (13, -17, 33), (-6, 50, -8), (41, 15, 4), (1, -49, -3), (-2, 35, -29), (-32, -9, -47), (-30, 11, -19), (20, 25, 40), (18, -27, 48), (-16, -12, 46), (42, 38, 10), (-39, 26, 24), (-34, 44, -22), (14, -5, 31), (36, 29, -34), (50, -10, -20), (-11, -5, -38), (30, 44, 45), (-33, -19, 48), (47, -7, -25), (13, -26, -9), (-49, -1, 15), (12, -41, 23), (46, 28, -18), (-39, 43, 31), (-27, 17, 14), (35, -37, -6), (3, -2, -8), (-21, 24, 42), (22, 40, -4), (47, -20, 4), (-24, 19, -37), (-12, 8, 39), (48, -17, -23), (-2, 44, -18), (43, -40, 41), (34, -45, -29), (-46, 27, -28), (-21, -38, -14), (49, -22, -33), (-15, -26, -50), (16, -36, -10), (9, 11, -31), (30, -3, 13), (35, 25, 1), (6, -42, -7), (-34, -27, -45), (33, 10, -24), (31, 28, -36), (-6, -50, -44), (12, 17, 46), (-38, 14, -29), (-47, -32, -37), (1, -18, -20), (4, -19, 25), (13, -15, 49), (5, -48, -43), (-30, -22, -23), (3, -7, 41), (39, 16, 9), (-2, 21, -26), (-42, -8, 40), (-19, 28, -17), (-9, 18, -8), (43, 22, -25), (41, -34, -49), (-10, -13, 35), (31, 5, -36), (32, -33, -2), (39, -30, -16), (46, 15, -24), (50, -1, -12), (20, -40, -23), (44, 7, -27), (-37, 38, 26), (42, -4, -45), (-6, 14, -3), (-11, -21, -29), (-17, -26, -22), (43, -32, 50), (33, -30, -46), (3, 7, 25), (19, -48, 45), (47, -6, 16), (1, -8, -36), (5, 35, 15), (34, 14, -12), (31, -42, -13), (-24, 37, 27), (20, 40, 21), (-9, -10, 41), (-29, -18, -11), (39, 4, 44), (23, 38, -2), (-21, -41, 2), (25, 42, 39), (50, 20, 24), (-46, 37, -4), (6, 13, 44), (-23, -17, 7), (14, 49, -8), (32, -27, 29), (45, 34, -47), (38, -18, 48), (43, 26, 5), (30, -16, -22), (-19, -33, 10), (-36, 28, 15), (31, -35, 9), (12, -11, 3), (49, -43, -6), (-42, 48, -41), (1, 39, 17), (-37, -32, -18), (-7, -35, -34), (19, 26, 29), (36, -47, 3), (30, 25, 14), (-11, -23, 46), (-31, 28, 20), (-16, 9, -13), (27, 15, -40), (-21, 8, 50), (-2, 45, -24), (-10, 44, 5), (4, -12, -22), (-44, 38, 23), (11, -29, -21), (15, 27, -37), (-10, -3, 34), (-49, 43, 14), (-46, 17, -5), (16, 2, 18), (-22, -33, -39), (7, 35, -25), (8, -47, -19), (1, 20, 12), (40, -31, 9), (-32, 13, 45), (24, -36, -30), (-50, -42, 4), (6, 28, -48), (-33, 20, -34), (9, -7, -43), (-2, 46, 13), (24, 42, 38), (17, -12, 36), (-29, -28, -50), (16, 26, -32), (19, -25, -18), (-47, 23, 10), (-30, -31, 22), (-40, 45, 37), (-27, -21, -35), (-44, -49, -41), (48, 11, 1), (-14, -8, -39), (-15, -5, -4), (29, 39, 17), (-31, -23, -47), (5, -2, 18), (15, -25, 45), (-28, 41, 27), (44, -10, -6), (3, 12, 26), (8, -48, -7), (-46, 1, 49), (30, -36, -32), (43, -11, -40), (4, -20, 37), (-21, 42, -38), (14, 35, -50), (-13, -24, -19), (9, -33, -22), (35, -18, -6), (-36, -42, 24), (-11, 26, 14), (1, -33, 50), (39, 34, 9), (7, 25, -28), (-16, 44, 37), (-43, -49, 47), (-40, 23, 22), (5, 12, -4), (-3, -8, 27), (32, -45, -38), (10, 2, 41), (29, 19, -20), (-48, 13, 17), (-46, -21, -31), (48, -5, 37), (-24, 49, -27), (40, -11, 23), (34, 35, -26), (-6, -29, -28), (-45, -1, 22), (-25, 9, -3), (44, 50, 12), (-2, -31, -15), (43, 33, 16), (46, -36, 21), (-38, -19, -47), (-13, 14, -7), (-41, 17, -32), (20, -8, -42), (-39, 4, -30), (-15, -14, -24), (50, -17, -36), (-46, 37, -35), (-27, 19, -33), (-41, 34, -31), (47, 6, -22), (25, 42, 38), (5, -10, 30), (-4, 9, 21), (1, 26, 29), (7, -39, -23), (40, -13, 32), (-45, 12, -43), (28, 49, -48), (16, -8, 2), (3, 11, -20), (48, 40, -26), (-1, -20, -37), (36, 49, 43), (-22, 5, 42), (-4, 38, 29), (18, -3, -28), (46, 24, -10), (35, -44, -30), (6, 25, 39), (-33, 19, 11), (14, -15, 23), (-7, -17, 32), (12, 13, 45), (-31, -50, -41), (34, -8, 2), (9, -47, 27), (49, -19, -39), (-13, 41, 26), (35, -18, 20), (33, 21, 1), (-37, 7, 44), (9, 40, -34), (-10, -14, 5), (-16, -48, 38), (28, 3, -4), (47, -46, 25), (-45, -22, 6), (-24, 36, 8), (-31, 2, -11), (-50, 15, 42), (-32, 27, -43), (-30, 23, -29), (-24, 27, -44), (-4, 16, 42), (38, -28, 47), (-40, -17, -43), (-31, -5, -15), (-19, -26, -46), (9, 50, -48), (-32, -29, 34), (-8, 36, -23), (-45, 10, -7), (-12, 41, 2), (-37, 25, 49), (11, 14, -6), (1, 3, -13), (-39, -22, 35), (-33, 20, 30), (35, 42, -4), (-20, 38, -31), (-36, 15, 16), (-30, 18, 25), (6, 14, 17), (-40, 8, 37), (11, 47, -9), (3, 13, -45), (-27, 12, 32), (21, -22, -10), (46, -26, 29), (-2, 33, 48), (-23, -19, 1), (5, 43, -44), (-41, 28, 7), (-24, 49, -34), (38, -32, 43), (-23, 25, -26), (-13, 33, 12), (42, 30, -40), (3, 46, -18), (-34, -24, -37), (28, 15, -49), (6, -7, 35), (-19, -39, 29), (-17, -22, -16), (8, 11, 2), (45, 41, 21), (-36, -50, 4), (-48, -27, -20), (31, -1, -9), (47, -14, 10), (-4, -7, -50), (46, -27, -6), (-24, 9, -18), (-15, 34, 40), (35, -3, 8), (42, -43, -33), (12, -29, -16), (11, -37, 20), (38, 22, 41), (26, -21, 44), (-13, -45, 39), (10, 25, 48), (36, -49, 17), (47, -14, 30), (-2, 31, -23), (-19, 32, 28), (-12, 27, -36), (6, 1, 29), (34, 45, 14), (2, -24, -19), (-46, -44, -21), (-48, -7, 13), (-40, 35, -25), (17, 23, -39), (30, 50, -42), (-41, 31, -22), (3, -20, 18), (-47, -5, 11), (43, 4, -33), (-15, -38, -10), (-8, 49, 26), (16, -9, 28), (-4, -6, -9), (42, 25, 26), (-44, 22, -28), (-40, -5, -20), (1, -39, 14), (-45, 7, -15), (41, 33, 35), (-16, 13, -36), (-48, 29, 37), (-31, -21, 30), (24, 8, 17), (3, -46, 10), (-19, 50, -12), (23, -11, -38), (-34, 47, -2), (-18, -27, 43), (31, -17, -30), (29, 21, -50), (-36, 28, -32), (-10, 16, -47), (-37, 14, 2), (41, 44, -9), (-1, -5, -49), (48, -7, 11), (23, 22, 43), (-45, 12, 39), (8, -18, 40), (46, -6, -4), (-25, -27, -15), (-3, 38, -34), (-13, 35, -33), (-26, 24, 20), (-10, 36, 39), (11, -38, -50), (24, -33, 43), (22, -16, 45), (37, -19, 6), (27, -35, 14), (13, -3, 48), (21, 15, 26), (-44, 34, 49), (-7, 18, -20), (-23, 46, 29), (28, -25, -30), (-12, -41, 31), (5, -17, -4), (-32, -47, -1), (9, 40, 2), (40, 30, 41), (3, 13, 47), (-48, 21, -22), (-39, -35, 18)] wcnf = WCNF() for each in clauses: wcnf.append(each, weight=1) rc2 = RC2(wcnf) model = rc2.compute() print(model, rc2.cost)