Sunteți pe pagina 1din 51

Treball de Fi de Grau

GRAU D'ENGINYERIA INFORMTICA

Facultat de Matemtiques
Universitat de Barcelona

PROGRAMACIN LGICA

Jordi A. Cardona Taltavull

Director: Juan Carlos Martnez Alonso


Realitzat a: Departament de Probabilitat,
lgica i estadstica. UB
Barcelona, 23 de gener de 2015
ndice general

1. INTRODUCCIN 4
1.1. Los computadores . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2. Los lenguajes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.1. El nacimiento de los lenguajes de programacin. . . . . . 7
1.2.2. El paradigma imperativo. . . . . . . . . . . . . . . . . . . 8
1.2.3. La orientacin a objetos . . . . . . . . . . . . . . . . . . 9
1.2.4. El paradigma declarativo. . . . . . . . . . . . . . . . . . . 9
1.2.5. El paradigma lgico. . . . . . . . . . . . . . . . . . . . . . 10

2. LGICA DE PRIMER ORDEN 13


2.1. Lenguajes de predicados . . . . . . . . . . . . . . . . . . . . . . . 13
2.2. Las interpretaciones. . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.3. Las equivalencias lgicas. . . . . . . . . . . . . . . . . . . . . . . 18
2.4. Mtodo de resolucin I. . . . . . . . . . . . . . . . . . . . . . . . 19
2.5. Algoritmo de unicacin. . . . . . . . . . . . . . . . . . . . . . . 22
2.6. Mtodo de resolucin II. . . . . . . . . . . . . . . . . . . . . . . . 24

3. EL LENGUAJE PROLOG 27
3.1. Introduccin. El Prolog y los lenguajes declarativos. . . . . . . . 27
3.2. Evolucin histrica del Prolog. . . . . . . . . . . . . . . . . . . . 28
3.3. Elementos bsicos de Prolog. . . . . . . . . . . . . . . . . . . . . 28
3.3.1. Los hechos. . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.3.2. Las preguntas. . . . . . . . . . . . . . . . . . . . . . . . . 29
3.3.3. Las reglas. . . . . . . . . . . . . . . . . . . . . . . . . . . 30
3.3.4. La sintaxis. . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.3.5. Las listas. . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.3.6. La unicacin. . . . . . . . . . . . . . . . . . . . . . . . . 32
3.3.7. Expresiones aritmticas. . . . . . . . . . . . . . . . . . . 32
3.4. El corte. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.5. El backtracking. . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
3.6. Mecanismo de ejecucin del PROLOG. . . . . . . . . . . . . . . . 35
3.7. Especicaciones tcnicas y otros. . . . . . . . . . . . . . . . . . . 43

2
NDICE GENERAL 3

4. EJERCICIOS RESUELTOS. 44
4.1. Predicados predenidos. . . . . . . . . . . . . . . . . . . . . . . . 44
4.1.1. not/1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
4.1.2. select/3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
4.1.3. permutation/2 . . . . . . . . . . . . . . . . . . . . . . . . 45
4.1.4. length/2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
4.1.5. append/3 . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
4.1.6. member/2 . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
4.1.7. write/1 y nl . . . . . . . . . . . . . . . . . . . . . . . . . 45
4.1.8. El predicado subcjto. . . . . . . . . . . . . . . . . . . . . . 45
4.1.9. El predicado nat. . . . . . . . . . . . . . . . . . . . . . . . 46
4.2. Fibonacci. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
4.3. Ordenacin. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
4.4. El jurado. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
4.5. El vendedor viajero. . . . . . . . . . . . . . . . . . . . . . . . . . 47
4.6. El problema de las ocho reinas. . . . . . . . . . . . . . . . . . . . 48
4.7. Problema de colorear un mapa. . . . . . . . . . . . . . . . . . . . 48
4.8. Resolver un sudoku . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Captulo 1

INTRODUCCIN

Este texto pretende recoger el trabajo de investigacin realizado en un campo


muy concreto de la programacin, la programacin lgica. Para ello centro mi
trabajo en el estudio de la lgica de primer orden y en un lenguaje especco
para este paradigma, el Prolog.
Escriba el Dr. Pea Mar en su libro De Euclides a Java 1 , sobre la historia
de la algoritmia: Esta historia comienza casi a la vez que la historia de la
humanidad. . . . Pero este estudio no va tan lejos. Dado que el objeto del trabajo
es la programacin (una parte de ella), tenemos que avanzar un poco. . .
El objetivo de este trabajo es ampliar los conocimientos recibidos en la asig-
natura de Lgica i llenguatges del Grado de Ingeniera informtica de la UB.
En cursos anteriores se haba dado ms materia, incluso llegando a dividirse en
dos asignaturas. Mi labor ha sido estudiar toda la materia que ya no se da, en
especial el estudio del lenguaje Prolog, e, incluso, ampliarla.
Quiero iniciar mi exposicin poniendo en contexto, tanto histrico como cien-
tco, todo sobre lo que voy a hablar en este trabajo. En este primer captulo
introductorio dar unas pinceladas histricas, empezando con lo ms necesa-
rio para que exista programacin, mquinas programables. Tambin dar un
contexto a nuestro paradigma de programacin, el lgico.
Seguir, en el captulo 2, con la lgica de primer orden, ahora s, en detalle.
Repasar los conceptos bsicos y ms caractersticos del lenguaje de predicados,
las interpretaciones en estos lenguajes, algunas equivalencias lgicas, y terminar
con el algoritmo de unicacin y el mtodo de resolucin especcos para los
lenguajes con paradigma declarativo, y en concreto, lgico.
En el captulo 3 veremos el lenguaje Prolog. Analizaremos su relacin con
los lenguajes declarativos y lgicos, su evolucin en la historia, su modo de
uso, sus elementos bsicos, y el modo en que unica los trminos. Asimismo,
estudiaremos como se tratan listas, se usan expresiones aritmticas, se usa el
corte, etc.

1 R. Pea Mar. De Euclides a Java: Historia de los algoritmos y de los lenguajes de


programacin. 1 edicin. Madrid: Nivola, 2006.

4
CAPTULO 1. INTRODUCCIN 5

Acabaremos, en el capitulo 4, con unos cuantos ejercicios resueltos que nos


servirn para ejemplicar toda la teora dada en este trabajo: tanto de lgica
de predicados, como de fundamentos del Prolog.

Introducci (en catal)


