예제 #1
0
def test_tseitin_rep_if():
    from sweetpea.logic import __tseitin_rep, _Cache

    clauses = []
    cache = _Cache(3)

    # Make sure return is correct and value was cached.
    assert __tseitin_rep(If(1, 2), clauses, cache) == 3
    assert cache.get(str(If(1, 2))) == 3

    # Make sure equivalence clauses were added.
    assert Or([Not(1), 2, Not(3)]) in clauses
    assert Or([1, 3]) in clauses
    assert Or([Not(2), 3]) in clauses

    # Don't duplicate clauses when the cache was already populated.
    clauses = []
    cache = _Cache(3)

    # Prewarm the cache.
    assert cache.get(str(If(1, 2))) == 3
    assert __tseitin_rep(If(1, 2), clauses, cache) == 3

    # Make sure no clauses were added.
    assert clauses == []
예제 #2
0
def test_cnf_to_json():
    assert cnf_to_json([And([1])]) == [[1]]

    assert cnf_to_json([And([Or([1])])]) == [[1]]
    assert cnf_to_json([And([Or([Not(5)])])]) == [[-5]]
    assert cnf_to_json([And([Or([1, 2, Not(4)])])]) == [[1, 2, -4]]

    assert cnf_to_json([And([Or([1, 4]), Or([5, -4, 2]), Or([-1, -5])])]) == [
        [1, 4],
        [5, -4, 2],
        [-1, -5]]

    assert cnf_to_json([And([
        Or([1, 3, Not(2)]),
        Or([1, 3, 5]),
        Or([1, 4, Not(2)]),
        Or([1, 4, 5]),
        Or([2, 3, 1, 5]),
        Or([2, 4, 1, 5])])]) == [
            [1, 3, -2],
            [1, 3, 5],
            [1, 4, -2],
            [1, 4, 5],
            [2, 3, 1, 5],
            [2, 4, 1, 5]]
예제 #3
0
def test_tseitin_rep_or():
    from sweetpea.logic import __tseitin_rep, _Cache

    clauses = []
    cache = _Cache(4)

    # Make sure return is correct, and value was cached.
    assert __tseitin_rep(Or([1, 2, 3]), clauses, cache) == 4
    assert cache.get(str(Or([1, 2, 3]))) == 4

    # Make sure equivalence clauses were added.
    assert Or([Not(1), 4]) in clauses
    assert Or([Not(2), 4]) in clauses
    assert Or([Not(3), 4]) in clauses
    assert Or([1, 2, 3, Not(4)]) in clauses

    # Don't duplicate clauses when the cache was already populated
    clauses = []
    cache = _Cache(4)

    # Prewarm the cache
    assert cache.get(str(Or([1, 2, 3]))) == 4
    assert __tseitin_rep(Or([1, 2, 3]), clauses, cache) == 4

    # Make sure no clauses were added
    assert clauses == []
예제 #4
0
def test_distribute_ors_switching():
    from sweetpea.logic import __distribute_ors_switching

    # When lhs or rhs is a single variable, just distribute it.
    assert __distribute_ors_switching(Or([1, And([2, 3])]),
                                      4) == (And([Or([1, 2]),
                                                  Or([1, 3])]), 4)

    assert __distribute_ors_switching(Or([And([1, 2]), 3]),
                                      4) == (And([Or([1, 3]),
                                                  Or([2, 3])]), 4)

    # Should distribute over multiple individual variables
    assert __distribute_ors_switching(Or([1, 2, And([3, 4])]), 5) == (And(
        [Or([1, 2, 3]), Or([1, 2, 4])]), 5)

    # When both the lhs and rhs are more than just a single variable,
    # then introduce a switching variable to limit the formula growth.
    assert __distribute_ors_switching(Or([And([1, 2]),
                                          And([3, 4])]), 5) == (And([
                                              Or([1, Not(5)]),
                                              Or([2, Not(5)]),
                                              Or([3, 5]),
                                              Or([4, 5])
                                          ]), 6)
