AI กับ Python - การเขียนโปรแกรมลอจิก
ในบทนี้เราจะเน้นการเขียนโปรแกรมเชิงตรรกะและวิธีการช่วยในปัญญาประดิษฐ์
เรารู้อยู่แล้วว่าตรรกะคือการศึกษาหลักการของการใช้เหตุผลที่ถูกต้องหรือพูดง่ายๆก็คือการศึกษาสิ่งที่เกิดขึ้นหลังจากอะไร ตัวอย่างเช่นหากสองคำสั่งเป็นจริงเราสามารถอนุมานคำสั่งที่สามจากคำสั่งนั้นได้
แนวคิด
Logic Programming คือการรวมกันของสองคำตรรกะและการเขียนโปรแกรม Logic Programming เป็นกระบวนทัศน์ในการเขียนโปรแกรมซึ่งปัญหาจะแสดงเป็นข้อเท็จจริงและกฎเกณฑ์โดยข้อความของโปรแกรม แต่อยู่ในระบบของตรรกะที่เป็นทางการ เช่นเดียวกับกระบวนทัศน์การเขียนโปรแกรมอื่น ๆ เช่นเชิงวัตถุการใช้งานการประกาศและขั้นตอนเป็นต้นมันเป็นวิธีเฉพาะในการเข้าถึงการเขียนโปรแกรม
วิธีแก้ปัญหาเกี่ยวกับการเขียนโปรแกรมลอจิก
Logic Programming ใช้ข้อเท็จจริงและกฎเกณฑ์ในการแก้ปัญหา นั่นคือเหตุผลที่พวกเขาเรียกว่า Building Block ของ Logic Programming ต้องระบุเป้าหมายสำหรับทุกโปรแกรมในการเขียนโปรแกรมลอจิก เพื่อให้เข้าใจว่าปัญหาสามารถแก้ไขได้อย่างไรในการเขียนโปรแกรมลอจิกเราจำเป็นต้องรู้เกี่ยวกับหน่วยการสร้าง - ข้อเท็จจริงและกฎ -
ข้อเท็จจริง
จริงๆแล้วโปรแกรมลอจิกทุกโปรแกรมต้องการข้อเท็จจริงเพื่อให้สามารถบรรลุเป้าหมายที่กำหนดได้ ข้อเท็จจริงโดยทั่วไปคือข้อความที่เป็นจริงเกี่ยวกับโปรแกรมและข้อมูล ตัวอย่างเช่นเดลีเป็นเมืองหลวงของอินเดีย
กฎ
จริงๆแล้วกฎเป็นข้อ จำกัด ที่ทำให้เราสามารถสรุปเกี่ยวกับโดเมนปัญหาได้ กฎที่เขียนโดยทั่วไปเป็นข้อตรรกะเพื่อแสดงข้อเท็จจริงต่างๆ ตัวอย่างเช่นหากเรากำลังสร้างเกมใด ๆ ก็ต้องกำหนดกฎทั้งหมด
กฎมีความสำคัญมากในการแก้ปัญหาใน Logic Programming กฎเป็นข้อสรุปเชิงตรรกะซึ่งสามารถแสดงข้อเท็จจริงได้ ต่อไปนี้เป็นไวยากรณ์ของกฎ -
A∶− B1, B2, ... , B n .
ที่นี่ A คือหัวและ B1, B2, ... Bn คือร่างกาย
ตัวอย่างเช่น - บรรพบุรุษ (X, Y): - พ่อ (X, Y)
บรรพบุรุษ (X, Z): - พ่อ (X, Y) บรรพบุรุษ (Y, Z)
สิ่งนี้สามารถอ่านได้ว่าสำหรับทุก X และ Y ถ้า X เป็นพ่อของ Y และ Y เป็นบรรพบุรุษของ Z X คือบรรพบุรุษของ Z สำหรับ X และ Y ทุกตัว X คือบรรพบุรุษของ Z ถ้า X คือ พ่อของ Y และ Y เป็นบรรพบุรุษของ 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))
()
ผลลัพธ์แรกแสดงถึงค่าสำหรับ a และ b. นิพจน์แรกตรงกับรูปแบบดั้งเดิมและส่งคืนค่าสำหรับa และ b แต่นิพจน์ที่สองไม่ตรงกับรูปแบบเดิมจึงไม่มีการส่งคืน
กำลังตรวจหา 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)
การแก้ปริศนา
การเขียนโปรแกรมลอจิกสามารถใช้เพื่อแก้ปัญหาต่างๆเช่น 8-puzzle, Zebra puzzle, Sudoku, N-queen เป็นต้นต่อไปนี้เราจะยกตัวอย่างของตัวต่อ Zebra ที่แตกต่างกันซึ่งมีดังต่อไปนี้ -
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.
เรากำลังแก้ปัญหาสำหรับคำถามนี้ who owns zebra ด้วยความช่วยเหลือของ 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 = 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.