@@ -224,6 +224,16 @@ def prop_symbols(x):
224224 return list (set (symbol for arg in x .args for symbol in prop_symbols (arg )))
225225
226226
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+
227237def tt_true (s ):
228238 """Is a propositional sentence a tautology?
229239 >>> tt_true('P | ~P')
@@ -845,26 +855,6 @@ def subst(s, x):
845855 return Expr (x .op , * [subst (s , arg ) for arg in x .args ])
846856
847857
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-
868858def standardize_variables (sentence , dic = None ):
869859 """Replace all the variables in sentence with new variables."""
870860 if dic is None :
@@ -921,31 +911,42 @@ def fetch_rules_for_goal(self, goal):
921911 return self .clauses
922912
923913
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
938929
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
949950
950951
951952def fol_bc_ask (KB , query ):
@@ -972,6 +973,33 @@ def fol_bc_and(KB, goals, theta):
972973 for theta2 in fol_bc_and (KB , rest , theta1 ):
973974 yield theta2
974975
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+
9751003# ______________________________________________________________________________
9761004
9771005# Example application (not in the book).
0 commit comments