在這一章中,我們將集中討論邏輯編程以及它如何幫助人工智慧。
我們已經知道,邏輯是對正確推理原則的研究,或者簡單地說,它是對什麼之後發生什麼的研究。例如,如果兩個語句是真的,那麼我們可以從中推斷出任何第三個語句。
Concept
邏輯程序設計是兩個詞的組合,邏輯和程序設計。邏輯程序設計是一種程序設計範式,在這種編程範式中,問題通過程序語句表達爲事實和規則,但在形式邏輯系統中。與其他編程模式(如面向對象、函數式、聲明式和過程式等)一樣,它也是一種特殊的編程方法。
How to Solve Problems with Logic Programming
邏輯程序設計使用事實和規則來解決問題。這就是爲什麼它們被稱爲邏輯編程的構建塊。需要爲邏輯程序設計中的每個程序指定一個目標。要了解如何在邏輯編程中解決問題,我們需要了解構造塊&負;事實和規則&負;
Facts
實際上,每一個邏輯程序都需要事實來處理,這樣才能達到給定的目標。事實基本上是關於程序和數據的真實陳述。例如,德里是印度的首都。
Rules
實際上,規則是允許我們對問題域做出結論的約束條件。基本上作爲邏輯從句來表達各種事實的規則。例如,如果我們正在構建任何遊戲,那麼必須定義所有規則。
規則對於解決邏輯程序設計中的任何問題都非常重要。規則基本上是能夠表達事實的邏輯結論。下面是rule&minus的語法;
A∶− B1,B2,...,Bn.
這裡,A是頭部,B1,B2。。。Bn是身體。
例如,祖先(X,Y):-父親(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的祖先。
Installing Useful Packages
爲了在Python中啓動邏輯編程,我們需要安裝以下兩個包−
Kanren
它爲我們提供了一種簡化爲業務邏輯編寫代碼的方法。它讓我們用規則和事實來表達邏輯。下面的命令將幫助您安裝kanren−
pip install kanren
SymPy
SymPy是一個用於符號數學的Python庫。它的目標是成爲一個功能齊全的計算機代數系統(CAS),同時保持代碼儘可能簡單,以便易於理解和擴展。以下命令將幫助您安裝SymPy−
pip install sympy
Examples of Logic Programming
下面是一些可以通過邏輯編程來解決的例子−
Matching mathematical expressions
實際上,我們可以用一種非常有效的方法通過邏輯編程找到未知值。下面的Python代碼將幫助您匹配數學表達式-minus;
考慮先導入以下包−
from kanren import run, var, fact from kanren.assoccomm import eq_assoccomm as eq from kanren.assoccomm import commutative, associative
我們需要定義我們將要使用的數學運算;
add = 'add' mul = 'mul'
加法和乘法都是交際過程。因此,我們需要指定它,這可以按以下方式完成&負;
fact(commutative, mul) fact(commutative, add) fact(associative, mul) fact(associative, add)
必須定義變量;這可以按以下方式進行&負;
a, b = var('a'), var('b')
我們需要將表達式與原始模式匹配。我們有以下原始模式,基本上是(5+a)*b−
Original_pattern = (mul, (add, 5, a), b)
我們有以下兩個表達式與原始模式相匹配−
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)))
運行此代碼後,我們將得到以下輸出&負;
((3,2)) ()
第一個輸出表示a和b的值。第一個表達式與原始模式匹配,並返回a和b的值,但第二個表達式與原始模式不匹配,因此未返回任何內容。
Checking for Prime Numbers
藉助於邏輯編程,我們可以從一個數列中找到素數,也可以生成素數。下面給出的Python代碼將從一個數字列表中找到質數,並且還將生成前10個質數。
讓我們首先考慮進口下列包裝;
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的函數,它將根據給定的數字作爲數據來檢查素數。
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
現在,我們需要聲明一個將要使用的變量;
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)
Solving Puzzles
邏輯程序設計可以用來解決許多問題,如8字謎、斑馬謎、數獨、N皇后等。這裡我們以斑馬謎的一個變體爲例,它是如下所示的;
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的幫助下,我們正在解決誰擁有斑馬的問題。
讓我們進口必要的包裝;
from kanren import * from kanren.core import lall import time
現在,我們需要定義兩個函數−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)])
現在,我們將聲明一個可變的house,如下所示;
houses = var()
我們需要在lall包的幫助下定義以下規則。
一共有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) )
現在,使用前面的約束運行解算器;
solutions = run(0, houses, rules_zebraproblem)
藉助下面的代碼,我們可以從solver−
output_zebra = [house for house in solutions[0] if 'zebra' in house][0][0]
下面的代碼將幫助列印解決方案−
print ('\n'+ output_zebra + 'owns zebra.')
上述代碼的輸出如下所示&負;