예제 #5
0
    def apply_to_backend_request(self,
                                 block: Block,
                                 level: Tuple[Factor, Union[SimpleLevel, DerivedLevel]],
                                 backend_request: BackendRequest
                                 ) -> None:
        sublists = self._build_variable_sublists(block, level, self.k)
        implications = []

        # Handle the regular cases (1 => 2 ^ ... ^ n ^ ~n+1)
        trim = len(sublists) if self.k > 1 else len(sublists) - 1
        for idx, l in enumerate(sublists[:trim]):
            if idx > 0:
                p_list = [Not(sublists[idx-1][0]), l[0]]
                p = And(p_list) if len(p_list) > 1 else p_list[0]
            else:
                p = l[0]

            if idx < len(sublists) - 1:
                q_list = cast(List[Any], l[1:]) + [Not(sublists[idx+1][-1])]
                q = And(q_list) if len(q_list) > 1 else q_list[0]
            else:
                q = And(l[1:]) if len(l[1:]) > 1 else l[self.k - 1]
            implications.append(If(p, q))

        # Handle the tail
        if len(sublists[-1]) > 1:
            tail = sublists[-1]
            tail.reverse()
            for idx in range(len(tail) - 1):
                implications.append(If(l[idx], l[idx + 1]))

        (cnf, new_fresh) = block.cnf_fn(And(implications), backend_request.fresh)

        backend_request.cnfs.append(cnf)
        backend_request.fresh = new_fresh
예제 #6
0
def test_eliminate_iff():
    from sweetpea.logic import __eliminate_iff

    # P <-> Q ==> (P v ~Q) ^ (~P v Q)
    assert __eliminate_iff(Iff(1, 2)) == And([Or([1, Not(2)]), Or([Not(1), 2])])

    assert __eliminate_iff(Iff(1, And([2, 3]))) == And([
        Or([1, Not(And([2, 3]))]),
        Or([Not(1), And([2, 3])])
    ])
예제 #7
0
def test_distribute_ors_naive():
    from sweetpea.logic import __distribute_ors_naive

    # When f is int or Not, return it. (Not can only contain int, as we've
    # already applied DeMorgan's laws)
    assert __distribute_ors_naive(1) == 1
    assert __distribute_ors_naive(Not(1)) == Not(1)

    # When f in an Or, distribute the Or over the contained clauses.
    assert __distribute_ors_naive(Or([1, 2])) == And([Or([1, 2])])
    assert __distribute_ors_naive(Or([1, And([2, 3])])) == And([Or([1, 2]), Or([1, 3])])
    assert __distribute_ors_naive(Or([And([1, 2]), And([3, 4])])) == And([
        Or([1, 3]), Or([1, 4]), Or([2, 3]), Or([2, 4])
    ])

    # When f is an And, disitribute Ors over the contained clauses.
    assert __distribute_ors_naive(And([1, Not(2)])) == And([1, Not(2)])
    assert __distribute_ors_naive(And([1, Or([2, And([3, 4])])])) == And([
        Or([2, 3]), Or([2, 4]), 1
    ])
예제 #8
0
def test_to_cnf_tseitin():
    assert to_cnf_tseitin(Or([1, And([2, 3])]), 4) == (And([
        # 4 <=> (2 ^ 3)
        Or([Not(2), Not(3), 4]),
        Or([2, Not(4)]),
        Or([3, Not(4)]),

        # 5 <=> (1 v 4)
        Or([1, 4, Not(5)]),
        Or([Not(1), 5]),
        Or([Not(4), 5]),

        # Final clause
        5
    ]), 6)
예제 #9
0
def test_to_cnf_naive():
    assert to_cnf_naive(1, 2) == (And([1]), 2)
    assert to_cnf_naive(And([1]), 2) == (And([1]), 2)
    assert to_cnf_naive(And([1, 2]), 3) == (And([1, 2]), 3)

    assert to_cnf_naive(Or([1, 2]), 3) == (And([Or([1, 2])]), 3)
    assert to_cnf_naive(Or([1, And([2, 3])]),
                        4) == (And([Or([1, 2]), Or([1, 3])]), 4)

    formula = And([Iff(1, And([2, 3])), Iff(4, And([5, 6]))])
    expected_cnf = And([
        Or([1, Not(2), Not(3)]),
        Or([Not(1), 2]),
        Or([Not(1), 3]),
        Or([4, Not(5), Not(6)]),
        Or([Not(4), 5]),
        Or([Not(4), 6])
    ])
    assert to_cnf_switching(formula, 7) == (expected_cnf, 7)
