我正在学习哈佛大学的Python人工智能入门课程,非常享受这个过程。然而,我下载了逻辑文件来使用布尔代数和知识,其中包含简单的操作(如OR、AND、NOT等)。在我提出疑问之前,我将分享来自哈佛源代码的知识类,希望其中没有问题:
这个类的链接:
logic.py
import itertoolsclass Sentence(): def evaluate(self, model): """Evaluates the logical sentence.""" raise Exception("nothing to evaluate") def formula(self): """Returns string formula representing logical sentence.""" return "" def symbols(self): """Returns a set of all symbols in the logical sentence.""" return set() @classmethod def validate(cls, sentence): if not isinstance(sentence, Sentence): raise TypeError("must be a logical sentence") @classmethod def parenthesize(cls, s): """Parenthesizes an expression if not already parenthesized.""" def balanced(s): """Checks if a string has balanced parentheses.""" count = 0 for c in s: if c == "(": count += 1 elif c == ")": if count <= 0: return False count -= 1 return count == 0 if not len(s) or s.isalpha() or ( s[0] == "(" and s[-1] == ")" and balanced(s[1:-1]) ): return s else: return f"({s})"class Symbol(Sentence): def __init__(self, name): self.name = name def __eq__(self, other): return isinstance(other, Symbol) and self.name == other.name def __hash__(self): return hash(("symbol", self.name)) def __repr__(self): return self.name def evaluate(self, model): try: return bool(model[self.name]) except KeyError: raise Exception(f"variable {self.name} not in model") def formula(self): return self.name def symbols(self): return {self.name}class Not(Sentence): def __init__(self, operand): Sentence.validate(operand) self.operand = operand def __eq__(self, other): return isinstance(other, Not) and self.operand == other.operand def __hash__(self): return hash(("not", hash(self.operand))) def __repr__(self): return f"Not({self.operand})" def evaluate(self, model): return not self.operand.evaluate(model) def formula(self): return "¬" + Sentence.parenthesize(self.operand.formula()) def symbols(self): return self.operand.symbols()class And(Sentence): def __init__(self, *conjuncts): for conjunct in conjuncts: Sentence.validate(conjunct) self.conjuncts = list(conjuncts) def __eq__(self, other): return isinstance(other, And) and self.conjuncts == other.conjuncts def __hash__(self): return hash( ("and", tuple(hash(conjunct) for conjunct in self.conjuncts)) ) def __repr__(self): conjunctions = ", ".join( [str(conjunct) for conjunct in self.conjuncts] ) return f"And({conjunctions})" def add(self, conjunct): Sentence.validate(conjunct) self.conjuncts.append(conjunct) def evaluate(self, model): return all(conjunct.evaluate(model) for conjunct in self.conjuncts) def formula(self): if len(self.conjuncts) == 1: return self.conjuncts[0].formula() return " ∧ ".join([Sentence.parenthesize(conjunct.formula()) for conjunct in self.conjuncts]) def symbols(self): return set.union(*[conjunct.symbols() for conjunct in self.conjuncts])class Or(Sentence): def __init__(self, *disjuncts): for disjunct in disjuncts: Sentence.validate(disjunct) self.disjuncts = list(disjuncts) def __eq__(self, other): return isinstance(other, Or) and self.disjuncts == other.disjuncts def __hash__(self): return hash( ("or", tuple(hash(disjunct) for disjunct in self.disjuncts)) ) def __repr__(self): disjuncts = ", ".join([str(disjunct) for disjunct in self.disjuncts]) return f"Or({disjuncts})" def evaluate(self, model): return any(disjunct.evaluate(model) for disjunct in self.disjuncts) def formula(self): if len(self.disjuncts) == 1: return self.disjuncts[0].formula() return " ∨ ".join([Sentence.parenthesize(disjunct.formula()) for disjunct in self.disjuncts]) def symbols(self): return set.union(*[disjunct.symbols() for disjunct in self.disjuncts])class Implication(Sentence): def __init__(self, antecedent, consequent): Sentence.validate(antecedent) Sentence.validate(consequent) self.antecedent = antecedent self.consequent = consequent def __eq__(self, other): return (isinstance(other, Implication) and self.antecedent == other.antecedent and self.consequent == other.consequent) def __hash__(self): return hash(("implies", hash(self.antecedent), hash(self.consequent))) def __repr__(self): return f"Implication({self.antecedent}, {self.consequent})" def evaluate(self, model): return ((not self.antecedent.evaluate(model)) or self.consequent.evaluate(model)) def formula(self): antecedent = Sentence.parenthesize(self.antecedent.formula()) consequent = Sentence.parenthesize(self.consequent.formula()) return f"{antecedent} => {consequent}" def symbols(self): return set.union(self.antecedent.symbols(), self.consequent.symbols())class Biconditional(Sentence): def __init__(self, left, right): Sentence.validate(left) Sentence.validate(right) self.left = left self.right = right def __eq__(self, other): return (isinstance(other, Biconditional) and self.left == other.left and self.right == other.right) def __hash__(self): return hash(("biconditional", hash(self.left), hash(self.right))) def __repr__(self): return f"Biconditional({self.left}, {self.right})" def evaluate(self, model): return ((self.left.evaluate(model) and self.right.evaluate(model)) or (not self.left.evaluate(model) and not self.right.evaluate(model))) def formula(self): left = Sentence.parenthesize(str(self.left)) right = Sentence.parenthesize(str(self.right)) return f"{left} <=> {right}" def symbols(self): return set.union(self.left.symbols(), self.right.symbols())def model_check(knowledge, query): """Checks if knowledge base entails query.""" def check_all(knowledge, query, symbols, model): """Checks if knowledge base entails query, given a particular model.""" # If model has an assignment for each symbol if not symbols: # If knowledge base is true in model, then query must also be true if knowledge.evaluate(model): return query.evaluate(model) return True else: # Choose one of the remaining unused symbols remaining = symbols.copy() p = remaining.pop() # Create a model where the symbol is true model_true = model.copy() model_true[p] = True # Create a model where the symbol is false model_false = model.copy() model_false[p] = False # Ensure entailment holds in both models return (check_all(knowledge, query, remaining, model_true) and check_all(knowledge, query, remaining, model_false)) # Get all symbols in both knowledge and query symbols = set.union(knowledge.symbols(), query.symbols()) # Check that knowledge entails query return check_all(knowledge, query, symbols, dict())
我知道代码量很大,但我的疑问很简单,我测试了基本的知识布尔代数操作,如NOT、AND和OR。问题只出现在OR函数上,如果至少有一个为真,它应该总是返回TRUE。但它返回的是false。
from logic import *a = Symbol("a")b = Symbol("b")# OR# Error hereorSentence = Or(a, b)valueOrSentence = model_check(orSentence, a)print(orSentence.formula() + f" ({valueOrSentence})")valueOrSentence = model_check(orSentence, Not(a))print(orSentence.formula() + f" ({valueOrSentence})")print('---/---/---/')
在检查模型时,它应该返回"true"
,但实际上返回的是"false"
我更愿意相信哈佛的logic.py
文件没有错误,我应该如何修复这个“OR”逻辑?
回答:
对于model
的一个特定情况,你的knowledge
成立但query
不成立,因此它返回False
。这并没有错。
当model = {'a': False, 'b': True}
时,orSentence.evaluate(model)
会返回True
,但a.evaluate(model)
会返回False
,使得model_check
的整体结果为False
。
如果你使用andSentence = And(a, b)
然后运行model_check(andSentence, a)
,它会返回True
,因为对于model
的每个值,andSentence
(知识)和a
(查询)要么都为True
,要么都为False
。