[CS188-Artificial Intelligence]命题逻辑& 一阶逻辑

本文深入探讨了命题逻辑和第一阶逻辑,包括知识库、模型、蕴含和合取范式(CNF)的概念。介绍了两种证明方法、DPLL算法以及SAT求解器的工作原理。同时,展示了如何构建和转换逻辑表达式,并通过具体的伪代码解释了算法的执行流程。此外,文章还讨论了在迷宫问题中应用逻辑代理进行路径规划的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Propositional Logic

一些术语

Knowledge Base(KB):已经确认为真的事情,可以理解为解题时的题目条件
world:真值表里的每一行都是一个world
在这里插入图片描述
entailment:区别于imply,虽然和imply有相同的真值表,但是entails表示对于任何model,(A entails B)如果A正确那么B也正确。而imply仅仅只对一个model而言
sound algorithm and complete algorithm

An algorithm is sound if, anytime it returns an answer, that answer is true. An algorithm is complete if it guarantees to return a correct answer for any arbitrary input

两种证明方式

在这里插入图片描述

伪代码
function PL-TRUE?(a,model) returns true or false
if a is a symbol then return Lookup(a, model)
if Op(a) = ¬ then return not(PL-TRUE?(Arg1(a),model))
if Op(a) = Ù then return and(PL-TRUE?(Arg1(a),model), 
PL-TRUE?(Arg2(a),model))
etc.

构建expression

def sentence1():
    """Returns a Expr instance that encodes that the following expressions are all true.
    
    A or B
    (not A) if and only if ((not B) or C)
    (not A) or (not B) or C
    """

    A = Expr('A')
    B = Expr('B')
    C = Expr('C')
    a_or_b = A | B
    not_b_or_c = ~B | C
    second = ~A % not_b_or_c
    third = disjoin(~A,~B,C)
    return conjoin(a_or_b, second, third)

CNF(合取范式)

形如 ( or )and ( or )

In Boolean logic, a formula is in conjunctive normal form (CNF) 
or clausal normal form if it is a conjunction of one or 
more clauses, where a clause is a disjunction of literals; 
otherwise put, it is a product of sums or an AND of ORs. 
REFERENCE:https://en.wikipedia.org/wiki/Conjunctive_normal_form
e.g.
A
A OR B
(A OR B) AND (C OR D)

CNF与正常人的想法有一些不同,我们平时思考用的是DNF,就是把各种情况枚举出来,但是实际上要将DNF转化成CNF还是很容易的

DNF 转 CNF 技巧

我们考虑否命题,列出所有情况,再取逆,注意到 NOT (A OR B) = (NOT A AND NOT B),把NOT放进去这样就直接转成CNF了

SAT solver

DPLL算法

1.early termination

如果所有clause都可以被满足或者任意一个clause不可以被满足则结束返回

2.pure literals

如果在所有未被满足的clause内,某一个symbol的sign相同,那么将能使剩余clause为True的值赋给那个symbol

3. unit clause

如果某个clause只剩下一个literal没有被赋值,那么将这个对应的symbol赋值是的该clause为True
e.g. 如果A为False,那么(A or B)and (A or not C) 变为 (B)and (not C)那么B和C 就可以直接赋值{B:T,C:F}

伪代码
function DPLL(clauses,symbols,model) returns true or false 
if every clause in clauses is true in model then return true
if some clause in clauses is false in model then return false
P,value ←FIND-PURE-SYMBOL(symbols,clauses,model)
if P is non-null then return DPLL(clauses, symbols–P, model∪{P=value}) 
P,value ←FIND-UNIT-CLAUSE(clauses,model)
if P is non-null then return DPLL(clauses, symbols–P, model∪{P=value}) 
P ← First(symbols); rest ← Rest(symbols)
return or(DPLL(clauses,rest,model∪{P=true}),
DPLL(clauses,rest,model∪{P=false}))
Efficiency
§ Naïve implementation of DPLL: solve ~100 variable

利用logic agent定位

state estimation:跟踪当前正确的一些信息
对于logic agent, 可以直接询问他自己,调用SAT_SOLVER(KB AND CLAIM).KB为当前的knowledge base, claim为你想证明或证伪的statement. 如果我们证明了一件事,我们将这件事加入KB(KB.append(CLAIM)), 如果我们证伪了,我们将这件事情不会发生的信息加入KB(KB.append(CLAIM))

