@@ -224,6 +224,16 @@ def prop_symbols(x):
224
224
return list (set (symbol for arg in x .args for symbol in prop_symbols (arg )))
225
225
226
226
227
+ def constant_symbols (x ):
228
+ """Return a list of all constant symbols in x."""
229
+ if not isinstance (x , Expr ):
230
+ return []
231
+ elif is_prop_symbol (x .op ) and not x .args :
232
+ return [x ]
233
+ else :
234
+ return list ({symbol for arg in x .args for symbol in constant_symbols (arg )})
235
+
236
+
227
237
def tt_true (s ):
228
238
"""Is a propositional sentence a tautology?
229
239
>>> tt_true('P | ~P')
@@ -845,26 +855,6 @@ def subst(s, x):
845
855
return Expr (x .op , * [subst (s , arg ) for arg in x .args ])
846
856
847
857
848
- def fol_fc_ask (KB , alpha ):
849
- """A simple forward-chaining algorithm. [Figure 9.3]"""
850
- new = []
851
- while new is not None :
852
- for rule in KB .clauses :
853
- p , q = parse_definite_clause (standardize_variables (rule ))
854
- for p_ in KB .clauses :
855
- if p != p_ :
856
- for theta in KB .clauses :
857
- if subst (theta , p ) == subst (theta , p_ ):
858
- q_ = subst (theta , q )
859
- if not unify (q_ , KB .sentence in KB ) or not unify (q_ , new ):
860
- new .append (q_ )
861
- phi = unify (q_ , alpha )
862
- if phi is not None :
863
- return phi
864
- KB .tell (new )
865
- return None
866
-
867
-
868
858
def standardize_variables (sentence , dic = None ):
869
859
"""Replace all the variables in sentence with new variables."""
870
860
if dic is None :
@@ -921,31 +911,42 @@ def fetch_rules_for_goal(self, goal):
921
911
return self .clauses
922
912
923
913
924
- test_kb = FolKB (
925
- map (expr , ['Farmer(Mac)' ,
926
- 'Rabbit(Pete)' ,
927
- 'Mother(MrsMac, Mac)' ,
928
- 'Mother(MrsRabbit, Pete)' ,
929
- '(Rabbit(r) & Farmer(f)) ==> Hates(f, r)' ,
930
- '(Mother(m, c)) ==> Loves(m, c)' ,
931
- '(Mother(m, r) & Rabbit(r)) ==> Rabbit(m)' ,
932
- '(Farmer(f)) ==> Human(f)' ,
933
- # Note that this order of conjuncts
934
- # would result in infinite recursion:
935
- # '(Human(h) & Mother(m, h)) ==> Human(m)'
936
- '(Mother(m, h) & Human(h)) ==> Human(m)'
937
- ]))
914
+ def fol_fc_ask (KB , alpha ):
915
+ """A simple forward-chaining algorithm. [Figure 9.3]"""
916
+ # TODO: Improve efficiency
917
+ def enum_subst (KB ):
918
+ kb_vars = list ({v for clause in KB .clauses for v in variables (clause )})
919
+ kb_consts = list ({c for clause in KB .clauses for c in constant_symbols (clause )})
920
+ for assignment_list in itertools .product (kb_consts , repeat = len (kb_vars )):
921
+ theta = {x : y for x , y in zip (kb_vars , assignment_list )}
922
+ yield theta
923
+
924
+ # check if we can answer without new inferences
925
+ for q in KB .clauses :
926
+ phi = unify (q , alpha , {})
927
+ if phi is not None :
928
+ yield phi
938
929
939
- crime_kb = FolKB (
940
- map (expr , ['(American(x) & Weapon(y) & Sells(x, y, z) & Hostile(z)) ==> Criminal(x)' ,
941
- 'Owns(Nono, M1)' ,
942
- 'Missile(M1)' ,
943
- '(Missile(x) & Owns(Nono, x)) ==> Sells(West, x, Nono)' ,
944
- 'Missile(x) ==> Weapon(x)' ,
945
- 'Enemy(x, America) ==> Hostile(x)' ,
946
- 'American(West)' ,
947
- 'Enemy(Nono, America)'
948
- ]))
930
+ while True :
931
+ new = []
932
+ for rule in KB .clauses :
933
+ p , q = parse_definite_clause (rule )
934
+ for theta in enum_subst (KB ):
935
+ if any ([set (subst (theta , p )) == set (subst (theta , p_ ))
936
+ for p_ in itertools .combinations (KB .clauses , len (p ))]):
937
+ q_ = subst (theta , q )
938
+ if all ([unify (x , q_ , {}) is None for x in KB .clauses + new ]):
939
+ print ('Added' , q_ )
940
+ new .append (q_ )
941
+ phi = unify (q_ , alpha , {})
942
+ if phi is not None :
943
+ print (q_ , alpha )
944
+ yield phi
945
+ if not new :
946
+ break
947
+ for clause in new :
948
+ KB .tell (clause )
949
+ return None
949
950
950
951
951
952
def fol_bc_ask (KB , query ):
@@ -972,6 +973,33 @@ def fol_bc_and(KB, goals, theta):
972
973
for theta2 in fol_bc_and (KB , rest , theta1 ):
973
974
yield theta2
974
975
976
+
977
+ test_kb = FolKB (
978
+ map (expr , ['Farmer(Mac)' ,
979
+ 'Rabbit(Pete)' ,
980
+ 'Mother(MrsMac, Mac)' ,
981
+ 'Mother(MrsRabbit, Pete)' ,
982
+ '(Rabbit(r) & Farmer(f)) ==> Hates(f, r)' ,
983
+ '(Mother(m, c)) ==> Loves(m, c)' ,
984
+ '(Mother(m, r) & Rabbit(r)) ==> Rabbit(m)' ,
985
+ '(Farmer(f)) ==> Human(f)' ,
986
+ # Note that this order of conjuncts
987
+ # would result in infinite recursion:
988
+ # '(Human(h) & Mother(m, h)) ==> Human(m)'
989
+ '(Mother(m, h) & Human(h)) ==> Human(m)'
990
+ ]))
991
+
992
+ crime_kb = FolKB (
993
+ map (expr , ['(American(x) & Weapon(y) & Sells(x, y, z) & Hostile(z)) ==> Criminal(x)' ,
994
+ 'Owns(Nono, M1)' ,
995
+ 'Missile(M1)' ,
996
+ '(Missile(x) & Owns(Nono, x)) ==> Sells(West, x, Nono)' ,
997
+ 'Missile(x) ==> Weapon(x)' ,
998
+ 'Enemy(x, America) ==> Hostile(x)' ,
999
+ 'American(West)' ,
1000
+ 'Enemy(Nono, America)'
1001
+ ]))
1002
+
975
1003
# ______________________________________________________________________________
976
1004
977
1005
# Example application (not in the book).
0 commit comments