def to_cnf(s): """Convert a propositional logical sentence to conjunctive normal form. That is, to the form ((A | ~B | ...) & (B | C | ...) & ...) [p. 253] >>> to_cnf('~(B | C)') (~B & ~C) """ s = expr(s) if isinstance(s, str): s = expr(s) s = eliminate_implications(s) # Steps 1, 2 from p. 253 s = move_not_inwards(s) # Step 3 return distribute_and_over_or(s) # Step 4
def KB_tell_corner_edge(KB, size, pnt): adj = pnt.adj() pnt = point_to_room(pnt, size).to_string() count_in = sum([1 if in_map(size, d) else 0 for d in adj]) if count_in == 2: fact = utils.expr("CORNER({})".format(pnt)) if fact not in KB.clauses: KB.tell(fact) elif count_in == 3: fact = utils.expr("EDGE({})".format(pnt)) if fact not in KB.clauses: KB.tell(fact)
def distribute_and_over_or(s): """Given a sentence s consisting of conjunctions and disjunctions of literals, return an equivalent sentence in CNF. >>> distribute_and_over_or((A & B) | C) ((A | C) & (B | C)) """ s = expr(s) if s.op == '|': s = associate('|', s.args) if s.op != '|': return distribute_and_over_or(s) if len(s.args) == 0: return False if len(s.args) == 1: return distribute_and_over_or(s.args[0]) conj = first(arg for arg in s.args if arg.op == '&') if not conj: return s others = [a for a in s.args if a is not conj] rest = associate('|', others) return associate('&', [distribute_and_over_or(c | rest) for c in conj.args]) elif s.op == '&': return associate('&', list(map(distribute_and_over_or, s.args))) else: return s
def tt_true(s): """Is a propositional sentence a tautology? >>> tt_true('P | ~P') True """ s = expr(s) return tt_entails(True, s)
def find_safe(world, KB): safe_list = [] s_list = [] for i in range(world.map_size): for j in range(world.map_size): p = Point(i, j) room = point_to_room(size=world.map_size, pnt=p).to_string() cl1 = utils.expr("SAFE({})".format(room)) cl2 = utils.expr("EXP({})".format(room)) safe = KB.ask(cl1) expanded = cl2 in KB.clauses if safe and not expanded: safe_list.append(p) cl3 = utils.expr("S({})".format(room)) s = cl3 in KB.clauses if s: s_list.append(p) return safe_list, s_list
def KB_tell_WUM_PIT_ADJ_SAFE(KB, size, pnt, cur_room): if in_map(size, pnt): # Check corner or edge KB_tell_corner_edge(KB, size, pnt) # Add Adjacent fact room = point_to_room(pnt, size).to_string() adj = utils.expr("ADJ({}, {})".format(cur_room, room)) if adj not in KB.clauses: KB.tell(adj) wum, pit, safe = KB_asking(KB, room) #print(room, "Safe", not not safe) if wum: cl = utils.expr("WUM({})".format(room)) if cl not in KB.clauses: KB.tell(cl) if pit: cl = utils.expr("PIT({})".format(room)) if cl not in KB.clauses: KB.tell(cl) if safe: cl = utils.expr("SAFE({})".format(room)) if cl not in KB.clauses: KB.tell(cl)
def init_KB(): # Init # ADJ kề sen = [ "(ADJ(x, y) & ADJ(x, z) & ADJ(x, t) & ADJ(x, v) & B(y) & B(z) & B(t) & B(v)) ==> PIT(x)", "(ADJ(x, y) & ADJ(x, z) & ADJ(x, t) & ADJ(x, v) & S(y) & S(z) & S(t) & S(v)) ==> WUM(x)", "(EDGE(x) & ADJ(x, y) & ADJ(x, z) & ADJ(x, t) & S(y) & S(z) & S(t)) ==> WUM(x)", "(EDGE(x) & ADJ(x, y) & ADJ(x, z) & ADJ(x, t) & B(y) & B(z) & B(t)) ==> PIT(x)", "(CORNER(x) & ADJ(x, y) & ADJ(x, z) & S(y) & S(z)) ==> WUM(x)", "(CORNER(x) & ADJ(x, y) & ADJ(x, z) & B(y) & B(z)) ==> PIT(x)", "(ADJ(x, y) & NULL(x)) ==> SAFE(y)", "B(x) ==> SAFE(x)", "S(x) ==> SAFE(x)", "NULL(x) ==> SAFE(x)" ] # Create an array to hold clauses clauses = [utils.expr(s) for s in sen] # Create a first-order logic knowledge base (KB) with clauses return logic.FolKB(clauses)
def eliminate_implications(s): """Change implications into equivalent form with only &, |, and ~ as logical operators.""" s = expr(s) if not s.args or is_symbol(s.op): return s # Atoms are unchanged. args = list(map(eliminate_implications, s.args)) a, b = args[0], args[-1] if s.op == '==>': return b | ~a elif s.op == '<==': return a | ~b elif s.op == '<=>': return (a | ~b) & (b | ~a) elif s.op == '^': assert len(args) == 2 # TODO: relax this restriction return (a & ~b) | (~a & b) else: assert s.op in ('&', '|', '~') return Expr(s.op, *args)
def move_not_inwards(s): """Rewrite sentence s by moving negation sign inward. >>> move_not_inwards(~(A | B)) (~A & ~B)""" s = expr(s) if s.op == '~': def NOT(b): return move_not_inwards(~b) a = s.args[0] if a.op == '~': return move_not_inwards(a.args[0]) # ~~A ==> A if a.op == '&': return associate('|', list(map(NOT, a.args))) if a.op == '|': return associate('&', list(map(NOT, a.args))) return s elif is_symbol(s.op) or not s.args: return s else: return Expr(s.op, *list(map(move_not_inwards, s.args)))
def KB_asking(KB, room): wum = KB.ask(utils.expr("WUM{}".format(room))) pit = KB.ask(utils.expr("PIT{}".format(room))) safe = KB.ask(utils.expr("SAFE({})".format(room))) return wum, pit, safe
def make_action_sentence(action, t): return Expr("Did")(action[expr('action')], t)
def make_action_query(t): return expr("ShouldDo(action, {})".format(t))
p = agenda.pop() if p == q: return True if not inferred[p]: inferred[p] = True for c in KB.clauses_with_premise(p): count[c] -= 1 if count[c] == 0: agenda.append(c.args[1]) return False """ [Figure 7.13] Simple inference in a wumpus world example """ wumpus_world_inference = expr("(B11 <=> (P12 | P21)) & ~B11") """ [Figure 7.16] Propositional Logic Forward Chaining example """ horn_clauses_KB = PropDefiniteKB() for s in "P==>Q; (L&M)==>P; (B&L)==>M; (A&P)==>L; (A&B)==>L; A;B".split(';'): horn_clauses_KB.tell(expr(s)) # ______________________________________________________________________________ # DPLL-Satisfiable [Figure 7.17] def dpll_satisfiable(s): """Check satisfiability of a propositional sentence. This differs from the book code in two ways: (1) it returns a model rather than True when it succeeds; this is more useful. (2) The