例子

比如说我们当前在一个迷宫里,我们知道迷宫的地图,但是我们不知道我们在哪里,我们感知到的信息为percept
在这里插入图片描述
迷宫里有多少位置满足呢?只有一个位置满足,所以我们知道了我们在迷宫中的具体位置。通常情况下需要在感知和操作来回多次才能确定自己本身的位置

Code

class LogicAgent(Agent):
    """
    This very general logic agent finds a path using a supplied planning
    algorithm for a supplied planning problem, then returns actions to follow that
    path.

    As a default, this agent runs positionLogicPlan on a
    PositionPlanningProblem to find location (1,1)

    Options for fn include:
      positionLogicPlan or plp
      foodLogicPlan or flp
      foodGhostLogicPlan or fglp


    Note: You should NOT change any code in LogicAgent
    """

    def __init__(self, fn='positionLogicPlan', prob='PositionPlanningProblem', plan_mod=logicPlan):
        # Warning: some advanced Python magic is employed below to find the right functions and problems

        # Get the planning function from the name and heuristic
        if fn not in dir(plan_mod):
            raise AttributeError(fn + ' is not a planning function in logicPlan.py.')
        func = getattr(plan_mod, fn)
        self.planningFunction = lambda x: func(x)

        # Get the planning problem type from the name
        if prob not in globals().keys() or not prob.endswith('Problem'):
            raise AttributeError(prob + ' is not a planning problem type in logicAgents.py.')
        self.planType = globals()[prob]
        self.live_checking = False
        print('[LogicAgent] using problem type ' + prob)

    def registerInitialState(self, state):
        """
        This is the first time that the agent sees the layout of the game
        board. Here, we choose a path to the goal. In this phase, the agent
        should compute the path to the goal and store it in a local variable.
        All of the work is done in this method!

        state: a GameState object (pacman.py)
        """
        if self.planningFunction == None:
            raise Exception("No planning function provided for LogicAgent")
        starttime = time.time()
        problem = self.planType(state) # Makes a new planning problem

        self.actions = [] # In case planningFunction times out
        self.actions  = self.planningFunction(problem) # Find a path
        totalCost = problem.getCostOfActions(self.actions)
        print('Path found with total cost of %d in %.1f seconds' % (totalCost, time.time() - starttime))
        # TODO Drop
        if '_expanded' in dir(problem):
            print('Nodes expanded: %d' % problem._expanded)

    def getAction(self, state):
        """
        Returns the next action in the path chosen earlier (in
        registerInitialState).  Return Directions.STOP if there is no further
        action to take.

        state: a GameState object (pacman.py)
        """
        # import ipdb; ipdb.set_trace()
        if 'actionIndex' not in dir(self): self.actionIndex = 0
        i = self.actionIndex
        self.actionIndex += 1
        if i < len(self.actions):
            return self.actions[i]
        else:
            print('Oh no! The Pacman agent created a plan that was too short!')
            print()
            return None
            # return Directions.STOP
class LocalizationLogicAgent(LocalizeMapAgent):
    def __init__(self, fn='localization', prob='LocalizationProblem', plan_mod=logicPlan, display=None, scripted_actions=[]):
        super(LocalizationLogicAgent, self).__init__(fn, prob, plan_mod, display, scripted_actions)
        self.num_timesteps = len(scripted_actions) if scripted_actions else 5

    def getAction(self, state):
        """
        Returns the next action in the path chosen earlier (in
        registerInitialState).  Return Directions.STOP if there is no further
        action to take.

        state: a GameState object (pacman.py)
        """
        # import ipdb; ipdb.set_trace()
        if 'actionIndex' not in dir(self): self.actionIndex = 0
        i = self.actionIndex
        self.actionIndex += 1

        planning_fn_output = None
        if i < self.num_timesteps:
            proposed_action = self.actions[i]
            planning_fn_output = next(self.planning_fn_output)
            self.drawPossibleStates(planning_fn_output, direction=self.actions[i])
        elif i < len(self.actions):
            proposed_action = self.actions[i]
        else:
            proposed_action = "EndGame"

        return proposed_action, planning_fn_output

    def moveToNextState(self, action):
        oldX, oldY = self.state
        dx, dy = Actions.directionToVector(action)
        x, y = int(oldX + dx), int(oldY + dy)
        if self.problem.walls[x][y]:
            raise AssertionError("Taking an action that goes into wall")
            pass
        else:
            self.state = (x, y)
        self.visited_states.append(self.state)

    def getPercepts(self):
        x, y = self.state
        north_iswall = self.problem.walls[x][y+1]
        south_iswall = self.problem.walls[x][y-1]
        east_iswall = self.problem.walls[x+1][y]
        west_iswall = self.problem.walls[x-1][y]
        return [north_iswall, south_iswall, east_iswall, west_iswall]

    def getValidActions(self):
        x, y = self.state
        actions = []
        if not self.problem.walls[x][y+1]: actions.append('North')
        if not self.problem.walls[x][y-1]: actions.append('South')
        if not self.problem.walls[x+1][y]: actions.append('East')
        if not self.problem.walls[x-1][y]: actions.append('West')
        return actions

    def drawPossibleStates(self, possibleLocations=None, direction="North", pacman_position=None):
        import __main__
        self.display.clearExpandedCells() # Erase previous colors
        self.display.colorCircleCells(possibleLocations, direction=direction, pacman_position=pacman_position)
