Example #1
0
def get_formula(observations, decision_variables_p, p_to_atom,
                decision_variables_a, a_to_atom, no_police, no_medics,
                indices_list, state_codes, no_rounds):
    formula = CNF()

    initial_state_clauses = get_initial_state_clauses(observations,
                                                      decision_variables_p,
                                                      p_to_atom, state_codes,
                                                      indices_list)

    action_precondition_clauses = get_action_precondition_clauses(
        decision_variables_a, p_to_atom, a_to_atom, no_police, no_medics,
        indices_list)

    action_interference_clauses = get_action_interference_clauses(
        decision_variables_a, a_to_atom, state_codes, no_rounds)

    fact_achievement_clauses = get_fact_achievement_clauses(
        decision_variables_p, p_to_atom, decision_variables_a, a_to_atom)

    permanent_clauses = get_permanent_clauses(p_to_atom, decision_variables_a,
                                              a_to_atom, no_police, no_medics,
                                              indices_list, state_codes)

    clauses = initial_state_clauses + action_precondition_clauses + action_interference_clauses +\
              fact_achievement_clauses + permanent_clauses

    formula.extend(clauses)

    return formula
Example #2
0
def get_clause(t, c):
    p = CNF()
    vpool = IDPool()
    # add numbers that are prefilled and add all boolean variables to the pool of used variables
    for i in range(n):
        for j in range(n):
            for z in range(1, n + 1):
                vpool.id('v{0}'.format(s(i, j, z)))
            if t[i][j] != "_":
                p.extend(
                    PBEnc.equals(lits=[s(i, j, t[i][j])], bound=1,
                                 vpool=vpool).clauses)
    # ensure there is at least one value per square
    for x in range(n):
        for y in range(n):
            lits = list(map(lambda z: s(x, y, z), range(1, n + 1)))
            p.extend(PBEnc.atleast(lits=lits, bound=1, vpool=vpool).clauses)
    # ensure there exists only 1 of each value in each row and column
    for z in range(1, n + 1):
        for a in range(n):
            lits_row = list(map(lambda b: s(a, b, z), range(n)))
            lits_col = list(map(lambda b: s(b, a, z), range(n)))
            p.extend(PBEnc.equals(lits=lits_row, bound=1, vpool=vpool).clauses)
            p.extend(PBEnc.equals(lits=lits_col, bound=1, vpool=vpool).clauses)
    # ensure inequalities hold
    for x in c:
        (a, b) = x
        (i1, j1) = a
        (i2, j2) = b
        lits = list(map(lambda z: s(i1, j1, z), range(1, n + 1))) + \
               list(map(lambda z: s(i2, j2, z), range(1, n + 1)))
        weights = list(range(1, n + 1)) + list(range(-1, -n - 1, -1))
        p.extend(
            PBEnc.atleast(lits=lits, weights=weights, bound=1,
                          vpool=vpool).clauses)
    return p
Example #3
0
    def encode(self, label, nof_terms):
        """
            Encode the problem of computing a DS of size nof_terms.
        """

        self.nof_terms = nof_terms
        self.nof_samps = len(self.samps)

        enc = CNF()

        # constraint 2
        for j in range(1, self.nof_terms + 1):
            for r in range(1, self.nof_feats + 1):
                enc.append([self.pvar(j, r), self.nvar(j, r)])

        # constraint 3
        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 = []
                    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.pvar(j, r))
                            cl.append(-self.nvar(j, r))
                            shift += 1
                        else:
                            cl.append(-self.slvar(j, r, q, shift))

                    enc.append(cl)

        # constraint 4
        for j in range(1, self.nof_terms + 1):
            for q in self.samps[label]:
                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
                        enc.append([self.pvar(j, r), -self.crvar(j, q + 1)])
                        enc.append([self.nvar(j, r), -self.crvar(j, q + 1)])
                        shift += 1
                    else:
                        enc.append([
                            self.slvar(j, r, q, shift), -self.crvar(j, q + 1)
                        ])

        # symmetry breaking constraints
        if self.options.bsymm:
            self.add_bsymm(enc)

        # constraint 5
        if self.options.accuracy == 100.0:
            for q in self.samps[label]:
                enc.append([
                    self.crvar(j, q + 1) for j in range(1, self.nof_terms + 1)
                ])
        else:
            for q in self.samps[label]:
                cv = self.cvvar(q + 1)
                enc.append([-cv] + [
                    self.crvar(j, q + 1) for j in range(1, self.nof_terms + 1)
                ])

                for j in range(1, self.nof_terms + 1):
                    enc.append([-self.crvar(j, q + 1), cv])

            cnum = int(self.options.accuracy * len(self.samps[label]) / 100.0)
            al = CardEnc.atleast(
                [self.cvvar(q + 1) for q in self.samps[label]],
                bound=cnum,
                top_id=enc.nv,
                encoding=self.options.enc)
            if al:
                enc.extend(al.clauses)

        # 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.pvar(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)

        # saving comments
        for j in range(1, self.nof_terms + 1):
            for r in range(1, self.nof_feats + 1):
                enc.comments.append('c p({0}, {1}) => v{2}'.format(
                    j, r, self.pvar(j, r)))
                enc.comments.append('c n({0}, {1}) => v{2}'.format(
                    j, r, self.nvar(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 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
Example #4
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 = CNF()

        # 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)]
            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)])

        # leaf constraints
        enc.append([-self.leaf(1)])  # first node can't be a leaf
        enc.append([self.leaf(self.nof_lits)])  # last node should be a leaf

        # 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)
                    ])

        # coverage constraints
        for i in self.samps[label]:
            cl = []

            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)

        # 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
