Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 164ffc4

Browse files
committed
Merge pull request aimacode#145 from Chipe1/test
Fixed a bug and added tests for logic.py
2 parents 33ddde4 + 7195001 commit 164ffc4

File tree

3 files changed

+77
-98
lines changed

3 files changed

+77
-98
lines changed

logic.py

Lines changed: 5 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,6 @@ class Expr:
160160
(3) (x % y) and (x ^ y).
161161
It is very ugly to have (x % y) mean (x <=> y), but we need
162162
SOME operator to make (2) work, and this seems the best choice.
163-
164-
WARNING: if x is an Expr, then so is x + 1, because the int 1 gets
165-
coerced to an Expr by the constructor. But 1 + x is an error, because
166-
1 doesn't know how to add an Expr. (Adding an __radd__ method to Expr
167-
wouldn't help, because int.__add__ is still called first.) Therefore,
168-
you should use Expr(1) + x instead, or ONE + x, or expr('1 + x').
169163
"""
170164

171165
def __init__(self, op, *args):
@@ -216,6 +210,8 @@ def __gt__(self, other): return Expr('>', self, other)
216210

217211
def __add__(self, other): return Expr('+', self, other)
218212

213+
def __radd__(self, other): return Expr('+', other, self)
214+
219215
def __sub__(self, other): return Expr('-', self, other)
220216

221217
def __and__(self, other): return Expr('&', self, other)
@@ -253,10 +249,6 @@ def expr(s):
253249
'x =/= y' parses as (x ^ y) # Logical disequality (xor)
254250
But BE CAREFUL; precedence of implication is wrong. expr('P & Q ==> R & S')
255251
is ((P & (Q >> R)) & S); so you must use expr('(P & Q) ==> (R & S)').
256-
>>> expr('P <=> Q(1)')
257-
(P <=> Q(1))
258-
>>> expr('P & Q | ~R(x, F(x))')
259-
((P & Q) | ~R(x, F(x)))
260252
"""
261253
if isinstance(s, Expr):
262254
return s
@@ -539,7 +531,7 @@ def distribute_and_over_or(s):
539531
return FALSE
540532
if len(s.args) == 1:
541533
return distribute_and_over_or(s.args[0])
542-
conj = find_if((lambda d: d.op == '&'), s.args)
534+
conj = first(arg for arg in s.args if arg.op == '&')
543535
if not conj:
544536
return s
545537
others = [a for a in s.args if a is not conj]
@@ -1031,14 +1023,15 @@ def retract(self, sentence):
10311023
def fetch_rules_for_goal(self, goal):
10321024
return self.clauses
10331025

1034-
1026+
""" TODO Rename test_ask to remove test from the name(or tell pytest to ignore it)
10351027
def test_ask(query, kb=None):
10361028
q = expr(query)
10371029
vars = variables(q)
10381030
answers = fol_bc_ask(kb or test_kb, q)
10391031
return sorted(
10401032
[dict((x, v) for x, v in list(a.items()) if x in vars)
10411033
for a in answers], key=repr)
1034+
"""
10421035

