在本章中,我們將重點(diǎn)介紹邏輯編程以及它在人工智能中的作用。
我們已經(jīng)知道邏輯是對正確推理原則的研究,或者簡單地說就是研究什么是什么。 例如,如果兩個陳述是真的,那么我們可以從中推斷出任何第三個陳述。
概念
邏輯編程是兩個字,邏輯和編程的組合。 邏輯編程是一種編程模式,其中問題通過程序語句表達(dá)為事實(shí)和規(guī)則,但在形式邏輯系統(tǒng)中。 就像面向?qū)ο螅瘮?shù)式,聲明式和程序式等其他編程模式一樣,它也是編程方法的一種特殊方式。
邏輯編程使用事實(shí)和規(guī)則來解決問題。 這就是為什么他們被稱為邏輯編程的基石。 在邏輯編程中需要為每個程序指定一個目標(biāo)。要理解在邏輯編程中如何解決問題,我們需要了解構(gòu)建塊 - 事實(shí)和規(guī)則 -
事實(shí)
實(shí)際上,每個邏輯程序都需要事實(shí)來處理,以達(dá)到既定目標(biāo)。 事實(shí)上基本上是關(guān)于計(jì)劃和數(shù)據(jù)的真實(shí)陳述。 例如,北京是中國的首都。
規(guī)則
實(shí)際上,規(guī)則是允許我們對問題域做出結(jié)論的約束條件。 規(guī)則基本上寫成邏輯條款來表達(dá)各種事實(shí)。 例如,如果構(gòu)建游戲,那么必須定義所有規(guī)則。
規(guī)則對于解決邏輯編程中的任何問題都非常重要。 規(guī)則基本上是可以表達(dá)事實(shí)的合乎邏輯的結(jié)論。 以下是規(guī)則的語法 -
A∶? B1,B2,...,Bn.
在這里,A是頭部,B1,B2,… Bn是主體。
例如 - ancestor(X,Y): - father(X,Y)。
ancestor(X,Z): - father(X,Y),ancestor(Y,Z)。
對于每一個X和Y,如果X是Y的父親,Y是Z的祖先,那么X是Z的祖先。對于每個X和Y,X是Z的祖先,如果X是 Y和Y的父親是Z的祖先。
為了在Python中開始邏輯編程,需要安裝以下兩個包 -
Kanren
它為我們提供了一種簡化業(yè)務(wù)邏輯編寫代碼的方式。 它讓我們用規(guī)則和事實(shí)來表達(dá)邏輯。 以下命令來安裝kanren -
pip install kanren
SymPy
SymPy是符號數(shù)學(xué)的Python庫。 它旨在成為一個全功能的計(jì)算機(jī)代數(shù)系統(tǒng)(CAS),同時保持代碼盡可能簡單,以便易于理解和擴(kuò)展。 以下命令是用來安裝SymPy -
pip install sympy
以下是一些可以通過邏輯編程解決的例子 -
匹配數(shù)學(xué)表達(dá)式
實(shí)際上,我們可以通過使用邏輯編程以非常有效的方式找到未知值。 以下Python代碼用于匹配數(shù)學(xué)表達(dá)式 -
考慮先導(dǎo)入下列軟件包 -
from kanren import run, var, fact
from kanren.assoccomm import eq_assoccomm as eq
from kanren.assoccomm import commutative, associative
需要定義要使用的數(shù)學(xué)運(yùn)算 -
add = 'add'
mul = 'mul'
加法和乘法都是交互進(jìn)程。 因此,我們需要指定它,這可以按照以下方式完成 -
fact(commutative, mul)
fact(commutative, add)
fact(associative, mul)
fact(associative, add)
定義變量是強(qiáng)制性的; 這可以如下完成 -
a, b = var('a'), var('b')
需要將表達(dá)式與原始模式相匹配。有以下原始模式,基礎(chǔ)是(5 + a)* b-
Original_pattern = (mul, (add, 5, a), b)
有以下兩個表達(dá)式來匹配原始模式 -
exp1 = (mul, 2, (add, 3, 1))
exp2 = (add,5,(mul,8,1))
輸出可以使用以下命令打印 -
print(run(0, (a,b), eq(original_pattern, exp1)))
print(run(0, (a,b), eq(original_pattern, exp2)))
運(yùn)行此代碼后,將得到以下輸出 -
((3,2))
()
第一個輸出表示a和b的值。 第一個表達(dá)式匹配原始模式并返回a和b的值,但第二個表達(dá)式與原始模式不匹配,因此沒有返回任何內(nèi)容。
在邏輯編程的幫助下,可以從數(shù)字列表中出素數(shù),也可以生成素數(shù)。 下面給出的Python代碼將從數(shù)字列表中找到素數(shù),并且還會生成前10個素數(shù)。
首先導(dǎo)入以下軟件包 -
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
現(xiàn)在,我們將定義一個名為prime_check的函數(shù),它將根據(jù)給定的數(shù)字檢查素數(shù)作為數(shù)據(jù)。
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
現(xiàn)在,聲明一個變量 -
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))))
上述代碼的輸出如下 -
{19, 23, 29, 41}
(2, 3, 5, 7, 11, 13, 17, 19, 23, 29)
邏輯編程可用于解決許多問題,如8拼圖,斑馬拼圖,數(shù)獨(dú),N皇后等。在這里,舉例說明斑馬拼圖的變體如下 -
有五間房子。
英國人住在紅房子里。
瑞典人有一只狗。
丹麥人喝茶。
綠房子在白房子的左邊。
他們在綠房子里喝咖啡。
吸Pall Mall的人有鳥。
吸Dunhill在的人黃色房子里。
在中間的房子里,他們喝牛奶。
挪威人住在第一宮。
那個抽Blend的男人住在貓屋旁邊的房子里。
在他們有一匹馬的房子旁邊的房子里,他們吸Dunhill煙。
抽Blue Master的人喝啤酒。
德國人吸Prince煙。
挪威人住在藍(lán)房子旁邊。
他們在房子旁邊的房子里喝水,在那里吸Blend煙。
在Python的幫助下解決誰有斑馬的問題。
導(dǎo)入必要的軟件包 -
from kanren import *
from kanren.core import lall
import time
現(xiàn)在,我們需要定義兩個函數(shù) - left()和next()來查找哪個房屋左邊或接近誰的房子 -
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)])
現(xiàn)在,聲明一個變量:houses,如下 -
houses = var()
需要在lall包的幫助下定義規(guī)則如下。
有5間房子 -
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)
)
現(xiàn)在,用前面的約束運(yùn)行解算器 -
solutions = run(0, houses, rules_zebraproblem)
借助以下代碼,可以提取解算器的輸出 -
output_zebra = [house for house in solutions[0] if 'zebra' in house][0][0]
以下代碼將打印解決方案 -
print ('\n'+ output_zebra + 'owns zebra.')
上述代碼的輸出如下 -
German owns zebra.