Example #5
0
    def world_dynamics(self):
        # single tile dynamics
        dynamics = CNF()
        dynamics.extend(self.U_tile_dynamics())
        dynamics.extend(self.I_tile_dynamics())
        dynamics.extend(self.S_tile_dynamics())
        dynamics.extend(self.Q_tile_dynamics())
        dynamics.extend(self.H_tile_dynamics())

        # exactly one state for each tile
        dynamics.extend(self.first_turn_rules())
        dynamics.extend(self.unique_tile_dynamics())

        # use all teams
        # dynamics.extend(self.use_all_medics_dynamics())
        dynamics.extend(self.hadar_dynamics())
        dynamics.extend(self.naveh_dynamics())

        return dynamics
Example #6
0
max_problem_var = nv

enc = EncType.ladder

# Encode constraints for each column
for i in range(N**2):
    for v in range(N**2):
        # Atleast-1 clause
        col = [V[i][j][v] for j in range(N**2)]
        F.append(col)
        # Atmost-1 encoding
        card = pysat.card.CardEnc.atmost(lits=col,
                                         top_id=nv,
                                         bound=1,
                                         encoding=enc)
        F.extend(card.clauses)
        nv = card.nv

# Encode constraints for each row
for j in range(N**2):
    for v in range(N**2):
        # Atleast-1 clause
        row = [V[i][j][v] for i in range(N**2)]
        F.append(row)
        # Atmost-1 encoding
        card = pysat.card.CardEnc.atmost(lits=row,
                                         top_id=nv,
                                         bound=1,
                                         encoding=enc)
        F.extend(card.clauses)
        nv = card.nv
Example #7
0
def make_formula(n_police, n_medics, n_rows, n_cols, n_time):
    states = {'U', 'H', 'S', 'I', 'Q'}
    variables = {}
    formula = CNF()
    var_pool = IDPool()
    for t in range(n_time):
        for r in range(n_rows):
            for c in range(n_cols):
                for s in states:
                    variables[(r, c), t,
                              s] = var_pool.id(f'({r}, {c}), {t}, {s}')
                variables[(r, c), t, 'P'] = var_pool.id(
                    f'({r}, {c}), {t}, P')  # Police were used
                variables[(r, c), t, 'M'] = var_pool.id(
                    f'({r}, {c}), {t}, M')  # Medics were used
                variables[(r, c), t, 'SS'] = var_pool.id(
                    f'({r}, {c}), {t}, SS')  # Stayed sick from last time
    for t in range(n_time):
        formula.extend(
            CardEnc.atmost([
                variables[(r, c), t, 'P'] for r in range(n_rows)
                for c in range(n_cols)
            ],
                           bound=n_police,
                           vpool=var_pool))
        formula.extend(
            CardEnc.atmost([
                variables[(r, c), t, 'M'] for r in range(n_rows)
                for c in range(n_cols)
            ],
                           bound=n_medics,
                           vpool=var_pool))
        for r in range(n_rows):
            for c in range(n_cols):
                formula.extend(
                    CardEnc.equals([variables[(r, c), t, s] for s in states],
                                   vpool=var_pool))
                if t > 0:
                    formula.extend(
                        req_equiv([
                            -variables[(r, c), t - 1, 'Q'], variables[(r, c),
                                                                      t, 'Q']
                        ], [variables[(r, c), t, 'P']]))
                    formula.extend(
                        req_equiv([
                            -variables[(r, c), t - 1, 'I'], variables[(r, c),
                                                                      t, 'I']
                        ], [variables[(r, c), t, 'M']]))
                    formula.extend(
                        req_equiv([
                            variables[(r, c), t - 1, 'S'], variables[(r, c), t,
                                                                     'S']
                        ], [variables[(r, c), t, 'SS']]))
                    nearby_sick_condition = []
                    for r_, c_ in nearby(r, c, n_rows, n_cols):
                        nearby_sick_condition.append(variables[(r_, c_), t,
                                                               'SS'])
                        formula.extend(
                            req_imply([
                                variables[(r, c), t, 'SS'],
                                variables[(r_, c_), t - 1, 'H']
                            ], [
                                variables[(r_, c_), t, 'S'],
                                variables[(r_, c_), t, 'I']
                            ]))
                        # formula.extend(req_imply([variables[(r, c), t, 'SS']], [-variables[(r_, c_), t, 'H']]))
                    formula.extend(
                        req_imply([
                            variables[(r, c), t - 1, 'H'], variables[(r, c), t,
                                                                     'S']
                        ], nearby_sick_condition))
                if t + 1 < n_time:
                    formula.extend(
                        req_equiv([variables[(r, c), t, 'U']],
                                  [variables[(r, c), t + 1, 'U']]))
                    formula.extend(
                        req_imply([variables[(r, c), t, 'I']],
                                  [variables[(r, c), t + 1, 'I']]))
                    formula.extend(
                        req_imply([variables[(r, c), t + 1, 'S']], [
                            variables[(r, c), t, 'S'], variables[(r, c), t,
                                                                 'H']
                        ]))
                    formula.extend(
                        req_imply([variables[(r, c), t + 1, 'Q']], [
                            variables[(r, c), t, 'Q'], variables[(r, c), t,
                                                                 'S']
                        ]))
                if t == 0:
                    formula.append([-variables[(r, c), t, 'Q']])
                    formula.append([-variables[(r, c), t, 'I']])
                    if t + 1 < n_time:
                        formula.extend(
                            req_imply([variables[(r, c), t, 'S']], [
                                variables[(r, c), t + 1, 'S'],
                                variables[(r, c), t + 1, 'Q']
                            ]))
                        formula.extend(
                            req_imply([variables[(r, c), t, 'Q']],
                                      [variables[(r, c), t + 1, 'Q']]))
                    if t + 2 < n_time:
                        formula.extend(
                            req_imply([
                                variables[(r, c), t, 'S'],
                                variables[(r, c), t + 1, 'S']
                            ], [
                                variables[(r, c), t + 2, 'S'],
                                variables[(r, c), t + 2, 'Q']
                            ]))
                        formula.extend(
                            req_imply([
                                variables[(r, c), t, 'S'],
                                variables[(r, c), t + 1, 'Q']
                            ], [variables[(r, c), t + 2, 'Q']]))
                        formula.extend(
                            req_imply([variables[(r, c), t, 'Q']],
                                      [variables[(r, c), t + 2, 'H']]))
                    if t + 3 < n_time:
                        formula.extend(
                            req_imply([
                                variables[(r, c), t,
                                          'S'], variables[(r, c), t + 1, 'S'],
                                variables[(r, c), t + 2, 'S']
                            ], [variables[(r, c), t + 3, 'H']]))
                if 0 < t and t + 1 < n_time:
                    formula.extend(
                        req_imply([
                            -variables[(r, c), t - 1, 'S'], variables[(r, c),
                                                                      t, 'S']
                        ], [
                            variables[(r, c), t + 1, 'S'],
                            variables[(r, c), t + 1, 'Q']
                        ]))
                    formula.extend(
                        req_imply([
                            -variables[(r, c), t - 1, 'Q'], variables[(r, c),
                                                                      t, 'Q']
                        ], [variables[(r, c), t + 1, 'Q']]))
                if 0 < t and t + 2 < n_time:
                    formula.extend(
                        req_imply([
                            -variables[(r, c), t - 1, 'S'],
                            variables[(r, c), t, 'S'], variables[(r, c), t + 1,
                                                                 'S']
                        ], [
                            variables[(r, c), t + 2, 'S'],
                            variables[(r, c), t + 2, 'Q']
                        ]))
                    formula.extend(
                        req_imply([
                            -variables[(r, c), t - 1, 'S'],
                            variables[(r, c), t, 'S'], variables[(r, c), t + 1,
                                                                 'Q']
                        ], [variables[(r, c), t + 2, 'Q']]))
                    formula.extend(
                        req_imply([
                            -variables[(r, c), t - 1, 'Q'], variables[(r, c),
                                                                      t, 'Q']
                        ], [variables[(r, c), t + 2, 'H']]))
                if 0 < t and t + 3 < n_time:
                    formula.extend(
                        req_imply([
                            -variables[(r, c), t - 1, 'S'], variables[(r, c),
                                                                      t, 'S'],
                            variables[(r, c), t + 1,
                                      'S'], variables[(r, c), t + 2, 'S']
                        ], [variables[(r, c), t + 3, 'H']]))
    return var_pool, formula