Aquest text pretn recollir el treball de recerca realitzat en un camp molt
concret de la programaci, la programaci lgica. Per aix, centro el meu treball
en l'estudi de la lgica de primer ordre i en un llenguatge especc per aquest
paradigma, el Prolog.
Escrivia el Dr. Pea Mar en el seu llibre De Euclides a Java, sobre la histria
de l'algortmica: aquesta histria comena quasi al mateix temps que la de la
humanitat. Per aquest estudi no va tant lluny. Com que l'objecte del treball es
la programaci (una part d'ella), hem d'avanar una mica...
L'objectiu d'aquest treball s ampliar els coneixements rebuts en l'assignatura
de Lgica i llenguatges del Grau d'Enginyeria informtica de la UB. En cursos
anteriors s'havia donat ms matria, ns i tot arribant a dividir-la en dues as-
signatures. La meva feina ha sigut estudiar tota la matria que ja no es dona,
en especial l'estudi del llenguatge Prolog, i, ns i tot, ampliar-la.
Vull comenar la meva exposici posant en context, tant histric com cien-
tc, tot sobre el que vaig a parlar en el treball. En aquest primer captol intro-
ductori donar unes pinzellades histriques, comenant per lo ms necessari per
a que existeixi programaci, mquines programables. Tamb donar un context
al nostre paradigma de programaci, el lgic.
Seguir, en el captol 2, amb la lgica de primer ordre, ara si, amb detall.
Repassar els conceptes bsics i ms caracterstics del llenguatge de predicats, les
interpretacions en aquests llenguatges, algunes equivalncies lgiques, i acabar,
amb l'algoritme d'unicaci i el mtode de resoluci especcs per els llenguatges
amb paradigma declaratiu, i en concret, lgic.
En el captol 3 veurem el llenguatge Prolog. Analitzarem la seva relaci amb
els llenguatges declaratius i lgics, la seva evoluci en la histria, el seu mode
d'us, els seus elements bsics, i el mode en que unica els termes. Aix mateix,
estudiarem com es tracten llistes, s'usen expressions aritmtiques, s'utilitza el
tall, etc.
Acabarem, en el captol 4, amb uns quants exercicis resolts que ens serviran
per a exemplicar tota la teoria donada en aquest treball: tant de lgica de
predicats, com de fonaments del Prolog.
CAPTULO 1. INTRODUCCIN 6

Introduction (in english)


This text aims to collect the research work done in a very specic eld of
programming, logic programming. Therefore, I have focused my work on the
study of rst-order logic and specic language for this paradigm: Prolog.
Dr. Pea Mar wrote in his book "De Euclides a Java", about the history of
algorithmics: This story begins almost at very same time that the history of
mankind.... But this study does not go that far. Since the purpose of the work
is programming -or rather, a part of it-, we must move forward in time a bit...
The aim of this work is to expand the knowledge received in the course of
"Logica i llenguatges, Grade Computer Engineering" at UB. In previous editions
more study material was dealt with, so that the course had to be divided in two
dierent matters. My work has consisted on studying all materials that are no
longer a topic within the course, extending them when necessary, namely the
study of Prolog language.
I want to start my presentation by putting, both in historical and scientic
context, everything connected with what I'm going to talk about in this work. In
this introductory chapter I will try to provide you with some historical details.
I will cite the most basic, necessary elements that make possible programming,
the programmable machines. I will give a context to our programming paradigm,
that is, logic programming.
In chapter 2 I will explain the rst-order logic, in full detail . I will review
the basic and most characteristic predicate language concepts, interpretations
in these languages and some logical equivalences. At the end we'll see the uni-
cation algorithm and the method of resolution especics for languages with
declarative paradigm, and more specically, the logical one.
In chapter 3 we will see the programming language Prolog. We will see its
relationship with the declarative and logic languages, its evolution throughout
history, the way we use it, its basic elements, and how it makes it possible to
unify terms. We'll see the way lists are dealt with, arithmetic expressions are
used, cut is used, etc.
We will nish in chapter 4 with a few solved exercises to exemplify all the the
information in this work, either related to predicate logic, or to fundamentals
of Prolog.
CAPTULO 1. INTRODUCCIN 7

1.1. Los computadores


Es ya a inicios del siglo XIX dnde se encuentra la primera mquina progra-
mable. Fue un telar, inventado por el ingeniero francs Joseph Marie Jacquard
(1752-1834), que haca mover sus hilos automticamente, en una cantidad y
orden preestablecidos.
Otro ejemplo de los primeros inventos progamables fue la tabla de diferencias
del matemtico Charles Babbage (1791-1817). Esta mquina estaba diseada
para evaluar polinomios de hasta grado 6 y, en esencia, era una mquina de
hacer sumas.
El siglo XX va a ver el nacimiento de los computadores electrnicos pro-
gramables tal y como los conocemos hoy. Este gran salto en la tecnologa fue
impulsado, bsicamente, por la necesidad de realizar clculos y la imposibilidad
de hacerlo de forma manual: la inquietud por conocer y hacer clculos sobre
la posicin de los astros, y especialmente de la luna o sobre el movimiento de
proyectiles militares.
Ser John von Neumann quien, en 1945, describir la arquitectura de un
computador, an vigente en la actualidad.
Durante los primeros aos, los computadores fueron diseados y construidos
en las universidades e instituciones pblicas. La primera comercializacin no se
produjo hasta el 1951, el UNIVAC (Universal Automatic Computer).
El resto de la historia de los computadores tiene ms relacin con la tec-
nologa que con nuevos avances conceptuales. Desde los aos 50 hasta ahora
sobre todo se ha aumentado la velocidad y la capacidad de memoria de los
ordenadores, a la vez que su precio y tamao han cado drsticamente, hacin-
dolos asequibles a un nmero cada vez mayor de empresas e instituciones, y
terminando por convertirse en aparatos de consumo domstico.

1.2. Los lenguajes.


1.2.1. El nacimiento de los lenguajes de programacin.
Con la comercializacin de los computadores comenzaba a abrirse paso la
idea de que el software era demasiado caro de producir. Requera ingenieros
muy cualicados y su trabajo progresaba lentamente, codicando instruccin
tras instruccin, hasta completar programas de varios miles de lneas. Adicio-
nalmente, consuman grandes cantidades de tiempo de computador, un recurso
muy caro en aquellos das, para poner a punto sus programas. Aproximada-
mente tres cuartas partes del tiempo de los ordenadores se usaban para crear
programas.
Se disearon notaciones de ms alto nivel que el lenguaje ensamblador para
problemas concretos, tales como el lenguaje Speedcode de John Backus, que
permita a los programadores usar la notacin cientca para nmeros en coma
otante, sin preocuparse de la representacin a nivel de lenguaje mquina. Esta-
ba claro que era necesario utilizar herramientas que generaran automticamente
CAPTULO 1. INTRODUCCIN 8

las instrucciones mquina a partir de notaciones de ms alto nivel.


Es en este ambiente donde se produce el desarrollo del primer lenguaje de
alto nivel, el FORTRAN (acrnimo de FORmula TRANslating system), por
un equipo de IBM liderado por John Backus. Gran parte del esfuerzo de este
grupo se destin a que el nuevo lenguaje no fuera signicativamente ms lento
que la codicacin manual porque entonces los programadores lo rechazaran.
El primer traductor de FORTRAN I estuvo disponible en abril de 1957.
El xito de FORTRAN abri el camino al desarrollo de nuevos lenguajes. El
ALGOL 58 (ALGOrithmic Language) fue creado por un comit de intelectos
en una reunin de ocho das. Fue aceptado como un conjunto de lneas maes-
tras alrededor de las cuales se podan denir distintos lenguajes. ALGOL 58
dejaba indeterminados los aspectos, tales como la entrada/salida. Algunos de
los lenguajes inspirados en ALGOL 58 fueron JOVIAL (System Development
Corporation), MAD (Universidad de Michigan) y NELLIAC (Naval Electronic
Laboratories).
El lenguaje COBOL, acrnimo de COmmon Business Oriented Language,
se gest tambin a nales de los 50. Responda a la necesidad de contar con un
lenguaje adaptado a la programacin de gestin, que se alejara de la apariencia
algebraica de los lenguajes numricos y que pusiera el nfasis en los aspectos de
descripcin de datos y de manipulacin de cheros.
Otro ejemplo es el LISP (LISt Processing language), apto para aplicaciones
de inteligencia articial.

1.2.2. El paradigma imperativo.


La programacin imperativa tiene un paradigama de programacin que des-
cribe la programacin en trminos del estado del programa y sentencias que
cambian dicho estado. Los programas imperativos son un conjunto de instruc-
ciones que le indican al computador cmo hacer una tarea.
Los lenguajes imperativos de alto nivel usan variables y sentencias ms com-
plejas, pero an siguen el mismo paradigma que antes con el lenguaje mquina,
dar instrucciones.
Asegurar la correccin de un programa y la imposibilidad de la comproba-
cin exhaustiva de las posibles soluciones llev a crear lo que se llama programa-
cin estructurada. Hoare dio en 1969 los axiomas lgicos de tres construcciones
sintcticas: la secuencial de dos instrucciones, la composicin condicional de
dos instrucciones y la composicin iterativa de una instruccin. Estos axiomas,
basados en la lgica de predicados de primer orden, establecan las reglas fun-
damentales para la vericacin matemtica de los programas. La vericacin
formal de programas se desarrolla notablemente durante la dcada de los 70,
impulsada sobre todo por E. W. Dijkstra.
El lenguaje expresamente diseado para reejar y ensear las ideas de la
programacin estructurada fue PASCAL, llamado as en honor a Blaise Pascal.
Tena la misma simplicidad de ALGOL, e inclua algunas construcciones nuevas:
registros, punteros, instruccin case, separacin de for y while en dos instruc-
ciones y algunas otras. PASCAL triunf inicialmente en el mbito universitario.
CAPTULO 1. INTRODUCCIN 9

El origen de C se sita a comienzos de los 70. All se haba desarrollado el


sistema operativo Unix. El primer compilador de C lo complet Dennis Ritchie
en 1973. El lenguaje fue evolucionando en los aos siguientes. En 1989, una
nueva versin del lenguaje fue estandarizada por la ANSI con el objetivo de
disponer de una referencia estable para la certicacin de compiladores. C ha
sido uno de los lenguajes ms utilizados de la historia.
En los 90 fue desplazado por un sucesor suyo, C++, que aada ms tipos,
orientacin a objetos, y mejor soporte a la modularidad. Recientemente, ambos
estn siendo desplazados por otro lenguaje, Java, que en muchos aspectos puede
considerarse un sucesor de ambos. En el siguiente captulo hablamos de estos
dos ltimos.

1.2.3. La orientacin a objetos


La programacin orientada a objetos es un paradigma de programacin que
usa los objetos en sus interacciones, para disear aplicaciones y programas in-
formticos. Est basado en varias tcnicas, incluyendo herencia, cohesin, abs-
traccin, polimorsmo, acoplamiento y encapsulamiento. Su uso se populariz
a principios de la dcada de los aos 90.
No son los primeros, pero si los mas conocidos, y usados, lenguajes de pro-
gramacin orientada a objetos en la actualidad: C++ y Java.
El desarrollo de C++ fue impulsado por Bjarne Stroustrup y se extiende
desde 1979 hasta 1992, si bien el primer compilador apareci en 1983. Se deseaba
extender C con clases y subclases, y mejorar la comprobacin esttica de tipos
de C para hacer ms seguro este lenguaje.
La dcada de los 90 ha visto nacer otro lenguaje orientado a objetos, Java,
que se ha extendido como la plvora y que ha reemplazado en muchas empresas
a C++. El xito de Java est ligado, en gran parte, a su asociacin con inter-
net. El lenguaje se ensea en la mayora de las universidades como lenguaje de
referencia del paradigma orientado a objetos y, en muchas de ellas, tambin se
emplea como lenguaje de introduccin a la programacin.

1.2.4. El paradigma declarativo.


La programacin declarativa es un paradigma de programacin que est ba-
sado en el desarrollo de programas especicando o declarando un conjunto de
condiciones, proposiciones, armaciones, restricciones, ecuaciones o transforma-
ciones que describen el problema y detallan su solucin. En la programacin
imperativa se describe paso a paso un conjunto de instrucciones que deben
ejecutarse para variar el estado del programa y hallar la solucin. En la pro-
gramacin declarativa, en cambio, las sentencias que se utilizan lo que hacen es
describir el problema que se quiere solucionar, pero no las instrucciones impera-
tivas necesarias para hacerlo. Por todo ello, los programas en PROLOG tienen
CAPTULO 1. INTRODUCCIN 10

menos detalles y son ms concisos, evitan controlar la secuencia de ejecucin


del programa.
No tenemos tampoco if , while, repeat, ni puntos y coma que expresan la
concatenacin de acciones. En un lenguaje declarativo no existen este tipo de
instrucciones. La repeticin de cmputo se suele expresar mediante recursin y la
eleccin entre varias alternativas se expresa de un modo ms abstracto. El punto
y coma, o su equivalente, estn ausentes. Se ha medido un factor de reduccin
entre cinco y diez en el nmero de lneas escritas al comparar la resolucin de
un mismo problema.
El precio a pagar por utilizar un paradigma declarativo es, en general, una
mayor ineciencia en el tiempo de ejecucin de programas y un mayor uso de
memria.
Existen varios tipos de lenguajes declarativos: lgicos como el Prolog (que
estudiaremos en el captulo tercero), algebraicos como Maude y SQL, y funcio-
nales, como Haskell y Erlang.

1.2.5. El paradigma lgico.


Histricamente, los ordenadores se han programado utilizando lenguajes muy
cercanos a las peculiaridades de la propia mquina: operaciones aritmticas sim-
ples, instrucciones de acceso a memoria, etc. Un programa escrito de esta manera
puede ocultar totalmente su propsito a la comprensin de un ser humano, in-
cluso uno entrenado. Hoy da, estos lenguajes pertenecientes al paradigma de
la Programacin imperativa han evolucionado de manera que ya no son tan
crpticos. En cambio, la lgica matemtica es la manera ms sencilla, para el in-
telecto humano, de expresar formalmente problemas complejos y de resolverlos
mediante la aplicacin de reglas, hiptesis y teoremas. De ah que el concepto
de "programacin lgica" resulte atractivo en diversos campos donde la progra-
macin tradicional no es tan til.
Un programa lgico consta de un conjunto de frmulas lgicas que expresan
propiedades satisfechas por un cierto problema. En el caso ms habitual estas
frmulas pertenecen a un subconjunto de la lgica de predicados de primer
orden, que veremos en el segundo captulo, conocido como clusulas de Horn
(B1 ... Bn A).
Ms adelante me extiendo tanto en la lgica de primer orden como en el
lenguaje PROLOG, especco de este paradigma. Vamos, las aplicaciones ms
importantes de este tipo de programacin.

Las bases de datos.


En este caso usamos la lgica para basar un tipo de sistema de bases de datos.
Los lenguajes de consulta de las bases de datos relacionales estn basados en la
lgica de predicados de primer orden, al igual que PROLOG.
Los datos, representados mediante tablas en las bases de datos relacionales,
se pueden representar en PROLOG mediante un conjunto de hechos.
CAPTULO 1. INTRODUCCIN 11

Las operaciones del lgebra relacional que permiten generar nuevas relacio-
nes a partir de las existentes pueden ser reproducidas fcilmente en PROLOG.
Veremos algn ejemplo en el apartado de PROLOG: la conjuncin, la negacin,
la clusula vaca, etc.

Las gramticas.
El trmino procesamiento del lenguaje natural se reere a una forma res-
tringida del lenguaje humano. El lenguaje usado por los humanos en su totalidad
es demasiado complicado y ambiguo para ser tratado por un ordenador. En el
caso de los humanos la ambigedad es resuelta por el contexto y por muchos
aos de experiencia.
Como PROLOG tiene su origen en la lgica, es el lenguaje de programacin
ms apropiado para el tratamiento del lenguaje natural. De hecho, PROLOG
fue diseado originalmente para traducir lenguaje natural.
Bsicamente la tarea de procesar el lenguaje natural consiste en las siguientes
tres fases:

1. Anlisis lxico.

2. Anlisis sintctico.

3. Anlisis semntico.

Un lenguaje puede verse como un conjunto (normalmente innito) de frases de


longitud nita. Cada frase est compuesta de smbolos de algn alfabeto, segn
una combinacin determinada para formar frases correctas. Para especicar c-
mo construir frases correctas en cualquier lenguaje se utiliza como formalismo
las gramticas, que constituyen un conjunto de reglas que denen la estructura
legal en un lenguaje.

Sistemas expertos.
Un sistema experto es un programa que se comporta como un experto para
algn dominio de aplicacin, normalmente reducido. Debe ser capaz de explicar
las decisiones que ha ido tomando y el razonamiento subyacente. Algunas veces
es interesante que los sistemas expertos manejen incertidumbre y conocimiento
incompleto.
Para el desarrollo de un sistema experto se distinguen tres mdulos: la base
de conocimiento, el motor de inferencia y la interfaz con el usuario. La base de
conocimiento contiene el conocimiento especco del dominio de la aplicacin, es
decir, un conjunto de hechos, un conjunto de reglas que denen relaciones en el
dominio, y mtodos, heursticos e ideas para resolver problemas en el dominio.
El motor de inferencia contiene los programas necesarios para manejar el co-
nocimiento de la base. La interfaz de usuario permitir una comunicacin fcil
y agradable entre el usuario y el sistema, proporcionando detalles del proceso
de resolucin del problema. El motor de inferencia y la interfaz de usuario se
pueden ver como un mdulo, que le llamaremos shell. Tericamente, el shell es
CAPTULO 1. INTRODUCCIN 12

independiente de la base de conocimiento. Sin embargo, para sistemas expertos


complejos, un mismo shell no funciona todo lo bien que sera deseable para dis-
tintas bases de conocimiento, a no ser que los dominios de las aplicaciones sean
muy similares. Aunque se necesiten algunas modicaciones en el shell cuando se
cambia de dominio, los principios del shell permanecen invariables para distintas
bases de conocimiento.
s un campo muy grande y an desarrollandose, para ms informacin sobre
el tema, consultar
2 y 3.

2 I. Bratko. Prolog Programmin for Articial Intelligence.


4 edicin. Boston, Massachu-

setts: Addison Wesley, 2011.


3 L. Sterling y E. Shapiro: The art of Prolog: Advanced Programming Techniques. 2 edicin.
Cambridge, Massachusetts: MIT press, 1994.
Captulo 2

LGICA DE PRIMER

ORDEN

2.1. Lenguajes de predicados


Denicin. Un predicado es una expresin formal cuyo tipo de datos es boo-
leano.

1. x+y =7
2. (x + y = 7) ( xy < z)

3. n Z tal que m {1, ..., k} , A[m] < n


(A[m] es la posicin m del vector A)

4. vaco(p) donde p es una pila (isempty)

Denicin. Un predicado es atmico si no puede descomponerse en predicados


mas simples. Los ejemplos anteriores 1 y 4 son atmicos.

Smbolos de los lenguajes de predicados


Variables: U, V, X, Y, Z, U0 , V0 , X0 , Y0 , Z0 , ..., Un , Vn , Xn , Yn , Zn , ...
Constantes: a, b, c, ..., a0 , b0 , c0 , ..., an , bn , cn , ...,
Operadores (funciones): f, g, h, f0 , g0 , h0 , ..., fn , gn , hn , ...
Smbolos de relacin: A, B, ..., Z, A0 , B0 , ..., Z0 , ..., An , Bn , ..., Zn , ...

Conectivos y cuanticadores: , , , , , ,
Auxiliares: parentesis y comillas( , ), ,

13
CAPTULO 2. LGICA DE PRIMER ORDEN 14

Observacin. Todo smbolo de operador y todo smbolo de relacin tiene aso-


ciado un entero positivo que es su aridad. Es el nmero de argumentos al que se
aplica. Por ejemplo pondremos fn si n es la aridad de f, y Rn si n es la aridad
de R.
Denicin. Un vocabulario es un conjunto de smbolos de constante, de ope-
rador, y de relacin.

Denicin. Si es un vocabulario, el conjunto de los -trminos es el conjunto


de elementos generados por las siguientes reglas:

1. Toda variables es un trmino

2. Todo smbolo de constante de es un trmino.

3. Si fn es un operador de de n argumentos y t1 , ..., tn son trminos,


entonces f (t, ..., tn ) es un trmino.

Ejemplo.

= c, f 2 , R1 V3 , c, f (V3 , c) son trminos
Ejemplo. f (V3 ) no es trmino.

Denicin. Un tomo (o una frmula atmica) es una expresin Rt1 , ..., tn


donde Rn y t1 , ..., tn son trminos.

Denicin. El lenguaje de las frmulas es el conjunto de elementos generados


por las siguientes reglas:

1. Todo tomo es una frmula.

2. Si es frmula, tambin lo es.

3. Si y son frmulas, entonces ( ) ,( ) ,( ) ,( )


tambin son frmulas.

4. Si es una frmula y x es una variable, entonces x y x tambin son


frmulas.

Reglas de formalizacin
Todo A es B

x(Ax Bx)

Ningn A es B

x(Ax Bx)

Algn A es B

x(Ax Bx)
CAPTULO 2. LGICA DE PRIMER ORDEN 15

Algn A no es B

x(Ax Bx)
Ejemplo. Todos los esquiadores aman la montaa.

x(Ex Ax)

Ejemplo. A ningn esquiador le gusta la lluvia.

x(Ex Gx)
Ejemplo. Hay personas imprudentes y poco sensatas.

x(P x Ix Sx)
Ejemplo. Cuando alguien se muere, todos sus familiares se aigen.

x(M x y(F xy Ay))


Ejemplo. Cuando una persona es honesta, sus amigos le aprecian.

x((P x Hx) y(Ayx Ryx))

Denicin. Una aparicin de una variable x en una frmula es una aparicin


libre si no est afectada por ningn cuanticador. En caso contrario es una
aparicin ligada.
Una variable x es una variable libre en una frmula si hay alguna aparicin
libre de x en . En caso contrario, x es una variable ligada en .

Ejemplo. En la frmula

x(Ryz y(P yx Ryz))

y es libre, z es libre y x es ligada.

Denicin. Una frmula cerrada es una frmula sin variables libres. El ejemplo
anterior no es cerrada.

Ejemplo. La frmula
x(yRxy yRyx)
es cerrada.
CAPTULO 2. LGICA DE PRIMER ORDEN 16

Notacin:
Si D es un conjunto no vaco y n 1, escribimos Dn = {(x1 , ..., xn ) \x1 , ..., xn D }
Un operador de n argumentos sobre D es un subconjunto de Dn .
Si R es una relacin de n argumentos, pondremos Rx1 , ..., xn , en lugar de
(x1 , ..., xn ) R.

2.2. Las interpretaciones.


Denicin. Si es un vocabulario, una - interpretacin I es una estructura
que consta de lo siguiente:

Un conjunto no vaco D al que llamaremos dominio de la interpretacin.

Una aplicacin tal que

A toda variable x le asigna un elemento I(x) D.


A todo smbolo de constante c en le asigna un elemento I(c) D.
A todo smbolo de operador f n
le asigna un operador de n
argumentos sobre D.
A todo smbolo de relacin Rn le asigna una relacin de n argu-
mentos sobre D.

Evaluacin de trminos y tomos en una interpretacin.


1. Se sustituye cada smbolo por su interpretacin.

2. Si la entrada es un trmino, el resultado es un elemento del dominio.

3. Si la entrada es una frmula, el resultado es un valor booleano.

Ejemplo. Con el vocabulario

= a, b, f 2 , g 2 P 2


denimos la interpretacin I por:


D = Z , I(a) = 1 , I(b) = 2, f = +, g = , I(xi ) = 3i, I(p) =nmeros
primos

1. t1 = f (x2 , x4 )I(t1 ) = I(f (x2 , x4 )) = I(x2 + x4 ) = I(x2 ) + I(x4 ) = 18


2. t2 = g(b, f (x2 , x4 ))I(t2 ) = I(b)I(f (x2 , x4 )) = 2 18 = 36

3. 1 = P f (x1 , b) I(1 ) = I(P (3 + 2)) = I(P (5)) = T rue


4. 2 = P g(a, f (x1 , x3 )) I(2 ) = I(P (1 (3 + 9))) = I(P (12)) = F alse
CAPTULO 2. LGICA DE PRIMER ORDEN 17

Evaluacin de una frmula en una interpretacin I


Se sustituyen los smbolos de constante, de operador, y de relacin que apa-
recen en por sus interpretaciones.
Una aparicin libre de una variable x en se sustituye por I(x) y una apa-
ricin ligada de x en se interpreta mediante los cuanticadores que le afectan,
tomando como dominio de los cuanticadores el dominio de la interpretacin I .

Ejemplo. Con el vocabulario

= a, f 2 , g 2 , P 2


denimos la interpretacinI por:


D = Z, I(f ) = +, I(g) = , I(P ) =0 <0 = (x, y) Z2 ; x < y , I(vi ) = 2i i


1. 1 = vP g(v1 , v7 )v Existe un entero z tal que 28 < z 


Existe un entero mayor que 28 I(1 ) = T rue
2. 2 = v0 v1 P (v0 , v1 )
Para todo entero z0 existe un entero z1 tal que z0 < z1 
Todo entero tiene enteros mas grandes I(2 ) = T rue
3. 3 = v0 v1 v2 (P v0 v2 P v2 v1 )
Para todo z0 y z1 enteros, existe un z2 tal que z0 < z2 y z2 < z1 
Para todo par de enteros existe un entero entre ellos I(2 ) = F alse

Notacin:
Si I es una -interpretacin, pondremos:

x = I(x) para toda variable x


s = I(s) para todo s
= I() para toda frmula .
Ejemplo. Con el vocabulario

= c, P 2 , Q2 , R2


denimos la interpretacin I por:


D = {1,
 2, 3, 4} , I(c) = c = 2, Q = {2, 3}, P = {1, 2}, R = {(1, 2), (2, 3), (3, 3)}
1, si i impar
xi =
2, si i par

1. 1 = P x0 Qx1 1 = P 2 Q1 = T F = F
2. 2 = Rx1 x2 Rx1 x3 2 = R12 R11 = V F = F
3. 3 = x0 Rcx0 n0 tal que Rcn0 = V n0 tal que R2n0 = V .
3 = V si n0 = 3 ( n0 = 1)
CAPTULO 2. LGICA DE PRIMER ORDEN 18

4. (4 = x0 P x0 Qx1 ) (n0 {1, 2, 3, 4} = D tal que P n0 = V


Q1 = V )
Como Q1 = F , entonces 4 = F

5. 5 = x0 x1 Rx0 x1 n0 1, 2, 3, 4, n1 1, 2, 3, 4 tal que n0 n1 R


5 = F si n0 = 4
6. 6 = x0 x1 Rx0 x1 6 = V si n0 = 4

Ejemplo. Con el vocabulario

= {a,f 1 ,P 1 ,Q2 }
denimos I por:

D = {0, 1} , a = 0 , f (0) = 1 , f (1) = 1, P (0) = F , P (1) = V ,

Q(0, 0) = V , Q(0, 1) = V , Q(1, 0) = F , Q(1, 1) = V , x = 0 x variable


3 = x0 Rcx0 n0 tal que Rcn0 = V n0 tal que R2n0 = V .
3 = V si n = 3 ( n = 1)
1. 1 = X(P X QXa) n {0, 1}\(P n = V ) (Qna = V )
Si n = 0 F V = F
Si n = 1 V F = F

Denicin. Una frmula se llama satisfactible si existe alguna interpretacin


que la hace cierta.
Una frmula se llama insatisfactible (contradiccin) si es falsa para toda
interpretacin.
Una forma se llama tautologia si es cierta para toda interpretacin.

Denicin. Una clusula de Horn es una implicacin lgica de la forma:

B1 ... Bn A

donde A y los Bi son predicados atmicos posiblemente con variables. Infor-


malmente, dicha clusula expresa que el predicado A es cierto siempre que lo
sean todos los predicados Bi .

2.3. Las equivalencias lgicas.


Denicin. Dos frmulas y son lgicamente equivalentes, notamos ,
si
CAPTULO 2. LGICA DE PRIMER ORDEN 19

I, I() = V I() = V
Tabla de equivalencias lgicas.
1.
( ) ( )
2.

3. ( ) ( )
( ) ( )
4. F
F F
V V
V

5.
( ) =
( ) =
( ) =

6. ( ) ( ) ( )
( ) ( ) ( )
7. xy yx
xy yx
8. x x
x x
9. x( ) x x
x( ) x x

Denicin. Si 1 , ..., n , son frmulas, decimos que es consecuencia lgica


de 1 , ..., n , si la frmula 1 ... n , es una tautologia. Entonces,
escribimos 1 , ..., n |= . Escribimos 1 |= 2 en lugar de {1 } |= 2 .

Denicin. Un demostrador es un programa que determina si una frmula es


una tautologia.

2.4. Mtodo de resolucin I.


Primero veremos el mtodo de resolucin en lgica de proposiciones.
CAPTULO 2. LGICA DE PRIMER ORDEN 20

Denicin. Llamaremos literal a un tomo o a la negacin de un tomo.


Una clusula es una disyuncin de literales (posiblemente vaca).
Denotamos por  a la clusula vaca. Como  es una disyuncin vaca, es
una frmula insatisfactible, y por consiguiente representa una contradiccin.

Denicin. Dadas dos clusulas proposicionales 1 , 2 , si existe un literal 1


en 1 que es complementario de un literal 2 en 2 , entonces se suprimen 1 , 2
y se toma la disyuncin de las clusulas resultantes. A la frmula as construida
se le llama resolvente de 1 , 2 .

Regla de resolucin.

1
2

1 , 2 clusulas y
Entradas, salida,
un resolvente de 1 , 2 .
Si 1 ,n , son clusulas, escribiremos. 1 , . . . , n `R si existe una
... ,
demostracin de , tomando a 1 ,..., n como premisas, utilizando nicamente
la regla de resolucin.

Denicin. Una frmula est en forma normal conjuntiva (FNC), si es


una conjuncin de clusulas.

Teorema (de Resolucin Bsico ). (Lgica de proposiciones) Sean 1 , ... , n ,


frmulas de un lenguaje de proposiciones. Sea 1 . . .n una forma normal
conjuntiva de 1 ... n . Entonces,
1 , . . . , n |= si y slo si {1 , . . . , n } `R  .
Por consiguiente, el mtodo de resolucin sirve para validar razonamientos
concretos. El algoritmo que se obtiene a partir del Teorema de Resolucin Bsico
funcina de la siguiente forma. Si 1 , ... , n son las premisas de un razonamiento
y es su conclusin, el algoritmo calcula en primer lugar una forma normal
conjuntiva 1 . . .n de la frmula 1 ...n . Y a continuacin, aplicara
la regla de resolucin, partiendo de las premisas , . . . , n , hasta obtener la
clusula vaca .

Denicin. Una frmula esta en forma normal prenexa (FNP), si es de la


forma Q1 x1 ....Qm xm donde Q1 , ..., Qm son cuanticadores y es una frmula
en la que no aparece ningn cuanticador. Diremos entonces que Q1 x1 ....Qm xm
es el prejo de y es el ncleo de .
Cualquier frmula puede ser transformada en una frmula en forma normal
prenexa. Para ello, se ha de seguir el siguiente algoritmo:

1. Aplicar las reglas:



( )
( ) ( )
CAPTULO 2. LGICA DE PRIMER ORDEN 21

2. Aplicar las reglas:



( ) =
( ) =
x x
x x

3. Renombrar las variables cuanticadas que sea necesario.

4. Llevar los cuanticadores a la izquierda.

Denicin. Decimos que una frmula est en forma normal de Skolem


(FNS), si est en forma normal prenexa, el ncleo de est en forma normal
conjuntiva y el prejo de no tiene ningn cuanticador existencial.
Las formas normales de Skolem son las que se utilizan en el mtodo de
resolucin para la lgica de predicados.
Para encontrar una forma normal de Skolem de una frmula , se ha de
seguir el siguiente algoritmo:

1. Obtener una forma normal prenexa de .

2. Poner el ncleo de la frmula obtenida en (1) en forma normal conjuntiva.

3. Eliminar los cuanticadores existenciales en la frmula obtenida en (2).

Acabamos de ver un algoritmo para efectuar la etapa (1). Para efectuar la etapa
(2) es suciente con aplicar las equivalencias bsicas para frmulas sin cuanti-
cadores. Y para efectuar la etapa (3) se procede de la siguiente manera. Sea
la frmula obtenida en (2). Entonces, si una cuanticacin existencial x del
prejo de no est precedida por ninguna cuanticacin universal, se sustituye
toda aparicin de x en el ncleo de por un nuevo smbolo de constante y se
elimina dicha cuanticacin existencial del prejo de . Y si una cuanticacin
existencial z del prejo de est precedida por n cuanticadores universales
x1 , ..., xn , entonces se toma un nuevo smbolo de funcin f de n argumen-
tos, se sustituye toda aparicin de z en el ncleo de por el trmino f (x1 , ..., xn )
y se elimina la cuanticacin existencial z del prejo de .

Ejemplo. Consideremos la siguiente frmula:

= uvxyw(P uxv Qywu)


CAPTULO 2. LGICA DE PRIMER ORDEN 22

Cambiamos x por f (u, v) ya que antes del cuanticador existencial de x, hay


dos cuanticadores universales, de u y de v . Lo mismo para w que lo cambiamos
por g(u, v, y). Entonces, nos queda:

sk = uvy(P uf (u, v)v Qyg(u, v, y)u)

En general, una forma normal de Skolen de una frmula no es lgicamente


equivalente a . Sin embargo, se puede demostrar que si es una forma normal
de Skolem de una frmula , entonces es insatisfactible si y slo si es in-
satisfactible. Este resultado simplica el proceso para validar razonamientos en
lgica de predicados. Si queremos demostrar que la conclusin de un razona-
miento es consecuencia de sus premisas 1 , ..., n , tendremos que probar que la
frmula (1 ... n ) es una tautologa, lo cual es equivalente a demostrar
que la frmula 1 ... n es insatisfactible. Pero por el resultado que
acabamos de mencionar, esto ltimo es equivalente a demostrar que una forma
normal de Skolem de 1 ... n es insatisfactible, lo cual es ms fcil de
demostrar por no aparecer cuanticadores existenciales en las formas de Skolem,
y ser por tanto frmulas ms simples.
Nuestro objetivo ahora es denir la nocin de resolvente para la lgica de
predicados. Las nociones de literal y clusula se denen como en lgica de propo-
siciones. Representamos por  a la clusula vaca. Para poder denir la nocin
de resolvente de dos clusulas necesitamos un criterio para poder emparejar fr-
mulas atmicas. Dicho criterio queda establecido por el llamado algoritmo de
unicacin, que veremos a continuacin.

Denicin. Llamaremos expresin a un trmino o a un literal. Un trmino es


compuesto si no es ni una constante ni una variable. Si t = f (t1 , ..., tn) es un
trmino compuesto, diremos que f es el funtor de t. Y si = Rt1 ...tn es un
tomo, diremos que R es el smbolo de predicado de .

2.5. Algoritmo de unicacin.


Entrada: dos expresiones e1 y e2 .
Salida: un unicador de {e1 , e2 } o fallo.
Variables utilizadas: pila p, vector inicializada vaca [ ], variable booleana
b inicializada f alse.
Se pone en la pila e1 = e2 (p.push(e1 = e2 )) .

Mientras (while) p no est vaco (p.empty == f alse) y b == f alse.


Sacar la igualdad e = e0 de la cima de p.

Si e es una variable que no aparece en e0 , sustituir e por e0 en los


0
elementos de p y de , y aadir la ecuacin e=e a .
Si e0 es una variable que no aparece en e, sustituir e0 por e en los
0
elementos de p y de , y aadir la ecuacin e =e a .
CAPTULO 2. LGICA DE PRIMER ORDEN 23

Si e0 , e son constantes, o variables, idnticas, continuar.

Sie = f (t1 , ..., tn ) y e0 = f (s1 ...sn ) para algun operador f y algn


n > 0, se pone en p las ecuaciones t = sn , ..., t1 = s1 .
Si e = Rt1 ...tn y e0 = Rs1 ...sn para algun smbolo de predicado R y
algn n > 0, entonces poner en p las ecuaciones tn = sn , ..., t1 = s1 .

En otro caso, b = true.

Si b == f alse, salida = . Si no, salida = fallo.

Una sustitucin es un conjunto {t1 = X1 , ..., tn = Xn } donde X1 , ..., Xn son


variables distintas dos a dos y t1 , ..., tn son trminos. Si es una estructura y
= {t1 = X1 , ..., tn = Xn } es una sustitucin, denotamos por a la expresin
que resulta de sustituir en toda aparicin de xi por ti (i = 1, ..., n). Y si W es
un conjunto de estructuras y es una sustitucin, escribimos W = { :
W }.
Si W es un conjunto nito de estructuras y es una sustitucin, diremos
que es un unif icador de W si el conjunto W tiene exactamente un elemento.
Y diremos que un conjunto nito de estructuras W es unif icable si W tiene un
unicador. El algoritmo de unicacin visto anteriormente recibe como entrada
un conjunto nito W de estructuras, y determina entonces si el conjunto W es
unicable.
Si es una clusula y = {t1 = X1 , ..., tn = Xn } es una sustitucin,
denotamos por a la expresin que resulta de sustituir en toda aparicin
de xi por ti (i = 1, ..., n). Diremos que una sustitucin {t1 = X1 , ..., tn = X}
es simple, si t1 , ..., tn son variables. Utilizaremos las sustituciones simples para
renombrar las variables de una clusula.

Ejemplo 1: Unicable.
Entradas: e1 = hcXf (f (Y )) y e2 = hZf (Z)f (U )
Inicialmente: p = [hcXf (f (Y )) = hZf (Z)f (U )], = [ ] y b = f alse
Empezamos el bucle:

1. Sacamos la cabeza de la pila y aadimos las partes que deben unicar


p = [c = Z, X = f (Z), f (g(Y )) = f (U )].
2. Sacamos la cabeza de la pila, c = Z , y, como Z no est en c, sustituimos
en p y las Z por c y aadimos la ecuacin a la lista p = [X =
f (c), f (g(Y )) = f (U )], = [Z = c].
3. Sacamos X = f (c), como X no est en f (c), sustituimos X por f (c) y
aadimos la ecuacin a p = [f (g(Y )) = f (U )], = [Z = c, X = f (c)].
4. Sacamos f (g(Y )) = f (U ), ahora tienen que unicar g(Y ) y U , lo aadimos
a la pila, no cambia p = [g(Y ) = U ], = [Z = c, X = f (c)].
5. Sacamos g(Y ) = U , como U) no est en g(Y ), sutituimos en p y , U por
g(Y ) y aadimos la ecuacin p = [ ], = [Z = c, X = f (c), U = g(Y )].
CAPTULO 2. LGICA DE PRIMER ORDEN 24