10431036
test_kb = FolKB(
10441037
list(map(expr, ['Farmer(Mac)',
@@ -1229,88 +1222,3 @@ def d(y, x):
12291222
# ________________________________________________________________________
12301223

12311224

1232-
class logicTest:
1233-
1234-
"""
1235-
### PropKB
1236-
>>> kb = PropKB()
1237-
>>> kb.tell(A & B)
1238-
>>> kb.tell(B >> C)
1239-
>>> kb.ask(C) ## The result {} means true, with no substitutions
1240-
{}
1241-
>>> kb.ask(P)
1242-
False
1243-
>>> kb.retract(B)
1244-
>>> kb.ask(C)
1245-
False
1246-
1247-
>>> pl_true(P, {})
1248-
>>> pl_true(P | Q, {P: True})
1249-
True
1250-
1251-
# Notice that the function pl_true cannot reason by cases:
1252-
>>> pl_true(P | ~P)
1253-
1254-
# However, tt_true can:
1255-
>>> tt_true(P | ~P)
1256-
True
1257-
1258-
# The following are tautologies from [Fig. 7.11]:
1259-
>>> tt_true("(A & B) <=> (B & A)")
1260-
True
1261-
>>> tt_true("(A | B) <=> (B | A)")
1262-
True
1263-
>>> tt_true("((A & B) & C) <=> (A & (B & C))")
1264-
True
1265-
>>> tt_true("((A | B) | C) <=> (A | (B | C))")
1266-
True
1267-
>>> tt_true("~~A <=> A")
1268-
True
1269-
>>> tt_true("(A >> B) <=> (~B >> ~A)")
1270-
True
1271-
>>> tt_true("(A >> B) <=> (~A | B)")
1272-
True
1273-
>>> tt_true("(A <=> B) <=> ((A >> B) & (B >> A))")
1274-
True
1275-
>>> tt_true("~(A & B) <=> (~A | ~B)")
1276-
True
1277-
>>> tt_true("~(A | B) <=> (~A & ~B)")
1278-
True
1279-
>>> tt_true("(A & (B | C)) <=> ((A & B) | (A & C))")
1280-
True
1281-
>>> tt_true("(A | (B & C)) <=> ((A | B) & (A | C))")
1282-
True
1283-
1284-
# The following are not tautologies:
1285-
>>> tt_true(A & ~A)
1286-
False
1287-
>>> tt_true(A & B)
1288-
False
1289-
1290-
### An earlier version of the code failed on this:
1291-
>>> 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)) # noqa
1292-
{B: False, C: True, A: True, F: False, D: True, E: False}
1293-
1294-
### [Fig. 7.13]
1295-
>>> alpha = expr("~P12")
1296-
>>> to_cnf(Fig[7,13] & ~alpha)
1297-
((~P12 | B11) & (~P21 | B11) & (P12 | P21 | ~B11) & ~B11 & P12)
1298-
>>> tt_entails(Fig[7,13], alpha)
1299-
True
1300-
>>> pl_resolution(PropKB(Fig[7,13]), alpha)
1301-
True
1302-
1303-
### [Fig. 7.15]
1304-
>>> pl_fc_entails(Fig[7,15], expr('SomethingSilly'))
1305-
False
1306-
1307-
### Unification:
1308-
>>> unify(x, x, {})
1309-
{}
1310-
>>> unify(x, 3, {})
1311-
{x: 3}
1312-
1313-
1314-
>>> to_cnf((P&Q) | (~P & ~Q))
1315-
((~P | P) & (~Q | P) & (~P | Q) & (~Q | Q))
1316-
"""

tests/test_logic.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import pytest
2+
from logic import *
3+
4+
5+
def test_expr():
6+
assert repr(expr('P <=> Q(1)')) == '(P <=> Q(1))'
7+
assert repr(expr('P & Q | ~R(x, F(x))')) == '((P & Q) | ~R(x, F(x)))'
8+
9+
def test_PropKB():
10+
kb = PropKB()
11+
assert count(kb.ask(expr) for expr in [A, B, C, P, Q]) is 0
12+
kb.tell(A & B)
13+
assert kb.ask(A) == kb.ask(B) == {}
14+
kb.tell(B >> C)
15+
assert kb.ask(C) == {}
16+
kb.retract(B)
17+
assert kb.ask(B) is False
18+
assert kb.ask(C) is False
19+
20+
def test_pl_true():
21+
assert pl_true(P, {}) is None
22+
assert pl_true(P, {P: False}) is False
23+
assert pl_true(P | Q, {P: True}) is True
24+
assert pl_true((A|B)&(C|D), {A: False, B: True, D: True}) is True
25+
assert pl_true((A&B)&(C|D), {A: False, B: True, D: True}) is False
26+
assert pl_true((A&B)|(A&C), {A: False, B: True, C: True}) is False
27+
assert pl_true((A|B)&(C|D), {A: True, D: False}) is None
28+
assert pl_true(P | P, {}) is None
29+
30+
def test_tt_true():
31+
assert tt_true(P | ~P)
32+
assert tt_true('~~P <=> P')
33+
assert not tt_true('(P | ~Q)&(~P | Q)')
34+
assert not tt_true(P & ~P)
35+
assert not tt_true(P & Q)
36+
assert tt_true('(P | ~Q)|(~P | Q)')
37+
assert tt_true('(A & B) ==> (A | B)')
38+
assert tt_true('((A & B) & C) <=> (A & (B & C))')
39+
assert tt_true('((A | B) | C) <=> (A | (B | C))')
40+
assert tt_true('(A >> B) <=> (~B >> ~A)')
41+
assert tt_true('(A >> B) <=> (~A | B)')
42+
assert tt_true('(A <=> B) <=> ((A >> B) & (B >> A))')
43+
assert tt_true('~(A & B) <=> (~A | ~B)')
44+
assert tt_true('~(A | B) <=> (~A & ~B)')
45+
assert tt_true('(A & (B | C)) <=> ((A & B) | (A & C))')
46+
assert tt_true('(A | (B & C)) <=> ((A | B) & (A | C))')
47+
48+
def test_dpll():
49+
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} #noqa
50+
51+
def test_unify():
52+
assert unify(x, x, {}) == {}
53+
assert unify(x, 3, {}) == {x: 3}
54+
55+
def test_to_cnf():
56+
#assert to_cnf(Fig[7, 13] & ~expr('~P12')) BUG - FAILING THIS TEST DUE TO AN ERROR
57+
assert repr(to_cnf((P&Q) | (~P & ~Q))) == '((~P | P) & (~Q | P) & (~P | Q) & (~Q | Q))'
58+
pass
59+
60+
def test_pl_fc_entails():
61+
assert pl_fc_entails(Fig[7,15], expr('Q'))
62+
assert not pl_fc_entails(Fig[7,15], expr('SomethingSilly'))
63+
64+
def tt_entails():
65+
assert tt_entails(P & Q, Q)
66+
assert not tt_entails(P | Q, Q)
67+
assert tt_entails(A & (B | C) & E & F & ~(P | Q), A & E & F & ~P & ~Q)
68+
assert tt_entails(Fig[7,13], alpha)
69+
70+
71+
if __name__ == '__main__':
72+
pytest.main()

tests/test_search.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import pytest
22
from search import * # noqa
3-
from random import choice #noqa
43

54

65
romania = GraphProblem('Arad', 'Bucharest', Fig[3, 2])

0 commit comments

Comments
 (0)