test_logic.py 7,54 ko
Newer Older
Chipe1's avatar
Chipe1 a validé
import pytest
from logic import *


def test_expr():
    assert repr(expr('P <=> Q(1)')) == '(P <=> Q(1))'
    assert repr(expr('P & Q | ~R(x, F(x))')) == '((P & Q) | ~R(x, F(x)))'
Peter Norvig's avatar
Peter Norvig a validé
    assert (expr_handle_infix_ops('P & Q ==> R & ~S')
            == "P & Q |InfixOp('==>', None)| R & ~S")
Chipe1's avatar
Chipe1 a validé

Peter Norvig's avatar
Peter Norvig a validé
def test_extend():
    assert extend({x: 1}, y, 2) == {x: 1, y: 2}

Chipe1's avatar
Chipe1 a validé
def test_PropKB():
    kb = PropKB()
    assert count(kb.ask(expr) for expr in [A, C, D, E, Q]) is 0
    kb.tell(A & E)
    assert kb.ask(A) == kb.ask(E) == {}
Peter Norvig's avatar
Peter Norvig a validé
    kb.tell(E |implies| C)
Chipe1's avatar
Chipe1 a validé
    assert kb.ask(C) == {}
    kb.retract(E)
    assert kb.ask(E) is False
Chipe1's avatar
Chipe1 a validé
    assert kb.ask(C) is False

Peter Norvig's avatar
Peter Norvig a validé

def test_KB_wumpus():
    # A simple KB that defines the relevant conditions of the Wumpus World as in Fig 7.4.
    # See Sec. 7.4.3
    kb_wumpus = PropKB()

    # Creating the relevant expressions
Peter Norvig's avatar
Peter Norvig a validé
    # TODO: Let's just use P11, P12, ... = symbols('P11, P12, ...')
Peter Norvig's avatar
Peter Norvig a validé
    P[1,1] = Symbol("P[1,1]")
    P[1,2] = Symbol("P[1,2]")
    P[2,1] = Symbol("P[2,1]")
    P[2,2] = Symbol("P[2,2]")
    P[3,1] = Symbol("P[3,1]")
    B[1,1] = Symbol("B[1,1]")
    B[2,1] = Symbol("B[2,1]")
Peter Norvig's avatar
Peter Norvig a validé
    kb_wumpus.tell(B[1,1] |equiv| ((P[1,2] | P[2,1])))
    kb_wumpus.tell(B[2,1] |equiv| ((P[1,1] | P[2,2] | P[3,1])))
    kb_wumpus.tell(~B[1,1])
    kb_wumpus.tell(B[2,1])

    # Statement: There is no pit in [1,1].
    assert kb_wumpus.ask(~P[1,1]) == {}

    # Statement: There is no pit in [1,2].
    assert kb_wumpus.ask(~P[1,2]) == {}

    # Statement: There is a pit in [2,2].
    assert kb_wumpus.ask(P[2,2]) == False

    # Statement: There is a pit in [3,1].
    assert kb_wumpus.ask(P[3,1]) == False

    # Statement: Neither [1,2] nor [2,1] contains a pit.
    assert kb_wumpus.ask(~P[1,2] & ~P[2,1]) == {}

    # Statement: There is a pit in either [2,2] or [3,1].
    assert kb_wumpus.ask(P[2,2] | P[3,1]) == {}

Peter Norvig's avatar
Peter Norvig a validé

def test_definite_clause():
    assert     is_definite_clause(expr('A & B & C & D ==> E'))
    assert     is_definite_clause(expr('Farmer(Mac)'))
    assert not is_definite_clause(expr('~Farmer(Mac)'))
    assert     is_definite_clause(expr('(Farmer(f) & Rabbit(r)) ==> Hates(f, r)'))
    assert not is_definite_clause(expr('(Farmer(f) & ~Rabbit(r)) ==> Hates(f, r)'))
    assert not is_definite_clause(expr('(Farmer(f) | Rabbit(r)) ==> Hates(f, r)'))