6. Como la pila est vaca salimos del bucle con la b aun f alse. Por lo tanto,
salida = .

Ejemplo 2: No unicable.
Entradas: e1 = h(f (a), g(X)) y e2 = h(Y, Y ).
Inicialmente: p = [h(f (a), g(X)) = h(Y, Y )], = [ ] y b = f alse
Empezamos el bucle:

1. Sacamos de la pila h(f (a), g(X)) = h(Y, Y ), ahora tienen que unicar f (a)
con Y y g(X) con Y , lo aadimos a la pila y no cambia p = [f (a) =
Y, g(X) = Y ].

2. Sacamos de la pila f (a) = Y , como Y no est en f (a), sustituimos en p


y en las Y por f (a) y aadimos la ecuacin a p = [g(X) = f (a)],
= [f (a) = Y ]
3. Sacamos de la pila g(X) = f (a), como son distintos operadores f y g no
pueden unicar b = true y salimos del bucle. Salida = fallo.

2.6. Mtodo de resolucin II.


Ahora veremos el mtodo de resolucin en lenguaje de predicados

Denicin de resolvente.
Sean 1 , 2 clusulas de un lenguaje de predicados. Tomamos sustituciones
simples 1 , 2 tales que 1 1 , 2 2 no tengan ninguna variable en comn. Pa-
ra obtener un resolvente de 1 , 2 se sigue entonces uno de los dos siguientes
procesos:

