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

Skip to content

Commit c831e43

Browse files
committed
logic.py cleanup and incidental bugsquashing, part 1.
1 parent 8f136a6 commit c831e43

File tree

1 file changed

+39
-40
lines changed

1 file changed

+39
-40
lines changed

logic.py

Lines changed: 39 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,14 @@
2626

2727
from __future__ import generators
2828
import re
29+
import itertools
2930
import agents
3031
from utils import *
3132

3233
#______________________________________________________________________________
3334

3435
class KB:
35-
"""A Knowledge base to which you can tell and ask sentences.
36+
"""A knowledge base to which you can tell and ask sentences.
3637
To create a KB, first subclass this class and implement
3738
tell, ask_generator, and retract. Why ask_generator instead of ask?
3839
The book is a bit vague on what ask means --
@@ -50,42 +51,40 @@ def tell(self, sentence):
5051
abstract
5152

5253
def ask(self, query):
53-
"""Ask returns a substitution that makes the query true, or
54-
it returns False. It is implemented in terms of ask_generator."""
55-
try:
56-
return self.ask_generator(query).next()
57-
except StopIteration:
58-
return False
54+
"""Return a substitution that makes the query true, or,
55+
failing that, return False."""
56+
for result in self.ask_generator(query):
57+
return result
58+
return False
5959

6060
def ask_generator(self, query):
6161
"Yield all the substitutions that make query true."
6262
abstract
6363

6464
def retract(self, sentence):
65-
"Remove the sentence from the KB"
65+
"Remove sentence from the KB."
6666
abstract
6767

6868

6969
class PropKB(KB):
70-
"A KB for Propositional Logic. Inefficient, with no indexing."
70+
"A KB for propositional logic. Inefficient, with no indexing."
7171

7272
def __init__(self, sentence=None):
7373
self.clauses = []
7474
if sentence:
7575
self.tell(sentence)
7676

7777
def tell(self, sentence):
78-
"Add the sentence's clauses to the KB"
78+
"Add the sentence's clauses to the KB."
7979
self.clauses.extend(conjuncts(to_cnf(sentence)))
8080

8181
def ask_generator(self, query):
82-
"Yield the empty substitution if KB implies query; else False"
83-
if not tt_entails(Expr('&', *self.clauses), query):
84-
return
85-
yield {}
82+
"Yield the empty substitution if KB implies query."
83+
if tt_entails(Expr('&', *self.clauses), query):
84+
yield {}
8685

8786
def retract(self, sentence):
88-
"Remove the sentence's clauses from the KB"
87+
"Remove the sentence's clauses from the KB."
8988
for c in conjuncts(to_cnf(sentence)):
9089
if c in self.clauses:
9190
self.clauses.remove(c)
@@ -95,23 +94,23 @@ def retract(self, sentence):
9594
class KB_Agent(agents.Agent):
9695
"""A generic logical knowledge-based agent. [Fig. 7.1]"""
9796
def __init__(self, KB):
98-
t = 0
97+
steps = itertools.count()
9998
def program(percept):
99+
t = steps.next()
100100
KB.tell(self.make_percept_sentence(percept, t))
101101
action = KB.ask(self.make_action_query(t))
102102
KB.tell(self.make_action_sentence(action, t))
103-
t = t + 1
104103
return action
105104
self.program = program
106105

107-
def make_percept_sentence(self, percept, t):
108-
return(Expr("Percept")(percept, t))
106+
def make_percept_sentence(self, percept, t):
107+
return Expr("Percept")(percept, t)
109108

110-
def make_action_query(self, t):
111-
return(expr("ShouldDo(action, %d)" % t))
109+
def make_action_query(self, t):
110+
return expr("ShouldDo(action, %d)" % t)
112111

113112
def make_action_sentence(self, action, t):
114-
return(Expr("Did")(action, t))
113+
return Expr("Did")(action, t)
115114

116115
#______________________________________________________________________________
117116

@@ -175,13 +174,13 @@ def __call__(self, *args):
175174