Example #8
0
def solve_problem2(input):
    num_rounds = len(input["observations"])
    observations = input["observations"]
    num_police = input["police"]
    num_medics = input["medics"]
    rows = len(observations[0])
    columns = len(observations[0][0])
    c = CNF()

    # init
    unpopulated = set()
    for round in range(num_rounds):
        for i in range(rows):
            for j in range(columns):
                condition = observations[round][i][j]
                if condition == "?":  # one condition only
                    c.extend([[-get_k("H", round, i, j), -get_k("I", round, i, j)],
                              [-get_k("H", round, i, j), -get_k("U", round, i, j)],
                              [-get_k("H", round, i, j), -get_k("S", round, i, j, 1)],
                              [-get_k("H", round, i, j), -get_k("S", round, i, j, 2)],
                              [-get_k("H", round, i, j), -get_k("S", round, i, j, 3)],
                              [-get_k("H", round, i, j), -get_k("Q", round, i, j, 1)],
                              [-get_k("H", round, i, j), -get_k("Q", round, i, j, 2)],
                              [-get_k("I", round, i, j), -get_k("U", round, i, j)],
                              [-get_k("I", round, i, j), -get_k("S", round, i, j, 1)],
                              [-get_k("I", round, i, j), -get_k("S", round, i, j, 2)],
                              [-get_k("I", round, i, j), -get_k("S", round, i, j, 3)],
                              [-get_k("I", round, i, j), -get_k("Q", round, i, j, 1)],
                              [-get_k("I", round, i, j), -get_k("Q", round, i, j, 2)],
                              [-get_k("U", round, i, j), -get_k("S", round, i, j, 1)],
                              [-get_k("U", round, i, j), -get_k("S", round, i, j, 2)],
                              [-get_k("U", round, i, j), -get_k("S", round, i, j, 3)],
                              [-get_k("U", round, i, j), -get_k("Q", round, i, j, 1)],
                              [-get_k("U", round, i, j), -get_k("Q", round, i, j, 2)],
                              [-get_k("Q", round, i, j, 1), -get_k("S", round, i, j, 1)],
                              [-get_k("Q", round, i, j, 1), -get_k("S", round, i, j, 2)],
                              [-get_k("Q", round, i, j, 1), -get_k("S", round, i, j, 3)],
                              [-get_k("Q", round, i, j, 1), -get_k("Q", round, i, j, 2)],
                              [-get_k("Q", round, i, j, 2), -get_k("S", round, i, j, 1)],
                              [-get_k("Q", round, i, j, 2), -get_k("S", round, i, j, 2)],
                              [-get_k("Q", round, i, j, 2), -get_k("S", round, i, j, 3)],
                              [-get_k("S", round, i, j, 1), -get_k("S", round, i, j, 2)],
                              [-get_k("S", round, i, j, 1), -get_k("S", round, i, j, 3)],
                              [-get_k("S", round, i, j, 2), -get_k("S", round, i, j, 3)],
                              [get_k("H", round, i, j), get_k("I", round, i, j), get_k("U", round, i, j),
                               get_k("Q", round, i, j, 1), get_k("Q", round, i, j, 2),
                               get_k("S", round, i, j, 1), get_k("S", round, i, j, 2), get_k("S", round, i, j, 3)]])
                if condition == "S":
                    c.extend([[-get_k("H", round, i, j)], [-get_k("I", round, i, j)], [-get_k("U", round, i, j)],
                              [-get_k("Q", round, i, j, 1)], [-get_k("Q", round, i, j, 2)],
                              [get_k("S", round, i, j, 1), get_k("S", round, i, j, 2), get_k("S", round, i, j, 3)]])
                if condition == "H":
                    c.extend([[get_k("H", round, i, j)], [-get_k("I", round, i, j)], [-get_k("U", round, i, j)],
                              [-get_k("Q", round, i, j, 1)], [-get_k("Q", round, i, j, 2)],
                              [-get_k("S", round, i, j, 1)], [-get_k("S", round, i, j, 2)],
                              [-get_k("S", round, i, j, 3)]])
                if condition == "Q":
                    c.extend([[-get_k("H", round, i, j)], [-get_k("I", round, i, j)], [-get_k("U", round, i, j)],
                              [get_k("Q", round, i, j, 1), get_k("Q", round, i, j, 2)],
                              [-get_k("S", round, i, j, 1)], [-get_k("S", round, i, j, 2)],
                              [-get_k("S", round, i, j, 3)]])
                if condition == "I":
                    c.extend([[-get_k("H", round, i, j)], [get_k("I", round, i, j)], [-get_k("U", round, i, j)],
                              [-get_k("Q", round, i, j, 1)], [-get_k("Q", round, i, j, 2)],
                              [-get_k("S", round, i, j, 1)], [-get_k("S", round, i, j, 2)],
                              [-get_k("S", round, i, j, 3)]])
                if condition == "U":
                    unpopulated.add((i, j))
                if round == 0:
                    if condition == '?':
                        c.extend(
                            [[get_k("S", 0, i, j, 3), get_k("H", 0, i, j), get_k("U", 0, i, j)],
                             [-get_k("S", 0, i, j, 2)]
                                , [-get_k("S", 0, i, j, 1)], [-get_k("Q", 0, i, j, 1)], [-get_k("Q", 0, i, j, 2)],
                             [-get_k("I", 0, i, j)]])
                    if condition == "S":  # if S, stay S for 3 rounds
                        c.append([get_k("S", 0, i, j, 3)])

    # all unpopulated are unpopulated in all rounds
    for pair in unpopulated:
        for round in range(num_rounds):
            c.extend([[-get_k("H", round, pair[0], pair[1])], [-get_k("I", round, pair[0], pair[1])],
                      [get_k("U", round, pair[0], pair[1])],
                      [-get_k("Q", round, pair[0], pair[1], 1)], [-get_k("Q", round, pair[0], pair[1], 2)],
                      [-get_k("S", round, pair[0], pair[1], 1)], [-get_k("S", round, pair[0], pair[1], 2)],
                      [-get_k("S", round, pair[0], pair[1], 3)]])

    index = 1
    k = v_id.vpool.id(1)  # current action
    for round in range(num_rounds - 1):
        round_actions = []
        for a in all_actions(observations[round], num_police, num_medics):
            affected = []
            cur_map = [list(r) for r in observations[round]]
            stop = False
            l = []  # consists of preconditions and effects of current action
            num_Q = 0
            num_I = 0
            for pair in a:
                if observations[round + 1][pair[1][0]][pair[1][1]] != '?' and pair[0] != \
                        observations[round + 1][pair[1][0]][pair[1][1]]:
                    stop = True
                    break
                affected.append(pair[1])
                cur_map[pair[1][0]][pair[1][1]] = pair[0]  # updated map if action occurs, used for infection
                if pair[0] == 'Q':  # precondition + effects
                    l.append(
                        [-k, get_k("S", round, pair[1][0], pair[1][1], 1), get_k("S", round, pair[1][0], pair[1][1], 2),
                         get_k("S", round, pair[1][0], pair[1][1], 3)])
                    l.append([-k, get_k("Q", round + 1, pair[1][0], pair[1][1], 2)])
                    num_Q += 1
                if pair[0] == 'I':
                    l.append([-k, get_k("H", round, pair[1][0], pair[1][1])])
                    l.append([-k, get_k("I", round + 1, pair[1][0], pair[1][1])])
                    num_I += 1
            if stop == True:
                index += 1
                k = v_id.vpool.id(index)
                continue

            round_actions.append(k)
            c.extend(l)

            # if not all police or medics were used, then ? cant be H or S respectively
            if num_I < num_medics:
                for i in range(rows):
                    for j in range(columns):
                        if cur_map[i][j] == '?':
                            c.append([-k, -get_k("H", round, i, j)])

            if num_Q < num_police:
                for i in range(rows):
                    for j in range(columns):
                        if cur_map[i][j] == '?':
                            c.extend([[-k, -get_k("S", round, i, j, 1)],
                                      [-k, -get_k("S", round, i, j, 2)],
                                      [-k, -get_k("S", round, i, j, 3)]])

            for i in range(rows):
                for j in range(columns):
                    if (i, j) in affected:
                        continue
                    else:
                        condition = cur_map[i][j]

                    # update S (depends on the chosen action)
                    if condition == 'S':
                        c.extend([[-k, -get_k("S", round, i, j, 3), get_k("S", round + 1, i, j, 2)],
                                  [-k, -get_k("S", round, i, j, 2), get_k("S", round + 1, i, j, 1)],
                                  [-k, -get_k("S", round, i, j, 1), get_k("H", round + 1, i, j)]])
                        continue

                    if condition == '?':
                        c.extend([[-k, -get_k("S", round, i, j, 3), get_k("S", round + 1, i, j, 2)],
                                  [-k, -get_k("S", round, i, j, 2), get_k("S", round + 1, i, j, 1)],
                                  [-k, -get_k("S", round, i, j, 1), get_k("H", round + 1, i, j)]])

                    # conditional infection
                    neighbors_unknown = []
                    if condition == "H":
                        # infect if there's an S
                        if ((i - 1 >= 0 and cur_map[i - 1][j] == 'S') or
                                (i + 1 < rows and cur_map[i + 1][j] == 'S') or
                                (j - 1 >= 0 and cur_map[i][j - 1] == 'S') or
                                (j + 1 < columns and cur_map[i][j + 1] == 'S')):
                            c.extend([[-k, get_k("S", round + 1, i, j, 3)]])
                            continue

                        # conditional infect if there's a ? (if ? is S)
                        else:
                            if i - 1 >= 0 and cur_map[i - 1][j] == '?':
                                c.extend([[-k, -get_k("S", round, i - 1, j, 1), get_k("S", round + 1, i, j, 3)],
                                          [-k, -get_k("S", round, i - 1, j, 2), get_k("S", round + 1, i, j, 3)],
                                          [-k, -get_k("S", round, i - 1, j, 3), get_k("S", round + 1, i, j, 3)]])
                                neighbors_unknown.append((i - 1, j))
                            if i + 1 < rows and cur_map[i + 1][j] == '?':
                                c.extend([[-k, -get_k("S", round, i + 1, j, 1), get_k("S", round + 1, i, j, 3)],
                                          [-k, -get_k("S", round, i + 1, j, 2), get_k("S", round + 1, i, j, 3)],
                                          [-k, -get_k("S", round, i + 1, j, 3), get_k("S", round + 1, i, j, 3)]])
                                neighbors_unknown.append((i + 1, j))
                            if j - 1 >= 0 and cur_map[i][j - 1] == '?':
                                c.extend([[-k, -get_k("S", round, i, j - 1, 1), get_k("S", round + 1, i, j, 3)],
                                          [-k, -get_k("S", round, i, j - 1, 2), get_k("S", round + 1, i, j, 3)],
                                          [-k, -get_k("S", round, i, j - 1, 3), get_k("S", round + 1, i, j, 3)]])
                                neighbors_unknown.append((i, j - 1))
                            if j + 1 < columns and cur_map[i][j + 1] == '?':
                                c.extend([[-k, -get_k("S", round, i, j + 1, 1), get_k("S", round + 1, i, j, 3)],
                                          [-k, -get_k("S", round, i, j + 1, 2), get_k("S", round + 1, i, j, 3)],
                                          [-k, -get_k("S", round, i, j + 1, 3), get_k("S", round + 1, i, j, 3)]])
                                neighbors_unknown.append((i, j + 1))

                        # if no one infected, stay H
                        lst = [get_k("S", round, n[0], n[1], 1) for n in neighbors_unknown] + \
                              [get_k("S", round, n[0], n[1], 2) for n in neighbors_unknown] + \
                              [get_k("S", round, n[0], n[1], 3) for n in neighbors_unknown]
                        lst.append(get_k("H", round + 1, i, j))
                        lst.append(-k)
                        c.append(lst)

                    elif condition == '?':
                        # conditional infect if there's an S (if current ? is H)
                        if ((i - 1 >= 0 and cur_map[i - 1][j] == 'S') or
                                (i + 1 < rows and cur_map[i + 1][j] == 'S') or
                                (j - 1 >= 0 and cur_map[i][j - 1] == 'S') or
                                (j + 1 < columns and cur_map[i][j + 1] == 'S')):
                            c.extend([[-k, -get_k("H", round, i, j), get_k("S", round + 1, i, j, 3)]])
                            continue

                        # conditional infect of there's a ? (if current ? is H and other ? is S)
                        else:
                            if i - 1 >= 0 and cur_map[i - 1][j] == '?':
                                c.extend([[-k, -get_k("S", round, i - 1, j, 1), -get_k("H", round, i, j),
                                           get_k("S", round + 1, i, j, 3)],
                                          [-k, -get_k("S", round, i - 1, j, 2), -get_k("H", round, i, j),
                                           get_k("S", round + 1, i, j, 3)],
                                          [-k, -get_k("S", round, i - 1, j, 3), -get_k("H", round, i, j),
                                           get_k("S", round + 1, i, j, 3)]])
                                neighbors_unknown.append((i - 1, j))
                            if i + 1 < rows and cur_map[i + 1][j] == '?':
                                c.extend([[-k, -get_k("S", round, i + 1, j, 1), -get_k("H", round, i, j),
                                           get_k("S", round + 1, i, j, 3)],
                                          [-k, -get_k("S", round, i + 1, j, 2), -get_k("H", round, i, j),
                                           get_k("S", round + 1, i, j, 3)],
                                          [-k, -get_k("S", round, i + 1, j, 3), -get_k("H", round, i, j),
                                           get_k("S", round + 1, i, j, 3)]])
                                neighbors_unknown.append((i + 1, j))
                            if j - 1 >= 0 and cur_map[i][j - 1] == '?':
                                c.extend([[-k, -get_k("S", round, i, j - 1, 1), -get_k("H", round, i, j),
                                           get_k("S", round + 1, i, j, 3)],
                                          [-k, -get_k("S", round, i, j - 1, 2), -get_k("H", round, i, j),
                                           get_k("S", round + 1, i, j, 3)],
                                          [-k, -get_k("S", round, i, j - 1, 3), -get_k("H", round, i, j),
                                           get_k("S", round + 1, i, j, 3)]])
                                neighbors_unknown.append((i, j - 1))
                            if j + 1 < columns and cur_map[i][j + 1] == '?':
                                c.extend([[-k, -get_k("S", round, i, j + 1, 1), -get_k("H", round, i, j),
                                           get_k("S", round + 1, i, j, 3)],
                                          [-k, -get_k("S", round, i, j + 1, 2), -get_k("H", round, i, j),
                                           get_k("S", round + 1, i, j, 3)],
                                          [-k, -get_k("S", round, i, j + 1, 3), -get_k("H", round, i, j),
                                           get_k("S", round + 1, i, j, 3)]])
                                neighbors_unknown.append((i, j + 1))

                        # if no one infected, stay H (if ? is H)
                        lst = [get_k("S", round, n[0], n[1], 1) for n in neighbors_unknown] + \
                              [get_k("S", round, n[0], n[1], 2) for n in neighbors_unknown] + \
                              [get_k("S", round, n[0], n[1], 3) for n in neighbors_unknown]
                        lst.append(get_k("H", round + 1, i, j))
                        lst.append(-get_k("H", round, i, j))
                        lst.append(-k)
                        c.append(lst)

            index += 1
            k = v_id.vpool.id(index)

        lst = []
        for r in round_actions:
            lst.append(r)
            for t in round_actions:
                if r > t:
                    c.append([-r, -t])
        c.append(lst)

        for i in range(rows):
            for j in range(columns):
                condition = observations[round][i][j]
                if condition == 'Q':
                    c.extend([[-get_k("Q", round, i, j, 1), get_k("H", round + 1, i, j)],
                              [-get_k("Q", round, i, j, 2), get_k("Q", round + 1, i, j, 1)]])
                if condition == 'I':
                    c.append([get_k("I", round + 1, i, j)])
                if condition == '?':
                    c.extend([[-get_k("I", round, i, j), get_k("I", round + 1, i, j)],
                              [-get_k("Q", round, i, j, 1), get_k("H", round + 1, i, j)],
                              [-get_k("Q", round, i, j, 2), get_k("Q", round + 1, i, j, 1)],
                              [-get_k("U", round, i, j), get_k("U", round + 1, i, j)],
                              [-get_k("U", round + 1, i, j), get_k("U", round, i, j)]])
    return c