Se busca un tomo 1 en 1 1 y un literal 2 en 2 2 tales que el conjun-


to {1 , 2 } es unicable, se borran 1 , 2 de 1 1 , 2 2 respectivamente,
se construye la disyuncin de las dos clusulas resultantes y se aplica a
dicha disyuncin el unicador del conjunto {1 , 2 } obtenido mediante el
algoritmo de unicacin.

Se busca un literal 1 en 1 1 y un tomo en 2 2 tales que el


conjunto {1 , 2 } es unicable, se borran 1 , 2 de 1 1 , 2 2 respec-
tivamente, se construye la disyuncin de las dos clusulas resultantes y
se aplica a dicha disyuncin el unicador del conjunto {1 , 2 } obtenido
mediante el algoritmo de unicacin.

Ejemplo. Consideremos las clusulas siguientes:


CAPTULO 2. LGICA DE PRIMER ORDEN 25

1 = P f (Y ) Rg(Y )

2 = P f (g(a)) Qb
Siguiendo el proceso descrito anteriormente tenemos que,

Rg(g(a)) Qb

es un resolvente de 1 ,2 .

Regla de resolucin.

1
2

Entradas, 1 , 2 clusulas y salida, un resolvente de 1 , 2 .
En las demostraciones por resolucin, adems de utilizar la regla de resolu-
cin que acabamos de ver, se utiliza otra regla para simplicar las clusulas que
intervienen en dichas demostraciones.
Diremos que un miembro de de una clusula signo positivo, si
tiene
es un tomo. En caso contrario, diremos que tiene signo negativo. Si dos o
ms miembros con el mismo signo de una clusula son unicables y es un
unicador de dichos miembros obtenido mediante el algoritmo de unicacin,
diremos que es un f actor de .

Regla de simplicacin.

1
0
0
Entrada, clusula y salida, un factor de
.
Si1 , ... , n , son clusulas de un lenguaje de predicados, escribiremos.
1 , . . . , n `R si existe una demostracin de , tomando a 1 , ... , n como
premisas, utilizando nicamente las reglas de resolucin y simplicacin.
Recordemos que una frmula es cerrada, si no tiene ninguna variable libre.
Si 0 es una forma normal de Skolem de una frmula , denotamos por sk(0 )
0
al conjunto de smbolos de constante y smbolos de funcin que aparecen en
0
pero no en . Es decir, sk( ) es el conjunto de smbolos que tenemos que aadir
0
para construir la forma normal de Skolem .

Teorema de Resolucin.
Sean 1 , ... , n , frmulas cerradas de un lenguaje de predicados. Sean
01 , ... , 0n , 0 formas normales de Skolem de 1 , ... , n , respectivamente
CAPTULO 2. LGICA DE PRIMER ORDEN 26

tales que sk(01 ), ... , sk(0n ), sk(0 ) son conjuntos disjuntos dos a dos. Sean
1 , ..., k las clusulas que aparecen en los ncleos de 01 , ... , 0n , 0 . Entonces,

{1 , ..., n } |= si y slo si {1 , ..., k } `R 

Por consiguiente, el mtodo de resolucin sirve para validar razonamientos


correctos en lgica de predicados. El algoritmo que se obtiene a partir del Teo-
rema de Resolucin funciona de la siguiente forma. Si 1 , ..., n son las premisas
de un razonamiento y es su conclusin, el algoritmo calcula en primer lugar
formas normales de Skolem 01 , ... , 0n , 0 de 1 , ..., n , respectivamente ta-
0 0 0
les que sk(1 ), ... , sk(n ), sk( ) son conjuntos disjuntos dos a dos. Entonces,
0
el algoritmo extrae las clusulas 1 , ..., k que aparecen en los ncleos de 1 ,
0 0
... , n , . Y a continuacin, aplicar las reglas de resolucin y simplicacin,
partiendo de las premisas 1 , ..., k hasta obtener . Obsrvese que si el razo-
namiento es correcto, por el Teorema de Resolucin, el algoritmo encontrar la
clusula vaca.
El mtodo de resolucin a que da lugar el Teorema de Resolucin es el llama-
do mtodo general de resolucin. El interpretador de PROLOG est basado en
un renamiento del mtodo general de resolucin, a travs del cual el interpre-
tador es capaz de realizar inferencias lgicas y simular razonamiento. Por este
motivo, el lenguaje PROLOG tiene un notable inters en la programacin para
la Inteligencia Articial.
Podemos encontrar una demostracin del Teorema de resolucion en
1 , pero
no he visto la necesidad de incluirlo en este trabajo por querer centrarme en el
Prolog y la parte prctica de los lenguajes lgicos con ejemplos.

1 U.Schning. Logic for computer scientists. 1 edicin. Boston, Massachusetts: Birkhuser,

1989.
Captulo 3

EL LENGUAJE PROLOG

3.1. Introduccin. El Prolog y los lenguajes de-


