예제 #1
0
    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)
예제 #2
0
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]
예제 #3
0
    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
예제 #4
0
    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)
예제 #5
0
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
예제 #6
0
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
예제 #7
0
    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))])
예제 #8
0
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
예제 #9
0
    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)
예제 #10
0
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")
예제 #11
0
    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
예제 #13
0
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
예제 #14
0
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
예제 #15
0
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]
예제 #16
0
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
예제 #17
0
    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
예제 #18
0
    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
예제 #19
0
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]
예제 #20
0
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
예제 #21
0
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)