Académique Documents
Professionnel Documents
Culture Documents
Informática
INFORMATICA PERSONAL-PROFESIONAL
RESPONSABLE EDITORIAL:
José Carlos Jiménez Pérez
AUTOEDICIÓN:
Sistemas de Imagen y Palabra
DISEÑO DE CUBIERTA:
Narcís Fernández
REALIZACIÓN DE CUBIERTA:
Gracia Fernández-Pacheco
Fundamentos de
Informática
Gregorio Fernández
Fernando Sáez Vacas
ANAYA
•MULTIMEDIA*
Reservados todos los derechos. De con-
formidad con lo dispuesto en el artículo
534-bis del Código Penal vigente, podrán
ser castigados con penas de multa y pri-
vación de libertad quienes reprodujeren o
plagiaren, en todo o en parte, una obra
literaria, artística o científica fijada en
cualquier tipo de soporte, sin la precepti-
va autorización.
Edición española:
Indice 5
Prólogo 19
Parte I
Lógica 27
1. Ideas generales 29
5
2. Lógica de proposiciones 39
1. Introducción 39
1.1. Variables proposicionales y sentencias 39
1.2. Conectivas 40
1.3. Interpretaciones y evaluaciones binarias de variables
proposicionales y de sentencias 40
1.4. Ejemplos de formalización e interpretación 45
1.5. Cálculo, sistema axiomático y sistema inferential 51
2. Sintaxis 53
2.1. Alfabeto 53
2.2. Expresiones y sentencias 53
2.3. Sentencias equivalentes 54
2.4. Conectivas primitivas y definidas 55
2.5. Axiomas, demostraciones y teoremas 56
3. Semántica 60
3.1. Interpretaciones y evaluaciones 60
3.2. Satisfacción 62
3.3. Tautologías y contradicciones 64
3.4. Completitud y consistencia de un sistema axiomático 64
3.5. Equivalencia entre sentencias 64
3.6. Las conectivas binarias 66
4. Modelo algebraico de la lógica de proposiciones 67
4.1. Algebra de Boole de las evaluaciones binarias 67
4.2. Algebra de Boole de las clases de equivalencia
entre sentencias 69
4.3. Dos teoremas del álgebra de Boole 70
5. Sistemas inferenciales 71
5.1. Análisis y generación de razonamientos 71
5.2. Implicación lógica y razonamientos deductivos 72
5.3. Reglas de inferencia 73
5.4. Sistemas inferenciales 76
5.5. Forma clausulada de la lógica de proposiciones 78
5.6. Las cláusulas como sentencias condicionales 80
5.7. La regla de resolución 81
5.8. Refutación 85
6. Resumen 86
7. Notas histórica y blibliográfica 89
8. Ejercicios 90
3. Circuitos lógicos combinacionales 93
1. Introducción 93
2. Las puertas básicas 94
3. Circuitos 96
4. Modelos matemáticos de los circuitos 101
4.1. Utilidad de los modelos matemáticos 101
4.2. Funciones de conmutación 102
4.3. Formas booleanas 104
4.4. Relación entre los dos modelos matemáticos 108
5. Minimización 109
5.1. Principios 109
5.2. Método de Karnaugh 110
6. Ejemplos de aplicación 116
6.1. Máquina de escrutinio 116
6.2. Alarma para incendios 117
6.3. Etapa de sumador binario 119
6.4. Multiplicador binario de dos bits 121
6.5. Regulación de una piscina 123
7. La segunda forma canónica y la forma mínima
en producto de sumas 125
7.1. La segunda forma canónica 125
7.2. La forma mínima en producto de sumas 127
8. Otras puertas 130
9. Circuitos con puertas "NAND" y "NOR" 132
9.1. "NAND" y "NOR" como operaciones completas 132
9.2. La tercera forma canónica 133
9.3. La forma mínima sólo con NAND 133
9.4. La cuarta forma canónica 134
9.5. La forma mínima sólo con NOR 134
10. Resumen 134
11. Notas histórica y bibliográfica 136
12. Ejercicios 137
1. Introducción 141
1.1. Variables y constantes 141
1.2. Propiedades y relaciones 142
1.3. Predicados y fórmulas atómicas 142
1.4. Sentencias abiertas y cerradas 143
7
1.5. Cuantificadores 144
1.6. Evaluaciones binarias 144
1.7. Ejemplos de formalización e interpretación 146
1.8. Funciones 152
2. Sintaxis 152
2.1. Alfabeto 152
2.2. Términos y fórmulas atómicas 153
2.3. Sentencias 153
2.4. Sentencias abiertas y cerradas 154
2.5. Axiomas, demostraciones y teoremas 155
3. Semántica 158
3.1. Interpretaciones, asignaciones y evaluaciones 159
3.2. Satisfacción 161
3.3. Inconsistencia y validez 164
3.4. Modelos 164
4. Sistemas inferenciales 167
4.1. Razonamientos en lógica de predicados 167
4.2. Implicación lógica y razonamientos deductivos 167
4.3. Reglas de inferencia 169
4.4. Sistemas inferenciales 172
4.5. Forma clausulada de la lógica de predicados 172
4.6. Sustitución y unificación 176
4.7. La regla de resolución 178
4.8. Refutación 180
5. Resumen 182
6. Notas histórica y bibliográfica 182
7. Ejercicios 183
1. Introducción 187
2. Ampliaciones de la lógica de predicados 188
2.1. Lógica de predicados de orden superior 188
2.2. Lógica de clases y lógica de relaciones 189
2.3. Lógica de predicados con identidad 190
2.4. Lógica modal 191
2.5. Lógica temporal 193
3. Lógicas multivaloradas 193
4. Lógica borrosa 196
4.1. Justificación 196
4.2. Subconjuntos borrosos 198
4.3. Relaciones borrosas 201
4.4. Lógicas borrosas 206
5. Resumen 213
6. Notas histórica y bibliográfica 214
7. Ejercicios 215
Parte II
Autómatas 255
9
1.2. Representación 262
1.3. Máquinas de Moore y de Mealy 264
2. Ejemplos de autómatas como modelos 267
2.1. Detector de paridad 267
2.2. Sumador binario serial 268
2.3. El castillo encantado 271
3. Comportamiento de un autómata 275
3.1. Otra definición de autómata 275
3.2. Ampliación del dominio de las funciones de un autómata 277
3.3. El comportamiento de entrada-salida, o las máquinas
definidas por un circuito 277
3.4. Equivalencia y accesibilidad 278
3.5. Ejemplos 279
4. Capacidad de respuesta de un autómata finito 282
4.1. Introducción 282
4.2. Repaso de algunos conceptos de álgebra 283
4.3. Comportamiento de entrada-estados 288
4.4. Relación equirrespuesta y monoide de un autómata 290
4.5. Ejemplos 291
4.6. Relación entre el comportamiento de entrada-salida
y el comportamiento de entrada-estados 295
5. Minimización de un autómata finito 297
5.1. Planteamiento del problema 297
5.2. Autómata en forma mínima de un autómata dado 297
5.3. Comprobación de la equivalencia entre estados de un autómata 298
5.4. Algoritmo para minimización de un autómata finito 300
5.5. Ejemplos 300
6. Resumen 303
7. Notas histórica y bibliográfica 303
8. Ejercicios 304
1. Introducción 359
2. Redes de Petri 360
2.1. Estructura estática 360
2.2. Comportamiento dinámico 362
2.3. Autómata finito equivalente a una red de Petri
con espacio de estados finito 365
2.4. Ejemplos de aplicación 366
3. Autómatas estocásticos 373
3.1. Definición 373
3.2. Ejemplo 374
11
3.3. Reconocedores estocásticos 376
4. Autómatas estocásticos de estructura variable 376
5. Autómatas con aprendizaje 377
5.1. Una primera definición de "aprendizaje" 377
5.2. Aprendizaje en un APEV 378
6. Autómatas borrosos 379
7. Autómatas celulares 382
8. Sistemas con aprendizaje 384
8.1. ¿Puede aprender una máquina? 384
8.2. Enfoques conductistas: redes neuronales 386
8.3. Enfoques cognoscitivos: adquisición de conceptos 388
8.4. Formación de conceptos y descubrimiento 391
9. Resumen 391
10. Notas histórica y bibliográfica 392
Parte III
Algoritmos 397
2. Algoritmos 411
1. Introducción 411
2. Definiciones de algoritmo 411
3. Algoritmos y máquinas 413
3.1. El concepto de algoritmo, visto desde la teoría de conjuntos 413
3.2. Las máquinas, como estructuras capaces
de ejecutar algoritmos 416
4. Propiedades de los algoritmos 417
4.1. Propiedad de finitud 417
4.2. Propiedad de definitud 417
4.3. Propiedad de generalidad 418
4.4. Propiedad de eficacia 418
5. Problemas sin algoritmo 418
6. Resumen 420
12
7. Notas histórica y bibliográfica 421
1. Introducción 423
2. Definición formal de un programa para ordenador 424
2.1. Definición algorítmica 424
2.2. Función, programa, función de programa 425
2.3. Normalización de organigramas 426
3. ¿Qué es un programa estructurado? 428
3.1. Estructuras básicas 428
3.2. Definición de programa estructurado 428
3.3. Teorema de estructura para un programa limpio 430
3.4. Ejemplo de aplicación del teorema de estructura 431
4. Método general de diseño de programas estructurados 432
4.1. Recursos abstractos 432
4.2. Razonamiento deductivo (diseño descendente) 433
4.3. Ejemplo de diseño de un programa estructurado 434
5. Programación estructurada en Pascal y C 437
5.1. Bloque múltiple 439
5.2. Bucle "for" 439
5.3. Instrucción CASE 439
6. Ventajas de la programación estructurada 440
7. Resumen 441
8. Notas histórica y bibliográfica 442
9. Ejercicios 442
1. Introducción 447
2. Cómo se construye un programa 448
3. Técnicas de análisis y diseño 449
4. Programas correctos, robustos y convivenciales 451
5. Programación orientada a objetos 453
5.1. Propiedades de la programación orientada a objetos 456
5.2. Ventajas de la programación orientada a objetos 458
6. Análisis y diseño orientado a objetos 459
6.1. Metodologías de análisis y diseño 461
6.2. Ejemplo de análisis orientado a objetos 461
7. Resumen 464
8. Notas histórica y bibliográfica 465
13
5, Máquina de Turing: definición, esquema funcional y ejemplos 469
1 Introducción 469
2. Definición de máquina de Turing 470
3, Funcionamiento de la máquina de Turing a través de los ejemplos 472
3.1. Suma de dos números enteros no nulos escritos en el alfabeto {|} ..472
3.2. Algoritmo de Euclides para el cálculo del m.c.d.
de dos números enteros escritos en el alfabeto {|} 476
3.3. Cálculo del m.c.d. de dos números enteros escritos en D
(D = {0,1, 2, 3,..., 9}) por el procedimiento general
de construir un programa a base de subprogramas.
Composición de máquinas de Turing. 482
4. Diseño de una máquina de Turing 486
5. Simulación de máquinas de Turing, máquina de Turing universal
y otras consideraciones 491
5.1. Simulación de máquina de Turing por ordenador 491
5.2. Máquina de Turing universal 496
5.3. Otras consideraciones 496
6. Sucedáneos de la máquina de Turing 498
7. Resumen 498
8. Notas histórica y bibliográfica 499
9. Ejercicios 500
1. Introducción 507
2. Función computable y función parcialmente computable 508
2.1. Hipótesis de Church o de Turing 508
2.2. Función computable 508
2.3. Ejemplos 509
3. Numerabilidad de la colección de todas las M.T.'s 510
3.1. Números de Gódel 510
3.2. Catálogo de las M.T.'s 512
4. De nuevo la máquina de Turing universal 512
4.1. Teorema 513
5. Conjuntos recursivos y recursivamente numerables 513
5.1. Conjunto recursivo 514
5.2. Conjunto recursivamente numerable 514
5.3. Dos teoremas más 515
6. Determinación de la finitud del proceso de cálculo.
Problema de la aplicabilidad 515
7. Las máquinas de Turing y los lenguajes de tipo 0 516
8. Resumen 517
9. Notas histórica y bibliográfica 517
7. Complejidad 521
1. Introducción 521
2. Complejidad y máquinas de Turing . 522
2.1. Dificultad de encontrar un criterio universal de complejidad 522
2.2. Complejidad espacial. Complejidad temporal 524
2.3. Máquinas deterministas, máquinas no deterministas
y tipos de complejidad 526
2.4. Algunos resultados de la teoría de complejidad
en máquinas de Turing 527
3. Medidas de la complejidad algorítmica 528
3.1. Complejidad polinómica y complejidad exponencial 529
3.2. Ejemplos de algoritmos con complejidad polinómica 530
3.3. Sinopsis 533
4. Problemas P, NP y NP-completos 536
4.1. El problema P-NP 536
4.2. Completitud y problemas NP-completos 537
4.3. Un tema no cerrado 538
5. Complejidad del software 538
5.1. Física del software 540
5.2. Número ciclomático 543
6. Resumen 544
7. Notas histórica y bibliográfica 545
8. Ejercicios 547
Parte IV
Lenguajes 549
15
2. Gramáticas y lenguajes 559
1. Definición de gramática 559
2. Relaciones entre cadenas de E* 560
2.1. Relación de derivación directa, 560
2.2. Relación de derivación, 560
3. Lenguaje generado por una gramática. Equivalencia de gramáticas 561
4. Ejemplos 561
5. Clasificación de las gramáticas y de los lenguajes 564
5.1. Gramáticas de tipo 0 ó no restringidas 564
5.2. Gramáticas de tipo 1 ó sensibles al contexto 564
5.3. Gramáticas de tipo 2 ó libres de contexto 565
5.4. Gramáticas de tipo 3 ó regulares 565
6. Jerarquía de lenguajes 565
7. Lenguajes con la cadena vacía 566
8. Resumen 568
9. Notas histórica y bibliográfica 568
10. Ejercicios 569
17
4.4. Semántica axiomática 650
5. Procesadores de lenguajes 652
5.1. Ensambladores 652
5.2. Compiladores 661
5.3. Intérpretes 681
5.4. Procesadores de lenguajes declarativos 683
5.5. Herramientas para la generación de procesadores de lenguaje 685
6. Resumen 686
7. Notas histórica y bibliográfica 688
18
Prólogo
"Nada permanece, todo cambia", decía Heráclito. Incluso este libro, que, por
su carácter básico, tiene vocación de permanencia, ha sufrido dos importantes
tipos de cambio.
El primero de ellos es que, por razones empresariales, ha cambiado de sello
editorial. Antes, desde 1987, era conocido en el mundo universitario por el título
de "Fundamentos de Informática" y publicado en la colección Alianza Infor-
mática, de Alianza Editorial. Agotada dicha edición, publicamos ahora un nuevo
libro, bajo el sello de Anaya Multimedia, una división del Grupo Anaya, como
también lo es actualmente Alianza Editorial.
El segundo, y más importante para sus lectores precedentes y para los nuevos,
lo constituye la renovación de sus contenidos, con la inclusión de algunos
capítulos y secciones, la remodelación profunda de otros, la actualización de las
referencias bibliográficas y diversos retoques por aquí y por allá, cambios
orquestados para mantener por un lado las esencias que lo han afianzado como
texto de referencia en numerosos programas de la universidad y, por otro, para
modernizarlo señalando a sus lectores las vías de las aplicaciones más avanzadas.
Estimamos que estos cambios representan en volumen, no en extensión, aproxi-
madamente un 20% del total del libro ya desaparecido. Todo ello se explica con
mayor detalle en la segunda parte de ese prólogo. Su primera parte, que podrán
leer a renglón seguido, es una reproducción del prólogo del libro anterior, que en
buena parte sigue siendo éste.
19
en su difusión casi a formar parte material del mobiliario hogareño. Además de
este efecto distributivo sobre la sociedad, los espectaculares progresos tecno-
lógicos han producido un crecimiento desbordante de la especialización. Los
sistemas operativos, las bases de datos, los lenguajes concurrentes, la progra-
mación lógica, la inteligencia artificial, la arquitectura de ordenadores, las redes,
las herramientas de ayuda para ingeniería de software y tantas otras más espe-
cíficas e instrumentales son áreas de trabajo o técnicas que por sí solas requieren
esfuerzos considerables por parte de quienes pretenden estudiar y seguir su
evolución.
Nadie discute que la especialización es inevitable. También es verdad que los
inconvenientes que genera su abuso dentro de muchos de los dominios de
aplicación de la informática son importantes y cada día somos más los que
pensamos que aquéllos tienden a crecer en la misma proporción en que el
especialista ignora la perspectiva global donde se integra su particular disciplina.
Con mayor razón, si sucede que además desconoce las raíces de sus técnicas
profesionales. Es decir, la proliferación de especialistas demasiado pragmáticos
contribuye a crear una situación que comienza a ser ya preocupante y contra la
que se han alzado voces diversas. Estas voces se muestran unánimes en apelar a
la necesidad de construir o reconstruir una formación más sólida y básica en infor-
mática, dirigida como mínimo a aquéllos que se sienten deseosos de comprender
profundamente su profesión o de implicarse en un papel técnico significativo con
independencia de la especialidad escogida (por no hablar de la lucha contra la
obsolescencia técnica que acecha a todos cuantos trabajamos en este campo).
El libro que presentamos responde a esta llamada, puesto que se ocupa de
algunas de las raíces o fundamentos de la informática. Lo hemos escrito pensando
en los estudiantes universitarios de las ramas de informática, así como en los
profesionales antes mencionados. Estos últimos encontrarán un texto auto-
contenido, desprovisto en lo posible del aparato teórico habitual y preocupado
permanentemente en la tarea de desarrollar aperturas a cuestiones de la más viva
actualidad, como los sistemas borrosos o la complejidad del software, y a cues-
tiones en las que parece vislumbrarse un futuro. En cuanto a los estudiantes,
nuestra experiencia nos dice que, por un cúmulo de circunstancias que no hacen
al caso, se ven obligados con frecuencia a estudiar las materias objeto de nuestro
libro, tal vez, sí, con mayor extensión y formalismo matemático, pero no siempre
bajo condiciones óptimas: apuntes improvisados, textos en lenguas extranjeras,
dispersión de estas mismas materias en distintas asignaturas y por tanto frag-
mentación de su sentido radical (raíces), o desapego del sentido de su aplicación.
Sin poner en tela de juicio la necesidad científica del mejor formalismo posible,
está constatado que dosis excesivas y exclusivas de esa medicina conducen en el
plano educativo a un estéril desánimo de los estudiantes.
Consta el libro de cuatro partes, centradas en cuatro de los pilares básicos sobre
los que se sustenta el edificio teórico y práctico de la informática. Estos son la
lógica, la teoría de autómatas, la teoría de la computación y la teoría de los
lenguajes formales. Por razón del enfoque adoptado, mixto entre teoría y práctica,
y por razones de concisión, aquí los hemos enmarcado bajo los escuetos rótulos
de "Lógica", "Autómatas", "Algoritmos" y "Lenguajes". Para las referencias
cruzadas entre partes del texto se decidió utilizar el vocablo tema en lugar de
parte. Así, mencionaremos el apartado tal del capítulo cual del tema de "Lógica",
y no de la Primera Parte (por ejemplo).
A muy grandes rasgos, podemos esbozar el origen o motivación inicial de cada
área: filosófico (naturaleza del razonamiento humano) para la lógica, tecnológico
(formalización del diseño de circuitos lógicos) para los autómatas, matemático
(determinación de lo que puede o no computarse, y del grado de complejidad de
las computaciones) para la teoría de la computación, lingüísticos (estudio
científico del lenguaje natural) para la teoría de lenguajes. El paso del tiempo ha
ido haciendo emerger nuevas y múltiples relaciones entre dichas áreas y de ellas
con la gran mayoría de los desarrollos técnicos de la informática, por lo que su
cabal conocimiento añade al dividendo reconocido de los buenos fundamentos la
promesa de su permanente rentabilidad. Hemos intentado dotar al libro de
determinadas características, que a continuación resumiremos. En primer lugar,
dos propiedades dignas de mención son por un lado su carácter básico y su
carácter señalizador. El adjetivo básico debe tomarse en su acepción de fun-
damental y no de elemental, ya que estamos presuponiendo en poder del lector los
conocimientos equivalentes a una formación introductoria sólida sobre gene-
ralidades y estructura de ordenadores y sobre programación, más un lenguaje de
alto nivel.
Por el término señalizador queremos aludir a la incorporación de numerosos
apartados que introducen (a menudo en forma pormenorizada) a cuestiones
directa o indirectamente relacionadas con técnicas informáticas muy actuales o
con caminos científicos que se están abriendo. En pocas palabras, buscamos
comprometer - en la medida de lo factible - el interés del lector, y lo que queremos
significar con este objetivo se comprenderá mejor cuando entremos dentro de
unos momentos a relacionar algunos aspectos de los contenidos del libro.
Nuestra esperanza, sin embargo, reside en que su propiedad más notoria sea la
pedagógica, pues no en balde este libro ha tenido una vida anterior en la que a lo
largo de tres ediciones consecutivas y varias reimpresiones ha servido de texto
durante ocho o nueve años en la Escuela Técnica Superior de Ingenieros de
Telecomunicación de Madrid, donde ambos autores somos profesores. Era el
segundo de una obra en dos volúmenes, titulada genéricamente Fundamentos de
los Ordenadores y editada por dicha Escuela.
Sobre ese material el presente libro contiene aproximadamente un cuarenta por
ciento de cuestiones nuevas, lo que ha llevado a eliminar bastantes de las an-
teriores y a remodelar el sesenta por ciento restante. Aunque sus cualidades
didácticas tendrán que ser juzgadas por los lectores, en lo que a nosotros concierne
hemos puesto el máximo cuidado en estructurar y redactar los textos con la mayor
claridad de que hemos sido capaces, y utilizando tanto cuanto hemos creído
conveniente la ayuda de los ejemplos. Al formato también le hemos dado im-
portancia. Y es así que todos los temas se organizan idénticamente por capítulos,
21
y todos los capítulos, menos el primero, poseen la misma estructura, pues
cualquiera que sea su desarrollo terminan con un apartado de Resumen, un
apartado llamado de Notas Histórica y Bibliográfica y (siempre que procede) un
apartado de Ejercicios. El primer capítulo de cada tema es especial, ostenta el
nombre de Ideas Generales y la misión de exponer un planteamiento panorámico
del conjunto de los capítulos y de sus relaciones con los otros tres temas. Al final
del libro una bibliografía ordenada alfabéticamente recoge exclusivamente las
referencias citadas en las Notas de todos los capítulos, por lo que huelga decir que,
dado el enfoque primordialmente orientador de las Notas, la bibliografía no
pretende alcanzar ninguna meta de exhaustividad científica.
Por lo general, de los contenidos de un libro poco cabe decir en un prólogo, ya
que su índice normalmente excusa de tal esfuerzo, salvo que se entienda que no
ha de resultar ocioso captar la atención del lector acerca de diversas singularida-
des. Haremos de éstas un bosquejo rápido.
Refiriéndonos a la primera parte, es del común saber la naturaleza formativa
de la lógica formal para el razonamiento, pero en el campo de la informática
destaca además su naturaleza fundamentadora para numerosas aplicaciones de
inteligencia artificial, de programación y de diseño de circuitos. Este segundo
aspecto es el que hemos enfatizado en el tema de "Lógica", buscando, por
ejemplo, culminar la exposición de las lógicas proposicional y de predicados de
primer orden en el desarrollo de sistemas inferenciales, con la vista puesta en los
sistemas expertos (dominio aplicado y en auge de la inteligencia artificial), a los
que se dedica asimismo un amplio capítulo. Otro nos habla de Otras Lógicas que
se prefiguran en el horizonte como prometedoras bases para los mencionados
dominios aplicativos: ampliaciones de la lógica de predicados (lógica modal y
temporal), lógicas multivaloradas y, en especial, un extenso desarrollo de la lógica
borrosa. Una cuestión clásica como los circuitos combinacionales tiene aquí su
capítulo, lo mismo que en el tema de "Autómatas" lo tienen los circuitos lógicos
secuenciales.
Con respecto a la parte llamada "Autómatas", que versa sobre un área de
expresión típicamente matemática, hemos suavizado mucho su formalismo des-
criptivo ( a fin de cuentas, los autómatas de los que nos ocupamos son construccio-
nes formales). No solamente bastantes teoremas se enuncian y se explican sin
demostrarlos, también se usan ejemplos prácticos sencillos, entre los que, por
ilustrar, citamos el detector de paridad, el sumador, el problema del castillo
encantado, el contador, el reconocedor de una cadena de símbolos, etc. Como una
muestra, entre otras, de nuestro declarado objetivo de interconectar los cuatro
temas del libro está el capítulo dedicado a Autómatas Reconocedores y Lenguajes
Regulares, tradicional por otro lado en el área de estudio de los autómatas.
Menos tradicional en un libro sobre principios básicos resulta aquel otro
capítulo destinado a introducir Otros Autómatas, a saber: las redes de Petri, que
han adquirido considerable predicamento en el ámbito del diseño de sistemas
concurrentes, los autómatas estocásticos, los autómatas de aprendizaje y los autó-
matas borrosos.
En "Algoritmos" se establecen con cuidado definiciones de los conceptos de
algoritmo, programa y máquina y sus profundas interrelaciones. Se ha tomado un
esmero especial para que los lectores comprendan bien el análisis y diseño de
máquinas de Turing, así como el significado de piedra angular de esta máquina en
la teoría informática, en conexión con las cuestiones de la computabilidad. Por
último, un capítulo sobre Complejidad intenta exponer las nociones esenciales
que, en nuestra opinión, todo informático debe poseer sobre un campo teórico y
práctico de gran desarrollo en los últimos años. La complejidad algorítmica se
aplica en dominios tan diversos como la robótica, el diseño de circuitos integrados
a muy grande escala y el diseño de estructuras de datos eficientes.
Los lenguajes formales, en general, y con un mayor detalle los lenguajes libres
de contexto y las relaciones entre los diversos tipos de lenguaje y las estructuras
de máquina capaces de reconocerlos, constituyen el contenido de los cuatro
primeros capítulos de la última parte del libro. Es ésta un área obligada si se quiere
comprender algo sobre la esencia de los lenguajes para ordenador. Precisamente,
el extenso capítulo 5, Aplicaciones a los lenguajes de programación, intenta
salvar un poco la brecha explicativa con la que nos encontramos cotidianamente
entre la teoría de los lenguajes formales y su materialización en las herramientas
que todo el mundo utiliza para construir el software. De las diversas cuestiones
tratadas en ese capítulo, tal vez puedan destacarse por su interés sistemático las
referidas a sintaxis, semántica y procesadores de lenguaje. Como sección incita-
dora de novedades y de futuro es de subrayar el apartado acerca de los lenguajes
de la programación declarativa (programación funcional, programación lógica,
etc.).
Nuestros alumnos de la rama de Informática de la Escuela se encontrarán a
partir de este momento con un texto completamente nuevo. Comoquiera que hace
dos años no se reimprimía aquél del que éste es una reencarnación, ellos se van a
llevar una alegría, acaso un tanto atemperada por causa de los gajes del oficio de
tener que estudiárselo. Al mismo tiempo, estamos razonablemente seguros de que
también se alegrarán (con nosotros) de saber que desde ahora podrán compartir
esta fuente de conocimiento con otros estudiantes y con la vasta comunidad de
profesionales informáticos en el ámbito de la lengua castellana. Que así sea.
Los autores
Febrero, 1987
Anotamos aquí una especie de descripción casi notarial y ordenada (tema por
tema) de las novedades reseñables de este libro con respecto al libro anterior. En
cualquier caso, todos los capítulos aportan modificaciones menores (erratas,
estilo, alguna aclaración adicional, referencias cruzadas, nueva bibliografía), que
han supuesto finalmente más trabajo del que podíamos imaginar.
23
• Tema "Lógica"
Tanto el capítulo 2 (lógica de proposiciones) como el 4 (lógica de predicados)
se han modificado sustancialmente. Concretamente, la semántica queda ahora
definida de manera más rigurosa, porque la experiencia docente nos ha enseñado
que un mayor grado de formalización en este aspecto no perjudica a la com-
prensión de los conceptos (si se insiste con ejemplos adecuados) y deja en mejor
disposición al lector para entender sus aplicaciones (por ejemplo, en el estudio de
las bases de datos deductivas).
El capítulo 3 (circuitos lógicos combinacionales) es el más ligado a la tec-
nología electrónica y, sin embargo, apenas ha sido necesario retocarlo (salvo,
naturalmente, en las orientaciones bibliográficas, que se han actualizado). Esto
tiene fácil explicación: sus contenidos, básicos, no han cambiado. Lo mismo
puede decirse del capítulo 3 del tema "Autómatas" (circuitos secuenciales).
Tampoco el capítulo 5, dedicado a "otras lógicas", requería grandes cambios.
El crecimiento de las aplicaciones de la lógica borrosa en los últimos años
demuestra que nuestra decisión de hacer un especial énfasis en ella era adecuada.
Anecdóticamente, nos congratula que nuestro ejemplo del "aprendiz de con-
ductor", introducido con la intención de motivar al lector, se utiliza con la misma
intención y en términos muy parecidos en el editorial del primer número de una
revista especializada de reciente aparición (IEEE Transactions on Fuzzy Systems,
Feb. 1993).
Al capítulo 6 se le ha dotado de una introducción más amplia y actualizada
sobre la inteligencia artificial y la ingeniería del conocimiento. También se han
añadido algunas observaciones sobre el uso de la lógica de predicados.
• Tema "Autómatas"
El capítulo 5 se ha ampliado con autómatas celulares (cuyo interés ha aumen-
tado en los últimos años por su relación con los fractales y sus aplicaciones en
procesamiento de imágenes) y, sobre todo, con una extensa introducción a los
sistemas de aprendizaje, acompañada de numerosas orientaciones bibliográficas.
• Tema "Algoritmos"
El capítulo 3 sobre programación estructurada es una refundición abreviada de
los capítulos 3 y 4 del anterior libro, en el que se ha añadido una sección sobre
programación con Pascal y C.
El capítulo 4, que hemos titulado "Evolución de la programación" es abso-
lutamente nuevo y -para resumirlo de forma muy esquemática- trata más que nada
de la programación, el análisis y el diseño orientado a objetos. Consideramos a
este estilo de programación un paradigma de futuro muy prometedor, que se
extiende a todo un conjunto de nuevas prácticas informáticas conocido como
"tecnología de objetos". Por esta razón, se ha hecho un esfuerzo en escribir una
sección de "Notas histórica y bibliográfica" especialmente amplia para lo que son
los estándares de este libro. Queremos rendir un tributo de amistad y gratitud a
la insuperable colaboración del profesor Manuel Alfonseca Moreno en la redac-
ción de este capítulo y en la refundición del capítulo 3.
• Tema "Lenguajes"
En principio, el capítulo 5, dedicado a las "aplicaciones a los lenguajes de pro-
gramación", tampoco requería muchos cambios. Desde que se publicó el primer
libro, se ha progresado en cuanto al procesamiento de lenguajes, pero más bien en
las técnicas ligadas a la arquitectura hardware de las máquinas (optimización en
procesadores RISC y vectoriales, etc), no en lo relativo a los principios que aquí
se tratan. Creemos que confirma esta aserción el hecho de que el clásico libro de
Aho, Sethi y Ullman, de 1986, sigue siendo el libro de texto más utilizado. Sin
embargo, nos ha parecido conveniente, puesto que ya se hablaba de lenguajes
declarativos, ampliar la sección del procesamiento de lenguajes con una breve
descripción del funcionamiento de los intérpretes de Prolog. También se ha
añadido una introducción a las herramientas para la generación de procesadores.
Los autores
Septiembre, 1995
25
Parte I
Lógica
1
Ideas generales
1
La definición de "razonamiento" que puede encontrarse en cualquier diccionario recoge implícitamente estas
dos acepciones: "acción y efecto de razonar". El "efecto" guarda relación con lo funcional, o estático, y la
"acción" con lo procesal, o dinámico. El adjetivo "procesal" no es frecuente en informática, pero su adecuación
parece clara: "relativo a los procesos". El reconocimiento de la existencia de tres tipos de modelos (estructurales,
funcionales y procesales) resulta de gran utilidad para el estudio de los ordenadores y los sistemas informáticos
(Fernández, 1994).
29
La lógica se ocupa de los razonamientos en el sentido funcional. De los
aspectos procesales se ocupa la psicología, en el caso de que el "agente" sea
humano. Pero si el agente es un artefacto (que, con la tecnología actual, es lo
mismo que decir un ordenador) entonces es algo propio de la informática (o de
una rama de ésta conocida como "inteligencia artificial", sobre la que hablaremos
algo más adelante y en el capítulo 6).
El calificativo "válido", aplicado a un razonamiento, es sinónimo de "deduc-
tivo", y se aplica a aquel razonamiento en el cual se cumple que si las premisas
son verdaderas entonces podemos asegurar que la conclusión también lo es. Este
concepto reviste gran importancia. En el siguiente capítulo volveremos sobre él,
pero vamos a ilustrarlo ya con un ejemplo:
2
La lógica que, en principio, vamos a considerar es "binaria", y en ella no se puede "dudar": las afirmaciones
son o bien verdaderas o bien falsas. En el capítulo 5 estudiaremos otros tipos de lógica que se adaptan mejor a
los modos de razonamiento humanos. En particular, esperamos, obviamente, que el lector dude, al menos, de la
primera premisa y de la conclusión.
Premisa 2: El individuo u objeto x tiene la propiedadp.
2. Lógica e informática
Así pues, la lógica es una herramienta para el análisis de los razonamientos o
argumentaciones generados por la mente humana. ¿Y qué relación puede haber
entre la lógica y la informática? Pues bien, podemos mencionar, al menos, dos
puntos de contacto:
3
En realidad, la inteligencia artificial es un campo interdisciplinar, que interesa también a la psicología y a la
epistemología; aquí hablamos de "aplicaciones inteligentes de los ordenadores", y, por tanto, nos referimos a la
vertiente más ingenieril.
31
necesarias para ello. Pues bien, la lógica puede verse, precisamente, como un
lenguaje de especificación mediante el cual podemos plantear los problemas de
manera rigurosa. En el tema "Lenguajes" comentaremos los principios de la
programación lógica. Por otra parte, la tarea de programación se complica cuando
se hace preciso considerar procesos concurrentes e intercomunicantes (por
ejemplo, en los sistemas operativos de multiprogramación, en las aplicaciones de
"tiempo real", o en los sistemas distribuidos); ciertas extensiones de la "lógica
clásica", como las lógicas modal y temporal que veremos en el capítulo 5, son
herramientas matemáticas adecuadas para estos casos.
32
Por otra parte, existe una correspondencia muy estrecha, como veremos en los
Temas correspondientes, entre los autómatas y los lenguajes: a cada tipo de
autómata corresponde un tipo de lenguaje, y viceversa. La máquina de Turing es
una máquina lógica, un autómata de un tipo especial, que ha permitido formalizar
el concepto de algoritmo y ha proporcionado una de las aproximaciones teóricas
al campo de la computabilidad, como se verá en el tema "Algoritmos".
Puesto que la terminología asociada a la teoría de lenguajes va a utilizarse en
todas las partes de este libro, parece conveniente presentar ya las definiciones y
los conceptos básicos.
33
5.2. Concatenación
La concatenación de dos cadenas, JC, Y G A*, es una ley de composición
interna sobre A*, es decir, es una aplicación A* xA* —> A*, que consiste en
formar la cadena xy poniendo x delante de y.
Por ejemplo, si A = {a,b,c} y consideramos las cadenas x = ab, y = bba,
entonces xy = abbba, y yx = bbaab.
La representación de la concatenación de una cadena consigo misma puede
abreviarse mediante notación exponencial: x = X; x = x; x etc.
(Obsérvese, aunque sea a título anecdótico, que la longitud cumple respecto a
la concatenación las mismas propiedades formales que el logaritmo respecto a la
multiplicación: lg(xy) = lg(x)+lg(y); \g{x" ) = n.\g(x)).
La operación de concatenación satisface las siguientes propiedades:
d) Ninguna
ningún y e Acadena
tal que(salvo X) tiene inverso: dada x e A(x&X)
xy= X. , no existe
'algoritmo' es un sustantivo.
35
Finalmente,
6. Resumen
La lógica formal es uno de los fundamentos teóricos de la informática, que,
además, tiene importancia práctica en las aplicaciones llamadas de "inteligencia
artificial", en los lenguajes de programación declarativos, en la formalización de
lenguajes de programación en general, y en la programación concurrente.
Los circuitos lógicos, sin otra relación con la lógica formal que la existencia
de un modelo matemático común, son los componentes tecnológicos básicos de
los ordenadores actuales.
Los conceptos de alfabeto, cadenas, concatenación, lenguaje, sintaxis y
semántica, definidos en este capítulo, se utilizarán en el resto de este Tema, y
también en otros Temas del libro.
36
2
Lógica de
proposiciones
1. Introducción
1.1. Variables preposicionales y sentencias
Los lógicos clásicos distinguían entre juicio (el acto mental de pensar o
concebir algún hecho elemental), proposición (lo pensado o concebido en ese acto
mental) y razonamiento (combinación de unas proposiciones llamadas premisas
con otra llamada conclusión).
La noción de proposición se formaliza mediante el concepto de variable
proposicional. Las variables proposicionales representan proposiciones que han
de corresponder a enunciados declarativos, es decir, frases expresadas en el modo
gramatical indicativo.1 Para escribir variables proposicionales utilizaremos las
letras p, q, r, s, t..., eventualmente con subíndices.
'La formalización de modos subjuntivo, condicional e imperativo exige otros tipos de lógica.
39
Una sentencia representa a un enunciado compuesto por proposiciones
(enunciados elementales) y determinadas operaciones primitivas ("y", "o",
"si...entonces...", etc.), operaciones que se formalizan mediante las llamadas
conectivas. Como veremos enseguida, las premisas y la conclusión de un
razonamiento, y el razonamiento mismo, se formalizan con sentencias.
1.2. Conectivas
La conectiva uñaría (o monádica) de negación, "no", cuyo efecto es negar lo
que dice el enunciado que le sigue, se representa mediante el símbolo "->"
antepuesto a la variable proposicional o a la sentencia correspondiente. Así, si con
"p" estamos formalizando "la nieve es blanca", "~>p" representaría "la nieve no es
blanca". (En otros libros se utilizan otros símbolos: "~p", o "p", o "/?'").
Las conectivas binarias (o diádicas) son las que enlazan entre sí a dos variables
proposicionales o a dos sentencias. Las más utilizadas son:
• la conjunción, con símbolo " A " (en otros libros, "&" o "•"), que representa
a la conjunción ("y") del lenguaje natural;
• la disyunción, con símbolo " v " (en otros libros, o "+"), que representa
a la disyunción ("o") del lenguaje natural (en sentido incluyente-, "p v q"
significa "o bienp, o bien q, o bien ambos").
• el condicional, con símbolo " — ( e n otros libros, " =>" o "=>"), que
representa el "si...entonces...". De las dos variables enlazadas por el condi-
cional, la primera (la de la izquierda) se llama antecedente y la segunda,
consecuente.2
• el bicondicional, con símbolo " " (en otros libros, " " o " s"), que
representa el "si y sólo si".
Combinando de forma adecuada variables y conectivas se forman sentencias,
o cadenas correctas en el lenguaje de la lógica de proposiciones.
2
El símbolo " — q u e utilizaremos en adelante, coincide con el que se utiliza en matemáticas para representar
una aplicación, del que también tendremos que servirnos ocasionalmente (de hecho, ya ha aparecido en el
capítulo 1, apartado 5.2, al definir la operación de concatenación de cadenas). Por el contexto, quedará claro a
qué nos estamos refiriendo en cada caso.
Hemos dicho que las variables proposicionales representan proposiciones
(enunciados declarativos elementales), y las sentencias, en general, representan
enunciados declarativos. Esta idea de "representación" se formaliza con una
función que hace corresponder a cada variable proposicional y a cada sentencia
un enunciado, y esta función se llama interpretación. Así, ¿qué representan las
variables p y ql Depende de la interpretación. Una interpretación, i1, podría ser,
por ejemplo:
h (P) = Ia nieve es
blanca;
Ci(p)= i ;
ei(g)= i ;
e2(p)= 1;
e2(q)= 0;
41
si la sentencia es verdadera (valor 1) o falsa (valor 0), tenemos que dar un
significado a las conectivas. El significado umversalmente admitido es el que se
resume en la siguiente tabla:
Cada una de las filas de la tabla corresponde a una evaluación de las variables
proposicionales p y q. En el caso binario sólo hay cuatro evaluaciones distintas de
dos variables proposicionales: ambas falsas ( i 0 ( p ) = 0,i0(q)= 0), una ver-
dadera y otra falsa (e1 (p) = 0, e1 (q) = 1; e2(p) = l,e2(q)= 0) o ambas ver-
daderas (e 3 (p) = 1, e3 (q) = 1). Para cada una de estas evaluaciones, la tabla
muestra la evaluación de la sentencia formada mediante la negación de una
variable proposicional (columna de ->p) o mediante la unión de dos variables
proposicionales con una conectiva binaria (columnas siguientes). Esta forma de
dar significado a las sentencias que se forman con variables proposicionales y
conectivas merece algunos comentarios.
43
caso que nos ocupa podemos asegurar que el condicional no es falso. No lo
es porque, como hemos dicho más arriba, "p —> q" es igual que afirmar que
p es condición suficiente pero no necesaria de q, es decir, que no es la única
condición posible, por lo que perfectamente puede darse el caso de que q
sea verdadero siendo p falso. Es decir, la falsedad del antecedente no hace
falso al condicional. Y si no lo hace falso, lo hace verdadero. Por ejemplo:
"si corro, entonces me canso". ¿Qué ocurre si se dan los hechos de que no
corro y, sin embargo, me canso? Ello no invalida la sentencia, porque no se
dice que no pueda haber otras causas que me producen cansancio.
P <7 p^(q^p)
: _
0 0 1 1
0 1 0 1
1 0 1 1
1 1 1 1
Esto es lo que se llama una tautología: una sentencia que siempre es verdadera
sean cuales sean las interpretaciones de las variables proposicionales que in-
tervienen en ella. (Obsérvese que interpretaciones hay infinitas, pero evaluaciones
diferentes sólo cuatro). A primera vista, este resultado puede parecer paradójico,
porque, considerado como la formalización de un razonamiento en el que "p"
fuese la premisa y " q —> p" la conclusión, viene a decir que si un enunciado (p)
3
Incluso hoy, en ingeniería y en informática, donde el condicional se utiliza, entre otras cosas, para formalizar
"reglas" (capítulo 6, apartado 2.3), persisten concepciones equivocadas (y hasta aparecen publicadas, véase, por
ejemplo, Mendel, 1995) debidas a la identificación (por carencia de una sólida base de conocimientos sobre
lógica) entre "condicional" e "implicación lógica".
es verdadero, todo condicional en el que ese enunciado sea el consecuente es
verdadero, independientemente de que el antecedente sea verdadero o falso. Por
ejemplo, de un enunciado como "tengo frío" se deduce que "si salgo al campo
entonces tengo frío" siempre es verdadero, independientemente de que "salgo al
campo" sea verdadero o falso. Ahora bien, teniendo en cuenta el sentido material
del condicional, no es que "tengo frío" implique "si salgo al campo entonces tengo
frío", sino que la segunda cosa se sigue de la primera (es verdadera cuando la
primera lo es), y entonces la interpretación parece perfectamente razonable: si
tengo frío, tengo frío, pase lo que pase.
45
teriormente, cuando comentábamos el significado el condicional). Lo interesante
es que los resultados del análisis de la sentencia son generales y aplicables a cual-
quier otra interpretación. Veamos algunos ejemplos concretos.
Ejemplo 1.4.1. "Si corro entonces me canso". Ya hemos comentado antes este
enunciado, que podemos formalizar, simplemente, como " p - ^ q " . Si lo
repetimos aquí es para invitar al lector a reflexionar sobre el hecho de que hay
formas alternativas de decir lo mismo. Por ejemplo: "—¡pvq" ("o bien no
corro, o bien me canso, o ambos"), "—t (p A —¡Q) " ("no es el caso que corro y
no me canso"), etc.:
Ejemplo 1.4.2. "Si tengo hambre o tengo sed, entonces voy al bar". Definiendo
las variables proposicionales p, q, r para representar respectivamente "tengo
hambre", "tengo sed" y "voy al bar", podemos formalizar la frase en cuestión
mediante la sentencia:
pv q-^r
3
Como intervienen tres variables, hay 2 = 8 evaluaciones binarias para el
conjunto de las tres, y para cada una de ellas la sentencia tendrá una evaluación.
Las ocho evaluaciones, que se calculan de acuerdo con lo dicho anteriormente, se
resumen en esta tabla de verdad:
p q r pvq pv r
0 0 0 0 1
0 0 1 Ó 1
0 1 0 1 0
0 1 1 1 1
p q r pvq pv q-^r
1 0 0 1 0
1 0 1 1 1
1 i 0 1 0
1 1 1 1 1
P1: c —^ s
47
P2: s -im
C: c —> —im
y la formalization del razonamiento en su conjunto vendrá dada por la sentencia:
(c —>s) A (sir^—im) —> (c —>—im)
Analicemos ahora las evaluaciones de esta sentencia para todas y cada una de
las posibles evaluaciones de sus variables.
j c d s P1 P2 P3 P1 A P 2 aP3 c s
0 0 0 0 1 1 1 1 1 1
0 0 0 1 1 1 0 0 1 1
0 0 1 0 1 0 1 0 1 1
0 0 1 1 1 0 0 0 1
0 1 0 0 1 1 1 1 1 1
0 1 0 1 1 1 1 1 1 1
0 1 1 0 1 0 1 0 1 1
0 1 1 1 1 0 1 0 1
1 0 0 0 1 1 1 1 1 1
1 0 0 1 1 1 0 0 1 1
1 0 1 0 1 1 1 1 1 1
1 0 1 1 1 1 0 0 1
1 1 0 0 0 1 1 0 1 1
1 1 0 1 0 1 1 0 1 1
1 1 1 0 0 1 1 0 1 1
1 1 1 1 0 1 1 0 0 1
49
Vemos que la sentencia es una tautología, y, por consiguiente, el razonamiento
es válido. No obstante, en casos como éste la lógica de proposiciones empieza a
ser un lenguaje demasiado limitado para representar todos los matices del
lenguaje natural. Concretamente, aquí hemos hecho una pequeña "trampa": tal
como se han definido las variables proposicionales, lo representado p o r — > —¡c"
sería: "si alguien es judío entonces no es cierto que alguien esté en la cocina", lo
cual no es exactamente lo que queremos decir, y lo mismo con las otras tres
sentencias.
Lo que ocurre es que con la palabra "alguien" del lenguaje natural se representa
a un miembro cualquiera de un colectivo, es decir, formalmente, a una variable
(no una variable proposicional). Nuestras proposiciones hacen referencia a
propiedades de tales variables que determinan subconjuntos del colectivo, y esto
es algo que no se puede formalizar en lógica de proposiciones. Si aquí hemos
podido llegar a una formalization ha sido "fijando" ese "alguien", es decir,
considerando que en todas las premisas y en la conclusión se trata del mismo
individuo (como si, en vez de "alguien", hubiésemos dicho, por ejemplo, "Isaac")
y suponiendo implícitamente que si el razonamiento es válido para un individuo
cualquiera, lo es para todos.
se devalúa'.
P3: 'O bien baja la inflación y se devalúa la peseta, o bien los impuestos deben
subir'.
Nuestro político elabora luego un informe para el Ministerio de Economía que
concluye con la siguiente recomendación:
51
Los axiomas y los teoremas constituyen las tesis del sistema axiomático, y
pertenecen al lenguaje del cálculo; las reglas de formación y de transformación
pertenecen al metalenguaje del cálculo.
La formulación de los axiomas no es arbitraria ni fácil. Tiene que satisfacer
dos exigencias metalógicas imprescindibles:
Conviene, además, que los axiomas sean independientes, es decir, que ninguno
de ellos pueda demostrarse a partir de los restantes. Esta condición no es fácil de
comprobar. Prueba de ello es que en el sistema PM, que veremos en el apartado
2.5, se proponían inicialmente cinco axiomas, y sólo años más tarde se comprobó
que uno era redundante (se podía demostrar a partir de los otros cuatro).
El lector más interesado por las aplicaciones informáticas de la lógica que por
ésta en sí misma puede pensar que todo esto es de poca utilidad. Pero no es así.
En las aplicaciones, efectivamente, no tiene un interés especial la demostración
de teoremas a partir de unos axiomas. Lo realmente interesante es mecanizar los
procesos de inferencia. Es decir, dadas unas premisas o hechos comprobados
como verdaderos en una determinada situación, poder deducir conclusiones para
esa situación. Esto es lo que llamaremos un sistema inferencial: un conjunto de
reglas (pertenecientes al metalenguaje de la lógica) que permiten ejecutar
inferencias y unas metarreglas (pertenecientes al metametalenguaje) que dicen
cómo aplicarlas. Ahora bien, veremos en el apartado 5 que los teoremas del
sistema axiomático son precisamente la base de las reglas que permiten realizar
inferencias. Por otra parte, para acercarnos al ideal de "poder asegurar" el correcto
funcionamiento de los programas es preciso trabajar sobre una base teóricamente
sólida y rigurosa. (La pragmática de la informática dice que nunca se puede
asegurar que un programa funciona correctamente,4 pero poco a poco se avanza
hacia la posibilidad de la demostración formal de la corrección de los programas.
Véanse a este respecto el apartado 6 del capítulo 3 del tema "Algoritmos" y el
apartado 4.1 del capítulo 5 del tema "Lenguajes").
4
Hay una antigua "ley" de la informática práctica que dice: "Todos los programas reales contienen errores
mientras no se demuestre lo contrario, lo cual es imposible" (Gilb, 1975).
2. Sintaxis
2.1. Alfabeto
Entramos ya a definir formalmente la lógica de proposiciones como un
lenguaje, y en este apartado presentamos el cálculo de proposiciones. El alfabeto
que utilizaremos será el formado por los siguientes símbolos:
ip v'<?) r
rv) -^pq-.(
(p v q-,) r
53
Definición 2.2.2. Llamaremos secuencia deformación a toda secuencia finita
de expresiones, Av A 2 , ..., An, en la que cada A¡ satisface al menos una de las
tres condiciones siguientes:
Definición 2.2.3. Llamaremos sentencia a toda expresión An tal que existe una
secuencia de formación AVA2, ...,An. Y ésta será una secuencia de forma-
ción de An (puede no ser la única). Obsérvese que, según esta definición, todas
las expresiones que componen una secuencia de formación son sentencias.
a) (p V q) <-> (q vp)
c)(pv(qvr))<r*(pv(qvr))
d)(pA(qAr))<^(pA(qAr))
A->B
—i(—i(—iA v B ) v —1(—iB v A ) )
55
o bien, si se permite utilizar la conectiva previamente definida " A ",
(—iA v B) A (—iB v A)
Al. (pvp)
A2. q —» (pvq)
Como hemos avanzado en el apartado 1.5, la idea es que con estos axiomas y
unas reglas de transformación, junto con las definiciones dadas más arriba que
permiten sustituir unas conectivas por otras, se demuestran teoremas. Vamos a
definir las reglas de transformación y el proceso de demostración, pero antes
hemos de introducir una operación previa: la sustitución.
2.5.2. Sustitución
Definición 2.5.2.1. Dadas unas variables proposicionales, pvp2, • ••>/?„ y unas
sentencias cualesquiera, BltB2, ...,Bn, llamaremos sustitución a un conjunto
de pares ordenados
s= {B1/pvB2/p2, ...,Bn/pn}
Definición 2.5.2.2. Dadas una sentenciaA que contiene (quizás, entre otras) las
variables proposicionales pvp2, •••>P„ y una sustitución s, la operación de
sustitución en A de esas variables proposicionales por las sentencias
Bv B2, ...,Bn, consiste en poner en A, en todos los lugares donde aparezca la
variable pt, la sentencia B¡ que le corresponde de acuerdo con s, y esto para
todo i=l...n. El resultado es una expresión que representaremos como As.
Teorema 2.5.2.3. SiA es una sentencia y s una sustitución, As es una sentencia.
La demostración, que dejamos al lector, es sencilla: basta con ver que si tanto
A como todas las B¡ tienen secuencias de formación, entonces As tiene
también, al menos, una secuencia de formación. Es interesante observar que
este teorema, como otros que iremos dando, es, en realidad, un "metateorema"
para la lógica de proposiciones.
2.5.3. Demostraciones y teoremas
Definición 2.5.3.1. Llamaremos demostración (o prueba formal) a toda
secuencia finita de sentencias AVA2, ...An, en la que cada A(. satisface, al
menos, una de las cuatro condiciones siguientes:
a) A¡ es un axioma;
De modo similar a lo que hacíamos al definir las sentencias, podemos dar una
definición recursiva de tesis mediante cuatro reglas de transformación (corres-
pondientes a las cuatro condiciones anteriores):
2.5.4. Reglas de transformación
RTl. SiA es un axioma, entonces A es una tesis
RT2. (Regla de sustitución). SiA es una tesis en la que aparecen pv p2, ..., pn
y Bv B2, ..., Bn son sentencias, entonces A {B±/pv . ,.,Bn/pll} es una tesis.
57
2.5.5. Ejemplos de demostraciones en el sistema PM
Teorema 1: (p —> q) —» [ (r —>/?)—> (r q) ]
Demostración:
Teorema 3: p —
Demostración:
[ (p O q) A (q r) ] —> (p <-> r)
59
• Las leyes de distributividad\
[ (p A q) v r] [ (p v r) A (p v q) ]
[ (p v g) A r] <-> [ (p A r) v («j A r) ]
[p (q v r) ] o [ (p g) v (p -» r) ]
[p (9 A r) ] [ (p -> Í) A (p -> r) ]
3. Semántica
Las sentencias del lenguaje lógico permiten representar conocimientos acerca
de la realidad. Como paso previo a la formalización de esos conocimientos se
establece un modelo conceptual de la realidad, o conceptualización, que acota los
objetos y aspectos de la realidad que las sentencias van a representar. En el caso
de la lógica de proposiciones, una conceptualización es, simplemente, un conjunto
de proposiciones.
La semántica establece, como sabemos (capítulo 1, apartado 5.4), una corres-
pondencia entre las construcciones del lenguaje y los objetos que designan. En
este caso, entre las sentencias del cálculo de proposiciones y los elementos de la
conceptualización.
Representaremos por CP al conjunto (finito) de elementos de la conceptua-
lización, por P a un conjunto (finito) de variables proposicionales, por S al
conjunto (infinito) de sentencias que pueden construirse conP, por Sn al subcon-
junto (infinito) de S cuyas sentencias tienen exactamente n variables propo-
sicionales, y por S" al subconjunto (finito si n es finito) de S cuyas sentencias
tienen un número de conectivas igual o inferior a n.
60
determinadas operaciones definidas en él. A cada conectiva definida en el
alfabeto debe corresponder una operación en V.
Teorema 3.1.4. Dada una evaluación ei, existe una (y sólo una) extensión del
dominio de e¡ a S, a la que llamaremos E¡, tal que satisface estas dos
condiciones:
a) ( V A e S ) (Ei(-A)= -£t(A))
(Adviértase que, aunque los símbolos utilizados sean los mismos, "-•" y
representan distintas cosas en el primero y en el segundo miembro de esas
igualdades: en el primero, son las conectivas utilizadas en el alfabeto, que se
aplican a variables o a sentencias para obtener otras sentencias; en el segundo, son
las operaciones definidas en el conjunto V).
Demostración'.
61
• Para n=0, E°¡ (A) = e¡ (A) ;
• Supuesto que existe E", definimos E"+1 así:
+1
si A e S", Ef (—A) = -Ef (A) ;
+1
si A, Be S", Ef (AkB) = Ef (A) kEf (B)
De este modo, hemos construido una aplicación É ¡ + ' que cumple^ las
condiciones impuestas, y que está definida para toda sentencia de S
b) Unicidad. E°¡ es única, puesto que es igual a e¡. Y si E" es única, E"+1
también lo será, puesto que se ha construido de manera única.
Corolario: E¡ está unívocamente determinada por e¡. Esto quiere decir que,
dada una evaluación de variables proposicionales, puede calcularse la
evaluación de cualquier sentencia construida con esas variables propo-
sicionales.
3.2. Satisfacción
En el apartado anterior hemos definido el concepto de evaluación de una
manera general, lo cual permite aplicarlo a lógicas en las que las proposiciones (y
las sentencias) pueden tomar valores intermedios entre "verdadero" y "falso".
Veremos algunos de estos tipos de lógica en el capítulo 5. De momento, y hasta
entonces, nos limitaremos a la lógica clásica, o "binaria".
- , ( 0 ) = 1; - ( 1 ) = 0;
0 A 0= 0; 0 A 1= 0; 1 A 0= 0; 1 A 1= 1;
0 v 0= 0; 0 v 1= 1; 1 v 0= 1; 1 v 1= 1;
Al: pvq
A2:p A q
=
h (p) Ia nieve es blanca; e2 (p) = 1
63
3.3. Tautologías y contradicciones
Por tanto, la satisfacción de una sentencia depende, en general, de la interpre-
tación dada a sus variables proposicionales. Pero hay algunas sentencias que
siempre se satisfacen, sea cual sea la interpretación, y otras que no se satisfacen
nunca. A las primeras se les llama "tautologías", y a las segundas, "contra-
dicciones". Más formalmente:
Definición 3.3.1. Diremos que una sentencia A es una tautología si (y sólo si)
(Vi) (E¡ (A) = 1) . Utilizaremos la notación "EA " para indicar que "A es una
tautología".
Así, todas las sentencias cuyas cuatro evaluaciones sean las de la clase
Cx(p A q, —i (-¡p v —iq) , —i (p —> —iq) , etc.) son equivalentes entre sí.
Demostración-.
65
3.6. Las conectivas binarías
Hasta ahora venimos utilizando cuatro conectivas diádicas o binarias (binarias,
en el sentido de que enlazan dos variables proposicionales; además, e inde-
pendientemente de ello, estamos considerando una lógica binaria, en el sentido de
que V={0,1}). Hemos visto que, gracias a algunas equivalencias (apartado 2.4),
podemos limitarnos a usar una sola de ellas, junto con la negación. Pero también
podemos hacer lo contrario: definir nuevas conectivas. Veamos cuántas. Si
comparamos la tabla del apartado 1.3, en la que se definía el significado de las
conectivas utilizadas, con la tabla del apartado anterior, en la que se muestran las
evaluaciones de las dieciséis clases de equivalencia de las sentencias construidas
con dos variables proposicionales, vemos inmediatamente que las conectivas
"A", " V", " — y se corresponden con las clases de equivalencia
Cv C7, C13 y Cg, respectivamente. Y para cada una de las otras doce clases
podemos definir una nueva conectiva binaria. Por ejemplo, C6 correspondería a
la disyunción exclusiva, para la que a veces se utiliza el símbolo "©".
Las equivalencias dadas en el apartado 2.4 nos permitían representar las clases
de equivalencia Cv C 13 y C 9 mediante sentencias que sólo utilizan las conectivas
y " v ". Lo mismo puede hacerse para las otras clases. Por ejemplo, la clase
C 0 se representaría mediante ->(p v —>p), la C2 mediante ->(—p v q), etc.
Igualmente, podríamos trabajar con la pareja "A", O con la "->", " ", etc.
Pero también es posible representar cualquier clase de equivalencia utilizando
solamente una conectiva. Ello puede hacerse con dos de las dieciséis conectivas
binarias:
Por ejemplo, las equivalencias que permiten sustituir a las conectivas más
utilizadas por una cualquiera de éstas son:
formada por un conjunto de base, B, con tres operaciones definidas en él, suma
(+), producto (.) y complementación ( ), tales que se cumplen los siguientes
axiomas:
30 e B tal que Va e B, a + 0= a
a + a= 1 y a • a= 0
Va, b 6 B:
a + b =b+ a
a•b= b•a
Va, b, c e B :
67
a + (b + c)= (a + b) +c
a • (b • c)- (a • b) • c
Va, b, c e B:
a + (b- c) = (a + b) • (a+ c)
a+ (b • c) = (a + b) • (a+ c)
Idempotencia:
Va e B:
a + a= a
a - a= a
Absorción".
Va, b e B:
a+ 1 = 1
a - 0= 0
a + a- b= a
a • (a + b)= a
de Morgan:
Va, b e B:
(a + b)= (a-5)
(a - b)= a + b
etc.
68
Las operaciones "->", " v " y " a " definidas en el caso de evaluación binaria
(Definición 3.2.1) cumplen, como es fácil comprobar, los axiomas del álgebra de
Boole para el conjunto V={0,1}, con 0= 0 y 1= 1. Por tanto,
69
tanto, (A A -.A) G C 0 . Pero, por otra parte, tal como se han definido las
operaciones en Qn, podemos asegurar que ( A v - A ) e (C¡ v —iC¡) y que
(A A -iA) G (C¡ A —\C¡) . Ello nos permite concluir que C¡ v —iC¡= CN y
C.-A-iC— C 0 .
Como consecuencia de la estructura de álgebra de Boole de la lógica de
proposiciones, las transformaciones que estudiaremos en el capítulo 3 y que
aplicaremos a los circuitos (formas canónicas, formas mínimas, etc.), son también
aplicables a las sentencias de la lógica de proposiciones.
Definición 4.3.1. Dada un álgebra de Boole <B, +,., >, se llama elemento
atómico a cualquier be B (b^O) tal que para todo as B se cumple que o
bien a • b= 0 o bien a • b= a.
a= + ...+¿>í-(l< a,p,...£<«)
5. Sistemas inferenciales
5.1. Análisis y generación de razonamientos
La lógica es, entre otras cosas, una herramienta para analizar los procesos de
razonamiento que habitualmente se expresan en lenguaje natural. Pero dada la
diversidad de matices de éste, no puede pensarse en su traducción automática al
lenguaje de la lógica formal (al menos, no todavía; esto está íntimamente rela-
cionado con uno de los campos de investigación en inteligencia artificial, el del
procesamiento del lenguaje natural). Ahora bien, una vez obtenida la traducción
formalizada de un determinado proceso de razonamiento, puede analizarse éste,
y puede completarse con nuevas conclusiones de modo automático.
En la presentación del ejemplo 1.4.3 ya avanzábamos algo que formalizaremos
en el apartado 5.2: los razonamientos pueden formalizarse como sentencias
condicionales cuyo antecedente es la conjunción de las premisas y cuyo conse-
cuente es la conclusión, y la condición necesaria y suficiente para que el razo-
namiento sea válido es que la sentencia así formada sea una tautología (o, equiva-
lentemente, una tesis). Esto nos permite analizar razonamientos, pero no obtener
conclusiones de modo automático. Lo que necesitamos ahora no es un sistema
axiomático con el que podamos demostrar, por ejemplo, que YA, sino un procedi-
miento para que, dadas PvP2, . . . , podamos obtener Cv C2, ..., tales que
i- (P1AP2A...^C1)
Y (P1aP2A...^C2)
[ (p -> A (-14 r) ] (p r)
71
Para analizar tal razonamiento y averiguar si es correcto hemos de ver que la
sentencia es un teorema, o, equivalentemente, que es una tautología. Es decir,
podemos proceder de dos maneras:
a) Tratando de demostrar la sentencia en el sistema axiomático. (En este caso,
basta aplicar la sustitución (—¡q/q) en la primera de las leyes de
transitividad enunciadas en el apartado 2.5.6).
b) Construyendo la tabla de verdad, para ver si la sentencia es una tautología,
que es lo que hacíamos en los ejemplos del apartado 1.4. Esta forma podría
parecer, en principio, más fácil, pero obsérvese que, por ejemplo, el
teorema
A
liPi-^Pi) (Pi^Pi) A . . . A (p9->pw)] (Pi^Pw)
10
requeriría una tabla de 2 = 1024 líneas (una para cada una de las distintas
evaluaciones del conjunto de variables proposicionales).
Pero lo que más nos interesa no es el análisis del razonamiento, sino su
generación. En este caso, dadas las premisas
PvP^^q
P2: -,q r
qué conclusión (o conclusiones) podemos obtener? Pues bien, dado que la
sentencia anteriormente escrita es un teorema en forma de condicional que tiene
como antecedente la conjunción de Pt y P2, podemos afirmar como conclusión
el consecuente:
Y(P1AP2A...AP„^C)
[p A (p q) ] -> q
73
o bien, si A y B son sentencias, utilizando la sustitución { A / p , B/q},
[A A ( A - > 5 ) ]
Pl:c->s
P2: s <-> -im
P2 puede descomponerse en dos:
C: c —» —m
Lo que hacíamos en la exposición del ejemplo 1.4.3 era ver que la sentencia
(P, A P 2 ) —> C es una tautología. La consistencia del sistema axiomático nos
permite, de esta forma, asegurar que esta sentencia es también una ley. De aquí,
aplicando el teorema 5.2.2, podemos decir, entonces, que P l y P2 implican C, y,
así siendo, finalmente, por la definición 5.2.4 concluimos que el razonamiento es
válido.
¿Es éste el único razonamiento válido con esas premisas? No, porque, según
las definiciones 5.2.1 y 5.2.4, basta con que una sentencia se satisfaga para todas
las evaluaciones que satisfacen a las premisas para que tal sentencia sea una
conclusión de tales premisas, siendo indiferente lo que ocurra con las otras
evaluaciones. Rehaciendo la tabla de verdad, podemos poner en ella diversas
conclusiones válidas:
c s m A Pz PxaP2 c c C" c
0 0 0 1 0 0 1 1 0 1
0 0 1 1 1 1 1 1 1 1
0 1 0 1 1 1 1 1 1 1
0 1 1 1 0 0 1 1 1 1
1 0 0 0 0 0 1 0 0 1
1 0 1 0 1 0 0 0 1 0
1 1 0 1 1 1 1 1 1 1
1 1 1 1 0 0 0 0 1 0
75
C: c —> —m
C: c —> s A -I m
C":
C": m^—iC
etcétera.
Demostración:
h[(?1AP2a...aP„^C)]
{ P 1 A P 2 a . . . AP„}I=C
77
5.5. Forma clausulada de la lógica de
proposiciones
La regla de inferencia que estudiaremos en el apartado 5.7 se aplica úni-
camente a una forma especial de sentencias, pero vamos a ver que toda sentencia
de la lógica de proposiciones puede expresarse de modo equivalente en esa forma.
Definición 5.5.2. Diremos que una sentencia está en forma clausulada si tiene
la forma:
(LN V/ 1 2 V . . . ) A (L21 VL22 V A ...
Demostración:
—¡(AaB) = —A v —\B
—I (A v B) = —A A —iB
3. Paso a forma clausulada, distribuyendo " A " sobre " V" mediante la equi-
valencia:
[(A1AA2) vA3] ES [ ( A 1 V A 3 ) a (A2 vAJ) ]
-•{[(PA?) ^ [(^vr) A H A - , ? - ) ] }
79
contrario (una contradicción), representaríamos el resultado final como la única
cláusula —ip v p .
-ip v —i q v r
Sin embargo, aunque este ejemplo pueda inducir a pensar lo contrario, la forma
clausulada no es única: pueden existir sentencias que estén en formas clausuladas
diferentes y que sean equivalentes. Para ilustrarlo, consideremos esta sentencia:
(p<->?) A i (p A q A r)
p1Ap2A...pk^q1\/q2v ...vqm
Con esta nueva escritura vemos que la lectura metalógica de una cláusula es:
"si se dan como antecedentes todos los literales negativos, entonces se siguen
como consecuentes uno o varios de los literales positivos".
Hay algunos casos particulares de cláusulas que tienen un interés especial en
las aplicaciones:
a) Cláusulas de Horn con cabeza. Son las que solamente tienen un literal
positivo:
b) Cláusulas de Horn sin cabeza. Son las que no tienen ningún literal positivo:
v A
(-PI V
N P 2
V
••• ~<Pk) =~>(Pi PiA ••• A
Pk)
(9i V ? 2 V •••
d) La cláusula vacía, (p, en la que han desaparecido todos los literales, y que,
como veremos, aparece en un proceso inferencial cuando las premisas son
incompatibles.
81
pv^q
—ipvrvs
—i qv rv s
Como toda regla de inferencia, la resolución se fundamenta en una tesis,
concretamente, en
K(npvA) A (pvB) -> ( A v J ) ]
modus ponens:
A
A —> B
~B
resolución:
A
-AvB
~B
modus tollens:
-iB
A - > £
resolución:
S
-IA v B
transitividad:
~—A
A B
B^C
A C
resolución:
-A vB
—B v C
—A v C
Para completar el sistema inferencial tenemos que dar una estrategia sobre la
que basar el procedimiento de aplicación de la resolución. El más inmediato es el
de la búsqueda exhaustiva:
Pl: (p <->q)
P2: -I (p A q A r)
En forma clausulada:
Pía: {—p v q)
P2b:(pv^q)
Cl: (npv-,r)
C2: ( - i ^ v - i r )
83
Resolviendo con todas las parejas que pueden formarse con C1, C2 y las
premisas, se puede comprobar que no se obtienen más conclusiones. (Por ejemplo,
la resolución de C1 con Plb conduce de nuevo a C2). Si se analizan todas las
conclusiones posibles (construyendo la tabla de verdad) se comprobará que todas
ellas corresponden a algún elemento del conjunto formado por estas cinco
cláusulas (Pía, Plb, P2, C1, C2) más las conclusiones "triviales" (por ejemplo,
de Pía son conclusiones triviales —i (pv qv r) y —¡p v q v —¡r) o a una cláusula
formada por la disyunción de dos o más de ellas, o a una conjunción de dos o más
de ellas.
P l : —ic v s
P2a:—ts v —m
P2b:mvs
Resolviendo P l y P2a,
C: —i c v —m
C": c —»s A —im es, en forma clausulada, (—¡c v s) A (—ic v —>m) , conjun-
ción de P l y C
P l : —j v —ic
P2.'7 v —,d
P3: —is v c
De P l y P2, Cl: - , c v - , d
D e P 2 y C 2 , C3: -,dv-,s
5.8. Refutación
La refutación es un procedimiento útil cuando lo que se pretende no es generar
cuantas conclusiones sean posibles, sino comprobar si una determinada
conclusión es válida o no.
o, lo que es lo mismo,
85
De P2 y d resulta como resolvente j;
6. Resumen
En el apartado 1 hemos introducido, de manera informal y apoyándonos en
ejemplos, muchos de los conceptos que en los apartados siguientes se han definido
de manera más rigurosa: variables proposicionales, conectivas, sentencias,
interpretaciones y evaluaciones.
El apartado 2 se ha dedicado a la presentación del cálculo de proposiciones
como un sistema axiomático: se establecen unos axiomas ("verdades inde-
mostrables") y unas reglas de transformación que permiten demostrar teoremas.
Los axiomas y los teoremas son las tesis (o leyes) del sistema. Podemos ilustrar
estas definiciones con un diagrama de Venn:
Variables proposicionales
Expresiones
Sentencias
Axiomas
Demostraciones
Figura 3.25.
86
La semántica permite establecer la correspondencia entre las construcciones
simbólicas del cálculo y los elementos de la realidad que pretendemos representar
con ellas. En el apartado 3 hemos definido los conceptos de interpretación
(asignación de elementos de la realidad a variables proposicionales y sentencias)
y evaluación (asignación, para una determinada interpretación, de valores de
verdad o falsedad a las variables proposicionales y sentencias).
Así, la evaluación de una sentencia como verdadera o falsa depende de la
interpretación, pero hemos visto que ciertas sentencias son tautologías-, su
evaluación es verdadera para todas las interpretaciones posibles de las variables
proposicionales que la forman. El sistema axiomático es completo si toda
tautología es una tesis (t A —» h A ), y es consistente si toda tesis es una tautología
(fc A —» I-A)5
Hemos dedicado el apartado 4 a la estructura de álgebra de Boole de la lógica
de proposiciones, modelo que utilizaremos en el capítulo 3.
Finalmente, en el apartado 5 nos hemos centrado en los razonamientos válidos
(o deductivos) y en los sistemas inferenciales. Aquí ya no consideramos
"axiomas" (en el sentido que se le da a esta palabra en un sistema axiomático),
sino premisas, que son sentencias supuestamente verdaderas en un determinado
contexto, pero que no tienen por qué serlo siempre (algunos textos de lógica
aplicada llaman "axiomas" a estas premisas). Una premisa puede ser, por ejemplo,
una simple variable proposicional. La idea es que, supuesto que las premisas sean
verdaderas, el sistema pueda inferir de ello conclusiones. El diagrama ahora
podría ser este otro:
Figura 2.2.
3
Las dos expresiones que acabamos de escribir entre paréntesis son sentencias de la lógica de predicados. En
e f e c t o , » ( - » y " t " son predicados que se aplican a la sentencia A
87
Hemos definido el concepto de razonamiento válido, o deductivo, como aquél
formado por un conjunto de premisas, {Pl, Pl,..., Pn}, y una conclusión, C, tales
que las premisas implican lógicamente a la conclusión. Y hemos visto que la
condición necesaria y suficiente para que el razonamiento sea válido es que la
sentencia ( P l A P 2 A ... A Pn —> C) sea una tesis.
Después hemos definido los conceptos de regla de inferencia, proceso infe-
rencial y sistema inferencial, así como de consistencia y completitud de un
sistema inferencial. Un sistema inferencial es completo si, para cualquier conjunto
de premisas, el sistema es capaz de inferir todas las conclusiones que junto con
las premisas constituyen razonamientos válidos, y es consistente si, para cualquier
conjunto de premisas, toda conclusión que llegue a inferir el sistema es tal que
junto con las premisas constituye un razonamiento válido.
Por último, hemos presentado la "resolución". En la forma clausulada de la
lógica todas las sentencias se expresan como colecciones (conjunciones) de
cláusulas, siendo éstas colecciones (disyunciones) de literales. La resolución es
una regla de inferencia que se aplica a dos cláusulas (generatrices) y, si tienen una
pareja de literales complementarios, produce como conclusión otra cláusula
(resolvente). Esta regla nos permite realizar de manera única inferencias que en
los tratados de lógica requieren distintas reglas.
Concluiremos este capítulo con tres consideraciones importantes que tienen
que ver con la aplicación a la informática de los conceptos estudiados:
89
En los años 60 se desarrollaron diversos métodos orientados al procesamiento
automático de las inferencias, de los que el más conocido es el de "resolución",
debido a Robinson (1965). Lo que aquí hemos presentado es la particularización
a la lógica de proposiciones de ese método, que en el capítulo 4 estudiaremos ya
en su integridad.
Hay libros de introducción a la lógica cuya lectura, además de recomendable,
es muy amena. Destacamos el de Ferrater y Leblanc (1962) (donde se llama
"lógica sentencial" a lo que aquí hemos denominado "lógica de proposiciones") y
el de Deaño (1986) (donde se le llama "lógica de enunciados"). El ejemplo 1.4.3
está tomado del primero, y el 1.4.4, del segundo (Deaño hace uso de este ejemplo,
procedente de Lewis Carroll, para ilustrar la necesidad de la lógica de predicados;
aquí hemos visto que también se puede formalizar en lógica de proposiciones,
aunque abusando un poco del lenguaje natural). En el libro de Deaño nos hemos
inspirado también para la explicación sobre el significado del condicional y la
diferencia entre "leyes" y "reglas de inferencia". El ejemplo 1.4.5 es una adapta-
ción de otro similar de Gilbert (1976), un libro sobre álgebra aplicada cuyo
capítulo 2 se dedica a la lógica y los circuitos lógicos.
No obstante, y por las razones apuntadas al final del resumen, los textos más
recomendables sobre lógica aplicada a la informática tratan directamente con la
lógica de predicados, y los citaremos en el capítulo 4.
8. Ejercicios
8.1. Formalizar las siguientes frases como sentencias proposicionales, y
analizar sus tablas de verdad:
" La verdad es una brújula loca que no funciona en este caos de cosas
desconocidas" (Baroja).
" Se puede conocer la utilidad de una idea y, sin embargo no acertar a
comprender el modo de utilizarla" (Goethe).
" Ese lapso de tiempo, corto si se le mide por el calendario, es inter-
minablemente largo cuando, como yo, se ha galopado a través de él"
(Kafka).
"El mismo diablo citará a la Sagrada Escritura si viene bien a sus
propósitos" (Shakespeare).
8.2. Analizar los siguientes razonamientos:
P l : 'Si no llueve, salgo al campo'.
P2: 'Si salgo al campo, respiro'.
C: 'Respiro sí y sólo si no llueve'.
90
P l : 'Si un monte se quema, algo suyo se quema'.
P2: 'Algo suyo se quema sí y sólo si es usted descuidado'.
P3: 'Si usted no es descuidado, es acreedor a una felicitación'.
C: 'Si usted no es acreedor a una felicitación, entonces es que un monte
se quema'.
Pl:'Si un país es una democracia, el Presidente del Gobierno se elige
por sufragio universal'.
P2: 'En España, el Presidente no se elige por sufragio universal'.
C: 'Luego España no es una democracia'.
El mismo anterior, modificando así la primera premisa:
P l : 'Si el Presidente de un país es elegido por sufragio universal, ese
país es una democracia'.
Aplicar la resolución y la refutación a los anteriores razonamientos.
b) Pl:p q
Pl: r ^ —>p
(Contrastar estos dos casos con el del ejemplo 5.7.4)
c)Pl:p^q
Pl: r ^ p
P3: —¡r —» —i
PA: —i (s A —ir )
P5: -, t->s
d) P l : p - > g v r
Pl:q^>p
91
tí
V- - ^
Jf! ¿t'4,
iSV
3
Circuitos lógicos
combinacionales
1. Introducción
El hardware puede describirse y estudiarse en varios niveles de abstracción.
En el más bajo ("nivel físico-electrónico") se consideran los fenómenos físicos
básicos y las propiedades de los materiales (semiconductores, metales, dieléc-
tricos) que explican el funcionamiento de los componentes electrónicos (resisto-
res, diodos, transistores, etc.). En el siguiente ("nivel electrónico-circuital") se
hace abstracción de tales fenómenos: se da por supuesta la existencia de los
componentes, con comportamiento funcional conocido, y se estudian los circuitos
que resultan de su interconexión. Aquí vamos a movernos en el nivel de abstrac-
ción inmediatamente superior (el "nivel lógico"): supuesto que disponemos de
unos circuitos básicos, las "puertas lógicas", estudiaremos cómo pueden inter-
conectarse para conseguir sistemas con determinado comportamiento. En este
nivel, hacemos abstracción tanto de los detalles del nivel "físico-electrónico"
como de los del nivel "electrónico-circuital". Por ejemplo, una de las cosas de las
93
que hacemos abstracción es el valor real de los potenciales eléctricos. En los
circuitos digitales se opera siempre con sólo dos valores diferentes de tensión.
Según sea la tecnología utilizada, así serán esos dos valores, que, en el nivel
lógico, los representaremos por los símbolos "0" y "1". El "0" podría
corresponder, en el circuito electrónico, a una tensión de 0 voltios (o, con mayor
realismo, a un margen, por ejemplo, de 0 a 1 voltios), y el "1" a 5 voltios (o al
margen 3-6). Pero también podría ser al revés (corresponder el "0" a 5v y el "1" a
Ov), o podríamos tener otros valores u otros márgenes de tensión totalmente
diferentes. Nosotros consideraremos perfectamente definido el comportamiento
de los componentes básicos ("puertas") mediante relaciones de entrada-salida que
se refieren sólo a los valores lógicos.
Hay dos ideas esenciales que conviene tener muy claras desde el principio para
la buena comprensión de este capítulo:
94
sentarlas en los diagramas son los indicados en la figura 3.1. Su función se
corresponde exactamente con la que simbólicamente realizan las conectivas "->",
" v " y " a " en la lógica de proposiciones. Es decir, si siguiésemos el convenio de
representar por "p" y "q" las entradas de una puerta "OR", por ejemplo, la salida
estaría representada por la sentencia "p v q", lo que quiere decir que el nivel
lógico de esa salida será "0" si los niveles lógicos de las dos entradas son "0", y
"1" si una de las entradas, o ambas, tienen el nivel lógico "1".
NOT OR AND
Figura 3.1.
En este capítulo vamos a adoptar, sin embargo, otra notación, más habitual
cuando se trabaja con el álgebra de Boole: en lugar de "->", " v " y " A"
utilizaremos" ","+" y ".", respectivamente. Y para las variables que representan
valores lógicos (lo que luego llamaremos "variables booleanas") emplearemos las
letras x, y, z, eventualmente con subíndices.
Teniendo en cuenta lo dicho, la figura 3.2, que especifica las funciones de las
tres puertas mediante tablas de verdad, se explica por sí sola.
NOT OR AND
x
* / X y / x y /
0 1 0 0 0 0 0 o
1 0 0 1 1 0 1 o
1 0 1 1 0 0
1 1 1 1 1 1
Figura 3.2.
Las puertas "OR" y "AND" pueden tener más de dos entradas. Las operaciones
que realizan son, formalmente, las mismas operaciones conocidas del álgebra de
Boole, y, por tanto, tienen las mismas propiedades, y, concretamente, la propiedad
asociativa. Esto nos permite decir, por ejemplo, que la función de una puerta
"AND" de tres entradas (figura 3.3, izquierda) es la misma del circuito formado
por dos puertas "AND" de dos entradas conectadas según indica la figura 3.3
(derecha). Y lo mismo podríamos decir para las puertas "OR".
95
Figura 3.3.
3. Circuitos
Las puertas se pueden interconectar teniendo en cuenta la regla de que la salida
de una puerta cualquiera puede servir de entrada a una o varias puertas, pero nunca
pueden conectarse juntas dos o más salidas1. Los sistemas así construidos serán
circuitos lógicos con una o varias entradas y una o varias salidas. Como existe una
correspondencia biunívoca entre las operaciones que realizan las puertas y los
operadores del álgebra de Boole, si representamos por variables (x¡, y¡, etc.) los
valores lógicos de las entradas del circuito, podremos escribir una fórmula para
representar cada salida, en la que intervendrán esas variables y los símbolos " ",
"+" y ".". A cada salida de un circuito lógico corresponderá así una fórmula. Por
otra parte, el comportamiento del circuito puede especificarse mediante una tabla
de verdad para cada salida que nos dé los valores lógicos que toma esa salida para
todas y cada una de las posibles combinaciones de valores lógicos de las entradas.
La mejor manera de comprender todo esto es a través de ejemplos. En cada uno
de los ejemplos que siguen sólo se considera una salida, cuyo valor lógico se
simboliza por"/'.
Ejemplo 3.1
Fórmula:
f= x + y-z
Circuito: El de la figura 3.4..
Figura 3.4.
1
En realidad, esta regla tiene excepciones: por una parte, el número de entradas que puede alimentar la salida
de una puerta tiene una limitación tecnológica; por otra, a veces pueden conectarse directamente las salidas de
dos o más puertas, consiguiendo una función "OR" o "AND" "implícita". Pero estas excepciones entran ya en
el nivel de descripción "electrónico", más que en el "lógico", por lo que no las consideraremos aquí.
96
Tabla de verdad:
X y z f
0 0 0 0
0 0 1 0
0 1 0 0
0 1 1 1
1 0 0 1
1 0 1 1
1 1 0 1
1 1 1 1
Ejemplo 3.2
Fórmula:
f= x-y + x- z + x- y- z + x- y- z
Circuito:
El de la figura 3.5.
x y z
D-
Figura 3.5.
Tabla de verdad:
97
Ejemplo 3.3
Fórmula:
/= x1 • (x2 + x4) + x3
Circuito:
El de la figura 3.6.
iX3- O I
Figura 3.6.
Tabla de verdad:
*1 *2
X
3 f
0 0 0 0 0
0 0 0 1 0
0 0 1 0 1
0 0 1 1 1
0 1 0 0 0
0 1 0 1 0
0 1 1 0 1
0 1 1 1 1
1 0 0 0 1
1 0 0 1 1
1 0 1 0 1
1 0 1 1 1
1 1 0 0 0
1 1 0 1 1
1 1 1 0 1
1 1 1 1 1
Ejemplo 3.3
Fórmula:
y— X* #2 1 1
"í" 1
-^3 " "I"
Circuito:
El de la figura 3.7.
*3
Figura 3.7.
Tabla de verdad:
Ejemplo 3.5
Fórmula:
f= x-y+ (x + y) -z
Circuito:
El de la figura 3.8.
z
Figura 3.8.
Tabla de verdad:
x y z f
O O O O
0 0 1 O
0 1 0 O
0 1 1 1
1 0 0 O
1 0 1 1
1 1 0 1
1 1 1 1
Ejemplo 3.6
Fórmula:
/= x-y-z(x +y) • z
Circuito:
El de la figura 3.9.
Figura 3.13.
Tabla de verdad:
Ejemplo 3.7
Fórmula:
/= x-y-z + x- y- z + x- y- z + x- y- z
Circuito:
El de la figura 3.10.
y«i
D
Figura 3.10.
Tabla de verdad:
101
especificaciones, tenga el menor número posible de puertas . Este es el problema
de la minimización, que trataremos en el siguiente apartado. Para poder abordarlo,
necesitamos formalizar algunos conceptos; los modelos matemáticos de los
circuitos nos permitirán diseñar éstos de forma óptima.
En los ejemplos hemos comprobado que la función de cada salida de un
circuito puede expresarse mediante una tabla de verdad, pero que esta relación no
es biunívoca: puede haber varios circuitos con la misma tabla; diremos que todos
ellos realizan la misma función de conmutación. Por otra parte, también se ve en
los mismos ejemplos que a cada circuito podemos asociar de manera biunívoca
una "fórmula", construida por variables lógicas y operaciones" ","+" y "."; estas
fórmulas corresponden a lo que definiremos como formas booleanas.
( f . + f ^ . - X ^ f ^ X ) + fJ(X)
( f r f ^ x ^ f i W -fjiX)
X y z h h fl k fl+fl fl -fl
0 0 0 0 0 1 1 0 0
0 0 1 0 0 1 1 0 0
0 1 0 0 0 1 1 0 0
0 1 1 1 1 0 0 1 1
1 0 0 1 0 0 1 1 0
1 0 1 1 1 0 0 1 1
1 1 0 1 1 0 0 1 1
1 1 1 1 1 0 0 1 1
y cuyos elementos atómicos son las 2" funciones que hacen corresponder
todas las n-tuplas a 0, excepto una.
Demostración:
Las operaciones sobre funciones de orden n dan como resultado otras fun-
ciones de orden n, por lo que Fn es cerrado bajo las tres operaciones. Por otra
103
parte, tal como se han definido los elementos neutros, es inmediato que, para
cualquier f¡, resulta que (/ ¿ +/„)= f¡ y que (/, • fN) = f¡. El resto de los
axiomas del álgebra de Boole (capítulo 2, apartado 4.1) se cumplen también
por el hecho de que las operaciones entre funciones se han definido a partir de
las operaciones en el álgebra de Boole <{0,1}, +, ., >. Finalmente, es fácil
comprobar que las funciones que hacen corresponder todas las «-tupias, salvo
una, a 0, cumplen la definición de elemento atómico (capítulo 2, definición
4.3.1): su producto por cualquier otra función da como resultado o bien f0 o
bien el mismo elemento atómico.
Las seis "fórmulas" de los ejemplos del apartado 3 son ejemplos de formas
booleanas. Como los símbolos "+","." y " " se corresponden, respectivamente,
con las puertas "OR", "AND" y "NOT", a cada circuito lógico (o, mejor, a cada
salida del mismo) le corresponde una forma booleana, y viceversa.
En realidad, el lenguaje de las formas booleanas es el mismo de la lógica de
proposiciones, cambiando las conectivas " v", " A " y "->" por los símbolos "+",
ii ii y ii ii^ reS p ec tivamente. El hecho de que las variables y las formas booleanas
puedan tomar los valores "0" y "1" de un álgebra de Boole binaria se corresponde
con la evaluación binaria de variables proposicionales y de sentencias. Por todo
ello, lo que sigue viene a ser una repetición de lo que ya hemos estudiado en el
capítulo 2, y lo presentaremos de forma resumida.
4.3.2. Evaluación de formas booleanas
Definición 4.3.2.1. Dado un conjunto de variables booleanas, A, llamaremos
función de asignación de valores (o, simplemente, asignación) a una aplica-
ción del conjunto A en el conjunto {0,1}:
v:A —» {0, 1}
Vk(A) (AzCi)
105
La forma booleana del ejemplo 3.1 es equivalente a la del ejemplo 3.2, la del
3.3 es equivalente a la del 3.4, y las tres formas booleanas de los ejemplos 3.5,3.6
y 3.7 son equivalentes entre sí.
Este teorema es, en realidad, el mismo que habíamos visto para las clases de
equivalencia entre sentencias (capítulo 2, apartado 4.2), y su demostración es la
misma que allí apuntábamos (como también para el teorema 4.2.4 de este
capítulo): basta con ver que se satisfacen los axiomas del álgebra de Boole. En
cuanto a los elementos atómicos, basta con ver que se cumplen las condiciones de
su definición (definición 4.3.1 del capítulo 2): el producto de cualquier c( por un
elemento atómico da como resultado c0 o c¡.
107
mismo que entre las sentencias construidas con dos variables proposicionales
y con evaluaciones binarias, véase el apartado 3.5 del capítulo 2). Los
productos canónicos son cuatro: x • y, x • y, x • y, x • y (en notación abreviada,
"3", "2", "1" y "0", respectivamente), que corresponden a los cuatro elementos
atómicos c1 (clase de equivalencia de las formas cuyas evaluaciones son "0"
excepto para x = 1, y = 1), c 2 (idem, excepto para x = 1, y = 0), c4 (idem,
excepto parax = 0,y = 1) y cg (idem, excepto para x = 0,_y = 0). Cualquier otra
clase de equivalencia puede representarse como suma de dos o más productos
canónicos. Por ejemplo, la c9 tiene evaluación "1" para dos asignaciones: para
x = 0, y = 0, y para x = 1, y = 1; su forma canónica será la suma de los dos
productos canónicos correspondientes: x • y + x • y (o, en notación abreviada,
2(0,3)).
(en notación abreviada: X (3,4,5,6,7)). Del mismo modo, el lector puede compro-
bar que la forma canónica que corresponde a los ejemplos 3.5,3.6 y 3.7 es la forma
booleana del último de ellos (en notación abreviada: X (3,5,6,7)).
5. Minimización
5.1. Principios
Para encontrar formas booleanas equivalentes a una dada y más sencillas que
ella podemos utilizar dos equivalencias:
b) Idempotencia:
109
Por ejemplo, consideremos la forma booleana de tres variables:
x-y-z + x- y- z + x- y- z + x- y- z
Observamos que el último producto es adyacente a cada uno de los otros tres
(pero éstos no lo son entre sí). Podemos reducirlo con uno cualquiera de ellos; si
lo hacemos con el primero, resulta:
y-z + x- y- z + x- y- z
con el segundo:
x-y-z + x- z + x- y- z
y con el tercero:
x -y • z +x •y • z +x •y
Estas tres formas booleanas son equivalentes entre sí, y equivalentes a la
primera. Pero se puede conseguir otra con menos operaciones si previamente
"complicamos" la forma de partida teniendo en cuenta la propiedad de idempo-
tencia: se puede sumar dos veces el producto x • y • z, y cada uno de estos tres
productos se podrá reducir con uno de los tres primeros. El resultado es:
x-y + x- z + y- z
x • (y + z) +y • z
00 01 11 10
0 0 2 6 4
1 1 3 7 5
\clX
xjcA \ 00 01 11 10
00 0 4 12 8
01 1 5 13 9
11 3 7 15 11
10 2 6 14 10
*,=o x=1
•\jy-3
01 11 10 00 01 11 10
00 0 4 12 8 00 16 20 28 24
01 1 5 13 9 01 17 21 29 25
11 3 7 15 11 11 19 23 31 27
10 2 6 14 10 10 18 22 30 26
Figura 3.11.
es la que puede verse en la figura 3.12. Como se indica en ella, se agrupa uno
de los "1" (el que corresponde a x • y • z) con los tres que le son adyacentes.
111
Cuando se agrupan dos "1" desaparece una variable: la que tiene asignación
"0" en un caso y "1" en otro. El resultado es: x • y + x • z + y • z.
xy
00 01 11
0
0
n
—i—i—
0
y.z
Figura 3.12.
formando un cuadrado eliminamos dos variables: las que tienen valor "0" en
unos casos y "1" en otro. El resultado final para este ejemplo es: x + y • z.
0 0 fi\
ft
0 V1/ v /
x.y
xy
00 01 11 10
ñ
0 0 0
<T J>kí O
x .y x .z
z
Figura 3.14.
xy
00 01 11 10
x.y x.y
Figura 3.25.
113
Ejemplo 5.2.5. En la figura 3.16 podemos ver un ejemplo de minimización de
una forma booleana de cuatro variables: £(0,8,9,10,11,14).
00 01 11 10
\
00 1
) 0 0 ;< 1 i
X
' I
01 0 0 0 I 1 .
' I
11 0 0 0 I 1
I
10 0 0 <7 I 0!
V
f — X2 • • X4 + • X2 "H X¡ » X^ • X4
Figura 3.16.
00 01 11 10
00 '1 0 0
01
11 '1
0 0
1
/ f
I
~
'H
I
/ I '
10 1 / 1
/ /
_- O V
X, • X0
Figura 3.13.
Ejemplo 5.2.7. En la figura 3.18 podemos ver otras posibles agrupaciones en
tablas de Karnaugh de cuatro variables.
00 01 11 10 00 , 01 11
00 / f
01 \1
( y
11^ \i i/
10
2 4
00 01 11 10 *3*4 00 01 11 10
f
*3*4
OOM
01 i \ 1 i
11 1 i
10A i i \i
-OÍ IS" (y 0
Figura 3.18.
00 01 i 11 10 1 \ 00 01 11 10
1
00 0 0 'vi _ _1 / 00 0 0 0 0
01 ' T ; T 1 1T1 01 'J ) "_1/ ^ 0 ,'1
V/ —=1" \
11
11
10
0
0
0
0
0 0
\Vo 0
0
0 0
0 '1
__
0
r i
)
\ I
Figura 3.19.
115
En resumen, el método de Karnaugh consiste en recubrir todos los "1" que
aparecen en la tabla con el menor número posible de grupos (menor número total
de sumandos) y de modo que cada grupo sea lo más grande posible (menor
número de variables en cada uno de los productos que forman los sumandos).
6. Ejemplos de aplicación
6.1. Máquina de escrutinio
Supongamos que hay un comité formado por cuatro miembros, de los que uno
es presidente, y que las decisiones se toman por mayoría simple, decidiendo el
voto del presidente cuando existe empate. Se trata de diseñar una máquina con
cuatro entradas (un pulsador para cada miembro) cuya salida dé el resultado de la
votación. Llamando A, B, C, y D a las variables lógicas que representan el estado
del pulsador de cada miembro (donde A es el que corresponde al presidente) y S
a la que representa la salida del circuito, la especificación viene dada por la
siguiente tabla de verdad:
A B c D s
0 0 0 0 0
0 0 0 1 0
0 0 1 0 0
0 0 1 1 0
0 1 0 0 0
0 1 0 1 0
0 1 1 0 0
0 1 1 1 1
1 0 0 0 0
1 0 0 1 1
1 0 1 0 1
1 0 1 1 1
1 1 0 0 1
1 1 0 1 1
1 1 1 0 1
1 1 1 1 1
116
En la figura 3.20(a) tenemos esta misma información representada en una tabla
de Karnaugh. Vemos que pueden formarse tres grupos de cuatro "1" y un grupo
de dos, con el resultado:
S= AB+AC+AD+BC • D= A • (B + C + D) +BCD
A
vAB B
CD^ 00 01 11 10 C
D
00 0 0 0
-B.D (b)
01 0 0 /T
11
10
0
0
<c
vi 1J
-B.C
B.C.D A.B
BCD
(a) (C)
Figura 3.20.
117
o D). De acuerdo con todo esto, podemos especificar el circuito mediante esta
tabla:
A B c D s
0 0 0 0 0
0 0 0 1 0
0 0 1 0 0
0 0 1 1 0
0 1 0 0 0
0 1 0 1 1
0 1 1 0 1
0 1 1 1 1
1 0 0 0 1
1 0 0 1 1
1 0 1 0 1
1 0 1 1 1
1 1 0 0 1
1 1 0 1 1
1 1 1 0 1
1 1 1 1 1
X y r' s r
0 0 0 0 0
0 0 1 1 0
0 1 0 1 0
0 1 1 0 1
1 0 0 1 0
1 0 1 0 1
1 1 0 0 1
1 1 1 1 1
119
s xy
00 01 11 10 xy oo 01 11 10
0 0 1 0 1 0 0 0
f: 0
1 1 0 1 0 1
Figura 3.22.
0 ( 1
— Gí; —
1)
s= x-y-r'+x-y-r'+x-y-r' + x- y-r'
r= x • y + r' • (x + y)
sxy
(b) 00 I 01 I 111 10
• \
00 0 11 ij¿ ) 1 I
01 £¡ 0 0 0
11 JÓ 0 TA 0
10
5 1 ñ vZj
'
Figura 3.23.
r
r'. (x + y)
x \x + y
x.y
o ^ •«4
r. (x + y + r')
x.y. r
Figura 3.24.
121
x*y=z y,' yo
0*0=0 0 0 0 0 0 0 0 0
0*1=0 0 0 0 1 0 0 0 0
0*2=0 0 0 1 0 0 0 0 0
0*3=0 0 0 1 1 0 0 0 0
1 *0=0 0 1 0 0 0 0 0 0
1 *1=1 0 1 0 1 0 0 0 1
1 *2= 2 0 1 1 0 0 0 1 0
1 *3= 3 0 1 1 1 0 0 1 1
2*0=0 1 0 0 0 0 0 0 0
2 *1.= 2 1 0 0 1 0 0 1 0
2*2=4 1 0 1 0 0 1 0 0
2*3=6 1 0 1 1 0 1 1 0
3*0=0 1 1 0 0 0 0 0 0
3*1=3 1 1 0 1 0 0 1 1
3*2=6 1 1 1 0 0 1 1 0
3*3=9 1 1 1 1 1 0 0 1
00 01 11 10 00 01 11 10
00 0 0 0 0 00 0 0 0 0
01 0 0 0 0 01 0 0 0 0
0 0 1 0 0 0 0
dl)
11 11
10 0 0 0 0 10 0 0
00 01 11 10 00 01 11 10
00 0 0 0 0 00 0 0 0 0
01 0 0 (i > 01 0 T \ 0
0 y
11 0 (T^ 0 11 0 11 1 y 0
10 0 cr~ T ) 0 10 0 0 0 0
\ y
Figura 3.25.
122
De las tablas de Karnaugh (figura 3.25) obtenemos las formas booleanas:
z 3 = xx- x0 • y1-
123
y otra que permite añadir agua fría. Las especificaciones funcionales son las dadas
en la siguiente tabla:
Se supondrá que el termómetro tiene dos terminales de salida, cada uno de los
cuales puede estar en uno de entre dos niveles de tensión (a los que daremos los
niveles lógicos 0 y 1). Si la temperatura es demasiado alta, el primer terminal, TL,
está en el nivel 1 (y el segundo, T2, en el 0), si es demasiado baja ocurre lo con-
trario, y si está entre los límites prefijados ("temperatura normal") ambos son 0.
Los detectores del nivel del agua dan también niveles 0 y 1. Uno de ellos, Nt,
da 1 si el nivel es demasiado alto, y el otro, N2, da 1 si es demasiado alto (de modo
que 0 en ambos indica "nivel normal").
En cuanto a la salida, V, es la válvula para sacar agua y V2 es la válvula para
añadir agua. El nivel lógico 0 corresponde a la activación de la válvula, y el 0 a la
desactivación. Análogamente, para que el calefactor, o resistencia, (.R) caliente se
dará 1, y para que no actúe, 0.
La parte lógica del sistema será un circuito con cuatro entradas (Tv T2,NV
N2) y tres salidas ( V v V2, R). Las tablas de verdad se obtienen inmediatamente
de las especificaciones. Hay siete combinaciones de valores de entrada que son
imposibles (las que corresponden a 7\= T2= 0 , y las que corresponden a
Nx= N2= 0), por lo que las funciones de V1} V2 y R están incompletamente
especificadas. Aprovecharemos este hecho, del mismo modo que en el ejemplo
6.3, para minimizar tales funciones. Si el lector sigue los pasos necesarios llegará
al siguiente resultado:
V1=NÍ;V2=T1+N2;R=T2
Y el circuito (en lo que respecta al nivel lógico) sólo necesita de una puerta
"OR", como indica la figura 3.27.
.v;
Figura 3.27.
Demostración:
125
¿1= I ( ñ l j )
;= i
Aplicando los teoremas de de Morgan, obtenemos:
/ a \-i f « / II \
C: = = n
n h Uh n i h
v i 7 S=1 y S=1 '
que será la representación de c¡ en la segunda forma canónica. Y como c, es única
para c¡, esta representación también será única.
f_
0 0 0 1
0 1 1 0
1 0 1 0
1 1 0 1
f = x-y + x-y
De aquí,
f=x-y + x-y= (x • y) • (x^y) = {x + y) • {x + y)
que será la segunda forma canónica de/(en notación abreviada, II (0,3)).
Ejemplo 7.1.5. Para los ejemplos 3.1 y 3.2, fijándonos en los "0" de la tabla
de verdad, resulta:
/= x-y-z + x- y-z + x- y- z + x- y- z
f= (x + y + z) • (x + y + z) • (x + y + z) • (x + y + z) = 11(0,1,2,4)
/= (x^ + + + x^) • (x^ + + Xg + ^4) ' +^2 + ^2+ x • (Xj +^2 + ^2+ ^4) •
b) Idempotencia:
A A=A
/= (x + y) • (x + z) • (y + z)
que es la forma mínima en producto de sumas. Aplicando la propiedad dis-
tributiva, podemos escribir otras formas equivalentes:
127
(x + y) • (z + x • y) = (y + z) • (x + y • z) = (x + z) • (y + x • z)
Ejemplo 7.2.1. Si agrupamos los "0" en la tabla de Karnaugh del ejemplo 6.1
(fig. 3.28(a)) resulta:
S= AD+AC+AB+BCD
S= (A+D) • (A + C) • (A+B) • (B + C + D)
S= (A+B C D) • (B + C + D)
El circuito (fig 3.28(b)) es igual que el de la figura 3.20(b), cambiando los tipos
de puertas.
A.C B.C.D
1 11
00
00
¿| 1
/
10 1
B •
n (Is
01 0 J 1 B •
Vo
1 O
B
11 0 1 1 1
10 o\ 1 1
(b)
A.B
A.D B C D
D '
(a)
(C)
Figura 3.13.
Ejemplo 7.2.2. Para el caso del ejemplo 6.2, obtenemos ahora (figura 3.29):
S= AB+ACD
S= (A+B) • (A + C +D) = A + B (C + D)
A.C.D
00 0, 11 10
00 1 1
íOO
01 0 1 1 1
A.B
11 0 1 1 1
10 1 1 1
Figura 3.29.
00 01 11 10
00 (0} 1 0 1
01 K 0
v y /
1
11 VC 0 J 1 Vo
10 1 0 0 0
Figura 3.30.
129
8. Otras puertas
Igual que en lógica de proposiciones, donde teníamos dieciséis conectivas
binarias (entre dos variables proposicionales), también podemos definir dieciséis
operaciones distintas entre dos variables lógicas, a las que corresponderían otras
tantas puertas de dos entradas, aunque cuatro de ellas no tienen sentido: las que
dan siempre "0" o "1" a la salida (las tautologías y contradicciones de la lógica)
y las que dan el valor de una de las entradas independientemente del que tome la
otra. Ahora bien, las más utilizadas, aparte de las ya vistas ("NOT", "OR" y
"AND") son "ORX" ("OR" exclusivo), "NAND" y "NOR", cuyas tablas de verdad
son las de la figura 3.31. Para simbolizar las operaciones que realizan estas puertas
utilizaremos los símbolos " ©", y " I ", respectivamente (que son los mismos
que ya habíamos visto en el capítulo 2 para las correspondientes conectivas).
OR EXCLUSIVO X y f
0 0 0
0 1 1
1 0 1
1 1 0
x y f
NAND
0 0 1
0 1 1
1 0 1
1 1 0
x y f
NOR
0 0 1
0 1 0
1 0 0
1 1 0
Figura 3.31.
Y del mismo modo que unas conectivas pueden expresarse en función de otras
(capítulo 2, apartado 3.6), también la función que realiza una puerta puede
realizarse con un circuito formado por otras. Por ejemplo, la suma lógica con
"AND" y "NOT" (figura 3.32(a)), el producto lógico con "OR" y "NOT" (figura
3.32(b)), "NAND" y "NOR" con "AND" y "NOT" o "OR" y "NOT" (figura
130
3.32(c) y (d)), etc. Obsérvense, en la figura, las representaciones alternativas para
"NAND" y "NOR": la misma función se realiza complementando la salida de una
puerta "AND" que complementando las entradas de una "OR", y viceversa.
(a)x+y=x-y=x\y
o bien
-Oo-
Oo o bien
(c) x\y=x-y=x +y
(^)x\,y=x+y=x-y
Figura 3.32.
De acuerdo con las dos formas canónicas vistas en el ejemplo 7.1.4 (que no
pueden reducirse), la puerta "ORX" puede realizarse con puertas "NOT", "OR" y
"AND" con el circuito de la figura 3.33(a) o con el de la figura 3.33(b). La
disponibilidad directa de puertas "ORX" permite realizar de forma más simple
algunos circuitos. Por ejemplo, la salida z, del ejemplo 6.4 puede también
escribirse:
Por tanto, si puede utilizarse una puerta "ORX" el circuito se simplifica algo
con relación al de la figura 3.26.
131
(a) f=x¡.x1 + xl.x2
a) x— x ' x=
X ~ X ^ X— X X
x • y= x+ y= x\\,y = (x 1 x) (x ¿ y)
c ) x + y= x| y= (x| x) | (y| y)
x + y= x + y-(x i y)= (x i y) i (x 4 y)
Teorema 9.2.1:
= | (yi\y2\---\ym) |-l
(Para demostrarlo basta con aplicar dos veces las leyes de De Morgan).
133
Ejemplo (corresponde al Ejemplo 5.2.6):
(Obsérvese que cuando uno de los productos consta de una sola variable, en este
caso x 3 , este producto puede representarse como x3 • x3, y de ahí que al aplicar
el teorema pongamos x3 |x 3 (es decir, x3), y no x3).
Teorema 9.4.1:
Ejemplo:
= {x i x) i ((x 4- x) 4 y) 4- (y I (z i z))
(Aquí podemos hacer una observación similar a la del ejemplo anterior: si una de
las sumas sólo tiene un sumando , x en este caso, como jt= x + x, al aplicar el
teorema ponemos x i x= x, en lugar de x).
10. Resumen
Las funciones de conmutación y las formas booleanas son dos tipos com-
pletamente distintos de modelos para los circuitos lógicos combinacionales. Una
134
función de conmutación es un modelo funcional: indica "lo que hace" el circuito,
desde el punto de vista de cuáles son sus "respuestas" (valores lógicos de la salida)
para los posibles "estímulos" (valores lógicos de las entradas). Por el contrario,
una forma booleana es un modelo estructural", indica cómo se conectan los
componentes (puertas) del circuito. A cada circuito que sólo tenga una salida le
corresponde una forma booleana, y viceversa. Pero a una misma función de
conmutación le corresponden infinidad de circuitos (y, por tanto, de formas
booleanas).
Frecuentemente, de las especificaciones verbales se llega inmediatamente a las
funciones de conmutación (una para cada salida), expresadas como tablas de
verdad. Y el problema que se plantea es el de elegir de entre todos los circuitos
(formas booleanas) posibles el más sencillo (forma booleana con menos opera-
ciones)2. A la solución de este problema general ha ido encaminado todo el
desarrollo de este capítulo, que podemos resumir así:
d) Las álgebras de Boole , < Fn +, ., > y < Cn, +, ., > son isomorfas,
porque tienen el mismo número de elementos (card(/ 7 n ) = card(Cn ) = 22").
Por tanto, a cada función de conmutación de orden n le corresponde
biunívocamente una clase de equivalencia entre formas booleanas de n
variables, y, por tanto, un conjunto (infinito) de circuitos equivalentes. Esta
doble correspondencia se ilustra en la figura 3.34.
2
Esta es, desde luego, una simplificación del problema general. No siempre el circuito con menos puertas es el
de menor coste de realización, y esto es especialmente cierto desde la aparición de los circuitos integrados.
135
Figura 3.34.
f) Desde un punto de vista práctico, lo que interesa es, dada una función de
conmutación, o una forma canónica, o una forma booleana cualquiera,
encontrar la forma booleana que esté en la misma clase de equivalencia y
que tenga el menor número posible de operaciones (que corresponderá a un
circuito con el menor número posible de puertas). Es el problema de la
minimización, para cuya solución hemos estudiado el método más sencillo:
el de las tablas de Karnaugh.
12. Ejercicios
12.1. Considérese el ejemplo 5.7.3 del capítulo 2. Cada cláusula se corres-
ponde, en el lenguaje de las formas booleanas, con una suma de
variables. (Concretamente, P2 es una suma canónica). Representar en
una tabla de Karnaugh las evaluaciones de la conjunción de las tres
cláusulas, y ver cómo las dos aplicaciones de la regla de resolución que
hacíamos allí se corresponden con reducciones de términos adyacentes,
y tienen su representación gráfica como agrupaciones de "0".
137
12.3. El mismo ejercicio anterior, considerando que los números que se
presentan a la entrada están siempre comprendidos entre 0 y 9.
Diseñar un circuito para pasar del "8-4-2-1" a uno de los otros dos. El
circuito tendrá cinco entradas: las cuatro correspondientes a los bits del
código fuente y una entrada de control, C. Si C=0 entonces sus cuatro
salidas deben dar los bits del código "2-4-2-1" que correspondan, y si
C=1 en la salida se deberá obtener el código "exceso de 3".
138
valor "1"). Diseñar un codificador con cuatro entradas (y dos salidas).
Generalizar el diseño para ocho entradas (tres salidas).
12.7. Un multiplexor es un circuito con 2" entradas de información binaria
y n entradas de selección y una sola salida. Esta salida toma el valor de
la entrada de información que haya sido seleccionada por las entradas
de selección. Diseñar un multiplexor con n=3.
139
4
Lógica de
predicados de
primer orden
1. Introducción
1.1. Variables y constantes
En el capítulo 2 analizábamos un ejemplo (el 1.4.4) en el que parecía natural
introducir la idea de variable para referirnos a un miembro de un colectivo. Hay
razonamientos cuyo análisis es imposible si no es formalizando esa idea. Volva-
mos, por ejemplo, al clásico:
141
Si tratamos de formalizar este razonamiento en lógica de proposiciones, para
la primera premisa podríamos escribir la sentencia" h —> m". La segunda premisa,
al ser un simple enunciado declarativo, se formalizaría como una simple variable
preposicional,"s".Yde tales dos premisas es imposible inferir ninguna conclusión.
Lo que ocurre en este ejemplo es que en la primera premisa estamos diciendo
algo de todos los miembros de un colectivo, que, por tanto, es válido para uno
cualquiera de ellos, al cual representaremos con una variable. En la segunda,
hablamos de un valor determinado de esa variable, de una constante. Y la relación
de deducibilidad que aplica el razonamiento es un paso de lo general a lo
particular: lo que se dice de todos los miembros de un colectivo es válido para uno
cualquiera de ellos. Para expresarla es preciso entrar en la composición de los
enunciados, cosa que no puede hacerse en lógica de proposiciones, en la que todo
enunciado declarativo simple se representa como una variable proposicional.
143
1.5. Cuantificadores
Representaremos al cuantificador universal con el símbolo " V" seguido de la
variable que se cuantifica. Para delimitar el alcance de la cuantificación, pon-
dremos la sentencia cuya variable se cuantifica entre paréntesis. Por ejemplo,
es una sentencia cerrada, que formaliza la frase "para todo x, si x tiene la propiedad
H, entonces tiene la propiedad M", mientras que
(Vx) ( H ( x ) ) —>M(x)
sería una sentencia abierta ("si todos los x tienen la propiedad H, entonces x,
cualquiera, tiene la propiedad M"), lo mismo que
("para todos los x, si x tiene la propiedad H, entonces y tiene la propiedad M", que
viene a ser lo mismo de antes, supuesto que x e y tienen un rango común).
El otro cuantificador, también conocido del lenguaje matemático, es el
cuantificador existencial, que representaremos con el símbolo "3", y que se lee
" existe un... tal que...".
En realidad, bastaría con uno solo de los dos cuantificadores, y si usamos los
dos es por comodidad (por acercar el lenguaje lógico al lenguaje natural). En
efecto, decir que todos los individuos en consideración tienen cierta propiedad es
lo mismo que decir que no es cierto que exista algún individuo que no tenga esa
propiedad:
Y decir que existe un x (al menos) que tenga cierta propiedad es lo mismo que
decir que no es cierto que para todos los individuos la propiedad no se da:
(3x) ( P W ) =-,(VjC ) ( n P W )
(V*)(P(x))
es equivalente a
y la sentencia cerrada
(3x) (P(x))
es equivalente a
145
conjunción y disyunción para sentencias construidas con variables de
cualquier rango. En este caso de universo finito, podemos escribir la
tabla de verdad de cualquier sentencia en la que intervenga P(x) con x
cuantificada, considerando todas las evaluaciones posibles del
conjunto {P(a), P(b), P(c), P(d)} (que a todos los efectos es lo mismo
que un conjunto de variables proposicionales).
b2) Lo más normal es que el universo del discurso sea infinito (o ina-
bordable). En tal caso, es claro que no podemos construir ninguna
tabla de verdad. Pese a ello, hay sentencias que siempre son verda-
deras. Por ejemplo, nadie dudará de que
tiene que ser válida, o, lo que es lo mismo, todas las interpretaciones que
satisfacen a la conjunción de las dos premisas han de satisfacer también a la
conclusión para que el razonamiento sea válido. Ahora bien, como el universo
del discurso es inabordable, no podemos comprobar tal cosa construyendo una
tabla de verdad. Pero hagámoslo considerando que el universo se restringiese
a tres libros, éste (e) y otros dos (ol y o2). La premisa P1 se escribiría entonces
como Pie APIOI a P 1 o 2 , con
Pie: 1(e) ->A(e)
1(e) A (e) 7(01) A(01) 7(02) A (02) Pie Plol Plo2 P1 P2 = I(e) CsA(e) PL AP2 —> C
0 0 0 0 0 0 1 1 1 1 0 0 1
0 0 0 0 0 1 1 1 1 1 0 0 1
0 0 0 0 1 0 1 1 0 0 0 0 1
0 0 0 0 1 1 1 1 1 1 0 0 1
0 0 1 0 0 0 1 1 1 1 0 0 1
0 0 0 1 0 1 1 1 1 1 0 0 1
0 0 0 1 1 0 1 1 0 0 0 0 1
0 0 0 1 1 1 1 1 1 1 0 0 1
0 0 1 0 0 0 1 0 1 0 0 0 1
0 0 1 0 0 1 1 0 1 0 0 0 1
0 0 1 0 1 0 1 0 0 0 0 0 1
0 0 1 0 1 1 1 0 1 0 0 0 1
0 0 1 1 0 0 1 1 1 1 0 0 1
0 0 1 1 0 1 1 1 1 1 0 0 1
0 0 1 1 1 0 1 1 0 0 0 0 1
0 0 1 1 1 1 1 1 1 1 0 0 1
0 1 0 0 0 0 1 1 1 1 0 1 1
0 1 0 0 0 1 1 1 1 1 0 1 1
0 1 0 0 1 0 1 1 0 0 0 1 1
147
1(e). A (e) 1(01) A (01) 1(02) A (02) Pie Plol Plo2 PI P2sl(e) CsA(e) P1AP2->C
0 1 0 0 1 1 1 1 1 1 0 1 1
0 1 0 1 0 0 1 1 1 1 0 1 1
0 1 0 1 0 1 1 1 1 1 0 1 1
0 1 0 1 1 0 1 1 0 0 0 1 1
0 1 0 1 1 1 1 1 1 0 0 1 1
0 1 1 0 0 0 1 0 1 0 0 1 1
0 1 1 0 0 1 1 0 1 0 0 1 1
0 1 1 0 1 0 1 0 0 0 1 1
0 1 1 0 1 1 1 0 1 0 0 1 1
0 1 1 1 0 0 1 1 1 1 0 1 1
0 1 1 1 0 1 1 1 1 1 0 1 1
0 1 1 1 1 0 1 1 0 0 0 1 1
0 1 1 1 1 1 1 1 1 1 0 1 1
1 0 0 0 0 0 0 1 1 0 1 0 1
1 0 0 0 0 1 0 1 1 0 1 0 1
1 0 0 0 1 0 0 1 0 1 0 1
1 0 0 0 1 1 0 1 1 0 1 0 1
1 0 0 1 0 0 0 1 1 0 1 0 1
1 0 0 1 0 1 0 1 1 0 1 0 1
1 0 0 1 1 0 0 1 0 1 0 1
1 0 0 1 1 1 0 1 1 0 1 0 1
1 0 1 0 0 0 0 0 1 0 1 0 1
1 0 1 0 0 1 0 0 1 0 1 0 1
1 0 1 0 1 0 0 0 0 0 1 0 1
1 0 1 0 1 1 0 0 1 0 1 0 1
1 0 1 1 0 0 0 1 1 0 1 0 1
1 0 1 1 0 1 0 1 1 0 1 0 1
148
1(e). A(e) /(Ol) A (01) 1(02) A (02) Pie Plol Plol P1 P2 = I(e) CsA(e) P1aP2—» C
1 0 1 1 1 0 0 1 0 0 1 0 1
1 0 1 1 1 1 0 1 1 0 1 0 1
1 1 0 0 0 0 1 1 1 1 1 1 1
1 1 0 0 0 1 1 1 1 1 1 1 1
1 1 0 0 1 0 1 1 0 1 1 1
1 1 0 0 1 1 1 1 1 1 1 1 1
1 1 0 1 0 0 1 1 1 1 1 1 1
1 1 0 1 0 1 1 1 1 1 1 1 1
1 1 0 1 1 0 1 1 0 1 1 1
1 1 0 1 1 1 1 1 1 1 1 1 1
1 1 1 0 0 0 1 0 1 0 1 1 1
1 1 1 0 0 1 1 0 1 0 1 1 1
1 1 1 0 1 0 1 0 0 1 1 1
1 1 1 0 1 1 1 0 1 0 1 1 1
1 1 1 1 0 0 1 1 1 1 1 1 1
1 1 1 1 0 1 1 1 1 1 1 1 1
1 1 1 1 1 0 1 1 0 0 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1
Tras escribir toda esta tabla, comprobamos que, para este universo finito, la
sentencia que formaliza al razonamiento es una tautología, y, por tanto, el
razonamiento es válido. Pero comprobamos también que, además de tedioso, este
procedimiento (que en lógica de proposiciones podría tener algún sentido) es
inútil, porque, en principio, no nos garantiza que el razonamiento siga siendo
válido para un universo del discurso mayor.
Se ha demostrado que, si hay n predicados monádicos,' cualquier sentencia
válida en un universo que tenga 2" elementos es válida en todo universo. En este
ejemplo, como hay dos predicados monádicos, bastaría comprobar la validez en
un universo de cuatro elementos, lo cual sería factible. Pero para un número mayor
de predicados el procedimiento deja de ser práctico, y si hay predicados poliádicos
no nos garantiza nada. De hecho, también se ha demostrado que no hay un
procedimiento general que permita determinar la validez de cualquier sentencia
149
del cálculo de predicados. Por ello, se dice que el cálculo de predicados es
indecidible. Sin embargo, sí existe lin procedimiento tal que si una sentencia es
válida termina dictaminándolo (y si no lo es, no termina), por lo que también se
dice que el cálculo de predicados es semidecidible.
En cualquier caso, lo que nos interesa a efectos prácticos de aplicación de la
lógica a la informática es disponer de sistemas de inferencia. En el apartado 4.7
generalizaremos el método de resolución que habíamos visto para la lógica de
proposiciones. En los ejemplos que siguen nos limitaremos a formalizar los
razonamientos, dejando al lector la construcción de tablas de verdad para
comprobar su validez con universos finitos.
Ejemplo 1.7.2.
Teniendo en cuenta las relaciones que hay entre las conectivas y entre los
cuantificadores, la formalización no es única. Por ejemplo, la primera premisa
puede también escribirse así:
P1:M (a,l)
P 2 . P (j,a)
P3: (Vx) (Vy) (Az) (P(x,y) A ( P ( y ¿ ) vM(y¿)) ->A(*,z))
C:A (j,l)
Obsérvese que la premisa 3 establece una definición de la relación "abuelo de"
en función de las relaciones "padre de" y "madre de". Las premisas 1 y 2 son
hechos concretos que junto con esa definición nos permiten inferir otro hecho.
Ejemplo 1.7.5.
"Un antepasado de una persona es alguien que o bien es padre o madre de esa
persona o bien es antepasado de su padre o de su madre".
151
1.8. Funciones
Para terminar esta introducción informal, tenemos que hacer referencia a las
funciones. Se trata de una construcción del cálculo de predicados que no se
utilizaba en la lógica clásica, pero que, como veremos (en el apartado 4.5), es
necesaria para poder expresar las sentencias en forma clausulada como paso
previo a la aplicación de la resolución.
Las funciones, como los predicados, tienen argumentos que pueden ser
constantes o variables. Pero, a diferencia de los predicados, no representan
ninguna propiedad o relación entre los argumentos que pueda evaluarse como
verdadera o falsa. Una función en cálculo de predicados es una función
matemática definida en el universo del discurso. Por ejemplo, podemos definir la
función "padre", p. Aplicada a un individuo, nos daría como resultado otro
individuo, p(x) (su padre). Si definimos un predicado de igualdad, I(x,y), que es
verdadero cuando x es el mismo individuo que y, y falso en otro caso, sería lo
mismo escribir P(x,y) ("x es padre de y") que I(x,p(y)) ("el individuo x es el mismo
individuo que es padre de y"). Vemos con este ejemplo que los argumentos de los
predicados (y de las mismas funciones) pueden ser funciones, lo cual nos lleva a
ampliar el concepto de fórmula atómica, cosa que haremos enseguida.
2. Sintaxis
2.1. Alfabeto
Utilizaremos los siguientes símbolos (en su caso, y si es menester, con
subíndices):
152
A, B, C,... para cualquier sentencia.
2.3. Sentencias
Definición 2.3.1. Llamaremos secuencia deformación a toda secuencia finita
de expresiones, A 1; A2, ...,An en la que cada A¡ satisface al menos una de las
cinco condiciones siguientes:
153
d) existe un j menor que i tal que A¡ es lo mismo que (Vx) (A;. (x)) , donde
x es cualquier variable;
e) existe un j menor que i tal que A¡ es lo mismo que (3x) (A¿ (x)) , donde
x es cualquier variable.
RF4: Si A(x) es una sentencia con la variable x, (Vx) (A (x)) también lo es.
RF5: Si A(x) es una sentencia con la variable x, (3x) (A (x)) también lo es.
(Vx) ((3y)P(x,y) ) )
(3x) ( P ( x ) ) o ^ ( V x ) ( - P ( x ) )
155
2.5.2. Sustitución
En lógica de proposiciones, la sustitución era de variables preposicionales por
sentencias. Ahora, además, podremos sustituir fórmulas atómicas por sentencias
en las que figuren los mismos argumentos, y variables por términos en los que no
aparezcan otras variables de la sentencia.
5= {...J3/p¡,...,S/F¡,...,tk/xk,...}
(Vx) (3y) ( D ( x , y ) )
156
2.5.3. Demostraciones y teoremas
Para este apartado es íntegramente aplicable todo lo dicho en los apartados
2.5.3 y 2.5.4 del capítulo 2.
Demostración:
2. (p -» -nq) -¡P)
(Teorema de la lógica de proposiciones)
4. P(a) —>—,(Vx) ( - P ( x ) )
(Por separación de 1 y 3)
Demostración:
2. ( (P 9 ) A (q r)) (p r)
(Ley de transitividad de la lógica de proposiciones)
3. (( (Vx) P (*) P (a)) A (P (a) (3x) (P (x) )) -> ((Vx) (P (x)) (3x) (P (x)))
(Por sustitución en 2: { (Vx) (P (x)) />, P (a) (3x) (P (x)) /r}
157
2.5.5. Algunos teoremas útiles
La mayoría de las leyes de la lógica de proposiciones se pueden generalizar a
la lógica de predicados. Por ejemplo:
( P ( a ) A (Vx) ( - P ( x ) v —1¡2 ( x ) ) )
3. Semántica
Todo lo explicado en el apartado 3 del capítulo 2 es extensible a la lógica de
predicados. Vamos a hacerlo, recomendando al lector que alterne el estudio de lo
que sigue con la revisión de lo que allí decíamos. Empezaremos con la definición
de conceptualización.
158
• Un conjunto finito (que puede ser vacío), R, de relaciones entre los
elementos de U.
• Un conjunto finito (que puede ser vacío), F, de funciones que hacen
corresponder a ciertos elementos de ü otros elementos de U.
Una relación de grado n es un subconjunto del producto cartesiano u", es
decir, es un conjunto de tupias { (en, ei2, ..., ein) } , donde etj e U .Unapropie-
dad es una relación de grado 1.
Una función de grado n es una aplicación u " —>U, es decir, hace corresponder
a cada combinación de n elementos de U otro elemento de U.
159
Madre={ (Ana, Luis), (Ana, Bartolomé), (Ana, Carmen) }
(Es decir, José es padre de Ana, etc.)
(Es decir, todas las parejas que están en la relación "Padre" y las que están en
la relación "Madre" están también en la relación "Antepasado", y, además,
José es antepasado de Luis, etc.).
Para formalizar las sentencias, creamos los símbolos j, al, a2, etc. para las
constantes, y P, M y T para las relaciones, con la siguiente función de inter-
pretación:
i(P)=Padre; ¿(M)=Madre
z'(I)=Antepasado
3.2. Satisfacción
Como en el capítulo 2, podemos definir en general un conjunto de valores de
verdad (definición 3.1.2), evaluar en él las fórmulas atómicas (definición 3.1.3) y
extender estas evaluaciones a las sentencias (teorema 3.1.4). Pero ahora hay que
tener en cuenta que las fórmulas atómicas (que sustituyen a las variables propo-
sicionales) contienen normalmente variables, y solamente se puede evaluar una
fórmula atómica si sus variables están asignadas. Una evaluación es, pues, relativa
no sólo a la interpretación, sino también a la asignación de variables. En adelante
abreviaremos con "¿A" la expresión "interpretación y asignación de variables".
En el resto de este capítulo nos limitaremos a considerar evaluaciones binarias
(definición 3.2.1 del capítulo 2).
Una misma sentencia puede ser verdadera o falsa en una determinada con-
ceptualización dependiendo de la interpretación y de la asignación de variables.
Así, en la conceptualización de los Padres y Antepasados, la sentencia "P(x,;y)" es
verdadera para la interpretación i (la que llamábamos interpretación "pretendida"
o "natural") y las asignaciones A1 (x) =José, At (y) =Ana; A 2 (x) =José,
A 2 (y) =Baltasar, etc., pero es falsa para las mismas asignaciones si adoptamos la
interpretación f , y también es falsa para la interpretación i pero con otras
asignaciones.
1
"5" es aquí un metasímbolo para representar a una sentencia cualquiera. Más adelante utilizaremos también
"P" y "C" como metasímbolos para representar sentencias que son premisas y conclusiones de razonamientos.
Por otra parte, obsérvese que" £ ", como otros símbolos parecidos que iremos introduciendo, son predicados
de orden superior, ya que representan propiedades de sentencias del cálculo de predicados de primer orden.
161
Recordemos que las sentencias se forman siguiendo las reglas sintácticas
explicadas en el apartado 2.3. Si para cada una de las reglas (RF1 a RF5)
establecemos las condiciones bajo las cuales la sentencia se satisface, estas
condiciones definen la semántica de la lógica de predicados de primer orden. Son
las siguientes:
163
(Mortadelo,Filemón) no está ni en la relación "Padre" ni en la relación "Madre"
ni en la relación "Antepasado", y asimismo se satisface para A(x)=José, A(y)=
Luis, ya que esta asignación no satisface a P(x,y) ni a M(x,y), aunque sí a T(x,y).
De hecho, con la interpretación dada, la sentencia se satisface siempre, puesto que
todas las parejas de la relación "Padre" y todas la de "Madre" están también en la
relación "Antepasado". Como veremos enseguida, en este caso se dice que esa
interpretación es un "modelo" de la sentencia.
Aunque ya lo hemos explicado con detalle en el apartado 1.3 del capítulo 2,
conviene insistir en que no debe confundirse una sentencia condicional con una
"implicación lógica": esta última corresponde, como también veremos (en el
apartado 4.2), a un condicional que se satisface siempre (para toda i y toda A).
Definición 3.3.2. Una sentencia 5 es válida si y sólo si, para toda i y toda
A, t iA S. En este caso se escribe " fc5 ". El ejemplo más sencillo de sentencia
válida es P (x) v - P (x) ("principio del tercio excluso"). Una sentencia
válida que no contiene variables se llama tautología; por ejemplo, P (a)
v-P(a) .
3.4. Modelos
Las sentencias que escribimos para representar hechos o relaciones de una
conceptualization no son sentencias válidas:2 se satisfacen para una determinada
interpretación, pero no para otras.
2
Una sentencia válida, al satisfacerse siempre, no representa nada. Desde el punto de vista de la teoría de la
información, no proporciona información alguna.
Definición 3.4.1. Una interpretación i es un modelo de una sentencia S si S se
satisface con esa i para todas las asignaciones posibles de sus variables; se
escribe " t. S". Y una interpretación es un modelo de un conjunto de
sentencias si es un modelo de todas y cada una de ellas.
("todos los políticos son mentirosos" y "todos los mentirosos van al infierno").
i, (P) = {IndA}
il (M) ={IndA}
iL (F) = {IndA}
165
¿2 (P) ={IndA}
i2 (M) = {IndAJndB}
i2 (F) = {IndA,IndB,IndC}
z 3 (P) = {IndA}
¿3 (M) = {IndA}
¿3(P)=0
¿ 4 ( P ) = {IndA}
¿4 (M) = 0
hiF)= 0
ya que en este caso se satisface 52 pero no SI.
Se puede decir que las sentencias condicionales cerradas definen mundos
posibles: i1 e i2 son dos de los modelos de SI y 52, o mundos definidos por SI y
52.
Supongamos que a SI y 52 añadimos
S3:P(a)
i1 e i2 siguen siendo modelos de {S1,S2,S3}, pero / 1 es el modelo mínimo. Un
modelo es mínimo si ningún subconjunto de él es un modelo. Si no hubiésemos
añadido S3, el modelo mínimo sería i0 tal que i0 (P) = i0 (M) = i0 (F) = 0 .
4. Sistemas inferenciales
4.1. Razonamientos en lógica de predicados
Ahora extenderemos a la lógica de predicados todo lo que hemos estudiado en
el apartado 5 del capítulo 2 para la de proposiciones^. Como antes, sugerimos al
lector que vaya repasando aquél a medida que avanza en éste.
De momento, todo lo dicho en el apartado 5.1 sigue siendo aplicable, con dos
salvedades:
{ Si ,S2,...S„} 1=5
167
De la definición de sentencia válida y de modelo se sigue que t S si y sólo si
para toda i ocurre que t. S (S es una sentencia válida si y sólo si toda
interpretación es un modelo de S). Por tanto, si SI implica a S2 deberá ocurrir que,
para toda i, t. (SI —> S2) . Como el condicional sólo deja de satisfacerse en el
caso de que se satisfaga el antecedente y no el consecuente, resulta que decir que
SI implica a S2 es lo mismo que decir que toda i que sea modelo de SI también
lo es de S2, o que el conjunto de modelos de S2 es un subconjunto del de SI.
Prosiguiendo el razonamiento3, es fácil concluir que SI y S2 son equivalentes si y
sólo si tienen el mismo conjunto de modelos: todo modelo de SI lo es de S2 y
viceversa.
Las equivalencias dadas en el capítulo 2 (las que se derivan de las leyes con
forma de bicondicional que aparecen en los apartados 2.3,2.4 y 2.5) siguen siendo
válidas. Repetimos algunas de ellas (junto con dos nuevas: las que permiten
intercambiar los cuantificadores existencial y universal):
(1 ) - , ( - £ ) = S
3
Obsérvese que si quisiéramos formalizar estos razonamientos habríamos de hacerlo en lógica de predicados de
orden superior (capítulo 5, apartado 2.1): " t " , " =", etc., son predicados sobre sentencias que contienen
predicados.
Hagamos un ejercicio de transformaciones sucesivas de una sentencia
mediante aplicación de estas equivalencias. Tomemos la regla recursiva de la
definición de "Antepasado" (suponiendo, como hacíamos en el ejemplo 1.7.5, que
"P" representa "padre o madre", para que la sentencia sea más manejable):
169
P l : Todos los libros de informática son terriblemente aburridos
P2: Este es un libro de informática
C: Este libro es terriblemente aburrido
que habíamos formalizado así:
' Recuérdese que, según el teorema 5.4.3 del capítulo 2, para que un sistema inferencial sea consistente, todas
sus reglas de inferencia tienen que corresponderse con tesis del sistema axiomático.
La regla dice que se puede obtener la conclusión
A (i, e)
donde "i" es una constante arbitraria que no puede coincidir con ninguna de las
utilizadas en la conceptualización. Informalmente el razonamiento es así: "la
sentencia dice que existe un individuo (al menos) que cumple ciertas condiciones;
inventemos un nombre para este individuo y sigamos adelante".
Ahora bien, si la sentencia abarcada por el cuantificador existencial que se
elimina está dentro del alcance de un cuantificador universal entonces no
podemos sustituir la variable por una constante de Skolem. Para ver por qué es
así, consideremos este otro ejemplo: "todos los libros tienen al menos un autor",
o "para todo x, si x es un libro, entonces existe un y tal que y es el autor de x", o:
P:(3x) (S (x,yl,y2,...,yn))
C:S(f(yl,y2,...,yn),yl,y2,...,yn)
171
Lo que veíamos en los apartados siguientes de aquél capítulo (forma
clausulada, resolución y refutación) requiere algunas extensiones para aplicarse a
la lógica de predicados.
LxvL2v ...vL„
donde los L¡ son literales (fórmulas atómicas con o sin el símbolo " —.") con
cualquier número de variables cada uno. Todas las variables se suponen
cuantificadas universalmente, aunque no se escriba (Vx1) (Vx2) ... delante de la
cláusula.
Definición 4.5.2. Diremos que una sentencia está en forma clausulada si tiene
la forma:
1. Eliminación de todas las conectivas que no sean" V" o " A " (normalmente,
condicionales y bicondicionales). Se hace igual que en lógica de propo-
siciones:
—i(AvB) = (-iAa-IB)
— I ( A A B ) = (—iA v —iB)
—i—iA s A
(3x) ( P ( x ) ) ^P(a)
h(P(a) (3x) ( P ( x ) ) )
(3x) ( P ( x ) ) —>P(a)
173
5. Eliminación de los cuantificadores universales. Contra lo que pudiera pen-
sarse, este paso no plantea ningún problema. En este momento, si se han
seguido los pasos anteriores, sólo existen cuantificadores universales, y ca-
da uno de ellos afecta a una variable diferente. Por tanto, podemos escribir-
los todos al comienzo de la sentencia. Y, puesto que todas las variables
están umversalmente cuantificadas (como ya hemos dicho, sólo considera-
mos sentencias cerradas), podemos omitir la escritura de tales cuantifica-
dores. No se trata, pues, en rigor, de "eliminarlos" sino de suponer que
siempre existen.
Para centrar las ideas sobre los pasos seguidos hasta ahora, supongamos que
partimos de la sentencia
[(3*) (-P (x)) ] v [ (Vx) (Vy) (3z) (-P (x,y¿) v (VM) (/? (x,y,z,«))) ]
6. Distribución de " A " sobre " V". En el último ejemplo, ya hemos llegado a
una disyunción de literales, o sea, a una cláusula. Pero, en general, tras el
último paso tendremos una sentencia formada por literales unidos por las
conectivas " a " y " v " , y aplicaremos, jgu^l que hacíamos en lógica de
proposiciones, la propiedad distributiva
(L1AL2) VL3= (xjvlj) a (L2WL3)
7. Redenominación de variables para que cada cláusula tenga las suyas pro-
pias. Este paso tiene su justificación en la ley de distribución del
cuantificador universal sobre la conjunción. En efecto, si tras los pasos
anteriores se ha llegado a una sentencia como
P(x) A Q(x)
(dos cláusulas constituidas cada una por un literal), en realidad la sentencia es:
(Vx) (P (x) A Q (x))
y lo que hacemos es sustituirla por su equivalente
(Vx) (P (x)) A (Vy) (P (y))
es decir, nos quedamos con las cláusulas P(x) y P(y).
Ejemplo:
--P(g(xi)) v g ^ g ^ ) )
-nP(g(X 2 )) V P ( g ( x 2 ) )
->0 (*3, z 2 )
175
Las cláusulas se pueden expresar también como sentencias condicionales,
igual que veíamos en el apartado 5.6 del capitulo 2: el antecedente es la conjunción
de los literales negativos, hechos positivos, y el consecuente es la disyunción de
los literales positivos. Y, lo mismo que allí, se llaman cláusulas de Horn a las que
sólo tienen un literal positivo ("cabeza") o ninguno, y cláusula vacía, cp, a aquella
en la que han desaparecido todos los literales.
Con las sentencias en forma clausulada, la idea de la resolución es la misma
que en lógica de proposiciones: dadas dos generatrices que comparten un literal
positivo en la una y negativo en la otra, obtener la resolvente eliminando ese literal
y conservando los demás. Pero ahora hay un detalle nuevo a considerar: como los
literales dependen de argumentos, habrá que igualar los argumentos de los
literales que se eliminan. Por ejemplo, consideremos la inferencia de modus
ponens".
- i f f ( x ) vM(x)
H(s)
M(s)
Si eliminamos H(s) es porque podemos sustituir x por s en la primera premisa,
y así"unificar" los dos literales. El proceso de unificación está fundamentado en
la ley de especificación (como la regla de inferencia de particularización de un
universal explicada en el apartado 4.3), pero no es siempre tan fácil como en este
ejemplo. Vamos a estudiarlo de manera más general.
Definición 4.6.1. Dadas unas variables xv x 2 , ...,xn y unos términos tv t2, ...,
tn en los que no figuran esas variables, llamaremos ahora sustitución a un
conjunto de pares ordenados
s2= {b/x,g(z)/y}
Ls3= P(a,z,f(w))
LSL es un caso terminal, o un ejemplar6, de L: llamaremos así a los que no
contienen variables. Ls3 es una variante alfabética deL: sólo se han cambiado los
nombres de las variables por otros.
5
A veces se utiliza (incorrectamente) la palabra "instancia" (del inglés "instance").
6
"ground instance", en inglés.
177
sería:
SjS2= {f{a,b)/z,a/x,b/y,d/u}
(porque cuando fuésemos a aplicar Sj ya habríamos aplicado antes s2, con la que
habría desaparecido la z, sustituida por c).
a) Si s es otro unificador de {L¡} entonces existe una sustitución s' tal que 5=
|X s', es decir, L¡s es un caso de L¡[i. (En el ejemplo anterior, P(a,c,f(b)) es un
caso de P(ayxJ{b)) para s' = {c/x}).
178
<?1= {Lu}
G 2 = {L 2i }
Ejemplo:
179
|i= { x / z }
R= P (a,x,f(a)) v^P(a,y,f(a)) v -nP (a,y,f(x))
4.8. Refutación
Aquí es totalmente aplicable todo lo dicho en el apartado 5.8 del capítulo 2,
porque la ley de reducción al absurdo se aplica también en lógica de predicados.
Es decir, si
P= P1 A P2 A ... A P n
Pl:P(a, l)
P2:P(j,a)
7
Este resaltado se obtiene fácilmente sustituyendo P —» C = —,(P A —IC) en la tesis que corresponde a la
equivalencia (10) del apartado 4.2 (de la misma forma que hacíamos en el apartado 5.8 del capítulo 2).
8
En términos de algorítmica, el algoritmo es de complejidad no polinómica (apartado 3.1 del capítulo 7 del Tema
"Algoritmos").
La conclusión evidente en este caso es A(j,l). Pero normalmente tendremos
muchos más hechos9, y podríamos plantearnos la pregunta: "dados los hechos y la
definición de abuelo, ¿existen abuelos?" Vamos a ver que la refutación no sólo
nos permite responder a la pregunta, sino, si la respuesta es afirmativa, averiguar
los individuos que están en la relación.
La pregunta que acabamos de hacer se formalizaría así:
—iC: —A (u, v)
C2: —P (x, a)
C3: <p
C2: -P(/, z)
9
Por ejemplo, dejamos como ejercicio al lector el análisis de lo que ocurre cuando el universo del discurso es
el considerado en el ejemplo del apartado 3.1.
181
5. Resumen
La lógica de predicados nos permite entrar en la composición de los
enunciados, que en lógica de proposiciones se representan con simples variables
proposicionales. Ahora tendremos, en lugar de variables proposicionales,
predicados, que representan propiedades de individuos o relaciones entre
individuos, y constantes y variables, que representan a esos individuos.
Hemos seguido un camino paralelo al del capítulo 2, ampliando a la lógica de
predicados el sistema axiomático, la semántica y los sistemas inferenciales,
deteniéndonos especialmente en la regla de resolución, cuya aplicación es algo
más complicada aquí, primero por la existencia de variables cuantificadas, que
exige ciertas manipulaciones sobre las sentencias para expresarlas en forma
clausulada, y luego porque en el emparejamiento de literales complementarios
hay que buscar unificaciones.
El último ejemplo, que se complementa más adelante con el ejercicio 7.4, per-
mite vislumbrar cómo el método de resolución puede servir para búsquedas en
bases de datos construidas sobre la declaración de hechos elementales y de
definiciones de relaciones.
182
de elaborar teorías y métodos formales que permitan mejorar la productividad y
la fiabilidad del software.
Hay muchos libros sobre lógica recomendables para ampliar lo expuesto en
este capítulo. Destacamos los de Robinson (1979), Kowalski (1979) y Cuena
(1986), y, muy especialmente, el de Genesereth y Nilsson (1987). A través de la
Internet pueden obtenerse materiales didácticos que se utilizan en la Universidad
de Stanford para un curso basado en este último texto (Genesereth, 1995).
7. Ejercicios
7.1. Expesar como sentencias en lógica de predicados los siguientes
enunciados:
a) "Existen individuos que, sin ser completamente idiotas, se compor-
tan como tales".
b) "Todo lo que no es tradición es plagio". (Eugenio D'Ors).
c) "Diremos que una máquina es inteligente para un tipo de tareas si un
observador es incapaz de distinguir por el resultado a la máquina de un
humano que sabe resolver ese tipo de tareas". (Esto es lo que se llama
"prueba de Turing": véase el apartado 1.1 del capítulo 6).
d) "Un descendiente de una persona es o bien un hijo de esa persona o
bien un hijo de un descendiente".
7.2. Considerar la premisa:
P: En un pueblo hay un barbero que afeita a todas las personas del
pueblo que no se afeitan a sí mismas, y sólo a ellas".
¿Se puede inferir la conclusión C: "El barbero se afeita a sí mismo"? Si
esta conclusión fuese verdadera, la premisa nos dice que tendría que ser
falsa (sólo afeita a los que no se afeitan a sí mismos), y si fuese falsa,
la premisa nos dice que tendría que ser verdadera (afeita a todos los que
no se afeitan a sí mismos). Esta es la llamada "paradoja del barbero",
debida a Bertrand Russell. Descubrir el origen de la paradoja mediante
el análisis formal de la premisa.
7.3. Formalizar los siguientes razonamientos y comprobar las conclusiones
mediante resolución y refutación:
a) PL: Ningún ordenador se equivoca
P2: El que tiene boca se equivoca
183
b) PI: Algunos ordenadores se equivocan
P2: El que tiene boca se equivoca
185
5
Otras lóaicas
1. Introducción
La lógica clásica nos permite modelar los razonamientos (en su vertiente
funcional, no en la procesal: recuérdese la discusión sobre este asunto en el
apartado 1 del capítulo 1). Pero, como todo modelo, no es más que una aproxi-
mación a la realidad que se concentra en determinados aspectos relevantes de esa
realidad y que no contempla infinidad de matices y de detalles. Las lógicas
llamadas "no clásicas" son las que abordan alguno de los aspectos no modelados
en la lógica de proposiciones ni en la lógica de predicados. Y son de utilidad en
informática cuando tales aspectos juegan un papel importante en el fenómeno o
problema a estudiar o en la aplicación a desarrollar.
Dentro de estas "otras lógicas" pueden considerarse dos tipos: uno, el de las
que amplían los lenguajes de los cálculos de proposiciones y de predicados y en
las que todas las construcciones y teoremas de éstos siguen siendo válidos, y otro,
el de las que invalidan algunas leyes. Por ejemplo, en las lógicas multivaloradas
o polivalentes, que son aquellas en las que se admiten evaluaciones intermedias
entre la "verdad" y la "falsedad", la ley del tercio excluso, (Av—A) , (o,
equivalentemente, I- [ - I (A A -IA) ] ) deja de ser válida.
El campo es demasiado amplio como para pretender darle aquí un tratamiento
al mismo nivel formal y con la misma extensión que hemos hecho con las lógicas
de proposiciones y de predicados. Nos limitaremos a una presentación resumida
187
de las lógicas más conocidas, apuntando solamente sus aplicaciones en infor-
mática, y nos extenderemos finalmente con un poco más de detalle en una de ellas,
la lógica borrosa. Remitimos al lector interesado en estudiar con rigor alguna de
estas lógicas a la bibliografía que se comenta en el apartado 6.
("existe al menos un rasgo, R, tal que, para todo x, si x es español, x tiene el rasgo
R"). O cuando decimos "el cobre es conductor, propiedad que es muy interesante",
que formalizaríamos así:
C (c) AI(C)
1
En el capítulo anterior lo hemos hecho ocasionalmente, cuando expresábamos propiedades de sentencias, y así
lo hicimos observar en las notas a pie de página de los apartados 3.2 y 4.2.
188
2.2. Lógica de clases y lógica de relaciones
En realidad, las lógicas de clases y de relaciones no añaden nada nuevo a la
lógica de predicados: son otra manera de expresarla, con construcciones sintác-
ticas más cercanas a la teoría de conjuntos.
Una clase es una entidad abstracta que designa a todos los individuos que
comparten alguna propiedad. Conceptualmente, "clase" y "conjunto" son dos
cosas diferentes: no es lo mismo la clase de los libros de informática, algo
abstracto que designa a todos los objetos que comparten las propiedades de ser
libros y de tratar sobre informática, que el conjunto de todos los libros de
informática, que es algo concreto. Pero las mismas operaciones que se definen
entre conjuntos (unión, intersección, etc.) son también válidas entre clases. Y
consiguientemente, el álgebra de Boole, que es un modelo para la teoría de
conjuntos y para la lógica de proposiciones, también lo es para la lógica de clases.
El alfabeto de la lógica de clases incluye los símbolos para representar a las
clases (A, B, C,...), los símbolos de la teoría de conjuntos (LJ , P>, <= , e , etc.)
y las conectivas de la lógica clásica. Por ejemplo, el razonamiento "todos los
hombres son mortales, Sócrates es un hombre, luego Sócrates es mortal" se
formalizaría así en lógica de clases:
( ( H a M ) A ( j £ H)) -» ( s e m)
C= { x | P ( x ) }
R= {(x,y)\P(x,y)}
189
En el álgebra de relaciones se definen la relación universal y la relación vacía,
y un conjunto de operaciones: complementación, unión, suma, diferencia,
selección, proyección y productos de relaciones. Su interés informático radica en
el hecho de constituir un modelo matemático de gran utilidad para el diseño de un
tipo de bases de datos llamadas, precisamente, relaciónales.
establecemos una identidad entre "España" y "el más meridional de los países
europeos". Este uso del verbo "ser" para denotar la identidad es muy distinto de
otros que hemos visto antes, como el "ser" de la predicación ("España es un país
europeo"), el "ser" de la pertenencia ("España pertenece a la clase de los países
europeos") o el "ser" de la inclusión ("la clase de los españoles está incluida en la
clase de los europeos").
En principio, la identidad no es más que un predicado diádico como cualquier
otro. Si los lógicos le dan una importancia especial es porque muchos razo-
namientos sólo pueden explicarse ampliando el lenguaje de la lógica de
predicados para que lo considere como un caso especial. Por ejemplo:
P l : El que inventó la palabra "telemática" es abulense
P2: El que inventó la palabra "telemática" ha escrito "La vida en un chip"
P 3 : El que ha escrito "La vida en un chip" es Luis Arroyo
C: Luis Arroyo es abulense
Obsérvese que en P l y en C se utiliza el "ser" de la predicación (o de la
pertenencia, según se adopte la óptica de la lógica de predicados o de la lógica de
clases), mientras que e n P 2 y P3 es el "ser" de la identidad.
Tradicionalmente, en lógica se definen las "descripciones" para tratar con
enunciados de ese tipo, y se introducen un nuevo símbolo, =, para la relación de
igualdad, y un nuevo cuantificador, i (iota), para formalizar expresiones del tipo
"el x tal que...", de modo que el razonamiento anterior se formaliza así:
Pl:A((\x) (I(x,t)))
Pl: (ix) (I(x,t))= (xx) (E(x,v))
P3: (ix) (E(x, v ) ) = a
C:A (a)
con i(A) = "abulense", i(í) = "inventor de", i(E) = "autor de",
i(t) = "la palabra telemática", i(v) = "la vida en un chip", i(a) = "Luis Arroyo".
Y una ampliación del sistema axiomático permite analizar razonamientos de
ese tipo.
Pero tenemos otro recurso expresivo para formalizar ese tipo de razo-
namientos: las funciones (capítulo 4, apartado 1.8). Introduciendo las funciones
fi (y) Y fe 0 0 e n sustitución de "el x tal que x inventó y" y "el x tal que x ha escrito
y", podemos escribir:
Pl:A(ft(t))
P2:fi(t)=fe(v)
P3:fe(v)= a
C: A (a)
Nuestro sistema inferencial sólo necesita de la adición de una regla mediante
la cual pueda sustituirse cualquier término por otro que sea idéntico a él.
—i 0 (A A —B)
• (-AvB)
191
El uso de esta noción requiere, a efectos semánticos, el concepto de "mundos
posibles": OA será verdadera si A lo es en alguno de los mundos posibles, y LIA
será verdadera si A lo es en todos los mundos posibles.
En informática, la lógica modal tiene aplicaciones en la teoría de lenguajes de
programación y en los sistemas inferenciales llamados "no monótonos", que son
aquellos en los que se obtienen conclusiones provisionales que pueden verse
invalidadas a la luz de nuevas evidencias. En la lógica no monótona se añade otro
operador modal, "M", que significa "es consistente con lo que se sabe hasta
ahora". Por ejemplo, consideremos la sentencia:
cuya interpretación puede ser: "si x es padre de y, a menos que x sea un padre
desnaturalizado, entonces x ama a y". Si previamente se ha demostrado (por medio
de otras sentencias, o porque se da como un hecho) P(a,b) pero no D(a), entonces
la sentencia nos permite inferir provisionalmente A(a,b).
Además, la lógica no monótona permite formalizar un tipo de razonamiento
no deductivo muy interesante que se llama "abducción"2. Para ilustrarlo con un
ejemplo muy sencillo, supongamos que tenemos la sentencia:
2
Aclaramos, sólo para los lectores interesados en los "ovnis", que este término no tiene nada que ver aquí con
actividades de seres extraterrestres.
(Vx)(G(x)-^F(x))
F(a)
MG{a)
0 G (a)
Naturalmente, puede haber otras hipótesis consistentes con el conocimiento
previo, además de "G". Al mecanizar este tipo de razonamiento tenemos que
establecer una medida de credibilidad para las distintas hipótesis. Veremos un
enfoque basado en probabilidades en el apartado 3.2 del siguiente capítulo.
3. Lógicas multivaloradas
La idea que motiva a todas las lógicas multivaloradas, también llamadas
multivalentes o polivalentes, radica en el hecho de que a veces somos incapaces
193
de asignar valores de "verdad" o "falsedad" absolutos a las sentencias. Ahora bien,
esto es algo que ya habíamos previsto (definición 3.1.2 del capítulo 2): decíamos
que el conjunto de valores de verdad, V, debe tener, como mínimo, dos valores.
Hasta ahora, hemos considerado que card(V)=2. Las lógicas multivaloradas son
aquellas en las que card(V)>2.
Consideremos el caso más sencillo: card(V) = 3. Adoptemos los símbolos "1"
para "verdadero", "0" para "falso" y " 1/2 " para "ni verdadero ni falso". En esta
lógica trivalorada (o trivalente) la extensión del dominio de la función de
evaluación para las sentencias puede hacerse teniendo en cuenta la siguiente tabla
que define las conectivas en el conjunto V:
0 1 1 0 1 1 0
1/2 0 1/2 0 1/2 1/2 1/2
1/2 1/2 1/2 1/2 1/2 1 1
1/2 1 1/2 1/2 1 1 1/2
1 0 0 0 1 0 0
1 1/2 0 1/2 1 1/2 1/2
1 1 0 1 1 1 1
= 0 si (Vx) (E (A (x)) = 0)
E {—A) = 1 -E(A)
E(A^B)= 1 siE(A)<E(B)
E ( (Vx) (A ( x ) ) ) = mín (E (A ( x ) ) )
X
que, como puede comprobarse fácilmente, coinciden con las dadas por la tabla
para el caso particular de la lógica trivalorada (card(V)=3).
Si hacemos V= {x|0 < x < 1} tendremos una lógica con infinitos valores de
evaluación, que puede ponerse en relación con la lógica probabilitaria, en la que
las conectivas se corresponden con operaciones de la teoría de probabilidades.
Para el operador de negación, esta correspondencia es inmediata; así, por ejemplo,
si tiramos un dado, en el lenguaje de las probabilidades decimos:" el suceso 'sacar
un tres' tiene probabilidad 1/6, y el suceso contrario tiene probabilidad 1-1/6 = 5/
6", mientras que en el lenguaje de la lógica diríamos: "la sentencia 'al tirar un dado
sale un tres' tiene el valor de verdad 1/6, mientras que la sentencia 'al tirar un dado
sale un número distinto de tres' tiene el valor de verdad 1-1/6 = 5/6".
En una lógica multivalorada podemos definir la equivalencia entre sentencias
del mismo modo que en la lógica binaria (apartado 3.5 del capítulo 2). Es decir,
dos sentencias son equivalentes si sus evaluaciones son las mismas para todas las
interpretaciones posibles. El lector puede comprobar que la mayoría de las leyes
de la lógica binaria (distributividad, asociatividad, de Morgan, etc.) se siguen
cumpliendo si se adoptan las definiciones dadas para las conectivas. Por ejemplo:
195
S i £ ( A ) > E(B) entonces resulta: £ ( - , (A A B))= E(-AV^B) = l-E(B),
mientras que si E (A) < E (B) resulta: E (—,(A AB)) = E {—A v —B) = 1 -
E (A) . Por consiguiente,
—I (A A 5) = —A v —iB
Pero hay una ley importante que no se cumple: la del tercio excluso:
I- (A v —A) , o, equivalentemente, h (—i (A A —A)) . En efecto:
£ (A v -iA) = máx (E (A), 1 -E (A) ) > 1/2 (en general, distinto de 1) (en
general, distinto de "1")
E (A A -iA) = mín( E (A), 1 -E (A) ) < 1/2 (e« general, distinto de 0) (en
general, distinto de "0")
4. Lógica borrosa
4.1. Justificación
En el siguiente capítulo presentaremos los principios de la aplicación de la
lógica a los llamados "sistemas expertos". Como allí veremos, un problema
fundamental a considerar es el de la representación en la máquina de los conoci-
mientos y los procedimientos inciertos e imprecisos que utilizan los expertos
humanos para resolver problemas. En la mayoría de los sistemas expertos que se
han construido o se están diseñando se adoptan técnicas "ad hoc" para atacar ese
problema. Pero existen intentos teóricos para introducir en la lógica formal la
imprecisión y la subjetividad propia de la actividad humana, y parece obvio que
en el futuro se tienda a basar rigurosamente el diseño de los sistemas expertos en
tales teorías. La más conocida de ellas es la lógica borrosa ("fuzzy logic"). Las
consideraciones anteriores, unidas a la escasez de bibliografía en español sobre el
tema, nos han incitado a dedicar una atención especial a la lógica borrosa en este
capítulo de "otras lógicas".
La lógica borrosa va aún más allá que las lógicas con infinitos valores de
verdad. Porque ya no sólo se trata de considerar que hay una infinidad de valores
semánticos entre "verdadero" y "falso", sino también de tener en cuenta que estos
mismos valores de verdad son imprecisos. Por ejemplo, a la sentencia "este
párrafo es de difícil comprensión" podría asignársele el valor de verdad 0,7 en
lógica multivalorada. Pero generalmente hacemos inferencias imprecisas, como
"si alguien encuentra muy difícil comprender un párrafo, casi con seguridad
abandona la lectura; este párrafo es de difícil comprensión para tal persona, luego
196
es probable que esa persona abandone la lectura". La lógica multivalorada no nos
permite hacer inferencias de ese tipo, porque intervienen en ella matices
(relaciones entre "difícil" y "muy difícil", entre "casi con seguridad" y "es
probable") imposibles de abordar con la simple extensión del conjunto de valores
de verdad.
Ese tipo de inferencia imprecisa es el que aborda la lógica borrosa. Y para ello
parte de una reconsideración del mismo pilar básico de las matemáticas: el
concepto de conjunto. En la realidad se presentan situaciones (particularmente,
cuando aparecen consideraciones subjetivas) en las que resulta difícil determinar
la pertenencia o no de un elemento a un conjunto. Por ejemplo:
• el conjunto de los números naturales mucho mayores que 100: parece claro
que 101 no pertenece al conjunto, y que 10 sí, pero ¿y 500?;
• el conjunto de las personas pobres: ¿pertenezco yo a ese conjunto?;
• el conjunto de las mujeres preciosas, etc.
Tales conjuntos pueden denominarse "borrosos" (o "difusos") para indicar que
no existe un criterio que determine exactamente un límite entre pertenencia o no
pertenencia al conjunto.
Pero, en este momento, el lector atento puede objetar: "lo que ocurre es que no
se ha establecido el criterio para definir los conjuntos. Así, en el primer ejemplo,
puede decirse (por convenio, o por hipótesis de trabajo) que el límite está en 1000;
en el segundo, que es pobre toda persona que, sin tener patrimonio, perciba unos
ingresos inferiores al salario mínimo; y en el último ejemplo ya es más difícil
establecer un criterio, porque ¿a quién se le ocurre tratar de determinar
matemáticamente tal conjunto?".
Ahora bien, si tratamos de formalizar las relaciones del hombre con su entorno
siempre vamos a encontrarnos con elementos imprecisos o "borrosos", sobre todo
en la actividad más típicamente humana, la comunicación por medio del lenguaje.
Cuando alguien está aprendiendo a conducir, en un determinado momento puede
recibir una orden del instructor como ésta: "levante ligera y lentamente el pie del
embrague", pero nunca una como ésta: "levante el pie 8 o a una velocidad de 2°30'
por segundo". Y sin embargo el hombre, considerado como sistema, se comporta
bien (aprende) con entradas "borrosas" como las del primer caso, mientras sería
difícil que lo hiciera con las del segundo tipo.
A poco que se reflexione, se llegará a la conclusión de que si pretendemos
analizar sistemas muy complejos como el hombre, las sociedades, etc. (ya sea con
espíritu puramente científico, ya sea con fines utilitarios: diseño de máquinas que
puedan razonar, tomar decisiones, comprender el lenguaje natural, etc.), resulta
imprescindible introducir en los modelos la imprecisión y la subjetividad propias
de la actividad humana. Además, en estos sistemas complejos hay que tener en
cuenta el principio de incompatibilidad de Zadeh:
197
"A medida que aumenta la complejidad de un sistema, nuestra capacidad para
hacer afirmaciones sobre su comportamiento que sean precisas y, al mismo
tiempo, significativas, va disminuyendo, hasta alcanzar un umbral por debajo del
cual precisión y significación (o pertinencia) llegan a ser características casi
mutuamente excluyentes".
Como consecuencia, los resultados muy precisos (hacia los que se orientan las
herramientas matemáticas clásicas aplicadas en ingeniería) tienen poca utilidad
por su incapacidad para representar significativamente el comportamiento de un
sistema complejo. De esta forma, resultan más interesantes los modelos cuali-
tativos.3
Estas consideraciones conducen a una reformulación del concepto básico de
conjunto, admitiendo grados de pertenencia de los elementos a los conjuntos.
Puesto que la lógica borrosa se apoya en la teoría de conjuntos borrosos, será
preciso que veamos previamente los elementos básicos de esa teoría.
^i-(x)= 1 - M * )
M-Ana(*)= M * ) ' M * )
{ ( * | M * ) ) } , V x e U,
donde (x) es una función que toma sus valores en un conjunto M llamado
conjunto de pertenencia.
3
Los conjuntos y la lógica borrosa que varaos a estudiar aquí son una aproximación a la modelación de estos
sistemas complejos, pero no la única. En las últimas décadas se han propuesto y desarrollado al menos otras dos:
la simulación cualitativa y la teoría de las catástrofes. Creemos que estas aproximaciones convergerán,
finalmente, en una nueva matemática cualitativa.
Generalmente se toma M= {m\m e [0,1] }; si se hace M= {0,1}, enton-
ces A se reduce a un subconjunto ordinario, de manera que la teoría clásica de
conjuntos es un caso particular de la teoría de conjuntos borrosos.
Ejemplo 4.2.2. Si U= {1, 2, 3, ..., 10} , podemos definir el conjunto "va-
rios", V, como:
J
= { ( * | l ) o ^ 4 o ; ( * l ( l + (x —40)V40)~ 1 ) j . > 4 0 }
X= i (1 + 4 0 / ( * - 4 0 ) 2 ) " 1 ) j c > 4 0 }
Podemos tener una visión gráfica de estos conjuntos representando (X. (x) y
|a v (x) (figura 5.1):
Figura 5.1.
199
Definición 4.2.5. Se definen las operaciones de complementation, inter-
sección, unión, producto y potenciación del siguiente modo:
Intersección: C= AnB si |XC (x) = mín (|XA (x) ,\\.B (x)) ,Vx e U
Unión: C= AKJB si |0.c (x) = máx (fi.^ (x) ,\LB (X) ) ,Vx e U
Es fácil comprobar que las tres primeras se reducen a las definiciones clásicas
en conjuntos ordinarios para M= { 0,1} . Asimismo, que todas las propiedades
de estas operaciones en los conjuntos ordinarios (asociatividad, distributividad,
etc.) se siguen cumpliendo, salvo en lo que respecta a dos muy importantes:
|iJ(x)
1 - 1-1
0,5 0,5-
2rJ r 4. 8 10 x 2 6 '8 10 *
Figura 5.2.
Ejemplo 4.2.7. Con las definiciones dadas para "joven" y "viejo" en el Ejemplo
4.2.3, en la figura 5.3 pueden verse las representaciones gráficas de la
intersección y la unión de ambos conjuntos.
^nvW
r
r~
20
1
i — r ~ í
40 60 80
n
20
—
40
/
m
i
60
r
80
Figura 5.3.
201
diferentes: A c.U,B <z V, y sean a e A y be B elementos genéricos de cada
uno. Una relación borrosa entre A y B se define como un conjunto de pares
ordenados (a, b), cada uno con un determinado grado de pertenencia , |i / ( , a la
relación R :
R= {{a,b)\\iR{a,b)},a&A,beB,Q<\yR<l [1]
IJ-jj indica así en qué grado, o con qué intensidad, los elementos a y b están en la
relación R .
Por ejemplo, existe una relación entre la estación del año en que nos
encontramos y el calor o frío que se siente. Esta relación es subjetiva (y, por lo
tanto, borrosa), y una determinada persona podría expresarla explícitamente así:
U = {estaciones}
V = {sensaciones}
A = U= {primavera, verano, otoño, invierno}
B = {calor, frío}
B
0,7 0,4
in
V
1 0
o 0,6 0,5
„ i 0,1 1
RczAxB
202
En efecto, como A y B son ordinarios, su producto cartesiano consta de todos
los pares (a, b), y la relación borrosa le da un grado de pertenencia a cada uno.
En este caso binario la relación se suele escribir también así: ARB.
En general una relación borrosa «-aria entre n conjuntos ordinarios,
A 1; A2, ...,An (no tienen por qué ser todos distintos) será un subconjunto borroso
del producto cartesiano de todos ellos:
RCZA1XA2X ... xA n
O, también,
AR±B= {(a,b)\[lRi(a,b)},
y otra entre B y C:
BR2C- {(b,c)\\xR2(b,c)},
203
Es decir, para cada pareja {a, c) se toma como grado de pertenencia a RI°R2
el resultado de la siguiente operación:
U= {p, v, o, i},
V= {TVT2},
donde T1 = temperatura superior a 20° C; T2 = temperatura igual o inferior a
20° C (universos no borrosos).
Ty T2
p 0,2 0,3
V 0,1 0,1
o 0,2 0,4
i 0,2 0,8
Tx T2
P 0,2 0,2
V 0,1 0
o 0,2 0,3
i 0 0,8
Obsérvese que R± relaciona bastante bien la sensación de frío alta con las
estaciones, pero no tanto la sensación de poco frío con las mismas (particu-
larmente, el grado de pertenencia de (v, Tx) a R t debería ser mucho más alto del
0,1 que resulta).
La explicación es que, tal como se han definido A y B, R¡ relaciona la
sensación de frío con las estaciones frías, pero no la sensación de poco frío con
las estaciones poco frías. Para que así fuera, deberíamos definir una nueva
relación haciendo uso de las operaciones de unión y complementación.
Volveremos sobre este ejemplo en el apartado 4.4.2.
Consideremos ahora un nuevo subconjunto borroso, C, en el universo W =
{ropas de abrigo}, establecido así:
C= { & | 0 , l ; í | 0 , 5 ; a | 0 , 9 }
donde b = bañador; t = traje; a = abrigo.
205
El producto cartesiano de B y C es:
207
Así, en el caso de la sentencia "x es viejo", el subconjunto correspondiente a que
esta sentencia sea verdadera puede ser el definido en los ejemplos anteriores. Este
subconjunto es el significado del predicado. Definido este subconjunto, los
correspondientes a los otros valores de verdad lingüísticos pueden calcularse en
función de él definiendo previamente unos convenios para "falso" y para las
partículas lingüísticas "muy", "bastante", etc.:
• "falso" es el subconjunto tal que \ifalso (x) = \x.verdadero (c (x)) , donde c(x)
es alguna función complementaria definida sobre U (por ejemplo, si U =
[1,150], c (x) = (150 - x ) );
• "no verdadero" = ("verdadero ");
2
• "muy verdadero" = "verdadero "
1/2
• "algo verdadero" = "verdadero " ; etc.
Por ejemplo, en el caso de que la sentencia sea el predicado "viejo" aplicado a
alguien, tendremos para "muy viejo" el significado:
S(-IA)= S j A )
Es fácil comprender que con esto no hacemos sino abordar los casos más
sencillos. Las sentencias, normalmente, manejan palabras cuyos significados son
conjuntos borrosos de universos diferentes. Por ejemplo, en la sentencia "Manuel
es un viejo extraordinariamente decrépito" tenemos dos variables borrosas: edad
(con valor "viejo") y estado (con valor "decrépito"). La interpretación exige el
conocer la de cada una de las variables (y definir "extraordinariamente", que
podría ser, por ejemplo, el operador de potenciación con valor 3), y daría un
resultado bidimensional.
Veamos otro ejemplo: Con los conjuntos A = {estaciones frías }, B =
{sensación de frío} y C = {ropas de abrigo}definidos anteriormente, tendríamos:
209
¿(estaciones no muy frías) = A2= {p\0,91; v|0,99; o10,84; ¿|0,19};
1T T
1 2
T1 T2 b t a
211
4.4.4. Reglas de inferencia borrosas
Consideremos estas dos premisas:
Y= X ° R
En el ejemplo dado,
T, T2
p v o i p 0,7 0,3
T,
Y= [0,91 0,99 0,84 0,19] v 0,8 0,2
0
[0,8 0,4]
0,6 0,4
1 0,2 0,8
Si a las sentencias anteriores se añade: "si se siente frío se usa ropa de abrigo,
si no, no", el resultado (grado de uso de las distintas prendas en las estaciones no
muy frías) puede calcularse, de acuerdo con los resultados anteriores, así:
b t a
0,8 0,5 0,2 [0,8 0,5 0,4]
[0,8 0,4 ] 0,2 0,5 0,8
o así:
b t a
C l : { 7 ^ 0 , 8 ; T 2 |0,4}
C2: {fc|0,8;í|0,5;a|0,4}
referentes al frío que se siente y al grado de uso de las ropas de abrigo. Por otra
parte, los conjuntos borrosos correspondientes a los significados de "se siente
frío" y "la ropa es de abrigo" se habían definido así:
5. Resumen
Hemos pasado revista en este capítulo a algunas de las llamadas "lógicas no
clásicas" (hay otras que no hemos mencionado: intuicionista, dinámica,
situacional, intensional, epistémica, etc.), entendiendo por tales las que modelan
213
aspectos de los procesos de razonamiento no contemplados en las lógicas de
proposiciones y de predicados (aunque también hemos incluido aquí las lógicas
de clases y de relaciones, que no son más que otra manera de contemplar la lógica
de predicados).
Entre las que representan ampliaciones de la lógica clásica, es decir, las que
conservan todo su lenguaje y su sistema axiomático, hemos comentado la lógica
de predicados de orden superior, la lógica modal, la lógica no monótona y la lógica
temporal. Y entre las que invalidan ese sistema axiomático, la multivalorada y la
borrosa. Esta última, además de contemplar infinitos valores entre la verdad y la
falsedad, considera que esos mismos predicados semánticos ("verdadero" y
"falso", así como los intermedios) son, en sí mismos, imprecisos. Para modelar
esta situación hay una herramienta matemática, la teoría de conjuntos borrosos,
cuya base hemos estudiado.
214
filosófico, y el de Turner (1984), que lo hace centrándose en las aplicaciones a la
informática.
La lógica modal se ha aplicado tanto en teoría de la programación (Manna y
Pnueli, 1979) como en métodos de inferencia no monotónica (McDermott y
Doyle, 1980) y en representación del conocimiento (Moore, 1984).
Igualmente, la lógica temporal se ha aplicado para la programación
concurrente (Manna y Pnueli, 1981; Manna y Wolper, 1984) y para sistemas de
inteligencia artificial (Alien, 1981; McDermott, 1982).
Un texto clásico sobre lógicas multivaloradas es el de Rescher (1969).
Sobre conjuntos borrosos y lógica borrosa hay bastante bibliografía.
Recomendamos particularmente tres libros: el de Klir y Folger (1988) y los de
Dubois y Prade (1980, 1988). Pero donde más aplicaciones está encontrando la
teoría de conjuntos borrosos es en los sistemas de control, y particularmente en el
diseño de muchos productos japoneses4; tres libros de referencia sobre este campo
particular son los de Driankov et al. (1993), Yager y Filev (1994) y Kandelk y
Langhotz (1994). El número de marzo de 1995 del "Proceedings of the IEEE"
(Chand y Chiu, 1995) contiene varios artículos sobre aplicaciones de la lógica
borrosa en ingeniería. Además, hay revistas especializadas: "Fuzzy sets and
systems", editada por North Holland desde 1978, y "Transactions on fuzzy
systems", editada por el I.E.E.E. desde 1993. Aún persiste, sin embargo, bastante
controversia sobre la lógica borrosa; a este respecto resulta muy interesante
observar la disparidad de opiniones entre los mismos especialistas (Shastri, 1993).
7. Ejercicios
7.1. Analizar en lógica de clases los razonamientos expuestos en el ejercicio
7.3 del capítulo 4.
7.2. Formalizar los siguientes enunciados, teniendo en cuenta que algunos
pueden ser ambiguos (y tener más de una formalización):
a) Si es necesario que si p entonces q entonces si es necesario que p
entonces es necesario que q.
b) No es posible ser valiente u osado si y sólo si no es posible ser
valiente y no es posible ser osado.
c) Si Pepe siempre se ha mareado cuando ha bebidó entonces si mañana
bebe se mareará.
4
Quizás el lector haya visto algún anuncio de cámaras fotográficas o de vídeo en el que se dice que utilizan
"lógica fuzzy" o "lógica gradual". Obviamente, el adjetivo "borroso" no parece muy adecuado para la promoción
de este tipo de producto...
215
d) Es posible que un programa haya funcionado siempre bien y que
mañana no funcione.
7.5. Definir los conjuntos borrosos que sean necesarios en cada caso y
analizar los siguientes razonamientos:
a) Pl: La mayoría de los hombres son heterosexuales
P2: Sócrates era hombre
C: Es muy posible que Sócrates fuera heterosexual
b) Pl: La temperatura es un poco alta
P2: Cuando la temperatura es alta hay que cerrar un poco la válvula
C: Hay que cerrar ligeramente la válvula
Aplicaciones en
ingeniería del
conocimiento
219
entrevieron la posibilidad de mecanizar los procesos del razonamiento (por
ejemplo, Ramon Llull) o de simular los procesos cognoscitivos (por ejemplo,
Torres Quevedo). Ya antes de la aparición del primer ordenador comercial (el
"UNIVAC I", que se entregó en 1951), Alan Turing propuso una "prueba"
(imaginaria, al estilo de los "experimentos mentales" de los físicos teóricos1) para
determinar la pretendida inteligencia de una máquina. Adaptada y resumida, la
"prueba de Turing" podría expresarse así: "póngase a la máquina y a un ser
humano en comunicación con un observador (otro ser humano inteligente) a
través de sendos terminales con pantalla y teclado mediante los cuales el
observador plantea problemas para cuya solución se requiere un cierto grado de
inteligencia; si el observador, a la vista exclusivamente de las respuestas, es
incapaz de distinguir al ser humano de la máquina, habrá de admitir que ésta posee
el mismo grado de inteligencia que el primero, en lo que respecta a la inteligencia
necesaria para resolver ese tipo de problemas".
Se da como "fecha de nacimiento" de la inteligencia artificial el 15 de
diciembre de 1955, cuando el "Logic Theorist", un programa diseñado por
Newell, Shaw y Simon, demostró el teorema 2.15 de los "Principia Mathematical
de Whitehead y Russell. En el verano de 1956 se celebró en Darmouth la primera
conferencia de IA, en la que se hicieron previsiones muy optimistas (práctica
sustitución total de todo el trabajo del hombre por la máquina en un plazo de
veinticinco años) que poco después se vieron defraudadas. Los primeros resul-
tados de la LA en productos comerciales no aparecieron hasta la década de los 80.
Pero ¿qué es la IA? No hay una definición umversalmente admitida.2 Desde
los años 50, aparecen ya claramente diferenciados dos objetivos en los trabajos
sobre IA: unos están más orientados a las aplicaciones (se define la LA como "la
manera de hacer que las máquinas ejecuten tareas inteligentes") y otros hacia la
investigación psicológica (se define la LA como "una herramienta para investigar
sobre la naturaleza de la inteligencia", o, incluso, como "la ciencia de la inteli-
gencia"). Para lo que aquí nos ocupa, nos quedaremos con la primera definición,
pero hay que observar que conduce fácilmente a una concepción evanescente de
la IA: antes de la aparición de las calculadoras mecánicas podía pensarse que tales
máquinas serían "inteligentes"; hoy nadie diría tal cosa. Del mismo modo, cuando
los ordenadores se programaban en lenguaje de máquina, los que estaban defi-
niendo los primeros lenguajes simbólicos y diseñando sus traductores trabajaban
en LA (la tarea de traducción tenía que hacerla una persona, y requería "inte-
ligencia"). Y los sistemas expertos, de los que hablaremos más adelante, fueron
las primeras aplicaciones prácticas de la LA (olvidado ya el origen, lejano, de los
1
Ello no obsta para que, desde hace unos años, se organice periódicamente un "concurso" entre programas en
el que se premia al que mejor supera la prueba de Turing "engañando" a un equipo de observadores.
2
Hay quienes opinan que la inteligencia es un atributo esencialmente humano. Para ellos, la expresión
"inteligencia artificial" es, obviamente, una contradicción en sus términos.
primeros traductores de lenguajes), pero hoy pueden considerarse como productos
informáticos "normales".
Como se ve, la cuestión conduce, en definitiva, a preguntarse: "¿qué es la
inteligencia?", y, por tanto, al segundo tipo de objetivo que hemos mencionado.
A efectos prácticos, y para centrar el tema, comentaremos brevemente dos
ideas clave, o paradigmas, que impregnan el campo de la LA aplicada: la búsqueda
heurística y los sistemas basados en conocimiento (sin entrar en áreas concretas
de la LA, como el reconocimiento y síntesis del lenguaje natural y del habla, la
visión artificial, la robótica, etc.).
221
conocimiento sobre el problema, más que sus capacidades generales de resolución
de problemas).
Se llama sistema experto a un sistema informático diseñado para resolver
problemas en algún área de aplicación, con una competencia al menos similar a
la que pueda tener un experto humano en ese área. Por ejemplo, sistemas ya
clásicos son MYCIN, sistema experto para diagnóstico y tratamiento de un
número muy reducido de enfermedades infecciosas, PROSPECTOR, sistema
experto para determinar la probabilidad de la existencia de yacimientos de ciertos
minerales a partir de las evidencias de campo, XCON, para configurar sistemas
informáticos con ordenadores VAX y PDP, etc.
Según el caso, el objetivo del sistema experto puede ser el de sustituir al
experto humano (lo que puede tener un especial interés en aquellas aplicaciones
en las que la experiencia tiene que estar disponible en lugares peligrosos o
geográficamente remotos o inaccesibles) o el de ayudar a los expertos humanos a
tratar con volúmenes de información que desbordan su capacidad (por ejemplo,
en medicina). En cualquier caso, el objetivo final es el mismo de todas las apli-
caciones informáticas: relevar a las personas de tareas mecanizables y propor-
cionarles instrumentos amplificadores de sus capacidades mentales.
Considerado como una "caja negra", un sistema experto deberá satisfacer un
criterio similar a la mencionada "prueba de Turing". Es decir, para que un sistema
artificial pueda considerarse experto en un área determinada tendrá que resolver
problemas al menos con la misma eficacia que lo hace un experto humano en ese
área. Así planteado, este criterio conduciría a considerar como expertos a muchos
sistemas "convencionales". Pero generalmente se entiende que un sistema exper-
to, además de resolver problemas, tiene que asumir otras funciones características
de los expertos humanos. Por ejemplo, poder incrementar sus conocimientos, ya
sea por contacto con otros expertos o por experiencia (aspecto éste relacionado
con el aprendizaje, que comentaremos más adelante), y poder explicar el razo-
namiento seguido para resolver un problema.
Acabamos de definir un sistema experto funcionalmente, es decir, por "lo que
debe hacer". Hablemos ahora de su estructura, que guarda una relación estrecha
con el "paradigma del conocimiento". En primer lugar, hay que decir que un
sistema experto no es más que un programa (o un conjunto de programas) para
ordenador. El usuario interactúa con ese programa, que le resuelve, o le ayuda a
resolver, sus problemas.
Ahora bien, habitualmente, cuando alguien escribe un programa para resolver
una clase de problemas en un ordenador, mezcla en las sentencias de ese
programa, de manera más o menos desordenada, los conocimientos necesarios
para ello y los procedimientos que, actuando sobre esos conocimientos, permiten
encontrar una solución para cada problema específico. Nada impide, en principio,
mantener esa forma de construcción para desarrollar un sistema con unas
especificaciones funcionales que satisfagan las características enumeradas más
arriba. Pero la necesidad de representar de manera explícita el conocimiento, de
adquirirlo a partir de expertos humanos, de acceder a él no sólo para resolver
problemas, sino también para justificar la solución, etc., aconseja la separación de
los dos componentes (conocimientos y procedimientos que los manipulan y los
usan). Ello conduce a una estructura modular cuyos dos bloques principales son
la base de conocimientos y el motor de inferencias.
Esta concepción modular del sistema, en la que se separan claramente los
conocimientos del motor de inferencias, es la que conduce a la denominación de
"sistemas basados en conocimiento". En teoría, la definición funcional de
"sistema experto" no exige que también sea un "sistema basado en conocimiento"
(puesto que, como toda definición funcional, no entra en su estructura), pero en la
práctica, todos los sistemas expertos tienen esta arquitectura.
Otro componente de los sistemas basados en conocimientos es la base de
hechos, que contiene, para cada problema, los datos relativos al mismo (por
ejemplo, las manifestaciones de cada paciente y las conclusiones intermedias). Y
también son importantes las interfaces: la interfaz del experto (para construir,
examinar y modificar la base de conocimientos) y la interfaz del usuario final.
223
comunicación con el usuario final: para que el sistema sea aceptable debe
"convencer", y para ello debe ser capaz de justificar la línea de razonamiento
seguida en cada caso, y, si hace alguna pregunta (es decir, pide algún dato para
completar la base de hechos), explicar el motivo de la misma. Todo este conjunto
de problemas ha dado lugar a un campo de trabajo que se conoce con el nombre
de ingeniería del conocimiento (o "ingeniería del saber", o "ingeniería cognosci-
tiva", o "ingeniería epistemológica").
En el estado actual de la ingeniería del conocimiento, la adquisición se
entiende fundamentalmente como una actividad de modelación-, para diseñar un
sistema experto hay que empezar por establecer un modelo de la experiencia (es
decir, de la actividad del experto, en términos del conocimiento que aplica para
resolver los problemas), un modelo del entorno, de la comunicación, etc. Después,
hay que escoger la arquitectura más adecuada de acuerdo con ese modelo (la que
hemos sugerido, formada por los bloques de base de conocimientos, motor de
inferencias, base de hechos e interfaces, es la más primitiva; hay otras más
elaboradas, como las basadas en pizarras, las jerárquicas y las de agentes). Y para
la implementation del sistema existen herramientas (entornos de desarrollo
especializados, formados por programas que facilitan todas las actividades de
construcción del sistema) muy potentes.
En este capítulo veremos cómo la formulación lógica es un posible (aunque
primitivo) modelo para la representación del conocimiento. Para simplificar la
exposición, usaremos solamente la lógica de proposiciones. Explicaremos
asimismo el funcionamiento de los motores de inferencia (en lógica de propo-
siciones) y cómo se aborda el problema de la representación del conocimiento
impreciso. También daremos una idea de otros esquemas más estructurados para
la representación del conocimiento.
224
Este es un modelo muy general. Aquí sólo veremos algunos detalles del caso
particular en el que las reglas de producción son sentencias condicionales
expresadas en lógica de proposiciones, y la base de datos es un conjunto de
variables proposicionales.
A l A
hi A2 •••lAn l
B
De todos modos, A podría ser una sentencia cualquiera: con unas trans-
formaciones similares a las que hacíamos en el capítulo 2 (apartado 5.5) para
llegar a la forma clausulada, puede verse que A siempre se puede transformar en
un conjunto de sentencias de este tipo particular. Por su parte, B también podría
ser cualquier sentencia. Sólo supondremos, de momento, y por las razones que
veremos más adelante (en el apartado 3.1), que no contiene la conectiva " v". Si,
por ejemplo, B fuera una conjunción de literales, lB1 A lB2 A ... A lBm, la sentencia
podría descomponerse en m sentencias con el mismo antecedente y cada una de
ellas con uno de los literales como consecuente.
Obsérvese que esta forma de sentencia es la que en el capítulo 2 (apartado 5.6)
llamábamos "cláusula de Horn con cabeza", salvo que ahora las variables pro-
posicionales pueden ser literales. (Por otra parte, todo el conjunto de la base de
datos puede interpretarse como una cláusula de Horn sin cabeza y negada). Esta
forma, aparte de que nos va a simplificar la estructura del sistema de control (o
225
motor de inferencias), es, además, la que de manera natural se obtiene cuando se
le pide a un experto que ponga su conocimiento en forma de reglas.
Por ejemplo, en la base de conocimientos del sistema XCON hay unas 2500
reglas. Una de ellas (traducida a lenguaje natural) es:
(p1Ap2Ap3Ap4Ap5) -» q
Otro ejemplo, menos real pero quizás más sugerente, podría ser el de un
experto médico que contuviera las reglas:
Rl: f A t A m — » g
R2a: gA—M^a
R2b: g A —W
i —> c
R2c: r A —M —> a
R2d: T A —M — > c
2.4. Sistema de control (o motor de inferencias)
2.4.1. Estrategias hacia adelante y hacia atrás
Suponemos existente una base de conocimientos codificada como un conjunto
de reglas de producción, R1,R2... del tipo que hemos visto, en las cuales
interviene un conjunto de hechos diversos representados por literales, l v l2, ...,
l\, 1'2, .... Ante una situación, se tiene la evidencia de que un subconjunto de esos
hechos, l v l2, ... son verdaderos, y se trata de encontrar qué otros hechos,
l\, 1'2, ... pueden inferirse de esa certidumbre y de las reglas, o dicho de otro
modo, de encontrar los VK tales que
sean tautologías.
/A t Am
Rl: f A t A m —> g
(modus ponens)
g
g A —lU
R2a: g A —I u a
a (modus ponens)
g A-IM
R2b: g A —I U —» C
c (modus ponens)
Normalmente, no tendremos dos, sino muchas reglas (en los sistemas expertos
es frecuente que sean del orden de cientos o de miles), y, ante unos hechos, hay
227
dos formas de enfocar el procedimiento de inferencia (es decir, dos estrategias
básicas):
(b) Fijarse un hecho como objetivo y tratar de deducirlo, viendo de qué reglas
de producción es consecuente; si alguno de los antecedentes de esas reglas
no figura en la base de hechos fijarlo como subobjetivo, etc. Este es el
principio del encadenamiento hacia atrás.
2.4.2. Un ejemplo
Antes de entrar en la explicación de los algoritmos de inferencia, veamos sobre
un ejemplo cómo se aplicarían los procedimientos de encadenamiento hacia
adelante y hacia atrás. El ejemplo es abstracto, en el sentido de que partiremos de
un conjunto de reglas de producción y de hechos escritos en forma simbólica,
prescindiendo de su significado en un contexto de conocimiento.
Supongamos la base de conocimientos constituida por las siguientes reglas de
producción:
R1:A^>C R6:D A G —
R2:A^H R1:CaF^>B
R3:C^D R8:AaH^D
RA: D — R 9 : A a C a H - ^ B
ABH A C H D E B F X
R 1 2 3 4 9 10 5
donde en la línea superior se indican los hechos con los que sucesivamente se va
incrementando la base de hechos, y en la inferior las reglas que en cada momento
se aplican. Como vemos, en este caso termina por incluirse X, por lo que del hecho
inicial, A, se infiere X.
No es necesario volver a empezar siempre con la primera regla cada vez que
se llega a aplicar una de ellas. Otra estrategia, por ejemplo, es la de buscar la regla
que contenga más premisas incluidas en BH; con ella, la inferencia de X en el
ejemplo seguiría esta otra secuencia:
ABH A C H B F X
R 1 2 9 10 5
1. Se trata de ver si puede deducirse X. ¿En qué reglas figura como con-
secuente?
2. Vemos que sólo lo hace en la R5. Por tanto, nuestro objetivo (X) se
descompone en los subobjetivos que figuran como antecedentes (en forma
conjuntiva, es decir, tienen que darse ambos) de esa regla (B y F).
229
3. Empecemos con B. Figura como consecuente en tres reglas: R6, R1 y R9.
Basta pues con deducir los antecedentes de una de esas tres reglas.
(bucle)
Figura 6.1.
2.4.3. Estrategias de resolución impulsadas por los hechos
En el ejemplo anterior hemos utilizado siempre la regla de inferencia de modus
ponens. Como vimos en el capítulo 2 (apartado 5.7), todas las reglas de inferencia
pueden resumirse en una, la de resolución. Allí estudiamos la resolución en
general, aplicada sobre dos cláusulas cualesquiera (generatrices). Vemos que
ahora una de las cláusulas es un condicional y la otra un hecho (un literal). Por
ejemplo, una vez que la base de hechos contiene B y F, R5 nos permite inferir, por
modus ponens, X. Con la resolución necesitaríamos dos pasos (puesto que B y F
son dos cláusulas). Concretamente, R5 en forma clausulada sería:
—B v - i f v J
nFvI
Si la base de hechos contiene lA1, lA2, ..., lAn, la ley anterior nos permite inferir
lB.
Decimos que ésta es una resolución impulsada por los hechos", es una
restricción de la regla de resolución, porque sólo una de las generatrices es una
cláusula cualquiera (disyunción de literales), pero, al mismo tiempo, es una
ampliación porque admite un número indefinido de otras cláusulas siempre que
éstas sean simplemente literales (hechos).
231
Diremos que un literal l¡ está demostrado si figura en la base de hechos (BH).
Si figura como tal estará demostrado como cierto, y si lo que figura es su negación
estará demostrado como falso.
Diremos que una regla lx v l2 v ... v ln puede dispararse si todos los l¡ menos
uno están demostrados como falsos (y, en tal caso, nuestra regla de inferencia nos
permite decir que el que queda es cierto). Una regla se elimina si o bien se ha
disparado (y en ese caso no sirve más)3 o bien alguno de sus componentes
(literales) se ha demostrado que es cierto (y en ese caso no nos permite inferir
nada). Las reglas activas son las que no están eliminadas.
Llamaremos valor de una regla al número de componentes no demostradas, si
está activa; si una regla está eliminada su valor será 0. El valor de una componente
(dentro de una determinada regla) será 0 ó 1 según que esa componente figure
negada o sin negar, respectivamente, en la regla.
El algoritmo utiliza dos procedimientos. Uno de ellos, al que llamaremos
"inferir", recorre todas las reglas para ver si alguna puede dispararse, y, en
caso afirmativo, infiere la conclusión, la introduce en la base de hechos, elimina
la regla y llama al segundo procedimiento, "actualizar". Lo que hace éste es,
dado un hecho, actualizar el valor de todas las reglas en las que figura. Tenemos
así:
procedimiento inferir;
mientras haya reglas activas
para cada regla activa
si valor[regla] = 1 entonces
conclusión := componente no demostrado;
valor[conclusión] := valor del componente en la regla;
introducir conclusión con su valor en la BH;
valor[regla] := 0;
actualizar(conclusión);
procedimiento actualizar(hecho);
para cada regla activa
si regla contiene hecho entonces
si valor[hecho] = valor del hecho en la regla
entonces valor[regla] := 0
si no, valor[regla] := valor[regla]-1;
3
Obsérvese que ésto sería incorrecto en el caso de utilizar la lógica de predicados.
2.4.5. Un algoritmo con encadenamiento hacia atrás
Este otro algoritmo utiliza dos procedimientos. El llamado "nodoo" resuelve
un nodo "O" del árbol, examinando todas las reglas "aplicables" (una regla es
aplicable ante un objetivo si contiene un literal que es igual al complemento de
ese objetivo); si no puede demostrarlo (variable booleana "demostrado" con el
valor falso tras examinar todas las posibilidades), pregunta por él al usuario. El
procedimiento "nodoy" se aplica a un conjunto de objetivos (los que corres-
ponden a una ramificación de tipo "Y"), a cada uno de los cuales aplica el
"nodoo":
procedimiento nodoo(objetivo,demostrado);
demostrado := falso;
si objetivo incluido en BH entonces demostrado := cierto
si no, para todas las reglas aplicables
mientras demostrado sea falso
elegir una regla, Ri;
nodoy(literales de Ri salvo objetivo,demostrado);
si demostrado = falso entonces
preguntar(objetivo);
si hay respuesta entonces
añadirla a la BH;
demostrado := verdadero;
233
puede ser media, alta, etc. Si seguimos utilizando lógica de proposiciones
tendremos que multiplicar el número de variables proposicionales (fm: fiebre
media, fa: fiebre alta, etc.), y, para incluir todo el conocimiento, multiplicar
también el número de reglas (de modo que cada una incluya un caso particular).
Se comprende fácilmente que en una aplicación real (que contendrá muchos
atributos con muchos valores cada uno) esto conduce a un tamaño inadmisible de
la base de conocimientos.
Ya sabemos que la lógica de predicados nos permite expresar conocimientos
más generales. Así, si la regla fuese:
la lógica de proposiciones nos exige escribir una regla para cada una de las
combinaciones de valores de atributos, pero la de predicados nos permite
formalizar ese conocimiento así, por ejemplo:
donde F(x,y) se interpreta como "el paciente x tiene fiebre con valor y", y T(x,z)
como "el paciente x tose con intensidad z".
Por tanto, para las aplicaciones resulta mucho más conveniente tomar la lógica
de predicados como modelo para la representación del conocimiento. El
inconveniente es que entonces los algoritmos para el motor de inferencias pueden
llegar a ser muy ineficientes. Los esquemas que hemos visto anteriormente en
seudocódigo siguen siendo, en esencia, válidos, pero hay que incluir en ellos un
mecanismo de unificación (apartado 4.6 del capítulo 4). Como una misma regla
es aplicable a individuos u objetos distintos, hay que probarla para cada uno de
ellos.
Para mitigar este problema de eficiencia se puede restringir la forma de las
reglas y diseñar algoritmos de búsqueda no exhaustiva. Así se hace en Prolog,
lenguaje basado en la lógica, que comentaremos en el apartado 2.4.3 del capítulo
5 del tema "Lenguajes". En la mayoría de los sistemas expertos basados en reglas
se adopta un enfoque pragmático: se admite que los componentes de las reglas no
sean proposiciones, sino que tengan una cierta estructura, aunque no tan general
como la que permite la lógica de predicados. Concretamente, utilizan lo que se
llaman "triplas objeto-atributo-valor", y las reglas son de la forma:
Este enfoque, analizado desde un punto de vista formal, equivale a decir que
se utiliza una forma restringida de la lógica de predicados. En efecto, la tripla
<OA,V> es equivalente a "I(A(0),V)", donde I es el predicado "igual" y A es la
función "atributo". Todas las reglas se pueden así formalizar en una lógica de
predicados que sólo usa ese predicado. Es pues, una forma de la lógica intermedia
entre la de predicados (de primer orden) y la de proposiciones (de orden 0), y de
ahí que la llamemos " lógica 0+".
3. Inferencia plausible
3.1. Fuentes de imprecisión y de incertidumbre
Ocurre con mucha frecuencia que, desde el primer momento en que se empieza
a pensar en el diseño de un sistema basado en conocimiento, hay que enfrentarse
ineludiblemente al problema de la incertidumbre y de la imprecisión, cuyo origen
está tanto en el experto como en el usuario final.
En el experto, cuando tiene que expresar su conocimiento. Si el esquema de
representación elegido es el de las reglas de producción (el único que aquí estamos
tratando) la incertidumbre y la imprecisión se traducen en la forma de las reglas.
En efecto, decíamos en el apartado 2.3 que las reglas de producción tenían que
poder expresarse como sentencias condicionales en cuyo consecuente no figurase
la conectiva " v". La justificación es que una sentencia como
A^q1vq2
235
podría concluir nada): ante unas evidencias (signos y síntomas en el caso del
diagnóstico médico), puede albergar dudas, pero normalmente "cree" más en unas
alternativas que en otras. El problema es cómo cuantificar ese "grado de creencia",
y cómo trabajar con él para poder hacer deducciones "plausibles".
La imprecisión e incertidumbre en el usuario aparecen cuando tiene que decir
si cierto hecho está presente o no. Por ejemplo, decíamos más arriba (apartado
2.4.1) que parece poco razonable que el usuario tenga que responder "sí" o "no"
a una pregunta del sistema sobre si el paciente tose.
"Incertidumbre" e "imprecisión" son dos conceptos diferentes: una pro-
posición es incierta si su valor de verdad o falsedad no se conoce o no se puede
determinar, y es imprecisa si se refiere a alguna variable cuyo valor no puede
determinarse con exactitud (por tanto, una proposición incierta puede ser precisa,
y una imprecisa no ser incierta). En el ejemplo de dado más arriba para la regla,
el condicional es incierto, mientras que en el ejemplo de la respuesta del usuario,
ésta es imprecisa.
Veremos aquí dos de los mecanismos que se utilizan en los sistemas basados
en conocimiento para abordar estos problemas (un tercero lo hemos estudiado en
el capítulo anterior: la lógica borrosa). Al nivel introductorio en que nos vamos a
mover no será necesario entrar en diferenciaciones entre incertidumbre e
imprecisión.
Ahora bien, obsérvese que esto es, precisamente, lo que el experto tiene que
inferir: si hay varias hipótesis posibles (por ejemplo, aquí debajo hay un
yacimiento de molibdeno, o de cobre, o de oro, o... no hay nada) y se presenta una
evidencia E compuesta por otras, E = Et y E2 y... (por ejemplo, el terreno es
arcilloso y en un arroyo cercano alguien se ha encontrado una pepita de oro y...),
de lo que se trata justamente es de llegar a saber cuáles son las probabilidades
P(Ht\E), P(H2\E),... Si el experto (humano) pudiera darnos todas esas
probabilidades para todas y cada una de las posibles combinaciones de E,
entonces el sistema experto se limitaría a tenerlas almacenadas y a efectuar una
búsqueda cuando se le diera una determinada combinación de E. Pero esto es
impensable, por el gran número de combinaciones posibles que pueden formar E:
no hay experto dispuesto a pasarse años enumerando las distintas posibilidades
(terreno arcilloso o no, presencia de ciertas rocas o no, etc.) y dando para cada una
de ellas y para cada hipótesis posible una probabilidad.
Lo que sí puede darnos el experto humano son unas estimaciones de las
probabilidades a priori de cada una de las hipótesis (P(Hj): probabilidad de que
se dé H sin saber nada más) y de las probabilidades de que se presenten cada uno
de los elementos atómicos de evidencia supuesto que cada una de las hipótesis es
verdadera (P(Ej): probabilidad de que, supuesto que hay molibdeno, el terreno
sea arcilloso, etc.). Con esta información, el cálculo de las probabilidades a
posteriori, que es lo que interesa, se puede hacer aplicando el conocido teorema
de Bay es: Si aparece la evidencia E¡, entonces
P(Hj)P(Ei\Hj)
L
P{H¡\E¿= ' -
^PiHJPiE^Hj)
P(Hj)P(Ei\Hj)
P (Hj\Ef) = ^ — (1)
P (Hj) P (E¡\Hj) + P (Hj) P (E¡\Hj)
Análogamente,
P (H^Ei) = — — (2)
P (Hj)P (E¡\HJ) + P (H¡) P (E\H¡)
237
donde P (E¡\Hj) = 1 -P(Et\H¡) y P(Ei\Hj)= l-P(Et\Hj)
P{E\H¿= UP(.E,\Hj)
tras lo cual se aplica la fórmula anterior; para que ese cálculo fuese correcto sería
preciso que todos los E¡ fuesen independientes entre sí;
(b) por pasos: para , se calculan con la fórmula (1) P(Hj\E1) (si es que E¡
es verdadera; si no, se utiliza la fórmula (2)); estos valores se toman como
nuevos valores de las probabilidades a priori, P(Hj), y se vuelve a aplicar
la fórmula con E2, y así sucesivamente. Puede demostrarse que el error
cometido en el caso de que no todos los E¡ sean independientes es menor
que con el procedimiento anterior.
PjHJPjE^íh)
P(H1\E1) =
PiHJPiEi^) +P(H1)P(E1\H1)
239
y, similarmente, P[FÍ2\E-Ij= 2.0783*10 3;P(H3¡EI)= 4.084H0 - 3
con
Hj^E^MS^MNJ
241
V(Hj |-E,). Y para valores de R intermedios, el sistema hace una interpolación entre
MS¡j, 1 y MNjj. Si, por ejemplo, se hacen interpolaciones lineales, tendríamos las
siguientes fórmulas:
R*(MS„-1) +5
si R> 0, M¡j= ^
si R= 0, M¡j= 1
R* (1-MJV,.) +5
si R< 0, M¡¡= —j-1*
V(£RJ.¡EL)= MI}*V(HJ)
É^HjiC,;)
donde C¡j es el factor de certidumbre de la regla4, número comprendido entre -1
y +1 que expresa el "grado de confianza" en esa regla: supuesto que E¡ sea
verdadero, C¡j= + 1 correspondería a una seguridad absoluta de que se deduce
Hj, y C¡j= - 1 a una seguridad absoluta de que H¿ es falsa ( C¡j= 0 corres-
pondería a una incertidumbre o ignorancia total sobre el asunto).
4
Quizás fuera mejor llamarle "factor de incertidumbre": "certidumbre", sinónimo de "certeza", indica una
seguridad absoluta, y no parece adecuado graduarla mediante un "factor".
3
Recuérdese (apartado 1.2) que, en las técnicas de inteligencia artificial, se llama heurístico a cualquier "truco",
o regla empírica, que se ha comprobado que sirve de ayuda en la resolución de un problema.
243
En los nodos "Y", de acuerdo con los heurísticos anteriores, el C de la regla
se multiplica por el menor de los C de las premisas.
• En los nodos "O", si sólo hay dos ramas para cuyos elementos se han
calculado C1 y C 2 , el factor de certidumbre del resultado es:
C= C1 + C2-C*C2 si C1*C2 > 0
Cx + C 2
C slC C
- l-mín^C^C^) * 2< 0
Si hay más de dos ramas, se calcula el C para las dos primeras, el resultado se
combina con el de la tercera, etc.
• Siempre que como consecuencia de un cálculo resulte |C| < 0,2, se hace
C=0. (Esto acelera los algoritmos y hace más claras las explicaciones y
justificaciones del sistema).
Para ilustrar con un caso simplificado cómo se aplican estos heurísticos,
volvamos a nuestro ejemplo de la fiebre, la gripe, etc. Supongamos que la base de
conocimientos está formada por las nueve reglas enumeradas en el apartado 3.2,
pero interpretando que lo que allí se llaman "probabilidades" son factores de
certidumbre. Es decir:
- 0 , 4 + 0,09
-0 34
1 - 0,09 ~ '
y combinando este factor de certidumbre con el de la Rama3,
C 0,54
s~ 1-0,34 ~
Procediendo de igual modo con las otras hipótesis se obtiene:
Cb= 0,68 ,yCtb= -0,08,
es decir, algo más de certidumbre en que sea bronquitis que gripe, y una
incertidumbre prácticamente absoluta en cuanto a que pueda o no ser tuberculosis.
245
Esta base de hechos es pequeña, pero en un caso real podría contener cientos
de predicados, y para mejorar el acceso convendría estructurarla. Por ejemplo,
podríamos agrupar separadamente (aun cuando aparezcan repeticiones) los
hechos referentes a la memoria y los referentes al procesador:
Memoria:
t(mj>¿>); T(P,M,D)- t(MJPJ); f(maj)- f(maj>)
Procesador:
w ^ ) ; t(pmp)\ T(MJ>j); F(PJij)
Ahora los hechos están indexados por objetos del dominio del discurso. Se dice
que es una representación centrada en los objetos, en este caso, en los objetos
físicos. También podemos adoptar una representación centrada en objetos
abstractos: transferencias y funciones.
Todos los predicados de este ejemplo son ternarios. Pero en las repre-
sentaciones estructuradas es preferible trabajar sólo con predicados binarios. La
razón es que si se quiere perfeccionar el conocimiento diciendo, por ejemplo, que
la transferencia de datos de la memoria al procesador se hace a través del bus de
datos, habría que convertir el predicado ternario en otro cuaternario, y habría que
modificar también los procedimientos de inferencia. Vamos a ver que es posible
expresar todo con predicados binarios y conseguir un sistema más modular y fácil
de actualizar.
Definamos, para nuestro ejemplo, dos conjuntos, o clases: {transferencias} y
{funciones}. Todo lo que se dice sobre transferencias y funciones puede
expresarse mediante predicados binarios que relacionan a los argumentos de los
predicados ternarios originales con un elemento arbitrario de esas clases. Por
ejemplo, la fórmula atómica T(M,P,D) se transformará en la sentencia
y la F(Pjrj), en
TI
Pertenece(71, {transferencias})
fuente(Tl) = M
destino(ri) = P
objeto(ri) = D
etc.
Como ahora todas las funciones figuran dentro de un grupo identificado por su
argumento, no hace falta especificar éste, y escribiremos "fuente: M", etc.
Además, para abreviar el predicado "Pertenece(ri,{transferencias})"
escribiremos "tipo: transferencias". Llegamos así a la representación estructurada:
TI
tipo: transferencias
fuente: M
destino: P
objeto: D
T2
tipo: transferencias
fuente: P
destino: M
objeto: D
247
73
tipo: transferencias
fuente: M
destino: P
objeto: I
F1
tipo: funciones
unidad: P
función: R
objeto: I
F2
tipo: funciones
unidad: M
función: A
objeto:/
F3
tipo: funciones
unidad: M
función: A
objeto: D
tipo: unidades
tipo: funciones
tipo: funciones
/
D
tipo: informaciones
Una red semántica es un grafo en el que los nodos pueden representar objetos,
conceptos o conjuntos y los arcos relaciones entre ellos. Para nuestro ejemplo, la
red semántica podría ser la dibujada en la figura 6.2.
249
orientada a objetos, cuyos fundamentos estudiaremos en el tema "Algoritmos"
(capítulo 4, apartado 5).
5. Resumen
La lógica formal es una herramienta adecuada para la representación del
conocimiento declarativo, procedimental y de control y, por tanto, para el diseño
de sistemas basados en conocimiento y sistemas expertos.
Uno de los modelos más utilizados para el diseño de sistemas basados en
conocimiento es el de los sistemas basados en reglas. Las reglas pueden
formalizarse como sentencias condicionales, y, por tanto, todo lo que la lógica nos
enseña sobre sistemas inferenciales es aquí aplicable.
Los expertos humanos suelen trabajar con reglas no muy bien definidas y con
elementos de evidencia imprecisos o inciertos. Para diseñar un sistema experto es
preciso modelar esos aspectos de la actividad humana, y para ello existen varias
técnicas: factores de certidumbre, probabilidades, lógica borrosa, etc.
Hay otras técnicas para representar el conocimiento de una manera más
estructurada que con la lógica. Las más conocidas son los marcos ("frames") y las
redes semánticas.
250
software para el desarrollo de sistemas expertos. Actualmente podemos más bien
hablar de una "asimilación": la arquitectura de los sistemas basados en
conocimiento, y, particularmente, la basada en "agentes inteligentes" está
plenamente integrada entre las técnicas de la ingeniería del software (y raramente
se la relaciona ya con la "inteligencia artificial").
Post (1943) fue el primero que, desde un punto de vista teórico, formuló el
modelo de "sistema de producción" como un mecanismo computacional general.
Las redes semánticas se propusieron inicialmente como modelo de la memoria
humana (Quillian, 1968), y se han utilizado en los sistemas expertos PROS-
PECTOR (Duda etal., 1978), CASNET (Weiss el al., 1978), CADUCEUS(Myers
et al., 1982), IRIS (Trigoboff y Kulikowski, 1981), etc., y los marcos (frames)
fueron introducidas por Minsky (1975) con idea parecida ("cuando a la mente se
le plantea una situación nueva, busca en la memoria alguna estructura es-
tereotipada de información"), y en ellas se han basado otros diseños, como los
sistemas PIP (Pauker et al., 1976), RADEX (Chandrasekaran et al, 1980),
CENTAUR (Aikins, 1983), etc., y otras representaciones estructuradas, como las
escenas (scripts), de Schank y Abelson (1977).
Hayes (1977, 1979) puso de manifiesto las relaciones entre las repre-
sentaciones en lógica de predicados y mediante estructuras. En la presentación de
estas relaciones en el apartado 4 hemos seguido a Nilsson (1987).
Como textos generales sobre inteligencia artificial, aparte del ya citado de
Nilsson (que está traducido), teórico y académico, otro clásico, pero más práctico,
es el de Charniak y McDermott (1985), y, más moderno (y también traducido), el
de Rich y Knight (1994). Sobre el debate de si la IA es posible, todos los que se
sienten inclinados a responder inmediatamente "sí" deberían leer el libro de Kelly
(1993), que contiene una reflexión crítica profunda sobre la cuestión.
Sobre sistemas expertos, el libro de Buchanan y Shortliffe (1984) describe con
todo detalle MYCIN, EMYCIN y demás desarrollos del "Stanford Heuristic
Programming Project". Un texto detallado y orientado a la programación con
OPS5 (lenguaje orientado al desarrollo de sistemas de producción) es el de
Brownston et al. (1985). Más fundamental, sobre sistemas basados en cono-
cimiento en general, es el de Frost (1986). En estos libros se pueden estudiar los
principios y modelos básicos de los sistemas expertos. Sobre aspectos más
prácticos de la ingeniería del conocimiento (selección de herramientas, gestión de
proyectos, etc.) trata el de Prerau (1990). El de Durkin (1993) contiene un catálogo
de cientos de aplicaciones de los sistemas expertos. Hay muchas publicaciones
periódicas sobre este tema. Una de las más conocidas es el "IEEE Expert".
De la incertidumbre en IA trata el libro de Kanal y Lemmer (1986), y del
razonamiento aproximado el de López de Mántaras (1990). La teoría de la
evidencia se puede estudiar en el libro de Shaffer (1976), pero, como decíamos en
el apartado 3.3, no se está aplicando en el diseño de sistemas expertos. Los otros
dos marcos teóricos son la teoría de la posibilidad y la teoría de las redes de
creencias. Para el primero, remitimos a la bibliografía citada en el apartado 6 del
capítulo 5, y para el segundo, al texto de Pearl (1988).
251
Parte II
Autómatas
1
Ideas generales
1. Autómatas e información
La palabra "autómata", en el lenguaje ordinario, normalmente evoca algo que
pretende imitar funciones propias de los seres vivos, especialmente las relaciona-
das con el movimiento. (Véase, para corroborar esta aserción, la definición de un
diccionario cualquiera.) En este sentido, un ejemplo de autómata sería el típico
robot antropomorfo o zoomorfo dotado de capacidades autónomas de movimiento
que le permiten ejecutar las órdenes o seguir el programa establecido por un ser
inteligente.
En el campo de la Informática lo fundamental no es la simulación del mo-
vimiento, sino la simulación de los procesos de tratar la información, y el ejemplo
típico de autómata no es ya el robot mecánico sino el ordenador.
Pensemos en la naturaleza del trabajo que realizan los ordenadores. Bastan
unos conocimientos básicos de informática para llegar a conclusión de que un
ordenador no es más que un dispositivo que manipula símbolos. Un ejemplo será
útil para reforzar esta idea:
Consideramos un ordenador con registros de dieciséis bits. Supongamos que
este ordenador recibe de un periférico una serie de impulsos que se graban en un
registro dejando en él la siguiente configuración de bits:
255
1010010001000001
¿Qué significa esto para el ordenador? Entre otras muchas cosa puede ser:
• El diseñador del ordenador (para ser realista habría que hablar del equipo
de diseño), que decidió que los números se representen en binario y com-
plemento a 2, o que, interpretado como instrucción, ese código de operación
signifique, por ejemplo, "sumar", y no otra cosa, etc.,
• El usuario (en este caso, el programador), que decide que en momento dado
el ordenador lleve esa configuración de bits de la memoria al acumulador,
o al registro de instrucción, o a la unidad de salida, etc. Al tomar tal
decisión, el usuario está dotando al conjunto de bits de una significación y,
por consiguiente, de una capacidad para representar información. Para el
ordenador, sin embargo, los bits no son más que símbolos materializados
por los niveles de tensión en los circuitos.
3. Autómatas y lenguajes
Un campo importante dentro de la Informática, al que dedicaremos el último
tema, está constituido por el estudio de los lenguajes y las gramáticas que los
1
Realmente, no basta con conocer toda la historia de símbolos de entrada para saber cuál es la salida; es necesario
conocer también el "estado inicial", es decir, el estado en el que se encontraba el autómata al recibir el primero
de los símbolos de entrada.
257
generan. Los elementos de un lenguaje son sentencias, palabras, etc., formados a
partir de un alfabeto (capítulo 1, apartado 5 del tema "Lógica"). Establecidas unas
reglas gramaticales, una cadena de símbolos pertenecerá al correspondiente len-
guaje si tal cadena se ha formado obedeciendo esas reglas; puede entonces
pensarse en la posibilidad de construir un autómata reconocedor de ese lenguaje,
tal que cuando reciba a su entrada una determinada secuencia de símbolos
produzca, por ejemplo, un "1" a la salida si la secuencia es correcta, y un "0" si no
lo es. De este modo, como veremos en su momento, a cada tipo de gramática
corresponde un tipo de autómata.
4. Autómatas y álgebra
Las cadenas de entrada y salida de un autómata se forman a partir de los
correspondientes alfabetos mediante una operación que consiste en poner los
símbolos unos a continuación de otros. Esta operación se llama concatenación, y
es asociativa. Por consiguiente, el conjunto de todas las cadenas con la concate-
nación tiene una estructura algebraica de semigrupo; si, además, definimos un
elemento neutro, tendremos un monoide.
Por otra parte, como veremos en el capítulo siguiente, si el autómata es finito
(es decir, si tiene un número finito de estados) puede determinarse un número
finito de clases de equivalencia en el semigrupo (o monoide) de entrada, lo cual
permite definir un semigrupo (o monoide) cociente llamado el semigrupo (o
monoide) de la máquina, a partir del cual pueden formalizarse muchas cuestiones
relativas al funcionamiento de los autómatas.
Siguiendo esta línea de trabajo, se ha elaborado en las últimas décadas una
teoría abstracta de autómatas con una fuerte base algebraica que, según Arbib
(1969), constituye "la matemática pura de la Informática".
5. Resumen
La teoría de autómatas, también llamada teoría algebraica de máquinas, per-
mite estudiar de un modo sistemático las máquinas, más o menos complicadas,
que realizan un procesamiento de la información y que actúan de manera discreta,
es decir, la información se supone codificada a partir de un conjunto finito de
símbolos que el autómata trata secuencialmente, uno detrás de otro. La teoría de
autómatas proporciona métodos para el análisis y la síntesis de tales máquinas.
Los trabajos sobre lenguajes y gramáticas formales han evolucionado en una
dirección que les ha conducido a encontrarse con la teoría de autómatas como
herramienta matemática de gran utilidad.
La teoría de autómatas no sólo puede aplicarse a las "máquinas", en el sentido
estricto que normalmente damos a esta palabra, sino también a muchos sistemas
258
naturales, y, en general, permite estudiar procesos que dependen de una "historia",
es decir, cuyo comportamiento presente es función del pasado.
En sus treinta años de historia la teoría de autómatas se ha constituido en una
disciplina muy formalizada que sigue en evolución. Mientras la teoría básica
(autómatas finitos deterministas) puede considerarse definitivamente establecida,
se abren nuevas vías que actualmente son objeto de estudio de los investigadores
y que ofrecen amplias perspectivas de aplicación: autómatas estocásticos, bo-
rrosos, adaptativos, de aprendizaje, etc.
Evidentemente, en este tema no podemos exponer ni siquiera resumir, toda la
teoría de autómatas. Nuestro objetivo será presentar los principios básicos,
desarrollando algunos ejemplos de aplicación para ver su utilidad práctica en
diversos campos, especialmente el de la Informática.
259
2
Autómatas
Finitos
donde:
261
• / e s una función/: E x Q —»Q, llamada función de transición o función de
estado siguiente.
1.2. Representación
1.2.1. Tabla de transiciones
Las funciones/y g pueden representarse mediante una tabla con tantas filas
como estados y tantas columnas como entradas. Si la fila i corresponde al estado
q¡ y la columna j corresponde a la entrada e , en la intersección de ambas se
escribirá f(e.,q¡}lg(epq). Por ejemplo, sea el AF definido por los conjuntos
E = {a,b}
S = {0,1}
Q = U i M s }
f{a,q,) = q¿ g(a,q,) = 0
Ñ>Ai) = s(b,qt) = 1
flp,q2) = s(b,q2) = o
e
a b
9. qjo qjl
I2 qjo qj0
Í3 qjl qJO
Figura 2.1.
Figura 2.2.
263
1.3. Máquinas de Moore y de Mealy
El modelo general de autómata que hemos definido se llama máquina de
Mealy. Las funciones / y g determinan la salida y el estado siguiente cuando la
máquina se encuentra en un estado q e Q y recibe una entrada e e E. Ahora bien,
por conveniencia matemática, es interesante considerar, además de los símbolos
o elementos de E, un elemento neutro, A; físicamente, el decir que la entrada es
A,, es lo mismo que decir que no hay ninguna entrada. Es inmediato entonces
plantearse la siguiente pregunta: ¿qué ocurre si, estando un autómata en el estado
q e Q, recibe como entrada A ? Para responder a esto, matemáticamente, habría
que ampliar el dominio de /, que es E x Q, a {E u {A,} } x Q, y lo mismo el
dominio de g. La ampliación del dominio de / no plantea ningún problema: se
puede convenir que /(A ,q) = q (es decir, físicamente, que si no hay entrada no se
cambia de estado). Pero no ocurre lo mismo con g; y ello se ve fácilmente si nos
referimos al ejemplo desarrollado más arriba (figura 2.1): si llegamos a q1 ya sea
de q} (por efecto de entrada tí) o de q1 (por a) la salida es 0, por lo que podemos
asociar la salida 0 al estado qA y decir g(X, q¡) = 0; sin embargo, no podemos
definir g(X, q2), ya que si llegamos a q2 desde q¡ la salida es 1, mientras que si
llegamos desde el propio q2 la salida es 0. Es evidente que, en general, sólo puede
definirse g(X, q) en el caso en que se cumpla que
es decir, que a q se le pueda asociar una salida y una sola. Si esto ocurre para todo
q e Q podemos definir una función inyectiva h: Q S tal que g(e, q) = h\f(e,
q)], e e [E u {A,} } , qe Q. En este caso, podemos decir que la salida sólo
depende del estado, y el autómata se llama máquina de Moore. Expresando el
tiempo de manera explícita:
A = <E, S, Q, f, g>
A = <E,S,Q,f,g>
K e , ( f ) = W,q)r-)
g(e,q¡) = g(e,q)
A
S
1
s aquí es un superíndice, no un exponente.
265
a
JO b
QY 1
Figura 2.3.
Obsérvese que, al estar las salidas asociadas con los estados, todas las transi-
ciones que conducen a un estado producen la misma salida, por lo que en lugar de
rotular las salidas sobre los arcos las hemos incluido en los nodos. Del mismo
modo, en la tabla de transiciones podemos incluir las salidas en la misma columna
de estados; la tabla de esta máquina de Moore es entonces la de la figura 2.4.
En una máquina de Moore podemos considerar el monoide <E\ > , al que se
llama monoide libre de entrada. En una máquina de Mealy sólo podemos hablar
del semigrupo libre de entrada, <E\ >. En lo sucesivo siempre que hablemos de
un autómata supondremos, a menos que se diga lo contrario, que se trata de una
máquina de Moore, es decir, representaremos indistintamente la salida por la
función de salida g(e, q) o por h(q) teniendo en cuenta que g = hof.
266
e
a b
q¡s\
1
qjo h q
2
0 0
q /O q q
2 3 2
1
q'/0 q
3 3
1
ql 1 q
3 3
Figura 2.4.
267
El alfabeto de entrada del detector es, evidentemente, E = {0,1}. El alfabeto
de salida constará de dos elementos ("error" y "no error"); podemos tomar el
convenio de que sea también S = {0, 1}, donde "0" significa "no error" y "1"
significa "error". El conjunto de estados puede ser Q = {q0, qv q2}, donde q0 es el
estado inicial, del que sólo se sale al recibir el primer bit; en q1 se estará si se ha
recibido un número par de bits y en q2 si se ha recibido un número impar, de ma-
nera que, al finalizar la transmisión, si la máquina se ha quedado en q1 es que no
ha habido error (s = 0), y si se ha quedado en q2 es que sí lo ha habido (5 = 1), de
acuerdo con esto, es fácil establecer el diagrama de Moore de la figura 2.5.
Figura 2.7.
E = {00, 01,10,11}
S = {0,1}
Q = {<?„ Q }2
269
Figura 2.8.
Figura 2.2.
270
2.3. El castillo encantado
El siguiente ejemplo, tomado de Ashby (1956), nos servirá para ilustrar cómo
la teoría de autómatas tiene un campo de aplicación muy extenso: todo lo que se
refiera a sistemas (en el más amplio sentido de la palabra) discretos con memoria;
en este caso particular veremos cómo permite formalizar y resolver un problema
de lógica en el que interviene el tiempo.
El problema es el expuesto en esta carta:
271
q0\ ni risa, ni canto;
qt: no risa, sí canto;
q2: sí risa, no canto;
q3: risa y canto.
1: que haya algún sonido (salida asociada a los estados qv q2, q3);
2: que no haya ningún sonido (salida asociada al estado qg).
e O / q R c
0 0 Q0 0 0
«1 0 1 <7, 0 1
e 1
2 1 0 Q2 0
e 1 1
3 1 1 q3
(2) OrR, = 0 - » c f + 1 = C,
(4)7, = 1 ^Rl+1 = Ct
De (1) y (2) se deduce que
(5) C, + 1 = (O t R t ) © C ,
y de (3) y (4)
(6) R t + 1 = / , © C ,
0, /, Ft, C, Am C,+1
0 0 0 0 0 0
0 0 0 1 1 1
0 0 1 0 0 0
0 0 1 1 1 1
0 1 0 0 1 0
0 1 0 1 0 1
0 1 1 0 1 0
0 1 1 1 0 1
1 0 0 0 0 1
1 0 0 1 1 0
1 0 1 0 0 0
1 0 1 1 1 1
1 1 0 0 1 1
1 1 0 1 0 0
1 1 1 0 1 0
1 1 1 1 0 1
273
e
e e
e„ e, 2 3
<7/5\
«/o 9o 92 9. «3
93 <h 92 9o
qjí 9o h 9o 92
1J1 93 9i 93 9i
Figura 2.10.
274
A la vista de este diagrama, la solución al problema aparece fácilmente: pasar
primero de q3 a q1 mediante ei ó ev y luego a q0 mediante e3; o bien, respondiendo
en los mismos términos epistolares, "durante un minuto, queme usted incienso
(tocando o no el órgano, es indiferente), y desaparecerá la risa; durante el minuto
siguiente, queme incienso y toque el órgano, y al finalizar ese minuto cese toda
actividad, con lo que, si no vuelve a manipular ni el órgano ni el incienso, se
habrá librado para siempre de tan molestos moradores". Hay desde luego, otras
soluciones, pero todas ellas con secuencias de entrada más largas; por ejemplo, de
ql puede pasarse a q2 con e2, y de aquí a q0 con e0 6 e2. Obsérvese que, afortuna-
damente para el propietario de la casa, el estado q0 es estable, en el sentido dé que
con la entrada e0 (es decir, I = 0, O = 0) el siguiente estado es el mismo q0.
3. Comportamiento de un autómata
3.1. Otra definición de autómata
En el capítulo 1 comenzamos hablando de los autómatas como dispositivos
que producen cadenas de símbolos a la salida en respuesta a cadenas de símbolos
presentadas a la entrada. Según esto, podríamos definir un autómata como una
función:2
F*:E*^>S* [3.1.1.]
F:E* —» S [3.1.2]
F(e0) en el instante 1
F(e0e1) en el instante 2
2
Utilizamos la notación explicada en el apartado 5 del capítulo 1 del Tema "Lógica".
275
Fie^y-.e^ = F(x) en el instante n
x = 01.11.10.01.11.00
F(e0)=F( 01) = 1;
ent1:F(e0e1) = F(01.11) = 0-
en t2: F(eae,e2) = F(Ol.ll.lO) = 0;
en t3: F(e0e,e2e3) = F(01.11.10.01) = 0;
en tA: F^e^e^) = ^(01.11.10.01.11) = 1;
y en t5: F(e0e,e2e3e4es) = F(01.11.10.01.11.00) = 1;
C\E*
i -> S
C (e,) en t = t0
C (Cle2) en í = í0 + 1
Cq(e,e2... en) = C (x) en t = tn + n-1
277
Vemos así que para todo autómata (circuito) pueden definirse, en principio,
tantas funciones de la forma [3.1.2] (es decir, tantas "máquinas") como estados
tenga el autómata, aunque hay que advertir que algunas de estas funciones pueden
ser idénticas entre sí (lo que correspondería a estados equivalentes, según la
definición que daremos enseguida).
Definición 3.4.1. Dados dos autómatas con los mismos alfabetos de entrada y
salida, A j = <E,S, Qvfít gj> y A 2 - <E, S, Q2,f2, g2>, qA e Q1 es equivalente a
<7i e Qi si Cqt = Cq2.
La misma definición sirve para estados equivalentes dentro de un mismo
autómata: basta considerar que <2, = Q2,f =/2, g, = g2.
Figura 2.13.
a) Calcular Cq„ Cq2, Cq„ y Cq, (en la figura 2.12) para cadenas de entrada de
longitud igual o inferior a 3.
279
c) Comprobar que ambos autómatas son equivalentes.
Cq, 0 000 0 0 0 0 0 1 0 0 0 0 0
Cq, 0 000 0 1 0 0 0 1 0 0 0 0 0
Cq, 0 10 0 0 0 0 0 0 1 0 0 0 0 0
Cq4 1 000 0 1 0 0 0 1 0 0 0 0 0
Figura 2.14.
C:E*->S
<¡
281
Pues bien, sobre el ejemplo de las figuras 2.2 y 2.3, y si llamamos A a la
primera y A a la segunda, podemos comprobar que
etc., es decir,
Cq, — C q¡
En general, lo que ocurre es que todos los estados (f resultantes de una escisión
de q tienen igual comportamiento (salvo, naturalmente, para x = A,), ya que se
toma
g(x,q') = g(x, q)
4.1. introducción
Hemos visto que un circuito con n estados puede realizar hasta n máquinas
diferentes. Cada una de estas máquinas viene definida por el comportamiento de
entrada-salida para el correspondiente estado.
El número de cadenas diferentes en E* es infinito. Pero como el autómata es
finito es imposible que responda de distinta manera a cada una de ellas. Es decir,
debe ser posible particionar E* en un número finito de subconjuntos tales que el
autómata sea incapaz de distinguir dos cadenas pertenecientes al mismo subcon-
junto. Veremos que tales subconjuntos pueden considerarse como clases de
equivalencia; naturalmente, cuanto mayor sea el número de clases de equivalencia
mayor será la capacidad del autómata para responder de distinta manera a cadenas
diferentes. Cuando decimos que el autómata "responde" a una cadena o "dis-
tingue" entre una u otra pesamos en el símbolo de salida asociado a cada cadena,
de acuerdo con la definición de "máquina" (expresión [3.1.2]). Si consideramos
exclusivamente máquinas de Moore, existirá una función de salida h: .
Vamos en ese apartado a simplificar el análisis, suponiendo que h es biyectiva, es
282
decir, que a cada estado podemos asignarle una salida diferente3. En este caso, dos
cadenas pertenecerán a la misma clase de equivalencia (serán indistinguibles para
todas las máquinas definidas por el circuito) si, considerando un estado inicial
cualquiera, el estado final es el mismo para ambas cadenas. Nos vemos así condu-
cidos a estudiar, para cada cadena, funciones de la forma Q —» Q, y, si llamamos
Qa al conjunto de todas esas funciones, el comportamiento global del autómata
vendrá determinado por una función K: E* —> QQ, que asigna a cada cadena de
entrada una función Q —» Q. Si el número de estados diferentes es n, habrá n"
funciones Q —» Q, por lo que el número máximo de clases de equivalencia en E*
será n".
Vamos a formalizar estas ideas, y para ello comenzaremos por recordar algu-
nos conceptos de álgebra, pero antes debemos advertir al lector que este apartado,
que es el más teórico del tema, no es imprescindible para la comprensión del resto,
y, si lo que desea, puede omitirlo y saltar al apartado 5 (minimization de AF).
c
taotb e C
3
Esta simplificación no resta generalidad al análisis. En efecto, lo que haremos será estudiar la "respuesta de
estados" en el sentido de que para cada entrada nos fijaremos no en la salida, sino en las transiciones que provoca
entre los estados. Si h no fuera biyectiva lo único que podría ocurrir es que dos cadenas diferentes en cuanto a
su "respuestas de estados" fueran indistinguibles en cuanto a la salida, pero esto es fácil de analizar conociendo
la función h:Q —> S .
283
Además, podemos definir en elemento neutro en C c , í,: C —> C, tal que t l ot j
= tjot1 = t¡ ; este elemento neutro es í,(x) = x. Por consiguiente, < C°,o>
cumple las condiciones para ser un monoide.
Ejemplo. Sea C = {0,1}. Veamos cuál es el monoide de transformaciones de
C. Cc tendrá cuatro elementos:
í0:í0(0) = 0 , f 0 ( l ) =0
í,: ; , ( ( ) ) = (),
t2:t2(0) = l,t2(l)=0
í3:í3(0) = l , í 3 ( l ) =1
í2OÍ3(1)=í2(ís(1)) = ^(1) = 0
luego
f
h°h = o
S1xS1
/x/ | 4/
S2 xS2
es conmutativo.
e =C
K l) 2
Ejemplos:
285
= a y Or = 1
(¿es isomorfismo?).
4.2.3. Monoide libre y homomorfismo
Hemos definido en el apartado 5.2 del capítulo 1 del tema "lógica" el monoide
libre generado por un alfabeto E, <E*, >.
Teorema 4.2.3.1. Sea i: E —» E * la función que aplica todo elemento de E en
la correspondiente cadena de longitud unidad, es decir, (Va e E) (i(a) = a)
y sea / cualquier función de E en el conjunto de cualquier monoide <M, *>.
Entonces, existe un único homomorfismo monoide g: <E*, > —> <M,*> tal que
goi = f , es decir, tal que el diagrama
E —•£*
\ /
es conmutativo.
Demostración:
Para cadenas de longitud 1 podemos definir g(a) = f(a) para que se satisfaga
f(a) = goi (a) = g(i(a)) = g(a). Si x es una cadena de longitud l > 2 podemos
descomponerla en x = yan, donde lg(y) = / - 1 y lg(an) = 1, y tendremos:
g(x) = g(y)*f(a)
l&)=flad*K<h)
286
Este teorema nos permite extender el dominio de cualquier función E —» M
de alfabetoE en el conjunto de un monoide <M, *> a un homomorfismo monoide
<E*, > —> <M, *>, y nos será de utilidad más adelante.
[a][b] = [a*b]
es un monoide.
Demostración'.
En primer lugar hay que demostrar que la operación " •" está bien definida
sobre las clases de equivalencia, es decir, que el resultado es independiente de
que se tome un miembro u otro de la clase. Para ello, sean a1 s [a] ,
«2 e [a] , b1 e [b] , b2 e [fe] . Tenemos pues que a1R a2y bxR b2, y, como
R es una relación de congruencia, podemos escribir:
287
(ai* bJRia,* b2)y(ai* b2)R(a2* b2)
(a^bJRiaSbJ
es decir,
1) " •" es asociativa. En efecto, como "*" es asociativa (pues <M, *> es un
monoide),
f- Ex Q—í Q
Estado siguiente
k( 0)
289
i e ( 0 0 ) = ;fc(0)ojfc(0) =k(0)
K(01)=k(0)ok(l) = k(l)
etcétera.
En general,
4.5. Ejemplos
4.5.1. Detector de paridad
Ya hemos estudiado el comportamiento de entrada-estados del detector de
paridad, llegando a la conclusión de que sólo hay dos clases de equivalencia en
E*; en efecto, veíamos que K(x) = k(0) = ¡c(X), six tiene un número par de unos
(o ninguno) y K(x) = ¿(1), si x tiene un número impar de unos. Luego toda cadena
x es equivalente a "A," o a "1". Llamemos [A-] y [1] a estas dos clases de equi-
valencia, que serán los elementos del monoide del autómata. Al tener un número
finito de elementos, podemos describirlo mediante una tabla que indique el ele-
mento resultante de la concatenación de otros dos:
[X] [1]
[X] [X] [1]
[1] [1] [X]
291
4.5.2. Reconocedor de la cadena 010
El autómata, representado en la figura 2.12, tiene cuatro estados, por lo que el
número total posible de transformaciones en Q, es decir, el número máximo de
elementos del monoide del autómata es 44 = 256. Veamos si existen todos. Para
ello, calculemos K(x) para cadenas de longitud creciente desde x=X. Resumimos
los resultados en la tabla de la figura 2.15. El procedimiento para construir una
tabla de ese tipo es el siguiente:
Tenemos tantas filas como estados tiene la máquina. Para cada cadena x
ponemos en una columna los estados resultantes de la función K(x)\ Q —» Q.
Comenzamos por X, para la que la función es la unidad (es decir, ql en qt, q2 en
q2, etc). Para las cadenas de longitud l(en este caso 0 y 1) miramos en el diagrama
de Moore; en este ejemplo, cuando se aplica x = 0 la imagen de q1 es q2, la de q2
es q2, etc. Teniendo ya K(x) para cadenas de longitud 1 no hace falta consultar más
el diagrama; por ejemplo, ¿(01) = K(Q) °K(1) , y así, con 0, q1 se aplica en q2,
y luego con 1, q2 se aplica en qv por lo que la imagen de qí será qy Para cadenas
de longitud 3 nos basamos en los resultados anteriores; por ejemplo, i£(010) =
/ í ( 0 1 ) 0 ^ ( 0 ) = K(0) oK(W) (las dos formas de hacerlo son válidas). La tabla
se va así rellenando por columnas, aumentando la longitud de las cadenas por
postconcatenación de los símbolos del alfabeto a las cadenas ya tratadas, hasta que
encontramos cadenas x tales que K(x) = K(y), donde lg(y) < lg(x); entonces
podemos asegurar que x = y, y no es preciso que sigamos aumentando x, ya que,
si la concatenamos con un símbolo cualquiera, e, tendremos K(xe) = K(ye), es de-
cir, xe = ye, con lg(ye) < lg(x), por lo que la clase de ye o bien ya ha aparecido
(si lg(y)<lg(x)), o bien va a aparecer (si lg (y) = lg(x)).
ft ft ft ft ft ft ft ft ft ft ft
Estado ft ft ft ft ft ft ft ft ft ft ft
inicial ft ft ft ft ft ft ft ft ft ft ft
ft ft ft ft ft ft ft ft ft ft ft
ft ft ft ft ft ft ft ft
ft ft ft ft ft ft ft ft
ft ft ft ft ft ft ft ft
ft ft ft ft ft ft ft ft
Figura 2.15.
Concretemos con nuestro ejemplo. Siete de las ocho cadenas de longitud 3
tienen el mismo comportamiento que las cadenas de longitud 2:#(000) = #(00);
#(001) = #(01), etc, por lo que [000] = [00]; [001] = [01], etc. La única cadena
cuyo comportamiento difiere de los anteriores es 010. Por tanto, estudiamos 0100
y 0101, y vemos que #(0100) = i^(00) y #(0101) = #(001). Nos quedan así
solamente ocho clases de equivalencia: [X], [0], [1], [00], [01], [10], [11] y [010].
El monoide del autómata tendrá pues ocho elementos, no 256: # dista mucho de
ser suprayectiva. La tabla del monoide se obtiene sin dificultad de la figura 2.15,
y es la representada en la figura 2.16; por ejemplo, para saber el resultado de [11]
[10], con ayuda de la figura 2.15 vemos que #(1110) = # (11) o # (10) = #(00),
por lo que [11] [10] = [00],
Figura 2.16.
293
es finito sólo podrá contar hasta un determinado número y a partir de él volver al
principio; un contador módulop contará de 0 a p - 1 .
Consideremos p = 10; es decir, el contador contará de 0 a 9 y al recibir el
décimo "1" volverá a contar desde 0. Cada vez que recibe un "1" deberá cambiar
de estado (y, naturalmente, de salida). Así es fácil ver que el diagrama de Moore
es el de la figura 2.17, en donde se supone que el estado inicial es q0, y como
símbolos de salida se han tomado s0, ... s9, para abreviar la notación (en realidad
serían 0000, 0001,.., 1001).
Como hay diez estados, el monoide del autómata podría tener hasta 1010
elementos. Ahora bien, si construimos la tabla de K(x) (figura 2.18) vemos que
sólo hay diez clases de equivalencia.
En efecto, vemos que 0 = A, por lo que sólo hay que considerar cadenas
compuestas por "1". Calculamos K(l 2 ), K(l 3 ), etc. (el exponente indica concate-
nación: 13=111, etc.), y vemos que 1 = X . Por consiguiente, las clases de
equivalencia son:
\ /
Figura 2.17.
X 0 1 12 . 19 Vo
Qo Qo Qo <7, Q2 Qo Qo
<7, Q^ Q, Q2 Q3 Qo <7i
Qs Q* Qb Qo Qo Qi Qs
Q9 Qo Qo Qo <7i Qs Qo
Figura 2.18.
Cq: E* ->S
Así, para cada entrada, x, Cq(x) es la función que aplica x en g(x, q):
Cq(x): x->g(x, q)
K:E*^Qa
De modo que, para cada entrada, x, K(x) aplicará x en una función de transfor-
mación entre estados:
295
donde la función / está determinada por la función/restringida a la entrada x:
f.E* x G->G,
A-*): e^G
El sentido físico es el siguiente: C determina, dado un estado inicial, el
símbolo final de salida para cada cadena de entrada; K determina, para cada
cadena de entrada, la correspondiente transformación entre estados, es decir, nos
dice que de q1 se pasará a qt, de q2 a qP etc. Por tanto, K nos proporciona más
información acerca del comportamiento interno del autómata. Por otra parte, la
relación de equivalencia en E* inducida por K y el monoide del autómata
resultante nos permiten deducir fácilmente Cq para cualquier cadena de entrada.
Así, en el ejemplo del reconocedor de la cadena 010 veíamos que [010000100] =
[00], y de aquí que Cq¡ = 0; para llegar a la misma conclusión con el procedimiento
que seguíamos en el apartado 3.5 hubiera sido preciso reconocer sobre el diagrama
(figura 2.12) todas las transiciones producidas por la cadena.
Por otra parte, podría pensarse en estudiar el comportamiento de entrada-salida
para todo el conjunto de estados. Para ello podemos definir un comportamiento
global de entrada-salida, Ks(x), como una aplicación de E* en el conjunto de
funciones 1: Qa donde Q0 son los estados iniciales y Sr las salidas finales. Ks
no será ahora un homomorfismo entre monoides, como lo era K, ya que el
conjunto de funciones l no es un monoide; por tanto, Ks no nos permite definir un
monoide de la máquina, y por ello hemos utilizado K en el análisis anterior. En
cualquier caso, Ks también nos define una relación de equivalencia en E*, que
podría llamarse "relación equisalida", = s , tal que x = s y si y sólo si Ks(x) = Ks(y).
= s particiona£* en clases de equivalencia. Ahora bien, suponiendo máquinas de
Moore, tenemos una función h\ QT^ST que nos aplica el estado final en la salida
final correspondiente a ese estado, y por tanto, si llamamos [x]f a la clase de equi-
valencia deE* / = que conduce a una determinada transformación k:. Q0 —><2y y
[y], a la clase de equivalencia de E* / = s que corresponde a una determinada l.\
Q 0 -^S V tendremos:
QM = Q/=
ÍM(x> [<?]) = \Kx, q)\
hJM) = % )
297
= g(*2 J(*l><?l))
g(x1x2,q2) = g(x2,ftx1,q2))
por lo que ( V x , ) ([/(x„ q) =f(xv q2)]), es decir, (Vx e E* ) (\fix, q)\ = [/(x, q2)\).
Por otra parte, es evidente que A y Au son equivalentes, puesto que todo estado
q, de A será equivalente al estado [q] de A„.
Finalmente, AM está en forma mínima, ya que si los estados [ g j y [q2\ de AM
fueran equivalentes, q1 y q2 de A deberían ser también equivalentes, por lo que [ g j
= tej-
b) =
entonces existe un número entero k0 < card(Q) tal que (Vk>k0) (Pk = Pk0).
Para demostrarlo, supongamos que card(P0) = 0, card(P,) = 1, card(P2) = 2,....
Pero como, para todo k, card(P t )<card(0 = n (finito), deberá existir un entero
k0 < n tal que card(P^+i) = card(P£0), es decir, Pk„+i = Pk0, y, por la condición
b ),(\/k>kQ)(Pk = Pk0).
a) Si q1=M q2, entonces ( Vx lg(x) < k + 1) \Cqi (x) = Cq, (x)] y, evidentemente
Vx \g(x)<k, por lo que qí =t q2. Por tanto, todo bloque de la partición Pt+1
inducida por = itl está contenido en un bloque de Pk, es decir, PM es un refi-
namiento de Pk.
b) Supongamos que Pk+1 = Pk, es decir, (<y,st q2)-^(q1 =llt q2). Si qt y q2 son
equivalentes de orden k+ 1, los estados fie^) y f(e,q2) serán, sea cual sea
e, equivalentes de orden k, pero como PM = Pk también serán equivalentes
de orden k + 1, y por ello q1 y q2 son equivalentes de orden k + 2, de donde
Pk+2 = Pk+1- (El razonamiento es una sucesión de condicionales. Definiendo,
para abreviar la notación, las variables proposicionales
PM=Pk
b- P k ^P k + l
c: q1=„q2
299
5.4. Algoritmo para minimización
de un autómata finito
El algoritmo para hallar el AF en forma mínima de un AF dado se basa en los
resultados anteriores:
2. Formar PM, teniendo en cuenta que dos estados estarán en el mismo bloque
de PM si y sólo si para cada entrada los estados siguientes están en el
mismo bloque de Pk (q =ti, q. si y sólo si f(e, q) =t f(e, q¡), Ve & E U
m )•
3. Si P t + 1 ^Pk incrementar k en una unidad y volver al paso 2.
5.5. Ejemplos
Ejemplo 5.5.1
Consideremos el autómata reconocedor de 010 descrito en 3.5.1, y partamos
del diagrama no mínimo (figura 2.13). A efectos de aplicación del algoritmo es
más cómodo representar el AF por la tabla de transiciones:
0 i
qJO q2 q5
qJO q2 q3
qJO q< q5
q<H qz q3
qJO q6 qs
qJo qe q7
q7/0 q< q5
q-a/1 qa qy
1. Observando las salidas asociadas a cada estado podemos poner:
P0 = {<?.>ft'ft>ft,ft,ft}>{ft> ft}
2. Con entrada 0, de qv qv q5yq6 se pasa a estados del primer bloque de P0, y
con 1 también. De q3 y q7, con 0 se pasa a estados del segundo bloque de
P0, y con 1 a otros del primer bloque. Finalmente, de q4 y qs, con 0 se pasa
al primer bloque de P 0 y con 1 también. Luego
P
1 = {ft, ft> ft,ft}> {ft> ft}> {ft> ft)
2'. En lugar de con palabras, pongamos simbólicamente los resultados:
A0>ft)= ft
et
A1»ft)= ft
(l bloque) (2° bloque)
A ° > ft) = ft Al»ft)= ft
Luego,
301
c
Figura 2.19.
a b c
qj 0 <7, q2 q<
qjl <74 q3 <7i
qjl q2 q< q,
qjl q3 q2
qJO q2 qs <7i
qjl q< q5 q4
p
0 = {<?!> (ft, I,,1,}
302
p 2 =x p1
±
a, b
6. Resumen
Hemos expuesto la teoría básica de los autómatas finitos procurando buscar la
mayor generalidad, generalidad que se conserva aunque el estudio se restrinja a
la máquina de Moore.
El comportamiento de entrada-salida es un concepto importante en relación
con los lenguajes, que utilizaremos en el capítulo sobre autómatas reconocedores.
Otros conceptos importantes son los de equivalencia entre estados y entre autó-
matas, pero el interés de éstos radica más bien en la realización tecnológica.
El estudio del comportamiento global del autómata, es decir, inicializado en
cualquier estado, nos ha llevado a establecer el concepto de monoide del autó-
mata, estructura algebraica que refleja su capacidad para responder de distinto
modo a cadenas diferentes de entrada. Finalmente, hemos visto cómo se puede
comprobar la equivalencia entre diferentes estados con un número finito de
experimentos, lo que nos ha permitido establecer un algoritmo para obtener el AF
en forma mínima equivalente a un AF dado.
303
tos de los seres vivos, pero eso no tiene mucho interés en la práctica, y lo que
buscamos es un tipo de aparato que deje los meros gestos visibles del hombre e
intente conseguir los resultados que obtiene una persona, para, de este modo,
reemplazar a un hombre por una máquina" ("Torres and his remarkable automatic
devices", Scientific American , n a 113, 6 nov. 1915, p.296).
El primer estudio riguroso sobre autómatas fue el publicado por Moore (1956).
Con anterioridad, debido al desarrollo de los primeros ordenadores, se habían
estudiado diversos métodos para la síntesis de circuitos secuenciales (Huffman,
1954; Mealy, 1955). A finales de los años 50 se comenzó a ver la utilidad de los
autómatas en relación con los lenguajes, y la mayor parte de los trabajos sobre
teoría de autómatas finitos se realizó durante los años 60. Por esta razón, las
referencias más importantes que pueden darse sobre este campo son libros publi-
cados entre 1965 y 1970. El de Harrison (1965) cubre tanto la parte combinacional
como los circuitos secuenciales, con un tratamiento muy riguroso y fácil de seguir,
aunque se limita a estudiar autómatas reconocedores. Otra obra recomendable es
la de Booth (1967), que, además de autómatas finitos, trata también las máquinas
de Turing, lenguajes artificiales y autómatas estocásticos. Muchas de las defini-
ciones y terminología de este capítulo las hemos tomado de Arbib (1969) que
cubre muy ampliamente los diversos estudios desarrollados hasta aquella fecha.
La parte que trata del monoide del autómata está basada en el capítulo sobre
monoides de Gilbert (1976), libro muy interesante sobre aplicaciones del álgebra
moderna. Hay textos más recientes, como el de Shields (1987), pero la teoría
básica de autómatas se presenta actualmente integrada en obras más generales
sobre la teoría de la computación, como las de Lewis y Papadimitriou (1988) y
Cohen (1991).
Para no alargar excesivamente el tema hemos presentado el algoritmo de
minimización reducido al caso de máquinas de Moore (la máquina de Mealy
mínima tendrá normalmente, menos estados). El caso general viene expuesto en
cualquiera de los libros citados en éste o en el siguiente capítulo.
8. Ejercicios
8.1 Obtener la tabla de transiciones y el diagrama de Moore de la máquina
de Moore equivalente a la de Mealy, descrita por la siguiente tabla:
Sf
<7i qjs, qjs2
q2 qjs2 qjs2
q3 qjs, qjs2
q< qjs2 qjs,
304
8.2. Definir las máquinas de Mealy y de Moore de un restador binario.
8.3. Considérese un sistema eléctrico cuyas entradas son dos pulsadores, a
y c (apertura y cierre), que pueden estar en reposo (0) o pulsados (1) (se
supone que no puede ser a = c = 1), y cuyas salidas son tres lámparas:
verde, ámbar y roja (V, A, R), de las que, en cada momento, una y sólo
una está encendida. Inicialmente, está encendida la verde; al pulsar c,
ha de pasar de verde a ámbar, y, si se pulsa otra vez (o más veces), a
rojo. El pulsador a hace pasar siempre a verde.
a) Dibujar el diagrama de Moore, con Q = {V, A, R} y E = {a, c}.
b) El modelo anterior tiene un inconveniente: si la transición de un
estado a otro es instantánea (o casi), entonces el hecho de pulsar C
estando en verde va a provocar el paso a rojo sin detenerse (casi) en
ámbar. Las especificaciones dadas se pueden completar diciendo que
hasta que no "se suelte" el pulsador no puede hacerse otra transición.
Ahora va a ser necesario un estado más: "ámbar con c = 1" y "ámbar
con c = 0". Dibujar el nuevo diagrama de Moore.
8.4. Obtener los monoides del sumador y del restador binario y compa-
rarlos.
8.5. Un autómata retardador es aquel en que
s(t) = e(t - n)
q/s a b c
q2 q3
qJO ft q2 q3
qjl q3 q3 q2
305
utilizarse E = {L, C, F, H}, donde L quiere decir "día lluvioso", C
"caluroso", etc., y S = {T, B, M}, donde T = "latente", B = "brote", M =
"muerto". ¿Cuál es el número de elementos en el monoide de este
autómata?
8.8. (Gilbert, 1976). Un perro puede estar tranquilo, irritado, asustado, o
irritado y asustado, en cuyo caso muerde. Si le damos un hueso queda
tranquilo. Si le quitamos uno de sus huesos se pone irritado, y, si ya
estaba asustado, nos muerde. Si le amenazamos se asusta y, si ya estaba
irritado nos muerde. Obtener el diagrama de Moore y el monoide del
perro.
e a b
<7i qjl qJo
<72 qJO qJO
q3 qJO qjl
<74 qJO qjl
306
3
Circuitos
secuenciales
309
Por ejemplo, si el autómata que se quiere realizar es un ordenador, se seguirá,
normalmente, el enfoque a). (También puede seguirse el enfoque b), y en ese caso
se trataría de simulación o emulación en otro ordenador). Si el autómata es muy
complicado (como es un ordenador), se descompondrá generalmente en subautó-
matas; uno de ellos podría ser el sumador binario serial, ya estudiado, del que
veremos su realización en el apartado 6.1. (Conviene señalar que los ordenadores
suelen utilizar otro tipo de sumador, el paralelo, que exige unos circuitos más
complicados, pero que es mucho más rápido).
Otro ejemplo puede ser el reconocimiento de cadenas. Hemos visto un AF que
reconoce la cadena "010". Podemos pensar en un AF que reconozca varias
cadenas, dando una salida diferente para cada una. Así, si E = {A, B,..., Z} y S =
{00000,00001,.., 11111}, podría dar s = 00000 para* = CAR (cargar), 5 = 00001
parax = CMP (complementar), s = 00010 para x = SUM (sumar) y así, sucesiva-
mente, todos los códigos binarios de operación de algún ordenador para los
correspondientes códigos de su lenguaje ensamblador. Este AF sería parte de un
AF más completo, llamado "ensamblador", que traduciría a lenguaje de máquina
los programas escritos en lenguaje ensamblador. Pues bien, los autómatas ensam-
bladores, caso particular de procesadores de lenguajes, no se construyen física-
mente, sino mediante un programa de ordenador.
En este capítulo nos vamos a dedicar especialmente a las técnicas para realizar
autómatas finitos físiqamente. La realización del AF, salvo raras excepciones, es
con tecnología electrónica o electromecánica, y el sistema digital con memoria
resultante se llama circuito secuencial.
310
2.2. Elementos combinacionales
Son las puertas NOT, AND, OR, NAND, NOR, etc., ya estudiadas en el tema
"Lógica" (capítulo 3). Realizadas generalmente mediante tecnología electrónica,
para aplicaciones especiales aún se utilizan otras tecnologías: electromecánica,
hidráulica, neumática, etc.
con e,q,se {0,1}. Este sencillo modo de funcionamiento se puede ilustrar gráfi-
camente con un cronograma como el de la figura 3.1.
e(t)
_n r
s(t)
n Figura 3.1.
r
Estos elementos (que, de una manera general, se llaman líneas de retardo)
pueden realizarse mediante líneas de retardo acústicas, líneas de transmisión,
redes de condensadores e inductancias, puertas lógicas conectadas en serie, etc.,
y también con biestables, como veremos enseguida.
311
2.3.2. Biestables
Los elementos de memoria más utilizados en los circuitos secuenciales son los
biestables electrónicos. Un biestable es un circuito con dos estados estables que
son también su salida y que, simbólicamente, se denominan "0" y "1" (en la
realidad, cada uno de ellos corresponderá a un determinado nivel de tensión).
"Estables" quiere decir que el elemento sólo cambia de estado bajo la acción de
las entradas. Hay diversos tipos de biestables, que difieren entre sí por los posibles
símbolos de entrada y las funciones de transición. Todos ellos tienen dos líneas
de salida: en una de ellas, denominada habitualmente "Q", se tiene el nivel de
tensión correspondiente en cada momento al estado, 0 ó 1; en la otra, Q, se tiene
su complemento. Pasemos a ver el funcionamiento de algunos biestables.
Biestable tipo SR ("set-reset"). En este biestable E = {00, 01, 10}. Como las
señales en los circuitos secuenciales son binarias, tendrá dos líneas de entrada, S
y R (figura 3.2 a). Su funcionamiento puede expresarse formalmente mediante la
función de transición:
Biestable tipo D. También tiene dos líneas de entrada, ya que E = {00, 01,10,
11}. Estas líneas se llaman D ("data") y C ("clock") (figura 3.4 a). Su funciona-
miento puede representarse formalmente así:
que corresponde al diagrama de la figura 3.4 b. Ahora bien, aquí hay una
diferencia muy importante en cuanto al significado de los símbolos "0" y "1" para
D y para C. Para D, "0" significa, por ejemplo, una tensión de 0 v, y "1", 5 v; sin
embargo, para C "1" significa que hay una variación de tensión de 0 v a 5 v, y "0"
que no hay tal variación. En otras palabras, el valor de C es cero salvo en el
instante en que su tensión cambia de nivel bajo a nivel alto. Véase la figura 3.4 c,
para ilustrar este significado de "0" y "1".
Un cronograma que ilustra el funcionamiento del biestable tipo D es el de la
figura 3.4 d, donde hemos, también, despreciado el tiempo de basculamiento.
313
Obsérvese que si los cambios en D van retardados ligeramente un intervalo
constante e « 0 con relación a los cambios de 0 a 1 de C, lo que hace el biestable
es exactamente retardar la entrada D en G segundos, siendo 6 el período del reloj
(C).
10,11
00,01 00,10
01,11
(b)
In n nr
K
JLTULf]
i , i i
Q
mn nr
Q
futrí n .
(c)
(d)
Figura 3.3.
Este tipo de biestable, que sólo cambia de estado cuando cambia el nivel de la
geñal de reloj se llama sincronizado por flancos ("edge triggered"). El que hemos
visto está sincronizado por el flanco de subida; también lo hay sincronizado por
el flanco de bajada (es decir, cambia de estado cuando C pasa de 1 a 0). No
entramos ya en su circuitería lógica, que el lector interesado puede consultar en la
bibliografía.
Biestable tipo JKsincronizado. Tiene cinco líneas de entrada: S,R,J,KyC
(figura 3.5 a). S y R se utilizan para ponerlo a 1 ó a 0 de una manera asincrona, es
decir, independientemente de C, mientras que J y K son la puesta a 1 ó a 0
síncronas. La ecuación que describe su comportamiento es:
Q(t + 1) = S + R KQ + R C Q + R JCQ
11
OS
D Q 0 01
1
C Q 00,01,10 00,11,10
(a) (b)
0
JUUL
-»H M •H
10 10 10
->4
1 0 1
D
Q
m iUUUUL
~l l~L
Q
(c) Figura (d)
n n
J s Q
r
c
K R Q K | i
ii
Q
Q
(a)
(b)
Figura 3.5.
Aquí el valor lógico "1" para C significa una doble transición nivel bajo-nivel
alto-nivel bajo. Esto es debido a la constitución interna, en la que no entraremos
aquí, que incluye dos biestables en una configuración conocida como "maestro-
315
esclavo". Por ello, las transiciones de la señal de salida, Q, se dan en el flanco de
bajada de C. El cronograma de la figura 3.5 b ilustra el funcionamiento síncrono
(S y R actúan como en un SR normal, y, en caso de conflicto, predominan sobre
las/it).
q{t+í)=f(e(í), q(t))
s ( f ) = g(e(f), q(t))
z
i = fi(el> -> ew O1' -y <lp)> 1
= 2> -> m
z=/(e, q)
s = g(e, q)
s = h(g)
316
s(t) = g(e(t), q(t))
e(t) Circuito
combinacional q(t + l)=f(e(t),q(t))
q(t)
Elementos
de memoria
(a)
e(t)
Circuito q(t + l)
combinacional
q(t)
Elementos
de memoria
/
Circuito
combinacional ,s(t)
(b)
Figura 3.6.
sm
Figura 5.10.
317
4. Tipos de circuitos secuenciales
En el apartado 2.3 hemos visto dos tipos de elementos con memoria: los no
sincronizados, y los sincronizados con una señal de reloj, C. Por otra parte, las
señales de entrada pueden ser de cuatro tipos: impulsionales síncronas o asincro-
nas y de nivel síncronas o asincronas (figura 3.8). Si se utilizan unidades de
memoria sincronizadas lo normal es que las señales de entrada sean síncronas, y
así tenemos cuatro tipos de circuitos secuenciales:
Reloj
Impulsos
asincronos
Niveles
asincronos
Impulsos
síncronos
Niveles
síncronos
Figura 5.10.
318
Dependiendo de las características particulares de cada aplicación se utiliza un
tipo u otro de circuito secuencial. Aquí nos vamos a limitar para los ejemplos
exclu-sivamente a los tipos 1 y 2.
319
anotando gráficamente estos resultados obtenemos el cronograma de la figura
3.10.
El cronograma es muy útil para ver gráficamente el comportamiento del cir-
cuito, pero sólo lo representa para una determinada cadena de entrada. Para tener
una representación más general de este circuito podemos poner en forma de tabla
todas las posibles combinaciones de eh e2 y q y las resultantes para s y z. Esta
tabla (figura 3.11 a) nos conduce inmediatamente a la tabla de transición (figura
3.11 b) y al diagrama de Moore (figura 3.11 c). Obsérvese que este diagrama es
precisamente el del autómata sumador binario, es decir, el circuito de la figura 3.9
es la realización física de tal autómata. (La parte combinacional es una etapa de
sumador).
h n n n n n r
\ —
V
- —\V \ \
\ 1- —
X
\
\
Figura 3.10.
320
e
l e
2 q s z
00 01 10 11
0 0 0 0 0
0 0 i 1 0
0 1 0 1 0 0 0/0 0/1 0/1 1/0
0 1 i 0 1
1 0 0 1 0
1 0 i 0 1 1 0/1 1/0 1/0 1/1
1 1 0 0 1
1 1 i 1 1
(b)
(a)
01/1 01/0
00/1
10/1 10/0
(c)
Figura 3.11.
b) Minimizar el AF.
c) Hacer una asignación de estados.
d) Escribir la tabla de transición en binario.
e) En función del tipo de biestable utilizado, obtener las tablas de excitación,
que dan las entradas necesarias al biestable para cada transición.
f) De las tablas de excitación, obtener las ecuaciones lógicas de la parte
combinacional.
321
binarios, necesitaremos p elementos, con 2p'1 < N<2p. La asignación de estados
es una codificación arbitraria de los N estados con p dígitos binarios. El problema
aquí es que según se haga una u otra codificación de las (2P\) / (2P -N)! posi-
bles, el circuito combinacional resultante puede ser más o menos complicado, y
que no existe un método para saber cuál es la codificación óptima, aunque sí hay
algunas reglas en las que no vamos entrar, que el lector interesado puede estudiar
en la bibliografía.
El paso e) consiste en obtener las tablas de verdad de la parte combinacional.
Para los pasos f) y g) aplicaremos las técnicas ya conocidas de diseño de
circuitos lógicos.
6.2. Ejemplos
6.2.1. Detector de paridad
El diagrama de Moore es el de la figura 2.6. Si asignamos a los estados los
valores q1 = 0 y q2 = 1, la tabla de transición en binario será:
0 1
0/0 0 1
1/1 1 0
Escribamos la tabla de una forma lineal, es decir, con una línea para cada
combinación posible de e y q\
e q z
0 0 0
0 1 1
1 0 1
1 1 0
Supongamos ahora que vamos a utilizar un biestable tipo D (sólo hace falta
uno, puesto que sólo hay dos estados). Deberemos anotar en cada línea la entrada
necesaria al biestable para que tenga lugar la transición correspondiente. Por
ejemplo, en la primera línea, de q(t) = 0 se debe pasar -dz = q(t+ 1) = 0. Para ello,
D = 0; en la segunda línea D = 1, etc. Así, podemos poner la tabla:
e q D
0 0 0
0 1 1
1 0 1
1 1 0
que nos define D (entrada del biestable) en función de e(t) y q(t), y se llama tabla
de excitaciones. De ella obtenemos la función D:
D = e • q + e • q = e® q
Reloj
Figura 5.10.
323
pueden ser ambas O, o bien J = 0, K = 1 (puesta a cero); para la transición de q =
0 a z = 1 podemos hacer / = 1, K = 0 (puesta a uno), o bien / = 1, K = 1 (comple-
mentation), etc. Así, podemos escribir la tabla de excitaciones para este ejemplo:
e q z J K
0 0 0 0 0
0 1 1 0 0
1 0 1 1 0
1 1 0 0 1
en la que hemos puesto " 0 " en los lugares donde es indiferente que sea "0" ó "1";
como ya sabemos, esto nos ayuda en la minimización del circuito. Las tablas de
Karnaugh de J y K en función de e y q son:
K
e e
q q
\ 0 1 0 1
1
0
0
ñ
w
0
1
0
0
u
de las que obtenemos
J = K= e
e q s z K1 J2 K2
0 00 0 01 0 0 1 0
0 01 0 01 0 0 0 0
0 10 0 11 0 0 1 0
0 11 1 01 0 1 0 0
1 00 0 00 0 0 0 0
1 01 0 10 1 0 0 1
1 10 0 00 0 1 0 0
1 11 1 10 0 0 0 1
Las cuatro últimas columnas con las tres primeras definen las tablas de excita-
ciones. Si llamamos <2i y 02 (salidas de los biestables) al primero y segundo dígito
de q, minimizando por Karnaugh podemos hallar las ecuaciones lógicas de las en-
tradas de los biestables en función de e, Q1 y Q2; el resultado es:
e e = e = e
J\ = • Qi; = ® 02; >Ki
Por otra parte, de las tres primeras columnas se tendrá la función de salida, es
decir, s en función de e, Q1 y Q2. Minimizando resulta:
* = 01 ' 02
325
h
Qi
c
fii
h
Qi
c -Reloj
02 K
2
Figura 3.14.
Codifiquemos los estados con los mismos dígitos que las salidas asociadas:
qQ = s0 = 0000
q1 = s1 = 0001
<72 = ^2 = 0010
q9 = sg= 1001
e Q3 Q2 Oí Qo z J3 Ka J2 K2 J1 Jo Ko
0 0 0 0 0 0000 0 0 0 0 0 0 0 0
0 0 0 0 1 0001 0 0 0 0 0 0 0 0
0 0 0 1 0 0010 0 0 0 0 0 0 0 0
326
e Q3 Q2 Q1 Qo z J3 K3 J2 K2 KA J0 Ko
0 0 0 1 1 0011 0 0 0 0 0 0 0 0
0 0 1 0 0 0100 0 0 0 0 0 0 0 0
0 0 1 0 1 0101 0 0 0 0 0 0 0 0
0 0 1 1 0 0110 0 0 0 0 0 0 0 0
0 0 1 1 1 0111 0 0 0 0 0 0 0 0
0 1 0 0 0 1000 0 0 0 0 0 0 0 0
0 1 0 0 1 1001 0 0 0 0 0 0 0 0
0 0 0 0 0001 0 0 0 0 0 0 1 0
0 0 0 1 0010 0 0 0 0 1 0 0 1
0 0 1 0 0011 0 0 0 0 0 0 1 0
0 0 1 1 0100 0 0 1 0 0 1 0 1
0 1 0 0 0101 0 0 0 0 0 0 1 0
0 1 0 1 0110 0 0 0 0 1 0 0 1
0 1 1 0 0111 0 0 0 0 0 0 1 0
0 1 1 1 1000 1 0 0 1 0 1 0 1
1 0 0 0 1001 0. 0 0 0 0 0 1 0
1 0 0 1 0000 0 1 0 0 0 0 0 1
J3 = e • Q2 • Qx • Qo
Y, análogamente,
e
J2 = • Gi • Go;
Jt = e-Q3Q0;
327
J0 = e
K, = e-Q0
K2 = e •Qi • Q0
K1 = e-Q0
K0 = e
\ fi3 \ e3
G l\ Qi \ Qi
fi\ 21
00 01 11 10 e > \ 00 01 11 10
00 0 0 0 0 00 0 0 0 0
01 0 0 0 0 01 0 0 0 0
11 0 0 0 0 11 0 T 0
s>
10 0 0 0 0 10 0 0 0 0
e=0 e=1
S
•S3 2
Q J
KJ
!
Q
*
J
t L
Q J Q J
- 3 c - 2 c - 1 c - 0 c
K tí K tí K tí K
Reloj
Figura 5.10.
328
7. Resumen
Hemos estudiado algunos de los elementos utilizados como memorias en la
realización física de los AF (circuitos secuenciales). Conociendo el funciona-
miento de los elementos que lo componen, el análisis de un circuito secuencial se
puede llevar a cabo deduciendo paso a paso el cronograma correspondiente a una
determinada cadena, y también se puede obtener el diagrama de Moore, que
tendrá, si p es el número de elementos binarios de memoria, 2P estados.
Hemos visto el procedimiento general para la síntesis de circuitos secuen-
ciales, ilustrándolo con algunos ejemplos. No hemos abordado, por su mayor
complejidad, el diseño de máquinas incompletamente especificadas ni el proble-
ma de la asignación de estados.
9. Ejercicios
9.1. Diseñar el sumador binario serie utilizando un biestable de tipo JK.
9.2. En el ejercicio 9 del capítulo 2, supóngase que los tres posibles sím-
bolos de entrada se codifican en binario: 1 = 01; 2 = 10; 3 = 11 (es decir,
habrá dos hilos de entrada). Diseñar el circuito secuencial correspon-
diente.
9.3. Diseñar un contador módulo 10 en exceso de 3, utilizando JK. (Véase
el ejercicio 12.4 del capítulo 3 del tema "Lógica".)
329
9.7. Diseñar un circuito secuencial que simule la situación descrita para el
"castillo encantado" (véase el apartado 2.3 correspondiente al capítulo
2 de esta parte).
9.8. Dado el autómata definido por la tabla que hay a continuación, expresar
con palabras su funcionamiento (es decir, cuándo da 0 ó 1 a la salida
dependiendo de la secuencia de ceros y unos a la entrada), y diseñar un
circuito para materializarlo.
0 1
</i/0 <72 <7i
q2/0 <73 <7i
<?3/1 <73 <7i
Ji Qi
C
K 3
Jn
Q2
r
k2 a
Reloj
330
4
Autómatas
reconocedores
y lenguajes
regulares
1. Reconocedor finito
1.1. Definición
Hemos definido al principio del libro un lenguaje, L, sobre un alfabeto, A,
como un subconjunto cualquiera de A*. En este capítulo vamos a ver que ciertos
lenguajes pueden asociarse con autómatas finitos que sirven como reconocedores
de las cadenas pertenecientes a tales lenguajes.
Un reconocedor finito de un lenguaje L es un AF que sólo acepta las cadenas
de dicho lenguaje, en el sentido de que, inicializado en un estado predeterminado,
qv si se le introduce una cadena de entrada x1 e L, da un símbolo final de salida
que corresponde a "aceptación" (por ejemplo, s = 1), mientras que para x 1 g L
produce una salida de "no aceptación" (por ejemplo s = 0). En adelante supon-
333
dremos siempre que hablemos de reconocedores que se trata de máquinas de
Moore. Podemos entonces hacer abstracción del alfabeto de salida y de la función
g, y considerar el subconjunto de estados F c Q que producen la salida de acep-
tación, a los que llamaremos estados finales. De acuerdo con esto, daremos la
siguiente definición formal.
Un reconocedor finito es una quíntupla
R= <E,Q,f,qvF>
donde:
E es un conjunto finito (alfabeto de entrada).
Q es un conjunto finito (conjunto de estados),
/ e s una función/: E x Q —> Q (función de transición).
ql e Q es un estado designado como estado inicial.
F czQ es un conjunto de estados designados como estados finales.
Llamaremos L(R) al conjunto de cadenas aceptadas por R, es decir,
1.2. Ejemplos
Ejemplo 1.2.1
a b
<h <h <?4
<?2 <?2
®
% ?4 «4
o,
Figura 4.1.
0 1
ft ftft
O ftft
ft ftft
ft ftft
Figura 4.2.
Ejemplo 1.2.3
a,b,c a 6 c
«2 ft ft
ft ft ft
ft ft ft
ft ft ft
ft ft ft
Figura 4.3.
L(R)={a, be}
Ejemplo 1.2.4
1 2 3
ft ft ftft
(ft) ft ftft
ft ft ftft
Figura 4.4.
335
2. Lenguajes aceptados por
reconocedores finitos
2.1. Planteamiento del problema
Podemos preguntarnos si, dado un lenguaje cualquiera, L<^E*, podemos
siempre encontrar un reconocedor finito,/?, tal queL(i?) =L. Observemos que esa
pregunta ya la habíamos dejado planteada, en términos más generales, en el
capítulo 2, cuando, al final del apartado 3.1, decíamos: dada una máquina
¿podemos encontrar su circuito?
Baste un ejemplo para demostrar que existen lenguajes a los que no corres-
ponde ningún reconocedor finito. Consideremos E = {0,1}, y sea
L = {I"' | n>l}.
Supongamos que existe un i?, conp estados, tal que L(R) = L. Para cadenas del
tipo x = V tendremos que /(l', q) e F si i es un cuadrado perfecto. Para las p + 1
cadenas x0 = Io, x1 = l 1 , .., xp = V, tendremos como estados resultantes f(xa, qi),
f(xj, qi), ...,fíxp, pero como el reconocedor sólo tienep estados, al menos dos
de estos estados resultantes deberán ser el mismo: f(V, qi) =f(V, qi), con j -i<p.
Entonces, si el reconocedor acepta
ya que
Vemos pues que los lenguajes aceptados por algún reconocedor finito son un
subconjunto de todos los lenguajes posibles sobre E*.
336
Ahora podemos preguntarnos: ¿existe alguna propiedad que caracterice a los
lenguajes que son aceptados por un reconocedor finito? Si tal propiedad existe
parece lógico pensar que pueda deducirse de la capacidad del reconocedor para
responder de distinto modo a diferentes cadenas de entrada.
337
una relación de congruencia derecha enE*. Veamos cómo pueden aplicarse estas
conclusiones para caracterizar a los lenguajes aceptados por reconocedores fi-
nitos.
Es evidente que se trata de una relación de equivalencia. Para ver que también
es una congruencia derecha basta suponer que z = z,z2, con lo que
c) Es claro que
d) Y también que
e) Por definición de ,
[(xzeL) o (yz e L ) ] o ( x = ¿ y)
f) El razonamiento constituido por las premisas b), c), d) y e) nos lleva a la
conclusión de que
(*=* y)-»(*=£ y)
RL = <E,QL,fL, qp Fr >,
donde
y por la definición de
( V y G £ * ) (([XJ, y ] G L) <->([X 2 , y ] G L)
339
es decir, x t = L x2, x, y x2 se encuentran en la misma clase de equivalencia, por lo
que qLi = q L i .
a) Unión:
Ll u L 2 = {x |x e Z ^ v x e L 2 }
b) Concatenación:
340
a) LR es un subconjunto finito de E* (puede ser L = 0 ) , o bien;
1
A es la cadena vacía (elemento neutro para la concatenación de cadenas), y 0 es el conjunto vacío (elemento
neutro para la unión de conjuntos).
341
E Expresión regular, a Conjunto regular, | a |
2. {0,1} 1(01)* Conjunto de cadenas que
empiezan por "1" y sigue
(01) cualquier número de
veces (o ninguna).
3. {a, b,c} a + be {a, be}.
4. {1,2,3} (1 + 2)*3 Conjunto de cadenas for-
madas mediante los sím-
bolos 1 y 2 sucediéndose
cualquier número de veces
(y en cualquier orden), y
siempre dando por finali-
zada la cadena mediante el
símbolo 3.
5. {e„ e2,..., e„} (e, + e2 + ... + e„)* E*.
6. {0,1} (01)* El conjunto formado por X
y todas las cadenas consti-
tuidas por la cadena 01
repetida cualquier número
de veces.
7. {0, 1} 0*10* Conjunto de todas las ca-
denas que tienen un "1" (y
sólo uno).
(a = P ) H « l = IPI
Teniendo esto presente, es fácil demostrar las siguientes propiedades de las
expresiones regulares:
1. Asociatividad de la concatenación:
a(Py) = (ap)y
2. Distributividad de la suma:
a (3 + a y = a ( P + y);
P a + y a =(P + y ) a
a + 0 = 0 + a = oc
a 0 =0 a = 0
aX = Xa = a
| ( a * p * ) * | = { X } u | a * p * | u | a * p * | 2 u... =
= {A,} u|a*||P *| u|a*||P *||a*||P *| u ... =
= { A , } u | a | u | P | u | a | 2 u|p| 2 u | a | | p | u | p | | a | u . . .
Pasemos ahora a ver que todos los lenguajes aceptados por reconocedores
finitos son conjuntos regulares y que todo conjunto regular es un lenguaje
aceptado por un reconocedor finito, lo que nos va a permitir resolver los proble-
mas de análisis y de síntesis, respectivamente.
343
4. Resolución de los problemas de análisis
y de síntesis de un reconocedor finito
4.1. Análisis
4.1.1. Teorema de análisis
Todo lenguaje aceptado por un reconocedor finito es un conjunto regular.
Supongamos que el reconocedor finito tiene n estados, Q = {qv ..., qn}, con estado
inicial q1 y con estados finales F = {qf , qf , ..., qf } (n>r> 0). El lenguaje
aceptado es:
^ 0 si r = 0
344
4.1.3. Ejemplos
Vamos a tomar los mismos cuatro ejemplos del apartado 1.2: partimos de los
diagramas y debemos llegar a las expresiones regulares que ya conocemos.
« 4 B = OC313+ a 3 H « 4 ) * «343
3
Pero a 43 = 0 , como se ve directamente en el diagrama de Moore, por lo
que
a 2 1 3 = oc\ 3 + a^ia1,,)*
a \ 3 = a° 1 3 + a ° n ( a ° n ) * a° 13 = 0 + X(X)*0 = 0
aI
i2= «°,2+ «0ii(a°ii)*a0i2 = «+ X{X)*a = a
a\2 = a°22 + a°21 (<x°u )* a°12 = a+ 0(X)*a =a
a\3= a°23+ a°21(a°u)*a °13 = b+ 0(X)*0 =b
Luego:
345
Se ve sobre el diagrama que a 342 = 0 , por lo que ya no tenemos necesidad
de calcularla, ni de calcular a 3 14 ni a 344 :
4.2. Síntesis
4.2.1. Teorema de síntesis
Todo conjunto regular es un lenguaje aceptado por un reconocedor finito. Hay
publicadas varias demostraciones de este teorema,bastante laboriosas todas ellas,
por lo que, a fin de no alargar excesivamente este tema, nos permitimos no incluir
ninguna, remitiendo al lector a las notas bibliográficas del apartado 6. En cambio,
nos parece interesante dar un algoritmo que permite obtener directamente el
reconocedor de un conjunto regular denotado por su expresión regular. Para ello
necesitamos introducir un nuevo concepto: el de derivadas de una expresión
regular.
346
LR que empiezan por un determinado símbolo, e. Definimos el cociente izquierdo
d&LR por e, LR \ e, como el conjunto resultante de suprimir e en todas esas cadenas:
Lr \ e = {x | ex 6 LK}
X si ex = e 2
a) D(e2) =
0 si ex ^ e2
b) D£X)=De(0)=0
c) £>/oc + P) = £ > / « ) + £ ( | 3 )
5 ( a ) = 0 siXe |a|
8 ( a ) = X si Xe |a|
d) D . ( a P ) = [I>.(a)]P + S ( a ) D . ( P )
347
Finalmente, veamos cómo se calcula la derivada de la operación cierre.
Sabemos que
Dx( a) = a
Dxe(a) =De[Dx(a)]
4.2.4. Ejemplos
Para ilustrar la aplicación del algoritmo anterior vamos a tratar los mismos
cuatro ejemplos del apartado 1.2. Teníamos allí cuatro reconocedores; las expre-
siones regulares de los correspondientes lenguajes las obtuvimos en los apartados
3.3 y 4.1.3. Pues bien, ahora partiremos de esas expresiones y comprobaremos
que, con el algoritmo de síntesis, llegamos a los diagramas originales.
Ejemplo 1.
a = aa*bb* = (a)(a*bb*)
£>.(a) =Da(á)a*bb* + 6 (a) Da(a*bb*) =
= Xa*bb* + 0D£a*bb*) = a*bb*
Db(a)=Db(á)a*bb* + 8 (a) Db(a*bb*) = 0a*bb* + 0D„(a*bb*) = 0
Daa(a) = Da(a*)bb* + 8 (a*) Da(bb*) =
=D£a)a*bb* + X 0 = Xa*bb* = a*bb* =D£a)
Calcularemos ahora las derivadas terceras a partir de Dab(a) (puesto que ésta
es la única derivada segunda que no es igual a ninguna anterior).
DJLa)=D£b*)=D£b)b* = 0b* = 0
DM(a)=Db(b*) = Db(b)b* = b* =DJa)
349
De las derivadas calculadas, la única que contiene la cadena vacía es Dab(a) =
b* por lo que
F= {DÁa)}
Y la función de transición será
Ka,a)=D£a);f(b,a)=Db(a)
f(a,Dm(a))=Dm(a)=D£a)
j{b,D£a))=Dab(a)
j{a,Db(a))=Db£a)=Db(a)
j{b,Db(a))=Dbb(a)=Db(a)
f(a,Dab(a))=Dab£a)=Db(a)
Kb,Dab(a))=Dabb(a)=Dab(a)
Podemos así dibujar el diagrama de la figura 4.5, que es el mismo de la figura
4.1, c o n q i = a ; q 2 = D£a); qs = Dab(a); q4 = Db(a).
Figura 4.5.
Ejemplo 2.
Ai(«)=A[(01)*] = 0
Por tanto,
Q= {a,D0(a),D1(a)}
F = {D1(a)}
KO,a)=D0(a)
Kl,a)=Dt(a)
f(0,D0(a))=Dm(a)=D0(a)
Al,D0(a))=Dai(a)=D0(a)
f(0,D1(a))=Dw(a) =a
J{l,D1(a))=Dn(a)=D0(a)
351
Ejemplo 3.
a = a + be
Derivadas
Da(a)=Da(d)+Da{bc) =X +0 =X
Db(a) = Db(a) + Db{bc) = 0 +c = c
Dc(a) -Dc(a) +Dc(bc) = 0
Dm(a)=Dab(a)=Dac(a) = 0=D£a)
D¿a)=D£c)=0=D£a)
Dbb(a) = Db(c)=0=D£a)
Dbc(a)=Dc(e)=X=D£a)
DC£A)=DÁ a)=Dc£a)=0 = D£CL)
Q= {a,D£a),D£a),De(a)}
F = {Dm(a)}
Función de transición
Con esto, resulta el diagrama de la figura 4.7, que es distinto del original de la
figura 4.3. La explicación es la misma del ejemplo anterior: el de la figura 4.3 no
está en forma mínima (q2 y q4 son equivalentes).
Ejemplo 4.
a = (1 + 2)*3
Derivadas:
353
5. Resumen
Orientándonos ya hacia las relaciones entre lenguajes y autómatas, hemos
definido un reconocedor finito como un tipo particular de autómata finito en el
que existe un estado inicial fijo y el alfabeto de salida consta sólo de dos símbolos,
correspondientes a la aceptación o no aceptación de la cadena de entrada. Hemos
demostrado la condición general que debe cumplir un lenguaje para que todas sus
cadenas sean aceptadas por un reconocedor finito: que la relación de congruencia
derecha inducida por el lenguaje tenga índice finito (ese índice es, precisamente,
igual al número de estados del reconocedor).
Se han definido los conjuntos regulares, que, según los teoremas de análisis y
síntesis, son justamente los lenguajes que pueden ser aceptados por un reconoce-
dor finito. Las expresiones regulares constituyen un metalenguaje para describir
de una manera cómoda a los conjuntos regulares. El algoritmo de análisis permite,
dado un reconocedor finito, deducir la expresión regular del lenguaje que acepta
ese reconocedor. A la inversa, hemos visto un algoritmo de síntesis mediante el
cual se llega al diagrama de Moore de un reconocedor finito minimizado corres-
pondiente a una expresión regular dada.
354
7. Ejercicios
7.1. Dada la tabla de transición
a b c
Qi <?2 q6 <7i
q3 Q5 <7i
q3 q3
QA Qr QT
Qs Q5 ft
Qe Qs <7i
© Qt Qr <7i
7.5. Diseñar un circuito secuencial que dé una salida "1" cuando la cadena
de entrada tenga un número de "unos" congruente a 0 (mód. 2). (La
expresión regular es a = 0*(10*10*)*).
355
a b c d
<7, Qa q3 q< q4
<72 q3 q2 q* q<
q3 q3 q3 q3 q3
(5) q3 q3 q4 q4
356
7.7. Las expresiones regulares básicas que ilustra el diagrama de la página
anterior describen a los conjuntos regulares de los reconocedores co-
rrespondientes. (El estado inicial es siempre q{)\
a b
<7, <7i <7a
<72 <74 <7s
q3 <7S <7i
q* <7s <72
(?) <74 Qs
357
5
Otros autómatas
1. Introducción
El autómata finito estudiado en los anteriores capítulos es un modelo aplicable
a cualquier sistema dinámico, discreto y con memoria (siempre que la memoria
sea finita). Ahora bien, para determinados sistemas, la descripción que se obten-
dría con tal modelo seria inútil, por demasiado compleja (número de estados y de
transiciones desorbitado) o porque los estados engloban de forma poco natural un
conjunto de condiciones internas del sistema. Tal ocurre, por ejemplo, cuando el
sistema está compuesto por subsistemas con funcionamiento asincrono y concu-
rrente. Para modelar estos casos se han propuesto diversas generalizaciones del
modelo. Una de las más conocidas y más aplicadas en informática es la llamada
"red de Petri". La red de Petri puede, además, como veremos, modelar sistemas
con infinitos estados, por lo que se aproxima, en cuanto a potencia de descripción,
a la máquina de Turing. Otra posibilidad para la modelación de sistemas comple-
jos es construir redes de autómatas interconectados, llamados "autómatas
celulares".
Por otra parte, los modelos que hemos considerado hasta ahora son completa-
mente deterministas. Es decir, dado un estado y un símbolo de entrada, el estado
siguiente y el símbolo de salida vienen determinados por las funciones f y g,
respectivamente. Pero se dan situaciones cuya complejidad funcional y la imposi-
bilidad de analizar todos los factores que intervienen hacen que sea preferible
359
modelarlas a partir de la idea de probabilidad. Tal ocurre, por ejemplo, cuando la
fiabilidad de los componentes es pequeña, o cuando se quiere modelar órganos o
procesos de los sistemas vivos. Así, si observamos que, estando en el estado ql y
recibiendo entrada e, el sistema pasa al estado q2 un 80% de las veces y al q3 un
20%, diremos que f(e{, qt) = q2 con probabilidad 0,8 y /(e p qt) = q} con probabilidad
0,2. Esta es la idea básica del autómata probabilista o estocástico.
Si en lugar de "probabilidad" utilizamos "borrosidad" tendremos un autómata
borroso. Uno de los campos de aplicación más interesante de los autómatas
estocásticos y de los borrosos está en los sistemas de aprendizaje: el autómata, en
interacción con su entorno, puede ir modificando su estructura para adaptarse a
tal entorno. En este capítulo trataremos de todo esto (redes de Petri, autómatas
estocásticos y borrosos, autómatas celulares y aprendizaje).
2. Redes de Petri
2.1. Estructura estática
Definición 2.1.1. Una red de Petri (RdP) es una cuádrupla
<L, T, A, P>
donde:
a ( 0 = { / 1 , / 5 } ; P ( 0 = {/J
a(t2) = {l2y,$(t2) = {lvl5}
a(/ 3 ) = { / 3 , / 3 } ; P ( 0 = {/ 4 }
a ( 0 = {/4};P(0 = { U J
360
Una RdP puede representarse gráficamente como un grafo bipartido orientado,
en el que hay dos tipos de nodos: círculos (para los lugares) y segmentos (para las
transiciones), y los arcos representan a las funciones a y (3. Así, el grafo del
ejemplo anterior sería el de figura 5.1.
0 si i no es entrada ni salida de t¡
1 si /,. es salida de t¡
-1 si l es entrada de í.
-1 1 0 0
'2 1 -1 0 0
0 0 -1 1
'4 0 0 1 -1
íc - 1 1 -1 1
361
El concepto de RdP tal como lo acabamos de definir está incompleto, porque
no contempla ningún comportamiento dinámico. En particular, se observará
que no se ha definido el estado.
|i:L->N
El número de marcas en /,. será |j. (/.). El número y posición de las marcas varía
con el tiempo según las reglas que definiremos enseguida. En cada instante,
tendremos un vector |j. = (l¡), ¡1 (l2) ...] r que indica el número de marcas en cada
lugar.
<L,T, c c , | 3 , n 0 >
Definición 2.2.3. Una transición t¡ está permitida por el marcado si todos sus
lugares de entrada tienen al menos una marca, es decir, si
Definición 2.2.5. El estado de una RdP en un instante viene dado por su mar-
cado |j.( en ese instante. El conjunto de estados, M, será, pues, el conjunto de
todos los marcados posibles.
Definición 2.2.6. La función de transición, f de una RdP es una función
f: MxT —>M
HO = [ 1 0 1 0 LF;
m = [0 1 1 0 Of;
^3> Kl tv "O
363
Obsérvese que la ejecución no es única: con el marcado |X0 pueden dispararse
indistintamente t16 t3; cuál de ellas lo hace depende de acontecimientos externos
que no figuran en el modelo. Las RdP son, pues, modelos no deterministas, como
los autómatas que veremos en el tema "Lenguajes".
Teorema 2.2.8. La función de transición de una RdP puede escribirse explíci-
tamente en función de la matriz de incidencia, I, y de un vector, u:, cuyas
componentes (tantas como transiciones tenga la RdP) son todas nulas, salvo la que
corresponde a la transición disparada en el instante i, que vale 1, y ello mediante
la llamada ecuación de estado de la RdP:
Hitl = ili+I-u,
Para la demostración, que omitimos, basta con ver que todas las componentes
de satisfacen la ecuación, teniendo en cuenta la definición de / (apartado 2.1).
En nuestro ejemplo, si, partiendo de |i 0 , se dispara tv tendremos:
1 -1 1 0 0 1
0 1 -1 0 0 0
H ^ H o + 7-Wo = 1 + 0 0 -1 1 0
0 0 0 1 -1 0
1 -1 1 -1 1
1 -1 0
0 1 1
1 + 0 = 1
0 0 0
1 -1 0
0 -1 1 0 0 0
1 1 -1 0 0 1
^2 = M - I + / m I = 1 + 0 0 -1 1 0
0 0 0 1 -1 0
0 r l 1 -1 1
0 1 1
1 -1 0
1 + 0 = 1
0 0 0
0 1 1
I
= + / • X " / = Ho
j=i
1 -1 1 0 0 2
0 1 -1 0 0 1
1 + 0 0 -1 1 1
0 0 0 1 -1 1
1 -1 1 -1 1
1 -1 0
0 1 1
1 + 0 = 1
0 0 0
1 -1 0
365
limitado. Por ejemplo, en la RdP de la figura 5.3, la secuencia tv t2, tv tr.. hace
crecer indefinidamente el número de marcas en l y
Pero en ciertas RdP el número de marcados posibles a partir de uno inicial es
finito. Así ocurre en el ejemplo de la figura 5.2. Esa RdP es, además, binaria: a
partir de un marcado que no asigne a cada lugar más de una marca, todos los
marcados sucesivos son tales que cualquier lugar tiene una marca o ninguna. En
este caso, como hay cinco lugares, el número de marcados binarios posibles es 25
= 32. Sin embargo, no todos ellos son alcanzables a partir de uno inicial dado. Por
ejemplo, si |0.o es el de la figura 5.2, es decir,
|X0 = [1 0 1 0 l f
= [0 1 1 0 Of
\x2 = [1 0 0 1 Of
Figura 5.3.
Figura 5.4.
367
Programa 1 Programa 2
Sección A1 Sección A2
j P(exmut) ¡ P(exmut)
Sección crítica 1 Sección crítica 2
\ V(exmut) l l/(exmut)
V Sección B1 V Sección B2
Z5 es el semáforo "exmut".
t{ es la "P" del Proceso 1; hay que añadir la condición de disparo: fin de la
ejecución de la "Sección Al".
t2 es la "V" del Proceso 1; la condición de disparo es el fin de la ejecución de
la "Sección crítica 1".
Zj es "entrada en la Sección B1".
l2 es "entrada en la Sección crítica 1".
Z3, t4, Z3 y Z4 son las análogas del Proceso 2.
Obsérvese que los lugares l2 y l4 quedan mutuamente excluidos.
Como un ejemplo más concreto del problema de la exclusión mutua, conside-
remos uno clásico: el de los lectores y redactores, procesos concurrentes que
acceden a unos datos comunes con las siguientes restricciones:
a) Los lectores pueden acceder a los datos simultáneamente.
b) Por el contrario, los redactores, como modifican los datos, deben trabajar
en exclusión mutua entre sí y excluyendo también a los lectores. Es decir,
mientras un redactor está ejecutando la sección crítica (acceso a los datos)
ningún otro proceso puede entrar en su sección crítica.
c) Los procesos pueden estar en alguno de estos tres estados:
A (activo: ejecutando su sección crítica);
E (esperando entrar en su sección crítica);
R (reposo: no necesita los datos, aunque puede estar ejecutando otra parte
del programa).
Figura 5.5.
Supongamos que hay dos lectores y dos redactores. Cada uno de los cuatro
procesos puede modelarse como una RdP, según la figura 5.5. Los tres lugares
corresponden a los estados definidos, y las transiciones se disparan cuando en el
proceso aparecen determinados acontecimientos: D (demanda de acceso a los
datos), C (comienzo de ejecución de la sección crítica, o acceso a los datos), F (fin
de acceso a los datos).
Ahora bien, para poder cumplir las restricciones enunciadas será preciso
interconectar las cuatro subredes: el acceso de un lector a los datos tienen que
excluir acceso de los dos redactores, pero no del otro lector, y el acceso de un
redactor tiene que excluir el acceso de los otros tres. Podemos utilizar dos semáfo-
ros, S, y S2 para excluir al lector 1 de los dos redactores y S2 para el lector 2. La
RdP global será la de la figura 5.6, en la que 11,12, rl,r2 significan "lector 1",
"lector 2", "redactor 1" y "redactor 2".
Obsérvese que la RdP en este ejemplo es binaria , y, por ello, el número de
estados es finito. Por tanto, podríamos hallar un AF equivalente, como hacíamos
en el apartado 2.3. Los estados de tal AF corresponderían a combinaciones de
estados de cada uno de los procesos, haciendo más difícil la interpretación del
modelo. Además, la RdP es modular: si se ha comprendido la idea de la figura 5.6,
es muy fácil extenderla a casos con más lectores y/o redactores. Finalmente, el
paso a la programación es inmediato: basta con poner, en cada proceso, opera-
ciones P y V sobre S1 o S2 en las transiciones C y F.
369
2.4.3. Problemas de sincronización: productores
y consumidores
En muchas aplicaciones, dos o más procesos pueden ejecutarse concurrente-
mente pero no de manera independiente: uno de los procesos no puede seguir a
partir de un punto si el otro no ha realizado una cierta acción. Para concretar,
consideremos otro problema clásico en informática: un proceso productor genera
elementos que deposita en un almacén o zona de memoria ("buffer"), mientras
que un proceso consumidor extrae elementos del mismo almacén. El almacén
tiene una capacidad limitada, N. El productor repite continuamente un ciclo:
"producir un elemento-meterlo en el almacén-producir un elemento..."; el con-
sumidor, otro: "extraer un elemento-consumirlo-extraer...". En la figura 5.7, la
parte de la izquierda corresponde al ciclo del productor, con
M = meter un elemento;
370
Fm = fin de la operación de meter (y comienzo de producir);
P = producir un elemento;
Fp = fin de la producción,
S = sacar;
C = consumir un elemento;
Fc = fin de consumir.
Como indican las líneas de puntos , la RdP está incompleta. Es preciso añadir
los mecanismos de sincronización entre ambos procesos:
a) Cm no puede dispararse si no hay sitio disponible;
371
Figura 5.7.
Figura 5.8.
Obsérvese también aquí que el número de estados es finito, pero que el AF
equivalente, que podemos encontrar, modela de manera menos natural los fenó-
menos. Asimismo, que es fácil extender la RdP para que considere más
productores y/o consumidores.
Un ejemplo típico de procesos que han de coordinarse de este modo se tiene
en los sistemas operativos con los gestores ("drivers") de dispositivos de entrada
y salida: un gestor de salida es un consumidor que, cuando tiene en el almacén
alguna información para enviar al periférico de salida, se ejecuta; el productor es
el programa que produce esas informaciones. Simétricamente, un gestor de
entrada es un productor para los programas que consumen esas informaciones.
El esquema para la programación de un productor y un consumidor sería:
Productor Consumidor
r r
Producir-elemento; p(sey,
P(SJ;
P(SJ; Sacar-elemento;
Meter-elemento; V{Sm);
V(SJ; V{Ss);
Consumir-elemento.
3. Autómatas estocásticos
3.1. Definición
Un autómata estocástico o probabilista es una quíntupla
AP = <E, S, Q,P,h>,
donde:
373
h: es la función de salida (consideraremos sólo autómatas de tipo
Moore), que se supone determinista.
3.2. Ejemplo
Sea un autómata estocástico definido por:
E = S={ 0,1}
Q = Wv It}
%,) = 0; h(q2) = 1
P(0, qj = (0,7; 0,3); P( 1, qj = (0,4; 0,6)
P(0, q2) = (0,6; 0,4); P( 1, q2) = (0,2; 0,8)
374
Podemos representar este autómata por un diagrama de Moore (figura 5.9),
indicando sobre cada transición la probabilidad asociada.
qj 1
0/0,6
1/0,2
Figura 5.9.
2
0,7 0,3 0,4 0,6 0,268 0,732
M(011) =
0,6 0,4 0,2 0, 8 0, 264 0, 736
Así, la probabilidad de pasar de q, a q2 bajo la acción de x = 011 es 0,732. Al
mismo resultado se llega si se consideran las cuatro posibilidades existentes para
pasar de q, a q2 con la cadena 011:
375
O, 1, 1 : probabilidad = 0,3 X 0,2 x 0,6 = 0,036
Rp = <E, Q,qvP,F>
P(x) = YsPiiq
i
Así, en el ejemplo anterior, si q1 es el estado inicial y q2 el final, p(011) = 0,732.
Se define el lenguaje aceptado por un reconocedor estocástico haciéndolo
depender de un parámetro designado mediante la letra X „ llamado punto de corte
del lenguaje:
L¿\) = {xeE*\p(x)>'k}
376
donde E, S, Q, P, h tienen el mismo significado anterior, y A es un algoritmo
llamado esquema de actualización o esquema de refuerzo que genera P,+1 a partir
de P,, st y et. Así en un APEV las probabilidades de transición no son siempre las
mismas, sino que van evolucionando en función de su valor anterior, de la res-
puesta última y de la entrada. Esta característica es la que confiere al APEV la
capacidad de adaptarse y de aprender.
Figura 5.10.
377
En el apartado 8 veremos que esta definición se puede enmarcar en una
concepción más amplia del aprendizaje. Veamos ahora cómo con autómatas
sencillos pueden construirse sistemas cuyo comportamiento satisface a esta
definición.
e e E seS
APEV
Entorno
Figura 5.11.
Xc,
M ( 0) =
6. Autómatas borrosos
Podemos definir un autómata finito borroso como
AB = <E,S,Q,f,h>
/: ExQxQ^M
si J(e, q., q¡) = 0, seguro que, con entrada e, no hay transición de q. a q:,
si f(e, q¡, q) = 1, seguro que, con entrada e, hay transición de q¡ a qr,
si f(e, qP q~¡) = a , a es el grado de confianza de que, para entrada e, haya
transición de q¡ a qf
F-.ExQ^M
379
con
F(e, q) = (ft(e, q),f2(e, q), ...,fn(e,q)),
T(e) =
Ejemplo:
0 0 0,8
T(c) = 0 0,8 0
0 0,6 0,2
Gráficamente, representaremos al autómata por el diagrama de la figura 5.12.
El concepto recuerda al de autómata probabilista (AP),pero hay dos diferencias
importantes:
a) Puesto que no se trabaja con probabilidades, no es necesario que las filas
de las matrices de transición tengan componentes cuya suma sea la unidad.
Kx>qi>q¡) = X •/(<?!,qk,q¡)]
bl0,4
c/0,8
a/0,2
6/0,7
a/0,6
6/0,2
Figura 5.12.
0,6 0 0,1
Q'b" = [l o o] 0,5 0 0,1
0,2 0 0,1
381
= [0,6 O 0,l] = {(qi/0,6);(q3/0,l)}
7. Autómatas celulares
Evidentemente, los AF, sean deterministas, estocásticos o borrosos, pueden
interconectarse: si tenemos dos AF (deterministas, para simplificar),
A1 = <EVSV QvfVGT>
A2 = <E2,S2,QVF2,G2>
tales que E2 = ST, y si suponemos que A2 siempre recibe como entrada el símbolo
de salida generado por AV el conjunto es un AF:
382
típicos de la realimentación). En general, con N autómatas que compartan los
mismos alfabetos de entrada y salida podemos construir redes de autómatas.
Aunque cada uno de los autómatas componentes tenga un comportamiento indi-
vidual muy sencillo, siNy el número de conexiones son suficientemente grandes,
el comportamiento colectivo del sistema puede ser tan complejo como para imitar
los fenómenos que se encuentran en los sistemas físicos o biológicos reales.'
Los autómatas celulares son redes de autómatas en las que:
1
Esto se debe a un principio de la ciencia de los sistemas que se suele expresar informalmente con una frase
atribuida a Aristóteles: "el todo es más que la suma de las partes". Es decir, de la combinación de elementos
simples pero ricamente interconectados surge un sistema con modos de comportamiento complejos e imprede-
cibles a partir del comportamiento sencillo de cada uno de los elementos.
2
E1 lector comprenderá fácilmente por qué se les llama también "autómatas de mosaico" ("tessellated automata").
383
autómatas celulares son especialmente interesantes cuando, además, se les dota
de reglas de reproducción y desaparición: en función del estado de la vecindad y
del suyo propio, una célula puede "morir" o bien, si su vecindad no está completa,
"procrear". Resultan entonces modos de comportamiento evolutivos y complejos
que guardan relación con un campo de mucha actualidad: los sistemas caóticos y
los fractales.
'Entiéndase por "máquina" un "sistema artificial", a fin de evitar una respuesta similar a la que daba Claude
Shannon ante la pregunta de si las máquinas pueden pensar: "You bet. I'm a machine and you're a machine, and
we both think, don't we?" (Horgan, 1992).
384
internos (son los "cambios adaptativos"). Después de un número suficientemente
grande de ejemplos, el sistema ha "generalizado", en el sentido de que sabe "leer
en voz alta" frases que no se le han presentado como ejemplos durante el
entrenamiento. Otros sistemas son los que aprenden a reconocer los caracteres
manuscritos de una determinada persona (tras una fase de entrenamiento para esa
persona), que se están utilizando ya industrialmente, por ejemplo, en los "ordena-
dores de lápiz" ("pen computers").
Sin embargo, si aprender es adquirir conocimientos, la respuesta depende de
lo que entendamos por "conocimiento". En los casos mencionados puede enten-
derse que, tras la fase de entrenamiento, el sistema "tiene el conocimiento"
necesario para traducir de caracteres escritos a sonidos en un caso, o para distin-
guir unos caracteres de otros, en el otro. Pero ¿dónde está este conocimiento, y
qué forma tiene? Está en los parámetros internos del sistema, que se han ido
ajustando, y su forma, numérica, es ininteligible para un ser humano. "NetTalk",
o un sistema similar, podrá diferenciar entre, y pronunciar más o menos acepta-
blemente, "this" y "these", pero de ninguna manera puede decirse que haya apren-
dido el concepto de "fonema"; un sistema de reconocimiento de caracteres podrá
llegar a distinguir entre "A" y "H", pero no nos informará de la diferencia
morfológica entre ambos.
Ahora bien, como veremos más adelante, también hay procedimientos que
permiten adquirir y formar conceptos. Es posible, por ejemplo, diseñar un pro-
grama que obtenga descripciones estructurales imprecisas de los distintos carac-
teres escritos ("concepto H" = "dos segmentos aproximadamente verticales unidos
en las proximidades de sus puntos medios por un segmento más o menos horizon-
tal"). Sistemas de este tipo ya no sólo aprenden: descubren regularidades en los
datos de entrada, generalizan y expresan los conceptos aprendidos en un lenguaje
simbólico y comprensible.
Así pues, la respuesta, en cualquier caso, es "sí". Un caso es el del aprendizaje
entendido como capacidad de cambiar adaptativamente mediante la modificación
de ciertos parámetros internos. En el otro caso se supone que el sistema dispone
de algún mecanismo de representación del conocimiento de forma inteligible para
la mente humana, y los cambios adaptativos consisten en modificar conocimien-
tos previos o adquirir conocimientos nuevos. Diremos que los sistemas que adop-
tan el primer punto de vista siguen un enfoque conductista, y los que se centran
en el segundo, un enfoque cognoscitivo.
En cuanto a las aplicaciones, aparte de las ya comentadas (síntesis de voz y
reconocimiento de caracteres), hay una de tipo práctico en la ingeniería del
conocimiento: la adquisición del conocimiento (tema "Lógica", capítulo 6, apar-
tado 1.4). La adquisición automática o semiautomática para la construcción
sistemas expertos es una alternativa al procedimiento "tradicional" de entrevistar
a expertos humanos. El sistema puede inducir sus propias reglas generales a partir
de "ejemplos" concretos (casos resueltos por el experto o con solución conocida
por cualquier otra vía). Otra aplicación de gran interés y potencialidad para la
385
evolución futura de la ingeniería del conocimiento es la posibilidad de inducción
automática de conocimientos explorando grandes bases de datos (apartado 8.4).
387
Este sistema, con una sola capa, tiene una limitación grave: la condición para
que el sistema converja durante el entrenamiento hasta conseguir un conjunto de
pesos que discriminen perfectamente entre las clases es que haya separabilidad
lineal en el espacio de características (espacio con tantas dimensiones como cé-
lulas asociadoras, en el que se proyectan los ejemplares presentados a la entrada).
Esto quiere decir que para cada clase debe existir un hiperplano que separe a las
proyecciones de los elementos de esa clase de las de todos los demás. Esta
condición es extraordinariamente restrictiva, pero basta con introducir dos "capas
ocultas" para formar regiones de separación arbitrarias en el espacio de caracterís-
ticas. (Una neurona oculta es aquella cuya salida no se toma como salida del sis-
tema, sino que activa a otra u otras neuronas a través de nuevos pesos). El algo-
ritmo anteriormente esbozado ya no es válido (¿cómo podemos evaluar las salidas
de las neuronas ocultas?), y se han desarrollado otros más complejos. Mencione-
mos solamente, para terminar este apunte sobre redes neuronales, el nombre del
más conocido: algoritmo de retropropagación.
Las redes neuronales son, al menos en su origen, un modelo "biónico" (es
decir, un modelo para ingeniería inspirado por los sistemas biológicos) basado en
la ontogenia: la formación de un sistema nervioso mediante modificaciones de las
conexiones sinápticas para adaptarse al entorno. Otro tipo de modelos biónicos
son los basados en la filogenia, o evolución de las especies. Son los algoritmos
genéticos, y los programas evolutivos, en los que el sistema está formado por una
"población" con una "dotación genética" que va evolucionando por mutación,
entrecruzamiento, y otros operadores genéticos. También son ya numerosas las
aplicaciones en ingeniería de estos sistemas, y de nuevo remitimos al lector a la
bibliografía del apartado 10 si está interesado en su estudio.
Figura 5.14.
389
una solución conocida de un problema) a una situación nueva (por ejemplo, un
problema similar).
En cuanto al conocimiento de base (conocimiento que existe en el sistema
previamente a la fase de aprendizaje), en los métodos puramente inductivos puede
ser nulo, mientras que en los deductivos y analógicos, por su propia naturaleza, es
esencial. Pero también en el aprendizaje inductivo puede ser importante. En
efecto, el proceso de aprendizaje es asimilable a una búsqueda en un espacio de
descripciones, y el conocimiento de base puede servir para que esa búsqueda no
sea "ciega", sino guiada. Esto está muy estrechamente ligado con el lenguaje de
descripción. Antes hemos dicho que en muchos sistemas el lenguaje es del tipo
"0+", lo que limita el rango de problemas que pueden tratarse: por ejemplo, no
pueden aprenderse conceptos que se refieran a objetos estructurados o a relaciones
entre objetos; para ello sería preciso utilizar un lenguaje basado en la lógica de
predicados. El problema de utilizar un lenguaje de descripción más expresivo es
que el espacio de búsqueda se hace también mucho más extenso y aparece el
fantasma conocido en la inteligencia artificial como explosión combinatoria
(fenómeno que ya hemos comentado en el tema "Lógica": apartados 4.8 del
capítulo 4 y 2.5 del capítulo 6). De manera más rigurosa, y utilizando un término
que se definirá con precisión en el capítulo 7 del tema "Algoritmos", podemos
decir que el uso de estos lenguajes conduce a problemas de complejidad superior
a la polinómica en los algoritmos de aprendizaje. Es aquí donde entra enjuego el
conocimiento de base, "podando" la búsqueda y reduciendo la complejidad de
modo que el problema se haga tratable.
En cualquier caso, los sistemas más conocidos son los llamados de aprendizaje
empírico. Son sistemas inductivos sin conocimiento de base en los que el proble-
ma del aprendizaje se expresa en términos de adquisición de concepto. Un con-
cepto es, en principio, una clase de equivalencia. Los ejemplos que forman el
conjunto de entrenamiento deben estar clasificados en un número finito de clases,
y la tarea del sistema consiste en adquirir a partir de ellos una descripción para
cada clase, de modo que cuando se presente la descripción de un objeto nuevo
pueda asignársele una de las clases. Como ejemplo de sistema de este tipo, uno ya
clásico es la aplicación que se hizo de un algoritmo de aprendizaje empírico
llamado "AQ" a un sistema experto para el diagnóstico de enfermedades en la
planta de la soja. El número de enfermedades distintas (conceptos) era quince, y
el de síntomas (atributos) treinta y cinco. El sistema experto había sido construido
inicialmente con técnicas tradicionales de adquisición del conocimiento (entrevis-
tas con expertos para la obtención de reglas), y su precisión en el diagnóstico era
71,8%. A lo largo del trabajo se habían llegado a recopilar 630 casos de enferme-
dades diagnosticadas; de ellos se tomaron al azar 290 (conjunto de entrenamiento)
sobre los que se aplicó el algoritmo "AQ", y las reglas obtenidas se comprobaron
con los 340 casos restantes (conjunto de comprobación). La precisión obtenida al
sustituir las reglas de los expertos por las inducidas fue 97,6%.
8.4. Formación de conceptos y descubrimiento
Hasta ahora hemos venido suponiendo implícitamente, tanto en las figuras
como en el texto, que existe un "crítico" o "maestro" que "enseña" al sistema, bien
sea porque le da "premios" y/o "castigos" durante la fase de entrenamiento (como
suele hacerse en los enfoques conductistas), o porque ha proporcionado previa-
mente un conjunto de ejemplos "clasificados" con los que el sistema trabaja luego
para inducir su conocimiento (como en "AQ"). Se dice en todos estos casos que
el aprendizaje es "supervisado". En el aprendizaje "no supervisado" no hay
maestro: el sistema debe descubrir por sí mismo regularidades en los datos de
entrada e inducir categorías o conceptos. El aprendizaje supervisado se llama
también adquisición de conceptos, y el no supervisado, formación de conceptos.
En formación de conceptos hay tres campos: agrupamiento conceptual, descu-
brimiento cuantitativo y descubrimiento cualitativo.
Los sistemas de agrupamiento conceptual buscan "similaridades" entre los
objetos, los agrupan en clases (o conceptos) y obtienen descripciones de estas
clases. Su utilidad radica en que pueden descubrir clasificaciones cuando el
número de objetos y de sus atributos y relaciones es muy grande para la intuición
humana. Con el descubrimiento cuantitativo se trata de encontrar relaciones
numéricas en los datos. Así, el sistema "BACON" ha "redescubierto" muchas
leyes clásicas de la física y la química. El descubrimiento cualitativo pretende
encontrar entre los datos relaciones más generales, descubrir conceptos y formar
teorías.
Aparte de su evidente interés científico, estos sistemas tienen una aplicación
práctica inmediata en los sistemas de información. En efecto, es un hecho sobra-
damente conocido el crecimiento exponencial del volumen de datos almacenados
en los servidores de información repartidos por todo el mundo y las posibilidades
de acceso cada vez mayores a esos datos. Los sistemas de descubrimiento
automático pueden aplicarse a facilitar la navegación por esas fuentes y a encon-
trar en esas grandes masas de datos la información que se busca (y que se esconde
en ellos). A este campo se le llama también "minería de datos".
9. Resumen
El modelo básico de autómata finito (AF) descrito en los anteriores capítulos
puede generalizarse en varias direcciones. Las redes de Petri (RdP) y los modelos
derivados de ellas son generalizaciones útiles porque permiten representar, de
forma más expresiva que con AF, sistemas discretos compuestos por subsistemas
que se comunican entre sí. Esto tiene gran interés, por ejemplo, en el procesa-
miento distribuido, en las redes de ordenadores y en los protocolos de comuni-
caciones.
391
Una vía alternativa para la modelación de sistemas complejos son los autóma-
tas celulares, formados por retículos de células simples en un espacio geométrico,
y que encuentran aplicaciones, por ejemplo, en procesamiento de imágenes.
Otra generalización surge al considerar modelos estocásticos o borrosos. En
principio, su interés es la modelación de sistemas en los que no se conocen con
precisión las relaciones causales. Pero también son la base para el diseño, median-
te autómatas de estructura variable, de sistemas que "aprenden" (mejoran su com-
portamiento) al ir interactuando con su entorno.
Y este último asunto nos ha conducido al campo del aprendizaje automático
entendido de un modo más general. Aquí solamente hemos esbozado las ideas
básicas del campo. Como compensación, en el apartado siguiente nos extendere-
mos algo más de lo habitual tanto en su evolución histórica como en referencias
bibliográficas para el lector interesado en estudiarlo con detalle.
392
utilizar AF deterministas en un entorno aleatorio como modelos de aprendizaje, y
algo más tarde, Varshavskii y Vorontsova (1963) demostraron que el número de
estados se reduce utilizando autómatas estocásticos con actualización de las
probabilidades de transición (es decir, con estructura variable). Por otro lado,
Rosenblatt (1962), propuso el Perceptron, introduciendo mecanismos de refuerzo
en una sencilla red de neuronas. La formulación del autómata borroso aparece
algo más tarde (Wee y Fu, 1969). En esta definición, que es la que hemos
presentado en el apartado 6, la borrosidad sólo se da en la función de transición;
Virant y Zimic (1995) dan una formulación más general, con conjuntos de
entradas, estados y salidas borrosos.
Por su evidente analogía con los sistemas nerviosos naturales y por su poten-
cialidad para el aprendizaje en general (la "retina" puede generalizarse de modo
que las entradas sean señales de cualquier naturaleza) el Perceptron despertó
mucho interés hasta que Minsky y Papert (1969) demostraron sus limitaciones, y,
haciendo hincapié especialmente en la separabilidad lineal, pronosticaron muy
poco futuro para ellos, incluso para las redes multicapa. Su libro fue muy
influyente, y los 70 y primeros 80 fueron años "oscuros" para las redes neuronales,
pero es interesante indicar que los trabajos de Widrow (1962), paralelos a los de
Rosenblatt, derivaron en sistemas adaptativos con aplicaciones importantes en
sistemas de control y procesamiento de señales (Widrow y Lehr, 1990).
La dificultad para encontrar algoritmos de aprendizaje en redes multicapa se
resolvió, en dos líneas independientes, con el algoritmo de retropropagación de
Rumelhart, Hinton y Williams (1986) y con la máquina de Boltzmann de Hinton
y Sejnowski (1986), ambos publicados en un libro (Rumelhart y McClelland,
1986) que señala claramente el despegue actual de trabajos sobre el tema. La
aplicación "NetTalk" mencionada en el apartado 8.1 se describe en Sejnowski y
Rosemberg (1986).
Los primeros algoritmos genéticos los propuso Frieldberg (1958,1959): par-
tiendo de una colección de programas o de estructuras de datos en un momento
("población"), generaba mutaciones aleatoriamente sobre algunos de ellos, selec-
cionaba los mejores (basándose en algún criterio de "adaptación" dependiente de
la aplicación) y los recombinaba entre sí, obteniendo así la siguiente "generación",
sobre la que volvía a iniciar el proceso. Los resultados fueron decepcionantes,
como los posteriores de Fogel et al. (1966) (que acuñó la expresión "pro-
gramación evolutiva"): hacían falta millones de generaciones para conseguir algo
mínimamente alentador.4 Holland (1975) retomó la idea, pero con una variación
sustancial: la mutación no debe ser el único mecanismo, ni siquiera el fundamen-
tal; sólo se aplica esporádicamente, y se introducen otros operadores genéticos,
como el trueque de genes ("cross-over"). Tales operadores se aplican a cadenas
4
Los autores atribuyeron la causa del fracaso al uso del lenguaje de máquina y probaron mutaciones en el nivel
de organigrama; hoy, mejor conocida la problemática de la búsqueda, sabemos que la estrategia "ciega" de
"genera y comprueba" conduce a explosión combinatoria y al problema de los mínimos locales.
393
binarias en un sistema en el que las cadenas representan individuos que compiten
por "sobrevivir". Este nuevo enfoque ha demostrado su utilidad en diversas
aplicaciones de control y optimización.
Los primeros sistemas de algoritmos de aprendizaje siguiendo un enfoque
cognoscitivo se basaron en algunos modelos, pobres en formalización pero muy
ricos conceptualmente, propuestos dentro de la psicología en los años 60. A partir
del "CLS" (Concept Learning System) de Hunt et al. (1966), Quinlan formalizó e
implemento el primero y más conocido de los algoritmos de aprendizaje cognosci-
tivo, el "ID3" (Quinlan, 1979,1986), que ha servido de base para muchos sistemas
y aplicaciones. ID3 induce árboles de decisión a partir de ejemplos, y a resultados
similares llega AQ con un lenguaje de descripción sobre una lógica "0+" (Michal-
ski, 1975). La descripción de la aplicación basada en AQ para el diagnóstico de
enfermedades de la planta de la soja se encuentra en Michalski y Chilausky
(1980). Los sistemas de descubrimiento más conocidos son "BACON" de Lang-
ley et al. (1986), "AM" (Lenat, 1977) y "EURISKO" (Lenat, 1983), de los que
han derivado muchas investigaciones posteriores cuyas referencias pueden encon-
trarse en los libros que citamos más adelante.
Los distintos modelos que hemos mencionado se originaron de manera inde-
pendiente, pero más recientemente se han empezado a estudiar las relaciones entre
unos y otros y las posibilidades de utilizarlos de manera sinérgica. Así, se intro-
ducen funciones borrosas en redes neuronales (Kosko ,1991; Simpson, 1992,
1993) y en redes de Petri (Cao y Sanderson, 1995), se combinan algoritmos
genéticos y autómatas celulares (Mitchell et al., 1993), se aplican redes neuro-
nales al diseño de sistemas expertos ("sistemas expertos conexionistas": Gallant,
1988), se usan redes neuronales borrosas para la generación de reglas (Mitra y Pal,
1995), etc. Las referencias anteriores tienen un interés esencialmente histórico, y
las hemos incluido para dar una panorámica sobre la evolución de los modelos
tratados en este capítulo. Para estudiarlos con detalle recomendamos los si-
guientes libros:
Silva (1985) y Reisig (1985) tratan las redes de Petri y sus aplicaciones, Gupta
et al. (1977) los autómatas borrosos, y Narendra y Thathachar (1989) los autóma-
tas estocásticos y de aprendizaje. Aplicaciones de éstos (son especialmente
interesantes las que se refieren al encaminamiento adaptativo en redes de comu-
nicaciones) se describen en el capítulo 9 de este último libro, y en varios capítulos
del de Glorioso (1980). Los autómatas celulares y sus aplicaciones pueden
estudiarse en Wolfram (1986), Toffoli y Margolus (1987) y Gutowitz (1991).
En redes neuronales, la explosión de publicaciones desde 1986 ha sido tal que
resulta ya difícil seguir los avances. Es muy recomendable el libro de Anderson y
Rosenfeld (1988), que recopila las publicaciones pioneras más importantes. Un
tratado sistemático es el de Hertz et al. (1991) y un libro sobre sus aplicaciones a
sistemas expertos el de Gallant (1993). Una buena perspectiva puede conseguirse
con los artículos publicados en dos números monográficos del "Proceedings of the
I.E.E.E." (septiembre y octubre de 1990). El I.E.E.E. publica también un "Trans-
actions on Neural Networks" desde 1990, y desde 1988 Pergamon Press publica
"Neural Networks".
Sobre algoritmos genéticos hay menos literatura, pero también crece rápida-
mente. Están los libros de Goldberg (1989) y de Michalewicz (1992), los trabajos
de síntesis de Holland (1986) y DeJong (1990) y las actas de los congresos que se
celebran regularmente desde 1985: Grefenstette (1985, 1987), Schaffer (1989),
Belew y Booker (1991), Rawlings (1991) y Whitley (1992). El libro de Holland
et al. (1986) trata de inducción en general, pero presenta los algoritmos genéticos
tal como los introdujo modernamente Holland. Para una perspectiva sobre el tema
son recomendables los artículos de Srinivas y Patnaik (1994) y Ribeiro et al.
(1994).
Sobre psicología cognoscitiva (o "cognitiva", como prefieren los especialistas)
hay, naturalmente, multitud de textos. Nosotros hemos encontrado especialmente
útü y esclarecedor el de Vega (1985).
El libro de Soucek (1991) contiene una colección de trabajos sobre integración
de paradigmas (redes neuronales, algoritmos genéticos, sistemas borrosos, etc.)
para la construcción de sistemas inteligentes, y el de Gallant (1993) trata de
sistemas expertos conexionistas.
La "biblia" del aprendizaje en máquinas la forman cuatro volúmenes titulados
"Machine learning: an artificial intelligence approach" (Michalski et al., 1983,
1986; Kodratoff y Michalski, 1990; Michalski y Tecucci, 1994). En ellos pueden
encontrarse trabajos de síntesis escritos por los autores más conocidos de los
distintos enfoques del aprendizaje. El libro de Kodratoff (1988) cubre todos los
enfoques cognoscitivos utilizando fundamentalmente un lenguaje lógico, y el
compilado por Carbonell (1989) tiene un alcance más reducido, pero incluye
capítulos sobre redes neuronales y algoritmos genéticos. Un estudio teórico del
aprendizaje puede encontrarse en el libro de Osherson et al. (1986).5 Desde 1986
se publica la revista "Machine Learning" (Kluwer Academic Publishers,
Holanda). Sobre sistemas de descubrimiento en general trata el libro de Ziarko
(1994), y en cuanto a su aplicación en bases de datos, hay que acudir a las
recopilaciones de las comunicaciones presentadas a los congresos sobre el tema:
Piatetsky-Shapiro y Frawley (1991), Piatetsky-Shapiro (1993) y Fayyad y Uthu-
rusamy (1994).
!
Para hacerse una idea de su enfoque basta con esta frase del prefacio: "Tal como se desarrolla en este libro, la
teoría del aprendizaje una colección de teoremas sobre ciertos tipos de funciones de la teoría de números".
395
Parte III
Algoritmos
1
Ideas generales
1. Algoritmos y ordenadores
La palabra algoritmo procede del apellido latinizado de un matemático árabe,
Mohamed ibn Musa al-Khowárizmi (o al-Khárezmi) que en 828 y 825 d.C.
escribió respectivamente dos tratados, el primero de cálculo con los números hin-
dúes y el segundo de resolución de ecuaciones. La deformación del título de esta
última obra ha originado el nombre de álgebra, con el que se conoce a la rama de
las matemáticas consagrada al cálculo literal.
En nuestro siglo, no solamente se ha hecho más frecuente el uso del término
algoritmo, sino que su contenido, su significación precisa, ha sido explorado pro-
fundamente. En la técnica de los computadores es palabra de uso cotidiano, aun-
que es necesario advertir que no todos los profesionales de la informática la cono-
cen y emplean en su sentido cabal.
Lo cierto es que la aparición de los ordenadores con sus extraordinarias
posibilidades de proceso y almacenamiento de información ha impulsado fuerte-
mente el estudio de los algoritmos. Tanto es así, que a veces es difícil percibir que
399
pueden distinguirse dos campos de interés-, uno, de índole fundamental en mate-
máticas, en donde se plantea el problema de si tienen solución ciertos tipos de
problemas, lo que es equivalente a preguntarse si existe un algoritmo que conduz-
ca siempre a una solución para esa clase de problema. En el próximo capítulo se
abordarán las definiciones formales del concepto de algoritmo, pero por el mo-
mento podemos aceptar que un algoritmo es, intuitivamente, la expresión de una
secuencia precisa de operaciones que conduce a la resolución de un problema.
El otro campo de interés investiga o afronta los problemas que surgen de la
aplicación de las máquinas computadoras al procesamiento de algoritmos. En
este campo caen, entre otras, las relaciones de los algoritmos con las estructuras
de los datos y con los lenguajes de programación, y la complejidad computacional
(o algorítmica) es decir, la cantidad de recursos necesaria para computar determi-
nados problemas. El estudio de la complejidad algorítmica ha adquirido en las dos
últimas décadas un nivel teórico considerable.
Puesto que hablamos de resolver problemas, será bueno tener una idea general
de los principales aspectos implicados en dicha tarea. La resolución de un pro-
blema implica un proceso de varias etapas, que, a grandes rasgos, son las expresa-
das en el flujograma de la figura 1.1.
IF A = 0 THEN
ULTIMO: DO;
MCD = B; RETURN; END;
IF B = 0 THEN DO;
MCD = A; RETURN; END;
AQUI: G = A/B;
/*Suponiendo G variable entera*/
R = A - B * G;
IF R = 0 THEN GO TO ULTIMO;
A = B; B = R; GO TO AQUI;
401
Este mismo algoritmo, descrito en un lenguaje de máquina o en un lenguaje
ensamblador, sería mucho más largo y en cierta manera incomprensible para una
mente humana no entrenada. Si le aplicásemos un lenguaje impropiado como
DYNAMO, que es un lenguaje de simulación de sistemas continuos, la expresión
de este algoritmo podría hacerse prácticamente imposible o por lo menos extraor-
dinariamente enrevesada. En cambio, resultaría muy sencilla de escribir y de com-
prender si contásemos con una máquina capaz de entender y ejecutar la instruc-
ción CALL MAX ( ). Este programa consistiría simplemente en la sentencia
CALL MAX (A, B, MCD), que presupone la existencia de una máquina es-
pecializada, con dos entradas A y B para los dos números a procesar y una salida
MCD para el resultado.
Es evidente que no siempre se dispone de una máquina así y cuando se dispone
de ella no podríamos asegurar que tenga existencia física en la forma que sugiere
la figura 1.2. Se dispondría más bien de una máquina virtual que, en términos
generales, es el ordenador armado con un programa procesador de lenguaje de
unas determinadas potencia y funcionalidad. En tales circunstancias, el autor del
algoritmo puede desentenderse de las características de la máquina física y
expresarlo en un formato adecuado a las características funcionales de la má-
quina virtual, esto es, del lenguaje escogido. Esta idea puede tal vez expresarse
de otra manera diciendo que el lenguaje transforma el ordenador en una máquina
virtual.
MCD
Figura 1.2.
403
Además de desarrollar algunas cuestiones de importancia teórica relacionadas
con las máquinas de Turing y los algoritmos, habremos de enfatizar el análisis y
el diseño de estas máquinas como una vía hacia la comprensión de la complejidad
de la tarea de diseñar algoritmos cuando las máquinas virtuales son de muy bajo
nivel (en otras palabras, cuando los lenguajes son de muy bajo poder expresivo)
y de cómo, con un lenguaje tan elemental como el de la máquina de Turing, se
puede expresar cualquier algoritmo. En tal sentido, existe una relación de la má-
quina de Turing con la complejidad algorítmica. Se dedicarán los capítulos 5 y 6
y algún apartado del séptimo a todas estas cuestiones.
No acaba aquí el interés de la máquina de Turing. Tratándose de un autómata,
podría habérsela considerado en el tema "Autómatas". Sin embargo, su particular
relevancia le ha hecho merecedora de estos capítulos específicos. Por parecidas
razones, la relación de los autómatas con los lenguajes, brevemente abordada ya
en "Autómatas", será ampliada en el tema de "Lenguajes". Ciertos autómatas son
capaces de reconocer las cadenas de símbolos que constituyen el lenguaje gene-
rado por una determinada gramática. Las máquinas de Turing reconocen len-
guajes generados por sistemas de escritura no restringidos, a los que se llama
lenguajes de tipo 0. En el capítulo 6 encontraremos una breve consideración de
este punto, a la espera de sistematizarlo en "Lenguajes".
4. Computabilidad y complejidad
Hemos dicho que un problema computable (o decidible) es aquel que admite
solución algorítmica. En los problemas computables es interesante estimar el
orden de magnitud de los recursos computacionales que requieren los distintos
algoritmos que puedan resolverlos. La complejidad computacional es, en pocas
palabras, ese orden de magnitud. Así, un problema concreto podría necesitar 500
años de cómputo continuado, por lo que, siendo un problema computable, lo
consideraríamos un problema no factible, un problema de una complejidad in-
tratable.
Los recursos habituales para procesar algoritmos son: tiempo, capacidad de
memoria y velocidad de procesamiento. Por simplificar, fijémonos en el tiempo
que, además, depende en alguna proporción de los otros dos factores señalados.
Es evidente que, una vez fijado un algoritmo para un determinado problema, el
tiempo de cálculo necesario depende del tamaño de los datos del problema. Por
ejemplo, multiplicar dos números lleva más tiempo si éstos constan de 1.543 dí-
gitos cada uno que si sólo constan de 10, y lo mismo puede decirse si de lo que se
trata es de clasificar un conjunto de elementos: el tiempo es función del tamaño
de los datos. La búsqueda de expresiones matemáticas para la estimación del
tiempo de procesamiento de un algoritmo como función del tamaño de los datos
de entrada entra en el campo de competencia de la teoría de la complejidad, que,
entre otras actividades, evalúa por consiguiente el grado de factibilidad de los
404
problemas. De esta manera se llega a clasificar los algoritmos por la expresión de
su complejidad (comportamiento asintótico) en algoritmos de complejidad poli-
nómica y exponencial. Sobre tales cuestiones hablaremos en el capítulo 7.
El lector debe comprender que el estudio de la complejidad algorítmica, pese
a haber alcanzado un notable nivel teórico, no puede de ninguna manera ser
catalogado como un campo especulativo, puesto que se ocupa de cuestiones emi-
nentemente prácticas o proporciona herramientas para abordarlas. Imagínese un
caso como el siguiente: para controlar por computador un reactor nuclear resulta
vital conocer el máximo lapso con el que el algoritmo programado es capaz de
responder a ciertos supuestos de emergencia. O el caso de tener que elegir un
algoritmo cuya complejidad esté acotada entre un límite superior y uno inferior.
O el de tener que evaluar la ventaja obtenida entre procesar un algoritmo en un
ordenador de estructura secuencial o en otro de estructura paralela.
Otro tipo de complejidad, menos fundamental en sus implicaciones que el
anterior, aunque de considerable importancia práctica, es el de complejidad del
software. Le dedicaremos algún espacio en el mismo capítulo 7. En primera
aproximación, esta complejidad tiene que ver con la estructura de predicados del
programa construido para describir un determinado algoritmo. Cuanto más rica
sea esta estructura parece intuitivamente evidente que la tarea del programador
resulta más difícil, mayor su esfuerzo para desarrollarla y también mayor la
probabilidad de error, puesto que se acrecienta el número de caminos de proceso
que pueden tener que recorrer los datos tratados por el algoritmo. Existe un
vínculo de proporcionalidad entre el número de predicados y el número de dis-
criminaciones mentales del programador en su diseño y descripción del algoritmo.
La fiabilidad y el coste del software guardan una fuerte relación con la riqueza de
tal estructura.
Una forma de visualizar y hasta de medir esta complejidad consiste en asociar
a la estructura de control de los programas un grafo orientado. Tomemos el ejem-
plo sencillo del programa en PL/I para calcular el m.c.d. de dos números, visto en
el apartado 1.
La figura 1.4 es el grafo correspondiente a este programa, si suponemos que
cada uno de sus nodos representa un bloque de código con flujo de control se-
cuencial y los arcos representan ramas en el programa. No vamos a entrar en deta-
lles ahora. Con lo dicho, cualquiera puede comprender que la dificultad asociada
con el diseño y codificación de un programa ha de tener una relación con la mag-
nitud y enrevesamiento del grafo. Esta es a grandes rasgos la complejidad del soft-
ware. Al mismo tiempo se hace patente que dicha complejidad es función del nivel
de lenguaje, puesto que la instrucción CALL MAX ( ), que resuelve el mismo
problema, tiene un grafo absolutamente elemental.
405
o
5. Resumen y conclusiones
No es fácil de resumir este capítulo. El esquema conceptual de la figura 1.5
intenta plasmar una imagen incompleta e imperfecta de la íntima relación entre
algunos de los conceptos de que versa este libro, pero se pretende que sirva sobre
todo como un plano-guía para los siguientes capítulos de este tema.
El sentido de la flecha quiere significar algo parecido al sentido de una
navegación conceptual. Así pues, partiendo del concepto de algoritmo, nos vemos
conducidos al concepto de máquina ejecutora, bien sea un autómata, bien sea un
ordenador, y éste último es básicamente un conjunto de autómatas. Un autómata
muy especial, que resulta ser el ordenador universal, es la máquina de Turing, por
cuyo intermedio se construye una teoría formal de los algoritmos y se llega a los
conceptos de recursividad y computabilidad.
406
Algoritmos
I
Máquinas
Complejidad
Autómatas Ordenadores algorítmica
I
Máquinas virtuales
Máquina de Turing I
Lenguajes/estructuras
(ordenador universal)
I t
de datos
Computabilidad Recursividad
t
Programas W Problemas de fíabilidad,
costes y otros
f
Complejidad del
T Programación
Programación orientada a
software estructurada .
objetos
Figura 1.5.
407
un conjunto de técnicas ya clásicas para mejorar los resultados de la programación
secuencial. La programación estructurada es el modelo básico de lo que ahora se
conoce como programación imperativa tradicional. Existe otro modelo de pro-
gramación llamado programación declarativa, en el que se distinguen "dos esti-
los" principales, la programación funcional y la programación lógica (véase
capítulo 5 del tema "Lenguajes". Pero ciñéndonos ahora a la programación impe-
rativa, ésta ha visto desarrollarse un enfoque muy potente y de gran futuro, la
programación orientada a objetos (o programación mediante objetos).
Los mismos problemas han conducido a interesarse por definir y medir la
complejidad de los programas. Naturalmente, la complejidad del software tiene
relación con los algoritmos a través de la programación, del lenguaje y del nivel
de máquina virtual disponible en el ordenador (siguiendo el esquema en sentido
inverso), pero no tiene en principio una relación directa con el concepto de com-
plejidad algorítmica. Para muchos autores, esta última complejidad constituye una
parcela importante de la teoría de la programación, aunque otros le dan un carácter
todavía más básico. En cambio, la complejidad del software es indiscutiblemente
un aspecto práctico, metodológico, de la programación.
Un detalle final aparentemente anecdótico, pero que puede dar una cierta
medida de la importancia informática atribuida a los conceptos aquí esbozados es
que la contribución a su estudio ha proporcionado el premio Turing a varios
investigadores, a saber: Knuth (algoritmos, estructura de datos), Dijkstra (teoría
de la programación), Wirth (lenguajes), Hoare (algoritmos, teoría de la progra-
mación) y Cook (complejidad algorítmica).
El premio Turing del año 1985 se entregó a Karp por sus trabajos sobre com-
plejidad en problemas de tipo combinatorio.
2
Algoritmos
1. Introducción
El presente capítulo se dedica básicamente a definir el concepto de algoritmo.
Primero empieza con unas definiciones diversas y no totalmente coincidentes, que
se contrastarán. Se pasará a continuación a una definición formal en teoría de
conjuntos, que comprende y precisa todas las anteriores.
De la definición se extraen unas propiedades o condiciones que debe cumplir
todo algoritmo, a las que se añaden propiedades que se puede desear que cumplan
los "buenos algoritmos".
El capítulo prepara ya el terreno para hablar de programas y de máquinas,
destacando en la definición formal aquellos elementos, como el número de orden
de una ejecución y la existencia misma de los estados, que prefiguran la existencia
de determinadas condiciones generales en cualquier máquina ejecutora de algo-
ritmos.
2. Definiciones de algoritmo
No hay una, sino muchas definiciones de algoritmo. Aquí recuadramos varias
de distintos autores, todas (¡y no es casualidad!) tomadas de libros sobre computa-
ción o computadores.
411
Definiciones de algoritmo
Lo primero que sorprende es que las definiciones difieren no poco entre sí,
aunque tal vez sólo sean las apariencias. Esto deja ya suponer que no son muy
precisas. Pero fijémonos en las semejanzas y no en las diferencias.
412
La amplitud del campo de los problemas es tan grandiosa que cualquiera
percibe la dificultad de aprehender la noción de algoritmo si uno se sitúa en medio
de la diversidad de los problemas y la diversidad de los agentes ejecutores. Es
obligatorio reducir el ámbito de atención e investigar el asunto como un proceso
intelectual independiente del problema específico, por una parte. De ahí se des-
prende que, si bien hay algoritmos numéricos y no numéricos, en última instancia
todos pueden reducirse a la especificación de operaciones sobre símbolos. Y por
otra, es obligatorio independizarse en lo posible del agente ejecutor de estas
operaciones simbólicas y, para ello, una solución ha consistido en definir un
agente ejecutor único (veremos que será la máquina de Turing), al cual podrían
reducirse en última instancia todos los demás.
3. Algoritmos y máquinas
Fijémonos ahora en la ejecución del procedimiento o algoritmo, con indepen-
dencia del problema y de la máquina de que se trate, para lo cual daremos unas
definiciones más formales que en el apartado anterior.
A = (Q,E,S,F) (1)
con
Q: Conjunto de todos los elementos simples y de todas las K-uplas que pueden
describir el cálculo.
E: Subconjunto de Q. Sus elementos son los datos de entrada al proceso de
cálculo.
S: Subconjunto de Q. Sus elementos son los diferentes resultados al término
del cálculo.
F: Q —» <2, aplicación que describe la regla de cálculo propiamente dicha y
que, a partir de cualquier elemento q0, genera la construcción de una
sucesión qQ, qu q2... tal que:
Para que A represente un algoritmo, cada sucesión (2) debe ser finita. Así
pues, es preciso, como condición necesaria no suficiente, que la función F deje
invariante el subconjunto S; es decir: Vs 6 S, F(s) = s. Si la sucesión es finita, su
413
punto de parada viene dado por el menor índice y para el que q¡ e S. No será
finita si e N; F(qJ e S.
Ejemplo: Cálculo del m.c.d. de dos números enteros no negativos nxy n2. El
organigrama de la figura 2.1 expresa un procedimiento conocido para resolver
este problema. (P.E. significa "parte entera" de dividir n por ri).
Este algoritmo que se expresa en la figura 2.1 en una forma, en parte icónica
(diagrama), en parte formal (expresiones matemáticas), puede representarse a
través del lenguaje de los conjuntos así:
Q : (<n>, <n, rí>, <n, n',r, 1>, <n,p, r, 2>, <p, n'r, 3>), n, n',p, r e N
E :(<n, rí>)
S : (<n>)
F :F(nx,n2) = {nv nv 0,1) si ní> nv si no F(nv n2) = (n2, nv 0,1);
F(n) = («);
F (n, n', r, 1) = (n) si n' = 0, si no
F (n, n', r, 1) = (n, n', n - n' xP.E.(n/n'), 2;
F(n,p,r,2) = (p, p, r,3);
F(p, n, r,3) = (p, r, r, 1);
El signo; separa las distintas variantes de la regla de cálculo que el lector puede
usar para hallar la sucesión q0, ...q¡, ... partiendo de cualquier pareja de números
enteros no negativos, familiarizándose así con la definición que se acaba de dar.
Por cierto que dicha definición habría que perfeccionarla en el sentido de que la
aplicación F no implique operaciones que no sepa realizar. En definitiva, las
restricciones que habría que imponer a Q, E, S y F son de naturaleza tal que la
cuádrupla A no contenga más que operaciones elementales simples (repare el
lector en la relatividad del argumento de simplicidad, siendo la operación más
simple la que pueda ejecutar un autómata).
Un ejemplo como el del cálculo del m.c.d. pone de manifiesto, mediante el
empleo de lo números 1,2,3, etc., la idea de que una aplicación o un cálculo es
una secuencia de aplicaciones o cálculos más elementales y que tal secuencia
puede expresarse mediante un número asignado a las órdenes que deben eje-
cutarse. De forma general, podría decirse que el estado del algoritmo es un par (a,
j), donde j indica el número de la orden que debe ejecutarse y a es la información
que caracteriza el estado del algoritmo cuando hay que ejecutar la orden j
(información que comprende combinaciones de datos, resultados intermedios y
resultados finales). Así, a cada evaluación de la aplicación F(q¡) = F(a¡, k) =
(ai+1, l) se le puede llamar ejecución de la orden k del algoritmo. El conjunto S
incluiría la información correspondiente a los resultados finales y el conjunto E,
la información de los datos de entrada.
414
Figura 3.10.
415
El concepto de algoritmo puede examinarse formalmente también en relación
con un alfabeto y en términos de una máquina de Turing, cosa esta última que
haremos más adelante. De momento, veamos más de cerca y en forma intuitiva
las implicaciones de los algoritmos sobre las máquinas.
ENTRADA
Subsistema de Subsistema de
E/S proceso
SALIDA
Figura 2.2.
416
que los subsistemas podrán llevar asociados elementos de memoria (asociados
siempre, como se sabe, a todo circuito secuencial) para memorizar las informa-
ciones de estado que corresponden a la misión de cada subsistema.
Figura 2.3.
417
4.3. Propiedad de generalidad
Un algoritmo no debe contentarse con resolver un problema particular aislado
sino, por el contrario, toda una clase de problemas para los que los datos de
entrada y los resultados finales pertenecen respectivamente a conjuntos espe-
cíficos.
418
1
ann + an_1x" + ... axx + a0 = O
419
Podemos formar una sucesión de 011010001001 101110110011
ceros y unos que tenga "descen- 01000100100 1101100111101
dencia" mediante las siguientes 0010010000 11001111011101
reglas: 001000000 011110111011101
1. Si la sucesión tiene menos de tres 00000000 11011101110100
símbolos, parar 0000000 111011101001101
2. Si la sucesión comienza por 0, 000000 0111010011011101
borrar los tres primeros símbolos y 00000 101001101110100
añadir 00 al final. 0000 0011011101001101
3. Si la sucesión comienza por 1, 000 10110100110100
borrar los tres primeros símbolos y 00 1101001101001101
añadir 1101 al final.
¿Hay un algoritmo para determinar (parar) (descendencia con-
si una de las dos sucesiones dadas tinua)
es descendiente de la otra?
6. Resumen
Para empezar se han definido verbalmente los algoritmos como un conjunto o
lista de reglas, instrucciones o prescripciones que especifican a un agente ejecutor
una secuencia finita de operaciones para la resolución de un problema. El proble-
ma ha de ser lo más general que sea posible, aunque esta condición es siempre
bastante relativa.
Cuando se pretende resolver un problema, se desarrolla un proceso de varias
etapas en las que normalmente unas son más próximas a la estructura propia del
problema (etapas de análisis y de formulación de un procedimiento de solución)
y otras más decantadas del lado de las capacidades operativas del (o de los) agente
ejecutor (en muchas ocasiones, una máquina y modernamente casi siempre un
computador, al menos en nuestro caso). Este proceso resulta tanto más largo o
complejo cuanto mayor sea la distancia entre la complejidad del problema y la
capacidad operativa del agente ejecutor disponible.
Si se hace caso omiso de este último factor, puede plantearse una definición
formal de algoritmo como una cuádrupla A = <Q, E, S, F>, donde la regla de
cálculo F:Q —> Q lleva al algoritmo desde un estado inicial ( e E) a un estado
420
final ( e S) en un número finito de pasos, supuesto que se sepa realizar F con
todos los elementos de Q.
Pensando ahora precisamente en términos del factor anteriormente descartado,
vemos que el uso y el concepto de estado del algoritmo, en donde puede dis-
tinguirse un número de orden de ejecución, lleva a concebir un agente ejecutor-
máquina como una estructura con tres o cuatro subsistemas (entrada/salida, pro-
ceso, control y memoria).
No se tiene un algoritmo si el procedimiento elaborado no cumple las con-
diciones de finitud y definitud, a las que pueden añadirse, si se quiere hablar de
"buenos algoritmos", las de generalidad y eficacia, relacionadas con el grado de
ambición o de optimización con que se enfoque la resolución de un problema.
De todas formas hay problemas que no tienen solucion o, al menos, solución
conocida. Esta última parte del capítulo nos muestra cómo el grado de generalidad
de un algoritmo tiene unos límites y nos pone delante de temas fundamentales de
las matemáticas modernas.
421
3
Programación
estructurada
1. Introducción
La programación estructurada surgió en la década de los sesenta como reac-
ción contra los problemas que para entonces comenzaban a plagar el desarrollo de
software, relacionados primordialmente con la falta de fiabilidad de los progra-
mas, cuya complejidad iba creciendo considerablemente. El software de sis-
temas, por ejemplo (sistema operativo, compiladores, etc), es especialmente com-
plicado, y cualquier fallo conduce a consecuencias, cuando menos desagrada-
bles, en muchos casos catastróficas.
Tras imponerse en la década de los setenta, la programación estructurada
puede considerarse hoy como un estilo enteramente clásico. Los lenguajes de pro-
gramación imperativos más utilizados en los últimos años (Pascal, C, Ada) están
diseñados de manera que se favorece esta forma de programar, convirtiéndola en
algo natural, mientras se desaconseja con énfasis el uso de instrucciones no estruc-
turadas, especialmente GOTO.
423
En un libro como éste no puede faltar un capítulo sobre la programación
estructurada, que abarca, en forma muy sumaria, desde aspectos formales básicos
sobre programas en general y programas estructurados, hasta cuestiones prácticas
sobre diseño y ejemplos de estructuras complementarias facilitadas por lenguajes
hoy tan comunes como Pascal y C.
P= <X,x0,Y,f>
donde
- g : E en x 0
- h : Xsobre Q, tal que h(Y)= S
- r : X en N
tales que
424
- Si xg X, entonces F (h(x)) = h (/* r(x)) , donde la notación f* r(x)
significa que la función f debe ser iterada r (x) veces.
f:E-*E
=
P { f v f l ' f v •••j/n}
9 , = / - ( - / 3 (ACA ( 9 o ) ) ) ) •••)
El valor qn obtenido se llama estado final de la ejecución.
Se llama función del programa [P] a:
425
Figura 3.1.
426
donde p : E -> {True, False} ({cierto, falso}) es un predicado que se aplica a un
estado y toma el valor True o el valor False. Supondremos que el arco superior o
el de la derecha (si el nodo se dibuja verticalmente) corresponde a True, y el infe-
rior o izquierda corresponde a False. (Nota: a veces, en la práctica, se invierte este
convenio).
Nodo de función
Nodo de predicado
(expresión lógica o condición)
Nodo de agrupamiento
Figura 3.2.
427
Figura 3.3.
BLOCK(f,g,...,h)(q) = h(...(g(f(q)))).
IFTHENELSE(p,f,g)(q) = Si p, f(q), si , g(q).
428
Expresión
Figura 3.4.
IFTHEN(p,f)(q) = Si p, f(q), si - , p , q.
DOWHILE(p,f)(q) = Si p, DOWHILE(p,f)(f(q)), si , q.
DOUNTIL(p,f)(q) = Sip, DOUNTIL(p,f)(f(q)), si - p , f(q).
BLOCK(f,g,h) = BLOCK(f,BLOCK(g,h))
La función identidad.
Cálculos de P.
Un subprograma limpio de P, también estructurado.
429
Figura 3.5.
430
TOP: Aplicado a un conjunto de datos al que se ha añadido un valor lógico,
su resultado es dicho valor lógico. Es decir, TOP(a,b) = b, donde b es
un valor lógico ("true" o "false").
Figura 3.6.
Figura 3.10.
431
equivalente a él. Obsérvese que al comienzo de la ejecución se realiza la secuencia
de sentencias (TRUE;TOP;POP;p), por lo que la función p tiene como dominio el
mismo conjunto de datos de partida que el programa original. En el ramal donde
se encuentra la función f marcamos uno de los arcos con TRUE y el otro con
FALSE para poder encaminar de nuevo la ejecución hacia el predicado p o hacia
la salida del programa. El ramal inferior (el de la secuencia (s;g) se marca con
FALSE para abandonar la ejecución la próxima vez que se pase por el predicado
TOP.
Este organigrama puede describirse mediante la siguiente fórmula o función
de programa:
432
(bloques básicos del diseño), brecha que es necesario salvar. Uno de las maneras
posibles para resolver este problema (veremos otra posibilidad en el capítulo
siguiente) consiste en descomponer las acciones complejas en otras acciones más
simples (recursos abstractos, según Dijkstra) concebidas como instrucciones para
una supermáquina (inexistente) capaz de poder ejecutarlas. Como es natural, una
vez que hayamos descompuesto el problema de esta manera, tendremos que
procesar esas superinstrucciones, que se convertirán de esta forma en subobje-
tivos, y para ello podemos aplicar recursivamente el mismo método. Esta manera
de concebir los programas no es exclusiva de la programación estructurada, pues
se aplica igualmente en ciertas formas de la programación modular. En nuestro
caso, sin embargo, hay que recordar que la descomposición en superinstrucciones
debe corresponderse con las estructuras básicas de las que hemos hablado en
apartados precedentes. Por lo tanto, el razonamiento utilizado para el diseño debe
guiarse por la decisión de utilizar siempre esas estructuras básicas en cada uno de
los pasos sucesivos, como veremos a continuación.
433
NIVEL N NIVEL N + 1
•
Punto de vista Punto de vista
exterior interior
Figura 3.8.
435
436
i
DIA = 01
\ 1
437
Figura 3.10.
438
Además de las estructuras básicas, ya detalladas en la figura 3.4, ambos
lenguajes permiten utilizar otras, que definiremos a continuación.
En Pascal:
begin
f;g;...;h
end
EnC:
{f;g;...;h}
En Pascal:
f o r N : = l t o 10 do f ;
EnC:
439
ma cierto número de IFTHENELSE consecutivos cuyos predicados respectivos
son comparaciones de valor de una variable con dos o más constantes. Veamos
un ejemplo en Pascal y C:
En Pascal:
case N of
1: X =3;
3: X = 7;
5: X =2;
else X:=5
end
EnC:
s w i t c h (N) {
c a s e 1: X=3; b r e a k ;
c a s e 3: X=7; b r e a k ;
c a s e 5: X=2; b r e a k ;
default: X=5; b r e a k ;
}
440
efecto, si la fórmula de un programa emplea sólo las estructuras básicas, pue-
de probarse si es correcto o no mediante un censo de todos los nodos del gra-
fo. Dejamos sugerida esta cuestión, de gran complejidad teórica, que se sale
del objetivo de este libro.
7. Resumen
Se ha definido un programa como la representación de un algoritmo. Análo-
gamente, un organigrama (u ordinograma o diagrama de flujo) es un grafo que
representa un programa.
Se ha visto que el organigrama de cualquier programa puede construirse con
sólo tres tipos de nodos: de función, de predicado y de agrupamiento. Además,
cualquier programa puede sustituirse por otro equivalente (en cuanto a la función
que realiza) cuyo organigrama está construido con sólo tres tipos de estructuras
o diagramas simples: concatenación, alternativa y repetitiva. Estas tres estructu-
ras simples tienen una entrada y una salida única. Un programa está estructurado
cuando su organigrama está formado únicamente por las tres estructuras simples,
o por otras, igualmente simples, derivadas de ellas.
Si un programa es limpio, pero no estructurado, es posible construir un pro-
grama estructurado equivalente, sin distorsionar demasiado la estructura original,
añadiendo tres funciones (TRUE, FALSE, POP) y un predicado (TOP) que
amplían el conjunto de estados introduciendo variables lógicas binarias.
El método general de diseño de programas estructurados se resume en el es-
quema conceptual de la figura 3.11 sin necesidad de mayores palabras.
t
RAZONAMIENTO DEDUCTIVO
(sin olvidar la lógica)
±
•
ESTRUCTURAS BASICAS
I
?
RECURSO ABSTRACTO
Figura 3.10.
441
8. Notas histórica y bibliográfica
En 1966, Bóhm y Jacopini pusieron las primeras piedras de la teoría de la
programación estructurada, partiendo de los diagramas o estructuras básicas in-
dispensables en un lenguaje de programación. Otras aportaciones teóricas en este
campo se deben a Dijkstra, Hoare, Wirth y Mills (Mills, 1975). Es notable el libro
de Dahl, Dijkstra y Hoare (1972). Otras obras interesantes corresponden a Manna
(1974), Dijkstra (1976) y Alagic y Arbib (1978).
Más al alcance de los programadores profesionales, es de notar el impacto
causado por un número de la revista Datamation (1973), que dedicó varios ar-
tículos a este tema con el título genérico de "Revolución en la Programación".
No se pretende que estas referencias constituyan siquiera un conjunto mínimo
básico. Sólo estudiando una obra colectiva preparada por distintos especialistas
puede uno hacerse una idea de conjunto. Merece la pena citar un estudio panorá-
mico en español, editado por Gamella (1985).
En este capítulo, el teorema de estructura del subapartado 3.3 se tomó de
Tabourier et al. (1975), referencia utilizada asimismo en varios pasajes del ca-
pítulo.
En cuanto al método de diseño de programas estructurados, se debe a Dijkstra
(en Dahl et al., 1972). Se trata de un método muy general, utilizable en toda
circunstancia. Sin embargo, motivos prácticos han aconsejado el desarrollo de
procedimientos dirigidos a cierta clase de problemas, como los de Yourdon,
Linger y Mills (EE.UU., véase Yourdon, 1975), Jackson (G.B., 1975), Warmer y
Bertini (véase Warnier, 1973). Sáez Vacas (1976) ha estudiado algunos de estos
métodos y su relación con los fundamentos científicos de la P.E.
El ejemplo de simulación de un reloj digital lo hemos adaptado de Arbib
(1977).
Para ampliar la programación estructurada en Pascal o en C pueden utilizarse
los dos textos clásicos de los autores de estos lenguajes: Kernighan y Ritchie
(1978) y Wirth (1980), o bien libros más moderaos, como Kelley y Pohl (1987),
Gottfried (1993), Joyanes (1990) o Salmon (1993). Sobre programación en
general, puede verse Cerrada y Collado (1993), que emplea el lenguaje Modula-2.
9. Ejercicios
9.1. Dado el grafo adjunto, indicar cuál de las siguiente opciones se
corresponde con la fórmula de programación estructurada que define
los mismos cálculos.
a) BLOCK ( f , DOWHILE (p, -,q, g))
b) BLOCK ( f , IFTHEN (p, DOUNTIL (q, g)))
442
c) BLOCK ( f , DOWHILE (p, DOUNTIL (q, g)))
d) BLOCK ( f , IFTHEN (p, IFTHEN -,q} g))
443
9.3. Obtener la fórmula correspondiente al siguiente grafo estructurado:
444
4
Evolución de la
programación
1. Introducción
En este capítulo profundizamos en las metodologías de análisis y diseño
apuntadas en el capítulo anterior al hablar de recursos abstractos. Se discute tam-
bién cómo se puede asegurar que el programa desarrollado para plasmar un algo-
ritmo es correcto (no contiene fallos) o, en caso de contenerlos, es robusto (los
detecta y actúa ante ellos de forma ordenada).
Actualmente, la orientación a objetos se ha convertido en una de las meto-
dologías de análisis, diseño y programación más extendidas. Por ello, su descrip-
ción somera no podía faltar en este libro, aunque no sea éste el lugar adecuado
para entrar a fondo en la cuestión. Para compensar un tratamiento tan sucinto, el
capítulo termina con unas "Notas" relativamente amplias, dirigidas a los lectores
más interesados.
447
2. Cómo se construye un programa
A principios de los años ochenta se llegó a establecer una metodología, que
podríamos llamar estándar, para el desarrollo de aplicaciones de programación.
Esta metodología, que no es más que una generalización, aplicada a la infor-
mática, de la que mencionamos al referirnos a la resolución de problemas en el
capítulo 1 (figura 1.1), tiene el aspecto que indica la figura 4.1.
Análisis
Diseño
| Codificación
| Pruebas
I Mantenimiento
Figura 4.1.
• Diseño: en esta etapa, lo que hay que definir es cómo vamos a hacerlo. Entre
todas las formas posibles de resolver el problema, se trata de elegir la más
simple, o la más barata, o la más eficiente, o la que mejor se adapte a los re-
quisitos del análisis.
• Codificación: una vez sabemos lo que hay que hacer, y cómo hacerlo, ha
llegado el momento de la verdad: hay que ponerse a programar y construir la
aplicación. Esta es, normalmente, la parte más larga del proceso y la que
consume más recursos.
Pruebas: no basta con que el programa esté terminado, hay que asegurarse de
que funciona perfectamente, no sólo en un caso, sino en todos. Un buen di-
seño de pruebas es esencial para esto. Otra alternativa podría ser la compro-
bación automática de programas.(Tema "Lenguajes", cap. 5, apartado 4.1)
448
corregir los problemas que puedan ir surgiendo, y para ello es esencial que
el programa esté muy bien documentado. Además, puede que sea necesarió
volver de nuevo a las fases de análisis y diseño, para corregir, mejorar o
adecuar la aplicación, ya sea porque vamos a construir una segunda versión,
o simplemente para responder a cambios en las condiciones de contorno de
la aplicación a lo largo de su vida útil.
Diálogo
Especificaciones
Descomposición funcional
Definición de abstracciones
Codificación
Pruebas/verificación
Presentación
Figura 4.2.
449
• Etapa 3: descomposición funcional. Es la división sistemática del proceso en
una serie de pasos diferentes entre sí. Una vez realizada, la descomposición
puede aplicarse de nuevo a cada uno de los pasos obtenidos, reduciendo
progresivamente su grado de complejidad hasta que llegue a ser manejable.
En esencia, esta etapa ha sido descrita en el capítulo 3, en relación con el
diseño descendente de programas estructurados.
• Etapa 4: definición de las abstracciones. Esta es la última subíase del diseño,
en la que se decide cómo construir cada una de los pasos obtenidos en la etapa
precedente. Este es el lugar adecuado para reutilizar código (si ya hemos
tenido que realizar alguna de las operaciones en aplicaciones anteriores) o
para decidir si un paso debe construirse como subrutina (si hay posibilidades
de usarlo en varios sitios diferentes, ya sea en esta misma aplicación o en otras
que puedan venir después), o como código embebido (en caso contrario).
• Etapa 5: codificación.
• Etapa 6: pruebas y verificación. Estas dos etapas son idénticas a la tercera y
la cuarta de la metodología en cascada.
• Etapa 7: presentación. Tiene por objeto facilitar el mantenimiento del pro-
grama, producto o aplicación construido, añadiendo información sobre quién
lo ha construido, en qué fechas, y de qué manera, especificando además qué
rutinas de las utilizadas por el programa podrían utilizarse en otros entornos
y de qué manera.
La descomposición funcional no es la única metodología de diseño existente.
Hay otras, entre las que destacan las siguientes:
El modelo entidad-relación (E-R), que trata de definir las componentes prin-
cipales de la aplicación y las relaciones que existen entre ellas, por medio de
una red semántica (Tema "Lógica", cap. 6, apartado 4) como la de la figura 4.3.
Figura 4.10.
450
• El diagrama de flujo de datos (DFD), que describe el camino que recorren los
datos en un sistema o aplicación, dónde se almacenan, de dónde vienen y
adonde van. La figura 4.4 muestra un ejemplo autoexplicativo.
Figura 4.4.
451
¿Qué ocurre cuando, a pesar de nuestros esfuerzos, se nos ha escapado algún
error? El programa podría reaccionar ante esta situación de maneras muy dife-
rentes:
Figura 4.5. a)
Figura 4.5. b)
/* Algoritmo a realizar:
f(a)^longitud de la cadena de caracteres a */
unsigned short longitud (char *a) {
unsigned short b=0;
for (;a[0]!=1\01;a++) b++;
return b;
}
Figura 4.5. c)
453
3 para construir un programa que simula un reloj digital. Descompusimos el
proceso completo en fases más simples, cada una de las cuales representa una
función concreta y viene definida por un verbo de acción: "Lee datos", "Imprime
hora", "Inicia oscilador", etcétera. De hecho, el procedimiento de diseño des-
cendente mencionado más arriba (la descomposición funcional) tiene como
resultado usual un conjunto de verbos.
Sin embargo, la mente humana evolucionada no funciona así: el verbo no es,
normalmente, el elemento primario de nuestra percepción. Hay algo más
importante y básico: el nombre sustantivo. Lo primero que nos llama la atención
cuando entramos en contacto con el mundo es la multitud de los seres, los objetos.
No vemos en primer lugar acciones, sino cosas que actúan o permanecen inertes.
Si un insecto pasa volando por nuestro campo de visión, no pensamos "algo
vuela", sino "una mosca": el nombre va antes que el verbo, y no sólo sintác-
ticamente. Esto tiene la consecuencia de que nuestras clasificaciones siempre se
basan en los nombres, los objetos, nunca en los verbos. Dividimos los animales
según sus propiedades físicas (vertebrados o invertebrados, según tengan o no
columna vertebral), no según su comportamiento: no se nos ocurre construir el
grupo de los que "se arrastran" o de los que "corren".
Entre paréntesis, es sugerente el paralelismo entre la evolución de los modelos
de la programación y la del lenguaje humano. Los pueblos primitivos se las arre-
glan con pocas palabras, casi todas verbos en modo imperativo. Los algonquinos
preagrícolas del norte de América poseen ya un vocabulario total de unas 4.500
palabras, con un 53% de verbos y un 32% de nombres. Finalmente, el inglés
moderno contiene alrededor de un 10% de verbos sobre un total de unas 150.000
palabras.
Como hemos comentado anteriormente, la programación tradicional se basa
principalmente en los verbos, y que éste no es exactamente el método natural. ¿No
podríamos cambiar de modo de pensar y pasar a una forma de programar basada
en los nombres? La respuesta a esta pregunta resulta ser afirmativa. Desde finales
de los ochenta ha comenzado a extenderse una metodología alternativa, la
programación orientada a objetos (OOP, por las siglas inglesas de Object-
Oriented Programming). En esta forma de programar, el elemento fundamental
no es la acción, sino el objeto, del mismo modo que en las representaciones
estructuradas del conocimiento (Tema "Lógica", cap.6 ap. 4). Además, diversos
objetos se relacionan entre sí de varias maneras:
Diálogo Mensaje
Figura 4.6.
• Sus propiedades o atributos (datos asociados al objeto), con sus valores aso-
ciados. Del mismo modo que los objetos corresponden a los nombres sustan-
tivos, los valores de sus atributos vienen a desempeñar el papel de los adjeti-
vos. Recuérdese que los números son adjetivos numerales, y que otros valo-
res típicos, como los colores (verde, rojo, etc.) son adjetivos calificativos.
455
Su comportamiento o funcionalidad (programas asociados al objeto), con su
código asociado. En la terminología OOP, los programas se llaman métodos.
Como hemos dicho, corresponden a los verbos de nuestro vocabulario. Los
mensajes OOP dirigidos a un objeto son indicaciones para que ejecute uno de
sus métodos. El código de cada método ejecuta o realiza un algoritmo,
entendiendo este término en el sentido en que se ha utilizado en los capítulos
anteriores. La figura 4.7 resume estos conceptos.
Figura 4.7.
- Herencia simple, si un objeto sólo puede pertenecer a una clase, y cada clase
sólo puede ser subclase de una sola superclase.
- Herencia múltiple, si un objeto puede pertenecer a dos clases, o cada clase
puede ser subclase de más de una superclase.
456
Todos los sistemas y lenguajes OOP tienen herencia simple, pero sólo algunos
incorporan la múltiple, que por otra parte no es difícil de simular en función de la
simple. Además de los conceptos anteriores, hay otros tres que desempeñan un
papel fundamental en la programación orientada a objetos:
• Encapsulamiento: significa que la información interna de un objeto (los
valores de sus atributos) debe estar protegida contra la manipulación directa
por parte de otros objetos. Sólo podrá accederse a ella enviándole un mensaje
para que ejecute un método. Esta propiedad es muy útil, pues protege a las
aplicaciones contra efectos secundarios indeseados, causa frecuente de
errores muy difíciles de detectar.
El encapsulamiento nos permite representar los objetos como un huevo de
cáscara compacta, que sólo permite el acceso desde el exterior a través de sus rela-
ciones con otros objetos y de su comportamiento (métodos). El interior del huevo
se divide en dos secciones (equivalentes a la clara y la yema) y cada una de ellas,
a su vez, en otras tres, que son las componentes generales de un objeto que hemos
457
concreto debe ejecutarse hasta el instante mismo de la ejecución del
programa (no podrá resolverse la cuestión en tiempo de compilación).
• Es trivial extender las aplicaciones, pues basta con añadir clases nuevas a la
jerarquía, subclasificar las existentes, crear objetos nuevos o dotarles de pro-
piedades y comportamientos adicionales.
^ Ensamblaje de la
^ ^ aplicación
Figura 4.9.
459
El diseño orientado a objetos (OOD) tiene que realizar el diseño en pro-
fundidad de cada una de las clases detectadas por el análisis, que incluye el diseño
de las estructuras de datos y los métodos (programas) que van a implementar los
atributos y el comportamiento de los objetos, así como la identificación de los
errores que pueden producirse y la forma de subsanarlos. También le corresponde
la identificación y definición de clases de objetos no relacionadas directamente
con la resolución del problema, sino con cuestiones de programación, como la
interfaz de usuario, la base de datos a utilizar, el soporte de las relaciones entre
los diversos objetos, y otras cuestiones básicas y de utilidad.
El diseño orientado a objetos es eminentemente modular, pues ha de conseguir
la definición de clases con poco acoplamiento externo, pero con una gran cohesión
interna y un mínimo de efectos laterales. Evidentemente, al realizar el diseño debe
tenerse en cuenta y aprovechar convenientemente la herencia, definiendo cada
método o cada propiedad lo más arriba posible en la jerarquía de clases, para
minimizar la redundancia. Además, el diseño debe ser muy general, para asegurar
la reutilización futura de las clases diseñadas, haciendo abstracción en lo posible
de las particularidades específicas de la aplicación que se desea construir.
Desde el punto de vista del diseñador de clases, el objetivo fundamental es
crear clases cuya interfaz sea clara y comprensible, sin dejar traslucir el menor
detalle de la implementación concreta que hay debajo (encapsulamiento), lo que
le permitirá en el futuro cambiar las estructuras de datos y los algoritmos sin
afectar en lo más mínimo a las aplicaciones que estaban utilizando la versión
anterior de la clase. Todo esto, naturalmente, tiene un coste: el esfuerzo necesario
para asegurar que las clases sean reutilizables.
Desde el punto de vista del programador que va a utilizar una clase para construir
su aplicación, pero que no va a diseñarla, el objetivo fundamental es hacer uso de
ella con el mínimo esfuerzo, para lo que espera que la interfaz proporcionada por
el diseñador sea comprensible y se adapte a sus necesidades. También esto tiene
un coste: la pérdida de eficiencia consiguiente al uso de una herramienta
generalizada, en lugar de la programación ad hoc.
Durante el diseño de una clase concreta, hay que identificar y especificar sus
atributos y sus métodos. Para los primeros, conviene tener en cuenta las siguientes
consideraciones:
• Cada atributo tendrá un tipo, que puede ser uno de los siguientes:
• Atómico predefinido (numérico entero o real, carácter, cadena de
caracteres, pixel, etc.)
• Atómico enumerativo (color, día de la semana, etc.)
• Colección (conjunto, lista, etc.)
• Composición (incluye referencias a otros objetos).
• Estructura compleja (formada por combinación de dos o más de los tipos
anteriores).
De igual manera se procederá con los métodos, los programas que utilizan o
modifican los atributos, cuyo conjunto define el comportamiento de la clase y que
se desencadenan por medio de un mensaje. Al diseñarlos, conviene tener en
cuenta lo siguiente:
• El conjunto de los métodos de una clase debe ser:
• Completo (deben realizar toda la funcionalidad de la clase).
• General (cada método debe aplicarse a todos y cada uno de los objetos de
la clase).
• Diferenciado (cada método debe ser simple y realizar una sola función).
461
• Ventanas.
• Barras de acción.
• Menús de selección.
• Paneles de diálogo.
• Textos fijos.
• Campos de entrada de datos alfabéticos.
• Menús de selección.
• Ventanas de presentación de datos.
Metodología Autor(es)
(ver ref.bibliográf.)
Figura 4.10.
462
Se observará que algunos de los objetos de la segunda lista aparecen ya en la
lista anterior. Otros pueden considerarse casos particulares o subconjuntos de
aquellos. Por ejemplo, un campo de entrada de datos alfabéticos es un tipo espe-
cial de ventana que permite escribir texto.
La segunda cuestión que hay que resolver, una vez tenemos claro con qué
objetos vamos a movernos, es la construcción de la jerarquía más apropiada. En
definitiva, se trata de ver qué clases de objetos son subclases de otras, y cuáles son
las superclases. También es posible que la relación entre dos clases diferentes no
sea de inclusión, sino de partición (en el sentido en que el motor de un coche es
parte del coche, pero no un subconjunto del mismo). Por ejemplo, algunos de los
objetos mencionados podrían clasificarse de acuerdo con la figura 4.11, donde las
líneas llenas representan relaciones de inclusión y las flechas de trazos indican la
existencia de la relación contiene a. El tercer paso consiste en tomar las clases de
objetos, una por una, y analizarlas independientemente de las demás, tratando de
definir sus atributos.
Ventana Barra de acción
Figura 4.11.
463
• Carácter de relleno: a veces puede interesarnos que el campo de lectura no
esté inicialmente lleno de espacios en blanco, sino con otro carácter diferen-
te, cuyo comportamiento, sin embargo, debería ser equivalente al de un espa-
cio en blanco.
• Dirección de la sombra arrojada por el campo, si se desea.
• Definición del funcionamiento de ciertas teclas y del ratón, cuando el campo
de entrada de datos está activo.
• Otras particularidades, generalmente representadas por un solo bit de infor-
mación: si el campo permite al usuario escribir o, por el contrario, es
read-only (sólo de lectura); en el primer caso, si debe producirse una reorga-
nización automática del texto para no cortar una palabra cuando ésta aparece
al final de una línea; si el campo debe dibujarse con un marco alrededor, o no.
7. Resumen
En este capítulo se han detallado dos de los principales sistemas que se están
utilizando para el desarrollo de aplicaciones de software: la metodología en
cascada y la orientación a objetos. En el primer caso se han mencionado algunos
de los métodos más utilizados, como el modelo entidad-relación, la descompo-
sición funcional (pusimos el ejemplo de la metodología MAPS) o el diagrama de
flujo de datos.
464
Respecto a la orientación a objetos, hemos definido sus elementos principales
(objetos, clases y herencia), sus propiedades esenciales (encapsulamiento, poli-
morfismo y cierto grado de enlace dinámico), y el hecho de que, en lugar de la
llamada de subrutina (instrucción CALL), se apoya en el paso de mensajes entre
unos objetos y otros.
Se ha visto una breve introducción a la metodología general de análisis y
diseño orientados a objetos, y a las muchas formas en que, según los autores, se
presenta en la actualidad. Un pequeño ejemplo (cuyo desarrollo completo se sale
del alcance del libro) habrá servido para fijar los conceptos más importantes.
465
Obviamente, C++ es un lenguaje híbrido o extendido. También lo es Ada 95.
En ambos casos, las clases no son otra cosa que tipos abstractos de datos, mientras
los objetos son variables pertenecientes a dichos tipos. Muchas de las extensiones
introducidas en C para convertirlo en C++ tienen que ver con la conversión de la
declaración struct en un verdadero sistema de construcción de tipos extensibles.
Ada 83 poseía excelentes constructores para la descripción de tipos de datos, por
lo que no fue difícil introducir los conceptos OOP en la versión Ada 9X
(Skansholm, 1994), recientemente aprobada como Ada 95. Los lenguajes Pascal
(Turbo Pascal 5.5) y Modula-2 (Modula-3 y Oberon) se han extendido al mundo
de la OOP. También lenguajes tan aparentemente diferentes como el APL pueden
extenderse en esta dirección (Alfonseca, 1989).
Es frecuente que muchas aplicaciones comerciales estén escritas en lenguajes
extendidos, mientras que los puros desempeñan un papel muy importante para
precisar y difundir los conceptos de la programación orientada a objetos. Las
diferencias entre unos y otros no se reducen a la terminología (por ejemplo, lo que
en Smalltalk se llama método en C++ suele denominarse función miembro y en
Ada 95 es una operación primitiva), sino que a menudo afectan a la manera de
realizar internamente diversos mecanismos, como la propiedad esencial de la
herencia y, sobre todo, el enlace dinámico.
La descripción de la programación orientada a objetos del apartado 5 se apoya
esencialmente en Alfonseca y Alcalá (1992). Otros dos libros que dan una
excelente introducción son Meyer (1988) y Love (1993). Las técnicas de análisis
y diseño orientados a objetos disponen de una amplia bibliografía, como Booch
(1994), Coad y Yourdon (1991), Jacobson (1992), Martin y Odell (1992),
Rumbaugh y otros (1991), Shlaer y Mellor (1988) o Wirfs-Brock y otros (1990).
Actualmente, la programación orientada a objetos es sólo una parte del
conjunto de actividades científicas, técnicas e industriales agrupadas bajo el
nombre de Tecnología de Objetos (entendiendo tecnología en su acepción
anglosajona) u Objectware. En este contexto se habla de objetos distribuidos,
servidores de objetos, depósitos de objetos y otros conceptos semejantes, lo que
ha dado lugar a la necesidad de que objetos de diversos fabricantes puedan
entenderse entre sí, para lo que es preciso definir interfaces estándar. Este es el
objetivo del Object Management Group (OMG), formado por un consorcio de
empresas del ramo para definir normas y estándares aplicables a los objetos
distribuidos, equiparables a las que patrocinan instituciones públicas y profesio-
nales tan establecidas como el American National Standard Institute (ANSI), la
International Standards Organisation (ISO) y el Institute of Electrical and
Electronics Engineers (IEEE).
El trabajo del OMG se ha plasmado en la arquitectura CORBA (Common
Object Request Broker Architecture), al que generalmente se adaptan todos los
productos de diversas compañías. Y no es esto todo, pues encima de CORBA, y
utilizando como base la tecnología de objetos, han surgido nuevos consorcios y
propuestas en campos como la tecnología multimedia, en los que las empresas
más potentes ofrecen soluciones alternativas.
Por último, desde varios puntos de vista, la tecnología de objetos se manifiesta
como un movimiento técnico asimilable a un proceso de evolución cultural
progresivo, que trasciende a la programación para extenderse, como hemos visto,
al análisis, diseño y desarrollo completo de aplicaciones e incluso a la estructura
de las bases de datos que éstas utilizan. Esto explica que esta tecnología tienda a
integrar o abarcar lo que hemos llamado programación tradicional (métodos =
programas, algoritmos), y ya ha comenzado a incorporar asimismo otros estilos y
lenguajes de programación, como demuestra el caso de la extensión orientada a
objetos de Lisp (CLOS), e incluso se habla de sistemas operativos orientados a
objetos.
467
5
Máquina de Turing:
definición,
esquema funcional
y ejemplos
1. Introducción
El propósito fundamental de este capítulo es definir qué es, cómo funciona y
cómo se diseña una máquina de Turing. A través de varios ejemplos se fami-
liarizará el lector con la estructura de esta máquina, los alfabetos externo e interno,
su programación y las distintas representaciones de la misma (lista de quíntuplas,
esquema funcional, diagrama de estados) y la representación y manejo de las
informaciones en la cinta de la máquina.
Pondremos el máximo de énfasis en visualizar configuraciones sucesivas y
significativas de la información almacenada en la cinta de la máquina.
469
2. Definición de máquina de Turing
Una máquina de Turing es un autómata finito, junto con una cinta de longitud
infinita (que en cualquier momento contiene sólo un número finito de símbolos)
dividida en casillas (cada casilla puede contener un sólo símbolo o estar en blanco)
y un aparato para explorar (leer) una casilla, imprimir un nuevo símbolo sobre
ella, y mover la cinta una casilla a la derecha o a la izquierda. Veamos en detalle
estos elementos:
a) La cinta constituye una memoria infinita. Los símbolos que sobre ella están
escritos o se pueden escribir, e¡, i e IcN, pertenecen a un conjunto finito
E, al que llamamos alfabeto externo de la máquina. Hagamos m = Card(£).
Estos m símbolos sirven para codificar la información suministrada a la
máquina. El símbolo blanco, o vacío ( • , generalmente, a no ser que se
designe expresamente por 0) forma parte del alfabeto, lo que no querrá
decir que pueda considerarse infinita la información contenida en la cinta.
Por tanto, en un estadio cualquiera del funcionamiento de la máquina, toda
información registrada sobre la cinta se presenta bajo la forma de una
palabra escrita en el alfabeto externo E, a razón de un símbolo por casilla.
Cabeza de
lectura-escritura
M Q
I mh
I
Figura 5.1.
470
( <— ) , inmóvil ( < - » ) ; conjunto M,M = { —>, <—, } . (Obser-
vación: puede definirse la M.T. con M= { —>, }, pero aquí se ha op-
tado por la primera versión, más flexible).
c) El bloque T, que puede atravesar diferentes estados q¡, de un conjunto finito
Q, está conectado a la cabeza de lectura/escritura por un enlace de entrada
(lectura, símbolo e¡) y un enlace de salida (escritura, símbolo ek). El estado
le es presentado por el bloque Q. La función lógica realizada por el bloque
T hace corres-ponder a la pareja (e¡, q¡) un vector de salida (ek, mh, qp)
con e¡, ek e E, mh e M, qjt qpe Q. Naturalmente, el autómata, en un
sentido formal está cons-tituido por los bloques T y Q. Los bloques Q y M
actúan como dos memorias internas, que conservan respectivamente el es-
tado q y la orden de movimiento m h , producidos por el autómata durante
su trabajo, hasta el comienzo del instante siguiente, comienzo desencade-
nado por un secuenciador C, que controla los pasos o fases de trabajo. (No-
ta: aunque se designen por las mismas letras M y Q, no confundir bloque
con conjunto. El contexto dirá de qué cosa se trata). En un eje de tiempos
se representan las fases del funcionamiento de una M.T. (figura 5.2).
t t+1 t+ 2
Figura 5.2.
471
1. Bien, al cabo de un número finito de pasos se detiene la máquina dando la
señal de stop. Sobre la cinta se encontrará una cierta palabra/? escrita según
el mismo alfabeto, que representa la información resultante. Se dice que la
máquina es aplicable a la información A, y que transforma A enB.
2. Bien, la señal de stop no se produce nunca, en cuyo caso se dice que la má-
quina es inaplicable a la información inicial A.
El funcionamiento de una particular y concreta máquina de Turing podrá
describirse especificando los ítems (1) a (6), junto con los siguientes elementos:
o, lo que es lo mismo, mediante los ítems (7) a (9) y una tabla (también llamada
esquema funcional) de todas las quíntuplas posibles, e¡, q-, ek> mh, qp. Esta tabla
es un programa para la máquina de Turing, cuyas instrucciones dicen: "si la
máquina está en el estado q¡ y lee el símbolo e¡ que escriba el símbolo ek, mueva
la cabeza una posición mh y cambie al estado qp".
472
E= {•,!,*}
e
k mh qp
1 00 • — >
02
1 0i 1 <— 0i
1 q2 1 02
• 0o • 0o
\ 0 /
• 0i • — > 0o 0o 01 02
• 02 1 O 0i 1 • -> q 2 1 0i 1 "">02
*
• Stop • • ->90 • -^q0
0o 1 01
*
0i
*
0i *
• Stop * 0i * ^02
* *
02 02
Figura 5.3. Dos representaciones tabulares alternativas
473
1 I | * i l l 16
* i i l
(4,
7 ^ I * i i i 17 * i i i i
A í^l
3 >- I *
i 1 i 18
*
i i i l
*
4 S I * I i i 19 i l l
A
I
*
i i i < 20
*
i i i i
* *
6 I i i i 21 i i i i
Í^I
7 | *
1 i i 22 *
1 1 1 <
8 X | *
i l i 1 23
* lili | | 11 ^
9 X | * 1 i i i 24 * 111111111 ^
io y | *l 1 1 1 1 1 1 1 25 * 11111111 <
11 y I *l 11 1 1 1 1 1 26
*
1 1 1 i
r €
i?, >- I I I *l I I I i i 27 1 hll 1 i
¡Oí
13 y III •lili i i 28 1 M i l i 1 i
1 ¿-i
i * * l
14 ^ i l l 29 1 1 l
!<¡h
15 >• i *
l l 1 1 30 * 1 i
f^top)
Figura 5.4. Máquina de Turing para sumar dos números enteros no nulos
474
En efecto, la descripción realizada, si no se toma en cuenta la variable q¡, nos
proporciona el contenido de la cinta y, puesto que el símbolo situado a la derecha
de en la expresión es e¡ (por este motivo no resulta necesario incluir el
subrayado indicativo de la posición de la cabeza), se tiene además la pareja
(e¡, q¡) que representa a su vez la situación de trabajo en que se encuentra la
máquina.
CINTA ESTADO
001 00 00
000 00 02
000 00 02
000 00 02
000 00 02
000 00 02
000 00 02
000 o 01
000 o 01
000 o 01
000 o 01
000 o 01
000 o
01
000 o
01
000 o
02
0000^ o
02
0000* o
02
0000* o
0000* o 02
0000* o 02
0000* o 02
0000* 02
0000* 01
0000* 01
0000* 01
0000* 01
0000* 01
0000* 01
0000* 01
00000 00
stop
Figura 5.5.
475
0 0 q 0 1 0 0
0 0 0 ?2 0 0
0 0 0 q 2 0 0
0 0 0 *
A2 0 0
0 0 0 * q 0 0
2
<72 0 0
*
0 0 0
12 0 0
*
0 0 0
0 0 0 *
1 1 0
0 0 0 *
1 0
0 0 0 * 0
0 0 0 * 0
0 0 0 0
q
0 0 0 0
1 i
0 0 0 0
q 1
0 0 0 0
7 0
0 0 0 0 0
q
Figura 5.6.
Figura 5.7.
0o 01 02 93 04
*
1 "^02 a ^q2
a 1 <-03 • ^04
477
P^ • -» a * < -
478
Para comparar los dos números y detectar cual de ellos es mayor, la máquina
examina los dos grupos de |, marcando con un símbolo diferente ( a para el nú-
mero de la izquierda, P para el de la derecha), alternativamente un símbolo | de
cada grupo. El punto de partida del ciclo de comparación es el movimiento 13, en
que ya se ha sustituido un primer símbolo | del número de la izquierda por a .
Dos instantes más tarde (configuración 15) , el primer símbolo | del segundo
número ha sido sustituido por P . El proceso sigue así, en sustituciones alternadas,
hasta la configuración 33, en la que vemos que ya no hay más sustituciones
posibles en el primer número. Pero esto la máquina no lo descubre hasta trans-
curridos 6 instantes más (configuración 39).
El estado q4 provoca, cuando en la cinta hay a o p , sucesivos desplaza-
mientos a derecha con sustitución de a por • (borrado) y de p por 1, respectiva-
mente. Así se llega a la configuración 46 y un instante después, a la 47.
479
El diagrama de estados permite poner de manifiesto la existencia de dos
tipos de bucles, que son aquellos procesos peculiares en que la máquina puede
permanecer repetidamente en un mismo estado:
a)
Ñ
5 P P P a i I I I I 39
a a a P P P I I |
Ñ ÉL
* * * a I I i I I a a a P P P
9 I 40
a I
10
* * *
46
A
I I I
03 04
11
* * a | | I i I | 47 I I I I I I
02 [01
13
a
48
1 1 a 1 I 1
02
a a a a P P P
14 74
0^)
a
15 81
82
[stop]
Fjgura 5.11. Instantes significativos en el proceso de cálculo del m.c.d.
de 3 y 6 por una máquina de Turing.
481
instante 81. Las alternancias de ciclos de comparación y de sustracción seguirían
desarrollándose hasta llegar a tener dos números iguales, en cuyo momento se
acaba el proceso. Esto es precisamente lo que ya ha ocurrido en el caso del 3 y del
6, y en la configuración 82 se detiene la máquina, quedando el resultado escrito a
la izquierda de la cabeza: 3.
M.T.O
M.T.l
M.T.2
M.T.3
Figura 4.10.
483
% q2
0 9 <-
CINTA INICIAL
1 0 -»
2 1 qx NeD
3 2 -> qx - >
4 3 -> q1 0o' i
5 4 -» qx
6 5 -> qx iY r e { | 1
!
7 "I -l
6 -> qx
8 7 q1
stop
9 8 -> qx — > • -»
1 stop CINTA F I N A L
• -» <?2 1 — >
484
figura 5.17 recoge la configuración de la cinta de datos antes y después de
aplicarle la M.T. correspondiente al proceso indicado en el organigrama de la
figura 5.12, con señalamiento expreso de las modificaciones que hay que producir
en aquella para ajustar la situación final de una máquina con la inicial de la
siguiente.
92 ?3
0 < -
1 — » — > < -
CINTA INICIAL
2 <r~
3 - > < -
4 <—
N2SD { |}
5 - > — >
6 - > - >
."3n2 "1
7 < -
I { | }
8 < -
N,e { | } JT2eD
9 I I I
\ i A 1
•
*
•<—stop CINTA FINAL
485
CINTA INICIAL
N, e { | } e { | }
0o 01 02 03 04
* a 1 ">• - > 0 2
N3e { |}
a <- — > | • -»
486
El trabajo de la máquina consistirá en acudir a la referencia, recordar un bit y
sustituirlo por otro símbolo (0 por a , 1 por P ). Memorizado este bit, se desplazará
la cabeza hacia la derecha en busca del primer registro no explorado y, dentro de
él, del bit homólogo. Si coinciden bit de referencia y bit homólogo, éste último
deberá ser anulado por la cabeza, que escribirá en su lugar a o P, volviendo a
buscar el siguiente bit de referencia.
lo 9i q2
0 1( stop
l2 - >
1 2q2 stop
2 3^2 stop
N3Z { | }
6 iq2 stop
7 8q2 stop
9 0 <- stop
N3GD
• <-q0
n2 nx
• 1<?2 stop
stop
CINTA FINAL
487
N2 e D N1e D
Inicial.
'N2eD' ' ^ i t
Después de aplicar M.T.O,
con r = 1.
/ Ü /
, / N,e { J4 Ajuste que habría que rea-
lizar para aplicar el esque-
ma M.T.I, (fig 5.12.).
Pi-
b ^ D f
Ni* J. hi
Después de aplicar M.T.l.
Wie { | } 2e Í l>
Después de aplicar M.T.O,
con r = 2.
Nxe { |}
Ú| } / /
Ajuste que habría que rea-
lizar para aplicar el esque-
ma M.T.2. (fig 5.13.).
e { I}
JV3le { | }
Ú Ajuste que habría que rea-
lizar para aplicar el esque-
ma M.T.3. (fig 5.14.).
N3sD
Después de aplicar M.T.3.
Ú
Figura 5.17. Sucesivas configuraciones de la cinta al aplicar el proceso de la figura 5.12
488
M.T.O' M.T.I' M.T.2' M.T.3'
Nueva denominación
9o 91 «2 93 Í4 «5 9« 97 <h «9 9io 9n 9l2 9l3 9l4 915
V de estados
e¡ \ 9o 91 „ /// _ nn Denominación
92 9o' íl' «2' 9s' 9o" 1" 9o 1"' I2" 93"' 9o"" 9i 92""
parcial
5 stop
4->9I —» <- -> 6 92"" -»
6 stop
5->9I -> <- <- 5-» <?," 7 g2""
stop
7 6->9I «- 8 q2"" —>
„ //// stop
• 92' |->9i' *->9I' 92 1 4"
*
92 <~9o «r <~9o a->q2 • <-9Ó
a 1 «-
p <- • 1 -»
Figura 5.18. Esquema funcional de una M.T. para el cálculo del m.c.d. de NT y N2 ; información inicial N2* N j y N2 e D
REFERENCIA ETIQUETA ETIQUETA
Figura 5.19.
P <r~ — >
<—
= ->01 > 08
491
£
Leer el primer bit numérico de la
referencia, mientras quede alguno
( Stop )
Figura 4.10.
492
v
Retroceder ndicionalmente hasta símbolo =, cambiando a
% otro estado para continuar explorando referencia
Si No
^es ^
Si No
-esO
i
Poner OC,cambiar a un estado que lo Poner P .cambiar a un estado que lo
recuerde y avanzar un paso recuerde y avanzar un paso
JL
Avanzar atravesando 0 , 1 hasta primer Avanzar atravesando U, 1 nasta prime
<?2. , cambiando de estado para iniciar la A , cambiando de estado para iniciar i a
comparación del bit recordado. Avanzar comparación del bit recordado. Avanz ir
un paso un paso
:5E
Avanzar atravesando (X „ (3 , ^ hasta Avanzar atravesando OC „ (3, ^ hasta
encontrar un 0 ó 1. encontrar un 0 ó 1.
=3fc
Avanzar, restaurando 0 , 1 , hasta primer Cam-
biar a estado Q 0
( Stop )
Figura 5.22.
493
Lo primero podría tomarse como un desafío intelectual, como una prueba
(necesaria y no suficiente) demostrativa del grado de capacidad lógica de un
futuro especialista en informática, como un juego de sociedad en grupos humanos
altamente intelectualizados o como entretenimiento inagotable de náufragos,
solitarios y presos que no fueran delincuentes comunes. Lo segundo es un trabajo
rutinario con una mecánica que, una vez conocida, no aporta nada especial al
individuo e incluso puede resultar psicológicamente casi inaceptable en esta hora
en que se dispone fácilmente de ordenadores.
Así pues, simular por ordenador la M.T. es una idea congruente con la
eliminación de tarea rutinaria y que permite, dentro de cierto límites, preservar y
hasta acentuar los aspectos teóricos de la M.T. Entre otras cosas permite -es un
ejemplo- ayudar a poner a punto el diseño de una M.T. como la del apartado 3.3.
Se han escrito algunos programas simuladores de M.T.'s, utilizando un len-
guaje de programación con las siguientes características:
MO T(M3, 1)
T(M4, B)
T(M5, *)
M1 T(M6, 1)
T(M7, B)
T(M8, *)
M2 T(M9, 1)
T(M10, B)
T(M11, *)
M3 E(B)
D1
T(M20)
M4 D1
T(M0)
M5 E(B)
T(M2)
M6 11
T(M1)
M7 D1
T(M0)
M8 11
T(M1)
M9 D1
T(M2)
M10 E1
T(M1)
M11 D1
T(M2)
M20 END
Figura 4.10.
495
5.2. Máquina de Turing universal
Todas las M.T.'s pueden ser simuladas por otra máquina de Turing llamada
M.T. universal, siempre que se le dé a ésta la información necesaria sobre la
primera, a saber:
Los conceptos necesarios para definir una M.T. universal son éstos. Se
demuestra que:
1. Cualquier M.T. concreta puede ser simulada por otra con alfabeto binario
({0,1}, { • , | } ) o los dos símbolos preferidos de cada uno. En general,
los símbolos de un alfabeto cualquiera son codificables por paquetes de
unos, paquetes distinguibles entre sí por paquetes convenidos de ceros).
2. Las posibilidades de una M.T. no se restringen por el hecho de que su cinta
sea ilimitada sólo por un extremo.
Una M.T. universal dispone de una cinta ilimitada por ambas partes, con un al-
fabeto externo{ 0,1, a, (3,^, £ , * , b } correspondiéndose acón 0 y P con
lFigura 5.23. El símbolo * representa la posición de la cabeza simulada, b es el
blanco y al iniciar y terminar la simulación de un movimiento de la M.T. simulada
sólo habrá símbolos numéricos {0, 1} en la M.T. universal. La información de
datos de la cinta simulada se sitúa a partir de una posición a la izquierda de y
la información sobre sus estados y funciones a la derecha de ese mismo símbolo.
Esta es una versión de una máquina de Turing universal.
Con estos elementos se puede construir una M.T. universal que, combinando
las posibilidades de una M.T. de cinta direccionable (apartado 4) y de una M.T.
transcriptora de información, puede simular todas las M.T.'s definidas en un alfa-
beto binario.
i M.T.
CAPACIDAD
DE MEMORIA Situación y tendencia
de los ordenadores
reales
(Grado de variedad de
algoritmos ejecutables)
0, N e DE INSTRUCCIONES
DISTINTAS
(Grado de facilidad para
describir un algoritmo)
Figura 5.23.
497
tantas veces utilizada en este capítulo. Así pues, no solamente goza de la virtud
teórica de poder ejecutar cualquier algoritmo, como, por ejemplo, simular a un
ordenador moderno que es una máquina más compleja dotada de un rico reper-
torio de instrucciones, sino que esto lo hace mediante los pasos más elementales
de que se tiene noticia.
La genialidad de Turing consistió en poner su invento fuera de las limitaciones
espacio-temporales (espacio para la información, infinito; tiempo, el que sea, pero
un número finito de pasos). En tales circunstancias, una sola M.T. es capaz de re-
producir el funcionamiento de todas las demás , siempre que disponga de la des-
cripción de las mismas.
Esta última idea, inmanente a la M.T.U., de que una máquina pueda desarrollar
procesos más complejos que los que su propia estructura parece permitirle, a
condición de que se le suministre la información adecuada, despertó gran interés
y ha sido trasladada por analogía al campo de la reproducción biológica para
intentar explicar la construcción de la vida y su mantenimiento a partir de las
informaciones genéticas.
a) M.T.'s con sólo dos de las tres salidas posibles ek, mh, qp .
b) M.T.'s con cinta limitada por un extremo.
c) M.T.'s con más de una cinta y más de una cabeza.
d) M.T.'s no deterministas.
7. Resumen
Una máquina de Turing es un artefacto computador constituido por un
autómata finito que controla una cinta infinita. Cada paso en el cálculo de una
M.T. consiste en escribir un símbolo en la cinta, desplazar la cabeza de lectura/
escritura una casilla a la derecha o a la izquierda y asumir un nuevo estado. La
acción concreta de cada paso viene determinada por el estado en curso de la
máquina y por el símbolo que lee en ese instante la cabeza.
El funcionamiento de una M.T. se especifica completamente por una lista de
quíntuplas e¡, (¡j, ek, mh, qp, donde están todas las combinaciones e¡, q¡ que
permiten los alfabetos externo E e interno Q, por la cinta con la información
inicial y por la situación inicial de la máquina expresada por la posición de la
cabeza y el estado del autómata. A la lista de quíntuplas se le llama esquema
funcional o programa de la M.T.
498
Distintos ejercicios a lo largo del capítulo han buscado familiarizar al lector
con el funcionamiento y las diferentes formas de representar los resultados de una
M.T. Una M.T. es capaz de realizar sólo operaciones muy elementales, pero
secuencias adecuadas de estas operaciones pueden llegar a componer una amplia
variedad de operaciones de manipulación de bloques. Estas últimas operaciones
comprenden: formar copias de bloques especificados, sustituir un bloque por otro
y comparar bloques. Empleando estas operaciones como subprogramas, es
posible diseñar M.T.'s que realizan cálculos muy complejos.
El modelo de M.T. que se ha presentado puede modificarse en varios sentidos
sin alterar sus posibilidades últimas como máquina computadora. Tal vez
convenga subrayar que, dado un algoritmo a ejecutar por una máquina de Turing,
en el diseño de ésta -supuesto escogido un modelo específico de M.T. (por ejem-
plo, con una sola cinta ilimitada por ambos extremos)- se presenta, en principio,
la disyuntiva de disminuir el cardinal del alfabeto externo a costa de aumentar el
del interno, o viceversa. Uno de los resultados más interesantes de esta propiedad
es que siempre es posible simular una M.T. por otra M.T. definida sobre un
alfabeto externo binario.
Por último, debe resaltarse la máquina de Turing universal, diseñada para
ejecutar un algoritmo de simulación de todas las otras M.T.'s que poseen su
misma estructura. Las especificaciones completas de la M.T. simulada y sus datos
de trabajo figuran como datos en la cinta de la M.T.U.
499
Disponer de herramientas gráficas de diseño y programación y de entornos
operativos de usuario final, del tipo Windows y similares (Macintosh), para
ordenadores personales permite hoy día construir simuladores de última gene-
ración, muy didácticos, que desplazan la cabeza de la máquina, resaltan en pan-
talla los nodos y arcos activados en el diagrama de estados, e integran estos
esquemas en un documento generado por procesamiento de texto, si así se desea.
Citemos, al respecto, el paquete Turing's World, formado por libro y disquete, del
Center for the Study of Language and Information (CSLI) (ver Barwise y
Etchemendy, 1995) y el simulador, mucho más elemental, de D. Matz (1995). El
CSLI produce otros materiales de interés para los lectores de este libro.
A título de curiosidad, tal vez merezca la pena reflexionar acerca de la
trascendencia del concepto de máquina de Turing universal acercándose a
especulaciones en otros ámbitos disciplinares ajenos a la informática. En tal
sentido, cabe mencionar la analogía que habla de construir vida compleja a partir
de un núcleo básico y reducido de mecanismos sencillos e informaciones (Singh,
1976, cap. 13).
El lector que necesite o desee una presentación más formal y amplia de la
máquina de Turing dispone de varias opciones en la bibliografía. Pero si
tuviéramos que recomendar aquí un solo texto nos inclinaríamos por el libro de
Hopcroft y Ullman (1979), por la simple razón de que, dejando a un lado su
incuestionable calidad, tiene la ventaja de que trata conjuntamente la mayor parte
de los temas abordados en nuestro libro.
El primero de estos autores ha escrito un artículo de alta divulgación sobre
máquinas de Turing en la revista Scientific American, posteriormente traducido al
castellano (Hopcroft, 1984), que consideramos muy recomendable. Se extiende
también en aspectos básicos de computabilidad y complejidad, sobre los que
versarán nuestros próximos capítulos.
9. Ejercicios
9.1. Completar la definición del autómata finito de una máquina de Turing
de la que se conoce lo siguiente:
• El contenido inicial de la cinta es un número entero representado en
el alfabeto { | } , seguido de un "*".
• El contenido final de la cinta será el mismo número en binario natural
representado en {0,1}, seguido de un "*".
• Conjunto de símbolos de entrada { • , | , 0,1, *} .
• Conjunto de movimientos de la cabeza { - > , < — , < - > } .
9.2. Escribir, exclusivamente, el contenido de la cinta (utilizando el formato
de descripción instantánea) de una máquina de Turing para la reso-
lución del algoritmo de Euclides (subapartado 3.2) con dos números
enteros en el alfabeto [ en los instantes que se indican:
500
1. La máquina está en q2, al que acaba de cambiar por segunda vez.
2. La máquina está en q2, al que acaba de cambiar por cuarta vez.
3. La máquina está en qí, al que acaba de cambiar por tercera vez.
4. La máquina está en q3, al que acaba de cambiar por segunda vez.
La máquina se inicia con los números 9 y 3 en la cinta, respectivamente,
a izquierda y derecha del asterisco.
9.3. Obtener el esquema funcional de una máquina de Turing quejpasa por
las configuraciones de cinta indicadas en el diagrama de la pagina an-
terior. Nótese que a la derecha de cada una de las configuraciones se
escribe el instante correspondiente. Razonar por escrito la obtención del
esquema funcional.
lo q¡ &
I
n
*
1
1 1 1 1 *
1 1 1 1
2
1 1 1 1 *
[ 1 1
12
1 1 1 1 *
1 1 1
11 1 1 1 13
*
1 1 1
11 1 1 1 24
*
1 1
r®i
1 1 1 25
11 1 1 1 *
Penúltima
1 1 1 11 1 1 1 *
rSoi
1 1 1 1 1 1 1 1 Ultima
fstopl
501
9.4. En la figura 5,14 puede consultarse el esquema funcional de una
máquina de Turing que permuta los números N2 (representado en el
alfabeto decimal) y (expresado en palotes).
Partiendo de la misma posición: contenido inicial de la cinta, estado
interno y posición de la cabeza, se pide introducir las modificaciones
pertinentes en el antecitado esquema funcional para que la máquina
realice la siguiente transformación:
N2eD
i l>
Cinta inicial
{ |} N2fD
502
Notas:
Ejemplos:
Contenido inicial
0 i 0 1 0 1 0 1
r "
4o 4o
* *
Contenido final i 0 1 1 0 *
f »
9.7. Diseñar una máquina de Turing que sume enteros no negativos en las
siguientes condiciones:
503
b) Los dos números n1 y n2, que suma la M.T. se presentan en la cinta,
de izquierda a derecha, separados por un cero (o blanco • ) y el
resto a ceros (o blancos).
1. Introducción
Este capítulo aborda de manera muy esquemática la noción de computabilidad
(calculabilidad) en el sentido de Turing (y conceptos relacionados), que formaliza
la noción un tanto intuitiva de algoritmo de las definiciones de autores recogidas
en el segundo capítulo. Respecto a la definición formal de algoritmo del mismo
capítulo ésta es una alternativa más fértil, pues se expresa en términos de una
máquina que, no por ser ideal o conceptual, es menos concreta.
507
2. Función computable y función
parcialmente computable
2.1. Hipótesis de Church o de Turing
La idea intuitiva de procedimiento efectivo para desarrollar un cálculo es la
misma que la de algoritmo. Pues bien, según la hipótesis de Turing/Church: la
noción intuitiva informal de un procedimiento efectivo sobre secuencias de sím-
bolos es idéntica a la de nuestro concepto preciso de un procedimiento que puede
ser ejecutado por una máquina de Turing.
No existe prueba formal de esta hipótesis pero, hasta la fecha, siempre que en
la teoría de las funciones recursivas1 ha sido intuitivamente evidente que existía
un algoritmo, ha sido posible diseñar una M.T. para ejecutarlo.
nx + 1 n2 + l «3 + I nr + l
(r)
0 = 1, 1 = 11, 2 = 111,.., 5 = l i l i l í , . . .
508
El cero hará las veces de separador, por lo que una r-upla (n1, n2,..., nr) se
convendrá en representar como en (1), lo que abreviadamente equivale a
nl0ñ20tt30...0nl.. Si ésta es una información A en la cinta de una máquina de
Turing Z, Z será aplicable o no a A. En el primer caso, Z produce el cálculo
que es una función de valores enteros no negativos, definida sobre i f o sobre una
parte de N r (función parcialmente definida).
Si se hace ahora al revés, es decir, se parte de una función definida sobre l í o
sobre una parte de Nr se tienen las siguientes definiciones.
2.3. Ejemplos
2.3.1. La función f(n1, n2) = n1 + n2 definida sobre las parejas de enteros no
negativos, que es calculable (computable) en el sentido habitual de la palabra, lo
es también en el sentido de la definición 2.2.2. Puede construirse una máquina de
Turing Z, tal que
(2)
+ n2 = SUMZ («1, n2) (4)
509
e
4o 9i 42 43 44 45 46
¡
i 4i 42 0 - » q3 — >
0 < - 44
n1 + n2 = 0 si n1< n2
3. Numerabilidad de la colección
de todas las M.T.'s
Una M.T. está especificada por una lista de quíntuplas ej, q¡, ek, mh, qp,
que forman un conjunto finito. Los valores posibles de i, j, k, h, p son toaos
numerables. Así pues, la colección de todas las quíntuplas es numerable. Consi-
guientemente, las listas de quíntuplas son numerables y, por ende, los autómatas
por ellas representados.
Esto significa que las M.T.'s pueden ordenarse numéricamente. El problema
es cómo escoger un código tal que, dado un número, puedan determinarse las
especificaciones de la M.T. correspondiente, si la hubiere, y viceversa.
510
Kurt Gódel, lógico eminente desaparecido hace pocos años, escribió en 1930
un artículo que, cuando se publicó en una revista alemana en 1931, produjo el
efecto de un paquete de dinamita colocado precisamente en la base de la viga
maestra de los fundamentos de la matemática. Fundamentos que, con celo enco-
miable, estaban renovando los matemáticos de la época, con Hilbert a la cabeza.
Para el lector que no conozca en qué contexto propuso Gódel su técnica de
codificación, la preocupación matemática del momento consistía en probar la con-
sistencia de la teoría axiomática de conjuntos, para lo cual Hilbert propuso un
programa completo. Pues bien, Gódel probó dos cosas:
1. Si la teoría axiomática de conjuntos es consistente, existen teoremas que
no pueden ser probados ni refutados.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ... y, ...
4 + 7 = 11
12 1 15 7 9 9
La fórmula a(a - i) = aa - a
511
tendría el siguiente número de Gódel: 2 •3 •5 • 7 • 11 • 13 • 17 • 19 •
!
• 2318 • 29 2 • 3118 •.
4 2 1
La cadena - + se codifica por 2 - 3 - 5 igual a 720. Pero, a causa de la
unicidad de la factorización en número primos, una cadena puede reconstruirse a
partir de su código. Esto es, el número 720, factorizado, nos da 2 - 3 -5 que
corresponde a la cadena + - +, pues los símbolos que componen ésta tienen los
códigos 4 , 2 y 1 respectivamente.
En resumen, cada cadena tiene un número, y números diferentes corresponden
a cadenas diferentes. Disponiendo éstas según el tamaño de sus números de
Gódel, puede verse que el conjunto de cadenas es numerable.
512
calcula dicha función (es evidente que puede haber varias máquinas que calculen
la misma función).
Se define una función Q(z']:
FZ{X) = Fu(z,X)
4.1. Teorema
(r)
Las funciones Qz (X) son funciones parcialmente computables.
Una M.T. que calcula la función Q(zr) (X) se llama universal: inscribiendo en
su cinta el número z adecuado, ella puede calcular la función parcialmente
computable correspondiente a este número.
2
E1 análogo de U es el ordenador cargado de programas al que se le da el nombre z de uno de éstos y los datos
sobre los que tiene que operar.
513
Hay dos procesos fundamentales de cálculo que pueden asociarse a un conjun-
to específico G de números naturales. Uno es el proceso de determinar si, dado
cualquier número natural x, éste pertenece a G. El otro es el proceso de generar,
uno a uno, todas los elementos de G. Ambos procesos están relacionados, pero no
son equivalentes.
Para expresar qué es un conjunto de alguna de estas clases debe recordarse
previamente la definición de función característica de G, CG, se define así:
lsixe G
CG(X)= (
0 si x g G
'Podría sustituirse "función computable" por "función recursiva" (véase pie de página del apartado 2.1); y
"función parcialmente computable" por "función parcialmente recursiva".
5.3. Dos teoremas más
Enunciamos sin demostración que:
- "Sí, x e E, Z a s e parará".
- "No, XG E, Za no se parará".
515
Observación.
El problema de la aplicabilidad es trasladable al terreno práctico de la pro-
gramación de ordenadores. Dados un programa P y los datos D correspondientes,
¿existe un programa general PH que permita saber si P, aplicado a D, se detendrá?
La respuesta es que PH no existe.
- Puede construirse una M.T. que acepte cualquier lenguaje generado por un
sistema de escritura no restringido (lenguajes tipo 0).
- Cualquier lenguaje generado por una gramática del tipo 0 es recursivamente
numerable.
516
8. Resumen
Se han definido las funciones computables como aquellas a las que corres-
ponde una máquina de Turing aplicable a una r-upla «¡0«¡0ñ¡0...0ñ r que pro-
duce un número (y ) de unos.
Las M.T.'s pueden catologarse mediante alguna técnica de codificación, tal
que a cada máquina le corresponda un número entero positivo y a cada número
entero positivo le corresponda como máximo una sola M.T. La técnica clásica, a
nivel teórico, es la de los números z de Gódel.
Así codificada la colección de M.T.'s, pueden diseñarse dos máquinas de
Turing, una para codificar máquinas de Turing (es decir, transformar un esquema
funcional en número de Gódel) y otra para decodificar (es decir, transformar un
número de Gódel en un esquema funcional de M.T., si ésta existe).
Con este instrumental se ha redefinido la máquina de Turing universal como
aquella a la que sólo es necesario darle el número de catálogo de la M.T. a simular
y los datos para ésta.
Las nociones de computabilidad y de parcial computabilidad se emplean en re-
lación con los procesos de cálculo en conjuntos de números naturales para definir
qué es un conjunto recursivo (función característica computable) y qué es un
conjunto recursivamente numerable (dominio de función parcialmente compu-
table).
Por último, se han dado unas muestras del grado de interés de los conceptos de
los conjuntos recursivos y recursivamente numerables aplicándolos al razona-
miento acerca de la indecibilidad del problema de aplicabilidad de cualquier má-
quina de Turing y a la aceptación de lenguajes generados por sistemas de escri-
tura no restringidos.
517
Formalismos equivalentes a las funciones parcialmente recursivas incluyen el
X -cálculo (Church, 1941), las funciones recursivas (Kleene, 1952) y los sistemas
de Post (1943).
Para este capítulo hemos utilizado con preferencia los libros de Arbib (1965),
y de Gross y Lentin (1967). En particular, a este último le debemos la enunciación
de los teoremas 5.3.1 y 5.3.2, así como la definición de función característica de
un conjunto y el segundo de los enunciados del problema de la aplicabilidad.
Un libro bien escrito sobre introducción a las máquinas de Turing, a las
funciones recursivas y temas conexos, es el de Hennie (1977), del que, entre otras
cosas, se ha usado su descripción de los procesos fundamentales de cálculo
asociables a un conjunto G de números naturales.
La leve referencia del final del apartado 7 a los desarrollos de la línea lingüís-
tica dentro de la Inteligencia Artificial se encontró en Hunt (1975).
7
Complejidad
1. Introducción
Este capítulo aborda el fundamento teórico de las limitaciones prácticas que se
presentan en la aplicación del concepto de algoritmo. En pocas palabras, se dedica
a estudiar la factibilidad de los algoritmos.
De entre todos los problemas que pueden plantearse, el conjunto de aquellos
que son computables (decidibles), es decir, que pueden teóricamente ser resueltos
aplicando un algoritmo, es muy reducido. Sin embargo, no todos los problemas
computables son factibles en la realidad, por requerir a veces demasiados recur-
sos, ya sean de tiempo, espacio de memoria o circuito materiales.
La teoría de la complejidad algorítmica es la encargada de definir los criterios
básicos para saber si un problema computable es factible o, dicho de otro modo,
si tiene un algoritmo eficiente para su resolución y en este caso cuál es su grado
de eficiencia (recuérdese la propiedad de eficacia de todo buen algoritmo, apar-
tado 4 del capítulo 2). Aunque nada más una ínfima parte de los problemas son
algorítmicamente factibles, el conjunto es lo suficiente amplio y variado como pa-
ra que esta teoría resulte no solamente interesante, sino del todo imprescindible
para el conocimiento de las nociones esenciales de la informática.
Iremos de lo más general a lo más particular. Primero, se tratará el asunto de
la complejidad en términos de la máquina de Turing, puesto que así el tamaño del
521
problema puede expresarse de la manera más sencilla posible como el número n
de posibles casillas que ocupa la información de entrada. Lógicamente, la com-
plejidad del algoritmo resolutor se podrá poner en función de n contabilizando (o
estimando por algún procedimiento), bien el número de casillas que es necesario
explorar, bien el número de movimientos de la máquina.
Con posterioridad, se trasladará la cuestión a un terreno más práctico, en el que
se dispone de operadores más funcionales, por lo general en forma de máquinas
computadoras secuenciales, aunque no pueda dejarse sin mencionar la emer-
gencia cada día más patente de máquinas de proceso físicamente concurrentes y
su repercusión sobre la complejidad. En todo caso, y al igual que con las máquinas
de Turing, se medirá la complejidad por un orden de magnitud, del tiempo (por
ejemplo), expresado en forma abstracta como función del tamaño del problema.
Decir "en forma abstracta" significa expresar el tiempo como un número de pasos
operativos elementales, al objeto de independizarlo de la velocidad concreta de la
máquina ejecutora.
A grandes rasgos, los problemas computables se clasifican en buenos {com-
plejidad polinómica) y malos (complejidad exponencial). Entraremos en algunos
detalles sobre estos conceptos y conceptos derivados.
Para terminar, nos ocuparemos de un apartado de la complejidad teóricamente
menor, la complejidad de los programas, a la que se ha dado en llamar -de manera
a nuestro juicio incorrecta- complejidad del software. La complejidad del soft-
ware tiene que ver, no con la eficiencia de los algoritmos, sino con la eficiencia
de la programación de los algoritmos.
522
Establecer un criterio universal para poder saber cuán eficiente es un algoritmo
no es sencillo a priori, porque un mismo problema puede resolverse sobre dife-
rentes tipos de máquinas, con diferentes grados de eficiencia. Examinemos un
momento este asunto por medio de un ejemplo sencillo. Multiplicar dos números
de n dígitos decimales por el procedimiento que a todos nos enseñaron en la
escuela requiere un tiempo de ejecución proporcional a n . El ejemplo de la figura
7.1.a) muestra un caso en el que n = 5. El número de operaciones necesarias es,
de una parte, aproximadamente igual a n x «para obtener las n filas: cada fila
resulta de efectuar n multiplicaciones de dos números de 1 dígito decimal. De otra
parte, después hay que sumar las n filas interdesplazadas y esto puede costar
alrededor de n sumas de dos números de 1 dígito decimal. En resumen, el tiempo
total se compone de c • n (c, constante) operaciones, que convencionalmente
podemos suponer equivalentes a unidades de tiempo, aunque sabemos que hay
involucrados dos tipos de operaciones distintas.
42013
x 27491
4 2 0 13
378117
16 8 0 5 2
(a) 2 9 4 0 91
84026
1154979383
A B c D
42 013 X 27 491
AC = 1134
(A+B) • (C + D) -A • C-B D = 20973
B D = 6383
1154979383
Figura 7.1.
Existen algoritmos más rápidos para resolver el mismo problema. Uno de ellos
está aplicado al caso práctico escogido en la figura 7.1.b). Este algoritmo requiere
un tiempo proporcional a n y se ha obtenido dividiendo el problema en sub-
problemas. El algoritmo más rápido conocido a este respecto ejecutable en una
523
máquina secuencial tiene un tiempo proporcional a n • log2 n • log2log2 n. Si la
máquina fuera paralela, el tiempo podría ser proporcional a logz n.
En resumen, la eficiencia de un algoritmo no depende sólo del tiempo y del
espacio (memoria) utilizados, sino también de los circuitos disponibles (hardware
y, en particular, del número y estructura de los procesadores), en suma, de los
recursos concretos (véase capítulo 3).
La máquina de Turing nos permite, una vez más, liberarnos de la mayor parte
de esas ligaduras materiales gracias a su estructura de operación de formato único
(aunque, como sabemos, su estructura admite diversas variantes).
No obstante, utilizaremos la máquina de Turing solamente para iniciarnos en
los conceptos básicos de complejidad espacial y temporal, la complejidad en tér-
minos asintóticos y algunos resultados sobre los efectos en la complejidad debido
al aumento lineal de velocidad, la comprensión de la información y la reducción
del número de cintas. El estudio detallado de estas cuestiones es objeto de obras
especializadas. En el subapartado 2.4 se dará una breve idea sobre la cuestión de
los efectos en la complejidad.
a: (1)
El problema se convierte en un lenguaje L que una máquina de Turing concreta
acepta o no. Lícitamente, podemos preguntarnos por la complejidad de las
máquinas de Turing (o de los algoritmos) por referencia a los lenguajes.
Se define la complejidad espacial utilizando la máquina de Turing M de la
figura 7.2, que consta de una cinta de entrada de sólo lectura con la información
enmarcada por delimitadores en sus extremos y de K cintas semi-infinitas de
memoria de lectura-escritura. La máquina M tiene una complejidad espacial S(n)
(o es S(n)-limitada en espacio) si, para cualquier entrada de longitud n, explora
como máximo S(n) casillas en cualquiera de las cintas de trabajo.
Cintas para
memoria
y trabajo
UNIDAD
LOGICA
Cinta de sólo
INFORMACION lectura
# #
DE ENTRADA
Figura 7.2.
525
Cintas para
memoria y
trabajo
INFORMACION
DEENTRADA
"N
UNIDAD
LOGICA
Figura 7.3.
Obsérvese que las funciones S(n) y T(n) no necesitan ser una función exacta,
sino sólo un indicador de la forma de variación en función de la longitud de la
entrada. Por ejemplo, a efectos de estudiar la eficiencia de un algoritmo simulado
por una máquina de Turingilf, da igual que su tiempo de ejecución sea 14n +25n
-4 ó 3 n , pues su forma de crecimiento es en ambos casos de tipo n . Diremos
que la máquina M es de complejidad temporal (n ), o (« )-limitada en tiempo.
Esta segunda expresión se comprende intuitivamente, pues si nos fijamos en las
funciones anteriores, vemos que en el límite (n infinito) tienden a las asíntotas
14« y 3n respectivamente, que son del tipo en (c, constante).
Así pues, al hablar de complejidad estamos hablando en realidad de
complejidad, en términos asintóticos. Parece razonable asumir que toda máquina
de Turing será al menos de complejidad temporal (n + 1), pues éste es el tiempo
requerido para leer la entrada. Igualmente, toda máquina de Turing será al menos
de complejidad espacial (1), pues debe poseer al menos una casilla de entrada.
Cuando decimos que una máquina es T^nJ-limitada en tiempo, en realidad
estamos diciendo Máx[(n + 1), T(«)] limitada en tiempo, y lo mismo para la
complejidad espacial, que será Máx[(l), S(«)].
527
Es indudable que los que en el apartado 6 del capítulo 5 hemos denominado
sucedáneos de la máquina de Turing, algunos de los cuales se han utilizado líneas
arriba para definir, por conveniencias teóricas, la complejidad, nos proporcionan
una idea de la variabilidad de circuitos disponibles (número de cabezas, número
de cintas de memoria y sólo lectura, límites en la longitud de las cintas, etc.) y
consecuentemente de su influencia sobre la complejidad. Por fortuna, todos estos
tipos acaban pudiéndose reducir a una M.T. mono-cinta.
Es así como se demuestra, por ejemplo, que si un lenguaje L está en la clase
DTIME(T(«)), es decir, posee complejidad temporal T(n), entonces es aceptado
en tiempo i (ra) por una M.T. mono-cinta.
Asimismo, si L es aceptado por una M.T. r(ra)-limitada en tiempo de k cintas,
es aceptado por una M.T. de dos cintas de memoria con complejidad temporal
T(n) -logT(n) .
Resumiendo, comprobamos que alteraciones importantes de la estructura de
una M.T., como puede ser el aumento o disminución del número de cabezas y de
cintas de trabajo, si bien no restringen -como se estableció en capítulos anteriores-
las posibilidades de la máquina de Turing básica, afectan en cambio a la com-
plejidad temporal. Los dos teoremas que se acaban de enunciar son bien explícitos
en este sentido: el paso de complejidad temporal T(n) a complejidades T2 (n) o
7" (ra) • logT(n) nos ayudan, por analogía, a comprender el cambio cuantitativo
que cabe esperar de procesar algoritmos en forma secuencial a procesarlos en
forma concurrente (cuando ello es posible).
528
por qué existir estrictamente una limitación de recursos (salvo por razones de
competitividad económica), pero, por razones de rendimiento operativo, es
en cambio muy importante mejorar los algoritmos utilizados y optimizar,
• llegado el caso, su codificación.
Figura 7.4.
529
2
Así las complejidades de la figura 7.4 son denotadas O {log 2n),0(n), O {n ).
y O (2") . Un tiempo de ejecución de 14n + 25n - 4 se resume en que la com-
plejidad es O (2") .
Los algoritmos cuyo comportamiento asintótico es del tipo O («) , O {n ) ,
O {n ) ,..., en general O {n) para c constante, se llaman algoritmos polinómicos,
o de complejidadpolinómica. Los algoritmos que se comportan como 2" (en gene-
ral c ) son algoritmos exponenciales, o de complejidad exponencial.
Las figuras 7.4 y 7.5, examinadas conjuntamente, nos permiten apreciar que,
siendo totalmente merecido el apelativo de "malos" con el que se conoce a los
algoritmos exponenciales, también entre los polinómicos los hay mejores y peores
y algunos pueden llegar a resultar bastante malos en cuanto que crece un poco el
tamaño n.
n, tamaño de la entrada
del problema
Figura 7.5.
BEGIN
encontrado: = False;
ind: = 1;
WHILE (NOT encontrado) AND (ind < = n) DO
BEGIN
IF lista [ind] = clave
THEN encontrado: = True (2)
ELSE ind: = ind + 1
END; {bucle de búsqueda}
IF encontrado
THEN BuscSec: = ind
ELSE BuscSec: = 0
END; {Búsqueda secuencial}
531
Tanto la complejidad temporal como la espacial son 0(n). En adelante, sólo
hablaremos de complejidad temporal.
3.2.2. Búsqueda binaria
El algoritmo de búsqueda binaria es mucho más eficiente (esto es, su
complejidad mucho menor) que el de búsqueda secuencial. El algoritmo de
búsqueda binaria tiene complejidad O (log2n) . Véase la figura 7.5. Pero en
realidad no son estrictamente comparables, porque el algoritmo de búsqueda
secuencial es mucho más general, al no imponer condicionamiento alguno en
cuanto al orden de los elementos en el conjunto. Por el contrario, en la búsqueda
binaria se requiere previamente que el conjunto esté ordenado1.
Este algoritmo trabaja comparando la clave con el elemento situado en medio
de la lista. Si coincide, lo da como encontrado y si no, descarta la mitad (de ahí el
nombre) de la lista que no puede contener la clave y repite el proceso.
De nuevo en Pascal, el algoritmo de búsqueda binaria en una lista de enteros
puede expresarse en la forma de (3). Las variables "alto", "medio" y "bajo" son de
tipo intervalo con enteros, como antes "ind".
Obsérvese que con cada comparación se divide la lista por la mitad, de modo
que ésta se va convirtiendo en la mitad, en la cuarta, la octava... parte de su tamaño
inicial. En el peor de los casos, el proceso continuará hasta que la lista a explorar
esté vacía (en el programa, sentencia "ELSE BuscBin: =0"). En consecuencia, el
mayor número de comparaciones que puede necesitar el método de búsqueda
binaria será el primer valor entero k tal que 2 > n, es decir, k > log 2n.
BEGIN
bajo: = 1;
alto: = re-
encontrado: = False;
WHILE (NOT encontrado) AND (bajo < = alto) DO
BEGIN
medio: = (bajo + alto) DIV 2;
IF lista [medio] = clave
THEN encontrado: = True
ELSE IF lista [medio] > clave (3)
THEN alto: = medio - 1
ELSE bajo: = medio + 1
END; {bucle de búsqueda}
IF encontrado
THEN BuscBin: = medio
'El interés de aplicar la búsqueda binaria (precedida de un algoritmo de ordenación) frente a la búsqueda se-
cuencial dependerá del número de veces que haya que aplicar el algoritmo de búsqueda, y, por supuesto, también
del orden de complejidad del algoritmo de ordenación..
ELSE BuscBin: = 0
END; {búsqueda binaria}
3.2.3. Ordenación por el método burbuja
Ordenar es el proceso de reorganizar un conjunto de objetos según una
determinada secuencia. Existen muchos métodos de ordenación y los más sen-
cillos, denominados métodos directos, tienen complejidad O (n ). Normalmente,
hay un número máximo de comparaciones y movimientos y un número mínimo,
como resultante del grado inicial de ordenación del conjunto.
El método de la burbuja es un método de intercambio, que consiste en
comparar dos elementos consecutivos, permutándolos cuando están desordenados
y llegando hasta el final de la lista en cada una de las pasadas. Por ejemplo, si
tenemos inicialmente la siguiente lista de números enteros (seguiremos utilizando
por simplicidad este tipo de objetos):
(2,4,6,7,12,9,10,15)
BEGIN
Intercambio: = TRUE;
Paso: = 1;
{El número de pasadas puede variar de 1
hasta n - 1, dependiendo de la disposición inicial}
WHILE (Paso < = n - 1) AND (Intercambio)
DO BEGIN
{Por el momento no se han producido
intercambios}
Intercambio: = False;
FOR j : 1 TO n - Paso DO
{si un elemento es menor que el anterior,
hay que intercambiarlo}
IF a [j] > a [j + 1]
THEN BEGIN
Intercambio: = TRUE;
Aux: = a [j]; (4)
a [ j ] : = a [ j + 1] ;
a [j + 1]: = Aux
END; {if then}
Paso: = Paso + 1
END {while}
END; {procedimiento burbuja}
533
La segunda pasada inicia los movimientos a partir de la pareja 12, 9, que es
permutada, descendiendo 12 hasta el penúltimo lugar de la lista:
(2, 4, 6, 7, 9,10,12,15)
3.3. Sinopsis
El esquema de la figura 7.6 pretende sintetizar algunas de las ideas ya vistas o
que se desprenden de los conceptos y ejemplos examinados.
Un aspecto que no habíamos comentado anteriormente es el que se refiere, no
a la complejidad del algoritmo, sino a la complejidad del problema. Tal cuestión
remite a diseñar y comparar (en tiempo secuencial, por ejemplo) todos los algo-
ritmos posibles para resolver un problema. En el apartado 2 mencionábamos
distintas soluciones al problema de la multiplicación de dos números enteros de
longitud n. Sus complejidades oscilaban entre O (n ) y 0(n • log 2 n •
• log 2log 2n) o, lo que es lo mismo, entre O (n ) y O (n • logn • log • logn).
Se conoce como cota superior de la complejidad de un problema a la
complejidad del mejor algoritmo que se haya podido encontrar. En el caso de la
multiplicación, la cota superior es O (n • logn • log logn) , para recursos de
computación secuencial. Es posible probar, a veces, que no existe algoritmo que
pueda resolver un determinado problema sin emplear como mínimo una cierta
cantidad de recurso, a la que se llama cota inferior. Si seguimos razonando acerca
del problema de la multiplicación, convendremos en que no puede existir al-
goritmo más eficiente que el que necesitase un tiempo proporcional a n, puesto
que siendo éste el tamaño de la entrada, es evidente que, como mínimo, cada dígito
debería ser considerado al menos una vez.
¿Es posible encontrar algoritmo mejor que O (n • logn • log log „) para la
multiplicación? ¿Puede probarse la inexistencia de un algoritmo más rápido? En
suma, ¿cuál es la exacta complejidad de la multiplicación de dos números enteros?
Estas son preguntas abiertas dentro de la teoría de la complejidad.
Otra observación. El análisis de algoritmos se concentra mucha veces en un
algoritmo concreto, investigando en el interior de su orden de complejidad cual
es la dinámica interna de ésta como resultado de las diversas configuraciones de
datos. Esto conduce a evaluar medidas conocidas como casos peores, medios y
mejores, de enorme interés en la práctica. El subapartado anterior nos ha ofrecido
varios ejemplos en los que era patente una variabilidad de los tiempos de eje-
cución como producto de la configuración inicial de los datos. El lector puede
imaginar hasta qué punto la dinámica de ejecución de predicados de un algoritmo
complicado puede dificultar este tipo de análisis.
i
Definir complejidad según tipo y
número de recursos
Otros
E N BUSCA DE LA EXACTA
COMPLEJIDAD DEL PROBLEMA
Cota superior
Cota inferior
ir
Acotar complejidad para diferentes ocurrencias
de la entrada (fijados tipo y número de recursos
y el algoritmo)
535
algoritmo de ordenación Quicksort (O (n • logn)) que el de la burbuja. Sin embar-
go, el método de la burbuja se le ocurre a cualquiera, mientras que Quicksort lo
inventó Hoare, precisamente uno de los más prestigiosos científicos de la
informática. Desde una semántica antropológica, es más compleja (requiere más
o por lo menos mejores recurso intelectuales) la solución Quicksort que la de la
burbuja. En un caso estamos hablando de idear (inventar, diseñar, es un acto
creativo) una solución y, en el otro, de ejecutarla mecánicamente.
4. Problemas P, NP y NP-completos
Hemos estado hablando de algoritmos más o menos eficientes, entendiendo
que éstos son aquéllos cuyo crecimiento es polinómico. En general diremos que
un algoritmo es eficiente si existe una máquina de Turing M que lo simule en tiem-
po DTIME (n) . donde i es una constante. A la clase de algoritmos eficientes se
la denomina la clase P. Puede argumentarse, no sin razón, que un algoritmo
(n ) -limitado en tiempo, no resulta muy eficiente. Esto es cierto efectivamente,
pero en la práctica casi todos los problemas de P tienen un grado pequeño.
536
El problema principal en la teoría de los problemas intratables es, visto lo
anterior, muy fácil de definir: ¿Es NP igual a P? Este es el llamado problema P-
NP, y es tan difícil de resolver que casi nos vemos tentados a concluir que son dos
clases diferentes. Lo que sí es demostrable es que todo problema de P es un pro-
blema de NP.
Figura 7.7.
Sin embargo, la cosa no acaba ahí, ya que existe una puerta abierta que per-
mitiría demostrar que son iguales en el supuesto de encontrar la llave, si bien
también podría demostrar que son distintos en caso de demostrar que la llave no
existe. Vamos a ver esto con más detalle definiendo el concepto de completitud.
537
la cual las condiciones que deben verificarse para que M acepte la solución se
convierten en una expresión booleana. De esta forma, la simulación de M con Lsat
es como sigue: cójase una posible solución y verifiqúese que la expresión
booleana es "true". Si Lsat acepta la solución, M también acepta y viceversa, por
lo que las dos máquinas son iguales. Si la complejidad de la máquina M era T(n),
la de la nueva máquina Lsat será como mucho T(n) + log(n).
Aparte del problema de Hamilton y el de satisfactibilidad hay otros problemas
que también son NP-completos y son muy populares. Podemos mencionar unos
cuantos:
• El problema del agente de ventas: Dado un grafo, ¿cuál es 1 camino más corto
que pasa una sola vez por cada uno de los puntos del grafo?
• El problema de las particiones: Dada una lista de enteros (zl, i2,..., ik), ¿existe
algún subconjunto cuya suma sea exactamente 1/2(¿1 + i2,... + ik)?
Entre toda la variedad de problemas NP-completos, hay algunos para los que
se han realizado enormes esfuerzos en busca de un algoritmo determinista de tipo
polinómico, sin encontrarlo. Puesto que todos o ninguno de estos problemas están
en P, parece normal conjeturar que ninguno lo está. Casi parece más razonable
buscar mejorar en los algoritmos heurísticos, que pueden resolverlos con bastante
eficiencia en aplicaciones prácticas.
538
En informática, hay una tarea intermedia entre la de diseñar un algoritmo y la
de ejecutarlo por un instrumento mecánico. Es la tarea de programar y codificar
el algoritmo por medio de un lenguaje artificial. Aunque los lenguajes empleados
cada día tienden a ser de mayor potencia expresiva (lo que quiere decir que una
parte importante del trabajo de programación lo hace la propia máquina), esta
actividad todavía es mayoritariamente de carácter humano. Por lo que sabemos,
la codificación de un algoritmo puede introducir variaciones en su eficiencia de
ejecución, pero no alterar el orden de magnitud de su complejidad. En cambio,
determinadas circunstancias de esta tarea muestran una influencia profunda sobre
el número de errores cometidos, la cantidad de esfuerzo requerido y en general
sobre los costes del software. No existe una definición precisa de qué hay que
entender por "complejidad del software", viniendo éste a ser un nombre genérico
para sintetizar algunas de las mencionadas circunstancias, una especie de medida
de cuán difícil es de comprender un programa y de trabajar con él.
La complejidad del software se traduce así, de una manera difusa, en un
conjunto de recursos (en gran parte humanos) necesarios para producir software
de calidad. Algún autor la llama "complejidad psicológica del software".
Figura 7.8.
539
Se han propuesto diversas métricas para estimar la complejidad de la pro-
gramación. Terminaremos este capítulo sobre "complejidad" resumiendo la mé-
trica conocida como Física (o Ciencia) del Software y la métrica del número
ciclomático. El cuadro de la figura 7.8 resume, por analogía con medidas
literarias, las clases de complejidad de las que aproximadamente estamos hablan-
do en este apartado. Como se verá enseguida, la medida por medio de operadores
y operandos se corresponde con la Física del Software y ciertas propiedades de
grafos son el sustrato teórico del método del número ciclomático
Esfuerzo E = V/L
Figura 7.9.
El volumen del programa (figura 7.9) se mide en bits. El nivel del programaL
representa una medida de lo sucinta que puede ser la codificación de un programa.
Cuanto más elevado sea el nivel del lenguaje utilizado en el programa, tanto más
se aproxima la implementación a una llamada de procedimiento. Recordemos al
respecto la sentencia CALL MAX (A, B, MCD) frente al código del mismo
programa en PL/I del apartado 2 del capítulo 1. Por definición L=V*/V, donde V*
es el volumen del algoritmo codificado por una sentencia de llamada CALL (n2 *
suele representar el número de parámetros diferentes de entrada y salida; en el
caso del algoritmo del m.c.d. n2 * =3) y 0 < L < 1, siendo L tanto más próximo al
valor 1 cuanto más potente es el lenguaje empleado. El algoritmo (5) se podría
codificar con CALL RAIZCUA (X, B), con n2* =2, siendo B la raíz cuadrada de
541
X. Ñ y L son fórmulas predictoras de la longitud y del nivel del programa,
respectivamente.
Llama la atención la expresión empleada para el esfuerzo E que, como se puede
observar, ha sido interpretado como el número total de discriminaciones mentales
requeridas para codificar un determinado programa. Su valor, que podría tomarse
como el equivalente a un a medida de la complejidad d programación es tanto
mayor cuanto mayores son el tamaño del vocabulario y la longitud del programa
(ambos se traducen en el valor de V) y más próximo a la máquina el lenguaje
empleado. Diversos estudios empíricos demuestran la existencia de una fuerte
correlación entre E y el tiempo necesario para la programación, y asimismo entre
E y el número de errores hallados en los programas.
En cuanto al contenido de inteligencia I del programa, esta función tiende a ser
constante e independiente del nivel de codificación.
Si aplicamos el cuadro anterior de definiciones al programa (5) obtenemos los
valores de la figura 7.10.
n1 = 13
JVj = 24
«2 = H
N2 =25
n = 24
N = 49
V = 49 • log 2 24 = 224, 66
n* = 2 + 2 = 4
V* = 4 log 2 4 = 8
L = 2 • 11/13 • 25 = 0, 0676
I~4log 24 = 8
Figura 7.10.
5.2. Número ciclomático
La métrica que brevemente describiremos ahora se basa en la estructura
decisional (flujo de predicados) de los programas. A esta estructura se le asocia
un grafo orientado G. Recuérdese la figura 1.4 y las correspondencias allí
establecidas entre bloques de código y ramas de programa con nodos y arcos.
Por la teoría de grafos, se calcula el número de circuitos de control linealmente
independientes en G. Un grafo fuertemente conectado es aquel para el que existe
un camino entre cualquier pareja de nodos.
El número ciclomático V(G) de un grafo con n nodos, e arcos y p componentes
conectado es:
Figura 7.11.
543
6. Resumen
Existe un conjunto bastante grande de algoritmos demasiado difíciles de llevar
a la práctica por limitaciones de tiempo o espacio.
Figura 7.12.
544
que la clase NP es diferente de la clase P. De esta forma pueden centrarse los estu-
dios en la búsquedas de métodos no deterministas para resolver óptimamente toda
esta gama de problemas.
En paralelo con la complejidad algorítmica surge una preocupación por la
complejidad del software, correspondiente a una rama mucho menos teórica de la
informática, conocida hoy por el nombre de ingeniería del software.
En este capítulo se han presentado dos clases de métrica, la primera de carácter
lingüístico basada en la contabilidad de los operadores y operandos utilizados en
la codificación de los programas, y la segunda, en la evaluación del grafo
asociado a la estructura de control de los programas. Cualquiera de estas dos
clases de técnicas y otras muchas que se han elaborado sólo son aplicables en el
ámbito de los lenguajes clásicos de tipo imperativo y de los ordenadores de
funciona-miento secuencial según el modelo de von Neumann.
Tanto el campo de la complejidad algorítmica como el de la complejidad del
software siguen abiertos y muy activos.
545
Díaz (1982) y Balcázar, en (Gamella, 1985, pp. 61-65) describen algunos de
los campos a los que se extienden en la actualidad los trabajos relativos a la com-
plejidad algorítmica. Citando a este último, nos encontramos con parcelas dedi-
cadas:
8. Ejercicios
8.1. Buscar en la bibliografía sobre algoritmos de búsqueda y clasificación
una selección de éstos, familiarizarse con ellos y con su complejidad,
comparativamente a los vistos en este capítulo.
8.2. Aplicar la métrica de los operandos y los operadores a los códigos (2),
(3) y (4) escritos en Pascal.
8.4. Aplicar la métrica del número ciclomático a los mismos algoritmos (2),
(3) y (4).
547
8.5. Aplicar la métrica del número ciclomático a los siguientes grafos aso-
ciados a sendos programas.
8.6. Aplicar la métrica del número ciclomático a los programas de las figu-
ras 4.3 y 4.5, comparar y extraer alguna conclusión.
Parte IV
Lenguajes
1
Ideas
Generales
1. Lenguajes e informática
Ya al comienzo de este libro (tema "Lógica", capítulo 1, apartado 4) hemos
definido informalmente un lenguaje como un sistema de símbolos que permi-
te la comunicación entre personas, entre personas y máquinas o entre máqui-
nas. Hemos introducido también (en el apartado 5, que debería releerse ahora)
la terminología y los primeros conceptos de la teoría de lenguajes formales.
La importancia de la teoría de lenguajes en informática radica en la corres-
pondencia biunívoca que existe entre máquinas programables y lenguajes. A
cada máquina corresponde un lenguaje en el que se escriben sus programas; a
la inversa, a cada lenguaje de programación le corresponde una máquina que
interpreta los programas escritos con él1. La teoría de lenguajes permite desa-
rrollar de manera científica tanto la creación y la producción de programas
como el diseño de máquinas y lenguajes de programación.
Los tres capítulos centrales del tema que ahora comenzamos están dedica-
dos a presentar los conceptos básicos de la teoría de lenguajes formales y su
relación con la teoría de autómatas. Después, en el último capítulo, veremos la
utilidad de estos conceptos en los lenguajes de programación de ordenadores.
1
El término "máquina" debe entenderse aquí en un sentido abstracto. Por ejemplo, una "máquina BASIC" es
una "máquina virtual" cuyo lenguaje de máquina es el BASIC y que se materializa (se "implementa") median-
te una máquina real (un ordenador) y unos programas adecuados.
551
2. Descripciones de los lenguajes
La descripción formal de un lenguaje finito es inmediata: basta enumerar
las cadenas que lo forman. Pero si es infinito, será preciso inventar una des-
cripción finita; esta descripción será, a su vez, una cadena de símbolos combi-
nados de acuerdo con ciertas reglas (sintaxis) y con un determinado significa-
do, tanto para los símbolos como para las reglas (semántica). Por tanto, esta
cadena de símbolos pertenecerá a un metalenguaje, que servirá para describir
nuestro lenguaje. Por ejemplo, una expresión regular (tema "Autómatas", capí-
tulo 4) es una cadena del lenguaje de las expresiones regulares, que es un
metalenguaje para describir los lenguajes regulares.
Ahora bien, podemos preguntarnos si, dado un lenguaje finito cualquiera,
L <z A * , es posible siempre describirlo de manera finita. La respuesta es "no".
En efecto, sabemos (tema "Algoritmos", capítulo 6, apartado 3.1) que A* (con-
junto de todas las cadenas construidas sobre un alfabeto A) es recursivamente
numerable (a cada cadena se le puede asociar, por ejemplo, su número de
Godel), y, por tanto, cualquier L a A * también lo es. Supongamos que existe
un metalenguaje LMcA *M tal que cada cadena de L M es una representación
finita de un lenguaje sobre A*, es decir, tal que a c a d a L ( M ) < z A * , corres-
ponde al menos un xM e LM. Si tal metalenguaje existiera debería ser, como
todo lenguaje, recursivamente numerable. Esto implicaría que el conjunto de
todos los L c A * fuera recursivamente numerable. Sin embargo, existe un teo-
rema de la teoría de conjuntos según el cual el conjunto de los subconjuntos de
un conjunto recursivamente numerable (y A* lo es) no es recursivamente nume-
rable, lo que contradice la conclusión anterior y refuta la hipótesis de que exista
un LM para todo L c A *. Por consiguiente, podemos concluir que no todos los
posibles lenguajes tienen una representación finita en un metalenguaje.
En los dos capítulos siguientes estudiaremos la descripción de ciertos tipos
de lenguajes desde en punto de vista generativo: una gramática, G, es una des-
cripción metalingüística con la que se puede desarrollar un algoritmo enume-
rativo para generar las cadenas del lenguaje L(G), es decir, se puede diseñar
una máquina de Turing que haga corresponder el número 1 a la cadena el 2
ala x2, etc., de manera que genere el conjunto recursivamente numerable L(G)
= [xl,x2...}.
En el capítulo 4 consideraremos un punto de vista complementario: el del
reconocimiento, o sea, el estudio de algoritmos o estructuras de máquinas que
permiten, dado un lenguaje L y una cadena x, determinar si x e L o x £ L.
Finalmente, en el capítulo 5 abordaremos el aspecto interpretativo: un pro-
grama se escribe con el objetivo de que la máquina a la que va destinado ejecu-
te un determinado algoritmo. Para que ello sea posible es necesario que el pro-
gramador sepa con exactitud cómo la máquina va a reaccionar frente a cada una
de las instrucciones de su programa, es decir, qué significan (y entramos así en
el campo de la semántica) para la máquina las distintas cadenas del lenguaje.
552
3. Sintaxis, semántica y pragmática.
Actualmente, en la teoría de lenguajes formales, el campo de la sintaxis está
bien establecido: como veremos en el capítulo siguiente, existen metalengua-
jes (gramáticas) formales que describen con precisión varios tipos de lengua-
jes y que resultan de gran utilidad práctica en informática para el diseño de
lenguajes de programación y para el reconocimiento, traducción e interpreta-
ción de programas.
La semántica, hasta ahora, ha resultado más difícil de formalizar. En la
definición de casi todos los lenguajes de programación, la semántica se expre-
sa de manera informal, mediante explicaciones verbales en sus manuales sobre
lo que significa cada posible sentencia. La formalización de la semántica es,
sin embargo, importante desde un punto de vista práctico. Con una definición
formal de la semántica de un lenguaje se podrían elaborar métodos sistemáti-
cos de comprobación de programas, es decir, de verificar, antes de su ejecu-
ción, que los programas son correctos, en el sentido de que van a hacer lo que
se pretende que hagan Y, eventualmente, se podrían diseñar herramientas (es
decir, otros programas) basadas en estos métodos para automatizar la verifica-
ción de programas. Ello contribuiría a mejorar la productividad de los proce-
sos de producción de software y la fiabilidad de los programas. Se han pro-
puesto varios enfoques para definir formalmente la semántica de los lenguajes
de programación (los comentaremos en el capítulo 5), pero éste es todavía un
asunto sometido a numerosos trabajos de investigación.
En algunos textos sobre lenguajes de programación se habla de "pragmá-
tica", pero aún estamos lejos, no ya de disponer de una formalización, sino
siquiera de estar de acuerdo sobre lo que representa: para unos, se refiere a los
aspectos de comunicación con el usuario, para otros atañe a los problemas que
se presentan cuando se pasa de la definición formal de un lenguaje a las parti-
cularidades de las máquinas en las que los programas han de ejecutarse, según
otros trataría de los "aspectos prácticos" de la actividad de programar.
4. Dos ejemplos
Los ejemplos que desarrollamos a continuación nos servirán para introdu-
cir de una manera intuitiva algunos de los conceptos que formalizaremos en
capítulos posteriores.
Puesto que aún no hemos definido lo que es una gramática, haremos uso de
una que, más o menos vagamente, todos conocemos: la gramática del lengua-
je castellano.
Para describir la formación de sentencias (oraciones) utilizaremos catego-
rías sintácticas o sintagmas, como "nombre", "verbo", etc. (o sintagma nomi-
nal, sintagma verbal, etc.). Está claro que, si bien "nombre" es un nombre,
553
"verbo" no es un verbo. Esto es debido a que para describir el lenguaje caste-
llano utilizaremos como metalenguaje el propio castellano, y ponemos las
comillas para destacar que la palabra en cuestión se utiliza como elemento del
metalenguaje (es la diferencia entre uso y mención del lenguaje, ver tema
"Lógica", capítulo 1, apartado 5.3), La notación habitualmente seguida no es
poner comillas, sino encerrar la palabra entre paréntesis angulares: (nombre),
(verbo), etc.
Una sentencia castellana sintácticamente correcta estará compuesta por
palabras concretas pertenecientes a las diversas categorías sintácticas (uno o
varios sintagmas nominales, uno o varios sintagmas predicativos, etc.) combi-
nadas de acuerdo con ciertas reglas.
Por ejemplo, una regla puede ser:
Y otras:
España es un estado
2
El símbolo "—>" no tiene ahora nada que ver con el condicional de la lógica. En este contexto significa: "la
parte de la izquierda puede sustituirse por la parte de la derecha", o "la parte izquierda puede tener la forma de
la parte derecha".
554
(3) (Npr) —» España
(4) <SP> -> (FVtr) (SN)
(5) (FVtr) —» es
(6) (SN) -» (Det) (Ncom)
(7) (Det) -» (Art)
(8) (Art) —» un
(9) (Ncom) —> estado.
o bien, de una forma más gráfica, con un árbol llamado árbol de derivación o
árbol sintáctico (figura 1.1).
(Sentencia)
(Ncom)
España es un estado
Figura 1.1.
555
Su descomposición sintáctica, o derivación a partir de las reglas, es la indi-
cada por el árbol de la figura 1.2.
(Sentencia)
(Art) (Prep)
(Art)
I
La soberanía nacional reside en el pueblo español.
Figura 1.2.
etc., que serían sentencias correctas en la gramática definida por tales reglas.
5. Resumen
La teoría de lenguajes formales es una herramienta matemática que permi-
te abordar con rigor el diseño de lenguajes de programación y la producción
de software. Si bien existe ya una buena elaboración de la misma en el campo
de las sintaxis, queda aún mucho por hacer en cuanto a la semántica, y éste es
un aspecto de gran transcendencia práctica y económica: no basta con que los
programas sean sintácticamente correctos; es preciso que la máquina que los
interpreta haga exactamente lo que el programador pretende que haga.
557
2
Gramáticas y
lenguajes
1. Definición de gramática
Una gramática es una cuádrupla
1
En adelante representaremos con "£" a un alfabeto, porque "A" se utilizará frecuentemente como uno de los
símbolos del alfabeto auxiliar.
559
S E EA es un símbolo destacado del alfabeto auxiliar llamado símbolo inicial.
a) letras mayúsculas del alfabeto latino para los elementos de EA. (O bien,
palabras del metalenguaje castellano entre paréntesis angulares);
b) letras minúsculas del comienzo del alfabeto latino (a, b, c,...), o cifras,
para los elementos de ET. (O bien, palabras del castellano);
c) letras minúsculas del final del alfabeto latino {w, x, y, z) para los ele-
mentos de E*T;
d) letras minúsculas del alfabeto griego para los elementos de E + .
yaS ^ y/38
y diremos que la cadena y¡3 8 deriva directamente de la ya8 o bien que yaS
produce directamente y¡38 en la gramática G. (De ahí el nombre de produc-
ciones para los elementos de P.)
«i 7? <*2; «2 7? «a -i 7? ocm
Se escribirá entonces
a,1 =>
q am
m
560
diciendo que am deriva de «, , o que a¡ produce am
Por convenio, a a V a e E*
G
Siempre que sea evidente que nos referimos a una determinada gramáti-
ca , G, escribiremos => y => en lugar de => y =>
G G
L(G)= {x\xeEryS^>x}
G
4. Ejemplos
Ejemplo 4.1
Sea la gramática definida por E-¡= {0, 1}; EA - {5};
561
Por consiguiente, el lenguaje generado es el conjunto infinito
Ejemplo 4.2
EA={S,A}-, ET={a,b]
Aquí, L(G) está compuesto por cadenas que contienen (abb) y (baab)
intercambiándose y reproduciéndose cualquier número de veces, y terminando
siempre la cadena con el símbolo a.
Ejemplo 4.3
Ea = {S, A, B} ; EJ [a, b)
S aB A bAA
S^bA B —> b
P=
A a A^bS
A^aS A - » aBB
Ejemplo 4.4
ET = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
EA = {(número), (dígito)}
S . = (número)
(número) —> (dígito) (número) (1)
(número) -» (dígito) (2)
(dígito) (3)
(dígito) -> 1 (4)
(dígito) -> 2 (5)
p _ V (dígito)
\UIglLU/ -> 3J (6)
^ V
(dígito) —> 4 (7)
(dígito) —» 5 (8)
(dígito) —» 6 (9)
(dígito) -> 7 (10)
(dígito) -> 8 (11)
(dígito) -> 9 (12)
Como los símbolos terminales son los diez dígitos decimales, el lenguaje
que se obtiene es el conjunto infinito de cadenas que representan en decimal a
los números naturales.
Obsérvese que es la regla (1) la que permite obtener una cadena de cifras
de cualquier longitud.
Ejemplo 4.5
Ev = {a,b} ; Ea = {>1,5}
563
Un análisis del tipo de sentencias que pueden derivarse nos lleva fácilmen-
te a la conclusión de que todas terminan con el símbolo b, por aplicación de
(4), y todas empiezan por a, pudiendo tener en medio cualquier número de a
seguido de cualquier número de b. Obsérvese que para el lenguaje así genera-
do puede darse una expresión regular: L(G) = aa*bb*.
ax A «2 «i /? «2
con A eEA; ax, c^ e E* ; j8 e E+
564
tipo sensible al contexto (lo sería si fuera abA —> abab); sin embargo, la lon-
gitud del antecedente es menor o igual que la del consecuente en todas las
reglas, por lo que habrá una gramática equivalente sensible al contexto. En el
siguiente capítulo veremos cómo se puede encontrar.
A->/3
A aB o A —>a
6. Jerarquía de lenguajes
Llamaremos lenguaje de tipo 0 al generado por una gramática de tipo 0,
lenguaje de tipo 1 ó sensible al contexto al generado por una gramática de tipo
1, lenguaje de tipo 2 ó libre de contexto ó C-lenguaje al generado por una gra-
565
mática de tipo 2, y lenguaje de tipo 3 ó regular ó ^-lenguaje, o también, len-
guaje de estados finitos al generado por una gramática de tipo 3.
Según se han definido las gramáticas, es evidente que toda gramática
regular es libre de contexto, toda gramática libre de contexto es sensible al
contexto, y toda gramática sensible al contexto es de tipo 0. Por consiguiente,
si llamamos {L(G3)}, {L(G2)}, {L(G1)} y {LfGOj} a los conjuntos de lengua-
jes de cada tipo, tendremos que:
Teorema 7.1.
Si G es una gramática de tipo 1, 2 ó 3, puede encontrarse otra gramática
equivalente, G¡, de tipo 1,2 ó 3 respectivamente, tal que L(G¡) = L(G), y tal
que su símbolo inicial, Sl , no aparece en el consecuente de ninguna regla de
G1.SiG = (ET,EA,P ,S),
= (Et , Ea U {$!},/>!, 5 ! )
donde
P i = P U { a | ( ^ a ) e P )
Demostración:
a) Supongamos que S x, y sea S^a la primera regla utilizada en esa
G y siendo
b) Supongamos que 5, => B la primera regla utilizada
i
en Gi.
Ejemplo:
Sea G, definida por EA= { S }; ET= {0,1}; P = { ( 5 - > 0 5 1 ) ; ( 5 - > 0 1 ) } .
567
con lo que L (G2) = L (G) U { X } = { 0" 1" \n > 0}.
8. Resumen
En este capítulo hemos definido los conceptos de gramática, lenguaje gene-
rado por una gramática y gramáticas equivalentes. Hemos visto la clasificación
de las gramáticas según las restricciones impuestas a sus producciones y cómo
esta clasificación da lugar a una jerarquía de lenguajes. Finalmente, hemos
estudiado la manera de modificar una gramática para que el lenguaje conten-
ga la cadena vacía sin cambiar de tipo.
568
falta de un formalismo para estudiar estos mecanismos había inclinado pre-
viamente a ciertos lingüistas de la escuela conductista a negar tal propiedad,
y a otros, como Saussure, a considerarla como algo ajeno al campo de la lin-
güística (Chomsky, 1967).
En el campo de la informática, poco después de la aparición de las prime-
ras publicaciones de Chomsky, el concepto de gramática formal adquirió gran
importancia para la especificación de los lenguajes de programación ; con-
cretamente, se definió formalmente la sintaxis del lenguaje ALGOL 60 (con
ligeras modificaciones sobre su versión primitiva) mediante una gramática
libre de contexto (Naur, 1963). Ello condujo rápidamente, de una manera
natural, al diseño riguroso de algoritmos de compilación (Randell y Russell,
1964).
Desde una perspectiva bastante ambiciosa, hace tiempo se piensa que,
puesto que todos los lenguajes de programación son lenguajes artificiales sus-
ceptibles de formalización, la teoría de lenguajes podría ser la base de una
"teoría general de la programación" (Harrison, 1965) o de una "ciencia de la
programación" (Gries, 1981).
Finalmente, y enlazando con el campo de la lingüística, la teoría de len-
guajes es de gran utilidad para el trabajo en un campo de la inteligencia artifi-
cial: el procesamiento de lenguajes naturales (comprensión, generación y tra-
ducción) (Hirst, 1981; Tennant, 1981; Carbonell et al., 1981).
En cuanto a orientaciones bibliográficas para estudiar con mayor profundi-
dad la teoría de lenguajes formales, tres libros clásicos y recomendables son el
de Hopcroft y Ullman (1969), el de Harrison (1978) y el de Gross y Lentin
(1967). El ejemplo 4.2 (como también los ejemplos 4.3 y 5.4 del capítulo
siguiente, relacionados con él) está tomado del primero, donde pueden encon-
trarse algunos detalles y demostraciones que aquí omitimos. En otra obra pos-
terior de Hopcroft y Ullman (1979) se incluyen también aspectos de la teoría
de la computabilidad, y en la misma línea se orienta el libro, más completo, de
Denning et al. (1978)
Para referencias más modernas y más ligadas a la aplicación de la teoría a
los lenguajes de programación, véase el apartado 7 del capítulo 6.
Ejercicios
10.1 Muchas veces interesa que los árboles de derivación en una gramática
sean binarios, es decir, que de cada nodo sólo puedan salir uno o dos arcos.
¿Cómo deberán ser las reglas de escritura para que esto sea posible? Modificar
la gramática de los ejemplos del capítulo 1 para que sus árboles sean binarios.
569
P = {(5 -> OA); (A -> OA); (A 15); (A -> 0)},
10.3 Definir una gramática que permita generar todos los números raciona-
les escritos en decimal con el formato: (signo) (parte entera) (parte fracciona-
ria).
10.6 Modificar las gramáticas de los ejemplos del apartado 4 para que se
obtengan los mismos lenguajes con la cadena vacía.
3
De algunas
propiedades de
los lenguajes
formales
1. Introducción
En el estudio de los lenguajes se plantean problemas que tienen o no solu-
ción dependiendo del tipo de gramática. Por ejemplo, para una gramática, G,
de reglas sensibles al contexto, el problema de saber si L(G) es vacío, finito o
infinito es, en general, indecidible, mientras que para una gramática libre de
contexto es decidible, es decir, existe un algoritmo que, aplicado a G, produce
una de las tres repuestas; naturalmente, este problema será indecidible para las
gramáticas de tipo 0 y decidible para las regulares. Otro ejemplo es el de ave-
riguar si dos gramáticas son equivalentes, problema sólo decidible para las
gramáticas regulares.
Al aumentar el grado de generalidad de la gramática, es decir, al ir desde el
tipo 3 hacia el tipo 0, el estudio se hace más complejo y aumenta el número de
problemas indecidibles.
573
Desde el punto de vista de aplicación práctica tanto a los lenguajes natura-
les como a los de programación, son particularmente importantes las gramáti-
cas libres de contexto. Este capítulo se dedica, esencialmente, a dos caracte-
rísticas asociadas a tales gramáticas: la recursividad y la ambigüedad.
La recursividad, como veremos, es una propiedad válida no sólo para las
gramáticas libres de contexto, sino también para las sensibles al contexto, ya
que es una consecuencia del no decrecimiento de las cadenas. La ambigüedad
sólo puede definirse y estudiarse cómodamente para las gramáticas de tipo 2
(y 3), en las que pueden describirse las derivaciones mediante árboles.
En aras de la brevedad omitiremos las demostraciones de algunos teoremas,
que pueden encontrarse en la bibliografía referenciada en el apartado 9.
Teorema 2.1.
Dada una gramática G, con reglas de longitud no decreciente, puede
encontrarse otra gramática G2 equivalente a G, cuyas reglas son sensibles al
contexto.
Demostración
Sea A —> ¡5 una regla de G , , y sea
a = P\ Pi - Pg y P = <?2 -fy+m
PiPiPi-P^ ->
574
por
R
P i P i P i - P £ - P i P 3 - P f ) -1 Pe
Rq2q3-qe-iPe^> RpiPz- P e - i P e
Rqi
Es evidente que:
pipi-p¿ ^ qxqt-q^+m
b) Al ser R un símbolo auxiliar no pueden producirse más sentencias que
las que pueda producir a —> ¡3.
c) Las reglas introducidas sustituyen un px por un símbolo o una cadena en
un contexto. Por tanto, son del tipo sensible al contexto, salvo si px e Er. En
este caso, sustituimos por e EA e introducimos la regla terminal P~> pv
Ejemplo:
Consideremos el ejemplo 4.2 del anterior capítulo. Sustituiremos la regla
abA —> baab por:
abA —» Rba
RbA -> RaA
RaA —» Raab
Raab —> baab
S —> P{ P2 AS S
P I PIA -+RP2A A
P= RP2 A R Pl A P^a
RPL A ~^RPlPlP2
RPiPfi
575
3. Recursividad de los lenguajes sensibles al
contexto
Una gramática es un algoritmo para generar un lenguaje, pero un problema
de gran importancia es el del reconocimiento, es decir, dados un lenguaje
L c E* y una cadena x e E*, ¿existe un algoritmo para determinar si l e i ó
x £ L? Si, por ejemplo, L es un lenguaje de programación y x un programa, es im-
portante poder determinar si el programa es sintácticamente correcto (x e L) o
no ( i g L). El problema del reconocimiento está íntimamente ligado al con-
cepto de recursividad (ver tema "Algoritmos", capítulo 6). En efecto, decir que
un lenguaje L c E* es recursivo es lo mismo que decir que existe un algoritmo
para calcular la función característica de todo x e E*, o, lo que es lo mismo,
para determinar si x e L o x € L.
Teorema 3.1.
Todo lenguaje generado por una gramática de reglas sensibles al contexto
es recursivo.
Aunque no daremos una demostración de este importante teorema, puede
fácilmente intuirse que es una consecuencia de la propiedad de no decreci-
miento. En efecto, un lenguaje de tipo 0 es recursivamente numerable, ya que
existe un algoritmo (la gramática de tipo 0) para generar sus elementos (sen-
tencias). Dado un elemento x e L, podemos compararlo con cada uno de los
elementos generados hasta comprobar que coinciden, pero si x£ L habría que
generar las infinitas sentencias para ver que efectivamente x g L ; es decir, en
general, un lenguaje de tipo 0 no es recursivo. Sin embargo, si el lenguaje
cumple la propiedad de no decrecimiento (tipo 1 en adelante), tenemos un
algoritmo para generar primero todas las sentencias de longitud 1, luego las de
longitud 2, etc., si lg (x) = £ , generaremos todas las sentencias de longitud C,
y si x no se encuentra entre ellas, entonces x £ L.
Podemos preguntarnos si la inversa es también cierta, es decir, si todo len-
guaje recursivo puede ser generado por una gramática sensible al contexto. La
contestación es "no":
Teorema 3.2.
Existen lenguajes recursivos que no son sensibles al contexto.
576
Definición 4.1.
Un árbol es un conjunto finito de nodos unidos por arcos orientados (dire-
mos que un arco sale del nodo n¡ y entra en el nodo nj ), cumpliéndose tres
condiciones:
Definición 4.2.
Dada una gramática libre de contexto G = ( EA, ET, P, S ) un árbol es un
árbol de derivación o árbol sintáctico en G si:
Ejemplo 4.3
EA = Et= {a,b}
577
S aB (1) A -> a (5)
S -> bA (2) A —> bAA (6)
P= S -> aBS (3) B b (7) '
S bAS (4) B aBB (8)
a B S
b A
Figura 3.1.
a B B
b b
Figura 3.2.
Teorema 4.4.
Dada una gramática libre de contexto, G, si y sólo si existe un árbol
de derivación en G con resultado a.
Ejemplo 5.2
Los árboles de derivación suelen utilizarse en lingüística para el análisis
sintáctico de oraciones. A la oración (ambigua) "Juan ve a Luis con gafas"
puede corresponderle el árbol de la figura 3.3a o el de la figura 3.3b, según se
interprete que es Juan o Luis, respectivamente, quien usa gafas.
V OI P NC
P NP
P NC
Figura 3.3.
579
Ejemplo 5.3
Consideremos la gramática definida por:
Ea = ((EA)}; ET = { | , + , * } ; S = (EA)
Si admitimos que una sucesión de n " |" representa el número natural n, esta
gramática genera sentencias que representan combinaciones de los números
naturales con las operaciones de suma y producto. Consideremos la sentencia
| +1 |*[ | |; la derivación puede hacerse mediante el árbol de la figura 3.4.
Figura 3.4.
(EA) + (EA)
Figura 3.5.
Ejemplo 5.4
La gramática del ejemplo 4.3 del capítulo 2 es ambigua. En efecto, la sen-
tencia aabbab, por ejemplo, puede derivarse según indican los dos árboles de
la figura 3.6.
B B
'l\ ' W
B B,
B B
b b S S b
B
A A
a
Figura 3.3.
581
Sin embargo, la gramática del ejemplo 4.3 de este capítulo es equivalente a
ella y no ambigua, por lo que el lenguaje generado (conjunto de cadenas que
tienen igual número de a's que de b's) no es inherentemente ambiguo. La deri-
vación de la misma cadena en esta segunda gramática se representa por el
árbol de la figura 3.7.
S
a B S
b b b
Figura 3.7.
Ejemplo 5.5
Una ambigüedad similar a la del ejemplo 5.3 puede ocurrir en las expre-
siones aritméticas decimales. Con una gramática definida por
EA = {(E>, (CTE), (DIG)}
ET= { 1 , 2 , 3 , 4 , 5 , 6 , 7, 8, 9, +, *}
S = {(EA)}
y las reglas
(EA) (EA) + (EA)
(EA) (EA) * (EA)
— >
(EA) (CTE)
— >
(CTE) (DIG)
(DIG) 0
— >
(DIG) 1
— >
(DIG) 2
— >
(DIG) - » 3
(DIG) - » 4
(DIG) 5
(DIG) 6
— >
(DIG) 7
— »
(DIG) 8
— >
(DIG) 9
— >
el lector puede fácilmente comprobar (de igual manera que en el ejemplo 5.3)
la ambigüedad de, por ejemplo, " 1 + 2 * 3 " .
Sabemos que una notación eficaz para eliminar la ambigüedad en casos como
éste es el uso de los paréntesis. Podemos incluir esta posibilidad en nuestra gra-
mática ampliando ET con "(" y ")" y P con la producción "(EA) -> ((EA))".
Ahora, existe un árbol único para "1 + (2*3)" y otro para "(1 + 2)*3". Pero ello
no impide que la sentencia "1 + 2*3" siga siendo válida en nuestro lenguaje y
ambigua.
Sabemos también que la ambigüedad en una sentencia como "1 + 2*3" se
elimina estableciendo una prioridad entre los operadores. Concretamente, se
suele dar prioridad a "*" sobre "+", de manera que la sentencia se interpreta
como "1 + (2*3)". Pues bien, podemos establecer una gramática equivalente a
la anterior que refleja esta prioridad y que, por tanto, no es ambigua. Para ello,
ampliamos EA con dos nuevos símbolos: "(TERM)" (término) y "(FACT)"
(factor), y definimos las nuevas producciones así:
(EA) (EA) + (TERM)
(EA) (TERM)
(TERM) (TERM)* (FACT)
(TERM) (FACT)
(FACT) (CTE)
(FACT) ((EA))
(CTE) (CTE) (DIG)
(CTE) (DIG)
(DIG) 0
(DIG) 9
Ahora, la sentencia 1 + 2 * 3 sólo tiene un árbol, el de la figura 3.8. Y, en
general, "*" tiene siempre precedencia sobre "+", excepto cuando se usan
paréntesis para invalidar tal precedencia.
(EA)
(E/y
(TERM)
(TERM)
(TERM) (FACT)
(FACT)
(FACT)
(CTE) (CTE)
(CTE)
(DIG) (DIG) (DIG)
+ 2 * 3
Figura 3.3.
583
El problema de la ambigüedad, en general, es indecidible:.
Teorema 5.6.
No existe un algoritmo que, aplicado a una C-gramática arbitraria, permi-
ta decidir si la gramática es ambigua o no.
6. Resumen
Los lenguajes de tipo 0 son recursivamente numerables pero no todos son
recursivos. Los lenguajes de tipo 1 (y 2 y 3) son recursivos: existe un algorit-
mo para decidir si x e L ó x € L. Sin embargo, hay lenguajes recursivos que
no son de tipo 1. Es decir:
584
8. Ejercicios
8.1 Dada la gramática definida por
EA=[S}-,ET= { 1 , 2 , 3 , 4 , 5 , 6 , 7, 8,9}
S -> 125
12 -» 345
P=
45 -» 678
S ^ 9
S OA B -> 150
P= S ^ IB fi 0
A OS
8.3 ¿De qué tipo es una gramática cuyas reglas son todas de la forma A —>
B ó A —> x, con A, B e EÁ , x e ?; demostrar que siempre puede encon-
trarse una gramática regular equivalente.
S —> aSa
S bSb
P IH S —» aaSaa >
S c
5 —» aSa
P2= S ->
5 -» c
i
585
es equivalente a Gj y no es ambigua. Comprobarlo haciendo algunas deriva-
ciones. Describir informalmente la forma general de las sentencias del lengua-
je.
8.5 Definir una gramática para las expresiones aritméticas como las del
ejemplo 5.5, pero tal que "+" tenga preferencia sobre "*".
8.6 Definir una gramática para expresiones algebraicas que incluya tanto
"constantes" como "identificadores" (ver el ejercicio 10.4 del capítulo anterior).
4
Lenguajes y
Autómatas
1. Introducción
En este capítulo vamos a plantear el problema del reconocimiento de len-
guajes desde un punto de vista material, ya que estudiaremos las relaciones
entre el tipo de lenguaje y la estructura de la máquina capaz de reconocerlo;
estas relaciones pueden enfocarse en dos sentidos:
589
tos es precisamente la clase de lenguajes que pueden ser generados por una
gramática de tipo 3 (regular), y análogamente para las MT y las gramáticas de
tipo 0. Para los dos tipos intermedios de gramática definiremos unos autóma-
tas que pueden considerarse como restricciones de la máquina de Turing o
como extensiones del autómata finito. Tendremos así una jerarquía de máqui-
nas paralela a la jerarquía de lenguajes 1 .
Reflexione el lector en el hecho de que las "clases de lenguajes" (la clase
de los lenguajes generados por una gramática regular, la clase de los lenguajes
reconocidos por un autómata finito, etc.) son subconjuntos de P(E*) (conjun-
to de las partes de E*).
El desarrollo completo de las ideas expuestas exige la demostración de una
serie de teoremas acompañada de las correspondientes construcciones (dada
una gramática de tipo 0, diseñar la correspondiente MT y viceversa, etc.) que
alargaría excesivamente este tema, por lo que nos contentaremos con desarro-
llar únicamente el caso más sencillo (gramáticas regulares y autómatas fini-
tos), limitándonos a enunciar los teoremas en los otros tres.
590
Definiremos los estados finales de aceptación como aquellos para los que
la función h es "stop", siendo la h del estado anterior "1". Tendremos así un
conjunto FAc.Q de estados de aceptación:
2.5 Conclusión
El teorema MT1 viene a decir que { L(G0) } c { L (RUR) } , y el MT2, que
{ L (i?MT) } c { L(G0) }. Además, sabemos que la clase de lenguajes recono-
cibles por un 7?mt coincide con la clase de los lenguajes recursivamente nume-
591
rabies (esto es una consecuencia de la hipótesis de Turing) y que los lenguajes
recursivos son un subconjunto de éstos, luego, como conclusión, escribiremos:
C
{ ^recurs. ) { ^recurs, num.) = { L (#MT) } = { L(G0) }
cadena de entrada
# #
Figura 4.1.
592
Como las gramáticas de tipo 1 generan lenguajes recursivos, siempre exis-
tirá también R\hh tal que L (R'ALh ) = E*-L (Gl) .
3.5 Conclusión
De los teoremas anteriores deducimos:
{ L (Rall )} = { L (Gl)}
!
— > pn+l • pn
pn pn • pn-1
• • •
• •
•
• •
• •
• •
•
pi P' P1 pi
Pila inicial Pila despues Pila inicial Pila despues
de introducir de extraer
Figura 3.3.
593
El símbolo " —»" en la figura indica en cada momento cuál es la "cabeza"
o "cima" de la pila 2 . x
CE)
P«
P'
Figura 4.3.
4.5 Conclusión
De los teoremas enunciados se desprende que
{ L (Raf) } = [L (G2) }
595
te con la clase de lenguajes que pueden ser generados por gramáticas de tipo 3
ó regulares. Para ello tenemos que recurrir a un concepto auxiliar: el AF no
determinista. Su necesidad aparece claramente teniendo en cuenta cómo se
establecen las relaciones entre gramáticas de tipo 3 y autómatas. En efecto, si
en un AF existe una transición del estado A al estado B bajo el efecto de la
entrada e, veremos que la gramática correspondiente contiene la producción
A —» eB, y a la inversa. Ahora bien, nada impide que una gramática regular con-
tenga simultáneamente las reglas A—>eB y A —» e C , lo que nos lleva a con-
siderar la posibilidad de que del estado A con entrada e se pase bien al estado
B, bien al C. Un AF en el que tal cosa puede ocurrir se llama no determinista.
Quede bien claro que no es la idea de probabilidad la que aquí interviene. El AF
no determinista debe ser considerado con un concepto abstracto, desprovisto de
interpretación física. (El autómata estocástico estudiado en el tema
"Autómatas", capítulo 5 apartado 3, podría verse como un autómata no deter-
minista si atribuimos probabilidades de manera consistente a las producciones.)
Definición 5.1.1.
Un autómata finito no determinista es una quíntupla
f.EXQP(Q)
Es decir, f{e, q) = [qa, q¡, q^} <z Q . (Obsérvese que puede ser f(e, q) = 0.)
Un reconocedor finito no determinista se define siguiendo la misma línea
que en el caso determinista: se considera un conjunto de estados finales, F, un
estado inicial, qlt y
f(X,q)={q}-,f(x1x2,q)= ^J f(x2,qk)
<7*e n
M.q)
Ejemplo 5.1.2.
Sea el RFND definido por
a b
!
ql ¡ {q2,q3) 0
q2 i 0 {q2,qA)
0
© \
f ( a , q = {q2,q3}
f (ab, q¿ =f [b, q2} U f [b, q3] = {qz, qA)
f (abb, qj = f [b, q2} U f {b, q4} = {q2, qA}
/ (abba, = f {a, q2} U / {a, qA) = {qA}
f (abbab, = f [a, q4} = 0
597
5.2 Lenguaje aceptado por un reconocedor
finito no determinista, y equivalencia con
algún reconocedor finito determinista
Definiremos el lenguaje aceptado por un RFND como el conjunto de cade-
nas para las cuales la función de transición conduce a un subconjunto de Q
dentro del cual se encuentra al menos un estado final:
Teorema 5.2.1.
Para lo reconocedor finito no determinista, RFND = (E, Q,f, qu F), puede
construirse un reconocedor finito determinista, RF = (E, Q' , f \ , q\, F'), tal que
L(RF) = L(RFND).
Hagamos: Q' = P(Q) (de modo que RF tendrá, en general, card (£>') =
2card(0 estados). Al estado de Q' que corresponda a [qa, qb, ..., q^ } lo deno-
taremos [qa,qb, ...,
f'(e,[qa,...,qp]) = [qm,...,qk] si y sólo si
f(e, { qa,..., q¿}) = { qm, ..., qk } .
(Es decir, se calcula/'(e, q') aplicando/a cada estado q de los que figuran
en q' y haciendo la unión de todos los resultantes.)
<7'i=Ui]
F' = {q'eQ' \ qfeq> y qfeF'}
(Es decir, para q' sea estado final basta que uno o más de los estados de Q
que lo componen sea final.)
Para demostrar que ambos autómatas aceptan el mismo lenguaje bastará
comprobar que, para todo x e E*, f ' (x, q{) e F' si y sólo si / ( x , q{) contie-
ne un estado (o varios) ¡E F , y, teniendo en cuenta la definición de F\ esto
será evidentemente cierto si demostramos que
Por tanto,
/' ( xe, q\) = [qm,..., qk] si y sólo si f(xe, q¡) = {qm,..., qk)
Ejemplo 5.2.2.
Tomemos el RFND del ejemplo 5.1.2. Siguiendo la construcción del
Teorema 5.2.1, el RF tendrá, en principio, 24 = 16 estados:
599
Q' = {0, [ft], [ft], [ft], M - [ft, ft] - [ft , ft, ft , ft]}
= [ft]
^" = {[ft], [ft, ft], [ft, ^4]» [ft, 94]. [ft, ft> ft], - [ft, ft, ft, ft] }
0 0 0
[ft]
[ft]
ta2, ft]
0
0
[ft, ft]
[ft] ta3] [ft]
m taJ 0
[ft, ft] [ft, ft] [ft, ft]
— >
[ft, <73] ta2. ft] [ft]
[ f t , ft] [ft, ft, ftl 0
[ft> ft] [ft] [ft. ft]
[ft. 94] [ft] [ft. ft]
ta3, ft] ta3, ft] [ft]
- > tal. ft. ft] [ft. ft] [ft, ft]
tai, ft, ^4] [ft, ft, ft] [ft, ft]
tai. ft.94] [ft.ft,ft] [ft]
— >
ta2.93. <74] [ft, ft] [ft, ft]
- > tal. ft> ft, <?4] [ft, ft. ft] [ft, ft]
Ahora bien, en un RF los estados que no son accesibles desde el inicial pue-
den eliminarse. Así, eliminamos [q2] porque no lo vemos aparecer dentro de la
tabla, y lo mismo [q^ q2\, etc. (los señalados con una flecha). Obsérvese que
[q2, ft, q4] sólo es accesible desde otros que previamente han sido eliminados
por lo que también puede eliminarse, y lo mismo ocurre con q4].
Naturalmente, el único del que no puede prescindirse en ningún caso es
0 en este caso, no puede eliminarse, ya que es accesible desde [qJ (y desde
ta4])- Finalmente, de los 16 estados nos hemos quedado con 6, y el resultado
puede representarse en forma de diagrama de Moore según indica la figura 4.5.
Comprobemos que el lenguaje aceptado es el mismo del RFND de partida
(expresión regular a (a* + b*) ba*) . Al estado final [q2, qA\ sólo podemos ir
pasando por [q2, ft]; tenemos así que las cadenas aceptadas en [q2, q4] tienen
por expresión regular: abb*\ a [q4] puede llegarse por [q2, q4] (abb*aa*) o por
[<73] (aaa*ba*).
Figura 4.5.
601
E = Et= {a„ a2, ..., an}
Q = EAU[X} = {AI,A2,...,AN,X}
F=[X]
q1 = S
Si (Aj —> ay) e P, entonces X e f (dp A¡)
Si (A¡ —> a¡Ak) e P, entonces Ake f (a¡, A¡)
(VA¿ G (/(A,-,X) = 0 )
5 fljA!
A!
• —> a 2•A 2
• •
• •
AT G / ( F L T , <?,)
A•2 G f{a2 •
, AJ
• •
• •
e f(akl,Ak_2)
Xe f(ak,AkA)
S^aS
S^aA
P =
A^bA
A^b
El correspondiente RFND
Figura 4.6.
a b
0 0 0
[5] [5, A] 0
-» [A] 0 IA,X\
— > [X] 0 0
[S,A] [S,A] [A,X\
[S,X] [5, A] 0
[A,X] 0 [A,X\
[.S.A.X] [S, A] [A,X\
603
Eliminamos los estados [A], [ X ], [ S, X ], [ S, A, X ], inaccesibles desde
[ S ], y resulta el diagrama de Moore de la figura 4.7.
© a
a
b b
a
a, b
Figura 4.7.
EA = Q;ET = E;S = qx
f ( a , 0 ) = f ( b , 0 ) = 0.
S-^aA
A aA
A^bB
A^b
B^>bB
fi -> Z>
Esta gramática tiene un símbolo auxiliar (B) y dos reglas más que aquélla
de la que habíamos partido, aunque, naturalmente, ambas deben ser equiva-
lentes. La diferencia se ha originado en el paso a través del RF determinista.
El lector puede extender la construcción del teorema AF2 al caso más general
de RFND, y aplicarla al ejemplo 5.3.1 para ver que entonces sí se llega a la
misma gramática original.
5.5 Conclusión
Según el teorema AF1, [L (G3)} <= {L (RF)}, y según el AF2, [L (RF)} c
{L (G3)}. Además, del tema "Autómatas" (capítulo 4, apartado 4.4.1; teorema
de análisis) sabemos que {L (RF)} = {Lregulares}. En resumen:
605
6. Jerarquía de autómatas
Paralelamente a la jerarquía de lenguajes, aparece una jerarquía de autó-
matas, desde la MT hasta el AF. Para compararlos puede utilizarse como cri-
terio la capacidad de memoria de cada uno.
La MT dispone, sobre la cinta, de una capacidad ilimitada de casillas para
memorizar una cantidad ilimitada de símbolos.
La cinta de un ALL es también ilimitada, pero para una determinada cade-
na de entrada, x, de longitud t = lg (x), sólo puede utilizar t casillas . Además,
habrá que añadir a esta capacidad variable de memoria (dependiente, en cada
caso, de cada entrada), una capacidad fija, n, que corresponde a la capacidad
de la unidad central para memorizar estados. En resumen, la memoria de un
ALL es una función de la longitud i de la cadena de entrada: 6 + n . La forma
lineal de esta función justifica el nombre del autómata.
El AP sólo puede utilizar la cinta de entrada para leer, pero dispone de una
cinta de trabajo o pila potencialmente ilimitada que le sirve de memoria. Aquí
también puede estimarse, para una longitud í de la cadena de entrada, un lími-
te superior de la memoria a utilizar. En efecto, si la cadena más larga que
puede escribirse en la pila como consecuencia de la lectura de un símbolo de
entrada tiene longitud k, la capacidad total de memoria será la suma de la parte
variable (pila): kt y de la parte fija, n\ en total, kt + n . Esta es también una
función lineal de i , por lo que del AP puede también decirse que es un autó-
mata limitado linealmente, pero con dos restricciones importantes: la cinta de
entrada sólo se desplaza en un sentido, y la memoria tiene estructura de pila
(si se quiere recuperar un símbolo que no está en la cima, hay que borrar toda
la información comprendida entre la cima y el símbolo, cosa que no ocurre con
la MT ni el ALL).
La capacidad de memoria de un AF es fija e independiente de la cadena de
entrada.
Finalmente, es preciso que mencionemos un punto importante que, al omi-
tir la demostración de la mayoría de los teoremas, hemos pasado por alto: que
los autómatas de que venimos hablando son, en general, no deterministas, es
decir, que la función de transición de la unidad de control tiene la forma que
veíamos en el AF no determinista. Esto solamente serviría para demostrar los
teoremas, y no tendría mayor importancia, si en todos los tipos de reconoce-
dores ocurriese lo que en el RF: que para todo RFND puede encontrarse un RF
que acepte el mismo lenguaje, pero no es así:
606
son no deterministas. Por supuesto, para todo /?ALLND puede diseñarse un /?MT
que acepte el mismo lenguaje; lo único que ocurre es que la longitud de cinta
necesaria en el /?MT (determinista) puede ser una función exponencial de la
longitud de la cadena de entrada, en lugar de lineal, como en el ^ ALLND .
c) En el AP, se sabe que { L (/?AP)} c: { L (/?APND) }, y, es más, se conoce
el tipo de gramáticas correspondientes a los /?AP deterministas, que son una
particularización del tipo general de gramáticas libres de contexto, llamadas
gramáticas deterministas, y que, entre otras propiedades, no son ambiguas.
7. Resumen
La figura 4.8 resume las principales conclusiones de este capítulo.
Figura 4.8.
607
equivalencia entre lenguajes aceptados por MT y lenguajes de tipo 0 fue
demostrada por Chomsky (1959).
El nombre y el concepto de ALL fueron introducidos por My hill (1960).
La generalización al caso no determinista y la equivalencia con las gramáticas
sensibles al contexto se deben a Kuroda (1964).
Oettinger (1961) fue el primero en definir formalmente el AP, y Chomsky
(1962) y Evey (1963), independientemente, demostraron su relación con los
lenguajes libres de contexto.
Como bibliografía de consulta son recomendables los mismos libros cita-
dos en los anteriores capítulos, y, especialmente, los de Hopcroft y Ullman
(1969, 1979).
9. Ejercicios
9.1 Hallar una gramática regular que genere el lenguaje correspondiente al
RF del ejemplo 5.2.2. Partir del RFND del ejemplo 5.1.2 y obtener otra gra-
mática, equivalente pero más sencilla.
a = 00* + 10*10*
S 1A A 1 '
S -> ÍB B->1A
< A->0A B -> 1C
A —> 0C B ->1
, A —> 1C C-> 1
dar una expresión regular del lenguaje generado por ella y diseñar un circui-
to secuencial con biestables JK que sirva como reconocedor de tal lenguaje.
608
9.5 Repetir el ejercicio anterior para la gramática
LR = {x \ xR e L}
es también regular
609
5
Aplicaciones a
los lenguajes de
programación
1. Lenguajes, traductores e intérpretes
En los tres capítulos anteriores hemos presentado los fundamentos de la
teoría de lenguajes formales y su relación con la teoría de autómatas. Veremos
ahora cómo estos conceptos teóricos se aplican en la práctica a la problemáti-
ca de la programación de ordenadores. El asunto es demasiado complejo y
extenso como para pretender darle aquí un tratamiento completo. Por otra
parte, es bastante probable que el lector tenga algunos (o muchos) conoci-
mientos previos sobre programación de ordenadores. Por todo ello, nos limi-
taremos a apuntar las principales ideas, remitiendo a las orientaciones biblio-
gráficas del apartado 7 a quien desee profundizar en alguno de los aspectos
comentados.
Si L es un lenguaje de programación, xe L será un programa escrito en ese
lenguaje, programa que corresponderá a algún algoritmo (tema "Algoritmos",
capítulo 2) y que se habrá escrito para resolver algún problema. Entonces, lo
que interesa es disponer de una máquina que ejecute x. Llamaremos intérpre-
te de L1 a una máquina, M, que reconoce si x e L, y, en caso afirmativo, lo eje-
cuta. Y diremos que L es el lenguaje de máquina de M.
611
Ahora bien, si afrontamos lo que ocurre en la realidad, nos encontramos
con que los lenguajes de máquina de los ordenadores resultan prácticamente
inutilizables para su uso directo. Codificar los algoritmos en un lenguaje cuyos
únicos símbolos son "0" y "1" sería algo excesivamente tedioso para el pro-
gramador, y de un coste prohibitivo por la cantidad de trabajo necesario, no
sólo para la escritura de los programas, sino también para su depuración y
mantenimiento. Por eso, desde los tiempos de los primeros ordenadores, uno
de los campos de mayor actividad en informática ha sido el relacionado con el
diseño de lenguajes que hagan más fácil y más productiva la tarea de progra-
mar. Escrito un programa en uno de estos lenguajes, Ll, antes de que pueda
ejecutarse en una máquina, M2 , cuyo lenguaje de máquina es L2, es preciso
traducirlo. Un traductor de Ll a L2 , 712, es un programa que recibe como
dato de entrada* e Ll y, tras comprobar que, efectivamente, x e Ll, produce
como resultado y e L2. Naturalmente, si este traductor ha de ejecutarse en M2
deberá estar escrito en L2 (o bien, haber sido traducido previamente a L2 desde
el lenguaje en que fue escrito). El conjunto formado por TI 2 y M2 puede
entonces verse como una "máquina virtual" (capítulo 1, apartado 1), MI, cuyo
lenguaje de máquina es Ll. Podemos, por tanto, decir que MI es un intérpre-
te (reconocedor y ejecutor) de Ll.
De acuerdo con la descripción que acabamos de hacer de la máquina virtual
MI, la interpretación y de un programa x e Ll se lleva a cabo en dos pasos: en
el primero, la máquina real, M2, interpreta el programa traductor 712 dando
como resultado de la ejecución y e L2; después, la misma M2 interpreta y. A
Ll se le llama lenguaje fuente y a L2 lenguaje objeto.
Pero hay otra alternativa para la ejecución en M2 de un algoritmo descrito
por un programa x 6 Ll. Como sabemos (tema "Algoritmos", capítulo 3, apar-
tado 2.2), x consta de una secuencia finita de instrucciones, instrucciones que
tienen sentido para MI (máquina virtual) pero no para M2 (máquina real).
Podemos pensar en un programa para M2,112, que vaya reconociendo, una a
una, la¿ instrucciones de x y haciendo que M2 ejecute las acciones oportunas
para que dé el mismo resultado que hubiera dado MI. Este tipo de programa
se llama intérprete.
La figura 5.1 ilustra la descripción que acabamos de hacer sobre el funcio-
namiento de un traductor y el de un intérprete. Ambos son procesadores de
lenguaje, y, desde el punto de vista del programador, ambos permiten disponer
' Utilizaremos el término "intérprete" con dos sentidos. Uno es el que acabamos de definir: una máquina que
reconoce las órdenes o instrucciones de un programa escrito en su lenguaje de máquina y las ejecuta, una tras
otra. El otro sentido, que veremos enseguida, y que es el más utilizado en la práctica, se refiere a un programa
que va examinando y reconociendo una tras otra las instrucciones del programa original y generando las ins-
trucciones oportunas para la máquina ejecutora.
2
Este es el segundo sentido de "intérprete" que mencionábamos en la nota anterior. Obsérvese que, funcional-
mente, la diferencia entre un programa traductor y un programa intérprete es la misma que hay entre las pro-
fesiones de traductor e intérprete.
de una máquina virtual Mí, con lenguaje de máquina L1 (en el que el progra-
mador escribe sus programas) a partir de una máquina real M2, con lenguaje
de máquina L2 (en el que sería mucho más difícil, o prácticamente absurdo,
escribir los programas).
x e L1 j M2 ' resultados
— " i — -
r
programa
712
datos
b) interpretación
Figura 5.1.
613
2. Lenguajes de programación
614
nivel para un ordenador puede ejecutarse en otro cualquiera (siempre que se
disponga del traductor o del intérprete adecuado). Los traductores para len-
guajes de alto nivel se llaman compiladores, y, como veremos en el apartado
4, son bastante más complejos que los ensambladores.
Veamos con algunos ejemplos las características básicas de los distintos
niveles de lenguajes.
3
Suponemos que el lector tiene algunos conocimientos de la arquitectura básica de los ordenadores para enten-
der este ejemplo. Así, debe saber que una "palabra" es el conjunto de bits que se transfieren en paralelo entre
la memoria y la unidad de procesamiento.
615
• 0100: restar del contenido del acumulador el de la palabra direccionada
y dejar el resultado en el acumulador;
0001000000000001
0011000000000010
0101000000000000
0010000000000011
0000000000000000
Las dos líneas de puntos iniciales indican que habrá unas instrucciones de
entrada de datos para leer los números, convertirlos a binario y guardarlos en
las direcciones 0, 1 y 2. A continuación vienen cuatro instrucciones, cada una
de dieciséis bits. La primera tiene código de operación 0001 (cargar) y el
número 1 en su campo de dirección; es decir, su ejecución provocará que el
contenido de esa palabra de memoria se transfiera al acumulador. El código de
operación de la segunda instrucción es 0011 (sumar) y su campo de dirección
es 2 (10 en binario); por tanto, cuando la máquina la ejecute, su efecto será el
de sumar el contenido de la palabra de dirección 2 a lo que en ese momento
haya en el acumulador, y dejar la suma en el mismo acumulador. Con la
siguiente, se multiplica ese resultado parcial por lo que haya en la dirección 0,
y con la cuarta el resultado final se transfiere a la memoria, a la palabra de
dirección 3 (11 en binario). A continuación se incluirían las instrucciones para
sacar ese resultado por algún periférico, y, finalmente, viene la instrucción de
parar.
Los ordenadores son máquinas de programa almacenado. Esto quiere decir
que la secuencia de instrucciones que constituyen un programa se carga en la
memoria y luego se ejecutan una detrás de otra, salvo cuando aparece una ins-
trucción de salto (o bifurcación). Se llaman así aquellas que provocan una
"ruptura de secuencia" en la ejecución del programa, es decir, que la siguiente
instrucción a ejecutar no es la que viene a continuación (almacenada en la
siguiente palabra de la memoria), sino la que está almacenada en la dirección
indicada por la propia instrucción de salto. Estas instrucciones suelen utilizar-
se para controlar bucles o acciones condicionales. Por ejemplo, nuestro orde-
nador puede tener una instrucción de salto incondicional, con código 0110, y
otra de salto si acumulador es cero (0111). La primera, al ejecutarse, hace que
la siguiente instrucción a ejecutar sea la que está almacenada en la dirección
especificada en su campo de dirección, y la segunda lo mismo pero condicio-
nado al hecho de que el contenido del acumulador esté formado por dieciséis
ceros, de lo contrario, se ejecuta la siguiente de la sentencia.4 Obsérvese que
esto implica que el programador tiene que conocer exactamente las direccio-
nes en que van a almacenarse las instrucciones de su programa. Otra instruc-
ción interesante es la de salto a subprograma (con código, por ejemplo, 1000),
cuyo efecto es el mismo del salto incondicional, pero guardando en algún sitio
(en otro registro, o en una determinada palabra de la memoria) la dirección de
retorno, dirección de la instrucción que le sigue en la secuencia; el subpro-
grama es un conjunto de instrucciones que termina con una instrucción de
retorno, y es muy útil cuando han de realizarse repetidamente ciertas opera-
ciones a lo largo de un programa (por ejemplo, cálculo de la raíz cuadrada, lec-
tura de datos, etc.).
Veamos un ejemplo de programación en este lenguaje de máquina hacien-
do uso de las instrucciones de salto. Se leen dos números, A y B (suponemos
que A < B) y se trata de igualar el primero con el segundo a base de sumarle
sucesivamente una unidad, como indica el organigrama de la figura 5.2.
Supondremos que a partir de la dirección 20 (10100 en binario) hay almace-
nado un subprograma que permite leer números. La primera vez que "se le
llama" (con la instrucción de salto a subprograma) lee un número y lo alma-
cena en la dirección 0; la siguiente, lee otro y lo almacena en la dirección 1, y
así sucesivamente. Nuestro programa puede ser el siguiente (la primera colum-
na indica la dirección de memoria, en decimal):
4
Suponemos que la representación del número "0" en esta máquina se hace mediante dieciséis ceros.
617
contenido
dir. (binario) comentario
0 aqui se almacenará el
primer dato
1 aqui, el segundo
2 0000000000000001 esta es la constante 1
3 1000000000010100 salto al subprograma de
lectura (lee un dato
y lo almacena en la
dirección 0)
4 1000000000010100 salto al subprograma de
lectura (lee otro dato
y lo guarda en 1)
5 0001000000000000 carga el primer número
(A)
6 0100000000000001 le resta el segundo (B)
7 0111000000001100 si A=B, salta a ejecu-
tar la instrucción alma-
cenada en la dirección
12
8 0001000000000000 si no, carga A (almace-
nado en 0)
9 0011000000000010 le suma una unidad
(está en 2)
10 0010000000000000 almacena el resultado en
la dirección de A
(dirección 0)
11 0110000000000101 y vuelve a la instruc-
ción almacenada en la
dirección 5
12 0000000000000000 cuando A=B se para
c i
Z Leer Ay B
1
7
SI
| no
A: = A+ 1 O
Figura 5.2.
código de código
máquina ensamblador
0000 PAR
0001 CAR
0010 ALM
0011 SUM
0100 RES
0101 MUL
0110 SAI
0111 SAC
1000 SAS
619
Para el primero de los dos ejemplos anteriores, un posible programa en
ensamblador sería:
A MEM 1
B MEM 1
C MEM 1
D MEM 1
CAR B
SUM C
MUL A
ALM D
PAR
FIN
A MEM 1
B MEM I
UNO CEN 1
SAS LEER
SAS LEER
BUCLE CAR A
RES B
SAC FIN
CAR A
SUM UNO
ALM A
SAI BUCLE
FIN PAR
LEER (a partir de aqui vendrian las
instrucciones del subprograma de
lectura de datos)
FIN
621
un programa completo, sino cada una de las unidades elementales que forman
parte de él y que tienen un significado en la definición del lenguaje. Así, en el
lenguaje Pascal, existen sentencias de asignación como
x := 3
if EB then 51 else 52
while EB do 5
factorial (5,f);
"5" y "f" son los parámetros reales, que, cuando el procedimiento se eje-
cute atendiendo a esta llamada, irán a sustituir a los parámetros formales.
Un procedimiento puede comunicarse también con el programa que le
llama (o sea, recibir datos o entregar resultados) mediante el uso de variables
globales, es decir, variables definidas en el programa y accesibles también
desde el procedimiento. (En el procedimiento "factorial" que hemos
escrito, "i" es una variable local, porque está definida dentro del cuerpo del
procedimiento).
Una función es otro tipo de subprograma. Al igual que un procedimiento,
puede tener parámetros formales, y compartir variables globales, pero, a dife-
rencia de él, devuelve directamente un valor al programa que la llama. Por
ejemplo, para el factorial podemos escribir esta función en Pascal:
623
function factorial(n:integer):integer;
var i,fact:integer;
begin
fact:=1;
for i:=2 to n do fact:=fact*i;
factorial:=fact
end;
f:=fact (5)
function factorial(n:integer)¡integer;
begin
if n<2 then factorial:=1
else factorial:=n*factorial(n-1)
end;
625
2.4.2 Programación funcional
El fundamento teórico de la programación funcional tiene su origen en el
problema de la computabilidad de funciones matemáticas, y, concretamente,
en el llamado "cálculo lambda". Sin entrar en esta base matemática, digamos
simplemente que un programa funcional es un conjunto de ecuaciones que
definen funciones a partir de otras funciones más sencillas o de primitivas. Por
ejemplo, en el programa
max3[x,y,z] := max2[max2[x,y],z]
la primera sentencia define la función "max 2" a partir de las primitivas "if",
">", "then" y "else", y la segunda define la función "max3" a partir de
"max2". Es importante señalar que el símbolo ": =" no representa, como en
algunos lenguajes imperativos, una asignación; aquí significa "se define
como". De hecho, en LISP, por ejemplo, no se utiliza este símbolo, sino la
palabra clave "defun".
Las definiciones de funciones pueden ser recursivas. Por ejemplo:
y (suma x y)
(igual(suma(mul a (cuad x))(suma(mul b x) c)) 0)
Para manejar listas, los lenguajes funcionales suelen tener incorporada una
función de construcción que permite encadenar dos listas. Esta función se
puede escribir de forma prefija: cons [L1,L2] o de forma infija: Ll. L2.
Por ejemplo, la lista (a, b, c) se puede construir así a partir de los átomos a,
byc :
o bien:
A :- B, C, D.
B A C A D - ) A
627
donde A, B, C y D representan, fórmulas atómicas.
Por ejemplo, un programa que declara unos hechos de parentesco y define
la relación "abuelo" es éste, formado con dos hechos y dos reglas:
madre(ana,luis).
padre(josé,ana).
abuelo(X,Z) :- padre(X,Y),padre(Y,Z).
abuelo(X,Z) :- padre(X,Y),madre(Y, Z) .
?- abuelo(josé,luis).
SI
?- abuelo(josé,ana).
NO
?- abuelo(X,luis).
X = josé
pad_o_mad(X, Y) :- padre(X,Y).
pad_o_mad(X, Y) :- madre(X,Y) .
antepasado(X, Y) :- pad_o_mad(X, Y) .
antepasado(X,Y) :- pad_o_mad(X,Z),antepasado(Z,Y).
3. Definiciones sintácticas
A:\ = « i
Aw = «2
A:\ =
629
en una sola línea, de este modo:
(una expresión es o bien un solo término o bien una suma de términos) pueden
escribirse en BNF así:
o bien:
Cíbegin /3 x /end.
A ::=a\p
631
En éste, como en otros muchos casos, es fácil encontrar otras reglas que
generen las mismas cadenas y que cumplan la condición enunciada.
Concretamente, basta con introducir un nuevo símbolo auxiliar, R, y sustituir
la regla anterior por:
A :: = aR
R:: = Pl\p2
Ese procedimiento de "sacar factor común" puede conducir a algo que nor-
malmente está prohibido en la definición de las gramáticas libres de contexto,
pero que pese a todo se utiliza para cumplir la condición. Se trata de que,
excepcionalmente, el consecuente de una regla puede ser la cadena vacía. Por
ejemplo, en el caso de la regla
A ::= a \ a/5
A ::= aR
R::=p\X
(Obsérvese que, pese a tener la regla R::= X , las cadenas derivadas a par-
tir de A siguen siendo de longitud no decreciente).
Este caso aparece, por ejemplo, en la sentencia " i f " de los lenguajes de
programación, con sus dos posibilidades:
A ::= oc\A ¡3
A ::= aR
R ::= pR I X
o bien, usando la notación BNF ampliada:
A ::=«{£}
Ahora bien, esta regla indicaría que las instrucciones deberían ir una tras
otra en la misma línea, mientras que, como hemos visto en los ejemplos del
apartado 2.2.2, se escriben cada una en una línea separada. Para reflejar esta
imposición en la forma de la regla, introduciremos un símbolo terminal espe-
cial, "el" (cambio de línea) entre <instrucción> y <programa>. Por otra parte,
la definición anterior de programa como secuencia de instrucciones es incom-
pleta: puede haber también seudoinstrucciones (MEM y CEN). Además, la regla
anterior tiene un problema: la última línea de un programa sería el símbolo ter-
minal "FIN" con la letra "F" en la primera columna de la línea. Pero, como se
desprende de los ejemplos, las etiquetas se escriben justamente desde la pri-
mera columna, por lo que el ensamblador no sabría que "FIN" es una seu-
doinstrucción y no una etiqueta. La regla sintáctica es que los códigos de las
instrucciones y seudoinstrucciones no pueden empezar en la primera columna:
tienen que llevar delante al menos un espacio en blanco. Llamaremos <separ>
a la categoría sintáctica que significa "uno o más espacios en blanco".
Finalmente, vamos a considerar la posibilidad de escribir comentarios. Un
comentario es un texto que el procesador (ensamblador, en este caso) debe
ignorar. Supondremos que los comentarios se escriben en líneas diferentes de
las que corresponden a las instrucciones y seudoinstrucciones. De acuerdo con
todo esto, escribimos dos reglas:
633
Tenemos ahora que introducir nuevas reglas para obtener derivaciones a
partir de <instrucc>, <seudoinstrucc> y <coment>. Sabemos que una instruc-
ción (y una seudoinstrucción) puede llevar etiqueta o no. La etiqueta se escri-
be a partir de la primera columna de la línea. Supondremos que el código de
operación no tiene por qué escribirse en columnas determinadas: basta con que
esté separado del final de la etiqueta por uno o más espacios en blanco
("<separ>"), y si no hay etiqueta debe ir precedido por <separ>. Hay, además,
ciertas instrucciones que tienen que ir acompañadas de una dirección de
memoria (SUM, RES, etc.); las seudoinstrucciones CEN y MEM tienen que ir
seguidas de un número. Se separará esta dirección o este número del código de
operación mediante <separ>. Otras instrucciones, como PAR, CMP (comple-
mentar el acumulador), etc., no llevan nada más. En cuanto a los comentarios,
supondremos que las líneas correspondientes se distinguen porque en la pri-
mera columna tienen el carácter "*" y luego cualquier texto (cadena de carac-
teres). Todo ello se puede formalizar con las siguientes reglas:
Tenemos ahora nuevas categorías sintácticas para las que hemos de intro-
ducir nuevas reglas: <eti>, <dir>, etc. Escribamos ya, sin extendernos en más
explicaciones, el resto de las reglas:
(11) <dígito> : : = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
635
3.4 Gramática para un lenguaje de alto nivel
Tomaremos como ejemplo sencillo de un lenguaje de alto nivel un peque-
ño subconjunto de Pascal. Presentaremos primero de manera informal su sin-
taxis y su semántica.
Para simplificar, sólo consideraremos un tipo de dato: entero ("integer").
En el programa pueden figurar constantes literales (por ejemplo, -3, 100, etc.)
y constantes y variables denominadas mediante identificadores; estas últimas
deben declararse al principio mediante sentencias de declaración. Por ejemplo:
program ejemplo;
const menosdos = -2;
diez = 10;
var i,j : integer;
begin
end.
Las constantes y variables pueden combinarse con los operadores aritméti-
cos "+", "-", "*" y "/" formando expresiones aritméticas, y con los operado-
res relaciónales "=", "<", ">", "<=", ">=", " o " formando condiciones que se
evalúan como verdaderas (por ejemplo, "3>2") o falsas (por ejemplo, "3<2").
• La sentencia de asignación:
Sintaxis: v : = expresión
Semántica: asocia a la variable v el valor resultante de evaluar la expre-
sión (sustituyéndolo por el que tenía asociado anteriormente).
• La sentencia de iteración:
Sintaxis: while condición do sentencia
Semántica: se ejecuta la sentencia repetidamente siempre que la eva-
luación de la condición sea verdadera.
• La sentencia de entrada de datos5:
Sintaxis: read (v)
Semántica: lee un valor del periférico de entrada y lo asigna a la varia-
ble v.
En todos los casos anteriores, "sentencia" puede ser una sentencia simple o
compuesta por una secuencia de varias; en este caso deben ir separadas por
";", precedidas por "begin" y terminadas por "end". Los espacios en blan-
co y los cambios de línea no tienen significado, y pueden introducirse arbitra-
riamente para mejorar la legibilidad.
Una definición formal de la sintaxis del lenguaje es la dada por las siguien-
tes reglas en notación BNF:
5
"read" y "write" no son, realmente, "sentencias": véase la observación al final de este apartado.
637
while <condición> do <sentencia>l
rea d(<identif>) I w r i t e (<expresión>)
while C do SI;52
C 51
(sentencia)
C (sentencia) ; (sentencia)
SI S2
Figura 5.3.
<resto> ::=<sentencia>ks-no-emparejada>else<s-emparejada>
639
(sentencia)
C1
if (condición) then (sentencia) (resto)
else (sentencia)
C2 SI S2
(sentencia)
C2 SI S2
Figura 5.4.
(b) Pi P2 ...p„
Figura 5.23.
641
El diagrama completo se presenta como un conjunto de subdiagramas en
cada uno de los cuales pueden figurar símbolos auxiliares que se desarrollan
en otros subdiagramas. La recursividad se manifiesta en el hecho de que el
subdiagrama correspondiente a un símbolo auxiliar puede contener el nodo
correspondiente a ese mismo símbolo, u otro cuyo subdiagrama lo contiene.
Como ejemplo, en la figura 5.6 reproducimos el diagrama sintáctico corres-
pondiente al lenguaje definido en el apartado 3.4.
sentencia
-o
identif - letra
l )
cte -
%
( dígito J dígito
cte
sentencia
Figura 5.10.
condición
expresión
TTTTTl
© 0 0 © © ©
l i l i l í expresión
expresión
factor
identif
num.
expresión
-©
4. Definiciones semánticas
4.1 Objetivos
La definición sintáctica de un lenguaje permite comprobar si un determina-
do programa pertenece o no al lenguaje, y, como veremos en el apartado 5.2,
reconstruir el árbol de derivación de ese programa. Pero no nos dice nada
sobre el efecto de la ejecución del programa. Esto pertenece al campo de la'
semántica. Hemos visto en los anteriores ejemplos que una primera ventaja de
la presentación formal de la sintaxis de un lenguaje procede del rigor y la con-
643
cisión del lenguaje matemático. El primer objetivo de la formalización de la
semántica es, asimismo, definir el lenguaje sin la ambigüedad y la pérdida de
detalles con que se hace cuando, como es habitual, se utiliza el lenguaje natu-
ral para ello. Por ejemplo, en la referencia básica del lenguaje Pascal6 puede
leerse con relación a la sentencia de asignación: "especifica que un valor a
computar se asigne a una variable. El valor está especificado por una expre-
sión" (pág. 28). Pero esta definición es incompleta: ¿qué ocurre si la expresión
no puede evaluarse, o si los tipos de la variable y del resultado de evaluar
la expresión son distintos? Desde luego, en el libro citado se indican, tam-
bién informalmente, las distintas posibilidades de compatibilidad entre tipos
(pag. 33), pero no cabe duda de que lo mejor sería expresar escueta, clara y
completamente el significado de la sentencia.
Es obvio que no sólo es importante que un programa sea sintácticamente
correcto; es preciso que haga justamente lo que se pretende de él. Típicamente,
en el proceso de desarrollo de un programa, una vez depurados los errores sin-
tácticos se le somete a una serie de pruebas para examinar su comportamiento
y se va refinando hasta que se está "razonablemente" seguro7 de que funciona
correctamente. Este es un procedimiento rudimentario, costoso e inseguro.
Una alternativa es desarrollar y aplicar métodos de prueba formal de progra-
mas. Es decir, demostrar, matemáticamente, que un programa dado hace lo que
se supone que tiene que hacer. O, inversamente, sabiendo lo que tiene que
hacer, demostrar constructivamente el programa. Este sería el segundo objeti-
vo de la definición formal de la semántica: proporcionar una base rigurosa
para razonar sobre los programas, y, por tanto, poder diseñar programas que,
por el propio método de diseño, sean correctos.8
Un tercer objetivo está en relación con las ayudas informáticas al desarro-
llo de programas y los entornos de programación. La formalización de la sin-
taxis ha permitido diseñar herramientas para mejorar la productividad del
desarrollo de software. Con la formalización de la semántica podrían conse-
guirse herramientas mucho más potentes. Por ejemplo, un método de diseño de
programas es el basado en transformaciones: a partir de una especificación for-
mal de lo que el programa debe hacer (escrita en un lenguaje de muy alto
nivel), mediante transformaciones sucesivas con la ayuda de unas herramien-
tas que elijan las reglas de transformación adecuadas, llegar al código de
máquina final. Es como una generalización del proceso de compilación que
veremos en el siguiente apartado. Pero al ser mucho más complejo, también
resulta mucho más difícil diseñar las herramientas de modo que la semántica
6
El manual que describe la norma ISO: Jensen y Wirth (1985).
7
Recuérdese la "ley de Gilb": tema "Lógica", capítulo 2, apartado 1.5.
8
Hablar de "programa correcto" es común en el lenguaje cotidiano de la informática, y algo que todos enten-
demos: se trata de una propiedad que atañe tanto a la sintaxis del lenguaje (el programa es una cadena que
puede derivarse en la gramática) como a la semántica (el programa cumple con las especificaciones). No obs-
tante, podemos objetar el mismo reparo terminológico que expresábamos en el tema "Lógica" (capítulo 4,
apartado 2.4) con respecto a "fórmula bien formada": ¿acaso un "programa incorrecto" puede llamarse "pro-
grama"?
se mantenga en estas transformaciones. Una definición formal de la semántica
es imprescindible para ello.
Finalmente, la definición semántica formal es útil en el proceso de diseño
de nuevos lenguajes, para contrastar distintas posibilidades en la definición de
las construcciones sintácticas básicas del lenguaje.
Como ya decíamos en el primer capítulo de este tema (apartado 3), se han
propuesto varios enfoques para la definición formal de la semántica. Estos
enfoques no son competitivos, sino complementarios: según el objetivo que se
pretende con la formalización, resulta más adecuado un enfoque u otro.
Resumimos a continuación las ideas básicas de los más conocidos.
Q = [q: {ident} -» V]
645
estado actual, q, y de la entrada, e (sentencia o dato).
Veamos algunos ejemplos con relación al lenguaje definido en el apartado
3.4. Para no extendernos en demasiados detalles, nos referiremos sólo a la pri-
mera parte del estado (por lo que las definiciones serán incompletas). Para la
sentencia de asignación podríamos escribir:
/ ( i d e n t : = expr, q{) = q2
q2 (ident) = ve
(V ident' ¿ (ident)(<?2 (ident') = qx (ident'))
E = S = V*
647
Esto indica que E (y S) es el dominio de todas las posibles cadenas (inclu-
yendo la vacía) de elementos de V. Entonces, definiremos el dominio estado
como
Q=MXEXS
M = { f : I ^ V }
M = / —> V
5 [*]: Q -» Y u {error}
donde c e C.
Utilizamos corchetes (además de paréntesis) para las funciones semánticas
sólo para mejorar la legibilidad. Para representar, por ejemplo, la función S de
la sentencia A:=B sobre un estado q = (m,e,s) escribiremos:
5
El símbolo "—> " representa ahora la aplicación de un conjunto en otro (no el condicional de la lógica ni las
reglas de producción).
Para un lenguaje determinado, se llaman cláusulas semánticas a las defini-
ciones concretas de las anteriores funciones semánticas para todas y cada una
de las construcciones sintácticas del lenguaje (dadas por la definición sintácti-
ca). Veamos cómo podrían ser algunas de las cláusulas semánticas para nues-
tro lenguaje.
m [v/i] (j) = v si i = j
= m( j) si no
649
Para la sentencia "while",
En "otro caso" está comprendido el que S [x] o S [c] den error o que v no
sea ni "verd" ni "falso". Obsérvese que la definición es recursiva.
Veamos, como último ejemplo, el caso de la sentencia de salida:
10
Si se nos presenta siempre como básico el concepto de estado es porque estamos considerando lenguajes
imperativos. En un lenguaje lógico, por ejemplo, la semántica podría definirse como hicimos en el capítulo 4
del tema "Lógica"
todos los estados posibles es el conjunto de todas las funciones de identifica-
dores en valores, un predicado aplicado a unos identificadores representa a un
conjunto de estados. Por ejemplo, si i es un identificador y M (i) es el pre-
dicado "i es mayor o igual que cero", M (i) es falso para todos los estados
en los que valor(i) < 0 y verdadero para todos los estados en los que valor
(i) > 0. Por tanto, M (i), o, más nemotécnicamente, "i > 0", representa el con-
junto de estados tal que valor(i) > 0. Predicados de este tipo son predicados
sobre el estado.
Lo que interesa es establecer predicados sobre programas y poder demos-
trar que son verdaderos. Si Q y R son predicados sobre estados y P es un pro-
grama, la notación
{ Q}P[R }
651
Obsérvese que pmd, además de ser un transformador de predicados, es
también un predicado (puesto que su resultado es una aserción, verdadera o
falsa, que representa al conjunto de estados en los que es verdadera) con dos
argumentos: una sentencia, S, y un predicado, R. Estamos, pues, en lógica de
predicados de segundo orden (tema "Lógica", capítulo 5, apartado 2.1).
La primera tarea, dada la definición sintáctica del lenguaje, es definir pmd
para cada una de las posibles construcciones. Así, para la sentencia de asigna-
ción podemos definir:
pmd (i : = e, R) = Rs
5. Procesadores de Lenguajes
5.1 Ensambladores
5.1.1 Traducción, carga y ejecución
Antes de entrar en el estudio de la estructura de un ensamblador conviene
que nos detengamos un momento a ver su función en un contexto global, des-
cribiendo a grandes rasgos los procesos que tienen lugar desde la traducción
hasta la ejecución de un programa.
652
Por razones ya explicadas tanto en este tema como en el de "Algoritmos",
el desarrollo de un programa suele hacerse descomponiéndolo en módulos que
se prueban independientemente. Por ello, la mayoría de los ensambladores no
generan directamente un programa en lenguaje de máquina, sino lo que se
llama módulo objeto. Este módulo sólo difiere del programa final en lenguaje
de máquina en que las direcciones simbólicas no se han sustituido aún por las
direcciones absolutas de memoria, sino que figuran en una tabla junto con sus
desplazamientos con relación al comienzo del programa (como si éste fuera a
cargarse a partir de la dirección 0). Además, puede haber direcciones simbóli-
cas, conocidas como referencias externas, que corresponden a llamadas a otros
módulos o subprogramas que se ensamblan aparte o que son rutinas de utili-
dad ya incluidas en el sistema operativo, como las de comunicaciones con los
periféricos. Cuando se han ensamblado todos los módulos, un programa lla-
mado montador de enlaces, o enlazador ("linker"), "resuelve" estas referencias
externas y genera un módulo de carga. Finalmente, otro programa, el carga-
dor reubicador ("relocating loader") asigna las direcciones absolutas e introdu-
ce en la memoria el programa en lenguaje de máquina listo para ser ejecutado.
La figura 5.7 ilustra esta secuencia de procesos. Los rectángulos representan
programas que se ejecutan, y los bloques ovalados datos o resultados de esos
programas. Como se indica en la figura, los "módulos objeto" pueden haber
sido generados por un ensamblador o por un compilador.
Programas fuente
Figura 5.23.
653
Por limitaciones de capacidad, normalmente no es posible que coexistan en
la memoria central todos los programas que intervienen: programas fuente,
módulos objeto, ensamblador, compilador, montador y cargador. Por esta
razón, durante el ensamblaje (o la compilación) de cada módulo sólo está pre-
sente, además de una parte del sistema operativo llamada residente (que inclu-
ye al cargador), el ensamblador (o el compilador). Este lee las instrucciones
del programa fuente, una detrás de otra, de un periférico (normalmente, de un
disco), y deposita el módulo objeto en algún medio de almacenamiento auxi-
liar (normalmente, un disco). Cuando todos los módulos objeto están disponi-
bles, se carga el montador de enlaces, que genera el programa reubicable. La
figura 5.8 insiste en esta secuencia de procesos. No debe interpretarse errónea-
mente el hecho de que en la figura aparezca cinco veces el símbolo del disco:
los diferentes programas pueden estar en varios discos o en uno solo, en dis-
tintas zonas o ficheros.
Figura 5.8.
SAI PRINCIP
UNO CEN 1
N MEM 1
A MEM 100
PRINCIP SAS CALCULO
Etiqueta Dirección
UNO 1
N 2
A 3
PRINCIP 103
655
grama fuente. Este caso es ciertamente raro en la actualidad (hay "estaciones
de trabajo" sin disco, pero es porque utilizan un "servidor de ficheros" de la
red a la que están conectadas). Otra motivación para eludir la doble lectura del
programa fuente es tratar de reducir el tiempo total de proceso de ensamblaje.
Para tales casos, se puede tener un ensamblador de un solo paso. Basta con ir
formando una tabla adicional con los nombres no referenciados aún en la tabla
de etiquetas y la dirección relativa de las instrucciones en las que aparecen;
conforme se va llenando la tabla de etiquetas, se retrocede para poder obtener
el código de las instrucciones pendientes de traducir.
" Hemos decidido presentarlos así en aras de una mayor concisión. Comprendido el proceso, el lector puede
tratar de presentarlo de manera estructurada, siguiendo los principios explicados en el tema "Algoritmos".
656
Figura 5.23.
657
Se supone que el programa fuente está almacenado en un fichero de un
disco, de donde se van leyendo sucesivamente las líneas, que se introducen en
la variable LIN.
En el organigrama aparecen llamadas a tres procedimientos, "Explorador",
"BuscaETI" y "Act ETI", cuyas funciones son las siguientes:
5.2 Compiladores
5.2.1 Fases de la compilación
En la ejecución de un programa compilador podemos distinguir dos etapas:
la de análisis, en la que se reconoce el programa fuente y se le traduce a un
código o lenguaje intermedio, y la de síntesis, en la que se genera el módulo
objeto. En cada etapa tienen lugar varias fases, como indica la figura 5.11.
Figura 5.23.
661
El número de pasos del compilador (lecturas sucesivas del programa fuen-
te o de alguna versión intermedia) es muy variable y depende de diversos fac-
tores condicionantes del diseño. Si la capacidad de memoria central es reduci-
da, interesa realizar el proceso en muchos pasos, con resultados intermedios en
memoria auxiliar. En el caso extremo, que mencionábamos al hablar de los
ensambladores, de que no se disponga de memoria auxiliar, o cuando se quie-
ra una gran velocidad de compilación, puede llegarse a realizar todo el proce-
so en un solo paso.
En este apartado describiremos a grandes rasgos las funciones de cada
fase, y en los siguientes concretaremos viendo cómo se puede aplicar la defi-
nición formal de nuestro "minilenguaje" del apartado 3.4 para el diseño de las
dos primeras.
La primera fase del análisis es el análisis léxico. El analizador léxico, al
que también llamaremos explorador ("scanner")12, tiene como función princi-
pal leer los caracteres del programa fuente e identificar las categorías sin-
tácticas ("tokens") del lenguaje. Son categorías sintácticas las palabras clave
(begin, if, ...), los identificadores, las constantes, etc. Recuérdese que en
nuestro ejemplo de ensamblador del apartado anterior también teníamos un
explorador que reconocía las etiquetas, los códigos de operación y los núme-
ros. Además de esta labor de reconocimiento, el explorador va creando una
tabla de símbolos en la que se registran los nombres y los atributos de los iden-
tificadores (tipo de variable, número y tipos de los argumentos en el caso de
que sea un nombre de procedimiento, etc.).
La segunda fase es el análisis sintáctico ("parsing"). El analizador sintác-
tico ("parser") es, formalmente, un reconocedor del lenguaje. Como ya hemos
dicho, los lenguajes de programación se suelen formalizar con gramáticas
libres de contexto, y como sabemos del capítulo 4 (apartado 4), para recono-
cer lenguajes libres de contexto se precisan autómatas de pila. Y en efecto,
durante la fase de análisis sintáctico se construyen estructuras de pila en la
memoria central. Pero el analizador sintáctico no sólo reconoce si el programa
es correcto o no, también reconstruye el árbol de derivación. Para su diseño
resulta de gran utilidad disponer de la definición sintáctica formal.
Estas dos fases, como las siguientes, son fases lógicas que no necesaria-
mente tienen que ejecutarse una tras otra. Así, el explorador es normalmente un
subprograma llamado por el analizador sintáctico, como indica la figura 5.12.
Se puede pensar que, puesto que la definición formal del lenguaje permite
formar programas (y, a la inversa, analizarlos) a partir de los caracteres ele-
mentales, ambas fases, análisis léxico y sintáctico, podrían fundirse en un solo
algoritmo. Tal cosa es, en efecto, posible, pero hay varios motivos para hacer
la separación. Aparte de facilitar un desarrollo modular, la tarea de análisis
2
En otros textos se restringe el término "explorador", o "scanner", a un subprograma del analizador léxico
que realiza las funciones más sencillas, como leer caracteres y eliminar espacios en blanco y cambios de
línea.
662
léxico puede modelarse, como veremos con un ejemplo en el apartado 5.2.2,
mediante un reconocedor finito, lo que conduce a programas muy eficientes
para esa tarea.
Caracteres llamada
del programa Analizador
Explorador
fuente sintáctico
devuelve
Tabla de
símbolos
Figura 5.12.
663
puntero
nombre atri lutos
id2 el real
id3 c2 real
a) tabla de símbolos
(sent)
b) árbol de derivación
>
id idl /
Í
í
+ cte 2
I T
r
id id2 id id3
c) estructura de datos
Figura 5.10.
La fase de análisis semántico13 tiene dos funciones. Una es la de interpre-
tación, en el sentido de determinar el significado de las construcciones reco-
nocidas por el analizador sintáctico, y de detectar los errores llamados semán-
ticos (por ejemplo: asignación de un valor real a una variable declarada como
booleana o uso de un identificador no declarado). La segunda función consis-
te en representar ese significado en un lenguaje intermedio entre el lenguaje
fuente y el de máquina. Esta fase suele llevarse a cabo también en paralelo con
el análisis sintáctico: conforme va generando el árbol de derivación, el anali-
zador sintáctico va llamando a las correspondientes rutinas semánticas.
Para el ejemplo anterior, la traducción de la sentencia al lenguaje interme-
dio podría ser:
Este lenguaje sería el de una máquina virtual con tres direcciones de memo-
ria. Las instrucciones de máquina (o "cuádruplas") tienen cuatro campos: un
código de operación y las direcciones de dos operandos y del resultado. En las
instrucciones de transferencia del contenido de una dirección a otra o de asig-
nación de un valor constante a una dirección sólo se utilizan, como vemos, tres
de los campos.
En la fase de optimización se procura modificar el código intermedio para
obtener un programa que se ejecute más eficazmente (más rápido y usando
menos recursos; por ejemplo, en el segmento de código anterior las dos ins-
trucciones últimas pueden fundirse en una al tiempo que se ahorra una posición
de memoria: div mi m2 idl). Esta fase puede tener más o menos impor-
tancia dependiendo del uso que se vaya a hacer del compilador. Si el programa
final compilado va a ejecutarse con mucha frecuencia y rara vez se va a modi-
ficar, entonces interesa que esté lo más optimizado posible, a costa de que el
tiempo de compilación pueda ser muy grande. Si, por el contrario, se está desa-
rrollando y probando un programa, interesa más bien que el tiempo de compi-
lación no sea excesivo aunque el código final no esté muy optimizado.
En la fase final de generación de código se obtiene el programa traducido
ya al lenguaje objeto. Algunos compiladores terminan con el programa en
ensamblador, y otros incluyen las funciones de ensamblaje en la generación de
código, de manera que producen un módulo objeto.
Así, el código en ensamblador, optimizado, para el ejemplo que venimos
tratando podría ser:
13
Se trata aquí de lo que se llama "semántica estática", no de la semántica considerada en el apartado 4. En su
mayor parte, este análisis semántico es necesario porque, como ya hemos dicho, en los lenguajes suele haber
características dependientes del contexto que no se modelan en la sintaxis.
665
M2 CEN 2
CAR ID2
SUM ID3
DIV M2
ALM ID1
donde ID1, ID2, ID3 son las direcciones relativas de la tabla de símbolos.
Si no existiera la instrucción de dividir, se haría un salto a un subprograma de
división.
Las palabras clave, así como el símbolo ": =" y los operadores ">=", "<="
y " o " se consideran símbolos terminales en la gramática definida en el apar-
tado 3.4, pero para el explorador son cadenas, puesto que para él los símbolos
terminales son los caracteres individuales.
Si hemos elegido estos símbolos auxiliares y terminales como categorías
sintácticas es porque para cada uno de ellos podemos definir una gramática
regular:
a) Para <identif>, en lugar de la producción (5) del apartado 3.4 pode-
mos escribir:
<id> ::= a |b |... | z | A|B |... | Z
<id> ::= a<restoid>lb<restoid>l IZ<restoid>
<restoid> ::= a | b |... | Z | 0 111... | 9
<restoid> : := a<restoid>lb<restoid>l.. .1 Z<restoid>l 0 <restoid>l.. .19<res-
toid>
Para esta gramática tenemos el reconocedor finito (capítulo 4, apartado
5.3) de la figura 5.14(a), y el lenguaje puede representarse también
mediante la expresión regular:
(a+b+...+A+B+...)(a+b+...+A+B+...Z+0+1+...+9)*
(0+1+...+9)(0+1+...+9)*
667
Figura 5.10.
Y el reconocedor sería el de la figura 5.14(e). No obstante, la conside-
ración de todas las palabras clave implicaría un número muy elevado de
estados, y, consecuentemente, muchas instrucciones para el programa
explorador. Por ello, suele preferirse otra solución: las palabras clave se
tratan, a efectos de reconocimiento, igual que los identificadores, pero
inicialmente se introducen en la tabla de símbolos con un atributo que
indica su categoría de palabra clave. Cuando el explorador reconoce un
identificador tiene que explorar en cualquier caso la tabla de símbolos;
si se trata de una variable o de una constante devuelve el puntero, y si
está registrado como palabra clave, el código de la palabra.
media := (cl+c2)/2
669
Figura 5.23.
670
A partir del diagrama, podemos escribir la tabla de transiciones del reco-
nocedor (figura 5.16). Esta tabla puede estar en memoria y servir como guía al
programa explorador. Para ello, podemos programar un procedimiento, al que
llamaremos "transición" que reciba como parámetros de entrada el último
carácter leído (car) y el número del estado anterior (est_ant), y que, tras con-
sultar la tabla, devuelva como parámetro de salida el estado resultante
(est_act).
bl el 1 d + -
*
/ > •
> < ( )
*
1 1 1 2 3 + - / 5 4 = 5 6 7 )
2 id id 2 2 id id id id id id id id id id id id
3 cte cte cte 3 cte cte cte cte cte cte cte cte cte cte cte cte
4 •
5 > > > > > > > > > > > >= > > > >
6 < < < < < < < < < < < <= o < < <
7 ( ( ( ( ( ( 8 ( ( ( ( ( ( ( ( (
8 8 8 8 8 8 8 9 8 8 8 8 8 8 8 8 8
9 8 8 8 8 8 8 9 8 8 8 8 8 8 8 8 1
Figura 5.16.
etc.
671
dor sintáctico deberá leer un carácter antes de llamarlo la primera vez. Se
supone que el procedimiento "lee_car" lee el siguiente carácter del programa
fuente. "Act_Tabl_Simb" consulta, si es necesario (o sea, en el caso de que el
estado final sea "id" o "cte") la tabla de símbolos y devuelve los atributos al
analizador sintáctico.
Figura 5.17.
S ::= A I B
A ::= aA I b
B ::= aB \ c
S ::= A I aS
Ay.= b\c
673
s s
A B
C
(a) (b)
Figura 5.18.
S::=a\Sb
(a) (b)
Figura 5.23.
674
El problema está en que habría que seguir leyendo hasta el final para deci-
dir en qué momento aplicar la primera producción. Con la gramática equiva-
lente
S ::= aR
R ::= bR I X
675
begin
P(<*l)
P(V<l)
P(U„)
a
«1 «2 n end
a
l«2 ... <*„
P(<*n)
Figura 5.10.
Subdiagrama Procedimiento Codificación en Pascal
P( a);
while categ in prim ( P ) do P ((3 j
repeat
P< a)
while categ not in prim ( a )
P< a);
while categ in prim (¡i ) do
begin
P ( |3j,- P ( a )
end
cib
^ J t r 1
677
La aplicación de estas normas al caso particular de nuestro lenguaje es
inmediata. En la figura 5.21 puede verse el organigrama correspondiente al
primer subdiagrama de la figura 5.6. Este podría ser el programa principal, a
partir del cual se llama a "bloque", y de éste a los demás procedimientos. Antes
de llamar la primera vez al explorador se inicializa la variable "car" con un
espacio en blanco. Esto es necesario porque, como se recordará, el explorador
funciona con "un carácter por adelantado".
I
car: ="
i
explorador
categ = "program"
Jsi
explorador
no
error
Figura 5.10.
El resto de los organigramas no presenta mayores problemas. A título de
ejemplo, indicamos en las figuras 5.22, 5.23 y 5.24 los correspondientes a los
procedimientos "expresión", "término" y "factor".
Figura 5.22.
Figura 5.23.
679
Figura 5.24.
En esta descripción nos interesaba sobre todo ver cómo la definición sin-
táctica formal del lenguaje es una herramienta útil para el diseño sistemático
del procesador. Hemos prescindido de detalles, como el tratamiento de errores
y el manejo de la tabla de símbolos, que, aun siendo importantes, serían ya
propios de un texto sobre compiladores.
Quizás el lector se pregunte por la construcción del árbol del árbol de deri-
vación, que, como decíamos en el apartado 5.2.1, es una tarea del analizador
sintáctico. Pues bien, en este algoritmo predictivo el árbol está implícito en la
secuencia de procedimientos que se van llamando. Los punteros que aparecen
en la figura 5.13 los va devolviendo el explorador conforme va reconociendo
identificadores, y los utilizan las rutinas semánticas para ir generando el códi-
go intermedio. Estas rutinas semánticas son procedimientos asociados a cada
uno de los procedimientos que realizan el análisis sintáctico. Por ejemplo,
cuando se analiza la sentencia
media := (cl+c2)/2
5.3 Intérpretes
La estructura de un programa intérprete es mucho más sencilla que la de un
compilador. En esencia, puede representarse por el bucle de la figura 5.25.
CONT_SENT es una variable que indica en cada momento la posición en el
programa fuente de la siguiente sentencia a ejecutar. Su función es similar a la
de "CONT_ENS" del ensamblador descrito en el apartado 5.1.3: en principio,
se va incrementando en una unidad, pero puede tomar otro valor, dependiendo
del análisis de la sentencia (si ésta es una llamada a procedimiento, o de con-
681
trol de un bucle, etc.). A cada tipo de sentencia posible se le asocia un proce-
dimiento en el programa intérprete para ejecutar en la máquina real la acción
especificada por la sentencia.
O
Leer sentencia i CONST_SENT)
Incrementar (CONST_SENT)
Analizar la sentencia
Llamar al p rocedimiento
asociado a la sentencia
no
fin ?
si
O Figura 5.25.
11
Es decir, el intérprete no funciona exactamente como lo haría el motor de inferencias de un sistema exper-
to. Hay que decir, no obstante, que el lenguaje tiene muchas otras características no explicadas en el apartado
2.4.3, y que con ellas se pueden diseñar sistemas expertos con Prolog.
683
Para concretar el funcionamiento del intérprete de Prolog, aunque sea de
manera básica e informal, consideremos el programa del apartado 2.4.3 y la
consulta:
?-abuelo(X,luis).
15
Pero en las bases de datos deductivas, al residir los hechos en memoria secundaria, es imposible, por razo-
nes de eficiencia, aplicar el algoritmo que hemos descrito. Remitimos al lector interesado a un libro ya refe-
renciado en el tema "Lógica", el de Ullman (1988, 1989).
685
y que genere como salida un programa compilador (escrito en LP) tal que
cuando se ejecute (después de haber sido traducido con un compilador de LP)
acepte programas escritos en LF y los traduzca a LO. Tal programa se llama
compilador de compiladores.1<s
Así expresada, la idea es demasiado ambiciosa y general. Actualmente se
simplifica del siguiente modo:
Las herramientas de este tipo más conocidas son "Lex" y "Yacc", diseñadas
para el sistema operativo UNIX, y que utilizan el lenguaje C como LP. Lex es
un generador de exploradores: a partir de la definición de una gramática regu-
lar dada por una expresión regular genera el correspondiente explorador. Yacc
("Yet another compiler-compiler") es un generador de analizadores sintácticos:
a partir de una gramática libre de contexto, dada por las reglas BNF, genera un
analizador que sigue un algoritmo de reconocimiento ascendente. Aunque son
programas separados, Lex y Yacc están diseñados para funcionar conjunta-
mente, de acuerdo con el esquema de principio que veíamos en la figura 5.12.
6. Resumen
Los lenguajes de bajo nivel (ensambladores y macroensambladores) son
cercanos a los lenguajes de las máquinas reales, mientras que los de alto nivel
facilitan la tarea de codificar algoritmos, porque independizan al programador
de los detalles concretos del hardware y le permiten concentrarse en el pro-
blema a resolver.
En cualquier caso, siempre se puede considerar que todo lenguaje define a
una máquina que lo "entiende", es decir, que reconoce los programas escritos
en ese lenguaje y los ejecuta. Si el lenguaje no corresponde al de una máqui-
na "real" (construida con hardware solamente), entonces la máquina definida
es una máquina virtual.
16
Seguramente el lector tendrá que releer varias veces este párrafo para captar completamente la idea. La difi-
cultad radica en que ahora tenemos varios niveles de lenguajes: las entradas al compilador de compiladores
están escritas en un metalenguaje que describe a LF, LO y LP, y las entradas al compilador generado son pro-
gramas escritos en LF. Obsérvese también que si se considera que un compilador es una "herramienta", enton-
ces un compilador de compiladores es una "metaherramienta" (una herramienta que ayuda a crear herra-
mientas).
686
Los procesadores de lenguaje son programas que permiten ejecutar en una
determinada máquina (real o virtual), MO, programas escritos para otra máqui-
na (normalmente virtual), MF. El lenguaje de MF se llama lenguaje fuente, y
el de MO, lenguaje objeto. Hay dos tipos esencialmente diferentes de proce-
sadores: los traductores y los intérpretes. Los primeros toman como datos la
sucesión de caracteres que constituyen un programa fuente y generan un pro-
grama objeto que posteriormente se puede ejecutar en MO. Los traductores
para lenguajes ensambladores se llaman ensambladores, y los diseñados para
lenguajes de alto nivel, compiladores. Los intérpretes no generan de una sola
vez todo el programa objeto correspondiente a un programa fuente, sino que
van analizando sucesivamente las sentencias de éste y generando sobre la mar-
cha las instrucciones de la MO necesarias para ejecutar esas sentencias.
Los lenguajes tradicionales, sean de bajo o alto nivel, suelen ser imperati-
vos: las instrucciones o sentencias expresan órdenes elementales para una
máquina, real o virtual. La idea de los lenguajes declarativos es que el pro-
grama no sea una sucesión de órdenes, sino una especificación del problema.
En los lenguajes de programación funcional esta idea se plasma en tratar de
expresar los problemas a través de aplicaciones de funciones matemáticas,
mientras que en los lenguajes de programación lógica se trata de formular los
problemas por medio de sentencias de la lógica formal.
La definición formal de la sintaxis de un lenguaje de programación, sea
mediante la notación BNF o mediante diagramas sintácticos, es de gran utili-
dad en el diseño de las fases de análisis léxico y sintáctico de los procesado-
res de lenguaje. Generalmente, la parte que define las categorías sintácticas
del lenguaje (palabras clave, identificadores, números, etc.) a partir de los
caracteres elementales (símbolos terminales) se puede definir mediante una
gramática regular, a la que corresponde un reconocedor finito, que se mate-
rializa en el programa analizador léxico o explorador. El resto de la defini-
ción sintáctica se formaliza como una gramática libre de contexto, a la que
corresponde un reconocedor de pila, y que da lugar al programa analizador
sintáctico. La función del explorador es leer caracteres del programa fuente
de entrada y reconocer las distintas categorías sintácticas, mientras que la del
analizador sintáctico consiste básicamente en reconstruir el árbol de deriva-
ción del programa en cuestión según la gramática del lenguaje. Las rutinas
semánticas se ocupan de la traducción, sea al lenguaje objeto final, o a un
código intermedio.
La definición formal de la semántica es un asunto más difícil, y existen
actualmente varios enfoques (operacional, denotacional y axiomático) que
pueden aplicarse al diseño de nuevos lenguajes, a la verificación y construc-
ción sistemática de programas y al diseño de herramientas y entornos de pro-
gramación potentes.
Un compilador de compiladores es un programa que genera un compilador
a partir de las definiciones formales de los lenguajes de entrada (lenguaje fuen-
te) y salida (lenguaje objeto).
687
7. Notas histórica y bibliográfica
La historia de los lenguajes de programación es paralela a la de los mode-
los de máquinas computadoras, reales o virtuales. Suele decirse que el primer
programador fue Ada Augusta, Condesa de Lovelace, que a mediados del siglo
pasado propuso diversos programas para una máquina que jamás llegó a cons-
truirse, el "analytical engine" de Babagge.
Pero el comienzo de la historia moderna de los ordenadores está jalonado
por el modelo de von Neumann, propuesto en 1946, y la aparición del primer
ordenador comercial, el UNIVAC I, en 1951. En esta época aún se programa-
ba en lenguaje de máquina. En 1952, en el M.I.T., se diseñó un lenguaje lla-
mado SAP (Symbolic Assembly Program), un ensamblador para el IBM 701.
Y en el mismo año, Grace Murray Hopper publicaba el primer artículo sobre
compiladores, en el que se describía "A-O", un compilador para el UNIVAC I.
Por entonces, estas investigaciones se consideraban dentro del campo de la
inteligencia artificial llamado "programación automática". En Knuth y Pardo
(1980) se dan muchos detalles de la historia de los primeros tiempos de la pro-
gramación.
Al final de los años 50 aparecen ya las primeras versiones de tres lengua-
jes de alto nivel que todavía siguen siendo ampliamente utilizados: FORTRAN
(Backus et al., 1957), COBOL (cuyo primer borrador data de 1959) y LISP
(McCarthy, 1960). Backus propuso su notación en 1959, para describir el
"International Algebraic Language" (Backus, 1959), precursor de Algol (Naur,
1963). Y heredero de Algol es Pascal, diseñado por Niklaus Wirth (1971), y
que, a su vez, ha sido inspirador de otros lenguajes más modernos, como Ada
y Modula-2. En la primera edición del manual de Pascal se introducían los dia-
gramas sintácticos como alternativa a la notación BNF. Como ya hemos dicho
en el apartado 2.4.2, la programación funcional tiene su origen teórico en el
cálculo lambda, propuesto por el matemático Alonzo Church (1936). Un artí-
culo ya clásico sobre los lenguajes aplicativos es el de Backus (1978). En
cuanto a Prolog, procede de los trabajos de un equipo de investigadores de
Marsella sobre lenguaje natural (Colmerauer et al., 1973). Cabe citar también
una comunicación de Kowalski (1974) en la que por primera vez se expresan
claramente las ideas básicas de la programación lógica.
La semántica operacional está ligada a los estudios sobre relaciones entre
lenguajes y máquinas intérpretes, como los de McCarthy y Painter (1967) y
Alien et al. (1972). El origen de la semántica denotacional se encuentra en la
"teoría de dominios" de Scott y Strachey (1971) y en la "teoría del punto fijo"
de Manna (1974). La semántica axiomática está relacionada con la preocupa-
ción por demostrar matemáticamente la corrección de los programas. Un
precursor en esta línea es el creador de LISP, John McCarthy: "en lugar de
comprobar los programas con casos de prueba hasta que están depurados,
deberíamos poder demostrar que tienen las propiedades deseadas" (McCarthy,
688
1962). La teoría fue desarrollada por diversos autores, principalmente Floyd
(1967), Hoare (1969) y Dijkstra (1975). El transformador de predicados que
aquí hemos llamado "pmd" lo introdujo Dijkstra con el nombre de "wp" ("wea-
kest precondition").
Para ampliar los contenidos de este capítulo recomendamos los siguientes
libros:
Sobre lenguajes de programación en general, Horowitz (1984) describe
características comunes (tipos, procedimientos, abstracciones de datos, etc.) y
dedica tres capítulos a la programación funcional y a los lenguajes de flujo de
datos y orientados a objetos. El libro de Tucker (1986) tiene otro enfoque:
describe, en sucesivos capítulos, las características esenciales y específicas de
los lenguajes más conocidos. En una línea más conceptual, es muy interesan-
te la lectura de un artículo de Ambler et al. (1992), que contiene una revisión
y comparación de los distintos paradigmas de programación.
De Pascal, la referencia básica es el manual de Jensen y Wirth (1985).
Textos didácticos sobre el lenguaje hay muchos. En español, además de los ya
citados en el capítulo 4 del tema "Algoritmos", recomendamos el de Cueva et
al. (1994), que no se limita al lenguaje: es una introducción a la programación
estructurada y a la programación orientada a objetos.
Sobre programación funcional, Bird y Wadler (1988) es un libro introduc-
torio y general, y Wikstrom (1987) está centrado en el lenguaje ML. Para LISP
en particular, el texto más conocido es el de Winston y Horn (1991).
La referencia básica de Prolog (con la llamada "sintaxis de Edimburgo",
que es la más seguida, y la que hemos utilizado en la breve descripción del
apartado 2.4.3) es el libro de Clocksin y Mellish (1984). También cabe reco-
mendar los de Lloyd (1987) y Sterling y Shapiro (1986). Los de Walker et al.
(1987) y Bratko (1990) son especialmente interesantes, porque combinan
Prolog con aplicaciones a la inteligencia artificial (el inconveniente del prime-
ro es que no utiliza la sintaxis de Edimburgo, sino la de un producto comercial
de IBM). El libro de Maier y Warren (1988) presenta de manera muy clara y
detallada tanto los aspectos funcionales (definición y uso del lenguaje) como
los procesales (funcionamiento de los procesadores).
Una introducción a la programación funcional (con aplicaciones a la defi-
nición de lenguajes de programación) y la programación lógica (con los fun-
damentos de lógica formal) puede encontrarse en Delgado y Fernández (1994).
Sobre procesadores de lenguajes, Aho et al. (1986) sigue siendo el mejor
libro de texto. Más básico y centrado en los fundamentos es el de Pittman y
Peters (1992) (y, también, al ser más reciente, incluye temas más actuales; por
ejemplo, técnicas de optimización específicas para procesadores RISC y vec-
toriales). Lex y Yacc se describen con todo detalle en Levine et al. (1992). Para
la descripción del algoritmo de análisis sintáctico en el apartado 5.2.3 nos
hemos basado en Wirth (1976), un magnífico libro (y con muy buena traduc-
ción) sobre programación y estructuras de datos que, pese a su antigüedad,
sigue siendo recomendable.
689
Para un estudio completo de la definición formal de lenguajes y de su pro-
cesamiento, con notación y terminología unificadas, pueden seguirse los tres
libros de Watt (1990: "conceptos y paradigmas", 1991: "sintaxis y semántica",
1992: "procesadores").
Por último, tenemos que citar el libro de Davis (1994), no sólo porque
explica más detalladamente de lo que hemos podido hacer aquí la semántica,
sino, sobre todo, porque cubre los mismos temas que este libro (lógica, autó-
matas, algoritmos y lenguajes) en un nivel algo más avanzado de formaliza-
ción y conceptualización.
Referencias
bibliográficas
Aho, A.V., Sethi, R. y Ullman, J.D. Compilers. Principles, techniques, and tools.
Addison-Wesley, Reading, Mass., 1986.
Aikins, J.S. Prototypical knowledge for expert systems. Artificial Intelligence, 20
(1983), pp. 163-210.
Alabau, A. y Figueras, Z. Algoritmos y máquinas. Universidad Politécnica de Bar-
celona, C.P.D.A., 1.975.
Alagic, S. y Arbib, M.A. The design of well-structured and correct programs.
Springer-Verlag, N.Y., 1978.
Alfonseca, M. Frames, semantics networks and object-oriented programming in
APL2. IBM J. Res. Dev., 33:5, pp. 502-510, Sep. 1989.
Alfonseca, M. y Alcalá, A. Programación orientada a objetos. Anaya Multime-
dia, Madrid, 1992.
Allen, C.D., Chapman, D.N. y Jones, C.B. A formal definition of ALGOL 60. IBM,
TR. 12.105, Hursley (UK), ago. 1972.
Allen, J.F. An internal-based representation of temporal knowledge. Proc. 7th Int.
Joint Conf. Artif. Int., Vancouver, Canada, 1981, pp. 221-226.
Ambler, A.L., Burnett, M.M. y Zimmerman, B.A. Operational versus definitional:
a perspective on programming paradigms. Computer, 25, 9 (Sep. 1992), pp.
28-43.
691
Anderson, J.A. y Rosenfeld, E. (eds.). Neurocomputing: foundations of research.
MIT Press, Cambridge, Mass., 1988.
Arbib, M.A. Brains, machines and mathematics. McGraw-Hill paperbacks, 1965.
(Existe versión castellana en la colección Alianza Universidad).
Arbib, M.A. Theories of abstract automata. Prentice-Hall, Englewood Cliffs,
N.J., 1969.
Arbib, M.A. Computers and the cybernetic society. Academic Press, 1977. (Pu-
blicado en castellano por Editorial AC, bajo la supervisión de F. Sáez Vacas,
1978).
Ashby, W.R. An introduction to cybernetics. Chapman and Hall, Londres, 1956.
(Traducción de J. Santos: Introducción a la cibernética. Nueva Visión, Buenos
Aires, 1960).
Backus, J.W. Can programming be liberated from the von Neumann style? A
functional style and its algebra of programs. Comm. ACM, 21, 8 (1978), pp.
613-641.
Backus, J.W. The syntax and semantics of the proposed international algebraic
language of the Zurich ACM-GAMM Conference. Proc. Internal Conf.
Information Processing, UNESCO, Paris, 1959 (Butterworth's, Londres, 1960,
pp. 125-132).
Backus, J.W., Beeber, R.J., Best, S., Goldberg, R., Haibt, L.M., Herrick, H.L.,
Nelson, R.A., Sayre, D., Sheridan, P.B., Stern, H., Ziller, I., Hughes, R.A. y
Nutt, R. The FORTRAN automatic coding system. Proc. Western Joint Com-
puter Conf, AIEE (actualmente IEEE), Los Angeles, 1957.
Bar-Hillel, Y., Perles, M. y Shamir, E. On formal properties of simple
phrase structure grammars. ZeitschriftfiirPhonetikSprachwissenschaft und
Kommunikationsforschung, 14 (1961), 143-172.
Bartee, T.C. Digital computers fundamentals. McGraw-Hill, N.Y., 1960 (sexta
ed.: 1985).
Bartee, T.C. Computer architecture and logic design. McGraw-Hill, N.Y., 1991.
Bartee, T.C., Lebow, I.L. y Reed, I.S. Theory and design of digital machines.
McGraw-Hill, N.Y., 1962.
Barwise, J. y Etchemendy, J. Turing machines. Accesible en la Internet en la
dirección: http://csli-www.stanford.edu/hp/Turingl.htm
Beck, K. y Cunningham, W. A laboratory for teaching object-oriented thinking.
Proc. Object-Oriented Programming Systems, Languages and Applications
1989 (OOPSLA'89). SIGPLAN Notices, Vol. 24, No 10, october 89, pp. 1-6.
Bellew, R.K. y Booker, L.G. (eds.) Proceedings of the fourth international con-
ference on genetic algorithms and their applications. Morgan Kaufmann, San
Mateo, Calif, 1991.
Bird, R. y Wadler, P. Introduction to functional programming. Prentice-Hall, En-
glewood Cliffs, N.J., 1988.
Bochmann, G.V. Architecture of distributed computer systems. Springer-Verlag,
Berlin, 1979.
Bochvar, D. On three-valued logical calculus and its application to the analysis of
contradictions. Matematiceskij Sbornik, 4 (1939), pp. 353-369.
Bohm, C. y Jacopini, G. Flow diagrams, Turing machines and languages with only
two formation rules. Comm. ACM, 9, 5, may. 1966.
Booch, G. Object-oriented analysis and design with applications. Benjamin/
Cummings Publishing Company, Redwood City, Cal., 1994.
Boole, G. An investigation of the laws of thought on which are founded the
mathematical theories of logic and probabilities. McMillan, London, 1854.
Reimpr: Dover Publ. Inc., N.Y., 1958.
Booth, T.L. Sequential machines and automata theory. Wiley, N.Y., 1967.
Bratko, I. Prolog programming for artificial intelligence (2nd. ed.) Addison-
Wesley, Reading, Mass., 1990.
Brownston, L., Farrel, R., Kant, E. y Martin, N. Programming expert systems in
OPS5. An introduction. Addison-Wesley, Reading, Mass., 1985.
Brozozowski, J.A. A survey of regular expressions and their applications. IRE
Trans. Elec. Comp.,EC-U (1962), pp. 324-325.
Brozozowski, J.A. Regular expressions for lineal sequential circuits. IEEE Trans.
Elec. Comp., EC-14 (1965), pp.148-156.
Buchanan, B.G. y Shortliffe, E.H. (eds.) Rule-based expert systems. Addison-
Wesley, Reading, Mass., 1984.
Buchanan, B.G., Sutherland, G.L. y Feigenbaum, E.A. Heuristic DENDRAL: A
program for generating explanatory hypotheses in organic chemistry. En B.
Meltzer y D. Michie (Eds.): Machine Intelligence, vol 4, Edinburgh Univ.
Press, 1969, pp. 209-254.
Cantor, D.C. On the ambiguity problem of Backus systems. Journal of ACM, 9
(1962), 4, 477-479.
Cao, T. y Sanderson, A.C. Task sequence planning using fuzzy Petri nets. IEEE
Trans. Sys., Man, andSMC25, 5 (May 1995), pp. 755-768.
Carbonell, J. (ed.) Machine learning. Paradigms and methods. Elsevier,
Amsterdam, 1989.
Carbonell, J.G., Cullingford, R. y Gershman, A. Steps towards knowledge-based
machine translation. IEEE Trans. Pattern Anal, and Mach. Int., 3, 4 (Jul.
1981), pp. 376-392.
Cerrada, J.A. y Collado, M. Programación I. Universidad Nacional de Educación
a Distancia, 1993.
693
Chand, S. y Chiu, S.L. (Guest eds.) Special issue on fuzzy logic with engineering
applications. Proc. IEEE, 83, 3 (Mar. 195), pp. 343-483 (incluye 7 contribu-
ciones de 22 autores).
Chandrasekaran, B., Mittal, S. y Smith, J.N. RADEX. Towards a computer-based
radiology consultant. En E.S. Gelsema y L.N. Kanal (eds.): Pattern
recognition in practice. North-Holland, Amsterdam, 1980, pp. 463-474.
Charniak, E. y McDermott, D. Introduction to artificial intelligence. Addison-
Wesley, Reading, Mass., 1985.
Chomsky, N. Three models for the description of language. I.R.E. Trans. Inf.
Theory, IT-2 (1956), 113-114.
Chomsky, N. On certain formal properties of grammars. Information and Control
2 (1959), 137-167.
Chomsky, N. Context-free grammars and pushdown storage. Quart. Prog. Dept.
No. 65 (1962), MIT Res. Lab. Elect., 187-194.
Chomsky, N. Prólogo al libro de Gross y Lentin (1967).
Chomsky, N. Language and mind. Harcourt Braze, N.Y., 1968.
Chomsky, N. The logical structure of linguistic theory. Plenum Press, N.Y., 1975.
Chomsky, N. y Miller, G.A. Finite state languages. Information and Control, 1
(1958), 91-112.
Chomsky, N. y Schutzenberger, M.P. The algebraic theory of context-free
languages. Computer Programming and Formal Systems. North-Holland,
Amsterdam, 1963,118-161.
Church, A. An unsolvable problem in elementary number theory. American
Journal of Mathematics, 58 (1936), pp. 345-363.
Clocksin, W.F, Darlington, J., Kennaway, S.R. y Sleep, M.R. "Part II. Declarative
systems". En Chambers, F.B., Duce, D.A. y Jones, G.P. (eds.): Distributed
computing. Academic Press, Londres, 1984, pp. 55-138.
Cloksin, W.F. y Mellish, C.S. Programming in Prolog. Springer Verlag, Berlin,
1981.
Coad, P. y Yourdon, E. Object-oriented analysis. Prentice-Hall, Englewood Ciffs,
NJ, 1991.
Coad, P. y Yourdon, E. Object-oriented design. Prentice-Hall, Englewoods Cliffs,
NJ, 1991.
Codd, E.F. A relational model of data for large shared data banks. Comm. ACM,
13, 6 (1970), pp. 337-387.
Cohen, D. Introduction to computer theory. John Wiley, N.Y., 1991.
Colmerauer, A., Kanoni, H., Pasero, R. y Roussel, P. Un systéme de commu-
nication homme-machine enfrangais. Groupe d'Intelligence Artificielle. Uni-
versit'e d'Aix-Marseille. Luminy, 1973
Corge, Ch. Eléments d'informatique. Larousse Université, Paris, 1975.
Coulter, N.S. Software science and cognitive psychology, IEEE Trans. Softw.
Eng., SE-9, 2 (mar. 1983), pp. 166-171.
Cox, B. Object-oriented programming: an evolutionary approach. Addison-Wes-
ley, 1986.
Cuena, J. Lógica informática. Alianza, Madrid, 1986.
Cuena, J., Fernández, G., Verdejo,F. y López de Mántaras, R. Inteligencia artifi-
cial: sistemas expertos. Alianza, Madrid, 1986.
Cueva, J.M., García, P.A., López, B., Luengo, M.C. y Alonso, M. Introducción a
la programación estructurada y orientada a objetos con Pascal. Cuaderno Di-
dáctico núm. 69, Dep. Matemáticas, Universidad de Oviedo. Gráficas Oviedo,
1994.
Curtís, M.W. A Turing machine simulator. Journal of the ACM, 12,1, (ene. 1965),
pp. 1-13.
De Morgan, A. Formal logic. Londres, 1847.
Dahl, O. y Nygaard, K. SIMULA: an Algol-based simulation language. Comm.
ACM, Vol. 9, No. 9, pp. 671-678, sept. 1966.
Dahl, O.I., Myhrhaugh, B. y Nygaard, K. The SIMULA-67 common base lan-
guage. Rept. S-22, Norwegian Computing Centre, Oslo, 1970.
Dahl, O.I., Dijkstra, E.W. y Hoare, C.A.R. Notes on structured programming.
Academic Press, 1972.
Datamation. Revolution in programming. Datamation, Die. 1973. Número dedi-
cado preferentemente al tema de la programación estructurada.
Davis, M. y Putnam, H. A computing procedure for quantification theory. Journal
of the ACM, 1, 3 (jul. I960), pp. 201-215.
Davis, M.D., Sigal, R. y Weyuker, J. Computability, complexity and languages:
fundamentals of computer science (2nd. ed.) Academic Press, Sand Diego,
Calif., 1994.
Deaño, A. Introducción a la lógica formal. Alianza, Madrid, 1974. (3a. ed., reimpr,
1986).
DeJong, G. Capítulo 21 de Kodratoff y Michalski (1990).
Delgado Kloos, C. Simulador de Máquina de Turing. Proyecto Fin de Carrera,
E.T.S.I.Telecomunicación, Madrid, Sep. 1978.
Delgado Kloos, C. y Fernández, G. Programación declarativa. Servicio Publi-
caciones E.T.S.I.T.M., Madrid, 1994.
Denning, P.J., Dennis, J.B. y Qualitz, J.E. Machines, languages and computation.
Prentice-Hall, Englewood Cliffs, N.J., 1978.
695
Díaz Cort, J., Complejidad concreta y complejidad abstracta de algoritmos: Un
panorama actual. IV Escuela de Verano de Informática, Asociación Española
de Informática y Automática, Granada, 1982.
Diez Medrano, J., Complejidad. Trabajo para la asignatura de Fundamentos de
Ordenadores I, Escuela Técnica Superior de Ingenieros de Telecomunicación,
Madrid, junio 1984.
Digitalk Inc. Smalltalk/V PM tutorial and programming handbook. Digitalk Inc.,
Los Angeles, Cal., 1989.
Dijkstra, E.W. Guarded commands, non-determinacy and the formal derivation
of programs. Comm. ACM, 18 (Aug. 1975), pp. 453-458.
Dijkstra, E.W., A discipline ofprogramming. Prentice-Hall, N.J., 1976.
Driankov, D., Hellendoorn, H. y Reinfrank, M. An introduction to fuzzy control.
Springer Verlag, Berlin, 1993.
Dubois, D. y Prade, H. Fuzzy sets and systems. Theory and applications. Aca-
demic Press, New York, 1980.
Dubois, P. y Prade, H. Théorie des possibilités. Application á la représentation
des connaissances en informatique. Masson, París, 1985.
Dubois, D. y Prade, H. Possibility theory. An approach to computerized proces-
sing of uncertainty. Plenum Press, New York, 1988.
Duda, R.O., Hart, P.E., Nilsson, N.J. y Sutherland, G. Semantic network re-
presentation in rule-based inference systems. En D.A. Waterman y F. Hayes-
Roth (Eds.): Pattern-directed inference systems. Academic Press, N.Y., 1978,
pp. 203-221.
Durkin, J. Expert systems catalog of applications. Intelligent Computer Systems,
Akron, Ohio, 1993.
Evey, J. The theory and application of pushdown store machines. (Tesis Doc-
toral). Harvard University, Cambridge, Mass., 1963.
Fayyad, U. y Uthurusamy, S. (eds.) KDD-94: Proceedings of AAAI-94 know-
ledge discovery in databases workshop. AAAI Press, 1994.
Fernández, G. Curso de ordenadores. Conceptos básicos de arquitectura y sis-
temas operativos. Ed. Syserco, Madrid, 1994.
Ferrater, J. y Leblanc, H. Lógica matemática. Fondo de Cultura Económica,
México, 1955 (2o ed., 1962).
Floyd, R.W. On ambiguity in phrase structure languages. Comm. ACM, 5 (1962),
10, 526-534.
Floyd, R.W. Assigning meaning to programs. En J.T. Schwartz (ed.): Mathe-
matical aspects of computer science. Proc. Symp. Amer. Math. Soc., 1967, pp.
19-33.
Floyd, R.W. The syntax of programming languages-A survey, I.R.E. Trans.
Electronic Computers, 14 1964, 4, 346-353.
Fogel, L., Owens, A. y Walsh, M. Artificial intelligence throught simulated
evolution. John Wiley, New York, 1966.
Frege, G. Die Grundlagen der Arithmetic, eine logisch- mathematische Unter-
suchung ber den Begriff der Zahl. Breslau, 1884. Versión traducida al inglés
en J. van Heijenoort (ed.): From Frege to Gódel. Harvard University Press,
1967.
Frenkel, K. Piecing together complexity, and complexity and parallel processing:
an interview with Richard Karp. Comm. ACM, 29, 2 (feb.1986), pp. 110-117.
Frieldberg, R.M. A learning machine: Part I. IBM Journal of Research and De-
velopment, 2, 1 (Jan. 1958).
Frieldberg, R.M. A learning machine: Part II. IBM Journal of Research and De-
velopment, 3, 3 (Jul. 1959).
Frost, R.A. Introduction to knowledge-based systems. Collins, Londres, 1986.
Gallant, S. Connexionist expert systems. Comm. ACM, 31 (1988), pp. 152-169.
Gallant, S. Neural networks learning and expert systems. MIT Press, Cambridge,
Mass., 1993.
Gamella, M. (ed.) La tecnología del software. Temática y situación en España.
Fundesco, Madrid, 1985.
Gardner, M. Mathematical games: On cellular automata, self- reproduction, the
garden of Eden, and the game of life. Scientific American, Feb., Mar., Apr.
1971;Jan. 1972.
Garijo, M. et al. Tema 10: Algoritmos y complejidad. Apuntes complementarios
para la asignatura Fundamentos de la Programación, Escuela Técnica Superior
de Ingenieros de Telecomunicación, Madrid, 1986.
Genesereth, M.R. y Nilsson, N J . Logical Foundations of Artificial Intelligence.
Morgan Kaufmann, Los Altos, Calif., 1987.
Genesereth, M.R. Computational logic. An introduction in twenty easy lessons
(1995). Accesible en la Internet en la dirección:
http://logic.stanford.edu/csl57/index.html
Gilbert, W.J. Modern algebra with applications. John Wiley, N.Y., 1976.
Gilb, T. Laws of unreliability. Datamation, vol. 21, N.3, Mar. 1975.
Ginsburg, S. The mathematical theory of context-free languages. McGraw-Hill,
N.Y., 1966.
Ginsburg, S. Lectures on context-free languages. En Arbib, M.A. (ed.): Algebraic
theory of machines, languages, and semigroups. Academic Press, N.Y., 1968.
697
Glorioso, R.M. y Colón, F.C. Engineering intelligent systems. Digital Press, Bed-
ford, Mass., 1980.
Gódel, K., Über formal unentscheidbare Sátze der Principia Mathematica und ver-
wandter Systeme, I (sobre proposiciones formalmente indecidibles de los Prin-
cipia Mathematica y sistemas relacionados). Monatshefte für Mathematik und
Physik, 38,1931, pp. 173-98.
Goldberg, D.E. Genetic algorithms in search, optimization, and machine
learning. Addison-Wesley, Reading, Mass., 1989.
Goldberg, A. y Robson, D. Smalltalk-80: the language and its implementation.
Addison-Wesley, Reading, Mass., 1983.
Goldschlager, L. y Lister, A. Computer science: a modern introduction, Prentice-
Hall, N.J., 1982.
Gottfried, B.S. Programación en C. McGraw-Hill, Madrid, 1993.
Grefenstette, JJ. Proceedings of the first international conference on genetic
algorithms and their applications. Lawrence Erlbaum, Hillsdale, N.J., 1985.
Grefenstette, J.J. Proceedings of the second international conference on genetic
algorithms and their applications. Lawrence Erlbaum, Hillsdale, N.J., 1987.
Gross, M. y Lentin, A. Notions sur les grammaires formelles. Gautier-Villars,
Paris, 1967. (Traducción: Tecnos, Madrid, 1976).
Gupta, M.M., Saridis, G.N. y Gaines, B.R. (eds.). Fuzzy automata and decision
processes. North-Holland, Amsterdam, 1977.
Gutowitz. H. Cellular automata: theory and experiment. MIT Press, Cambridge,
Mass., 1991.
Haak, S. Deviant logic. Cambridge University Press, 1974.
Haak, S. Philosophy of logics. Cambridge University Press, 1978.
Halstead, M.H. Elements of software science, Elsevier, N.Y., 1977.
Harrison, M.A. Introduction to switching and automata theory. McGraw-Hill,
N.Y., 1965.
Harrison, M.A. Introduction to formal language theory. Addison Wesley, Read-
ing, Mass. 1978.
Hayes, P.J. In defense of logic. Proc. 5th Int. Joint Conf Artif. Intell. (1977), pp.
559-565.
Hayes, P.J. The logic of frames. En The frame reader. De Guyter, Berlin, 1979.
Hehner, E.C. The logic of programming. Prentice-Hall, Englewood Cliffs, N.J.,
1984.
Hennie, F. Introduction to computability. Addison-Wesley, Reading, Mass.,
1977.
Hertz, J., Krogh, A. y Palmer, R.G. Introduction to the theory of neural compu-
tation. Addison-Wesley, Redwood, Calif., 1991.
Hinton, G.E. y Sejnowski, T.J. Learning and relearning in Boltzmann machines.
En Rumelhart y McClelland (1986), Vol.1, Ch.7.
Hirst, G. Anaphora in natural language understanding: a survey. Springer-
Verlag, Berlin, 1981.
Hoare, C.A.R. An axiomatic approach to computer programming. Comm. ACM,
12 (Oct. 1969), pp. 576-580, 583.
Holland, J.H. A universal computer capable of executing an arbitrary number of
sub-programs simultaneously. Proc. 1959Eastern Joint Comp. Conf., pp. 108-
113.
Holland, J.H. Adaptation in natural and artificial systems. Univ. Michigan Press,
1975.
Holland, J.H. Escaping brittleness: the possibilities of general-purpose learning
algorithms applied to paralell rule-based systems. En Michalski et al., 1986,
pp.,593-623.
Holland, J.H., Holyoak, K.J., Nisbett, R.E. y Thagard, P.R. Induction. Processes
of inference, learning, and discovery. MIT Press, Cambridge, Mass., 1986.
Hopcroft, J.E. y Ullman, J.D. Formal languages and their relation to automata.
Addison-Wesley, Reading, Mass., 1969.
Hopcroft, J.E. y Ullman, J.E. Introduction to automata theory, languages, and
computation. Addison-Wesley, Reading, Mass., 1979.
Hopcroft, J.E. Máquinas de Turing. Investigación y Ciencia, 94, jul. 1984, pp.
8-19.
Horgan, J. Claude E. Shannon. IEEE Spectrum, 29, 4 (Apr.1992), pp.72-75.
Horowitz, E. Fundamentals of programming languages. Springer- Verlag, Berlin,
1984.
Huffman, D.A. The syntesis of sequential switching circuits. Journal Franklin
Institute, 257 (1954), 3, pp. 161-190, y 4, pp. 275-303.
Hunt, E.B. Artificial intelligence. Academic Press, 1975.
Hunt, E.B., Marin, J. y Stone, P.T. Experiments in induction. Academic Press,
New York, 1966.
Jackson, M.J. Principles ofprogram design. Academic Press, Londres, 1975.
Jacobson, I. Object-oriented software engineering: a use case driven approach.
Addison-Wesley, Reading, Mass., 1992.
Jensen, K. y Wirth, N. Pascal user manual and report. ISO Pascal standard (3a.
ed.) Springer-Verlag, N.Y., 1985.
699
Jones, C.F. Systematic software development using VDM. Prentice-Hall, Engle-
wood Cliffs, N.J., 1986.
Joyanes, L. Programación en Turbo Pascal. McGraw-Hill, Madrid, 1990.
Kanal, L.N. y Lemmer, J.F. (eds.) Uncertainty in artificial intelligence. Elsevier,
New York, 1986.
Kandel, A. y Langholtz, G. (eds.) Fuzzy control systems. CRC Press, Boca Raton,
1994.
Karnaugh, M. The map method for synthesis of combinational logic circuits.
Trans. ALEE, 72, 9 (1953), pp. 593-599.
Karp, R.M. Combinatorics, complexity, and randomness, Comm. ACM, 29,2 (feb.
1986), pp. 98-109.
Kelley, A. y Pohl, I. Lenguaje C. Introducción a la programación. Addison-
Wesley Iberoamericana, 1987.
Kelly, J. Artificial intelligence. A modern myth. Ellis Hordwood, Chichester, En-
gland, 1993.
Kernighan, B. W. y Ritchie, D. M. The Cprogramming language. Prentice-Hall,
1978. Existe 2a. edición y versión en castellano.
Kleene, S. Introduction to metamathematics. North-Holland, Amsterdam, 1952.
(Traducción de M. Garrido: Introducción a la metamatemática. Tecnos, Ma-
drid, 1974).
Kleene, S.C. Representation of events in nerve nets and finite automata. En Auto-
mata studies, Princeton Univ. Press, Princeton, N.J., 1956.
Klir, G. y Folger, N. Fuzzy sets, uncertainty, information. Prentice-Hall, Engle-
wood Cliffs, N.J., 1988.
Knuth, D.E. y Pardo, L.T. The early development of programming languages. En
N. Metropolis, J. Howlet y G.C. Rota (eds.): A history of computing in the
twentieth century. Academic Press, N.Y., 1980, pp. 197-213.
Knuth, D.E. Algoritmos. Investigación y Ciencia, num.9, jun. 1977, pp. 42-53.
Kodratoff, Y. Introduction to machine learning. Pitman, Londres, 1988.
Kodratoff, Y. y Michalski, R.S. (eds)Machine learning: An artificial intelligence
approach, vol. III. Morgan Kaufmann, San Mateo, Calif., 1990.
Kohavi, Z. Switching and finite automata theory. McGraw-Hill, N.Y., 1970.
Kosko, B. Neural networks and fuzzy systems: a dynamical approach to machine
intelligence. Prentice-Hall, Englewood Cliffs, N.J., 1991.
Kowalski, R. Predicate logic as a programming language. Proc. IFIP 74. North
Holland, Amsterdam, 1974, pp. 569-574.
Kowalski, R. Logic for problem solving. North-Holland, New York, 1979. (Tra-
ducción de J.A. Calle: Lógica, programación e inteligencia artificial. Díaz de
Santos, Madrid, 1986).
Kuroda, S.Y. Classes of languages and linear-bounded automata. Information and
control, 7 (1964), 2,114-125.
Ladd, S. R. C+ + techniques and applications. M & T Publishing, Redwood City,
Cal, 1990.
Langley, P , Zytkow, J.M, Simon, H. y Bradshaw, G.L. The search for regularity:
four aspects of scientific discovery. En Michalski et al. (1986), pp.425-469.
Lau, C. Object-oriented programming using SOM and DSOM. Van Nostrand
Reinhold, New York, 1994.
Lenat, D.B. Automated theory formation in mathematics. Proc. 5th Int. Joint
Conf. Artif. Intell. (1977), pp.833-842.
Lenat, D.B. The role of heuristics in learning by discovery: three case studies. En
Michalski et al. (1983), pp.243-306.
Levine, J.R, Mason, T. y Brown, D. Lex&Yacc, 2nd. ed.. O'Reilly and Asso-
ciates, 1992.
Lewis, C.I. y Langford, C.H. Symbolic logic. The Century Comp, N.Y, 1932 (2a.
ed, Dover Publ, N.Y, 1959).
Lewis, H.R. y Papadimitriou, C.H. Elements of the theory of computation. Pren-
tice-Hall, Englewood Cliffs, N.J, 1988.
Linger, R , Mills, H. y Witt, B. Structured programming theory and practice.
Addison Wesley, Reading, Mass, 1979.
Lloyd, J.W. Foundations of logic programming. Springer Verlag, New York,
1981.
López de Mántaras, R. Approximate reasoning models. Ellis Hardwoord, Chi-
chester, England, 1990.
Love, T. Object lessons. SIGS Books, New York, 1993.
Lukasiewicz, J. On 3-valued logic. (1920). Reproducido en McCall, S. (ed.): Po-
lish logic. Oxford University Press, 1967.
Lukasiewicz, J. Many-valued systems of propositional logic. (1930). Repro-
ducido en McCall, S. (ed.): Polish Logic. Oxford University Press, 1967.
Luria, A.R. Cerebro y lenguaje. Fontanella, Barcelona, 1974a.
Luria, A.R. Cerebro en acción. Fontanella, Barcelona, 1974b.
Madnick, S.E. y Donovan, J.J. Operating systems. McGraw-Hill, N.Y, 1974.
Maier, D. y Warren, D.S. Computing with logic. Logic programming with Prolog.
Benjamin-Cummings, Menlo Park, Calif, 1988.
Mandado, E. Sistemas electrónicos digitales. (7a. ed.). Marcombo, Barcelona,
1991.
701
Manna, Z. y Pnueli, A. The modal logic of programs. Proc. 6th Int. Colloquium
on Automata, Languages and Programming. Springer Verlag (Lecture Notes
in Computer Science, Vol. 71), 1979, pp. 385-411.
Manna, Z. y Pnueli, A. Verification of concurrent programs: the temporal frame-
work. En Boyer, R.S. y Moore, J.S. (eds.): The correctness problem in com-
puter science. Academic Press, New York, 1981, pp. 215-273.
Manna, Z., y Wolper, P. Synthesis of communicating processes form temporal
logic. ACM Trans. Progr. Lang. andSyst., 6 (1984), pp. 68-93.
Manna, Z., Mathematical theory of computation. McGraw-Hill, N.Y., 1974.
Mano, M.M. Digital design, 2nd. ed. Prentice-Hall, Englewood Cliffs, N.J., 1991.
Mano, M.M. y Kime, C.R. Logic and computer design fundamentals. Prentice-
Hall, Englewood Cliffs, N.J., 1994.
Martin, J. y Odell, J. Object-oriented analysis and design. Prentice-Hall, Engle-
wood Cliffs, NJ, 1992.
Martin, M.A. y Fateman, R.J. The MACSYMA system. Proc. 2nd Symp. Sym-
bolics and Algebraic Manipulation. Los Angeles, Ca., 1971, pp. 59-75.
Matz, D. What Is a Turing machine simulator? Accesible en la Internet en la di-
rección: http://odin.wosc.osshe.edu/cs407/matzd/turing.html
McCabe, T.J. A complexity measure. IEEE Trans. Softw. Eng., die. 1976, pp. 308-
320.
McCarthy, J. y Painter, J. Correctness of a compiler for arithmetic expressions.
En J.T. Schwartz (ed.): Mathematical aspects of computer science. American
Mathematical Society, 1967, pp. 33-41.
McCarthy, J. Recursive functions of symbolic expressions and their computation
by machine. Comm. ACM, 3, 4 (1960), pp. 184-195.
McCarthy, J. A basis for a mathematical theory of computation. Proc. IFIP Con-
gress 62, North Holland, Amsterdam, 1963.
McCulloch, W.S. y Pitts, W. A logical calculus of the ideas immanent in nervous
activity. Bulletin of Mathematical Biophysics, 5 (1943).
McDermott, D. A temporal logic for reasoning about plans and actions. Cognitive
Science, 6 (1982), pp. 101-155.
McDermott, D. y Doyle, J. Non-monotonic logic. Artificial Intelligence, 13
(1980), pp. 27-39.
McNaughton, R. y Yamada, H. Regular expressions and graphs for automata. IRE
Trans. Elec. Comp., EC-9 (1960), pp. 39-47.
Mead, C. y Conway, L. Introduction to VLSI systems. Addison- Wesley, Reading,
Mass., 1980.
Mealy, G.H. A method for synthetising sequential circuits. Bell System Tech. J.,
34 (1955), pp. 1045-1079.
Mendel, J.M. Fuzzy logic systems for engineering: a tutorial. Proc. IEEE, 83, 3
(Mar. 1995), pp. 345-377.
Meyer, B. Object-oriented software construction. Prentice-Hall, Englewood
Cliffs, NY, 1988.
Michalewicz, Z. Genetic algorithms + data structures = evolution programas.
Springer-Verlag, Berlin, 1992.
Michalski, R.S. Variable-valued logic and its applications to pattern-recognition
and machine learning. En D. Rine (ed.): Multiple-valued logic and computer
science. North-Holland, Amsterdam, 1975, pp. 506-534.
Michalski, R.S, Carbonell, J.G. y Mitchell, T.M. (eds.) Machine learning: An ar-
tificial intelligence approach. Tioga, Calif, 1983. (Publicado en Europa por
Springer Verlag, Berlin, 1984).
Michalski, R.S, Carbonell, J.G. y Mitchell, T.M. (eds.) Machine learning: An
artificial intelligence approach, vol. II. Morgan Kaufmann, Los Altos, Calif,
1986.
Michalski, R.S. y Chilausky, R.L. Learning by being told and learning from
examples: and experimental comparison of the two methods of knowledge
acquisition in the context of developing an expert system for soybean disease
diagnosis. Policy Analysis and Information Systems, 4,2 (Jun. 1980), pp. 125-
160.
Michalski, R.S. y Tecucci, G. (eds.) Machine learning: a multistrategy approach,
vol. TV. Morgan Kaufmann, San Francisco, Calif, 1994.
Mills, H.D. The new math of computer programming. Comm. ACM, 18, 1 (ene.
1975).
Minski, M. A framework for representing knowledge. En P. Winston (ed.): The
psychology of computer vision. McGraw-Hill, N.Y, 1975, pp. 211-277.
Minsky, M. y Papert, S. Perceptrons. MIT Press, Cambridge, Mass, 1969.
Mitchell, M , Crutchfield, J.P. y Hraber, P.T. Evolving cellular automata to
perform computations: mechanisms and impediments. Santa Fe Institute Wor-
king Paper 93-11-071. Accesible mediante "ftp" en la Internet:
servidor "santafe.edu"
directorio "/pub/Users/mm/"
ficheros "sfi-93-ll-071.partl.ps.Z" y "sfi-93-ll-071.part2.ps.Z".
Mitra, S. y Pal, S.K. Fuzzy multilayer Perceptron, inferencing and rule generation.
IEEE Trans. Neural Networks, 6 , 1 (Jan. 1995), pp. 51-63.
Mompin, J. (coord.) Inteligencia artificial. Conceptos, técnicas y aplicaciones.
Marcombo, Barcelona, 1987.
703
Moore, E.F. Gedanken-experiments on sequential machines. Automata studies:
Annals of mathematical studies, No. 34, Princeton Univ. Press, Princeton, N J.,
1956, pp.129-153.
Moore, R.C. A formal theory of knowledge and action. En Hobbs, J.R. y Moore,
R.C. (eds.): Formal theories of the common sense world. Ablex, Norwood,
N.J., 1984.
Morgan, Ch., ed., Smalltalk. BYTE, vol.6, no. 8, agosto 1981.
Murata, T. Petri nets: properties, analysis, and applications. Proc. IEEE, 77, 4
(Apr. 1989), pp. 541-580.
Myhill, J. Linear bounded automata. WADD Tech. Note 60-165, Wright Patter-
son Air Force Base, Ohio, 1960.
Narendra, K.S. y Thathachar, M.A.L. Learning automata. An introduction. Pren-
tice-Hall, Englewood Cliffs, N.J., 1989.
Naur, P. (ed.). Revised report on the algorithmic language ALGOL 60. Comm.
ACM., 6 , 1 (1963), pp. 1-17.
Nilsson, J J . Principles of artificial intelligence. Springer Verlag, Berlin, 1982.
(Traducción de J. Fernández-Biarge: Principios de inteligencia artificial. Díaz
de Santos, Madrid, 1987).
Oberman, R.M.M. Disciplines in combinational and sequential circuit design.
McGraw-Hill, N.Y., 1970.
Oettinger, A.G. Automatic syntactic analysis and the pushdown store. Proc.
Symp. Applied Math., Amer. Math. Soc., Providence, Rhode Island, 1961.
Osherson, D.N., Strob, M. y Weinstein, S. Systems that learn. An introduction to
learning theory for cognitive and computer scientists. MIT Press, Cambridge,
Mass., 1986.
Ott, G. y Feinstein, N. Design of sequential machines from their regular expres-
sions. Journal of the ACM, 8,4 (1961), pp. 585-600.
Patterson, D.A. y Hennessy, J.L. Computer organization and design. The hard-
ware/software interface. Morgan Kaufmann, San Mateo, Calif., 1994. (Tra-
ducción de J.M. Sánchez: Organización y diseño de computadores. La interfaz
hardware/software. McGraw-Hill Interamericana de España, Madrid, 1995).
Pauker, S.G., Gorry, G.A., Kassirer, J.P. y Schwartz, W.B. Towards the simu-
lation of clinical consultation. Taking a present illness by computer. American
Journal of Medicine, 60 (1976), pp. 981-996.
Pearl, J. Probabilistic reasoning in intelligent systems. Morgan Kaufmann, Palo
Alto, Calif., 1988.
Peterson, J.L. Petri nets. Computing Surveys, 9, 3 (sep. 1977), pp. 223-251.
Petri, C.A. Kommunication mit automaten. Univ. Bonn, 1962. (Versión traducida
al inglés en Supplement 1 to Technical Report RADC-TR-65-377, vol. 1, Ro-
me Air Development Center, Griffis Air Force Base, New York, 1965).
Piatetsky-Shapiro, G. (ed.) KDD-93: Proceedings of AAAI-93 knowledge
discovery in databases workshop. AAAI Press, 1993.
Piatetsky-Shapiro, G. y Frawley, W.J. Knowledge discovery in databases. AAAI-
MIT Press, Menlo Park, Calif, 1991.
Pittman, T. y Peters, J. The art of compiler design: theory and practice. Prentice-
Hall, Englewood Cliffs, N.J, 1992.
Pople, H.R, Myers, J.D. y Miller, R.A. DIALOG: A model of diagnostic logic for
internal medicine. Proc. 4th Int. Joint Conf. Artif. Int.. Tbilisi (URSS), 1975,
pp. 848-855.
Post, E. Formal reduction of the general combinatorial problem. American Jour-
nal of Mathematics, 65 (1943), pp. 197-268.
Prerau, D.S. Developing and managing expert systems. Proven techniques for
business and industry. Addison-Wesley, Reading, Mass, 1990.
Pucknell, D.A. y Eshraghian, K. Basic VLSI design, 3rd. ed. Prentice-Hall, Engle-
wood Cliffs, N J , 1994.
Pylyshyn, Z.W. Perspectives on the computer revolution. Prentice-Hall, Engle-
wood Cliffs, N.J, 1970. (Traducción de L. García Llórente: Perspectivas de la
revolución de los computadores. Alianza, Madrid, 1975).
Pylyshyn, Z.W. y Bannon, L.J. Perspectives on the computer revolution, 2nd. ed.
Ablex Publishing, Norwood, N.J, 1989.
Quillian, M.R. Semantic memory. En M. Minsky (ed.): Semantic information
processing. M.I.T. Press, Cambridge, Mass, 1968, pp. 354-402.
Quinlan, J.R. Discovering rules from large collections of examples: a case study.
En D. Michie (ed.): Expert systems in the microelectronic age. Edinburgh
Univ. Press, 1979.
Quinlan, J.R. Induction of decision trees. Machine Learning, 1 (1986), pp.81-106.
Rabin, M.O. Probabilistic automata. Information and control, 6, 3 (1963), pp.
230-245.
Rabin, M.O. y Scott, D. Finite automata and their decision problems. IBM Journal
Res. Dev., 3 (1959), 2,114-125.
Randell, B. y Russell, L.J .Algol 60 implementation. Academic Press, N.Y, 1964.
Rawlings, G. J.E. (ed.) Foundations of genetic algorithms. Morgan Kaufmann,
San Mateo, Calif, 1991.
Reisig, W. Petri nets. Springer-Verlag, Berlin, 1985.
Rescher. N. Many-valued logic. McGraw-Hill, New York, 1969.
705
Ribeiro, J.L., Treleaven, P.C. y Alippi, C. Genetic-algorithm programming envi-
ronments. Computer, 27, 6 (Jun. 1994), pp. 28-43.
Rich, E. y Knight, K. Artificial intelligence (2nd. ed.) McGraw- Hill, New York,
1991. (Traducción de P.A. González y F. Trescastro: Inteligencia artificial.
McGraw-Hill Iberoamericana de España, Madrid, 1994).
Robinson, J.A. A machine-oriented logic based on the resolution principle. Jour-
nal of the ACM, 12,1 (ene. 1965), pp. 23-41.
Robinson, J.A. Logic: form and function. Edinburg University Press, 1979.
Rosenblatt, F. Principles of neurodynamics, Perceptrons and the theory of brain
mechanisms. Spartan Books, Washington D.C., 1962.
Rubin, K.S. y Goldberg, A. Object behavior analysis., Comm. ACM, vol. 35, no
9, pp. 48-62, sept., 1992.
Rumbaugh, J., Blaha, M., Premerlani, W., Eddy, F. y Lorenson, W. Object-
oriented modelling and design. Prentice-Hall, Englewood Cliffs, NJ, 1991.
Rumelhart, D.E. y McClelland, J.L. (eds.) Parallel distributed processing. MIT
Press, Cambridge, Mass., 1986.
Rumelhart, D.E., Hinton, G.E. y Williams, R.J. Learning internal representations
by error propagation. En Rumelhart y McClelland (1986), Vol.1, Ch.8.
Sáez Vacas, F. Guía para un análisis estructurado de la programación estruc-
turada. Inforprim 1975. Proceso de Datos, num. 54, ene.-feb. 1976.
Sáez Vacas, F. Complejidad y tecnología de la información. Instituto Tecnológico
Bull, Madrid, 1992, reedición E.T.S.I. Telecom., Madrid, 1994.
Salmon, W.I. Introducción a la computación con Turbo Pascal. Addison-Wesley
Iberoamericana, 1993.
Samuel, A. Some studies in machine learning using the game of checkers. IBM
Journal of Research and Development, 3 (1959).
Samuel, A. Some studies in machine learning using the game of checkers. Part II.
IBM Journal of Research and Development, 11 (1967).
Sanders, G. Hardware design. A modern introduction. Prentice- Hall, Englewood
Cliffs, N.J., 1993.
Scala, J.J. y Minguet, J.M. Informática II. Unidad didáctica 3. Universidad
Nacio-nal de Educación a Distancia, 1974.
Schaffer, J.D. (ed.) Proceedings of the third international conference on genetic
algorithms and their applications. Morgan Kaufmann, San Mateo, Calif, 1989.
Schank, R.C. y Abelson, R.P. Scripts, plans, goals, and understanding. Lawrence
Erlbaum, Hillsdale, N.J., 1977.
Scott, D. y Strachey, C. Towards a mathematical semantics for computer langua-
ges. Proc. Symp. Computers and Automata, 1971, y en Technical Monograph
PRG-6, Oxford Univ. Comp. Lab., pp. 19-46.
Sejnowski, T.J. y Rosemberg, C.R. NetTalk: a parallel network that learns to read
aloud. Technical Report TR-86-01, Dep. Electrical Eng., John Hopkins Univ,
1986.
Shafer, G. A mathematical theory of evidence. Princeton University Press,
Princeton, N.J, 1976.
Shannon, C.E. The synthesis of two-terminal switching circuits. Bell System Tech.
J., vol. 28 (1949), pp. 59-98.
Shannon, C.E. A symbolic analysis of relay and switching circuits. Van Nostrand,
N.Y, 1954.
Shastri, L. (guest ed.) Fuzzy logic symposium. IEEE Expert, 9,4 (Aug. 1994), pp.
2-49 (incluye 17 contribuciones de 23 autores).
Sheffer, H.M. A set of five independent postulates for boolean algebras, whith
application to logical constants. Trans. Amer. Math. Soc., 14 (1913).
Shields, M.W. An introduction to automata theory. Blackwell Scientific Publ,
1987.
Shlaer, S. y Mellor, S.J. Object-oriented system analysis: modelling the world in
data. Prentice-Hall, Englewood Cliffs, NJ, 1988.
Shooman, M.L. Software engineering. McGraw-Hill, International Student Edi-
tion, Auckland, 1983.
Shortliffe, E.H. Computer-based medical consultations. Elsevier, N.Y, 1976.
Silva, M. Las redes de Petri en la automática y la informática. AC, Madrid, 1985.
Simpson, P.K. Fuzzy min-max neural networks - Part I: Classification. IEEE
Trans. Neural Networks, 3, 5 (Sep. 1992), pp. 776-786.
Simpson, P.K. Fuzzy min-max neural networks - Part II: Clustering. IEEE Trans.
Fuzzy Systems, 1 , 1 (Feb. 1993), pp. 32- 45.
Singh, J. Teoría de la información, del lenguaje y de la cibernética (2a. ed.) Alian-
za, Madrid, 1976.
Skansholm, J. Ada: from the beginning. 2a. ed, Addison-Wesley, Wokingham,
Engl, 1994.
Skolem, T. Uber die mathematishe logik. Norsk matematisk tidsskrift, 10 (1928),
pp. 125-142. Versión traducida al inglés en van Heijenoort, J. (ed.): From
Frege to Gódel. Harvard University Press, 1967, pp.508-524.
Soucek, B. Neural and intelligent systems integration. John Wiley, New York,
1991.
Srinivas, M. y Patnaik, L.M. Genetic algorithms: a survey. Computer, 27, 6 (Jun.
1994), pp. 17-26.
Steimann, F. y Adlassnig, K.P. Clinical monitoring with fuzzy automata. Fuzzy
sets and systems, 61 (1994), pp. 37-42.
707
Sterling, L. y Shapiro, E. The art of Prolog. MIT Press, Cambridge, Mass., 1986.
Stewart, I. Conceptos de matemática moderna. Alianza, Madrid, 1977.
Stone, H.S. Introduction to computer organization and data structures. McGraw-
Hill, N.Y., 1972.
Stroustrup, B. The C+ + programming language. Addison-Wesley, Reading,
Mass., 1986.
Tabourier, Y., Rochfeld, A. y Frank, C. La programmation structurée en infor-
matique. Les Editions d'Organisation, Paris, 1975.
Tennant, H. Natural language processing. Petrocelli, New York, 1981.
Tenny, T. Structured programming in Fortran. Datamation, jul. 1974.
Tocci, R.L. Digital systems (6th ed.) Prentice-Hall, Englewood Cliffs, N.J., 1995.
Toffoli, T y Margolus, N. Cellular automata machines. A new environment for
modeling. MIT Press, Cambridge, Mass., 1987.
Trakhtenbrot, B. A. Algoritmos. En Z. W. Pylyshyn: Perspectivas de la revolución
de los computadores. Alianza Universidad, 1975, pp. 108-130.
Trigoboff, M. y Kulikowski, C.A. IRIS: a system for the propagation of inferences
in a semantic net. Proc. 5th Int. Joint Conf. Artif. Intell., Cambridge, 1977, pp.
274-280.
Tsetlin, M.L. Sobre el comportamiento de autómatas finitos en entornos aleatorios
(en ruso). Automatika i telemekhanika, 22,10 (oct. 1961), pp. 1345-1354.
Tucker, A.B. Programming languages (2a. ed.) Mc-Graw-Hill, N.Y., 1986. (Tra-
ducción de J.M. Troya: Lenguajes de programación. McGraw-Hill, Madrid,
1987).
Tucker, A.B., Bradley, W.J., Cupper, R.D., y Garnick, D.K. Fundamentals of
computing I. McGraw-Hill (Schaum), Hightstown, NJ, 1992.
Turing, A. Computing machinery and intelligence. Publicado originalmente en
Mind: a quaterly review of psychology and philosophy (1950). Puede
encontrarse traducción en Z.W. Pylyshyn: Perspectivas de la revolución de los
computadores, Alianza, Madrid, 1975, pp. 305-333.
Turner, R. Logics for artificial intelligence. Ellis Horwood, Chichester (UK),
1984.
Ullman, J.D. Principles of database and knowledge-base systems. Vol. I. Com-
puter Science Press, Rockville, Md., 1988.
Ullman, J.D. Principles of database and knowledge-base systems. Vol. II\ The
new technologies. Computer Science Press, Rockville, Md., 1989.
Varshavskii, V.I. y Vorontsova, I.P. Sobre el comportamiento de autómatas esto-
cásticos con estructura variable (en ruso). Automatika i telemekhanica, 24, 3
(mar. 1963), pp. 353-360.
Vega, M. de. Introducción a la psicología cognitiva. Alianza Editorial, Madrid,
1985.
Veitch, E.W. A chart method for simplifying truth funtions. Proc. ACM, May.
1952, pp. 127-133.
Virant, J. y Zimic, N. Fuzzy automata with fuzzy relief. IEEE Trans. Fuzzy
Systems, 3 , 1 (Feb. 1995), pp. 69-74.
Von Neumann, J. The general and logical theory of automata. En Cerebral
machanisms in behaviour - TheHixon Symposium. John Wiley, N.Y, 1951.
Von Neumann, J. Probabilistic logic and the syntesis of reliable organisms from
unreliable components. En C. Shannon y J. McCarthy (eds.): Automata
studies, Princeton Univ. Press, Princeton, N.J, 1956.
Von Neumann, J. (ed. A. Burks). Theory of self-reproducing automata. Univ.
Illinois Press, Urbana, 1966.
Wakerly, J.F. Digital design, 2nd. ed. Prentice-Hall, Englewood Cliffs, N.J,
1993.
Walker, A , McCord, M , Sowa, J.F. y Wilson, W.G. Knowledge systems and
Prolog. Addison-Wesley, Reading, Mass, 1987.
Wang, H. Juegos, lógica y computadores. En Computadoras y computación. Ed.
R.R. Fenichel y J. Weizenbaum. Blume, 1974, pp. 150-158. Edición inglesa:
W.H. Freeman. (El artículo de Wang se publicó en 1965 en el Scientific
American).
Warmer, J.D. Programación lógica. Tomos I y II, Editores Técnicos Asociados,
Barcelona, 1973.
Watt, D.A. Programming language concepts and paradigms. Prentice-Hall,
Engle-wood Cliffs, N.J, 1990.
Watt, D.A. Programming language sintax and semantics. Prentice-Hall, Engle-
wood Cliffs, N.J, 1991.
Watt, D.A. Programming language processors. Prentice-Hall, Englewood Cliffs,
N.J, 1993.
Wee, W.G. y Fu, K.S. A formulation of fuzzy automata and its application as a
model of learning systems. IEEE Trans. Syst. Sci. Cyb., SSS5 (1969), pp. 215-
223.
Weiss, S.M. y Kulikowski, C.A. EXPERT: A system for developping consul-
tations models. Proc. 6th Int. Joint Conf. Artif. Int.. Tokyo, 1979, pp. 942-947.
Weiss, S.M, Kulikowski, C.A. y Safir, A. Glaucoma consultation by computer.
Computers in Biology and Medicine, 8 (1978), pp. 25- 40.
709
Whitehead, A.N. y Russel, B. Principia Mathematica. Cambridge, 1910 (vol. I),
1912 (vol. II), 1913 (vol. III). Segunda edición en Cambridge Univ. Press,
1950.
Whitley, D. (ed.) Foundations of genetic algorithms. Morgan Kaufmann, San
Mateo, Calif., 1992.
Widrow, B. Generalization and information storage in networks of adaline "neu-
rons". En M. Yovitz, G.T. Jacobi y G.D. Goldstein (eds.): Self-Organizing
Systems. Spartan Books, Washington D.C., 1962, pp.435-461.
Widrow, B. y Lehr, M.A. 30 years of adaptive neural networks: perceptron,
madaline and backpropagation. Proc. IEEE, 78, 9 (Sep.1990), pp.1415-1442.
Wilkinson, B. y Makki, R. Digital system design, 2nd. ed. Prentice-Hall, Engle-
wood Cliffs, N.J., 1992.
Winblad, A.L., Edwards, S.D. y King, D.R. Object-oriented software. Addison-
Wesley, Reading, Mass., 1990.
Winograd, S. y Cowan, J.D. Reliable computation in the presence of noise. M.I.T.
Press, Cambridge, Mass., 1963.
Winston, P.H. y Horn, B.K.P. LISP (3rd. ed.) Addison-Wesley, Reading, Mass.,
1991.
Wirfs-Brock, R., Wilkerson, B. y Wiener, L. Designing object-oriented software.
Prentice-Hall, Englewood Cliffs, NJ, 1990.
Wirth, N. The programming language Pascal. Acta Informática, 1 , 1 (1971), 35-
36.
Wirth, N. Algorithms + data structures = programs. Prentice-Hall, 1976 (Tra-
ducción de A. Alvarez y J. Cuena: Algoritmos + estructuras de datos = pro-
gramas. Ediciones del Castillo, Madrid, 1980, 4a. impr., 1985).
Wirth, N. Algoritmos y estructuras de datos. Investigación y Ciencia, num. 98,
nov., 1984, pp. 24-35.
Wolf, W. Modern VLSI design. A CAD-based approach. Prentice-Hall, Engle-
wood Cliffs, N.J., 1994.
Wolfram, S. (ed.) Theory and applications of cellular automata. World Scientific,
Singapore, 1986.
Yager, R.R. y Filev, D.P. Essentials of fuzzy modelling and control. John Wiley,
New York, 1994
Yourdon, E., Techniques ofprogram structure and design. Prentice-Hall, Engle-
wood Cliffs, N.J., 1975.
Zadeh, L.A. Fuzzy sets. Information and Control, 8 (1965), pp. 338-353.
Zadeh, L.A. Fuzzy algorithms. Information and control, 12 (1968), pp. 94-102.
Zadeh, L.A. Biological applications of the theory of fuzzy sets and systems. En
L.D. Proctor (ed.): Biocybernetics of the central nervous system. Little, Brown
and Co., Boston, Mass., 1969, pp. 199-212.
Zadeh, L.A. Outline of a new approach to the analysis of complex systems and
decision process. IEEE Trans. Systems, Man, and Cyb., SMC-3 (1973), pp. 28-
44
Zadeh, L.A. Fuzzy logic and its applications to approximate reasoning. Proc. IFIP
Congress Information Processing 74, North- Holland, Amsterdam, 1974, pp.
591-594.
Zadeh, L.A. Fuzzy sets as a basis for a theory of possibility. Fuzzy sets and
systems, 1 (1978), pp. 3-28.
Zadeh, L.A. A theory of approximate reasoning. Machine Intelligence, 9. John
Wiley, New York, 1979, pp. 149-194.
Zadeh, L.A. The calculus of fuzzy if-then rules. AIExpert, 7,3 (1992), pp. 22-27.
Ziarko, W. (ed.) Rough sets and knowledge discovery. Springer- Verlag, Berlin,
1994.
711
Indice
alfabético
713
B definición 5 1 9
del software 4 0 5 , 5 3 7
Backus, notación de 629 espacial 5 2 3
Bajo nivel, lenguaje de 6 1 4 exponencial 5 2 8
B a s e de conocimientos 2 2 3 medidas 526
B a s e de datos 224 polinómica 5 2 8
B a s e de datos deductiva 685 presentación 4 0 4
Biestable 3 1 2 temporal 5 2 3
BJ, diagramas 4 2 7 y máquina de Turing 5 2 0
B N F 629 Completitud 52,64,76,535
Borrosa Comportamiento
función de transición 379 de entrada-estados 288,295
lógica 196,206 de entrada-salida 277,295
regla de inferencia 2 1 2 Computabilidad 4 0 4
relación 201,203 Computable, problema 4 0 3
Borroso Concatenación 3 4
autómata 3 7 9 Conceptualización 60,158
subconjunto 198 Conductista, enfoque 385
Búsqueda Conectiva 40,53,66
exhaustiva 83 Conexionista, sistema 3 8 9
heurística 2 2 1 Conjunto
borroso 198
c regular 3 4 0
Conocimiento
Cadena 33,53
adquisición de 223,385
Cadena vacía 33,566,605
base de 2 2 3
Cálculo 5 1
ingeniería del 2 2 3 , 2 2 4 , 3 8 4
Canónica, forma 125
Consistencia 5 2 , 6 4 , 7 6
Cascada, metodología en 4 4 9
Contador binario 2 9 3
Caso de sustitución 177
Contradicción 6 4
Castigo, probabilidades de 3 7 8
Convivencial, programa 4 5 3
Categoría sintáctica 6 6 2
C O R B A (Common Object Request Broker
Celular, autómata 3 8 2
Certidumbre, factor de 2 3 7 Architecture) 4 6 6
Ciclomático, número 5 4 1 Cuantificador
Circuito lógico alcance 154
combinacional 96 existencial 144
secuencial 310 universal 144
Cláusula 7 8 , 1 7 2
D
de Horn 81,176,627
semántica 6 4 9 D (biestable) 313
Clases 4 5 4 D e Morgan, leyes de 59,68
lógica de 189 Declarativa, programación 625
Cognoscitivo, enfoque 385,388 Declarativo, lenguaje 614,625
Compilador 615,661 Deductiva, base de datos 685
de compiladores 686 Deductivo, razonamiento 30,73,167
generación de código 665 Demostración 57,157
optimización 665 Denotacional, semántica 6 4 7
Complejidad computacional 404,519 Derivación, relación de 5 6 0
caso peor 5 3 2 Derivada de expresión regular 3 4 6
cota inferior 5 3 2 Desarrollo, entorno de 6 2 9
cota superior 5 3 2 Descubrimiento 3 9 1
Diagrama Fórmula atómica 143, 153
BJ 4 2 7 Fórmula molecular 154
de Moore 2 6 3 Función 152,159,623
de flujo 4 2 4 computable 5 0 8
sintáctico 640 de conmutación 102
Diseño descendente 4 3 3 de salida 2 6 2
Disparo de red de Petri 3 6 2 de transición 2 6 2
Dominio de transición borrosa 3 7 9
semántico 647 de transición de red de Petri 3 6 4
sintáctico 6 4 7 recursiva 5 0 8
Funcional, programación 626
E
G
Ejecución de red de Petri 3 6 3
Ejemplar 177,248 Genético, algoritmo 3 8 6 , 3 9 3
Encadenamiento Generación de código 665
hacia adelante 2 2 8 , 2 3 2 Godel, números de 5 1 0
hacia atrás 2 2 8 , 2 3 3 Gramática
Encapsulamiento 4 5 7 ambigua 5 8 1
Enlace dinámico 4 5 7 de lenguaje de programación 631
Ensamblador, lenguaje 6 1 4 , 6 1 9 , 6 5 2 definición 5 5 9
Entorno 629,644 equivalencia 5 6 1
Entrada-estados, comportamiento de 288,295 generativa 568
Entrada-salida, comportamiento de 277,295 lenguaje generado por 561
Entrenamiento 3 8 5 , 3 8 7
Equirrespuesta, relación 2 9 0 , 3 3 7 H
Equivalencia 6 4
Herencia 4 5 6
de autómatas 2 7 8
Herramienta 224,628,644,685
de gramáticas 5 6 1
Heurística, búsqueda 2 2 1
de sentencias 55,64,167
Heurístico 2 2 1 , 2 4 3
Esquema de refuerzo 377
Estado 2 5 7 2 6 1 I
de red de Petri 3 6 2
Estocástico Identidad, lógica con 190
autómata 373 Imperativa, programación 625
reconocedor 3 9 2 Implicación
Evaluación 61,161 estricta 1 9 1
binaria 41,62,105 lógica 72,167
Exclusión mutua 3 6 7 material 4 3
Existencial, cuantificador 1 4 4 Imprecisión 2 3 6
Experto, sistema 2 2 2 Incertidumbre 2 3 6
Explorador 662 Incompatibilidad, principio de 197
Expresión regular 3 4 1 Indecidible, problema 5 1 5
Inferencia
F abductiva 192
bayesiana 2 3 6
Factor de certidumbre 2 3 7 borrosa 2 1 2
Finito, reconocedor 3 3 4 imprecisa 196
Física del software 538 plausible 2 3 5
Forma canónica 125 regla de 7 3
Forma clausulada 7 8 , 1 7 2 Inferencial
Formación de conceptos 3 9 1 proceso 7 6
Formal, lógica 2 4
715
sistema 76 Lógica 2 9
Inferencias, motor de 2 2 3 0+ 2 3 3
Ingeniería del conocimiento 2 2 3 , 2 2 4 , 3 8 4 borrosa 196,206
Instrucción con identidad 190
de máquina 615 de clases 189
de retorno 617 de predicados 141
de salto 6 1 7 de proposiciones 3 9
de salto a subprograma 6 1 7 de relaciones 189
Intérprete 611 formal 2 9
Inteligencia artificial 31,219,384,569 implicación 72,167
Interpretación 41,60,159 modal 191
de red de Petri 366 multivalorada 193
pretendida 160 no monótona 192
probabilitaria 195
J programación 6 2 7
puerta 9 4
JK (biestable) 3 1 3 temporal 193
trivalorada 194
K
Lógico, circuito
Karnaugh, tabla de 110 combinacional 96
secuencial 310
L
M
Léxico, análisis 662,666,672
Lectores y redactores 3 6 7 Máquina
Lenguaje 34,551,686 aprendizaje en 3 8 4
ambiguo 5 8 1 de Mealy 2 6 4
de alto nivel 614,621 de Moore 2 6 4
de bajo nivel 6 1 4 de programa almacenado 6 1 7
de máquina 611,615 virtual 4 0 2 , 6 1 2
de programación 614 Máquina de Turing 4 0 3 , 4 7 0
declarativo 614,625 cálculo 4 7 6
ensamblador 6 1 4 , 6 1 9 , 6 5 2 composición 4 8 2
fuente 6 1 2 definición 4 7 0
generado por una gramática 5 6 1 descripción instantánea 4 7 4
jerarquía de 565 diagrama de estados 4 7 7
macroensamblador 621 diseño 4 8 6
objeto 612 esquema funcional 4 7 7
OOP 465 presentación 4 0 3
regular 595 simulación por ordenador 4 9 1
tipo 0 y máquina de Turing 5 1 5 simulador 5 0 0
transportable 6 1 4 universal 495
procesador de 6 1 2 , 6 5 2 y algoritmos 4 0 3
tipos de 564 y complejidad 5 2 0
y autómatas 589 y función computable 5 0 8
Lex 6 8 6 y lenguaje tipo 0 5 1 5
Ley 52,57 M.A.P.S. (Methodology for Algorithmic
L e y e s de de Morgan 59,68 Problem Solving) 4 9 9
Libre de contexto, gramática 565 Macroensamblador, lenguaje 6 2 1
Línea de retardo 3 1 1 Marcado de red de Petri 3 6 2
Lingüística, aproximación 2 1 3 Marco 248
Literal 53 Mealy, máquina de 2 6 4
716
Mensajes 455 Petri, red de 360
Metalenguaje 35,341,552 Pila 5 9 3
Metodologías Poliádico, predicado 143
de análisis orientado a objetos 4 6 1 Polimorfismo 4 5 7
de diseño orientado a objetos 4 6 1 Pragmática 53,553
en cascada 4 4 9 Predicado 142
Métodos 4 5 6 monádico 142
Minería de datos 391 poliádico 143
Minimización de autómatas 2 9 7 Predicados, lógica de 141
Modal, lógica 191 Premio Turing 4 0 3
Modelo 165 Probabilístico, autómata 3 7 3
Modus ponens 58,158 Probabilidades
Modus tollens 5 8 , 1 5 8 de castigo 378
Monádico, predicado 142 de transición 3 7 4
Monoide de un autómata 291 Probabilitaria, lógica 195
Moore Problema
diagrama de 263 computable 403
máquina de 2 6 4 de aplicabilidad 515
Motor de inferencias 2 2 3 de la deducción 4 1 9
Multivalorada, lógica 193 indecidible 515
NP 534
N P-NP 534
tamaño del 533
N A N D 66,130,133
Procedimiento 623
Neurona 3 8 6
Procesador
Neuronal, red 386
de lenguaje 6 1 2 , 6 5 2
N o monótona, lógica 192
de objetivos 683
N O R 66,130,133
de reglas 683
N O T 95
Proceso inferencial 76
Notación de Backus 629
Producción 559
NP, problemas 5 3 4
regla de 2 2 4
Número ciclomático 541
sistema de 225
Números de Godel 5 1 0
Productores y consumidores 370
O Programa
análisis 4 4 8
Objetivos, procesador de 683 codificación 448
Objetos convivencial 4 5 3
análisis orientado a 4 5 8 correcto 4 5 1
diseño orientado a 4 5 8 definición 4 2 4
propiedades de 4 5 6 diseño 4 4 8
tecnología de 466 estructurado 428, 4 3 2
OOP, lenguaje 465 limpio 4 2 7
Operacional, semántica 645 robusto 4 5 3
Optimización, fase de 665 Programación
OR 95 a gran escala 5 3 7
OR exclusivo 130 con Pascal y C 4 3 7
Organigrama 4 2 6 estructurada 4 2 3
orientada a objetos 4 5 3
P entorno de 629,644
P-NP, problemas 5 3 4 lenguaje de 6 1 4
Paridad, detector de 2 6 7 , 2 9 1 , 3 2 2 tipos de 625
Perceptron 386 Proposicional, variable 39,53
Proposiciones, lógica de 39 Reutilización 4 5 8
Prueba de Turing 220 Robusto, programa 4 5 3
Puerta lógica 9 4
s
R
Salida, función de 2 6 2
Razonamiento 29,39,73 Salto, instrucción de 6 1 7
deductivo 30,73 Satisfacción 6 3 , 1 6 1
válido 30,73,167 Secuencia de formación 54,153
Reconocedor Semáforo 3 6 7
de Turing 5 9 0 Semántica 35,60,158,162,553,643
estocástico 3 9 2 cláusula 649
finito 3 3 4 red 2 4 9
finito, análisis 3 4 4 tipos de 645
finito, síntesis 3 4 6 Semántico
Recursividad 5 7 6 análisis 662,665
Recurso abstracto dominio 6 4 7
definición 4 3 2 Sensible al contexto, gramática 5 6 4
presentación 4 0 2 Sentencia 5 4 , 1 5 4 , 6 2 1
Red abierta 143, 155
de autómatas 3 8 3 cerrada 143, 155
de Petri 3 6 0 equivalente 5 5 , 6 4 , 1 6 7
de Petri binaría 366 válida 146,164
de Petri, interpetación 3 6 6 Seudoinstrucción 620
neuronal 3 8 6 Sincronización 3 6 7
semántica 2 4 9 Sintáctica, categoría 6 6 2
Refuerzo, esquema de 3 7 7 Sintáctico, dominio 647
Refutación 85,180 Sintagma 5 5 3
Regla Sintaxis 35,53,152,553,637
de escritura 5 5 9 Sistema
de inferencia 73 axiomático 5 1
de inferencia borrosa 2 1 2 conexionista 3 8 9
de producción 2 2 5 de producción 225
de resolución 178 experto 2 2 2
procesador de 683 inferencial 76
Regular PM 56,155
conjunto 3 4 0 Software
expresión 3 4 1 complejidad del 4 0 5 , 5 3 7
gramática 565 física del 538
Relación 142,159 SR (biestable) 3 1 2
borrosa 201,203 Subprograma 6 1 7
de congruencia derecha 338 Sumador binario 2 6 7 , 3 2 0
de derivación 5 6 0 Sustitución 56,156,176
equirrespuesta 290,337 caso de 177
entre objetos 456
Relaciones, lógica de 189 T
Resolución
Tabla
mpulsada por hechos 2 3 1
de Karnaugh 110
regla de 178
de transiciones 2 6 2
Restringida, gramática 5 6 4
Tautología 6 4 , 1 6 4
Retorno, instrucción de 6 1 7
Tecnología de objetos 4 6 6
Retropropagación 386
Temporal, lógica 193
Teorema 5 2 , 5 7 , 1 5 7
Término 153
u
Tesis 5 2 , 5 7 Unificación 178
Tipo de datos 6 2 4 Universal, cuantificador 144
Tipos de lenguaje 5 6 4 Universo del discurso 158
Traductor 6 1 2
Transición V
borrosa 3 7 9
Válido, razonamiento 30,73,167
función de 2 6 2
Variable
probabilidades de 3 7 4
booleana 104
tabla de 2 6 2
libre 1 5 4
Tripla O - A - V 2 3 4
Verdad, valores de 6 0
Trivalorada, lógica 194
Virtual, máquina 4 0 2 , 6 1 2
Turing (ver «máquina de Turing»)
premio 4 0 3 Y
prueba de 2 2 0
reconocedor de 5 9 0 Yacc 6 8 6 -