clarativos.
PROLOG es un lenguaje de programacin declarativo, es decir que estn
basado en formalismos abstractos, y por tanto su semntica no depende de la
mquina en la que se ejecuta. Las sentencias en los lenguajes declarativos se
entienden sin necesidad de hacer referencia al nivel mquina. Un programa es-
crito en un lenguaje declarativo, por tanto, es, en s mismo una descripcin
formal de la resolucin de un programa. Otra ventaja de los programas escri-
tos en lenguajes declarativos es que pueden ser sintetizados o transformados
sistemticamente.
PROLOG es un lenguaje de programacin muy til para resolver problemas
que implican objetos y relaciones entre objetos. Est basado en los mecanismos
bsicos que se han explicado a lo largo del captulo 2 de este trabajo, as como
en el algoritmo de unicacin, las estructuras de datos basadas en rboles, y el
backtracking automtico, que veremos ms adelante.
PROLOG tiene una sintaxis que consiste en declarar hechos, hacer preguntas
y denir reglas sobre objetos y sus relaciones. Se detallan estos aspectos del
lenguaje en los apartados 3.3.1, 3.3.2, y 3.3.3 de ste captulo.
PROLOG se puede ver como una extensin de la programacin lgica pura,
en el sentido de que, adems de permitir programar de acuerdo con el paradigma
de la programacin lgica, incorpora una serie de elementos adicionales cuyo
objetivo es ofrecer una herramienta de programacin que sea til en la prctica.
Se puede encontrar ms informacin y ms extensa en
1 y 2.

1 R. Farr, R. Nieuwanhuis, P. Nivela, A.Oliveras, E. Rodrguez y J. Sierra. Lgica para


informticos. 1 edicin. Barcelona: Marcombo
2 W.Clocksin y C.S.Mellish. Programming in Prolog. 5 edicin. Berlin: Springer-Verlag,

2003.

27
CAPTULO 3. EL LENGUAJE PROLOG 28

3.2. Evolucin histrica del Prolog.


El PROLOG, del francs PROgrammation en LOGique fue el primer len-
guaje basado en el paradigma de la programacin lgica.
Fue ideado a principios de los aos 70 en la Universidad de Marsella (Francia)
por los estudiantes Alain Colmerauer y Philippe Rousel. Otros estudiantes como
Robert Pasero, Jean Trudel, o Robert Kowalski participaron en el proyecto. ste
ltimo aport sus resultados tericos que dieron forma a la primera versin
preliminar del Prolog a nales de 1971. La versin denitiva apareci en 1972.
Los primeros aos de vida, el Prolog fue de uso reducido, hasta que, en 1983,
David H.D.Warren desarroll un compilador capaz de traducir Prolog en un con-
junto de instrucciones de una mquina abstracta denominada Warren Abstract
Machine (WAM). Desde entonces Prolog es un lenguaje semi-interpretado. Ini-
cialmente el uso de ste lenguaje era reducido, hasta que a lo largo de la dcada
de 1980 se populariz por diferentes motivos, sobretodo la aparicin de intr-
pretes para microordenadores y para ordenadores domsticos.
En 1995 se normaliza el lenguaje con el correspondiente estndar ISO. Lo que
diferencia el Prolog de otros lenguajes ms populares como Fortran, Pascal, C o
Java s que se enmarca en el paradigma de los lenguajes lgicos y declarativos.
Es bastante conocido en el rea de la ingeniera informtica para investiga-
cin en inteligencia articial, as como en otros campos de la informtica. Se
ha convertido en una herramienta de desarrollo de software prctica y de gran
aceptacin para la que se dispone de mltiples compiladores, tanto comerciales
como de libre distribucin.

3.3. Elementos bsicos de Prolog.


Un programa lgico es un conjunto nito de frmulas lgicas de predicados
que reejan el conocimiento del que se dispone acerca del problema a resolver.
Por lo tanto, un programa en Prolog estar formado por una serie de frmulas
lgicas que, evidentemente, tendrn que adaptarse a la sintaxis especca del
lenguaje.
A continuacin, veremos las clusulas de Prolog, que son de tres tipos: he-
chos, preguntas y reglas. Los hechos y las reglas forman la base de datos del
programa; las preguntas se le hacen a ste para determinar qu cosas son ciertas.
Finalmente, entraremos, sin mucho detalle, a estudiar la sintaxis de este
lenguaje de programacin.

3.3.1. Los hechos.


Los hechos o clusulas, juntamente con un conjunto de reglas, forman la
base de datos con la que se resolver el problema en cuestin. Se componen de
atributos de un objeto o relaciones entre objetos. Por ejemplo:

valioso(oro).
CAPTULO 3. EL LENGUAJE PROLOG 29

progenitor(laura, damian).
Las relaciones son valioso y progenitor. Los argumentos son oro, laura,
y damian. Los hechos acaban siempre con un punto. De estos hechos podemos
interpretar que el oro es valioso o que Laura es la madre de Damian. Aunque
tambin podra ser Damian el padre de Laura, el orden lo establece el progra-
mador, es arbitrario. Los nombres tambin son arbitrarios, y el programador
decidir la interpretacin que se haga de ellos.
Los hechos no tienen que reejar, necesariamente, el mundo real, pero ser
nica y exclusivamente lo que Prolog tomar como verdadero (no tiene ms
informacin que la que le demos en los hechos).

3.3.2. Las preguntas.


Sobre un conjunto de hechos se pueden realizar una serie de preguntas. Por
ejemplo:

? progenitor(laura, damian).
PROLOG busca automticamente en la base de datos si existe un hecho que
se puede unicar (es decir, tiene el mismo nombre de relacin, el mismo nmero
de argumentos, y estos coinciden uno a uno) con el hecho que aparece en la
respuesta.
Observemos que una respuesta negativa a la pregunta no implica necesaria-
mente que el hecho sea falso, sino que no se puede probar (en general) que sea
verdadero con el conocimiento almacenado en la base de datos.
Se pueden realizar preguntas ms interesantes, como por ejemplo:

? progenitor(X, damian).
PROLOG, entonces, buscar en la base de datos cual podra ser el valor de la
variable X para que la pregunta sea armativa. La respuesta a la pregunta ser
negativa si no encuentra resultados, o el primer resultado encontrado. Pulsando
RETURN saldremos de la pregunta. Si antes escribimos ; y entonces puslamos
RETURN, nos ir dando, mientras existan, todas las respuestas que encuentre
en la base de datos.
En PROLOG disponemos tambin de la conjuncin de clusulas. La forma
de ponerlas es separndolas con una coma. Por ejemplo:

? progenitor(X, ana), progenitor(X, damian).


En este caso la respuesta ser armativa si lo son ambas preguntas. Pero aqu
aadimos la dicultad de que el progenitor encontrado para Ana y el encontrado
para Damin debern ser el mismo. El resultado, como antes, sern las personas
que sean a la vez padres de Ana i Damin. Otro ejemplo:

? progenitor(clara, X), progenitor(X, jaime).


CAPTULO 3. EL LENGUAJE PROLOG 30

El resultado de esta pregunta ser armativa si Clara es, efectivamente,


la abuela de Jaime. Y en ese caso, la respuesta ser X=Maria, por ejemplo,
suponiendo que Maria es la hija de Clara y madre de Jaime.

3.3.3. Las reglas.


Podriamos decir que una regla es un hecho compuesto por uno o mas hechos.
Por ejemplo, teniendo la relacin progenitor podramos crear las reglas tio y
abuelo, como se muestra a continuacin:

abuelo(X, Y ) : progenitor(X, Z), progenitor(Z, Y ).

tio(X, Y ) : progenitor(Z, Y ), progenitor(V, Z), progenitor(V, X), X| = Z.


El primer caso ya lo hemos visto antes, simplemente, ahora, podemos usar la
regla abuelo como si fuera una relacin. En el segundo caso, la resolucin nos
dar personas X, Y, Z, y V tales que Z sea padre de Y, V sea padre de Z y V
sea padre de X. Con lo que buscaremos, en denitiva, dos personas X y Z con
el mismo padre V y tal que Z sea el padre de Y. Entonces X es su to.
La gran potencia del Prolog, sin embargo, est en la denicin de reglas
recursivas que resuelven problemas como el que sigue:
Dadas denidas las reglas progenitor, abuelo, bisabuelo, tatarabuelo,
etc. Podemos denir la relacin predecesor. Por ejemplo, predecesor(X,Y) se
cumplir si X es padre, abuelo, bisabuelo, etc. Necesitaremos un conjunto de
reglas como:

predecesor(X, Y ) : progenitor(X, Y ).

predecesor(X, Y ) : progenitor(X, Z), progenitor(Z, Y ).

predecesor(X, Y ) : progenitor(X, Z), progenitor(Z, V ).

progenitor(V, Y ).
La denicin de varias reglas con el mismo nombre de relacin equivale en
Prolog a la disyuncin lgica. Pero la denicin de este conjunto de reglas es in-
nito para resolver este ejercicio, nunca terminaramos de escribirlo. Necesitamos
de una regla recursiva:

predecesor(X, Y ) : progenitor(X, Y ).

predecesor(X, Y ) : progenitor(X, Z), predecesor(Z, Y ).


Aqu resolvemos el problema innito con una recursin. X ser predecesor de y
si es su progenitor, o bien, si es progenitor de otro predecesor de Y.
CAPTULO 3. EL LENGUAJE PROLOG 31

3.3.4. La sintaxis.
Primero de todo, veamos cuales son los tipos de objetos que trata un pro-
grama en Prolog.
Un tomo es el objeto ms simple y se denota empezando su identicador con
una letra minscula. Los tomos, junto a los nmeros (normalmente naturales
o enteros) forman las constantes.
Por otro lado tenemos las variables que pueden ser normales, las que hemos
visto hasta ahora, o la variable annima. La variable annima se representa por
 _ y da a entender al programa que el valor que tome no es importante o que
es una variable que no unica con otra variable en la denicin. Por ejemplo:

tiene_un_hijo(X) : progenitor(X, Y ).
En este caso preguntamos si X tiene hijos, por lo que no interesa el nombre
de los hijos, solamente si los hay. Utilizaramos la variable annima _ en lugar
de la Y.
Las variables y las constantes son todos los posibles objetos simples. Los
dems objetos sern estructuras que relacionen algunas de las anteriores.

3.3.5. Las listas.


La lista es una estructura de datos simple, muy usada en la programacin no
numrica. La teora sobre las listas en Prolog podra ser muy larga, por lo que
intentar resumirla con unos cuantos ejemplos que ejempliquen la importancia
en su uso para el lenguaje.
La sintaxis para la listas consiste en englobar secuencias de elementos entre
corchetes.

[a, b, c, d, e]
La representacin interna es con rboles binarios, donde la rama de la iz-
quierda es el primer elemento (cabeza) y la derecha es el resto(cola). La cola,
a su vez, est compuesta por cabeza y cola, y as sucesivamente, tal y como se
muestra en la gura de la derecha.
La cabeza y la cola de una lista se pueden separar con el smbolo |. Por
ejemplo, son equivalentes:

[a, b, c] [a|[b, c]] [a, b|[c]] [a, b, c|[]]

Es importante saber que el orden de los elementos de una lista en Prolog s


importa y que un elemento se puede repetir en una misma lista. Solucionemos,
a continuacin, algunos problemas con listas.

Ejemplo. Una relacin miembro(X,L) que resolver cierta si X es un elemento


de L.
miembro(b, [a, b, c]).
miembro(b, [a, [b, c]]).
CAPTULO 3. EL LENGUAJE PROLOG 32

miembro([b, c], [a, [b, c]]).


En el siguiente caso, el elemento ser miembro de la lista si coincide con la
cabeza de la lista, o bien ser miembro de la misma lista sin el primer elemento.

miembro(X, [X|_]).

miembro(X, [_|R]) : miembro(X, R).


Hemos programado la relacin miembro de una lista, tan comn en otros len-
guajes, de manera recursiva.

Ejemplo. Concatenar dos listas.

concatenar([a, b, c], [d, e], [a, b, c, d, e]).

concatenar([a, b], [1, 2, 3], X).


Esta ltima lnea concatenaria las dos listas y lo pondra en X.

concatenar([], L, L).

concatenar([X|L1], L2, [X|L3]) : concatenar(L1, L2, L3).

3.3.6. La unicacin.
La operacin ms importante sobre trminos es la unicacin. Dos trminos
pueden unicarse si son idnticos o las variables de ambos trminos pueden
instanciarse a objetos tales que, despu de la sustitucin de las variables por
esos objetos, los trminos sean idnticos. Por ejemplo:

f echa(D, M, 2015) = f echa(D1, mayo, A).

Se unicaran si D y D1 pueden instanciarse con el mismo valor y si M se


puede instanciar con el valor mayo y A con el valor 2015.
Si [X|L] es una lista de Prolog, el interpretador considera a [X|L] como una
funcin cuyo primer argumento es X, y cuyo segundo argumento es L.
Las variables instanciadas son consieradas como constantes por el interpre-
tador.

3.3.7. Expresiones aritmticas.


Hay algunas expresiones aritmticas y de comparacin de trminos y expre-
siones, ya predenidas en Prolog:
X+Y /*suma*/
X-Y /*resta*/
X*Y /*multiplicacin*/
X/Y X div Y /*divisin real y entera*/
CAPTULO 3. EL LENGUAJE PROLOG 33