def sensorAxioms(t: int, non_outer_wall_coords: List[Tuple[int, int]]) -> Expr:
    all_percept_exprs = []
    combo_var_def_exprs = []
    for direction in DIRECTIONS:
        percept_exprs = []
        dx, dy = DIR_TO_DXDY_MAP[direction]
        for x, y in non_outer_wall_coords:
            combo_var = PropSymbolExpr(pacman_wall_str, x, y, x + dx, y + dy, time=t)
            percept_exprs.append(combo_var)
            combo_var_def_exprs.append(combo_var % (
                PropSymbolExpr(pacman_str, x, y, time=t) & PropSymbolExpr(wall_str, x + dx, y + dy)))

        percept_unit_clause = PropSymbolExpr(blocked_str_map[direction], time = t)
        all_percept_exprs.append(percept_unit_clause % disjoin(percept_exprs))

    return conjoin(all_percept_exprs + combo_var_def_exprs)

一个简单的logic plan

def positionLogicPlan(problem):
    """
    Given an instance of a PositionPlanningProblem, return a list of actions that lead to the goal.
    Available actions are ['North', 'East', 'South', 'West']
    Note that STOP is not an available action.
    """
    walls = problem.walls
    width, height = problem.getWidth(), problem.getHeight()
    walls_list = walls.asList()
    x0, y0 = problem.startState
    xg, yg = problem.goal
    
    # Get lists of possible locations (i.e. without walls) and possible actions
    all_coords = list(itertools.product(range(width + 2), 
            range(height + 2)))
    non_wall_coords = [loc for loc in all_coords if loc not in walls_list]
    actions = [ 'North', 'South', 'East', 'West' ]
    KB = []

    "*** BEGIN YOUR CODE HERE ***"
    KB.append(PropSymbolExpr(pacman_str, x0, y0, 0))
    for t in range(50):
        #pacman can only be at one location
        props = []
        for (x,y) in non_wall_coords:
            props.append(PropSymbolExpr(pacman_str, x, y, t))
        KB.append(exactlyOne(props))

        #is there a satisfying model assignment?
        knowledge_base = conjoin(KB)
        model = findModel(knowledge_base & PropSymbolExpr(pacman_str, xg, yg, t))
        if model:
            return extractActionSequence(model, actions)

        #pacman takes exactly one position per time step
        KB.append(exactlyOne([PropSymbolExpr('North', t), PropSymbolExpr('South', t), PropSymbolExpr('East', t), PropSymbolExpr('West', t)]))

        #add transition models to KB
        for (x,y) in non_wall_coords:
            KB.append(pacmanSuccessorStateAxioms(x, y, t+1, walls, pacman_str))

First Order Logic

first order logic 拥有比propositional logic更加优秀的表达能力,以pacman游戏为例,我们在时间t没死等价于我们在t-1时间没死并且我们在t-1时的位置没有和任何鬼重合。如果用propositional logic需要用几千页来表达
在这里插入图片描述

一些关键词

term

在这里插入图片描述

atomic sentence

在这里插入图片描述

complex sentences

在这里插入图片描述
注意!!!first order logic 只在variable上使用quantifier,如果是在predicate上使用的话就变成了second order logic

如何解FOL

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值