Chipe1's avatar
Chipe1 a validé
def test_pl_true():
    assert pl_true(P, {}) is None
    assert pl_true(P, {P: False}) is False
    assert pl_true(P | Q, {P: True}) is True
    assert pl_true((A|B)&(C|D), {A: False, B: True, D: True}) is True
    assert pl_true((A&B)&(C|D), {A: False, B: True, D: True}) is False
    assert pl_true((A&B)|(A&C), {A: False, B: True, C: True}) is False
    assert pl_true((A|B)&(C|D), {A: True, D: False}) is None
    assert pl_true(P | P, {}) is None

def test_tt_true():
    assert tt_true(P | ~P)
    assert tt_true('~~P <=> P')
Peter Norvig's avatar
Peter Norvig a validé
    assert not tt_true((P | ~Q) & (~P | Q))
Chipe1's avatar
Chipe1 a validé
    assert not tt_true(P & ~P)
    assert not tt_true(P & Q)
Peter Norvig's avatar
Peter Norvig a validé
    assert tt_true((P | ~Q) | (~P | Q))
Chipe1's avatar
Chipe1 a validé
    assert tt_true('(A & B) ==> (A | B)')
    assert tt_true('((A & B) & C) <=> (A & (B & C))')
    assert tt_true('((A | B) | C) <=> (A | (B | C))')
Peter Norvig's avatar
Peter Norvig a validé
    assert tt_true('(A ==> B) <=> (~B ==> ~A)')
    assert tt_true('(A ==> B) <=> (~A | B)')
    assert tt_true('(A <=> B) <=> ((A ==> B) & (B ==> A))')
Chipe1's avatar
Chipe1 a validé
    assert tt_true('~(A & B) <=> (~A | ~B)')
    assert tt_true('~(A | B) <=> (~A & ~B)')
    assert tt_true('(A & (B | C)) <=> ((A & B) | (A & C))')
    assert tt_true('(A | (B & C)) <=> ((A | B) & (A | C))')

def test_dpll():
Peter Norvig's avatar
Peter Norvig a validé
    assert (dpll_satisfiable(A & ~B & C & (A | ~D) & (~E | ~D) & (C | ~D) & (~A | ~F) & (E | ~F)
                             & (~D | ~F) & (B | ~C | D) & (A | ~E | F) & (~A | E | D))
            == {B: False, C: True, A: True, F: False, D: True, E: False})
    assert dpll_satisfiable(A&~B) == {A: True, B: False}
    assert dpll_satisfiable(P&~P) == False
    
Chipe1's avatar
Chipe1 a validé

def test_unify():
    assert unify(x, x, {}) == {}
    assert unify(x, 3, {}) == {x: 3}

def test_pl_fc_entails():
    assert pl_fc_entails(Fig[7,15], expr('Q'))
    assert not pl_fc_entails(Fig[7,15], expr('SomethingSilly'))

Chipe1's avatar
Chipe1 a validé
def test_tt_entails():
Chipe1's avatar
Chipe1 a validé
    assert tt_entails(P & Q, Q)
    assert not tt_entails(P | Q, Q)
    assert tt_entails(A & (B | C) & E & F & ~(P | Q), A & E & F & ~P & ~Q)

def test_eliminate_implications():
Peter Norvig's avatar
Peter Norvig a validé
    assert repr(eliminate_implications('A ==> (~B <== C)')) == '((~B | ~C) | ~A)'
    assert repr(eliminate_implications(A ^ B)) == '((A & ~B) | (~A & B))'
    assert repr(eliminate_implications(A & B | C & ~D)) == '((A & B) | (C & ~D))'

def test_dissociate():
    assert dissociate('&', [A & B]) == [A, B]
    assert dissociate('|', [A, B, C & D, P | Q]) == [A, B, C & D, P, Q]
    assert dissociate('&', [A, B, C & D, P | Q]) == [A, B, C, D, P | Q]