X mod Y /*resto de la divisin de X entre Y*/


X^Y /*X elevado a Y*/
-X /*negacin*/
abs(X) /*valor absoluto de X*/
acos(X) /*arco coseno de X*/
asen(X) /*arco seno de X*/
atan(X) /*arco tangente de X*/
cos(X) /*coseno de X*/
exp(X) /*exponencial de X*/
ln(X) /*logaritmo neperiano de X*/
log(X) /*logaritmo en base 2 de X*/
sin(X) /*seno de X*/
sqrt(X) /*raz cuadrada de X*/
tan(X) /*tangente de X*/
round(X,N) /*redondeo del real X con N decimales*/
X<Y /*X es menor que Y*/
X>Y /*X es mayor que Y*/
X=<Y /*X es menos o igual que Y*/
X>=Y /*X es mayor o igual que Y*/
X=Y /*X unica con Y*/
X\=Y /X no unica con Y*/
X==Y /*la expresin X es igual que la expresin Y, identidad*/
X\==Y /*la expresin X es distinta que la expresin Y*/
X=:=Y /*Igualdad aritmtica*/
X=|=Y/*No igualdad aritmtica*/

Adems, el siguiente operador permite evaluar expresiones aritmticas:

V is E
Siendo V una variable y E una expresin. Si la expresin E es evaluable, se
unica su resultado con V , si no, fallo. Si V no est instanciada, se le asignar
el del resultado de E; si lo est, slo se compararan ambos valores.
Veremos algunos ejemplos en el captulo 4 de ejercicios resueltos en Prolog.

3.4. El corte.
El corte es un predicado predenido, cuya sintaxis es ! y cuyo comporta-
miento es el siguiente. Supongamos denido el predicado a con las siguientes
clusulas:
a : b, !, c.
En el caso de que b sea falso, ya no se comprobar si lo es c. El corte acta
como barrera para no hacer comprobaciones innecesarias.
CAPTULO 3. EL LENGUAJE PROLOG 34

Pero hay otros usos para el corte. En el ejemplo anterior hemos visto que nos
sirve para no buscar soluciones en predicados alternativos. Tambin podemos
combinar corte y fallo, o bien que no necesitemos mas soluciones.

Ejemplo. La denicin del predicado not, usando corte y fallo:

not(P ) : call(P ), !, f ail.

not(P ).
En este caso, si P es cierto, falla (fail). Si es falso pasa a la siguiente clusula
que resuelve correctamente.
Slo es necesaria la primera solucin.
Cuando se encuentra una solucin al problema no se buscan ms. Por ejem-
plo si programramos, que resolviramos un sudoku, puede que nos interese
solamente una solucin. Con lo que al nal del predicado haramos una conjun-
cin con la expresin !, para que cortara el programa en caso de encontrar una
solucin al problema.

3.5. El backtracking.
En los lenguajes de programacin con paradigma lgica, y en particular en
el PROLOG, las instrucciones se ejecutan normalmente en orden secuencial,
es decir, una a continuacin de otra, en el mismo orden en que estn escritas,
que slo vara cuando se alcanza una instruccin de control (un bucle, una
instruccin condicional o una transferencia).
Los programas en PROLOG se componen de cl
ausulas de Horn. No obs-
tante, la forma de escribir las clusulas de Horn es al contrario de lo habitual.
Primero se escribe el consecuente y luego el antecedente. El antecedente puede
ser una conjuncin de condiciones que se denomina secuencia de objetivos. Ca-
da objetivo se separa con una coma. En el PROLOG no existen instrucciones
de control (if, while, etc). Su ejecucin se basa en dos conceptos: la unicacin
(explicada en el apartado 3.3.5) y el backtracking .
Gracias a la unicacin, cada objetivo determina un subconjunto de clusulas
susceptibles de ser ejecutadas. Cada una de ellas se denomina punto de eleccin.
Como ya hemos visto, PROLOG selecciona el primer punto de eleccin y sigue
ejecutando el programa hasta determinar si el objetivo es verdadero o falso.
En el caso de ser falso, o de querer seguir buscando ms soluciones, entra
el juego el backtracking, que consiste en deshacer todo lo ejecutado situando el
programa en el mismo estado en el que estaba justo antes de llegar al punto de
eleccin. Entonces se toma el siguiente punto de eleccin que estaba pendiente
y se repite de nuevo el proceso. Si los computos para los objetivos terminan, lo
hacen bien en xito o en fracaso.
En el ltimo ejemplo del apartado 3.9 podemos ver ejemplos de backtracking
al buscar ms de una solucin para el mismo objetivo.
CAPTULO 3. EL LENGUAJE PROLOG 35

3.6. Mecanismo de ejecucin del PROLOG.


El objetivo, que ser la entrada para el interpretador de Prolog, es una
conjuncin de frmulas atmicas de un lenguaje de predicados. Lo que har el
interpretador es evaluar si este objetivo es consecuencia lgica de las clusulas
del programa en cuestin.

Interpretador para programas lgicos.


Entrada: un programa lgico P y un objetivo = 1 , ..., n .
Algoritmo:

1. Poner k=0 (contador), Rk = 1 ... n .


2. Mientras Rk 6=  (clusula vaca):

a) Tomar el primer literal de Rk y una clusula (la primera, por


orden de aparicin) k = ( 0 : 10 , ..., n0 ) de P con las variables
renombradas, si es necesario para que no colapsen, tal que {, 0 }
uniquen.
Si tal eleccin no es posible salimos del bucle.

b) Poner en Rk+1 el resolvente deRk , k respecto de , 0 .


c) Aumentar el contador, k = k + 1.
3. Si R k = , salida = xito. Else, salida = fallo.

Mejora para el interpretador de PROLOG.


Rk tiene la forma 1 ... n para algn n > 0. Ahora el interpretador
trabajar con Ok = 1 ... n .
Entrada: un programa lgico P y un objetivo = 1 , ..., n .
Algoritmo:

1. Poner k=0 (contador), Ok = 1 ... n .


2. Mientras Ok 6=  (clusula vaca):

a) Tomar el primer tomo de Ok y una clusula (la primera, por


orden de aparicin) k = ( 0 : 10 , ..., n0 ) de P con las variables
renombradas, si es necesario para que no colapsen, tal que {, 0 }
uniquen.
Si tal eleccin no es posible salimos del bucle.

b) Poner en Ok+1 el resolvente de Ok , k respecto de , 0 . Ok+1 ser


0 0
el resultado de sustituir en Ok el tomo por 1 , ..., n y aplicar a
la frmula que resulta de unicar y 0 .
c) Aumentar el contador, k = k + 1.
3. Si Ok = , salida = xito. Si no, salida = fallo.

La mejora viene dada por la mayor comodidad al trabajar con conjunciones.


CAPTULO 3. EL LENGUAJE PROLOG 36

Ejemplos de ejecucin:
Ejemplo 1. Selecciona al ltimo elemente de una lista.
Programa:
ultimo([X], X).
ultimo([X|L], Y ) : ultimo(L, Y ).
Objetivo:
ultimo([17, 3, 10], X)

1. Tomamos la segunda clusula renombrando variables

ultimo([X 0 |L0 ], Y 0 ) : ultimo(L0 , Y 0 ).

comparamos la parte izquierda de la clusula con el objetivo y tenemos,


X 0 = 17, L0 = [3, 10] , Y 0 = X .
Tomamos la parte derecha de la clusula como nuevo objetivo sustituyen-
do con las igualdades anteriores: ultimo(L0 , Y 0 ) = ultimo([3, 10], X).

2. Tomamos la segunda clusula renombrando variables

ultimo([X 0 |L0 ], Y 0 ) : ultimo(L0 , Y 0 ).

comparamos con el objetivo y tenemos, X 0 = 3, L0 = [10] , Y 0 = X .


Tomamos la parte derecha de la clusula como nuevo objetivo sustituyen-
do con las igualdades anteriores: ultimo(L0 , Y 0 ) = ultimo([10], X).

3. Tomamos la primera clusula renombrando variables,

ultimo([X 0 ], X 0 ).

comparamos con el objetivo y tenemos, X 0 = 10, X 0 = X .


La parte derecha de la cusula est vaca, por lo tanto la salida es  y el
resultado X = 10.

Ejemplo 2. Computa la lista invertida de una lista dada.


Programa:
inversa(L1, L2) : inversa1(L1, [ ], L2).
inversa1([X|L1], L, L2) : inversa1(L1, [X|L], L2).
inversa1([ ], L, L).
Objetivo:
ultimo([a, b, c], L)
CAPTULO 3. EL LENGUAJE PROLOG 37

1. Tomamos la primera clusula

inversa(L1, L2) : inversa1(L1, [ ], L2).


comparamos la parte izquierda de la clusula con el objetivo y tenemos,
L1 = [a, b, c], L2 = L .
Tomamos la parte derecha de la clusula como nuevo objetivo sustituyendo
con las igualdades anteriores: inversa1([a, b, c], [ ], L).
2. Tomamos la segunda clusula renombrando variables,

inversa1([X 0 |L10 ], L0 , L20 ) : inversa1(L10 , [X 0 |L0 ], L20 ).


comparamos la parte izquierda de la clusula con el objetivo y tenemos,
X 0 = a, L10 = [b, c], L0 = [ ] , L20 = L.
Tomamos la parte derecha de la clusula como nuevo objetivo sustituyendo
con las igualdades anteriores: inversa1(L10 , [X 0 |L0 ], L20 ) = inversa1([b, c], [a], L).
3. Tomamos la segunda clusula renombrando variables,

inversa1([X 0 |L10 ], L0 , L20 ) : inversa1(L10 , [X 0 |L0 ], L20 ).


comparamos la parte izquierda de la clusula con el objetivo y tenemos,
X 0 = b, L10 = [c], L0 = [a] , L20 = L.
Tomamos la parte derecha de la clusula como nuevo objetivo sustituyendo
con las igualdades anteriores: inversa1([c], [b, a], L).
4. Tomamos la segunda clusula renombrando variables,

inversa1([X 0 |L10 ], L0 , L20 ) : inversa1(L10 , [X 0 |L0 ], L20 ).


comparamos la parte izquierda de la clusula con el objetivo y tenemos,
X 0 = c, L10 = [], L0 = [b, a] , L20 = L.
Tomamos la parte derecha de la clusula como nuevo objetivo sustituyen-
do con las igualdades anteriores: inversa1([], [c, b, a], L).

5. Tomamos la tercera clusula renombrando variables,

inversa1([ ], L0 , L0 ).
comparamos la parte izquierda de la clusula con el objetivo y tenemos,
L0 = [c, b, a] , sustituimos L0 por [c, b, a] y entonces, L = [c, b, a].
La parte derecha de la cusula est vaca, por lo tanto la salida es  y el
resultado L = [c, b, a].

Ejemplo 3. Mximo comn divisor entre dos nmeros.


Programa:
mcd(X, 0, X).
mcd(X, Y, Z) : U is X mod Y, mcd(Y, U, Z).
CAPTULO 3. EL LENGUAJE PROLOG 38

Objetivo:
ultimo(60, 42, A)

1. Tomamos la segunda clusula,

mcd(X, Y, Z) : U is X mod Y, mcd(Y, U, Z).

comparamos la parte izquierda de la clusula con el objetivo y tenemos,


X = 60, Y = 42, Z = A .
Tomamos la parte derecha de la clusula como nuevo objetivo sustitu-
yendo con las igualdades anteriores: U is 60 mod 42, mcd(Y, U, Z) U =
18, mcd(42, 18, A).
2. Tomamos la segunda clusula,

mcd(X, Y, Z) : U is X mod Y, mcd(Y, U, Z).

comparamos la parte izquierda de la clusula con el objetivo y tenemos,


X = 42, Y = 18, Z = A .
Tomamos la parte derecha de la clusula como nuevo objetivo sustitu-
yendo con las igualdades anteriores: U is 42 mod 18, mcd(Y, U, Z) U =
6, mcd(18, 6, A).
3. Tomamos la segunda clusula,

mcd(X, Y, Z) : U is X mod Y, mcd(Y, U, Z).

comparamos la parte izquierda de la clusula con el objetivo y tenemos,


X = 18, Y = 6, Z = A .
Tomamos la parte derecha de la clusula como nuevo objetivo sustitu-
yendo con las igualdades anteriores: U is 18 mod 6, mcd(Y, U, Z) U =
0, mcd(6, 0, A).
4. Tomamos la primera clusula,

mcd(X, 0, X).

comparamos la parte izquierda de la clusula con el objetivo y tenoemos,


X = 6, X = A A = 6 y en la parte derecha . Por tanto, el resultado
es A = 6.

Ejemplo. Antepasados. Objetivo con ms de una solucin. Backtracking.


Programa: en lenguaje natural, la clusula padre(X,Y) se podra traducir
como que X es el padre de Y, y la clusula ant(X,Y) que X es el antepasado de
Y.

padre(abraham, isaac).

padre(isaac, jacob).
CAPTULO 3. EL LENGUAJE PROLOG 39

