人工智慧邏輯程式設計


在本章中,我們將重點介紹邏輯程式設計以及它在人工智慧中的作用。

我們已經知道邏輯是對正確推理原則的研究,或者簡單地說就是研究什麼是什麼。 例如,如果兩個陳述是真的,那麼我們可以從中推斷出任何第三個陳述。

概念
邏輯程式設計是兩個字,邏輯和程式設計的組合。 邏輯程式設計是一種程式設計模式,其中問題通過程式語句表達為事實和規則,但在形式邏輯系統中。 就像物件導向,函式式,宣告式和程式式等其他程式設計模式一樣,它也是程式設計方法的一種特殊方式。

如何用邏輯程式設計解決問題

邏輯程式設計使用事實和規則來解決問題。 這就是為什麼他們被稱為邏輯程式設計的基石。 在邏輯程式設計中需要為每個程式指定一個目標。要理解在邏輯程式設計中如何解決問題,我們需要了解構建塊 - 事實和規則 -

事實
實際上,每個邏輯程式都需要事實來處理,以達到既定目標。 事實上基本上是關於計劃和資料的真實陳述。 例如,北京是中國的首都。

規則
實際上,規則是允許我們對問題域做出結論的約束條件。 規則基本上寫成邏輯條款來表達各種事實。 例如,如果構建遊戲,那麼必須定義所有規則。

規則對於解決邏輯程式設計中的任何問題都非常重要。 規則基本上是可以表達事實的合乎邏輯的結論。 以下是規則的語法 -

A∶? B1,B2,...,Bn.

在這裡,A是頭部,B1,B2,… Bn是主體。

例如 - ancestor(X,Y): - father(X,Y)

ancestor(X,Z): - father(X,Y),ancestor(Y,Z)

對於每一個XY,如果XY的父親,YZ的祖先,那麼XZ的祖先。對於每個XYXZ的祖先,如果XYY的父親是Z的祖先。

安裝必需的包

為了在Python中開始邏輯程式設計,需要安裝以下兩個包 -

Kanren
它為我們提供了一種簡化業務邏輯編寫程式碼的方式。 它讓我們用規則和事實來表達邏輯。 以下命令來安裝kanren -

pip install kanren

SymPy
SymPy是符號數學的Python庫。 它旨在成為一個全功能的計算機代數系統(CAS),同時保持程式碼盡可能簡單,以便易於理解和擴充套件。 以下命令是用來安裝SymPy -

pip install sympy

邏輯程式設計的例子

以下是一些可以通過邏輯程式設計解決的例子 -

匹配數學表示式

實際上,我們可以通過使用邏輯程式設計以非常有效的方式找到未知值。 以下Python程式碼用於匹配數學表示式 -

考慮先匯入下列軟體包 -

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))
()

第一個輸出表示ab的值。 第一個表示式匹配原始模式並返回ab的值,但第二個表示式與原始模式不匹配,因此沒有返回任何內容。

查詢素數

在邏輯程式設計的幫助下,可以從數位列表中出素數,也可以生成素數。 下面給出的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)

解決難題

邏輯程式設計可用於解決許多問題,如8拼圖,斑馬拼圖,數獨,N皇后等。在這裡,舉例說明斑馬拼圖的變體如下 -

有五間房子。
英國人住在紅房子裡。
瑞典人有一隻狗。
丹麥人喝茶。
綠房子在白房子的左邊。
他們在綠房子裡喝咖啡。
吸Pall Mall的人有鳥。
吸Dunhill在的人黃色房子裡。
在中間的房子裡,他們喝牛奶。
挪威人住在第一宮。
那個抽Blend的男人住在貓屋旁邊的房子裡。
在他們有一匹馬的房子旁邊的房子裡,他們吸Dunhill菸。
抽Blue Master的人喝啤酒。
德國人吸Prince菸。
挪威人住在藍房子旁邊。
他們在房子旁邊的房子裡喝水,在那裡吸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)])

現在,宣告一個變數:houses,如下 -

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)

借助以下程式碼,可以提取解算器的輸出 -

output_zebra = [house for house in solutions[0] if 'zebra' in house][0][0]

以下程式碼將列印解決方案 -

print ('\n'+ output_zebra + 'owns zebra.')

上述程式碼的輸出如下 -

German owns zebra.