Artificial Intelligence With Python 简明教程
AI with Python – Logic Programming
在本章中,我们将重点关注逻辑编程及其如何在人工智能中提供帮助。
In this chapter, we will focus logic programming and how it helps in Artificial Intelligence.
我们已经知道逻辑是对正确推理原则的研究,或者用简单的话来说,它是对什么在什么之后的研究。例如,如果两个语句为真,那么我们可以从中推断出任何第三个语句。
We already know that logic is the study of principles of correct reasoning or in simple words it is the study of what comes after what. For example, if two statements are true then we can infer any third statement from it.
Concept
逻辑编程是两个单词的组合,逻辑和编程。逻辑编程是一种编程范例,其中问题以程序语句表示为事实和规则,但处于形式逻辑系统内。就像面向对象、函数、声明和过程等其他编程范例一样,它也是一种特定的编程方法。
Logic Programming is the combination of two words, logic and programming. Logic Programming is a programming paradigm in which the problems are expressed as facts and rules by program statements but within a system of formal logic. Just like other programming paradigms like object oriented, functional, declarative, and procedural, etc., it is also a particular way to approach programming.
How to Solve Problems with Logic Programming
逻辑编程使用事实和规则来解决问题。这就是为什么它们被称为逻辑编程的构建块。必须为逻辑编程中的每个程序指定一个目标。要了解如何在逻辑编程中解决问题,我们需要了解构建块——事实和规则−
Logic Programming uses facts and rules for solving the problem. That is why they are called the building blocks of Logic Programming. A goal needs to be specified for every program in logic programming. To understand how a problem can be solved in logic programming, we need to know about the building blocks − Facts and Rules −
Facts
实际上,每个逻辑程序都需要事实来使用,以便它可以实现给定的目标。事实上,这些是关于程序和数据的真陈述。例如,德里是印度的首都。
Actually, every logic program needs facts to work with so that it can achieve the given goal. Facts basically are true statements about the program and data. For example, Delhi is the capital of India.
Rules
实际上,规则是允许我们对问题域做出结论的约束。规则基本上写为逻辑子句以表达各种事实。例如,如果我们构建任何游戏,则必须定义所有规则。
Actually, rules are the constraints which allow us to make conclusions about the problem domain. Rules basically written as logical clauses to express various facts. For example, if we are building any game then all the rules must be defined.
规则对于解决逻辑编程中的任何问题都非常重要。规则基本上是逻辑结论,其可以表达事实。以下是规则的语法:
Rules are very important to solve any problem in Logic Programming. Rules are basically logical conclusion which can express the facts. Following is the syntax of rule −
A∶− B1,B2,…,Bn.
此处,A 是头,而 B1, B2, … Bn 是正文。
Here, A is the head and B1, B2, … Bn is the body.
例如:ancestor(X,Y) :- father(X,Y)。
For example − ancestor(X,Y) :- father(X,Y).
ancestor(X,Z) :- father(X,Y), ancestor(Y,Z)。
ancestor(X,Z) :- father(X,Y), ancestor(Y,Z).
这可以理解为,对于每个 X 和 Y,如果 X 是 Y 的父亲并且 Y 是 Z 的祖先,那么 X 是 Z 的祖先。对于每个 X 和 Y,如果 X 是 Y 的父亲并且 Y 是 Z 的祖先,那么 X 是 Z 的祖先。
This can be read as, for every X and Y, if X is the father of Y and Y is an ancestor of Z, X is the ancestor of Z. For every X and Y, X is the ancestor of Z, if X is the father of Y and Y is an ancestor of Z.
Installing Useful Packages
要在 Python 中启动逻辑编程,我们需要安装以下两个软件包:
For starting logic programming in Python, we need to install the following two packages −
Kanren
它为我们提供了一种简化业务逻辑代码编写方式的方法。它允许我们以规则和事实的形式来表达逻辑。以下命令将帮助你安装 kanren:
It provides us a way to simplify the way we made code for business logic. It lets us express the logic in terms of rules and facts. The following command will help you install kanren −
pip install kanren
SymPy
SymPy 是用于符号数学的 Python 库。它的目标是成为一个功能齐全的计算机代数系统 (CAS),同时尽可能保持代码简单,以便易于理解和扩展。以下命令将帮助你安装 SymPy:
SymPy is a Python library for symbolic mathematics. It aims to become a full-featured computer algebra system (CAS) while keeping the code as simple as possible in order to be comprehensible and easily extensible. The following command will help you install SymPy −
pip install sympy
Examples of Logic Programming
以下是可以通过逻辑编程解决的一些示例:
Followings are some examples which can be solved by logic programming −
Matching mathematical expressions
实际上,我们可以使用非常有效的方法通过逻辑编程来发现未知值。以下 Python 代码将帮助你匹配数学表达式:
Actually we can find the unknown values by using logic programming in a very effective way. The following Python code will help you match a mathematical expression −
首先考虑导入以下软件包:
Consider importing the following packages first −
from kanren import run, var, fact
from kanren.assoccomm import eq_assoccomm as eq
from kanren.assoccomm import commutative, associative
我们需要定义将要使用的数学运算:
We need to define the mathematical operations which we are going to use −
add = 'add'
mul = 'mul'
加法和乘法都是可交换的过程。因此,我们需要指定它,可以如下执行:
Both addition and multiplication are communicative processes. Hence, we need to specify it and this can be done as follows −
fact(commutative, mul)
fact(commutative, add)
fact(associative, mul)
fact(associative, add)
必须定义变量;可以如下执行此操作:
It is compulsory to define variables; this can be done as follows −
a, b = var('a'), var('b')
我们需要将表达式与原始模式相匹配。我们有以下原始模式,它基本上是 (5+a)*b:
We need to match the expression with the original pattern. We have the following original pattern, which is basically (5+a)*b −
Original_pattern = (mul, (add, 5, a), b)
我们有以下两个表达式与原始模式相匹配:
We have the following two expressions to match with the original pattern −
exp1 = (mul, 2, (add, 3, 1))
exp2 = (add,5,(mul,8,1))
使用以下命令打印输出 -
Output can be printed with the following command −
print(run(0, (a,b), eq(original_pattern, exp1)))
print(run(0, (a,b), eq(original_pattern, exp2)))
运行此代码后,我们将获得以下输出 -
After running this code, we will get the following output −
((3,2))
()
第一个输出表示 a 和 b 的值。第一个表达式匹配原始模式并返回 a 和 b 的值,但第二个表达式不匹配原始模式,因此没有返回任何内容。
The first output represents the values for a and b. The first expression matched the original pattern and returned the values for a and b but the second expression did not match the original pattern hence nothing has been returned.
Checking for Prime Numbers
借助逻辑编程,我们可以从一组数字中找出质数,还可以生成质数。下面给出的 Python 代码将从一组数字中找出质数,并将生成前 10 个质数。
With the help of logic programming, we can find the prime numbers from a list of numbers and can also generate prime numbers. The Python code given below will find the prime number from a list of numbers and will also generate the first 10 prime numbers.
让我们首先考虑导入以下软件包 -
Let us first consider importing the following packages −
from kanren import isvar, run, membero
from kanren.core import success, fail, goaleval, condeseq, eq, var
from sympy.ntheory.generate import prime, isprime
import itertools as it
现在,我们将定义一个名为 prime_check 的函数,它将根据给定的数字作为数据检查质数。
Now, we will define a function called prime_check which will check the prime numbers based on the given numbers as data.
def prime_check(x):
if isvar(x):
return condeseq([(eq,x,p)] for p in map(prime, it.count(1)))
else:
return success if isprime(x) else fail
现在,我们需要声明一个将要使用的变量 -
Now, we need to declare a variable which will be used −
x = var()
print((set(run(0,x,(membero,x,(12,14,15,19,20,21,22,23,29,30,41,44,52,62,65,85)),
(prime_check,x)))))
print((run(10,x,prime_check(x))))
上述代码的输出如下 -
The output of the above code will be as follows −
{19, 23, 29, 41}
(2, 3, 5, 7, 11, 13, 17, 19, 23, 29)
Solving Puzzles
逻辑编程可用来解决诸如 8-puzzles、Zebra puzzle、数独、N-queen 等许多问题。这里我们以 Zebra puzzle 的一个变体为例,如下所示 -
Logic programming can be used to solve many problems like 8-puzzles, Zebra puzzle, Sudoku, N-queen, etc. Here we are taking an example of a variant of Zebra puzzle which is as follows −
There are five houses.
The English man lives in the red house.
The Swede has a dog.
The Dane drinks tea.
The green house is immediately to the left of the white house.
They drink coffee in the green house.
The man who smokes Pall Mall has birds.
In the yellow house they smoke Dunhill.
In the middle house they drink milk.
The Norwegian lives in the first house.
The man who smokes Blend lives in the house next to the house with cats.
In a house next to the house where they have a horse, they smoke Dunhill.
The man who smokes Blue Master drinks beer.
The German smokes Prince.
The Norwegian lives next to the blue house.
They drink water in a house next to the house where they smoke Blend.
我们借助 Python 帮我们解决问题 who owns zebra 。
We are solving it for the question who owns zebra with the help of Python.
让我们导入必要的软件包 −
Let us import the necessary packages −
from kanren import *
from kanren.core import lall
import time
现在,我们需要定义两个函数 - left() 和 next() 来检查谁的房子在谁的房子左边或旁边 -
Now, we need to define two functions − left() and next() to check whose house is left or next to who’s house −
def left(q, p, list):
return membero((q,p), zip(list, list[1:]))
def next(q, p, list):
return conde([left(q, p, list)], [left(p, q, list)])
现在,我们将声明一个变量 house,如下所示 -
Now, we will declare a variable house as follows −
houses = var()
我们需要借助 lall 软件包来定义规则,如下所示。
We need to define the rules with the help of lall package as follows.
有 5 所房子 -
There are 5 houses −
rules_zebraproblem = lall(
(eq, (var(), var(), var(), var(), var()), houses),
(membero,('Englishman', var(), var(), var(), 'red'), houses),
(membero,('Swede', var(), var(), 'dog', var()), houses),
(membero,('Dane', var(), 'tea', var(), var()), houses),
(left,(var(), var(), var(), var(), 'green'),
(var(), var(), var(), var(), 'white'), houses),
(membero,(var(), var(), 'coffee', var(), 'green'), houses),
(membero,(var(), 'Pall Mall', var(), 'birds', var()), houses),
(membero,(var(), 'Dunhill', var(), var(), 'yellow'), houses),
(eq,(var(), var(), (var(), var(), 'milk', var(), var()), var(), var()), houses),
(eq,(('Norwegian', var(), var(), var(), var()), var(), var(), var(), var()), houses),
(next,(var(), 'Blend', var(), var(), var()),
(var(), var(), var(), 'cats', var()), houses),
(next,(var(), 'Dunhill', var(), var(), var()),
(var(), var(), var(), 'horse', var()), houses),
(membero,(var(), 'Blue Master', 'beer', var(), var()), houses),
(membero,('German', 'Prince', var(), var(), var()), houses),
(next,('Norwegian', var(), var(), var(), var()),
(var(), var(), var(), var(), 'blue'), houses),
(next,(var(), 'Blend', var(), var(), var()),
(var(), var(), 'water', var(), var()), houses),
(membero,(var(), var(), var(), 'zebra', var()), houses)
)
现在,使用前面的约束运行求解器 -
Now, run the solver with the preceding constraints −
solutions = run(0, houses, rules_zebraproblem)
借助以下代码,我们可以从求解器中提取输出 -
With the help of the following code, we can extract the output from the solver −
output_zebra = [house for house in solutions[0] if 'zebra' in house][0][0]
以下代码有助于打印解决方案 -
The following code will help print the solution −
print ('\n'+ output_zebra + 'owns zebra.')
上述代码的输出如下 -
The output of the above code would be as follows −
German owns zebra.