Example #9
0
def solve_problem1(input):
    num_rounds = len(input["observations"])
    observations = input["observations"]
    rows = len(observations[0])
    columns = len(observations[0][0])
    c = CNF()

    # init
    unpopulated = set()
    for round in range(num_rounds):
        for i in range(rows):
            for j in range(columns):
                condition = observations[round][i][j]
                if condition == "?":  # one condition only
                    c.extend([[-get_n("S", round, i, j), -get_n("H", round, i, j)],
                              [-get_n("S", round, i, j), -get_n("U", round, i, j)],
                              [-get_n("U", round, i, j), -get_n("H", round, i, j)],
                              [get_n("S", round, i, j), get_n("H", round, i, j), get_n("U", round, i, j)]])
                if condition == "S":
                    c.extend([[get_n("S", round, i, j)], [-get_n("H", round, i, j)], [-get_n("U", round, i, j)]])
                if condition == "H":
                    c.extend([[-get_n("S", round, i, j)], [get_n("H", round, i, j)], [-get_n("U", round, i, j)]])
                if condition == "U":
                    unpopulated.add((i, j))
                if round == 0:
                    if condition == "S":  # if S, stay S for 3 rounds
                        c.append([get_n("S", 1, i, j)])
                        c.append([get_n("S", 2, i, j)])
                        c.append([get_n("H", 3, i, j)])
                    elif condition == "?":
                        c.extend([[-get_n("S", 0, i, j), get_n("S", 1, i, j)],
                                  [-get_n("S", 0, i, j), get_n("S", 2, i, j)],
                                  [-get_n("S", 0, i, j), get_n("H", 3, i, j)]])

    # all unpopulated are unpopulated in all rounds
    for pair in unpopulated:
        for round in range(num_rounds):
            c.extend([[-get_n("S", round, pair[0], pair[1])], [-get_n("H", round, pair[0], pair[1])],
                      [get_n("U", round, pair[0], pair[1])]])

    # infect each round
    for round in range(num_rounds - 1):
        for i in range(rows):
            for j in range(columns):
                condition = observations[round][i][j]
                neighbors_unknown = []
                if condition == "H":
                    # infect if there's an S
                    if ((i - 1 >= 0 and observations[round][i - 1][j] == 'S') or
                            (i + 1 < rows and observations[round][i + 1][j] == 'S') or
                            (j - 1 >= 0 and observations[round][i][j - 1] == 'S') or
                            (j + 1 < columns and observations[round][i][j + 1] == 'S')):
                        c.extend([[get_n("S", round + 1, i, j)],
                                  [get_n("S", round + 2, i, j)],
                                  [get_n("S", round + 3, i, j)],
                                  [get_n("H", round + 4, i, j)]])
                        continue

                    # conditional infect if there's a ? (if ? is S)
                    else:
                        if i - 1 >= 0 and observations[round][i - 1][j] == '?':
                            c.extend([[-get_n("S", round, i - 1, j), get_n("S", round + 1, i, j)],
                                      [-get_n("S", round, i - 1, j), get_n("S", round + 2, i, j)],
                                      [-get_n("S", round, i - 1, j), get_n("S", round + 3, i, j)],
                                      [-get_n("S", round, i - 1, j), get_n("H", round + 4, i, j)]])
                            neighbors_unknown.append((i - 1, j))
                        if i + 1 < rows and observations[round][i + 1][j] == '?':
                            c.extend([[-get_n("S", round, i + 1, j), get_n("S", round + 1, i, j)],
                                      [-get_n("S", round, i + 1, j), get_n("S", round + 2, i, j)],
                                      [-get_n("S", round, i + 1, j), get_n("S", round + 3, i, j)],
                                      [-get_n("S", round, i + 1, j), get_n("H", round + 4, i, j)]])
                            neighbors_unknown.append((i + 1, j))
                        if j - 1 >= 0 and observations[round][i][j - 1] == '?':
                            c.extend([[-get_n("S", round, i, j - 1), get_n("S", round + 1, i, j)],
                                      [-get_n("S", round, i, j - 1), get_n("S", round + 2, i, j)],
                                      [-get_n("S", round, i, j - 1), get_n("S", round + 3, i, j)],
                                      [-get_n("S", round, i, j - 1), get_n("H", round + 4, i, j)]])
                            neighbors_unknown.append((i, j - 1))
                        if j + 1 < columns and observations[round][i][j + 1] == '?':
                            c.extend([[-get_n("S", round, i, j + 1), get_n("S", round + 1, i, j)],
                                      [-get_n("S", round, i, j + 1), get_n("S", round + 2, i, j)],
                                      [-get_n("S", round, i, j + 1), get_n("S", round + 3, i, j)],
                                      [-get_n("S", round, i, j + 1), get_n("H", round + 4, i, j)]])
                            neighbors_unknown.append((i, j + 1))

                    # if no one infected, stay H
                    l = [get_n("S", round, pair[0], pair[1]) for pair in neighbors_unknown]
                    l.append(get_n("H", round + 1, i, j))
                    c.append(l)

                elif condition == '?':
                    # conditional infect if there's an S (if current ? is H)
                    if ((i - 1 >= 0 and observations[round][i - 1][j] == 'S') or
                            (i + 1 < rows and observations[round][i + 1][j] == 'S') or
                            (j - 1 >= 0 and observations[round][i][j - 1] == 'S') or
                            (j + 1 < columns and observations[round][i][j + 1] == 'S')):
                        c.extend([[-get_n("H", round, i, j), get_n("S", round + 1, i, j)],
                                  [-get_n("H", round, i, j), get_n("S", round + 2, i, j)],
                                  [-get_n("H", round, i, j), get_n("S", round + 3, i, j)],
                                  [-get_n("H", round, i, j), get_n("H", round + 4, i, j)]])
                        continue

                    # conditional infect of there's a ? (if current ? is H and other ? is S)
                    else:
                        if i - 1 >= 0 and observations[round][i - 1][j] == '?':
                            c.extend(
                                [[-get_n("H", round, i, j), -get_n("S", round, i - 1, j), get_n("S", round + 1, i, j)],
                                 [-get_n("H", round, i, j), -get_n("S", round, i - 1, j), get_n("S", round + 2, i, j)],
                                 [-get_n("H", round, i, j), -get_n("S", round, i - 1, j), get_n("S", round + 3, i, j)],
                                 [-get_n("H", round, i, j), -get_n("S", round, i - 1, j), get_n("H", round + 4, i, j)]])
                            neighbors_unknown.append((i - 1, j))
                        if i + 1 < rows and observations[round][i + 1][j] == '?':
                            c.extend(
                                [[-get_n("H", round, i, j), -get_n("S", round, i + 1, j), get_n("S", round + 1, i, j)],
                                 [-get_n("H", round, i, j), -get_n("S", round, i + 1, j), get_n("S", round + 2, i, j)],
                                 [-get_n("H", round, i, j), -get_n("S", round, i + 1, j), get_n("S", round + 3, i, j)],
                                 [-get_n("H", round, i, j), -get_n("S", round, i + 1, j), get_n("H", round + 4, i, j)]])
                            neighbors_unknown.append((i + 1, j))
                        if j - 1 >= 0 and observations[round][i][j - 1] == '?':
                            c.extend(
                                [[-get_n("H", round, i, j), -get_n("S", round, i, j - 1), get_n("S", round + 1, i, j)],
                                 [-get_n("H", round, i, j), -get_n("S", round, i, j - 1), get_n("S", round + 2, i, j)],
                                 [-get_n("H", round, i, j), -get_n("S", round, i, j - 1), get_n("S", round + 3, i, j)],
                                 [-get_n("H", round, i, j), -get_n("S", round, i, j - 1), get_n("H", round + 4, i, j)]])
                            neighbors_unknown.append((i, j - 1))
                        if j + 1 < columns and observations[round][i][j + 1] == '?':
                            c.extend(
                                [[-get_n("H", round, i, j), -get_n("S", round, i, j + 1), get_n("S", round + 1, i, j)],
                                 [-get_n("H", round, i, j), -get_n("S", round, i, j + 1), get_n("S", round + 2, i, j)],
                                 [-get_n("H", round, i, j), -get_n("S", round, i, j + 1), get_n("S", round + 3, i, j)],
                                 [-get_n("H", round, i, j), -get_n("S", round, i, j + 1), get_n("H", round + 4, i, j)]])
                            neighbors_unknown.append((i, j + 1))
                    # if no one infected, stay H (if ? is H)
                    l = [get_n("S", round, pair[0], pair[1]) for pair in neighbors_unknown]
                    l.append(-get_n("H", round, i, j))
                    l.append(get_n("H", round + 1, i, j))
                    c.append(l)
        for i in range(rows):
            for j in range(columns):
                condition = observations[round][i][j]
                if condition == '?':
                    c.extend([[-get_n("U", round, i, j), get_n("U", round + 1, i, j)],
                              [-get_n("U", round + 1, i, j), get_n("U", round, i, j)]])
    return c