def test_associate():
Peter Norvig's avatar
Peter Norvig a validé
    assert (repr(associate('&', [(A & B), (B | C), (B & C)]))
            == '(A & B & (B | C) & B & C)')
    assert (repr(associate('|', [A | (B | (C | (A & B)))]))
            == '(A | B | C | (A & B))')

def test_move_not_inwards():
    assert repr(move_not_inwards(~(A | B))) == '(~A & ~B)'
    assert repr(move_not_inwards(~(A & B))) == '(~A | ~B)'
    assert repr(move_not_inwards(~(~(A | ~B) | ~~C))) == '((A | ~B) & ~C)'

def test_to_cnf():
Peter Norvig's avatar
Peter Norvig a validé
    assert (repr(to_cnf(Fig[7, 13] & ~expr('~P12'))) == 
            "((~P12 | B11) & (~P21 | B11) & (P12 | P21 | ~B11) & ~B11 & P12)")
    assert repr(to_cnf((P&Q) | (~P & ~Q))) == '((~P | P) & (~Q | P) & (~P | Q) & (~Q | Q))'
Peter Norvig's avatar
Peter Norvig a validé
    assert repr(to_cnf("B <=> (P1 | P2)")) == '((~P1 | B) & (~P2 | B) & (P1 | P2 | ~B))'
Peter Norvig's avatar
Peter Norvig a validé
    assert repr(to_cnf("a | (b & c) | d")) == '((b | a | d) & (c | a | d))'
    assert repr(to_cnf("A & (B | (D & E))")) == '(A & (D | B) & (E | B))'
    assert repr(to_cnf("A | (B | (C | (D & E)))")) == '((D | A | B | C) & (E | A | B | C))'

def test_standardize_variables():
    e = expr('F(a, b, c) & G(c, A, 23)')
    assert len(variables(standardize_variables(e))) == 3
    #assert variables(e).intersection(variables(standardize_variables(e))) == {}
    assert is_variable(standardize_variables(expr('x')))
    def test_ask(query, kb=None):
        q = expr(query)
        answers = fol_bc_ask(kb or test_kb, q)
        return sorted(
            [dict((x, v) for x, v in list(a.items()) if x in test_variables)
             for a in answers],  key=repr)
    assert repr(test_ask('Farmer(x)')) == '[{x: Mac}]'
    assert repr(test_ask('Human(x)')) == '[{x: Mac}, {x: MrsMac}]'
    assert repr(test_ask('Rabbit(x)')) == '[{x: MrsRabbit}, {x: Pete}]'
    assert repr(test_ask('Criminal(x)', crime_kb)) == '[{x: West}]'

Chipe1's avatar
Chipe1 a validé
def test_WalkSAT():
    def check_SAT(clauses, single_solution = {}):
Peter Norvig's avatar
Peter Norvig a validé
        # Make sure the solution is correct if it is returned by WalkSat
        # Sometimes WalkSat may run out of flips before finding a solution
Chipe1's avatar
Chipe1 a validé
        soln = WalkSAT(clauses)
        if soln:
            assert every(lambda x: pl_true(x, soln), clauses)
            if single_solution:  #Cross check the solution if only one exists
                assert every(lambda x: pl_true(x, single_solution), clauses)
                assert soln == single_solution
Peter Norvig's avatar
Peter Norvig a validé
    # Test WalkSat for problems with solution
Chipe1's avatar
Chipe1 a validé
    check_SAT([A & B, A & C])
    check_SAT([A | B, P & Q, P & B])
    check_SAT([A & B, C | D, ~(D | P)], {A: True, B: True, C: True, D: False, P: False})
Peter Norvig's avatar
Peter Norvig a validé
    # Test WalkSat for problems without solution
Chipe1's avatar
Chipe1 a validé
    assert WalkSAT([A & ~A], 0.5, 100) is None
    assert WalkSAT([A | B, ~A, ~(B | C), C | D, P | Q], 0.5, 100) is None
    assert WalkSAT([A | B, B & C, C | D, D & A, P, ~P], 0.5, 100) is None

Chipe1's avatar
Chipe1 a validé

if __name__ == '__main__':
    pytest.main()