예제 #10
0
    def apply_to_backend_request(self, block: Block, level: Tuple[Factor, Union[SimpleLevel, DerivedLevel]],
                                    backend_request: BackendRequest) -> None:

        # Request sublists for k+1 to allow us to determine the transition
        sublists = self._build_variable_sublists(block, level, self.k + 1)

        implications = []
        if sublists:
            # Starting corner case
            implications.append(If(sublists[0][0], And(sublists[0][1:-1])))
            for sublist in sublists:
                implications.append(If(And([Not(sublist[0]), sublist[1]]), And(sublist[2:])))
            # Ending corner case
            implications.append(If(sublists[-1][-1], And(sublists[-1][1:-1])))

        (cnf, new_fresh) = block.cnf_fn(And(implications), backend_request.fresh)

        backend_request.cnfs.append(cnf)
        backend_request.fresh = new_fresh
예제 #11
0
def test_tseitin_rep_not():
    from sweetpea.logic import __tseitin_rep, _Cache

    # Should replace Not(var) with another variable
    clauses = []
    cache = _Cache(2)
    assert __tseitin_rep(Not(1), clauses, cache) == 2

    # Make sure that Not(1) was cached.
    assert cache.get(str(Not(1))) == 2

    # Make sure that the correct implication clauses were added.
    assert Or([    1,      2 ]) in clauses
    assert Or([Not(1), Not(2)]) in clauses

    # No clauses should be added if the value was already cached.
    clauses = []
    cache = _Cache(2)
    assert cache.get(str(Not(1))) == 2 # Prewarm the cache.
    assert __tseitin_rep(Not(1), clauses, cache) == 2
    assert clauses == []
예제 #12
0
def test_to_cnf_switching():
    formula = Or([
        And([3, 4]),
        And([Not(2), Or([1, 5])])
    ])
    expected_cnf = And([
        Or([3, Not(6)]),
        Or([4, Not(6)]),
        Or([1, 5, 6]),
        Or([Not(2), 6])
    ])
    assert to_cnf_switching(formula, 6) == (expected_cnf, 7)

    formula = And([
        Iff(1, And([2, 3])),
        Iff(4, And([5, 6]))
    ])
    expected_cnf = And([
        Or([1, Not(2), Not(3)]),
        Or([Not(1), 2]),
        Or([Not(1), 3]),
        Or([4, Not(5), Not(6)]),
        Or([Not(4), 5]),
        Or([Not(4), 6])
    ])
    assert to_cnf_switching(formula, 7) == (expected_cnf, 7)
예제 #13
0
def test_apply_demorgan():
    from sweetpea.logic import __apply_demorgan

    # P ==> P, ~P ==> ~P
    assert __apply_demorgan(4) == 4
    assert __apply_demorgan(Not(4)) == Not(4)

    # ~~P ==> P
    assert __apply_demorgan(Not(Not(4))) == 4

    # ~(P v Q) ==> ~P ^ ~Q
    assert __apply_demorgan(Not(Or([1, 2]))) == And([Not(1), Not(2)])

    # ~(P ^ Q) ==> ~P v ~Q
    assert __apply_demorgan(Not(And([1, 2]))) == Or([Not(1), Not(2)])

    assert __apply_demorgan(Or([1, Not(And([2, 3]))])) == Or([1, Not(2), Not(3)])
예제 #14
0
def test_exactlykinarow():
    backend_request = __run_kinarow(
        ExactlyKInARow(1, (color, get_level_from_name(color, "red"))))
    (expected_cnf, expected_fresh) = to_cnf_tseitin(
        And([
            If(1, Not(7)),
            If(And([Not(1), 7]), Not(13)),
            If(And([Not(7), 13]), Not(19))
        ]), 25)

    assert backend_request.fresh == expected_fresh
    assert backend_request.cnfs == [expected_cnf]

    backend_request = __run_kinarow(
        ExactlyKInARow(2, (color, get_level_from_name(color, "red"))))
    (expected_cnf, expected_fresh) = to_cnf_tseitin(
        And([
            If(1, And([7, Not(13)])),
            If(And([Not(1), 7]), And([13, Not(19)])),
            If(And([Not(7), 13]), 19),
            If(19, 13)
        ]), 25)

    assert backend_request.fresh == expected_fresh
    assert backend_request.cnfs == [expected_cnf]

    backend_request = __run_kinarow(
        ExactlyKInARow(3, (color, get_level_from_name(color, "red"))))
    (expected_cnf, expected_fresh) = to_cnf_tseitin(
        And([
            If(1, And([7, 13, Not(19)])),
            If(And([Not(1), 7]), And([13, 19])),
            If(19, 13),
            If(13, 7)
        ]), 25)

    assert backend_request.fresh == expected_fresh
    assert backend_request.cnfs == [expected_cnf]