padre(jacob, benjamin).

ant(X, Y ) : padre(X, Y ).

ant(X, Y ) : padre(X, Z), ant(Z, Y ).


Observaciones:

Habiamos visto tres tipos de clsulas: los hechos, las reglas y las preguntas.
En este caso podemos distinguir las clusulas con relacin padre, que son
hechos, las clusulas con relacin ant (antepasado), que son reglas, y el
objetivo sera una pregunta.

Vemos que para que X sea antepasado de Y es necesario, tal y como indican
las clusulas, que X sea padre de Y o bien que exista un Z tal que X sea
padre de Z y Z antepasado de Y.

Objetivo:
ant(abraham, A)
En este caso buscamos soluciones para A tales que abraham sea su antepa-
sado. Es decir, las respuestas deberan ser los descendientes de abraham.

1. Aqu podramos tomar la cuarta o la quinta clusula. En este caso nuestro


punto de eleccin ser la cuarta clusula y si fallara o quiseramos ms
respuestas volveramos a este punto para coger la quinta.

ant(X, Y ) : padre(X, Y ).

comparamos la parte izquierda de la clusula con el objetivo y tenemos,


X = abraham, Y = A .
Tomamos la parte derecha de la clusula como nuevo objetivo sustituyendo
con las igualdades anteriores: padre(abraham, A).
2. Slo tenemos una clusula con relacin padre y primer argumento abraham,
la primera.
padre(abraham, isaac).
comparamos la parte izquierda de la clusula con el objetivo y tenemos,
A = isaac .
Como la parte derecha de la clusula est vaca, la salida es  y la res-
puesta A = isaac. Hemos encontrado el primer descendiente de Abraham,
su hijo, Isaac.
CAPTULO 3. EL LENGUAJE PROLOG 40

3. Supongamos que le pedimos al programa otra solucin. Entonces, PRO-


LOG deber hacer backtracking hasta el ltimo punto de eleccin (paso
1). Tomemos ahora la quinta clusula. Recordemos que el objetivo vuelve
a ser ant(abraham, A).

ant(X, Y ) : padre(X, Z), ant(Z, Y ).

comparamos la parte izquierda de la clusula con el objetivo y tenemos,


X = abraham, Y = A .
Tomamos la parte derecha de la clusula como nuevo objetivo sustituyendo
con las igualdades anteriores: padre(X, Z), ant(Z, Y ) = padre(abraham, Z), ant(Z, A).
Para que se cumpla el objetivo, deben ser ciertas las dos clusulas:

a) Para la primera clusula, slo tenemos una clusula con relacin


padre y primer argumento abraham, la primera.

padre(abraham, isaac).

comparamos la parte izquierda de la clusula con el objetivo y tene-


mos, Z = isaac .
Como la parte derecha de la clusula est vaca, la salida es  con
Z = isaac .

b) Vamos a comprobar la segunda clusula. Para ello, ya tenemos la


informacin obtenida en 3.a), Z = isaac. Entonces, la clusula nos
queda ant(isaac, A). Podemos encontrar ms de una posible solu-
cin, en todo caso, en el paso 3 hemos visto que Y =A y teniamos
ant(abraham, Y ). Por tanto, las soluciones para A, lo seran para
nuestro objetivo inicial.

4. Objetivo: ant(isaac, A). Aqu podramos tomar la cuarta o la quinta clu-


sula. En este caso nuestro punto de eleccin ser la cuarta clusula, despus
volveremos a este punto para coger la quinta.

ant(X, Y ) : padre(X, Y ).

comparamos la parte izquierda de la clusula con el objetivo y tenemos,


X = isaac, Y = A .
Tomamos la parte derecha de la clusula como nuevo objetivo sustituyendo
con las igualdades anteriores: padre(isaac, A).
5. Slo tenemos una clusula con relacin padre y primer argumento isaac,
la segunda.
padre(isaac, jacob).
comparamos la parte izquierda de la clusula con el objetivo y tenemos,
A = jacob .
Como la parte derecha de la clusula est vaca, la salida es  y la res-
puesta A = jacob. Hemos encontrado otro descendiente de Abraham, su
nieto jacob.
CAPTULO 3. EL LENGUAJE PROLOG 41

6. Hacemos backtracking hasta el ltimo punto de eleccin (paso 4). Tome-


mos ahora la quinta clusula. Recordemos que el objetivo vuelve a ser
ant(isaac, A).

ant(X, Y ) : padre(X, Z), ant(Z, Y ).

comparamos la parte izquierda de la clusula con el objetivo y tenemos,


X = isaac, Y = A .
Tomamos la parte derecha de la clusula como nuevo objetivo sustituyendo
con las igualdades anteriores: padre(X, Z), ant(Z, Y ) = padre(isaac, Z), ant(Z, A).
Para que se cumpla el objetivo, deben ser ciertas las dos clusulas:

a) Para la primera clusula, slo tenemos una clusula con relacin


padre y primer argumento isaac, la primera.

padre(isaac, jacob).

comparamos la parte izquierda de la clusula con el objetivo y tene-


mos, Z = jacob .
Como la parte derecha de la clusula est vaca, la salida es , con
Z = jacob.
b) Vamos a comprobar la segunda clusula. Para ello, ya tenemos la
informacin obtenida en 6.a), Z = jacob. Entonces, la clusula nos
queda ant(jacob, A).

7. Aqu podramos, de nuevo, tomar la cuarta o la quinta clusula. Tomemos


primero la cuarta.
ant(X, Y ) : padre(X, Y ).
comparamos la parte izquierda de la clusula con el objetivo y tenemos,
X = jacob, Y = A .
Tomamos la parte derecha de la clusula como nuevo objetivo sustituyendo
con las igualdades anteriores: padre(jacob, A).
8. Slo tenemos una clusula con relacin padre y primer argumento jacob,
la tercera.
padre(jacob, benjamin).
comparamos la parte izquierda de la clusula con el objetivo y tenemos,
A = jacob .
Como la parte derecha de la clusula est vaca, la salida es  y la res-
puesta A = benjamin. Hemos encontrado otro descendiente de Abraham,
su bisnieto Benjamin.

9. Hacemos backtracking hasta el ltimo punto de eleccin (paso 7). Tome-


mos ahora la quinta clusula. Recordemos que el objetivo vuelve a ser
ant(jacob, A).

ant(X, Y ) : padre(X, Z), ant(Z, Y ).


CAPTULO 3. EL LENGUAJE PROLOG 42

comparamos la parte izquierda de la clusula con el objetivo y tenemos,


X = jacob, Y = A .
Tomamos la parte derecha de la clusula como nuevo objetivo sustituyendo
con las igualdades anteriores: padre(X, Z), ant(Z, Y ) = padre(jacob, Z), ant(Z, A).
Para que se cumpla el objetivo, deben ser ciertas las dos clusulas:

a) Para la primera clusula, slo tenemos una clusula con relacin


padre y primer argumento isaac, la primera.

padre(jacob, benjamin).

comparamos la parte izquierda de la clusula con el objetivo y tene-


mos, Z = benjamin .
Como la parte derecha de la clusula est vaca, la salida es , con
Z = benjamin.
b) Vamos a comprobar la segunda clusula. Para ello, ya tenemos la
informacin obtenida en 9.1, Z = benjamin. Entonces, la clusula
nos queda ant(benjamin, A).

10. Aqu podramos, de nuevo, tomar la cuarta o la quinta clusula. Tomemos


primero la cuarta.
ant(X, Y ) : padre(X, Y ).
comparamos la parte izquierda de la clusula con el objetivo y tenemos,
X = benjamin, Y = A .
Tomamos la parte derecha de la clusula como nuevo objetivo sustituyendo
con las igualdades anteriores: padre(benjamin, A).
11. No existe ninguna clusula (hecho) que tenga relacin padre y primer
argumento benjamin. Por lo tanto es un fallo y acaba la ejecucin de esta
rama.

12. Hacemos backtracking hasta el ltimo punto de eleccin (paso 10). To-
memos ahora la quinta clusula. Recordemos que el objetivo vuelve a ser
ant(benjamin, A).

ant(X, Y ) : padre(X, Z), ant(Z, Y ).

comparamos la parte izquierda de la clusula con el objetivo y tenemos,


X = benjamin, Y = A .
Tomamos la parte derecha de la clusula como nuevo objetivo sustituyendo
con las igualdades anteriores: padre(X, Z), ant(Z, Y ) = padre(benjamin, Z), ant(Z, A).
Para que se cumpla el objetivo, deben ser ciertas las dos clusulas:

a) Para la primera no existe ninguna clusula (hecho) que tenga relacin


padre y primer argumento benjamin. Por lo tanto es un fallo y acaba
la ejecucin de esta rama. El paso 12 tambin devuelve error ya que
una de las dos clusulas, la primera, ya es falsa. Ya hemos encontrado
todas las respuestas posibles.
CAPTULO 3. EL LENGUAJE PROLOG 43

3.7. Especicaciones tcnicas y otros.


Otros temas como por ejemplos los predicados predenidos en Prolog daran
lugar a desarrollar un trabajo ms extenso sobre el lenguaje. He querido destacar
los aspectos ms bsicos. En los libros
3 y 4 podemos encontrar mucho ms sobre
aplicaciones y tcnicas avanzadas de la programacin en Prolog. Sin embargo,
en la primera seccin del siguiente captulo podemos encontrar algunos ejemplos
de predicados predenidos que luego utilizaremos en los ejercicios.
Los programas en Prolog se pueden escribir mediante cualquier editor de
textos, aunque existen editores especiales que facilitan su escritura. La extensin
habitual para los programas en Prolog es .pl.
Utilizaremos el entorno SWI-Prolog para realizar las pruebas y ejecutar los
ejemplos y ejercicios en el captulo 4. Es un compilador de Prolog de dominio p-
blico diseado e implementado EN LA Universidad de msterdam, compatible
con el estndar ISO y disponible para distintas plataformas. Se puede obtener
en la direccin http://www.swi-prolog.org.

3 P.J.Iranzo y M.Alpuente. Programacin Lgica, teora y prctica. 1 edicin. Madrid:

Pearson Educacin, 2007.


4 L. Sterling y E. Shapiro: The art of Prolog: Advanced Programming Techniques. 2 edicin.
Cambridge, Massachusetts: MIT press, 1994.
Captulo 4

EJERCICIOS RESUELTOS.

A continuacin he enunciado unos cuantos problemas, la mayora bastante


tpicos y populares. Doy su resolucin explicando la funcin de cada clusula.
Todos estos ejemplos han sido probados.

4.1. Predicados predenidos.


A continuacin voy a explicar unos cuantos de los predicados predenidos
que tiene Prolog. El nombre de los predicados viene acompaado por /k , dnde
k es el nmero de argumentos que tendr el predicado. Aunque voy a denirlos
tambin, estos predicados ya los entiende Prolog sin necesidad de hacerlo en cada
programa. Los predicados subcjto y nat no son predenidos pero los necesitar
para los ejemplos; los pongo aqu y los supongo predenidos luego.

4.1.1. not/1
Ya habamos denido este predicado cuando hablbamos de corte. El predi-
cado not() tiene xito cuando todos los cmputos del interpretador de Prolog
para el objetivo terminan y dan fallo. Usamos el corte para que pare cuando
uno de los cmputos de cierto, ya que para que sea exito han de ser todos fallo.
not(P ) : call(P ), !, f ail.
not(P ).

4.1.2. select/3
El predicado select(X, L1, L2) genera la lista L2 extrayendo de la lista L1
una aparicin de X.
Se extrae por orden cada elemento de L1, y lo insertamos en L2 (segun-
da clusula), hasta que encontramos X, entonces slo la extraemos de L1 sin
insertarla en L2 (segunda clusula).
select(X, [X|Xs], Xs).
extract(X, [Y |Y s], [Y |Zs]) : extract(X, Y s, Zs).

44
CAPTULO 4. EJERCICIOS RESUELTOS. 45

4.1.3. permutation/2
permutation(L, P ) devuelve en P una permutacin de los ele-
El predicado
mentos de lista L.
Supongamos que la lista tiene n elementos, la idea es generar las permuta-
ciones los elementos extrayendo uno de ellos mediante extract/3 y generando
las permutaciones de orden inferior (n 1 elementos) a las que se aade por la
cabeza el elemento seleccionado con extract/3.
permutation(Xs, [Z|Zs]) : extract(Z, Xs, Y s), permutation(Y s, Zs).
permutation([], []).

4.1.4. length/2
El predicado length(L, N ) devuelve en N el nmero de elementos de la lista
L. Simplemente, de forma recursiva, va calculando la longitud de la misma lista
quitando un elemento en cada paso de la recursin.
length([ ], 0).
length([_|L], N ) : length(L, M ), N is M + 1.

4.1.5. append/3
El predicado append(L1, L2, L3) devuelve en L3 la concatenacin de L1 con
L2.
append([ ], L, L).
append([X|L1], L2, [X|L3]) : concat(L1, L2, L3).

