AI avec Python - Programmation logique

Dans ce chapitre, nous nous concentrerons sur la programmation logique et sur son utilité dans l'intelligence artificielle.

Nous savons déjà que la logique est l'étude des principes du raisonnement correct ou, en termes simples, c'est l'étude de ce qui vient après quoi. Par exemple, si deux déclarations sont vraies, nous pouvons en déduire n'importe quelle troisième instruction.

Concept

La programmation logique est la combinaison de deux mots, logique et programmation. La programmation logique est un paradigme de programmation dans lequel les problèmes sont exprimés sous forme de faits et de règles par des instructions de programme mais dans un système de logique formelle. Tout comme d'autres paradigmes de programmation comme orienté objet, fonctionnel, déclaratif et procédural, etc., c'est aussi une manière particulière d'aborder la programmation.

Comment résoudre les problèmes de programmation logique

La programmation logique utilise des faits et des règles pour résoudre le problème. C'est pourquoi ils sont appelés les blocs de construction de la programmation logique. Un objectif doit être spécifié pour chaque programme en programmation logique. Pour comprendre comment un problème peut être résolu en programmation logique, nous devons connaître les éléments de base - faits et règles -

Les faits

En fait, chaque programme logique a besoin de faits avec lesquels travailler pour pouvoir atteindre l'objectif donné. Les faits sont essentiellement des déclarations vraies sur le programme et les données. Par exemple, Delhi est la capitale de l'Inde.

Règles

En fait, les règles sont les contraintes qui nous permettent de tirer des conclusions sur le domaine du problème. Règles essentiellement écrites comme des clauses logiques pour exprimer divers faits. Par exemple, si nous construisons un jeu, toutes les règles doivent être définies.

Les règles sont très importantes pour résoudre tout problème de programmation logique. Les règles sont essentiellement des conclusions logiques qui peuvent exprimer les faits. Voici la syntaxe de la règle -

A∶− B1, B2, ..., B n .

Ici, A est la tête et B1, B2, ... Bn est le corps.

Par exemple - ancêtre (X, Y): - père (X, Y).

ancêtre (X, Z): - père (X, Y), ancêtre (Y, Z).

Cela peut être lu comme, pour chaque X et Y, si X est le père de Y et Y est un ancêtre de Z, X est l'ancêtre de Z. Pour chaque X et Y, X est l'ancêtre de Z, si X est le père de Y et Y est un ancêtre de Z.

Installer des packages utiles

Pour démarrer la programmation logique en Python, nous devons installer les deux packages suivants -

Kanren

Cela nous fournit un moyen de simplifier la façon dont nous avons créé du code pour la logique métier. Cela nous permet d'exprimer la logique en termes de règles et de faits. La commande suivante vous aidera à installer kanren -

pip install kanren

SymPy

SymPy est une bibliothèque Python pour les mathématiques symboliques. Il vise à devenir un système d'algèbre informatique (CAS) complet tout en gardant le code aussi simple que possible afin d'être compréhensible et facilement extensible. La commande suivante vous aidera à installer SymPy -

pip install sympy

Exemples de programmation logique

Voici quelques exemples qui peuvent être résolus par programmation logique -

Correspondance d'expressions mathématiques

En fait, nous pouvons trouver les valeurs inconnues en utilisant la programmation logique de manière très efficace. Le code Python suivant vous aidera à faire correspondre une expression mathématique -

Pensez d'abord à importer les packages suivants -

from kanren import run, var, fact
from kanren.assoccomm import eq_assoccomm as eq
from kanren.assoccomm import commutative, associative

Nous devons définir les opérations mathématiques que nous allons utiliser -

add = 'add'
mul = 'mul'

L'addition et la multiplication sont des processus communicatifs. Par conséquent, nous devons le spécifier et cela peut être fait comme suit -

fact(commutative, mul)
fact(commutative, add)
fact(associative, mul)
fact(associative, add)

Il est obligatoire de définir des variables; cela peut être fait comme suit -

a, b = var('a'), var('b')

Nous devons faire correspondre l'expression avec le modèle d'origine. Nous avons le modèle original suivant, qui est fondamentalement (5 + a) * b -

Original_pattern = (mul, (add, 5, a), b)

Nous avons les deux expressions suivantes à faire correspondre avec le modèle d'origine -

exp1 = (mul, 2, (add, 3, 1))
exp2 = (add,5,(mul,8,1))

La sortie peut être imprimée avec la commande suivante -

print(run(0, (a,b), eq(original_pattern, exp1)))
print(run(0, (a,b), eq(original_pattern, exp2)))

Après avoir exécuté ce code, nous obtiendrons la sortie suivante -

((3,2))
()

La première sortie représente les valeurs pour a et b. La première expression correspondait au modèle d'origine et a renvoyé les valeurs dea et b mais la deuxième expression ne correspondait pas au modèle d'origine, donc rien n'a été renvoyé.

Vérification des nombres premiers

Avec l'aide de la programmation logique, nous pouvons trouver les nombres premiers à partir d'une liste de nombres et pouvons également générer des nombres premiers. Le code Python ci-dessous trouvera le nombre premier à partir d'une liste de nombres et générera également les 10 premiers nombres premiers.

Considérons d'abord l'importation des packages suivants -

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

Maintenant, nous allons définir une fonction appelée prime_check qui vérifiera les nombres premiers en fonction des nombres donnés en tant que données.

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

Maintenant, nous devons déclarer une variable qui sera utilisée -

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

La sortie du code ci-dessus sera la suivante -

{19, 23, 29, 41}
(2, 3, 5, 7, 11, 13, 17, 19, 23, 29)

Résoudre des puzzles

La programmation logique peut être utilisée pour résoudre de nombreux problèmes comme 8-puzzles, Zebra puzzle, Sudoku, N-queen, etc. Ici, nous prenons un exemple d'une variante de Zebra puzzle qui est la suivante -

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.

Nous le résolvons pour la question who owns zebra avec l'aide de Python.

Importons les packages nécessaires -

from kanren import *
from kanren.core import lall
import time

Maintenant, nous devons définir deux fonctions - left() et next() pour vérifier à qui appartient la maison ou à côté de qui est la maison -

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

Maintenant, nous allons déclarer une maison variable comme suit -

houses = var()

Nous devons définir les règles à l'aide de lall package comme suit.

Il y a 5 maisons -

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

Maintenant, exécutez le solveur avec les contraintes précédentes -

solutions = run(0, houses, rules_zebraproblem)

À l'aide du code suivant, nous pouvons extraire la sortie du solveur -

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

Le code suivant aidera à imprimer la solution -

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

La sortie du code ci-dessus serait la suivante -

German owns zebra.