IA con Python - Programación lógica

En este capítulo, nos centraremos en la programación lógica y cómo ayuda en la Inteligencia Artificial.

Ya sabemos que la lógica es el estudio de los principios del razonamiento correcto o en palabras simples es el estudio de lo que viene después de qué. Por ejemplo, si dos afirmaciones son verdaderas, podemos inferir cualquier tercera afirmación de ellas.

Concepto

La programación lógica es la combinación de dos palabras, lógica y programación. La programación lógica es un paradigma de programación en el que los problemas se expresan como hechos y reglas mediante declaraciones de programa, pero dentro de un sistema de lógica formal. Al igual que otros paradigmas de programación como orientado a objetos, funcional, declarativo y procedimental, etc., también es una forma particular de abordar la programación.

Cómo resolver problemas con la programación lógica

La programación lógica usa hechos y reglas para resolver el problema. Por eso se les llama los bloques de construcción de la programación lógica. Es necesario especificar un objetivo para cada programa en la programación lógica. Para comprender cómo se puede resolver un problema en la programación lógica, necesitamos conocer los componentes básicos (hechos y reglas)

Hechos

En realidad, cada programa lógico necesita hechos con los que trabajar para poder lograr el objetivo dado. Los hechos son básicamente declaraciones verdaderas sobre el programa y los datos. Por ejemplo, Delhi es la capital de India.

Reglas

En realidad, las reglas son las restricciones que nos permiten sacar conclusiones sobre el dominio del problema. Reglas básicamente escritas como cláusulas lógicas para expresar varios hechos. Por ejemplo, si estamos construyendo cualquier juego, entonces se deben definir todas las reglas.

Las reglas son muy importantes para resolver cualquier problema en la Programación Lógica. Las reglas son básicamente conclusiones lógicas que pueden expresar los hechos. A continuación se muestra la sintaxis de la regla:

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

Aquí, A es la cabeza y B1, B2, ... Bn es el cuerpo.

Por ejemplo - ancestro (X, Y): - padre (X, Y).

antepasado (X, Z): - padre (X, Y), antepasado (Y, Z).

Esto se puede leer como, para cada X e Y, si X es el padre de Y e Y es un antepasado de Z, X es el antepasado de Z. Para cada X e Y, X es el antepasado de Z, si X es el padre de Y e Y es un antepasado de Z.

Instalación de paquetes útiles

Para iniciar la programación lógica en Python, necesitamos instalar los siguientes dos paquetes:

Kanren

Nos proporciona una forma de simplificar la forma en que creamos código para la lógica empresarial. Nos permite expresar la lógica en términos de reglas y hechos. El siguiente comando te ayudará a instalar kanren:

pip install kanren

SymPy

SymPy es una biblioteca de Python para matemáticas simbólicas. Su objetivo es convertirse en un sistema de álgebra computacional (CAS) con todas las funciones, manteniendo el código lo más simple posible para que sea comprensible y fácilmente extensible. El siguiente comando te ayudará a instalar SymPy:

pip install sympy

Ejemplos de programación lógica

Los siguientes son algunos ejemplos que pueden resolverse mediante programación lógica:

Coincidencia de expresiones matemáticas

De hecho, podemos encontrar los valores desconocidos usando la programación lógica de una manera muy efectiva. El siguiente código de Python lo ayudará a hacer coincidir una expresión matemática:

Considere importar primero los siguientes paquetes:

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

Necesitamos definir las operaciones matemáticas que vamos a utilizar -

add = 'add'
mul = 'mul'

Tanto la suma como la multiplicación son procesos comunicativos. Por lo tanto, debemos especificarlo y esto se puede hacer de la siguiente manera:

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

Es obligatorio definir variables; esto se puede hacer de la siguiente manera:

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

Necesitamos hacer coincidir la expresión con el patrón original. Tenemos el siguiente patrón original, que es básicamente (5 + a) * b -

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

Tenemos las siguientes dos expresiones para que coincidan con el patrón original:

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

La salida se puede imprimir con el siguiente comando:

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

Después de ejecutar este código, obtendremos el siguiente resultado:

((3,2))
()

La primera salida representa los valores de a y b. La primera expresión coincidió con el patrón original y devolvió los valores paraa y b pero la segunda expresión no coincide con el patrón original, por lo que no se ha devuelto nada.

Comprobación de números primos

Con la ayuda de la programación lógica, podemos encontrar los números primos de una lista de números y también podemos generar números primos. El código de Python que se proporciona a continuación encontrará el número primo de una lista de números y también generará los primeros 10 números primos.

Consideremos primero la importación de los siguientes paquetes:

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

Ahora, definiremos una función llamada prime_check que verificará los números primos basándose en los números dados como datos.

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

Ahora, necesitamos declarar una variable que se utilizará:

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 salida del código anterior será la siguiente:

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

Resolver acertijos

La programación lógica se puede utilizar para resolver muchos problemas como 8 rompecabezas, rompecabezas Zebra, Sudoku, N-queen, etc. Aquí tomamos un ejemplo de una variante del rompecabezas Zebra que es el siguiente:

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.

Lo estamos resolviendo para la pregunta who owns zebra con la ayuda de Python.

Importamos los paquetes necesarios -

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

Ahora, necesitamos definir dos funciones: left() y next() para comprobar de quién queda la casa o al lado de la casa de quién -

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

Ahora, declararemos una casa variable de la siguiente manera:

houses = var()

Necesitamos definir las reglas con la ayuda del paquete lall de la siguiente manera.

Hay 5 casas -

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

Ahora, ejecute el solucionador con las restricciones anteriores:

solutions = run(0, houses, rules_zebraproblem)

Con la ayuda del siguiente código, podemos extraer la salida del solucionador:

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

El siguiente código ayudará a imprimir la solución:

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

La salida del código anterior sería la siguiente:

German owns zebra.