Example #10
0
    def encode(self, nof_terms=1):
        """
            Encode the problem of computing a DS of size nof_terms.
        """

        self.nof_terms = nof_terms
        self.nof_samps = len(self.samps)
        self.nof_labls = len(self.labels)

        enc = CNF()

        # constraint 11
        for j in range(1, self.nof_terms + 1):
            enc.append([-self.svar(j, r) for r in range(1, self.nof_feats + 1)])

        # constraint 12
        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 13
        for j in range(1, self.nof_terms + 1):
            for z in range(1, self.nof_labls + 1):
                for lb in self.labels:
                    # skip current class label
                    if lb == self.labels[z - 1]:
                        continue

                    for q in self.samps[lb]:
                        cl = [-self.cvar(j, z)]

                        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 14
        for j in range(1, self.nof_terms + 1):
            for z, lb in enumerate(self.labels, 1):
                for q in self.samps[lb]:
                    cr = self.crvar(j, q + 1)
                    cl = [-self.cvar(j, z)]

                    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 16
        for i in range(1, self.nof_terms + 1):
            for j in range(i + 1, self.nof_terms + 1):
                if self.nof_labls == 2:
                    enc.append([-self.tlvar(i, j, 1), -self.cvar(i, 1), self.cvar(j, 1)])
                    enc.append([-self.tlvar(i, j, 1), self.cvar(i, 1), -self.cvar(j, 1)])
                    enc.append([self.tlvar(i, j, 1), -self.cvar(i, 1), -self.cvar(j, 1)])
                    enc.append([self.tlvar(i, j, 1), self.cvar(i, 1), self.cvar(j, 1)])

                    lhs = -self.tlvar(i, j, 1)
                else:
                    lits = []
                    for z in range(1, self.nof_labls + 1):
                        enc.append([-self.tlvar(i, j, z), -self.cvar(i, z), self.cvar(j, z)])
                        enc.append([-self.tlvar(i, j, z), self.cvar(i, z), -self.cvar(j, z)])
                        enc.append([self.tlvar(i, j, z), -self.cvar(i, z), -self.cvar(j, z)])
                        enc.append([self.tlvar(i, j, z), self.cvar(i, z), self.cvar(j, z)])

                        enc.append([-self.tlvar(i, j, self.nof_labls + 1), self.tlvar(i, j, z)])
                        lits.append(-self.tlvar(i, j, z))

                    enc.append([self.tlvar(i, j, self.nof_labls + 1)] + lits)
                    lhs = -self.tlvar(i, j, self.nof_labls + 1)

                terms = []
                for r in range(1, self.nof_feats + 1):
                    # equality between l variables
                    enc.append([-self.trvar0(i, j, r), -self.lvar(i, r), self.lvar(j, r)])
                    enc.append([-self.trvar0(i, j, r), self.lvar(i, r), -self.lvar(j, r)])
                    enc.append([self.trvar0(i, j, r), -self.lvar(i, r), -self.lvar(j, r)])
                    enc.append([self.trvar0(i, j, r), self.lvar(i, r), self.lvar(j, r)])

                    # r-th term
                    t = self.trvar1(i, j, r)
                    enc.append([-t, -self.svar(i, r)])
                    enc.append([-t, -self.svar(j, r)])
                    enc.append([-t, -self.trvar0(i, j, r)])
                    enc.append([t, self.svar(i, r), self.svar(j, r), self.trvar0(i, j, r)])

                    terms.append(t)

                enc.append([-lhs] + terms)

        # symmetry breaking constraints
        if self.options.bsymm:
            self.add_bsymm(enc)

        # constraint 15
        if self.options.accuracy == 100.0:
            for label in self.labels:
                for q in self.samps[label]:
                    enc.append([self.crvar(j, q + 1) for j in range(1, self.nof_terms + 1)])
        else:
            allcv = []
            for label in self.labels:
                for q in self.samps[label]:
                    cv = self.cvvar(q + 1)
                    enc.append([-cv] + [self.crvar(j, q + 1) for j in range(1, self.nof_terms + 1)])

                    for j in range(1, self.nof_terms + 1):
                        enc.append([-self.crvar(j, q + 1), cv])

                    allcv.append(cv)

            cnum = int(math.ceil(self.options.accuracy * len(allcv) / 100.0))
            al = CardEnc.atleast(allcv, bound=cnum, top_id=enc.nv, encoding=self.options.enc)
            if al:
                enc.extend(al.clauses)

        # 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)

        # at most one class per rule can be used
        if self.nof_labls > 2:
            for j in range(1, self.nof_terms + 1):
                onelb = CardEnc.equals([self.cvar(j, z) for z in range(1, self.nof_labls + 1)], top_id=enc.nv, encoding=self.options.enc)
                enc.extend(onelb.clauses)

        # saving comments
        for j in range(1, self.nof_terms + 1):
            if self.nof_labls > 2:
                for z in range(1, self.nof_labls + 1):
                    enc.comments.append('c c({0}, {1}) => v{2}'.format(j, z, self.cvar(j, z)))

            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 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