4.1.6. member/2
En el apartado de listas en Prolog hemos visto un ejemplo dnde escribamos
un predicado miembro(X, L) para saber si un elemento X es un elemento de la
lista L. El predicado predenido member(X, L) tiene esta misma funcin.
member(X, [X|_]).
member(X, [_|L1]) : miembro(X, L1).

4.1.7. write/1 y nl
El predicado write(X) devuelve el valor de X .
El predicado nl escribe una lnea en blanco.

4.1.8. El predicado subcjto.


Creamos un predicado subcjto(L, S) que devuelve un subconjunto en S de
la lista L.
subcjto([ ], [ ]).
subcjto([X|L1], [X|L2]) : sub(L1, L2).
subcjto([_|L1], L2) : sub(L1, L2).
CAPTULO 4. EJERCICIOS RESUELTOS. 46

4.1.9. El predicado nat.


El predicado nat(N ) genera todos los nmeros naturales.
nat(0).
nat(N ) : nat(N 1), N is N 1 + 1.

4.2. Fibonacci.
Se trata de escribir un predicado f ib(N, F ) que signique: F es el N-simo
nmero de Fibonacci para la N>0 dada. Denimos los nmeros de bonacci
como: f ib(1) = 1, f ib(2) = 1, f ib(N ) = f ib(N 1) + f ib(N 2).
f ib(1, 1).
f ib(2, 1).
f ib(N, F ) : N > 2, N 1 is N 1, N 2 is N 2, f ib(N 1, F 1), f ib(N 2, F 2), F is F 1+
F 2.

4.3. Ordenacin.
Programaremos un algoritmo de ordenacin de listas de nmeros basado en
elmerge sort. Est demostrado que es un algoritmo ptimo llegando a hacer
como mucho n logn comparaciones.
particion([ ], [ ], [ ]).
particion([A], [A], [ ]).
particion([A, B|R], [A|Ra], [B|Rb]) : particion(R, Ra, Rb).
ord_f us([ ], [ ]).
ord_f us([X], [X]).
ord_f us([X, Y |L], L3) : particion([X, Y |L], L1, L2), ord_f us(L1, L11),
ord_f us(L2, L22), f usion(L11, L22, L3).
f usion(L, [ ], L).
f usion([ ], L, L).
f usion([X|L1], [Y |L2], [X|L3]) : X =< Y, f usion(L1, [Y |L2], L3).
f usion([X|L1], [Y |L2], [Y |L3]) : X > Y, f usion([X|L1], L2, L3).

4.4. El jurado.
Un juez tiene que formar un jurado con N personas, de manera que ningn
miembro del jurado conozca a ningn otro miembro. Para eso dispone de M
personas candidatas (identicadas con nmeros de 1 a M) y de una lista de
aquellos pares de personas que no se conocen, expresada como un programa
Prolog formado por clusulas no_conoce(Pi , Pj )., donde 1 Pi < Pj M .

1. Hacemos un predicado compatible(X, L) que signique: la persona X no


conoce a ninguna de las personas de la lista L.
compatible(_, [ ]).
CAPTULO 4. EJERCICIOS RESUELTOS. 47

compatible(X, [Y |L]) : no_conoce(X, Y ), compatible(X, L).


compatible(X, [Y |L]) : no_conoce(Y, X), compatible(X, L).
2. Hacemos un predicado valido(L) que signique: ningn miembro de la
lista L conoce ningn otro miembro de la lista.
valido([ ]).
valido([X|L]) : compatible(X, L), valido(L).
3. Asumimos que M=10 y hazemos un predicado jurado(N ) que escriba por
pantalla un posible jurado con N personas. Tambin podriamos crear la
lista automticamente, per as es mas sencillo (en el siguiente ejercicio si
es automtico).
jurado(N ) : subcjto([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], S), length(S, N ), valido(S), write(S).

4.5. El vendedor viajero.


Un agente comercial debe visitar N ciudades dadas minimizando el nmero
total de km. recorridos. Puede escoger el orden en el que visita las ciudades,
en particular dnde comenzar y dnde acabar. Para la planicacin el agente
dispone de:

Una lista de ciudades a visitar, expresada mediante una clusula Prolog


de la forma:
ciudades([bcn, gir, tar]).(Aqu N=3)

Una tabla precalculada (a partir de un mapa del pas) con las distancias
mnimas entre cada par de ciudades, representada mediante clusulas Pro-
log de la forma:
dist(gir, tar, 200).
dist(tar, gir, 200).
dist(tar, bcn, 100).
dist(bcn, tar, 100).
...

1. Denominamos recorridoa una lista Prolog que contiene las N ciudades en


el orden en el que se visitan. Escribimos un predicado dist_tot(R, D) que,
dado un recorrido R instancie la variable D a la distancia total de dicho
recorrido
dist_tot([_], 0).
dist_tot([X, Y |L], T ) : dist(X, Y, D), dist_tot([Y |L], U ), T is D + U.
2. Escribimos un predicado recorrido_min que muestre el recorrido ms
corto posible
recorrido_min : nat(N ), ciudades(L), permutation(L, R), dist_tot(R, N ), write(R), nl, !.
CAPTULO 4. EJERCICIOS RESUELTOS. 48

4.6. El problema de las ocho reinas.


El problema de las ocho reinas consiste en colocar ocho reinas en un tablero
de ajedrez de dimensin 8 de tal forma que ninguna amenace a la otra (como
reinas de ajedrez). Es decir que dos reinas no pueden coincidir en la misma la,
columna, o diagonal.
En este caso hacemos el programa para N reinas.

1. Dividimos el problema en dos clusulas.


reinas(N, L) : rango(1, N, L1), reinas(L1, [ ], L).
2. En la primera, rango(1, N, L) crearemos una lista de los nmeros enteros
entre 1 y N. Seran las las del tablero.
rango(A, B, [A|L]) : A < B, A1 is A + 1, rango(A1, B, L).
rango(B, B, [B]).
3. La segunda clusula ya es el problema en si. Seleccionamos un elemento
de la lista con select, comprobamos que la eleccin es correcta y por tanto
no choca con nadie con ataca(Q, L), y otra clusula con la misma relacin
reinas para hacer el siguiente paso.
reinas(L1, L2, L) : select(Q, L1, L3), not(ataca(Q, L2)), reinas(L3, [Q|L2], L).
reinas([ ], L, L).
ataca(X, L) : ataca(X, 1, L).
ataca(X, N, [Y |_]) : X =:= Y + N, !.
ataca(X, N, [Y |_]) : X =:= Y N, !.
ataca(X, N, [_|L]) : N 1 is N + 1, ataca(X, N 1, L).
Est algoritmo va recorriendo todo el rbol de posibilidaes, pero solo computa
las que son correctas. Cuando un camino ya no puede dar respuestas correctas
se corta y se vuelve atras con backtracking.
Observemos que en las clusulas 7 y 8 de este ejemplo utilizamos el corte.
As, cuando encontramosa una reina que choca con la que estamos colocando,
ya no seguimos comprobando ms: esta opcin no puede ser correcta.

4.7. Problema de colorear un mapa.


Dado el mapa de un continente queremos colorear los paises con cuatro
colores distintos, cada pas de un slo color, de manera que dos paises con
frontera comn no pueden tener el mismo color. Vamos a generalizar el problema
con N paises i K colores. Haremos un programa que no diga si es posible o no
tal hiptesis.
Numeramos los paises de 1 a N. Queremos ver si existe una lista de N ele-
mentos de enteros de 1 a K, donde el i-ssimo elemento de la lista representa el
color del pas i (1 i N ).
Disponemos der la lista de paises vecinos. Para cada par de vecinos tenemos
una clusula de la forma v(Pi , Pj ), donde 1 Pi < Pj N .
CAPTULO 4. EJERCICIOS RESUELTOS. 49

1. Hacemos un predicado para(L, X, U )que, dados dos enteros L y U tales


que LU va instanciando X, bajo backtracking, a todos los enteros entre
L y U, ambos incluidos, en orden creciente.
para(L, N, U ) : U > L, P is U 1, para(L, N, P ).
para(L, N, N ) : N >= L.
2. Hacemos un predicado iesimo(I, L, X) que signica: el elemento I-simo
de la lista L es X.
iesimo(1, [X|_], X).
iesimo(I, [_|L], Y ) : I > 1, J is I 1, iesimo(J, L, Y ).

3. Hacemos un predicado ok(C, L) que signica: el coloreado C pinta de


colores distintos pases distintos, segn la lista de pases vecinos L.
ok(_ ,[]).
ok(C, [v(X, Y )|L]) : iesimo(X, C, A), iesimo(Y, C, B), A\ = B, ok(C, L).
4. Hacemos un predicado color(N, K, L)que, dados N, K y L, escribe por
pantalla un coloreado (si existe) para N pases de como mucho K colores
que pinte distinto pases vecinos, segn la lista L de pases vecinos.
gen(0, _,, []).
gen(N, K, [X|C]) : N > 0, M is N 1, gen(M, K, C), para(1, X, K).
color(N, K, L) : gen(N, K, C), ok(C, L), write(C), nl, !.

4.8. Resolver un sudoku


Este problema necesita de un nmero ms grande de clusulas. Ricardo Pea
en
1 nos indica como resolver el problema.
Un sudoku es un cuadriltero de 9x9 casillas, en algunas de las cuales hay
situados dgitos que toman valores entre 1 y 9. El jugador ha de completar las
casillas vacas con dgitos entre 1 y 9 de forma que:

1. No se repitan dgitos en ninguna la.

2. No se repitan dgitos en ninguna columna.

3. No se repitan dgitos en ninguno de los nueve bloques de 3x3 casillas en


que puede dividirse el cuadriltero total.

Si llamamos Xij al dgito que hemos de escribir en la casilla situada en la la i,


columna j, los elementos de este problema seran:

1. Un conjunto de 9x9 variables Xij , algunas de las cuales tienen ya un valor


prejado en el sudoku concreto que hemos de resolver.

2. Los dominios son intervalos de enteros Dij = {1, ..., 9}.


1 R. Pea Mar. De Euclides a Java: Historia de los algoritmos y de los lenguajes de
programacin. 1 edicin. Madrid: Nivola, 2006.
CAPTULO 4. EJERCICIOS RESUELTOS. 50

3. Las restricciones son 27 predicados distintas(Xi1 j1 , ..., Xi9 j9 ), que expre-


san que las nueve variables de cada la, columna y bloque, han de ser
distintas.

Ntese que el espacio de bsqueda es exponencial. En este caso hay 981 asigna-
ciones posibles.
La estrategia ingnua para resolver este tipo de problemas consiste en enu-
merar todas las posibles conguraciones y comprobar si alguna de ellas cumple
todas las restricciones (sera un algoritmo de fuerza bruta). Como es lgico,
se obtendra un coste computacional exponencial o superior.
Una notable mejora son los algoritmos de vuelta atrs, en los que se constru-
yen tupals parciales X1 , ..., Xj que cumplen las restricciones para las variables
involucradas. Si al aadir una nueva variable Xj+1 ms a la tubla con un cierto
valor se viola alguna restriccin, dicha tupla parcial no se completa y se ensaya
un nuevo valor para Xj+1 . Con ello se recorta bastante el espacio de bsqueda.
Los algoritmos de resolucin de restricciones suponen una mejora adicional
sobre las tcnicas de vuelta atrs debido a que mantienen siempre las restriccio-
nes en la forma ms simplicada posible y de forma que siempre sean satisfacti-
bles. Tienen adems diversas estrategias que les permiten ordenar las variables
y la enumeracin de valores de forma dinmica, buscando siempre podar al
mximo los estados a explorar.
Bibliografa

[1] L. Sterling y E. Shapiro: The art of Prolog: Advanced Programming Tech-


niques. 2 edicin. Cambridge, Massachusetts: MIT press, 1994. ISBN:
9780262691635.

[2] R. Pea Mar.De Euclides a Java: Historia de los algoritmos y de los lengua-
jes de programacin. 1 edicin. Madrid: Nivola, 2006. ISBN-10: 84-96566-
14-5. ISBN-13: 978-84-96566-14-9.

[3] R. Farr, R. Nieuwanhuis, P. Nivela, A.Oliveras, E. Rodrguez y J. Sierra.


Lgica para informticos. 1 edicin. Barcelona: Marcombo, 2011. ISBN:
978-84-267-1694-1.

[4] P.J.Iranzo y M.Alpuente. Programacin Lgica, teora y prctica. 1 edicin.


Madrid: Pearson Educacin, 2007. ISBN: 978-84-8322-368-0.

[5] I. Bratko. Prolog Programmin for Articial Intelligence. 4 edicin. Boston,


Massachusetts: Addison Wesley, 2011. ISBN 0-201-14224-4.

[6] W.Clocksin y C.S.Mellish. Programming in Prolog. 5 edicin. Berlin:


Springer-Verlag, 2003. ISBN-13: 9780387006789. ISBN-10: 0387006788.

[7] U.Schning. Logic for computer scientists. 1 edicin. Boston, Massachu-


setts: Birkhuser, 1989. ISBN:978-0-8176-4763-6

51

S-ar putea să vă placă și