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

Skip to content

Commit 8f136a6

Browse files
committed
Correctly parse the parts of a definite clause; clean up fol_bc_ask(); add crime example.
1 parent 7dcc214 commit 8f136a6

File tree

1 file changed

+33
-33
lines changed

1 file changed

+33
-33
lines changed

logic.py

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,16 @@ def is_definite_clause(s):
345345
or (antecedent.op == '&'
346346
and all(is_symbol(arg.op) for arg in antecedent.args))))
347347

348+
def parse_definite_clause(s):
349+
"Return the antecedents and the consequent of a definite clause."
350+
assert is_definite_clause(s)
351+
if is_symbol(s.op):
352+
return [], s
353+
antecedent, consequent = s.args
354+
antecedent = NaryExpr('&', antecedent)
355+
antecedents = antecedent.args if antecedent.op == '&' else [antecedent]
356+
return antecedents, consequent
357+
348358
## Useful constant Exprs used in examples and code:
349359
TRUE, FALSE, ZERO, ONE, TWO = map(Expr, ['TRUE', 'FALSE', 0, 1, 2])
350360
A, B, C, F, G, P, Q, x, y, z = map(Expr, 'ABCFGPQxyz')
@@ -914,8 +924,7 @@ def fol_fc_ask(KB, alpha):
914924
while True:
915925
new = {}
916926
for r in KB.clauses:
917-
r1 = standardize_apart(r)
918-
ps, q = conjuncts(r.args[0]), r.args[1]
927+
ps, q = parse_definite_clause(standardize_apart(r))
919928
raise NotImplementedError
920929

921930
def standardize_apart(sentence, dic=None):
@@ -947,7 +956,6 @@ def standardize_apart(sentence, dic=None):
947956

948957
#______________________________________________________________________________
949958

950-
951959
class FolKB (KB):
952960
"""A knowledge base consisting of first-order definite clauses
953961
>>> kb0 = FolKB([expr('Farmer(Mac)'), expr('Rabbit(Pete)'),
@@ -977,10 +985,10 @@ def ask_generator(self, query):
977985
def retract(self, sentence):
978986
self.clauses.remove(sentence)
979987

980-
def test_ask(q):
988+
def test_ask(q, kb=None):
981989
e = expr(q)
982990
vars = variables(e)
983-
ans = fol_bc_ask(test_kb, [e])
991+
ans = fol_bc_ask(kb or test_kb, [e])
984992
res = []
985993
for a in ans:
986994
res.append(pretty(dict([(x, v) for (x, v) in a.items() if x in vars])))
@@ -1003,11 +1011,22 @@ def test_ask(q):
10031011
])
10041012
)
10051013

1006-
1014+
crime_kb = FolKB(
1015+
map(expr,
1016+
['(American(x) & Weapon(y) & Sells(x, y, z) & Hostile(z)) ==> Criminal(x)',
1017+
'Owns(Nono, M1)',
1018+
'Missile(M1)',
1019+
'(Missile(x) & Owns(Nono, x)) ==> Sells(West, x, Nono)',
1020+
'Missile(x) ==> Weapon(x)',
1021+
'Enemy(x, America) ==> Hostile(x)',
1022+
'American(West)',
1023+
'Enemy(Nono, America)'
1024+
])
1025+
)
1026+
10071027
def fol_bc_ask(KB, goals, theta={}):
10081028
"""A simple backward-chaining algorithm for first-order logic. [Fig. 9.6]
10091029
KB should be an instance of FolKB, and goals a list of literals.
1010-
10111030
>>> test_ask('Farmer(x)')
10121031
['{x: Mac}']
10131032
>>> test_ask('Human(x)')
@@ -1018,40 +1037,21 @@ def fol_bc_ask(KB, goals, theta={}):
10181037
['{x: MrsMac, y: Mac}', '{x: MrsRabbit, y: Pete}']
10191038
>>> test_ask('Rabbit(x)')
10201039
['{x: MrsRabbit}', '{x: Pete}']
1040+
>>> test_ask('Criminal(x)', crime_kb)
1041+
['{x: West}']
10211042
"""
1022-
1023-
if goals == []:
1043+
if not goals:
10241044
yield theta
1025-
raise StopIteration()
1026-
1045+
return
10271046
q1 = subst(theta, goals[0])
1028-
10291047
for r in KB.clauses:
1030-
sar = standardize_apart(r)
1031-
1032-
# Split into head and body
1033-
if is_symbol(sar.op):
1034-
head = sar
1035-
body = []
1036-
elif sar.op == '>>': # sar = (Body1 & Body2 & ...) >> Head
1037-
head = sar.args[1]
1038-
body = sar.args[0] # as conjunction
1039-
else:
1040-
raise Exception("Invalid clause in FolKB: %s" % r)
1041-
1042-
theta1 = unify(head, q1, {})
1043-
1048+
ps, q = parse_definite_clause(standardize_apart(r))
1049+
theta1 = unify(q, q1, {})
10441050
if theta1 is not None:
1045-
if body == []:
1046-
new_goals = goals[1:]
1047-
else:
1048-
new_goals = conjuncts(body) + goals[1:]
1049-
1051+
new_goals = ps + goals[1:]
10501052
for ans in fol_bc_ask(KB, new_goals, subst_compose(theta1, theta)):
10511053
yield ans
10521054

1053-
raise StopIteration()
1054-
10551055
def subst_compose (s1, s2):
10561056
"""Return the substitution which is equivalent to applying s2 to
10571057
the result of applying s1 to an expression.

0 commit comments

Comments
 (0)