Example #11
0
def create_clauses(epeg):

    class_to_var, var_to_class, \
        class_pair_to_var, var_to_class_pair = create_vars_mappings(epeg)

    cnf = CNF(from_clauses=[])

    top_id = max(class_pair_to_var.values())

    # constraint (1) - at most one node from each class
    for class_name, class_nodes in epeg.classes.items():

        vars = [class_to_var[class_name]] + list(
            set([node.id for node in class_nodes]))
        weights = [1] + [
            -1 for _ in list(set([node.id for node in class_nodes]))
        ]

        constraint_formula = PBEnc.equals(lits=vars,
                                          weights=weights,
                                          bound=0,
                                          top_id=top_id)
        top_id = max([top_id] + [
            abs(var) for clause in constraint_formula.clauses for var in clause
        ])

        cnf.extend(constraint_formula.clauses)

    # constraint (2) - return class
    ret_class_var = class_to_var[epeg.root_class]
    return_constraint = PBEnc.equals(lits=[ret_class_var],
                                     weights=[1],
                                     bound=1,
                                     top_id=top_id)
    top_id = max(
        [top_id] +
        [abs(var) for clause in return_constraint.clauses for var in clause])
    cnf.extend(return_constraint.clauses)

    # constraint (3) - taking node implies taking each of its children eq-classes
    for _id, node in epeg.nodes.items():
        # node => child_eq_class ---> ~node \/ child_eq_class
        cnf.extend([[-_id, class_to_var[child.eq_class]]
                    for child in node.children])

    # constraint (4) - taking node implies taking pair of its class and each child class
    # (except for theta nodes' second child)
    for _id, node in epeg.nodes.items():
        for i in range(len(node.children)):
            if not (isinstance(node, THETANode) and i == 1):
                node_child_pair_var = class_pair_to_var[(
                    node.eq_class, node.children[i].eq_class)]
                clause = [-_id, node_child_pair_var]
                cnf.append(clause)

    # constraint (5) - if there is pair of same class, there must be at least one theta node from that class taken
    for class_name, nodes in epeg.classes.items():
        pair_var = class_pair_to_var[(class_name, class_name)]
        clause = [-pair_var] + [
            node.id for node in nodes if isinstance(node, THETANode)
        ]
        cnf.append(clause)

    # constraint (6) - transitivity
    for class_1 in epeg.classes.keys():
        for class_2 in epeg.classes.keys():
            for class_3 in epeg.classes.keys():
                if len(set([class_1, class_2, class_3])) == 3:
                    pair_1 = class_pair_to_var[(class_1, class_2)]
                    pair_2 = class_pair_to_var[(class_2, class_3)]
                    pair_3 = class_pair_to_var[(class_1, class_3)]
                    clause = [-pair_1, -pair_2, pair_3]
                    cnf.append(clause)

    return cnf, top_id