176175
def __repr__(self):
177176
"Show something like 'P' or 'P(x, y)', or '~P' or '(P | Q | R)'"
178-
if len(self.args) == 0: # Constant or proposition with arity 0
177+
if not self.args: # Constant or proposition with arity 0
179178
return str(self.op)
180-
elif is_symbol(self.op): # Functional or Propositional operator
179+
elif is_symbol(self.op): # Functional or propositional operator
181180
return '%s(%s)' % (self.op, ', '.join(map(repr, self.args)))
182181
elif len(self.args) == 1: # Prefix operator
183182
return self.op + repr(self.args[0])
184-
else: # Infix operator
183+
else: # Infix operator
185184
return '(%s)' % (' '+self.op+' ').join(map(repr, self.args))
186185

187186
def __eq__(self, other):
@@ -215,7 +214,7 @@ def __neg__(self): return Expr('-', self)
215214
def __or__(self, other): return Expr('|', self, other)
216215
def __pow__(self, other): return Expr('**', self, other)
217216
def __xor__(self, other): return Expr('^', self, other)
218-
def __mod__(self, other): return Expr('<=>', self, other) ## (x % y)
217+
def __mod__(self, other): return Expr('<=>', self, other)
219218

220219

221220

@@ -246,7 +245,7 @@ def expr(s):
246245

247246
def is_symbol(s):
248247
"A string s is a symbol if it starts with an alphabetic char."
249-
return isinstance(s, str) and s[0].isalpha()
248+
return isinstance(s, str) and s[:1].isalpha()
250249

251250
def is_var_symbol(s):
252251
"A logic variable symbol is an initial-lowercase string."
@@ -276,38 +275,38 @@ def is_negative(s):
276275
return s.op == '~'
277276

278277
def is_literal(s):
279-
"""s is a FOL literal
278+
"""Is s a FOL literal?
280279
>>> is_literal(expr('~F(A, B)'))
281280
True
282281
>>> is_literal(expr('F(A, B)'))
283282
True
284283
>>> is_literal(expr('F(A, B) & G(B, C)'))
285284
False
285+
>>> is_literal(expr('~~A'))
286+
False
287+
>>> is_literal(expr('x')) # XXX I guess this is intended?
288+
True
286289
"""
287-
return is_symbol(s.op) or (s.op == '~' and is_literal(s.args[0]))
290+
return is_symbol(s.op) or (s.op == '~' and is_symbol(s.args[0].op))
288291

289292
def literals(s):
290-
"""returns the list of literals of logical expression s.
293+
"""Return a list of the literals in expression s.
291294
>>> literals(expr('F(A, B)'))
292295
[F(A, B)]
293296
>>> literals(expr('~F(A, B)'))
294297
[~F(A, B)]
295298
>>> literals(expr('(F(A, B) & G(B, C)) ==> R(A, C)'))
296299
[F(A, B), G(B, C), R(A, C)]
297300
"""
298-
op = s.op
299-
if op in set(['&', '|', '<<', '>>', '%', '^']):
300-
result = []
301-
for arg in s.args:
302-
result.extend(literals(arg))
303-
return result
304-
elif is_literal(s):
301+
if is_literal(s):
305302
return [s]
306303
else:
307-
return []
304+
return flatten(map(literals, s.args))
305+
306+
def flatten(seqs): return sum(seqs, [])
308307

309308
def variables(s):
310-
"""returns the set of variables in logical expression s.
309+
"""Return a set of the variables in expression s.
311310
>>> ppset(variables(F(x, A, y)))
312311
set([x, y])
313312
>>> ppset(variables(expr('F(x, x) & G(x, y) & H(y, z) & R(A, z, z)')))
@@ -362,7 +361,7 @@ def parse_definite_clause(s):
362361
#______________________________________________________________________________
363362

364363
def tt_entails(kb, alpha):
365-
"""Use truth tables to determine if KB entails sentence alpha. [Fig. 7.10]
364+
"""Does kb entail the sentence alpha? Use truth tables. [Fig. 7.10]
366365
>>> tt_entails(expr('P & Q'), expr('Q'))
367366
True
368367
"""

0 commit comments

Comments
 (0)