LOGICA COMPUTACIONAL TEMA Introducción Lógica de Proposiciones Fundamentos de Prueba de Teoremas GSAT Satisfactibilidad y complejidad Lógica de Predicados Formas Prenexas y Algoritmo Clausular Sustitución y Unificación Resolución y Completez Resolución Regla de una Literal de Davis y Putnam Regla de una Literal Estructurada con Regla de Partición Especificación Formal Lógicas de Hoare INTRODUCCIÓN La Lógica Formal proporciona un medio para representar argumentos de una manera formal y rigurosa, estudia los fundamentos relacionados con su validez y los métodos para inferir proposiciones a partir de otras consideradas válidas. Por su parte, la Lógica Computacional es una disciplina que estudia la aplicación de la Lógica Formal para la representación computacional de argumentos, las técnicas de deducción automática o asistida por computadora, los fundamentos relacionados con validez y completez (completeness) de sistemas de proposiciones y, las aplicaciones de esas técnicas a las diferentes áreas de las Ciencias Computacionales en todas las etapas del desarrollo del software, es decir, especificación, diseño, construcción y verificación formal de programas. La Lógica Computacional, sin embargo, no actúa de manera aislada. Para el establecimiento de fundamentos de las ciencias computacionales concurren conjuntamente con la Lógica Computacional, disciplinas como Teoría de la Computación y Análisis de Algoritmos; para el desarrollo de sistemas, la Lógica Computacional participa con la Ingeniería de Software para el establecimiento de Métodos Formales de Especificación y Verificación de Programas, los cuales pueden ser usados para el desarrollo de sistemas críticos y/o concurrentes. Por otra parte la Lógica Computacional en conjunción con otras disciplinas permite la resolución eficiente de problemas complejos, así por ejemplo Métodos de Optimización Combinatoria y de Lógica Computacional mezclados adecuadamente con métodos heurísticos de la Inteligencia Artificial ofrecen alternativas de solución a problemas computacionales muy dificiles que se les ha denominado NP completos. La Lógica Computacional es muy amplia, por lo que no se puede cubrir plenamente en un solo semestre. Por esa razón, para este curso se ha hecho una selección de temas representativos de esta disciplina. Se presentan las técnicas y principios básicos y sus áreas de aplicación. El curso hace énfasis en la Lógica Proposicional y en la Lógica de Predicados, debido a que de esa manera es mas fácil presentar ejemplos y aplicaciones sobre ésas lógicas, lo cual no quita ni generalidad a los conceptos ni valor a las aplicaciones; por otro lado, el aprendizaje de esas Lógicas es necesario para el entendimiento posterior de Lógicas No-Clásicas; sin embargo se hace una presentación de la Lógica Modal y Temporal, con información suficiente como para que el alumno empiece a realizar aplicaciones donde el factor tiempo sea crucial. Se hace un análisis de la Lógica de Hoare y se explican sus axiomas a la luz del Cálculo de Secuentes de Gentzen. Esto nos permitirá explicar métodos de especificación y verificación formal. Se discuten la importancia de la Lógica de Hoare en sistemas distribuídos y concurrentes. Debido a la amplitud de los temas, consideramos que es mas importante que el alumno aprenda a realizar investigación y a trabajar en equipo sobre aspectos de la Lógica Computacional y, a apreciar la importancia de la Lógica y de la Lógica Computacional, ya que de esa manera se habrá sembrado la semilla de aprender continuamente sobre está disciplina. Por otra parte el trabajo en equipo, no sólo facilita el aprendizaje, sino que además entrena al alumno a resolver los problemas como deben ser resueltos en esta sociedad: colaborativamente. LÓGICA PROPOSICIONAL En la Lógica Formal se estudian los principios y métodos a través de los cuales podemos determinar la validez de argumentos, desde el punto de vista solamente de su estructura, sin tomar en cuenta el contenido semántico de las expresiones de los argumentos. De esta manera si se argumenta que: Todos los majadistanenses son de Majadistán Rudistein es Majadistanense En consecuencia,Rudistein es de Majadistan. En este argumento, no tomamos en cuenta si los majadistanenses son humanos, perros, pericos o un concepto abstracto de cualquier área. Tampoco nos importa si Rudinstein es un ciudadado de alguna ciudad del mundo o si es el nombre de un perro. De esta manera desde el punto de vista de su estructura este argumento es válido. Se hace incapié que la Lógica no se hace responsable de su aplicación a nivel semántico. Se puede decir que la Lógica es una herramienta para el análisis de la veracidad de argumentos en base sólo a la estructura de éstos, donde el significado de los elementos que intervienen no es tomado en cuenta. El argumento anterior tiene dos partes principales: A) Las premisas: Todos los majadistanenses son de Majadistán Rudistein es Majadistanense B) La conclusión: Rudistein es de Majadistán De esta manera el argumento es válido, ya que de las premisas sigue la conclusión, lo cual hasta cierto punto nos parece totalmente natural. Consideremos el siguiente argumento: Argentina está en Africa o Argentina está en Asia. Argentina no está en Asia En consecuencia, Argentina está en Africa. Nuevamente este argumento es válido desde el punto de vista lógico, aún cuando sabemos que la conclusión es falsa. ¿Cómo puede ser ésto? ¿A partir de la Lógica se pueden obtener conclusiones equivocadas? La respuesta es afirmativa, ya que la lógica no verifica el significado de las premisas. Debido a lo anterior es necesario distinguir entre proposiciones verdaderas y proposiciones lógicamente verdaderas. Las primeras son verdaderas independientemente de su estructura, mientras que las segundos no lo son. De esta manera, las proposiciones: Argentina está en Africa o Argentina está en Asia Argentina está en Africa Son verdaderas lógicamente debido a que la primera es una premisa y a que la segunda ha sido derivada lógicamente de sus premisas. Las proposiciones son expresiones que pueden ser evaluadas como verdaderas o falsas. En los lenguajes naturales (Español, Inglés, etc), las proposiciones sólo pueden ser expresiones declarativas y nunca interrogativas o imperativas. De esta manera las siguientes son proposiciones: Los cantantes no duermen. Comer mucho, engorda Las montañas cantan bonito Los mosquitos viven menos de un año El hombre desciende del elefante Sin embargo, las siguientes no son proposiciones por no poder ser evaluadas como verdaderas ni falsas: ¡Levántate temprano! ¿Has entendido lo que es una proposición? ¡Estudia esta lección! ¿Cuál es la dirección de la página de Lógica Computacional? En este módulo estudiamos la lógica proposicional, es decir, se estudian los principios para determinar la validez de argumentos conformados con proposiciones. Esto involucra los siguientes tipos de proposiciones: * Proposiciones simples o átomos * Proposiciones compuestas Los átomos o proposiciones simples son tales que no es posible encontrar en ellas otras proposiciones, mientras que las proposiciones compuestas están conformadas de varias proposicones simples a través de lo que se denomina conectores lógicos, entre los cuales se encuentran: y, o, implica. Ejemplo de proposiciones compuestas son: Las montañas cantan bonito o Los mosquitos viven menos de un año. El hombre desciende del elefante y Comer mucho, engorda. CONECTIVAS LOGICAS Las conectivas lógicas también se llaman a veces operadores, y son de dos tipos: Operadores unarios: NEGACION: not, ¬ Operadores binarios: CONJUNCION: and, &, y DISYUNCION: or CONDICIONAL: implies, ==>, implica BICONDICIONAL: <==> FORMULAS BIEN FORMADAS El Cálculo Proposicional estudia fórmulas proposicionales simples o compuestas. Las proposiciones simples o átomos son representadas por símbolos, generalmente las letras del alfabeto A,B,C,.... Para obtener proposiciones compuestas se utilizan, como se dijo antes, conectores lógicos. Así la proposición compuesta A or B puede corresponder por ejemplo a: El coronel no tienen quien le escriba or La jubilación del Coronel Buendía es insuficiente para su familia Una fórmula bien formada (fbf) es una expresión que representa una proposición simple o compuesta, la cual esta bien escrita de acuerdo con determinada sintaxis. Ahora bien, una fbf del Cálculo Proposicional, es una fórmula que está bien escrita de acuerdo con la sintaxis del Cálculo Proposicional. Las reglas de la sintaxis del Cálculo Proposicional definen de esta manera la forma de escribir o reconocer susu fbf's. Estas reglas son: a) Un átomo es una fórmula bien formada. b) Si G es una fórmula bien formada entonces ¬G también lo es. c) Si G y H son fórmulas bien formadas, entonces también lo son: G&H G or H G ==> H G <==> H d) Todas las fbf's se obtienen aplicando a, b y c. Es necesario puntualizar en la regla c anterior, que es posible utilizar otras conectivas, pero sin embargo son reducibles a las que aqui presentamos. De esta manera, fijaremos nuestra atención solo a las fbf's que aquí describimos. Ejemplos de fórmulas bien formadas son: P&Q P ==> Q Ejemplos de fórmulas que no son bien formadas son: P &, ==>Q. DEMOSTRACIÓN Y REGLAS DE INFERENCIA RESUMEN En el Cálculo Proposicional, existen dos métodos comunes de realizar una demostración: Directo e Indirecto. Ambos métodos realizan una demostración obteniendo una sucesión de fórmulas F1,F2,...,Fn Donde cada una de estas fórmulas se obtiene a través de reglas de inferencia o es un axioma. Aquí se discuten lo dos métodos de demostración directo e indirecto y las principales reglas de inferencia utilizadas en dichos métodos. PALABRAS CLAVE: LÓGICA PROPOSICIONAL, DEMOSTRACIÓN, DEDUCCION, I NFERENCIA INTRODUCCIÓN Una fórmula G es una consecuencia lógica (CL) de un conjunto de fórmulas F1,F2,...,Fn, si cuando F1,F2,...,Fn son verdaderas, G también lo es. A partir de esta definición se han establecido dos teoremas: TEOREMA 1: G es una CL de F1,F2,..,Fn si y solo si F1Ù F2Ù ..Ù Fn Þ G es válida. TEOREMA 2: G es una CL de F1,F2,..,Fn si y solo si F1Ù F2Ù ..Ù FnÙ (~ G) es inconsistente. Para determinar sí una fórmula G sigue de un conjunto de fórmulas F1,F2..,Fn, se pueden utilizar tablas de verdad. Esto será verdad F1Ù F2Ù ..Ù Fn Þ G es válida o F1Ù F2Ù ..Ù FnÙ (~ G) es inconsistente. Otra alternativa es utilizar el enfoque deductivo, el cual considera las fórmulas involucradas (G y F1,..,Fn) dentro de una teoría formal, de modo que G pueda ser obtenida a partir de las fórmulas F’s (de ahí que se diga que G siga de las F’s). En el marco del enfoque deductivo, se dice que una Teoría Formal (TF) consiste de los siguientes elementos [DOWSING et al] [MENDELSON]: 1) Las reglas de sintaxis que definen las fórmulas que pueden ser tratadas en la TF. 2) Un conjunto de fórmulas llamadas axiomas las cuales se suponen verdaderas en la TF. 3) Un conjunto de Reglas de Inferencia que establece bajo que circunstancias una fórmula se puede obtener (derivar) a partir de otras existentes. La fórmula derivada será una CL de las formulas que le dieron origen. Dentro de cualquier rama de la Ciencia se pueden establecer teorías formales (o TF’s), cada una de los cuales tendrá sus propios axiomas. Por ejemplo el siguiente es un axioma de la física newtoniana: La aceleración de un cuerpo es proporcional al producto de su masa por la fuerza ejercida sobre él. Este axioma se describe por la fórmula: F=ma (1) Este es un axioma puesto que lo tomamos como verdadero en el contexto de la mecánica newtoniana. Es de observar que (1) fué establecido como verdadero partiendo a su vez de otros enunciados supuestos también verdaderos, lo cual nos remontaría a axiomas como los de la geometría de Euclides y así sucesivamente hasta llegar a axiomas relacionados con la existencia misma del ser y la verdad. Esto, si nos se tiene cuidado, podría llevarnos por caminos absurdos ó no, del dogmatismo. Podríamos pensar entonces que la ciencia es dogmática, sin embargo, la diferencia entre el dogmatismo y la ciencia estriba en que la ciencia constante investiga la veracidad de los axiomas y, en cuanto se descubre que uno de ellos es falso, se realizan un cambio de paradigma, es decir, un cambio en el conjunto de axiomas y de sus reglas de inferencia. El problema de la deducción está inmerso en todas las ramas de las Ciencias por lo que es necesario conocer no solo lo que significa sino también los mecanismos de inferencia que se pueden aplicar en ellas. DEMOSTRACIÓN Una demostración de una fórmula A es una sucesión de fórmulas P1,P2,..,Pn, tales que: a) Cada Pi es: * Un axioma o, * Una fórmula obtenida a partir de las anteriores. b) El último elemento Pn, es A, la fórmula que se desea demostrar. En la definición anterior las fórmulas que se mencionan en el inciso b) son obtenidas a partir de reglas de inferencia. Como se mencionó en la introducción, las reglas de inferencia nos dicen cuales son las condiciones para poder obtener por CL otra fórmula a partir de las que previamente han sido probadas; de esta manera, las fórmulas que obtenemos usando reglas de inferencia son consideradas válidas, Entre las Reglas de Inferencia más comunes se encuentran Modus Ponens la cual establece que: ||= A, ||= AÞ B _________________ (2) ||= B donde el símbolo ||= establece que la fórmula que sigue es verdadera. La fórmula (2) tiene una estructura conocida como "secuente". Los secuentes fueron establecidos por Gentzen en lo que se conoce como Cálculo de secuentes, lo que permitió un gran avance en las técnicas de deducción. La regla de Modus Ponens comúnmente esta regla se establece como sigue: "Sí dos proposiciones X, X Þ Y son verdaderas, podemos inferir que Y es verdadera" REGLAS DE INFERENCIA GENERALES: Para la realización de cualquier demostración: P1,P2,...,Pn Cada Pi se puede obtener por una de las tres reglas de inferencia generales [TREMBLAY&MANOHAR]: 1) REGLAS P: Una fórmula Pi puede ser introducida en cualquier punto de la demostración. 2) REGLA T: Una fórmula S puede ser introducida en una demostración si S es CL de las fórmulas precedentes. 3) REGLA CP: Sí podemos derivar S a partir de R y un conjunto de premisas, entonces podemos derivar RÞ S a partir solamente del conjunto de premisas. REFERENCIAS [DOWSING] R.D. Dowsing, V.J. Rayward- Smith. C.D. Walter, " A first course in Formal Logic and its applications in Computer Science", Blackwell Scientific Publication, 1986, pp 26. [MENDELSON] Elliot Mendelson, "Introduction to Mathematical Logic",Third Edition,Wadsworth Inc. Wadsworth & Brookscole Advanced Books & Software Division, 1987. [TREMBLAY & MANOHAR] J.P. Tremblay, R. Manohar" Discrete Mathematical Structures with Applications to Computer Science", McGraw Hill International Editions, 1987. GSAT INTRODUCCION G es la abreviatura para Greedy y SAT es la abreviatura satisfactibilidad, refiriéndose al problema de la lógica proposicional que así se llama y que consiste en determinar los valores de verdad de las literales Xj de una forma norma conjuntiva F= F1 & F2 & ...& Fn, donde cada Fi se denomina una cláusula y es una disyunción de literales Xj. Cada literal Xj es tambien conocida como una proposición y la forma en que se encuentra F se dice que es una Forma Normal Conjuntiva o FNC. Dado que se pudiera plantear un problema similar en Logica de Predicados ó en otra lógica, el problema anterior se llama Problema de Satisfactibilidad de Lógica Proposicional, sin embargo, a menos que se especifique otra cosa, cuando se dice SAT se entiende que se trata del problema SAT de lógica proposicicional y no de otro. Para GSAT el problema de SAT es visto como sigue: Dada una fórmula F del Cálculo Proposicional con clausulas conformadas por literales propositivas (consideradas verdaderas), determinar una interpretación de las variables (símbolos de proposiciones) que hagan que F sea satisfactible (verdadera para ésa interpretación). Sí se encuentra dicha interpretación, mostrar cuáles proposiciones deben ser verdaderas para que la fórmula F sea verdadera en ésa interpretación. GSAT se ha probado particularmente para la instancia de SAT donde solo se permiten tres literales propositivas por claúsula; ésa instancia es conocida como 3 SAT y representa al problema de encontrar una asignación de valores de verdad satisfactoria para una oración en un formato especial denominado 3 FNC la cual es una forma normal conjuntiva donde solo se permiten tres literales por claúsula. Las literales Xj aparecen con signos negativos o sin ellos. Se dice que una literal Xj tiene signo propositivo si ella conjuntamente con su signo es considerada verdadera. Una proposición propositiva es aquélla que tiene un signo propositivo. Existen varias convenciones, pero una posible es aquélla en la cual la primera vez que aparece una literal ésta es considerada propositivamente. EJEMPLO1 : En la siguiente formula: (~P v R v ~T) & (P v ~R v S) Las siguientes son proposiciones propositivas: ~P, R, T, S. El valor de verdad para las proposiciones propositivas anteriores es V. De esta forma los valores de verdad para P, R, S, T son respectivamente: F, V, V, V. Las clausulas Fi pueden tener diferente número de literales dependiendo del problema SAT de que se trate. Para distinguir entre el número de literales en la instancia del problema de que se trate, se usa a veces la siguiente denominación: 2 Clausula: Clausula con dos literales 3 Clausula: Cláusula con tres literales k Clausula: Cláusula con k literales De esta forma se tienen instancias de problemas SAT denominados como sigue: 2 SAT: Solo se permiten clausulas con dos literales 3 SAT: Solo se permiten clausulas con tres literales ... k SAT: Solo se permiten clausulas con k literales 3 SAT es la instancia del problema SAT el cual es NP Completo. Durante mucho tiempo, SAT fue abordado con un enfoque de demostración de teoremas con algoritmos tipo Resolución. Dentro de estos enfoques sobresale el método de Davis & Putnam [Davis60] quienes establecieron varias reglas útiles en la demostración automática de Teoremas, mismas que son estudiadas por la Lógica Computacional. Dentro de las reglas de Davis & Putnam, hay dos que lllaman la atención: 1) La regla de una literal (R1L) y 2) La regla de Partición (RP). Los problemas de SAT fueron abordados primero con R1L y luego por RP. Existen además versiones modernas de las reglas de Davis & Putnam para cómputo paralelo y distribuido [Fang92] las cuales han sido poco exploradas para el problema de SAT. Desde la decada de los 1990's, el interes por el problema SAT se vió acrecentado, dadas las implicaciones en Teoria de la Complejidad y las multiples aplicaciones que SAT tiene en una inmensa cantidad de problemas, del área de planeación, scheduling, diseño de circuitos, etc. Las técnicas de solución que han aparecido desde la decada de los 1990´s se han enfocado a métodos de optimización combinatoria. Uno de los primeros en utilizar ese enfoque fue Selman en su famoso algoritmo de GSAT [Selman 92]al emplear un algoritmo de optimización tipo GREEDY, es decir glotón, para tratar de resolver el problema SAT. Algunos investigadors, entre ellos Selman [Selman93], consideran que algoritmos tipo GSAT resuleven problemas mas dificiles que los métodos de Davis & Putnam, cuestión que no ha sido absolutamente probada. No obstante el algorimo de GSAT es importante porque ha dado pie a una gran cantidad de algoritmos y, por que sirve de medida de comparación en el desarrollo de nuevos algoritmos que abordan SAT. Aqui presentamos una breve descripción de GSAT. PROBLEMA SAT VISTO POR GSAT El problema SAT es vsito por GSAT de la siguiente manera: Sea una fórmula F que se encuentra en su FNC conformada por claúsulas Fi de forma que: a) Una literal Xj es un símbolo de proposición con un signo propositivo o su negación. b) Una cláusula es una disyunción de literales; una cláusula 3 es la disyunción de exactamente tres literales. c) Una oración (fórmula) en FNC es un conjunto de cláusulas, una oración 3 FNC es el conjunto de tres cláusulas. Ejemplo 2. Para la siguiente formula normal conjuntiva: (P or Q or S)(P or Q or -R)(-P or -R or -S)(P or -S or T) O bien: (P or Q or S) & (P or Q or -R) & (-P or -R or -S) & (P or -S or T) Es una oración 3FNC con cuatro cláusulas y cinco proposiciones propositivas: P, Q, S, -R, T. EL AGORITMO DE GSAT Tal como es planeado por el propio Selman [Selman92], GSAT es un algoritmo no-determinístico de búsqueda local. Los algoritmos No-determinínisticos son aquéllos que emplean técnicas estocásticas de búsqueda. En el caso de GSAT, emplea una de tipo Montecarlo. GSAT es un algoritmo glotón o Hill Climbing de reincio aleatorio. Parte de un estado inicial el cual consiste en asignar valores de verdad a las variables proposicionales propositivas. EJEMPLO 3. Determinar el estado inicial al problema SAT del ejemplo 2. Solución Una alternativa es la siguiente. Asignar V(verdadero, ó 1) a las variables propositivas. De esta forma se tiene: T(P, Q, S, -R, T. )= (1,1,1,1,1) Por lo tanto los valores de verdad para P, Q, S, R, T son: (1,1,1,0,1) FUNCION DE EVALUACION Los algoritmos de optimización utilizan una función de evaluación para medir la efectividad de cada una de las soluciones. Dicha medida se conoce con diferentes nombres: Función objetivo, función de aptitud, función de aceptación y en el caso de GSAT, función de evaluación. Cualquiera que sea el nombre, el propósito es el mismo. Para SAT (y para la mayoría de los problemas de optimización), no existe una función de evaluación única. La utiliación de una función de evaluación adecuada impacta no solo en mejores soluciones sino, en muchos casos, en el tiempo de ejecución de los algoritmos para llegar a la solución bsucada. La determinación de funciones de evaluación adecuadas es una linea de investigación abierta. GSAT usa como función de evaluación la cantidad de cláusulas satisfechas (verdaderas). EJEMPLO 4 Cuál es el resultado de la función de evaluación de GSAT para el estado inicial del problema SAT del ejemplo 3. SOLUCION. Los valores de verdad del estado inicial son: para P, Q, S, R, T son: (1,1,1,0,1) Veamos el resultado de aplicar estos valores de verdad a cada una de las clausulas del problema: T(P or Q or S) T(P or Q or -R) T(-P or -R or -S) T(P or -S or T) =1 =1 =1 =1 Por lo tanto, en el caso mencionado el estado incial se evalúa como cuatro. PRESENTANDO EL ALGORITMO DE GSAT La función de evaluación mide la cantidad de cláusulas satisfechas (verdaderas). En el caso mencionado el estado incial se evalúa como tres. Si existen n signos propositivos, habrá n operadores, donde cada operador tiene que modificar el valor de verdad de uno de los signos. Puesto que se trata de una búsqueda avara, se utiliza siempre el operador que produce la mejor evaluación (escogiendo uno al azar en caso de haber varios igualmente buenos). A menos que encontremos una solución después de emprender un cierto número de ascensos (pruebas) tendremos que desistir y empezar de nuevo desde una nueva asignación inicial (de ahí lo de que éste sea un método multi-inicio). He aquí El algoritmo: function GSAT (oración, max_reinicios,max_ascensos) returns una asignación de verdad o falla for i= 1 a max_reinicios hacer A= Asignación de verdad generada aleatoriamente for j= 1 para max_ascensos hacer si A satisface la oración, entonces responder con A else A= la mejor alternativa de los vecinos de A end for j end for i return falla EJERCICIO a) ¿Es confiable el algoritmo GSAT (sound)? b) ¿Es completo? c) Implante GSAT y utilícelo para resolver los problemas que se añaden enseguida. d) Utilice GSAT para resolver problemas 3SAT generados al azar, de diversas extensiones. Hay dos parámetros clave: N, la cantidad de signos propositivos y C, la cantidad de cláusulas. Investigaremos los efectos de la relación C/N en el tiempo de ejecución de GSAT. Fije el valor de N en 20, haga una gráfica de la mediana del tiempo de ejecución en relación con C/N, considerando cd C/N va de 1 a 10. N simboliza el valor de max_reinicios y 5N es el valor de max_ascensos. e) Repita el procedimiento para tantos valores de N como su tiempo se lo permita. f) ¿Qué podría concluir acerca de la dificultad de los problemas 3SAT para distintos valores de N y la relación C/N? Existe mucha información sobre SAT por ejemplo, el artículo de Selman et al. (1992) "A new method for solving hard satisfiability problems", en donde verá más sobre GSAT. Problemas de prueba. 1.Humo --> Humo 2.Humo --> Fuego 3.(Humo --> Fuego)--> (-Humo --> -Fuego) 4.Humo o Fuego o -Fuego 5.(Humo y calor)--> (Fuego) <--> ((Humo--> Fuego) o (calor --> Fuego)) 6.(Humo--> Fuego)-->((humo y calor) --> Fuego) 7.(Grande o callado o (grande --> Callado)) 8.(Grande y callado) o -Callado Nota: --> Significa implicación, <--> Significa bicondicional - Para indicar negación REFERENCIAS [Davis60] M. Davis and H. Putnam, "A computing procedure for quantification theory", Journal of ACM, Vo., 7, No. 3, pp. 201-215, 1960. [Fang92] Ming-Yi Fang, Wen-Tsuen Chen, "Vectorization of Generalized Procedure for Theorem Proving in Propositional Logic on Vector Computer", IEEE Transactions on Knowledge and Data Engineering, Vol. 4, No 5. [Selman92] Bart Selman, Hector Levesque, David Mitchell, "A New Method for Solving Hard Satisfiability Problems", Proceedings of the Tenth National Conference on Artificial Intelligence (AAAI-92), San Jose, CA, July 1992, 440-446. [Selman93] Bart Selman, Henry A. Kautz, "An empirical Study of Greedy Local Search for Satisfiability Testing", Proceedings of the eleventh National Conference on Artificial Intelligence (AAAI-93), Washington ,D.C., 1993. COMPLEJIDAD COMPUTACIONAL INTRODUCCIÓN Prácticamente todas las áreas de las Ciencias Computacionales tratan, en mayor o menor grado con complejidad computacional. El tema es muy común entre expertos del área, sobre todo entre aquéllos relacionados con NP-completez y entre quienes buscan algoritmos eficientes para diversos problemas de aplicación. La importancia de la complejidad computacional estriba en que se ha convertido en una forma de clasificar buenos y malos algoritmos y de clasificar problemas computacionales como fáciles y dificiles. Aquí presentaremos una introducción a este tema. 2. Algoritmos y Complejidad: Una Descripción General Cada vez nos sorprendemos más de la velocidad de las computadoras de sus logros. Han permitido la solución de problemas muy complejos que serían ciencia ficción hace apenos unos cuantos años: Realidad virtual,simulación de procesos gigantescos, etc. Pese a lo que pueda pensarse, las computadoras no realizan ninguna actividad que pudiera calificarse como de una gran inteligencia. Las computadoras pueden únicamente llevar a cabo algoritmos; esto es, secuencias de instrucciones precisas y universalmente entendibles que solucionen cualquier instancia de problemas computacionales rigurosamente definidos. A pesar de que se ha llegado a logros sorprendentes como derrotar a un campeón de ajedrez Gary Kasparov en 1997 por una computadora Deep Blue de IBM, es dificil atribuirle características de inteligencia, cuando se tuvieron miles de horas hombre programando estrategias que derrotaran a Kasparov. Nótese que la inteligencia de Kasparonv requirió de cientos de cerebros pensando como derrotarlo. ¿Cuantas horas-hombre hubiera requerido cada uno de los que programaron a Deep Blue? ¿Cuál sería entonces la inteligencia relativa de estos hombres compardos con Kasparov? Quienes programaron a Deep Blue pusieron una serie de pasos a realizar para cada posible ataque de Kasparov. Es decir en Deep Blue pusieron algoritmos. ¿Pero qué son los algoritmos? El concepto intuitivo de algoritmo, lo tenemos prácticamente todos: Un algoritmo es una serie finita de pasos para resolver un problema. Hay que hacer enfásis en dos aspectos para que un algoritmos exista: 1) El número de pasos debe ser finito. De esta manera el algoritmo debe terminar en un tiempo finito con la solución del problema, 2) El algoritmo debe ser capaz de determinar la solución del problema. Alan Turing, en 1936 desarrolló su Máquina de Turing (la cual se cubre en los cursos denominados Teoría de la Computación o Teoría de Automátas), estableciendo que cualquier algoritmo puede ser representado por ella. Turing mostró también que existen problemas matemáticos bien definidos para los cuales no hay un algoritmo. Hay muchos ejemplos de problemas para los cuales no existe un algoritmo. Un problema de este tipo es el llamado problema de paro (halting problem): Dado un programa de computadora con sus entradas, ¿parará este alguna vez? Turing probó que no hay un algoritmo que pueda resolver correctamente todas las instancias de este problema. Alguien podría pensar en encontrar algunos métodos para detectar patrones que permitan examinar el programa para cualquier entrada. Sin embargo, siempre habrá sutilezas que escapen al análisis correspondiente. Alguna persona más suspicaz, podría proponer simplemente correr el programa y reportar éxito si se alcanza una declaración de fin. Desgraciadamente, este esquema no garantiza por sí mismo un paro y en consecuencia el problema no puede ser resuelto con los pasos propuestos. Como consecuencia de acuerdo con la definición anterior, ese último procedimiento no es un algoritmo, pues no se llega a una solución. Muchas veces aunque exista un algoritmo que pueda solucionar correctamente cualquier instancia de un problema dado, no siempre dicho algoritmo es satisfactorio porque puede requerir de tiempos exageradamente excesivos para llegar a la solución. Por ejemplo, considere el problema del agente viajero, el cual se establece como sigue: PROBLEMA DEL AGENTE VIAJERO: Dado un grafo de N nodos y A arcos, determinar la ruta más corta que parta de un nodo predeterminado Ni y visite todos los nodos solamente una vez y regrese al nodo de partida. O su versión como un problema de decisión: Existe un recorrido más corto que un valor K que parta de un nodo inicial Ni , recorra visite todos los otros N-1 nodos una sola vez y regrese al nodo inicial Ni. Este problema parece ser muy simple y puede ser que lo sea para ciertos tamaños de N y A. Sin embargo existen instancias de este problema, con valores ni siquiera demasiado grandes de N y A, para los cuales encontrar la solución es terriblemente ardúo. Tan solo basta pensar en una red de computadoras de unos 500 nodos con cierta topología para que sea muy difícil determinar la ruta más corta de un mensaje enviado desde un nodo i determinado y que debe visitar todos los nodos solamente una vez, trayendo de regreso el mensaje enviado y la traza de los nodos visitados. Para cualquier instancia del problema del agente viajero uno podría pensar en seleccionar todos y cada uno de los diferentes recorridos posibles y luego compararlos para encontrar el de menor longitud. Sin embargo, la ejecución de este algoritmo en una computadora requerirá de aproximadamente n! pasos, lo que para instancias relativamente pequeñas lo vuelve inútil. Para propósitos de comparación del rendimiento de diferentes algoritmos, se requiere de una medida de rendimiento de algoritmos; la medida más ampliamente aceptada es el tiempo que el algoritmo en cuestión consume antes de producir la solución final. Esta cantidad de tiempo puede variar de una computadora a otra, debido a diferencias en su velocidad de procesamiento y en la forma como el programa es traducido en instrucciones de máquina. En el análisis de algoritmos, el tiempo siempre es expresado en términos del número de pasos elementales (operaciones aritméticas, comparaciones, lecturas, escrituras, etc.) requeridos para la ejecución del algoritmo sobre una computadora hipotética. Dichos pasos elementales tienen una duración unitaria de tiempo. De esta forma, el tiempo requerido para la ejecución de un algoritmo es establecido como el número de pasos elementales o instrucciones que efectúa antes de producir la solución final. El número de pasos requeridos por un algoritmo no es siempre el mismo para todas las entradas y frecuentemente es difícil obtener una fórmula precisa que establezca la función de tiempo. Es por ello que se consideran tres medidas del tiempo de ejecución del algoritmo, las cuales dependen del tamaño de la entrada n: a. El mínimo tiempo necesario(mejor caso), b. El máximo tiempo necesario (peor caso) y, c. El tiempo promedio necesario (caso promedio). De esta forma la complejidad de un algoritmo es función del tamaño de la entrada (por ejemplo 10n3, 2n, n log n). El interés principal en el comportamiento de un algoritmo es para entradas grandes, pues estas establecerán los límites de aplicabilidad de este. Por lo tanto, generalmente se tiene poco interés en el valor exacto del tiempo requerido para la ejecución de un algoritmo. Siendo el interés principal la razón de crecimiento del mejor caso Por ejemplo, supóngase que el tiempo del peor caso de un algoritmo es: t(n) = 60n2 + 5n + 1 para entradas de tamaño n. Para n grandes, el término 60n2 es aproximadamente igual a t(n) (ver tabla 1). En este sentido, t(n) crece como 60n2. n t(n) = 60n2 + 5n + 1 60n2 10 100 1,000 10,000 6,051 600,501 60,005,001 6,000,050,001 6,000 600,000 60,000,000 6,000,000,000 Tabla1: Razón de crecimiento del tiempo del peor caso de un algoritmo Si la medida del tiempo de la tabla 1, está en segundos, se podría dividir entre 60 para obtener una medida del tiempo del peor caso para entradas de tamaño n en minutos. Este cambio de unidades no afecta la forma como crece la función f(n) que representa la medida del tiempo del peor caso. De esta manera, se puede eliminar los coeficientes constantes. Con estas suposiciones t(n) crece como n2 cuando se incrementa n. La formalización de la eficiencia de los algoritmos para el peor caso, caso optimista y caso promedio, se hace a continuación, mediante la definición de las siguientes funciones: Sea f(n), g(n) dos funciones que van de los enteros positivos a los reales positivos. a. f(n) es cuando mucho del orden de g(n) , escribiéndose f(n) (< =) O(g(n)), si existe una constante c > 0 tal que, para una n suficientemente grande, se cumple que f(n) (<, =) c g(n) . b. f(n) es del orden de al menos g(n), escribiéndose f(n) (>, =) W (g(n)) si existe una constante c > 0 tal que, para una n suficientemente grande, f(n) (> =) c g(n). c. f(n) es del orden de g(n), escribiéndose f(n) = Q (g(n)), si existen dos constantes c, c’ > 0 tales que, para una n suficientemente grande, c g(n) < f(n) < c’ g(n) . De acuerdo a las definiciones anteriores: * si f(n) < = O(g(n)), se puede concluir que f(n) está acotada por arriba por g(n). Así es que g(n) crece al menos tan rápido como f(n). * si f(n) > = W (g(n)), entonces, f(n) está acotada por abajo por g(n). Así es que g(n) crece cuando mucho tan rápido como f(n). * Si f(n) = Q (g(n)), podemos concluir que f(n) está acotada por arriba y por abajo por g(n). Así es que f(n) y g(n) crecen a la misma razón. Usando esta notación la razón de crecimiento de la complejidad de un algoritmo puede ser acotada mediante frases como "toma un tiempo O(n3)". Para leer un problema en una computadora, la entrada primero debe ser codificada como una secuencia de símbolos sobre un alfabeto determinado, generalmente en una secuencia de bits. De esta forma, el tamaño de la entrada es definido como la longitud de la secuencia o cadena de símbolos, esto es el número de símbolos en ella. La derivación de un límite superior riguroso para los requerimientos de tiempo de un algoritmo no es siempre una tarea sencilla; este puede requerir de tanto ingenio y trucos como el diseño de un algoritmo. En la actualidad hay un acuerdo general entre los investigadores de que un algoritmo es de utilidad práctica cuando su complejidad computacional crece polinomialmente con respecto del tamaño de la entrada, por ejemplo, algoritmos de complejidad O(n) o O(n3). Naturalmente, algoritmos para los cuales la complejidad asintótica no es un polinomio en sí pero puede ser acotada por un polinomio n log n) también están incluidos (n2.5, Se le da el nombre de algoritmo exponencial a todo aquel que viola todo acotamiento polinomial para instancias suficientemente grandes. Se les da este nombre porque 2n es una razón de crecimiento no polinomial. Otros ejemplos de razones exponenciales de crecimiento son kn (para cualquier constante k > 1), n!, nn y nlog n. Es obvio que, cuando el tamaño de la entrada crece, cualquier algoritmo polinomial eventualmente llegará a ser más eficiente que cualquier algoritmo exponencial (ver tabla 2). Función Valores Aproximados n 10 100 n log n 33 n3 1,000 1,000,000 109 106 n8 1,014 1022 1030 2n 1,024 1.27 x 1030 nlog n 2,099 1.93 x 1013 7.89 x 1029 n! 3,628,800 10158 4x 102,567 664 1,000 9,966 1.05 x 10301 Tabla 2: Crecimiento de funciones polinomiales y exponenciales Otra característica positiva de los algoritmos polinomiales es que toman más ventaja de los avances de la tecnología. Por ejemplo, cada vez que una mejora tecnológica incrementa la velocidad de las computadoras 10 veces, el tamaño de la instancia más grande que puede ser solucionada por un algoritmo polinomial en una hora, por ejemplo, será multiplicado por una constante entre 1 y 10. En contraste, un algoritmo exponencial experimentará únicamente un incremento pequeño que se sumará al tamaño de la instancia que este puede resolver (ver tabla 3). Función Tamaño de la Instancia Solucionada en un Día Tamaño de la Instancia Solucionada en un Día en una Computadora 10 Veces Más Rápida 1012 1013 n log n 0.948 x 1011 0.87 x 1012 n2 106 3.16 x 106 n3 104 2.15 x 104 108 n4 10 18 2n n 40 43 n 12 13 log n 79 95 14 15 10 n n! Tabla 3: Algoritmos de tiempo polinomial toman más ventaja de los avances de la tecnología. Finalmente se puede decir que los algoritmos polinomiales tienen la propiedad de cerradura: pueden ser combinados para resolver casos especiales del mismo problema; un algoritmo polinomial puede llamar otro algoritmo polinomial como una subrutina y el algoritmo resultante continuará siendo polinomial. Hay que tener cuidado cuando la complejidad de un algoritmo se expresa en términos de la entrada numérica de la instancia y no en función del tamaño de la entrada. Puede darse el caso que al codificar la entrada numérica de la instancia la longitud de la cadena se vuelva exponencial y por ende la razón de crecimiento de la entrada sea exponencial. A los algoritmos que poseen este tipo de acotamiento en tiempo se les da el nombre de pseudo-polinomiales. Probablemente la tesis de que un algoritmo acotado en tiempo polinomial es bueno pareciera caerse cuando uno se va a los extremos, por ejemplo, un algoritmo de complejidad n80 tomará para resolver instancias de tamaño 3 tiempos astronómicos, mientras que un algoritmo exponencial correrá más rápidamente para toda instancia razonable. Sin embargo, la experiencia ha demostrado que para la mayoría de los problemas una vez que un algoritmo acotado en tiempo polinomial es descubierto, el grado del polinomio rápidamente sufre una serie de decrementos tan pronto como varios investigadores mejoran la idea. Generalmente, la razón final de crecimiento es O(n3) o mejor. En contraste, los algoritmos exponenciales normalmente consumen tanto tiempo en la práctica como en la teoría, y ellos son rápidamente abandonados una vez que un algoritmo polinomial para el mismo problema es descubierto. No obstante esto no es una verdad absoluta, ya que en contra parte se tienen algoritmos exponenciales como el método simplex, el cual resuelve muchas instancias prácticas. 2.2. REGLAS PRACTICAS PARA los Conjuntos O(f) No existe una regla general para calcular la complejidad de todos los algoritmos. Sin embargo, es posible tratar sistematicamente una gran cantidad de ellos, si se siguen algunas reglas simples para instrucciones como las siguientes: 1. 2. 3. 4. 5. Sentencias sencillas secuencia (;) decisión (IF ... THEN ... ELSE ...) bucles (WHILE, REPEAT, FOR) llamadas a procedimientos SENTENCIAS SENCILLAS Son sentencias de asignación, entrada/salida, etc, siempre y cuando no trabajen sobre variables cuyo tamaño esté relacionado con el tamaño N del problema. Complejidad: O(1). Secuencia (;) La complejidad: Suma de las complejidades individuales. Decisión (IF ... THEN ... ELSE ... END) La condición suele ser de O(1), complejidad a sumar con la peor posible, bien en la rama THEN, o bien en la rama ELSE. En decisiones multiples (ELSIF, CASE), se tomara la peorde las ramas. Bucles (WHILE, REPEAT, FOR) En los bucles con contador explícito, podemos distinguir dos casos, que el tamaño N forme parte de los límites o que no. Si el bucle se realiza un número fijo de veces, independiente de N, entonces la repetición sólo introduce una constante multiplicativa que puede absorberse. Ej.- FOR i:= 1 TO K DO algo_de_O(1) END; => K*O(1) = O(1) Si el tamaño N aparece como límite de iteraciones ... Ej.- FOR i:= 1 TO N DO algo_de_O(1) END; => N * O(1) = O(n) Ej.- FOR i:= 1 TO N DO FOR j:= 1 TO N DO algo_de_O(1) tendremos N * N * O(1) = O(n2) Ej.- FOR i:= 1 TO N DO FOR j:= 1 TO i DO algo_de_O(1) el bucle exterior se realiza N veces, mientras que el interior se realiza 1, 2, 3, ... N veces respectivamente. En total, 1 + 2 + 3 + ... + N = N*(1+N)/2 -> O(n2) A veces aparecen bucles multiplicativos, donde la evolución de la variable de control no es lineal (como en los casos anteriores) Ej.- c:= 1; WHILE c <N DO algo_de_O(1) c:= 2*c; El valor incial de "c" es 1, siendo "2k" al cabo de "k" iteraciones. El número de iteraciones es tal que 2k >= N => k= eis (log2 (N)) [el entero inmediato superior] y, por tanto, la complejidad del bucle es O(log n). Ej.- c:= N; WHILE c > 1 DO algo_de_O(1) c:= c / 2; Un razonamiento análogo nos lleva a log2(N) iteraciones y, por tanto, a un orden O(log n) de complejidad. Ej.- FOR i:= 1 TO N DO c:= i; WHILE c > 0 DO algo_de_O(1) c:= c/2; tenemos un bucle interno de orden O(log n) que se ejecuta N veces, luego el conjunto es de orden O(n log n) Llamadas a procedimientos La complejidad de llamar a un procedimiento viene dada por la complejidad del contenido del procedimiento en sí. El coste de llamar no es sino una constante que podemos obviar inmediatamente dentro de nuestros análisis asintóticos. El cálculo de la complejidad asociada a un procedimiento puede complicarse notáblemente si se trata de procedimientos recursivos. Es fácil que tengamos que aplicar técnicas propias de la matemática discreta, tema que queda fuera de los límites de esta nota técnica. Ejemplo: evaluación de un polinomio Vamos a aplicar lo explicado hasta ahora a un problema de fácil especificación: diseñar un programa para evaluar un polinomio P(x) de grado N; CONST N= ...; TYPE TPolinomio= array [0..N] of real; FUNCTION EvaluaPolinomio (C: TPolinomio; X: REAL): REAL; VAR i, j: INTEGER; XN, S: REAL; BEGIN S:= C[0]; FOR i:= 0 TO N DO BEGIN 1 XN:= 1.0; 1 FOR j:= 1 TO i DO 2 XN:= XN * X; 2 S:= S + C[i]*XN; 1 END; 1 EvaluaPolinomio:= S; END {EvaluaPolinomio}; Como medida del tamaño tomaremos para N el grado del polinomio, que es el número de coeficientes en C. Así pues, el bucle más exterior (1) se ejecuta N veces. El bucle interior (2) se ejecuta, respectivamente 1 + 2 + 3 + ... + N veces = N*(1+N)/2 => O(n2) Intuitivamente, sin embargo, este problema debería ser menos complejo, pues repugna al sentido común que sea de una complejidad tan elevada. Se puede ser más inteligente a la hora de evaluar la potencia xn: FUNCTION Potencia (X: REAL; j: INTEGER): REAL; VAR t: REAL; BEGIN IF j = 0 THEN Potencia:= 1.0 ELSE IF (j mod 2) = 1 THEN Potencia:= X * Potencia (X, j-1) ELSE BEGIN t:= Potencia (X, j DIV 2); Potencia:= t*t; END; END {Potencia}; FUNCTION EvaluaPolinomio (C: TPolinomio; X: REAL): REAL; VAR i: INTEGER; S: REAL; BEGIN S:= C[0]; FOR i:= 0 TO N DO S:= S + C[i] * Potencia (X, i); EvaluaPolinomio:= S; END {EvaluaPolinomio}; El análisis de la función Potencia es delicado, pues si el exponente es par, el problema tiene una evolución logarítmica; mientras que si es impar, su evolución es lineal. No obstante, como si "j" es impar entonces "j-1" es par, el caso peor es que en la mitad de los casos tengamos "j" impar y en la otra mitad sea par. El caso mejor, por contra, es que siempre sea "j" par. Un ejemplo de caso peor seria x31, que implica la siguiente serie para j: 31 30 15 14 7 6 3 2 1 cuyo número de terminos podemos acotar superiormente por 2 * eis (log2(j)), donde eis(r) = entero inmediatamente superior Este cálculo responde al razonamiento de que en el caso mejor visitaremos eis(log2(j)) valores pares de "j"; y en el caso peor podemos encontrarnos con otros tantos números impares entremezclados. Por tanto, la complejidad de Potencia es de orden O(log n). Insertada la función Potencia en la función EvaluaPolinomio, la complejidad compuesta es del orden O(n log n), al multiplicarse por N un subalgoritmo de O(log n). Así y todo, esto sigue resultando estravagante y excesivamente costoso. En efecto, basta reconsiderar el algoritmo almacenando las potencias de "X" ya calculadas para mejorarlo sensiblemente: FUNCTION EvaluaPolinomio (C: TPolinomio; X: REAL): REAL; VAR i: INTEGER; XN, S: REAL; BEGIN XN:= 1.0; S:= C[0]; FOR i:= 0 TO N DO BEGIN 1 XN:= XN*X; 1 S:= S + C[i]*XN; 1 END; 1 EvaluaPolinomio:= S; END {EvaluaPolinomio}; que queda en un algoritmo de O(n). Habiendo N coeficientes C distintos, es imposible encontrar ningun algoritmo de un orden inferior de complejidad. En cambio, si es posible encontrar otros algoritmos de idéntica complejidad: FUNCTION EvaluaPolinomio (C: TPolinomio; X: REAL): REAL; VAR i: INTEGER; S: REAL; BEGIN S:= 0.0; FOR i:= N DOWNTO 0 DO 1 S:= S*X + C[i]; 1 EvaluaPolinomio:= S; END {EvaluaPolinomio}; No obstante que ambos algoritmos son del mismo orden de complejidad, cabe resaltar que sus tiempos de ejecución serán notablemente distintos. En efecto, mientras el último algoritmo ejecuta N multiplicaciones y N sumas, el penúltimo requiere 2N multiplicaciones y N sumas. Si, como es frecuente, el tiempo de ejecución es notablemente superior para realizar una multiplicación, cabe razonar que el último algoritmo ejecutará en la mitad de tiempo que el anterior. 2. Problemas NP completos En la sección anterior, la tabla 2 muestra que los algoritmos cuya complejidad es descrita por una función polinomial pueden ser ejecutados para entradas grandes en una cantidad de tiempo razonable, mientras que los algoritmos exponenciales son de poca utilidad excepto para entradas pequeñas. En esta sección se tratarán los problemas cuya complejidad es descrita por funciones exponenciales, problemas para los cuales el mejor algoritmo conocido requeriría de muchos años o centurias de tiempo de cálculo para entradas moderadamente grandes. De esta forma se presentarán definiciones que pretenden distinguir entre los problemas tratables (aquellos que no son tan duros) y los problemas intratables (duros o que consumen mucho tiempo). La mayoría de estos problemas ocurren como problemas de optimización combinatoria. Problemas Intratables Garey & Johnson, plantean una situación de intratabilidad interesante que describimos a través del siguiente caso: Si trabajas para una compañía que está pensando entrar a una nueva era globalizadora gavernicola y tu jefe te propone que obtnegas un método para determinar si o no cualquier conjunto dado de especificaciones para un nuevo componente gavernicola pueden ser satisfechas de alguna manera y, si es así, se deberá construir el diseño que satisfaga dichas expecificaciones. La realidad es que despues de un tiempo comprobaras que no hay manera de obtener tal método. De modo que tendrás dos alternativas: 1) Renunciar para evitar la pena de que te corran por inepto y 2) Esperar a que te corran por inepto. Sería muy penoso, pero tendrías que confesar que no pudiste resolver el problema por falta de capacidad. Para evitar la situación anterior tu podrías tratar de tomar una actitud de una persona más valiente y demostrar que enb realidad dicho método no se puede obtener. Si eso fuera así entonces tu podrías ir con tu jefe y aclararle que el problema no lo resolviste porque no se puede resolver: Es intratable. Sin embargo, es muy probable que a tu jefe esta característica del problema le tenga sin cuidado y, de todas maneras, te corran o tengas que renunciar. Es decir regresarás a las alternativas 1) y 2) antes citadas. Una situación mas prometedora, es tratar de probar que el problema no solo es tan dificil que nose puede resolver, sinoque ademas pertenece a una clase de problemas tales que cientos y miles de personas famosas e inteligentes, tampoco pudieron resolver.Aún así, no estamos muy seguros aun de tu permanencia en la compañia!, En realidad el conocimiento de que un problema es intratable es de gran utilidad en problemasde tipo computacional. Dado que el problema completo es intratable, tu podrías resolver el problema para ciertas instancias del mismo, o bien, reslver un problemamenos ambicioso, Por ejemplo, podra conformarte con obtener un método para las especificaciones de solo cieto tipo de componentes para determinadosconjuntos de entrada y no para "cualquier conjunto dado de especificaciones". Esto seguramente te llevará a tener mejor relaciones con tu compañía. En general, nos interesa encontrar el algoritmo más eficiente para resolver un problema determinado. Desde ese punto de vista tendríamos que considerar todos los recursos utilizados de manera que el algoritmo más eficiente sería aquél que consumiera menos recursos. ¿Cuáles recursos?. Si pensamos nuevamente que tu jefe te encarga que obtnegas el algoritmo más eficiente, es decir el que consume menos recursos so pena de que si no lo obtienes seas eliminado de la nominade la compañía, estoy seguro, en que pensarias en todos los recursos posibles (horashombre para construir el algoritmo, tiempo de sintonización, tiempo requerido para obtner una solución, número de procesadores empleados, cantidad de memoria requerida, etc.). Para simplificar un poco la tarea, consideraremos que tu jefe te permite que la eficiencia la midas sobre un solo recurso: El tiempo de ejecución. Pensemos por un momento que solo se tiene una sla máquina de modo que el número de procesadores no requiere de un análisis. ¿Qué le pasó a tu jefe? ¿De pronto se volvió comprensivo contigo? En realidad los otros parámetros los ha tomado en cuenta como costo directo del programa en cuestión. Esto es en realidad lo que se hace en teoría de complejidad. Para el análisis de complejidad, se considera por lo general la eficiencia sobre el tiempo, para un solo procesador en cómputo secuencial; para cómputo paralelo se considera también el número de procesadores. Los algorimos han sido divididos como buenos o malos algoritmos. La comunidad computacional acepta que un buen algoritmo es aquél para el cual existe un algoritmo polinomial deterministico que lo resuelva. Tambien se acepta que un mal algoritmo es aquel para el cual dicho algoritmo simplemente no exisste. Un problema se dice intratable, si es muy dificil que un algoritmode tiempo no polinomial lo resuelva. No obstante,esta clasificación de algoritmos en buenos y malos puede resultar a veces engañosa, ya que se podría pensar que los algoritmos exponenciales no son de utilidad práctica y que habrá que utilizar solamente algoritmos polinomiales. Sin embargo se tiene el caso de los métodos simplex y Branch & Bound, los cuales son muy eficientes para muchos problemas prácticos. Desafortunadamente ejemplos como estos dos son raros, de modo que es preferible seguir empleando como regla de clasificación en buenos y malos algoritmos, la que lo hace dependiendo de si son o no polinomiales; todo esto con la prudencia necesaria. La teoría de la NP-Completés fué presentada inicialmente por Cook desde 1971. Cook provó que un problema particular que se estudia en Lógica (no necesitamos ahora estudiarlo) y que se llama "El Problema de Satisfactibilidad", tenía la propiedad de que cualquier problema que perteneciera a la clase NP, podía ser reducido a él a través de una transformación de tipo polinomial. Estosignificaba que si el problema de satisfactibilidad podia ser resuelto en tiempo polinomial, todos los problemas No Polinomiales también podrían resolverse en tiempo polinomial, lo que significaría que la clase NP dejaría de existir!!. De esta forma, si cualquier problema en NP es intratable, entonces satisfactibilidad es un problema intratable.Cook también sugirió que el problema de satisfactibilidad y otros problemas NP tenían la característica de ser los problemas mas duros. Estos problemas tienen dos versiones: de decisión y deopitmización. El conjunto de estos problemas de optimización se denominan NP Completos,mientras que a sus correspondientes problemas de optimización, reciben el nombre de NP Hard. Problemas de Decisión Aquí hemos hablado de problemas de optimización como aquél donde buscamos el máximo ó el mínimo de una funicón donde existen ó no un conjunto de restricciones. Sin embargo un problema de optimización combinatoria puede también ser formulado de manera más relajada como sigue: Dado un problema de optimización, podemos encontrar el costo de la solución óptima Se sabe que dado un problema de optimización, se puede definir un problema de decisión asociado a él, esto es, una pregunta que puede ser contestada por si o no. Por otro lado, varios problemas computacionales bien conocidos son problemas de decisión. Entre los problemas de decisión se pueden mencionar por ejemplo: El problema de paro: dado un algoritmo y su entrada, ¿Parará éste alguna vez? El problema de satisfacibilidad: dada una fórmula booleana, ¿Es ésta satisfacible? El problema del circuito Hamiltoniano: dado un grafo G, ¿Hay un circuito en G que visite todos los nodos exactamente una vez?. La definición de problema de decisión a partir del problema de optimización permite estudiar ambos tipos de problemas de una manera uniforme. Además, como se ha puntualizado que un problema de decisión no es más difícil que el problema de optimización original, cualquier resultado negativo probado sobre la complejidad del problema de decisión será aplicable al problema de optimización también. Se está interesado en clasificar los problemas de decisión de acuerdo a su complejidad. Se denota por P a la clase de problemas de decisión que son polinomialmente acotados, esto es, la clase de problemas de decisión que pueden ser solucionados en tiempo polinomial. La clase P puede ser definida muy precisamente en términos de cualquier formalismo matemático para algoritmos, como por ejemplo la Máquina de Turing. Se puede decir que P es la clase de problemas de decisión relativamente fáciles, para los cuales existe un algoritmo que los soluciona eficientemente. Para una entrada dada, una "solución" es un objeto (por ejemplo un grafo coloreado) que satisface el criterio en el problema y justifica una respuesta afirmativa de si. Una "solución propuesta" es simplemente un objeto del tipo apropiado, este puede o no satisfacer el criterio. Informalmente se puede decir que NP es la clase de problemas de decisión para los cuales una solución propuesta dada para una entrada dada, puede ser checada rápidamente (en tiempo polinomial) para ver si ésta es realmente una solución, es decir, si ésta satisface todos los requerimientos del problema. Una solución propuesta puede ser descrita por una cadena de símbolos a partir de algún conjunto finito. Simplemente se necesita alguna convención para describir grafos, conjuntos, funciones, etc. usando estos símbolos. El tamaño de la cadena es el número de símbolos en ella. Checar una solución propuesta incluye checar que la cadena tenga sentido (esto es, que tenga una sintaxis correcta) como una descripción del tipo de objeto requerido, también como checar que ésta satisface el criterio del problema. ALGORITMOS NO DETERMINÍSTICOS Un algoritmo no determinístico tiene dos faces: 1a. Fase no Determinística: alguna cadena de caracteres, s, completamente arbitraria es escrita a partir de algún lugar de memoria designado. Cada vez que el algoritmo corre, la cadena escrita puede diferir (Esta cadena puede ser vista como una adivinación de la solución para el problema, por lo que a esta fase se le da el nombre de fase de adivinación, pero s también podría ser ininteligible o sin sentido). 2a. Fase Determinística: Un algoritmo determinístico ( es decir ordinario) siendo ejecutado. Además de la entrada del problema de decisión, el algoritmo puede leer s, o puede ignorarla. Eventualmente éste para con una salida de si o no, o puede entrar en un loop infinito y nunca parar (véase ésta como la fase de checar, el algoritmo determinístico verifica s para ver si ésta es una solución para la entrada del problema de decisión). El número de pasos llevados a cabo durante la ejecución de un algoritmo no determinístico es definido como la suma de los pasos en ambas fases; esto es, el número de pasos tomados para escribir s (simplemente el número de caracteres en s) más el número de pasos ejecutados por la segunda fase determinística. Normalmente cada vez que se corre un algoritmo con la misma entrada se obtiene la misma salida. Esto no ocurre con algoritmos no determinísticos; para una entrada particular x, la salida a partir de una corrida puede diferir de la salida de otra debido a que ésta depende de s. aunque los algoritmos no determinísticos no son realistas (algoritmos útiles en la práctica), ellos son útiles para clasificar problemas. Se dice que un algoritmo no determinístico es polinomialmente acotado si hay un polinomio p tal que para cada entrada de tamaño n para la cual la respuesta es si, hay alguna ejecución del algoritmo que produce una salida si en cuando mucho p(n) pasos. De esta forma se puede decir que: NP es la clase de problemas de decisión para los cuales hay un algoritmo no determinístico acotado polinomialmente (el nombre de NP viene de no determinístico polinomialmente acotado). Un algoritmo ordinario (determinístico) para un problema de decisión es un caso especial de un algoritmo no determinístico. En otras palabras, si A es un algoritmo determinístico para un problema de decisión, entonces A es la segunda fase de un algoritmo no determinístico. A simplemente ignora lo que fue escrito por la primera fase y procede con su cálculo usual. Un algoritmo no determinístico puede hacer cero pasos en la primera fase (escribiendo la cadena nula), Así si A corre en tiempo polinomial, el algoritmo no determinístico con a como su segunda fase corre también en tiempo polinomial. De lo mencionado se deduce que P es un subconjunto propio de NP. La gran pregunta es ¿ P = NP o es P un subconjunto propio de NP? Se cree que NP es un conjunto mucho mayor que P, pero no hay un solo problema en NP para el cual éste haya sido probado que el problema no está en P. No hay un algoritmo polinomialmente acotado conocido para muchos problemas en NP, pero ningún límite inferior mayor que un polinomio ha sido probado para estos problemas. NP-completo es el término usado para describir los problemas de decisión que son los más difíciles en NP en el sentido que, si hubiera un algoritmo polinomialmente acotado para un problema NPcompleto, entonces habría un algoritmo polinomialmente acotado para cada problema en NP. Definición Formal de la Clase NP La definición formal de NP-completo usa reducciones, o transformaciones, de un problema a otro. Suponga que se quiere resolver un problema P 1 y que se tiene ya un algoritmo para otro problema P 2. Suponga también que tiene una función T que toma la entrada x para P 1 y produce T(x), una entrada para P 2 tal que la solución correcta de P 1 en x es afirmativa (si) si y solo si la respuesta correcta para P 2 en T(x) es un si. Entonces, haciendo una composición de T y el algoritmo para P 2, se obtiene un algoritmo para P 1. Sea T una función que va del conjunto de entradas para el problema de decisión P 1 al conjunto de entradas para el problema de decisión P 2. T es una reducción polinomial (también llamada transformación polinomial) de P 1 a P 2 si T puede ser calculada en un tiempo acotado polinomialmente Para cada entrada x de P 1, la respuesta correcta para P 2 en T(x) es la misma que la respuesta correcta para P 1 en x. P 1 es polinomialmente reducible (también llamada polinomialmente transformable) a P 2 si existe una transformación polinomial de P 1 a P 2. La notación P 1 µ P 2 es usada para indicar que P 1 es reducible a P 2. El punto fundamental de la reducibilidad es que P 2 es al menos tan duro o difícil de resolver como P Esto puede precisarse a través del siguiente teorema. 1. Si P 1 µP 2 yP 2 está en P, entonces P 1 está en P. Ahora se puede dar una definición formal de NP-completo: Un problema P es NP-completo si éste está en NP y para cada otro problema P ’ en NP, Del teorema anterior y la definición de NP completo se deduce el siguiente teorema: Si cualquier problema NP-completo esta en P, entonces P=NP P’µP Este teorema indica, por un lado, que tan valioso sería encontrar un algoritmo polinomialmente acotado para cualquier problema NP-completo y, por otro, que tan improbable es que tal algoritmo exista pues hay muchos problemas en NP para los cuales han sido buscados algoritmos polinomialmente acotados sin ningún éxito. Como se señaló antes, el primer problema de decisión que se propuso como un problema NPcompleto es el satisfacibilidad de la lógica proposicional. Todos los problemas NP para los cuales se puede comprobar que pueden ser reducibles al problema de satisfctibilidad, son NP-completos. Así tenemos que los siguientes problemas son NP-completos: rutas y circuitos de Hamilton, asignación de trabajos con penalizaciones, el agente viajero, el problema de la mochila. Actualmente para probar que un problema es NP-completo, es suficiente con probar que algún otro problema NP-completo es polinomialmente reducible a éste debido a que la relación de reducibilidad es transitiva. La lógica de lo dicho es la siguiente: Si P ’ es NP-completo, entonces todos los problemas en NP µ P ’ Si se demuestra que P ’ µ P Entonces todos los problemas en NP µ P Por lo tanto, P es NP-completo Supóngase un problema P , P * es el complemento del problema P si el conjunto de símbolos en la cadena s de la fase de adivinación del algoritmo no determinístico que codifican las instancias si de P * son exactamente aquellas que no están codificando las instancias si de P . Por ejemplo, el problema del circuito Hamiltoniano es: dado un grafo G=(V, E), es G Hamiltoniano. Y el complemento del problema del circuito Hamiltoniano es: dado un grafo G=(V, E), es G no Hamiltoniano. Supóngase un problema P en P, entonces hay un algoritmo acotado polinomialmente que resuelve P . Un algoritmo acotado polinomialmente que solucione el complemento de P es exactamente el mismo algoritmo, únicamente con la sustitución de no por si cuando se obtiene una solución afirmativa y viceversa. El siguiente teorema expresa lo mencionado Si P es un problema en P, entonces el complemento P * de P está también en P. Los mismos argumentos no pueden ser aplicados para demostrar que un problema en NP está también en NP. Esto motiva la siguiente definición: La clase co.NP es la clase de todos los problemas que son complemento de problemas en NP Decir que el complemento de todos los problemas en NP está también en NP es equivalente a decir que NP = co-NP. Sin embargo, hay razones para creer que NP ¹ co-NP. La evidencia es tan circunstancial como la que se estableció para la conjetura de que P ¹ NP: Muchos investigadores han tratado por largo tiempo, sin éxito, de construir pruebas sucintas para el complemento del problema del circuito Hamiltoniano, así como para muchos otros problemas, Sin embargo, puede ser mostrado (como con P ¹ NP) que si la conjetura es verdadera, está en los problemas NP-completo testificar su validez. Si el complemento de un problema NP-completo está en NP, entonces NP = co-NP Así de todos los problemas en NP, Los problemas NP-completo son aquellos con complementos de estar en NP. Contrariamente, Si el complemento de un problema en NP está también en NP, esto es evidencia de que el problema no está en NP. Cuando todos los problemas en NP se transforman polinomialmente al problema P , pero no es posible demostrar P Î NP, se dice que P es tan difícil como cualquier problema en NP y por lo tanto NP-hard. NP-hard es usado también en la literatura para referirse a los problemas de optimización de los cuales su problema de decisión asociado es NP-completo Problemas que pueden ser solucionados por algoritmos cuyas operaciones pueden ser confinadas dentro de una cantidad de espacio que está acotado por un polinomio del tamaño de la entrada, pertenecen a la clase PSPACE. P, NP y co-NP son subconjuntos de PSPACE. Se dice que un problema es PSPACE-completo si éste está en PSPACE y todos los otros problemas en PSPACE son polinomialmente reducibles a él. Un esquema de las clases de problemas desde el punto de vista de la teoría de la complejidad. FÓRMULAS PRENEXAS Y ALGORITMO CLAUSULAR FÓRMULAS PRENEXAS : Las fórmulas prenexas, son aquellas donde todos los cuantificadores, Q1,Q2,..Qn, que pueda tener una fórmula del cálculo de predicados, están colocados a la izquierda de la fórmula, de manera que a la izquierda de ella queda una fórmula M sin cuantificadores. Es decir: F = (Q1 x1) ...(Qn xn) (M) donde las Qi son cuantificadores universales o existenciales y M es una fórmula sin cuantificadores, cuyos elementos son uno o más símbolos de predicados separados por conectores lógicos. A la forma anterior se le conoce como la Forma Normal Prenexa y es posible llegar a ella mediante un procedimiento simple: PASO PASO PASO PASO 1. 2. 3. 4. Eliminar símbolos de implicación y doble implicación. Pasar negaciones hacia adelante. Renombrar variables ligadas. Mover los cuantificadores hacia la izquierda. ALGORITMO CLAUSULAR : 1) 2) 3) 4) 5) 6) 7) 8) Eliminar => y <=> Pasar ~ hacia adelante Estandarizar variables Eliminar E's Convertir a la forma prenexa Escribir la matriz en forma conjuntiva Eliminar A's Eliminar ^ 's SUSTITUCIÓN Y UNIFICACIÓN EL PROBLEMA DE LA UNIFICACIÓN Y EL UNIFICADOR MÁS GENERAL En el caso de la lógica proposicional, es relativamente sencillo realizar apareamientos de claúsulas para obtener resolventes. Para ejemplificar apareamientos de cláusulas en Cálculo Proposicional, consideraremos un ejemplo. EJEMPLO 1. Si tenemos las siguientes cláusulas [1] P v Q [2] ¬ P v R el resolvente de [1] y [2] es: {1,2} [3] Q v R donde {1,2} [3] significa que se utilizan las cláusulas [1] y [2] en la obtención una nueva cláusula y [3] es el nombre de dicha claúsula. A [3] también se le llama resolvente de [1] y [2]. Obsérvese que las cláusulas [1] y [2] se pueden aparear debido a que ambas contienen un átomo que es diferente solamente en el signo (es decir P en [1] y ¬P en [2]). De esta manera se dice que P y ¬P son átomos complementarios o bien que forman un par complementario. DEFINICIÓN. Dos átomos son complementarios si difieren solamente en el signo. Cuando dos átomos L y ¬L son complementarios, se dice que forman un par complementarios. En el caso del cálculo de predicados, la situación es diferente, ya que las cláusulas tienen símbolos de predicados, los cuales tienen términos como argumentos. Por ejemplo, supongamos que deseamos encontrar el resolventes de las cláusulas: [1] P(x) v Q(x) [2] ¬ P(f(x)) v R(x) Las cláusulas [1] y [2] tienen átomos, con símbolos de predicado del mismo nombre (la literal P) que son diferentes en signo, de modo que estas dos cláusulas son candidatas a aparearse, para así obtener el resolvente correspondiente. No obstante, dicho apareamiento no podrá realizarse, a menos que exista una sustitución que logre que los argumentos de los símbolos de los predicados P y ¬P sean iguales, de modo que las literales P y ¬P sean complementarias. Al problema de encontrar una sustitución que logre que el conjunto de argumentos de dos símbolos de predicados sean iguales, se le llama el problema de unificación. Así tenemos que el problema de unificación es el siguiente: DEFINICIÓN. Dados dos términos (construidos a partir de símbolos de funciones, constantes y variables), el problema de unificación consiste en encontrar una sustitución, que logre que los dos términos sean idénticos. Regresemos al problema de encontrar un resolvente de las cláusulas [1] y [2]. Las cláusulas [1] y [2] no tienen ningún símbolo de predicado (al que nos referiremos como literal) que sea complementario, ya que en [1] existen diferencias adicionales al signo que impiden que P y ¬ P sean iguales. Sin embargo, podemos obtener nuevas instancias de [1] y [2] como se ilustra en el ejemplo siguiente. EJEMPLO 2. Considerar las cláusulas [1] y [2] que se repiten aquí: [1] P(x) v Q(x) [2] ¬ P(f(x)) v R(x) encontrar instancias de [1] y [2] que logre que en [1] y [2] se tenga un par complementario: SOLUCIÓN. Solo podemos formar un par complementario entre las literlas P y ¬P de las cláususlas [1] y [2] respectivamente. Encontramos instancias de estas cláusulas como sigue: a) de [1], cambiando x por f(a), se obtiene: [1'] P(f(a)) v Q(f(a)) b) de [2], cambiando x por a: [2'] ¬ P(f(a)) v R(a) En [1'] y [2'] hemos obtenido instancias aterrizadas de [1] y [2], ya que hemos cambiado el valor de la variable por una constante. De esta forma se ha logrado que estas dos cláusulas tengan una literal complementaria, es decir P(f(a)) con ¬ P(f(a)). Como consecuencia se puede obtener el resolvente de [1] y [2] para obtener la cláusula: [3'] Q(f(a)) v R(a) EJEMPLO 3: Consideremos nuevamente el conjunto del ejemplo 1, que reproducimos nuevamente aquí: [1] P(x) v Q(x) [2] ¬ P(f(x)) v R(x) encontrar una sustitución de [1] y [2], en base solo a las diferencias en los términos de P y ¬P que permita obtener un par complementario. SOLUCIÓN Los términos de P y ¬P son respectivamente x y f(x), es decir forman el conjunto D: D = {x, f(x)} De esta manera las diferencias de los términos de P y ¬P son justamente los elementos del conjuto D. Si sustituimos f(x) por x en [1] para obtener el siguiente conjunto de cláusulas: {1, f(x)/x} [1a] P(f(x)) v Q(f(x)) [2] ¬P(f(x)) v R(x) Donde {1, f(x)/x} [1a] significa que tomamos la cláusula 1, y realizamos la sustitución f(x) en lugar de x, para obtener la cláusula [1a]. Aquí empleamos la notación f(x)/x para denotar que sustituimos x en lugar de x. Efectuando el apareamiento de [1a] por [2] se obtiene: [3] Q(f(x)) V R(x) Nótese que el resolvente [3'] es una instancia del resolvente [3] que acabamos de obtener, ya que si en este último sustituimos x por a, obtenemos [3']. En realidad lo que pasa es que [3] es la cláusula mas general que podemos obtener, de modo que para cualquier par de instancias de [1] y [2] para las cuales obtengamos un resolvente [3x] cualquiera, siempre habrá un sustitución de las variables de [3], mediante la cual se obtendrá como aterrizamiento la cláusula [3x]. En el ejemplo 3, la sustitución que realizamos de cambiar f(x) en lugar de x se puede representar por el conjunto: Ø = {f(x) / x} De esta manera podemos decir que una sustitución es un conjunto donde se reemplazan términos por variables, como se define a continuación. Aquí el término sustitución se define como sigue: DEFINICIÓN: Una sustitución es un conjunto finito de la forma: {t1/v1, ....tn/vn} donde ti y vi son términos y variables respectivamente que cumplen las siguientes condiciones: A) Cada término ti es un término diferente a vi. Es decir el numerador y el denominador son diferentes. Ésto se debe a que, en caso contrario, no habría en realidad sustitución alguna. B) No existen dos elementos del conjunto que tengan la misma variable. EJEMPLO 4. El conjunto: { f(z)/ x, (a/z) } satisface la definicición de sustitución, ya que ninguna variable vi (los denominadores de cada elemento del conjunto) es igual a otra sus numeradores y denominadores son diferentes. EJEMPLO 5. El conjunto: {3/x, 4/x} no satisface la definición de sustitución, ya que no satisface la condición B, pues los dos elementos elementos de este conjunto tienen la misma variable. Nótese que no se permite cambiar 3 y 4 al mismo tiempo por la variable x. TÉCNICAS DE RESOLUCIÓN En esta sección describiremos las reglas de inferencia del Cálculo Proposicional usadas en el método de resolución, la forma clausular utilizada en resolución y las técnicas de resolución más comunes. REGLAS DE INFERENCIA Resolución Proposicional utiliza solamente una regla de inferencia, que se puede expresar en cualquiera de la siguientes tres formas, todas ellas equivalentes entre sí: FORMA I : 1) P => Q 2) Q => R ---------3) P => R FORMA II : !- P => Q; !- Q => R ------------------------!- P => R FORMA III : 1) - P v Q 2) -Q v R -------------3) -P v R La primera forma, también se conoce como regla de inferencia de encadenamiento, e indica que si p implica q (proposición 1), y q a su vez implica r (proposión 2), entonces se puede inferir que p implica r (proposición 3). El uso de la regla de inferencia de encadenamiento es muy utilizada en sistemas expertos y en aplicaciones tipo Prolog, donde los lados izquierdos de las implicaciones se conocen como premisas. La segunda forma, es la misma regla de inferencia pero escrita en la notación del Cálculo de Secuentes. Un secuente tiene dos partes principales, separadas por una linea horizontal como sigue: PREMISA1, PREMISA 2, ... , PREMISA N ------------------------------------------------------CONCLUSIÓN A Que se lee: "dadas las premisas 1, premisa2, ... , premisan, se deduce la CONCLUSIÓN A". De esta manera la FORMA 2 de la regla de encadenamiento, se lee: "dado que es válido P => Q, que es válido Q => R, se puede deducir que es válido P => R". La tercera forma, es la regla de inferencia de eliminación, la cual puede deducirse de la propia regla de encadenamiento, de acuerdo con las siguientes tautologías: P => Q Q => R P => R = ~P v Q = ~Q v R = ~P v R La forma III se puede también escribir (tomamos ahora símbolos de proposiciones, a las literalesA, B y C) FORMA III: (1) A v B (2) ~A v C ------------------{1,2}(3) B v C En la forma III, se indica que, dadas las cláusulas (1) y (2), se puede deducir (3), es decir, (3) es una consecuencia lógica de (1) y (2). De esta manera, la válidez de la forma III se puede comprobar, (de acuerdo con la definición de consecuencia lógica) verificando que la implicación de (1) y (2) es una fórmula válida. Es bastante conocido que para el Cálculo Proposicional, usando solamente la Forma III cómo la única regla de inferencia (sin ningún esquema axiomático u otras reglas de inferencia), es posible construir un demostrador de teoremas que sea consistente y completo para todos las lógicas conocidas del Cálculo Proposicional. FORMA CLAUSULAR EN RESOLUCIÓN El método de resolución se usa con el conjunto de fórmulas escritas en la forma normal conjuntiva, es decir, cada una de las fórmulas participantes (premisas y fórmula objetivo) se transforman en uno ó más cláusulas de la forma: fi1 v fi2 v ... v fik Una simple literal, representando a un símbolo de proposiciones, o simplemente, una literal, digamos P o su negación ~P son cláusulas y, por tanto, no requieren transformación. Se dice entonces que una literal puede ser una sentencia atómica P o bien su negación ~P. De esta forma se define cláusula como sigue: DEFINICION: Una cláusula es una literal o una disyunción de literales. De esta forma se puede también definir cláusula como sigue: P ~P PvQ Las cláusulas también se escriben como conjuntos de literales, es decir: {P} {~P} {P,Q} A veces se utiliza el término Base de Datos de Cláusulas o simplemente Base de Datos, para referirse a un conjunto de cláusulas. De esta manera, la siguiente base de datos: {{-P,Q},{R,-Q}} representa al conjunto de clausulas: -P V Q R V -Q CLÁUSULA VACÍA La cláusula vacía, denotada por NIL, es por definición falsa de modo que es insatisfactible. Esto se debe a que NIL es equivalente a una disyunción vacía (sin literales), de modo que no se satisface para ninguna interpretación. Sin embargo la base de datos vacía {} es satisfactible, ya que es equivalente a una conjunción vacía de cláusulas para la cual no se puede deducir NIL. Sin embargo, la base de datos conteniendo sólo de la cláusula vacía (es decir NIL), es no satisfactible, ya que NIL es siempre falsa. CONVERSIÓN A LA FORMA CLAUSULAR: Se hace en cuatro pasos: PASO 1) Eliminar implicaciones: P1 => P2 ---> P1 <= P2 ---> P1 <=> P2 ---> ~P1 v P2 P1 v ~P2 (~P1 v P2) & (P1 v ~P2) paso 2) Pasar las negaciones hacia adelante: ~~P ---> P ~(P1 & P2) ---> ~P1 v ~P2 ~(P1 v P2) ---> ~P1 & ~P2 Paso 3) Usar leyes distributivas: (Pasar disyunciones hacia adentro) P1 V (P2 & P3) ---> (P1 V P2) & (P1 V P3) Paso 4) Pasar operadores hacia afuera: 4A) DISYUNCIONES P1 v P2, SE ESCRIBEN COMO UNA SIMPLE CLÁUSULA {P1,P2} 4B) CONJUNCIONES SE ELIMINAN PARA FORMAR CLÁUSULAS P1 & P2 & ...Pm se escriben como m cláusulas: {P1},{P2},..,{Pm} donde las Pi son disyunciones. Ejemplo. Convertir a su forma clausular: (G & (R => F)) SOLUCIÓN Paso 1: (G & (~R v F)) Paso 2: no es necesario Paso 3: no es necesario Paso 4: 1) {G} 2) {~R,F} Ejemplo. Convertir a su forma clausular: ~(G & (R => F)) SOLUCIÓN Paso 1: Eliminar implicaciones. ~(G & (~R v F)) Paso 2: Pasar negaciones hacia adelante. (~G v ~(~R v F)) = (~G v (~~R& ~F)) (~G v (R & ~F)) Paso 3: no es necesario Paso 4 A) Pasar disyunciones hacia adelante (~G v R) & (~G v ~F) Paso 4 B) Eliminar &'s Cláusula 1: Cláusula 2: La cláusula ~G v R se escribe: {~G, R} La Cláusula ~G v ~F se escribe: {~G, ~F} TÉCNICAS DE RESOLUCIÓN COMUNES Existen diversas técnicas de resolución, las más comunes son las siguientes: 1) 2) 3) 4) 5) 6) Nivel de saturación Resolución unitaria Resolución ordenada Conjunto de Soporte Resolución Semántica Regla de una literal LA REGLA DE UNA LITERAL Y EL MÉTODO DE RESOLUCIÓN 1. INTRODUCCIÓN Para verificar si un conjunto de cláusulas S es insatisfactible usando el principio de resolución, la idea esencial es verificar si S contiene (o de él puede derivarse), la cláusula vacía, en cuyo caso S es insatisfactible. Este principio tiene sus bases en la Regla de una Literal del método de Davis y Putnam, la cual se explica en este ensayo. Se presentan ejercicios tomados del libro de Chang & Lee, pero resueltos todos aplicando la regla de una literal. Se espera que con los ejemplos proporcionados, los alumnos podrán por sí mismos reconocer un algoritmo que aplique dicha regla. Los ejemplos son solamente del cálculo de proposiciones pero ilustran correctamente el empleo de la regla de una literal. 2. Lemas para la Regla de una Literal 2.1 LEMA 1 "Sea un conjunto de cláusulas S0 : {L V A1, L V A2, L}, donde L no pertenece a Ai pertenece a NIL; entonces S0 es satisfactible". y L no DEMOSTRACIÓN : Considérese la Base de Datos, conformada únicamente por tres cláusulas: S0 = {L v A1, L v A2, L} Denotemos por S1 al siguiente conjunto, conformado solo por solamente dos cláusulas de S0: S1= { (a) (b) L V A1 L V A2 } Como S0 y S1 difieren solamente en la cláusula unitaria L, y esta es satisfactible, hay sólo dos condiciones sobre S1 que permiten que S0 sea satisfactible: A) El resolvente de (a) y (b) no sea ~L B) El resolvente de (a) y (b) no sea la cláusula vacía. Se pueden tener los siguientes casos sobre el conjunto S1, para los cuales examinamos el resolvente de las cláusulas (a) y (b). CASO 1. A1 y A2 son cláusulas unitarias simples y forman un par complementario. {a,b} (c) L por lo tanto S1 es satisfactible y S0 también. CASO 2. A1 y A2 son cláusulas unitarias simples pero no complementarias. Entonces no se puede determinar ningún resolvente para las cláusulas (a) y (b), de modo que el conjunto S1 es satisfactible. Como S0 y S1 difieren solamente en L, entonces S0 es satisfactible. CASO 3. A1 y A2 son disyunciones. Sean las disyunciones de A1 y A2 las siguientes: A1= a11 v ....a1n A2= a21 v ....a2m de forma que las cláusulas de S1 se escriben: (a') a11 v....v a1n v L (b') a21 v ...v a2m v L Dado que L no pertenece ni a A1 ni a A2, no existe ningun par complementario entre las literales aij y L. Esto significa que a partir de (a) y (b) no es posible eliminar L. Por lo tanto S1 es satisfactible. Por lo tanto S0 es satisfactible. LEMA 1.1 Sean las cláusulas: A1, A2, ...An, L, tales que en Ai no existe L. Entonces, cualquier conjunto de la forma: S0={L V A1, L v A2, L v A3, ..., L v An, L} es satisfactible. DEMOSTRACIÓN. Sea el conjunto: S1={ L v A1,L v A2, L v A3,..., L v An} puesto que todas las Ai son diferentes de L, no existe ningun resolvente que sea igual a ~L.Puesto que S1 y S0 difieren solamente en L, no es posible obtener un par complementario {L, ~L}, En consecuencia S0 es satisfactible. LEMA 1.2 Sea el conjunto S0 = {S1, L} donde S1 es un conjunto de cláusulas, entonces S0 es satisfactible si todas las cláusulas del conjunto S1 contienen la literal L. DEMOSTRACIÓN Del lema 1 anterior, si S1 contiene la literal L, entonces S0 es satisfactible. COROLARIO : Dado un conjunto S0 de cláusulas, con una cláusula unitaria L, si se eliminan todas las cláusulas en S0 conteniendo L para obtener un conjunto S1, S0 es satisfactible si S1 es vacío. 2.2 LEMA 2 : Dado los conjuntos de cláusulas S0, S1 y S2: S0 = {L v X1, L v X2, ...., L v Xn, ~L v B1, B2, L} S1= {~Lv B1, B2} S2= {B1, B2} donde S1, se ha obtenido eliminando de S0 todas las cláusulas que tengan L. Entonces S0 es insatisfactible. DEMOSTRACIÓN Eliminando de S0 todas las cláusulas que tengan L, se obtiene el conjunto: S1= {~L v B1, B2} Debido al corolario del lema 1, no podemos concluir que S0 es satisfactible, dado que S1 no es vacío. Obsérvese que al eliminar todas las cláusulas que tienen L, no se afecta la satisfactibilidad de S0. De esta manera, S0 es insatisfatible sólo si en S1 se produce la cláusula ~L, ya que al eliminarse todas las literales con la literal L solo queda en S0: a) Una cláusula unitaria L y b) Dos cláusulas: -L V B1, B2 1) De las cláusulas b: S1 = [-L V B1, B2] 2) Quitando -L de las cláusulas de S1 (i.e. solamente la primera de ellas): S2 = {B1, B2} Entonces si S2 es insatisfactible, S0 lo es. NOTA: Otra forma de ver este lema es el siguiente: Si S2 es insatisfactible, el resolvente de las cláusulas de S1 es -L. Como S1 (donde se infiere -L) existe en S0 (donde existe L), entonces se concluye: de S0 se deduce NIL. Entonces S0 es insatisfactible COROLARIO : Dado un conjunto S0 con una cláusula unitaria L, obtener el conjunto S1 eliminando todas las cláusulas que contengan L. Si S1 no es vacío, eliminar de S1 la literal -L para formar el conjunto S2. S2 es insatisfactible si y solo si S0 lo es. Note que si -L es una cláusula unitaria, entonces la cláusula se vuelve vacía cuando -L es eliminada. 2.3 Enunciado de la Regla de una Literal Del análisis anterior hemos obtenido las siguientes conclusiones para un conjunto S0 de cláusulas, con una cláusula unitaria L : 1) Si se eliminan todas las cláusulas en S0 conteniendo L para obtener un conjunto S1, entonces S0 es satisfactible si S1 es vacío. 2) Si al eliminar de S0 todas las cláusulas que contengan L, el conjunto S1 no es vacío, eliminar de S1 la literal -L para formar el conjunto S2. S2 es insatisfactible si y solo si S0 lo es. Note que si -L es una cláusula aterrizada, entonces la cláusula se vuelve vacía cuando -L es eliminada. De esta forma la regla de una literal establece que "Si hay una cláusula aterrizada L en S0, obtener S1 a partir de S0, eliminando las cláusulas que contengan L : a) Si S1 es vacío, entonces S0 es satisfactible. b) Si S1 no es vacío, obtener S2 eliminando de S1 a la literal -L. S2 es insatisfactible si S0 lo es. Note que si -L es una cláusula unitaria, esta eliminación indica de inmediato NIL y que S0 es insatisfactible". 3. Ejemplos EJEMPLO 1. Demostrar que el siguiente conjunto es insatisfactible. (1) (2) (3) (4) (5) P V Q V -R P V -Q -P R U ITERACIÓN 1 : S0 (1) (2) (3) (4) (5) P V Q V -R P V -Q -P R U S1/-P (1) P V Q V -R (2) P V -Q (3) (4) R (5) U S2/P (1) Q V -R (2) -Q (3) (4) R (5) U ITERACIÓN 2 : (EL ÚLTIMO CONJUNTO SE LLAMA AHORA S0) S0 (1) (2) (3) (4) (5) Q V -R -Q R U S1/-Q (1) Q V -R (2) (3) (4) R (5) U S2/Q (1) -R (2) (3) (4) R (5) U ITERACIÓN 3 : Ahora S0 (que es el conjunto anterior) contiene un par complementario sobre la literal R. De este modo se determina NIL, ya que de acuerdo con la regla de una literal, si en el primer paso se elimina R para S, en el segundo paso al determinar S2 y encontrarse que -L (es decir -R) es unitaria, se determina la cláusula vacía. EJEMPLO 2. Determinar si el siguiente conjunto es satisfactible. (1) P V Q (2) -Q (3) -P V Q V -R ITERACIÓN 1 : S0 (1) P V Q (2) -Q (3) -P V Q V -R S1/-Q (1) P V Q (2) (3) -P V Q V -R S2/Q (1) P (2) (3) -P V -R ITERACIÓN 2 : S0 S1/P S2/-P (1) P (2) (3) -P V -R (1) (2) (3) -P V -R (1) (2) (3) -R ITERACIÓN 3 : S0 S1/-R (1) (2) (3) -R (1) (2) (3) Puesto que S1 es vacío (es decir, no tiene cláusulas), el conjunto S inicial es satisfactible. EJEMPLO 3. S0 (1) (2) (3) (4) P V -Q -P V Q Q V -R -Q V -R INICIALIZACIÓN : OBTENER CLÁUSULAS UNITARIAS POR SATURACIÓN (Nivel 1) [1,2] [1,3] [2,4] [3,4] (Nivel 2) TAUTOLOGÍA (5) P V -R (6) -P V -R (7) -R [1,6] ---- (existente) [..] ---- no hay cláusulas unitarias SE AGREGA LA CLÁUSULA UNITARIA AL CONJUNTO INICIAL PARA FORMAR S0 : S0 (1') (2') (3') (4') (5') P V -Q -P V Q Q V -R -Q V -R -R S1/-R (1') (2') (3') (4') (5') P V -Q -P V Q Q -Q Puesto que S1 no es vacío, no podemos determinar que S0 es satisfactible, eso no implica que S0 no lo sea. Debido a ello, debemos recurrir a otra técnica. Una posibilidad es generar las cláusulas unitarias por el método de nivel de saturación; en ese caso en particular, la única cláusula unitaria que será generada es -R; como consecuencia, el resultado obtenido será que el conjunto es satisfactible. CONCLUSIONES : La regla de una literal permite obtener un tratamiento eficiente al demostrar teoremas mediante resolución. Sin embargo, existen situaciones donde se necesita de técnicas alternativas, ya que requiere que se tengan cláusulas unitarias. REGLA DE UNA LITERAL ESTRUCTURADA CON REGLA DE PARTICIÓN INTRODUCCIÓN En el módulo anterior vimos la regla de una literal de Davis y Putnam (a la que nos referiremos como la regla R1L de Davis) aplicada a un conjunto S0 de cláusulas, para el cual deseamos saber si es satisfactible o no. Para la aplicación de dicha regla, se requiere que S0 cuente entre sus elementos con una cláusula unitaria que denominamos L. En el primer paso de esta regla se eliminan todas las cláusulas que tengan la cláusula unitaria L, para así obtener un nuevo conjunto S1. Una condición que determina que S0 es satisfactible ocurre cuando S1 es un conjunto vacío de cláusulas. Si esa condición no se presenta, entonces se procede al segundo paso de la regla, que consiste en eliminar de cada cláusula de S1 la literal ~L, obteniendo de este modo un nuevo conjunto S2. Durante este segundo paso, se proporciona una condición para la insatisfactibilidad de S0 cuando S2 lo es. Nótese que la regla R1L de Davis no contempla la eliminación distribuida y que pierde de vista las cláusulas descendientes de la fórmula objetivo. Hay que notar también que esta regla sólo se aplica si existe al menos una cláusula unitaria en el conjunto S0 antes de interés. Por otro lado Davis y Putnam obtuvieron otras reglas útiles para la demostración de teoremas, entre las que destaca la Regla de Partición, misma que permite la demostración de teoremas en forma distribuida. De esta manera, nos proponemos mostrar una Regla de una Literal Estructurada en base a la identificación de la cláusula objetivo negada y de sus descendientes, para su utilización en forma distribuida en la demostración de teoremas. A esta regla la denominaremos regla R1L estructurada. DEFINICIONES PRELIMINARES Consideraremos la siguiente convención: S0 = conjunto de cláusulas para el cual se desea saber si éste es o no satisfactible. Sa es una secuencia de cláusulas cualesquiera de orden mayor o igual a 1. A1, A2,… , An son cláusulas de orden mayor o igual a 1. L es una cláusula unitaria tal que ni ella ni su complemento, ~L, existen en ninguna Ai L o ~L, pero no las dos, pueden existir en cada cláusula de Sa S1 es el conjunto obtenido de S0, eliminando las cláusulas que tengan la literal L. NIL= La cláusula vacía. Conjunto = Conjunto de cláusulas. DEFINICIÓN: Una cláusula es una disyunción de literales. Ejemplo. Las siguientes son cláusulas: i) A v B v C ii) A iii) NIL La primera es una disyunción de 3 literales, la segunda de 1 y la tercera de 0 (la cláusula vacía). DEFINICIÓN. El orden de una cláusula es el número de literales en ella. De este modo, el orden de las cláusulas del ejemplo anterior es 3, 1 y cero, respectivamente. DEFINICIÓN. Una literal L en un conjunto S0 es pura, si ~L no existe en So. EJEMPLO: A es pura para el conjunto: S0 = { A v B, A v ~B} Mientras que B y ~B no lo son.. DEFINICIÓN: Un conjunto no unitario es un conjunto de cláusulas en el cual no existe ninguna cláusula de orden menor o igual que la unidad. EJEMPLO: Los siguientes son conjuntos no unitarios: { A v B, A v ~B, R v Q, R v ~Q} {A v B, A v ~C} REGLA DE UNA LITERAL DE DAVIS Para un conjunto S0 de cláusulas donde existe una cláusula unitaria L, proceder como sigue: PASO 1: Formar un conjunto S1, eliminando de S0, todas las cláusulas que tengan L. S0 es satisfactible si S1 es vacío.. Si S1 no es vacío, pasar al paso 2. PASO 2. Formar el conjunto S2, eliminando de cada cláusula i de S1 la literal ~L (esto equivale a obtener el resolvente de cada cláusula i con la cláusula L). So es insatisfactible si S2 lo es. JUSTIFICACIÓN DE R1L DE DAVIS La estableceremos mediante varios teoremas que postularemos a continuación. TEOREMA 1: Todo conjunto no-unitario, con una literal pura L, de la forma: Ç= { A1 v L, A2 v L, ... , A n v L} (6) es satisfactible. DEMOSTRACIÓN Procederemos por demostración al absurdo. Supongamos que Ç es insatisfactible. Entonces ~ L existe en al menos una de las cláusulas de Ç. La existencia de ~ L en Ç, contradice su definición. En consecuencia el conjunto Ç es satisfactible. [] TEOREMA 2: Todo conjunto de cláusulas con una literal pura de la forma: Ç= { A1 v L, A2 v L, ... , A n v L, L} (7) es satisfactible. DEMOSTRACION Supongamos que Ç es insatisfactible. Entonces NIL se puede obtener de los conjuntos: a) L b) A1 v L, A2 v L, ... , A n v L En a) no existe NIL, puesto que L es diferente de ella. Las cláusulas de b) se pueden conformar en un conjunto no unitario y, por el teorema 1, éste es satisfactible. Por lo tanto NIL no existe en b). Entonces NIL se debe poder obtener como un resolvente entre L y las cláusulas en b). Como consecuencia, en b) se puede obtener ~ L como resolvente. Por lo tanto, ~ L existe en alguna cláusula del conjunto b, lo cual es imposible. En consecuencia el conjunto Ç es satisfactible. [] El conjunto (7) contiene una literal pura en todas sus cláusulas. Conjuntos como éste se denominarán puros, como se establece en la siguiente definición. DEFINICIÓN. Un conjunto puro contiene una literal pura en todas sus cláusulas. COROLARIO: Todo conjunto puro es satisfactible. Un procedimiento que determine que un conjunto es puro, indicará también que es satisfactible. Para ello usamos la siguiente nomenclatura: sign (Li) es el signo de una literal Li en S0 Sum (Li) es la suma acumulada de sign(Li) para Li en cada cláusula Max (S) el máximo valor entre todos los Sum (Li). N el número de cláusulas en S0. El algoritmo simple siguiente detecta si un conjunto S0 es puro y por tanto satisfactible. Si Max(S0) = N Entonces S0 es puro y satisfactible. EJEMPLO: Determinar si el siguiente conjunto es satisfactible: S0 = {P v ~Q v R, P v Q, P} SOLUCIÓN N = 3 cláusulas sign(P) = {1, 1, 1} ; SUM (P) = 3 sign(Q) = {-1, 1, 0} ; Sum (Q) = 0 sign(R) = {1, 0, 0} ; Sum(R) = 1 de modo que Max (S0) = 3. por lo tanto S0 es satisfactible. EJEMPLO: Determinar sI los siguientes conjuntos son satisfactibles. ii) {P v B v R, P v ~B} iii) {Pv Q} iv) P SOLUCIÓN Los tres casos conforman conjuntos puros. Por lo tanto, esos conjuntos son satisfactibles. TEOREMA 3 Sea un conjunto: S0 = {A1 v L, A2 v L, ..., An v L, L, Sa} (8) tal que S1 es vacío, entonces S0 es satisfactible. DEMOSTRACIÓN Puesto que S1 es vacío y, al obtenerlo, se eliminaron de S0 todas las cláusulas con la literal L, entonces todas las cláusulas en Sa contienen la literal L y por lo tanto ~L no existe en S0. En consecuencia el conjunto S0 contiene una literal pura. Es decir es de la forma: S0 = {C1 v L, C2 v L, ... , Cm v L, L} Esto es, S0 es puro. Del teorema 2, S0 es satisfactible. [] En consecuencia S0 es satisfactible si al eliminar las cláusulas conteniendo L, el conjunto S1 resultante es vacío. Esto significa que este teorema justifica el paso 1 de la regla R1L de Davis. TEOREMA 4 Sea un conjunto de cláusulas S0 = {A1 v L, A2 v L, ..., An v L, L, Sa} Tal que S1 no es vacío y se forma un conjunto S2, quitando de S1 la literal ~L, Entonces S0 es insatisfactible si S2 es insatisfactible. DEMOSTRACIÓN Como S1 no es vacío, no se puede concluir que S0 es satisfactible, pero tampoco que no lo es. Observe que S0 es insatisfactible si el resolvente de Sa y L es NIL; entonces se requiere que Sa tenga en alguna cláusula, la literal ~L. Como al momento de formar S1, se eliminaron de Sa las cláusulas con la literal L, entonces en Sa hay dos posibles tipos de cláusulas: a) Las que no contienen ~L b) Las que contienen ~L. Ahora bien, todos los resolventes de la cláusula L con las cláusulas tipo b de Sa se encuentran forzosamente en S2. De manera que si S2 es insatisfactible, S0 lo es. En consecuencia, este teorema justifica el paso 2 de la regla R1l de Davis. A partir de este teorema se desprende la regla de una literal pura de Davis la cual establece que para el conjunto S0 anterior, si Sa es insatisfactible, entonces, S0 es insatisfactible. Esto se justifica fácilmente, ya que para S0 sus cláusulas están en la fórmula normal conjuntiva. Es decir que S0 se puede representar por la secuencia: S0 = (A1 v L) & (A2 v L) &, ..., & (An v L) & , L, & Sa de tal manera que si Sa es insatisfactible, S0 forzosamente lo es. La regla de una literal pura de Davis & Putnam (no confundir con la regla de una literal, descrita aquí como R1L), se enuncia entonces como sigue: REGLA DE UNA LITERAL PURA: Sea un conjunto S0 de cláusulas del Cálculo Proposicional (o del Cálculo de Predicados, si las cláusulas están aterrizadas), de modo que en S0 se tenga una literal pura L. Se forma el conjunto S1 eliminando de S0, todas las cláusulas que contengan L. S0 es insatisfactible si S1 lo es. Si ocurre que S1 es vacío, S0 es satisfactible. EJEMPLO: Determinar si el siguiente conjunto de cláusulas es insatisfactible: S0 = { (A v B), (A v ~B), (C v B), (C v ~B)} SOLUCIÓN So tiene dos literales puras, que son A y C, pero S0 no es puro. Aplicando La regla de una literal pura sobre A, se tiene: S1/A = {(C v B), (C v ~B)} Hacemos S0 = {(C v B), (C v ~B)} Aplicamos ahora la regla de una literal pura sobre C para obtener: S' = {} ==> So es satisfactible. EXTENSIONES DE LA REGLA DE UNA LITERAL Es posible establecer extensiones de R1L para considerar aplicaciones distribuidas de la misma. Para ello se exponen aquí dos versiones: a) R1L ESTRUCTURADA CON CONJUNTO DE SOPORTE b) REGLA R1L ESTRUCTURADA PARA N LITERALES Para lo anterior recordemos que deseamos saber si una fórmula objetivo G, es una consecuencia lógica de un conjunto de fórmulas, Ø= {F1, F2, ..., Fn} (1) el cual es un conjunto de axiomas consistente, es decir, en Ø no existe ninguna cláusula contradictoria. Es decir, se desea saber si se cumple que: Ø |- G (2) Como hemos visto, se puede proceder negando la fórmula objetivo para determinar si la conjunción siguiente es inconsistente: F1 & F2 & ...& Fn & ~ G (3) o bien F1 & F2 & ...& Fn & G' (3a) donde G' = ~G Pasando ~G a su forma normal conjuntiva, obtenemos un conjunto S0 de cláusulas S0 = {F1, F2, ...Fn, g1, g2, ... , gr} (3b) donde g1, g2, … son cláusulas de la fórmula objetivo negada. Es decir las g's son de la forma: gi = gi1 v gi2 v, …, v gil (4) Consideraremos a S0 como una base de datos, de manera que cada posición de S0 es un campo. Obtendremos una regla de una literal, de manera que las cláusulas de los pasos 1 y 2 de R1L de Davis, se obtengan en los mismos campos de S0. Buscamos extender la regla R1l de Davis, de modo que se aproveche la información de la fórmula objetivo negada y que los resolventes obtenidos en cada uno de los pasos se almacenen en los mismos lugares del conjunto S0 original. Estos procedimientos de resolución se conocen como Procedimientos de Conjunto de Soporte y la práctica ha demostrado que son eficientes. Para obtener la regla que buscamos, primero enunciaremos la regla R1l de Davis en forma compacta. R1L DE DAVIS EN FORMA COMPACTA Sea So = { Ø, G'} un conjunto de cláusulas conteniendo un conjunto de axiomas Ø y una fórmula objetivo negada G'. Entonces se puede determinar la satisfactibilidad de So de la siguiente manera: PRIMER PASO: Obtener un conjunto S1 ={Ø, G'} a partir de S0, eliminando aquellas cláusulas que contengan una literal Li, las cláusulas restantes se acomodan en la Base de datos S1, en los lugares Ø o G' según corresponda a los axiomas ó a la formula objetivo, respectivamente. Si S1 es vacío, entonces S0 es satisfactible. Si S1 no es vacío, continuar con el paso 2. SEGUNDO PASO: Obtener el conjunto S2, al eliminar ~Li de S1. S0 es insatisfactible, si S2 lo es. Durante el primer paso de esta regla, si el conjunto S1 es vacío, esto significa que Ø y también G' es vacío. En este caso S0 es satisfactible. Pero G = ~G’. En consecuencia G no es un teorema. La regla que acabamos de enunciar como R1L de Davis en forma compacta, es en realidad la regla R1L de Davis, solamente que hemos identificado al conjunto de axiomas y a la fórmula objetivo. Ahora podremos enunciarla aprovechando el hecho de que cualquier contradicción sólo se puede presentar con la participación de las cláusulas de la G’ ó descendientes de ella. R1L ESTRUCTURADA CON CONJUNTO DE SOPORTE Sea So = {Ø, G'} un conjunto de cláusulas conteniendo un conjunto de axiomas Ø y una fórmula objetivo negada G' = ~G. Suponga que existe una literal L en Ø; entonces, para determinar la satisfactibilidad de S0 (y si G es una consecuencia lógica de Ø), se realizan los siguientes pasos: PASO 1: Formar S1, eliminando de S0 las cláusulas que tengan L, de modo que las cláusulas resultantes se acomodan en Ø y G' según provengan. Entonces si G' es vacío, S0 es satisfactible, de modo que G no es una consecuencia lógica de Ø. Si G' no es vacío, seguir con el paso 2. PASO 2. Eliminar la literal ~L de S1 para formar el conjunto S2, acomodando las cláusulas resultantes en Ø o G' según corresponda. Entonces si S2 es insatisfactible, S0 también lo es y G no sigue de los axiomas originales Ø. EJEMPLO Determinar si G es una consecuencia lógica de Ø: Ø = {A, B, ~C, D v R, ~D v A} G = {~A, ~ B, ~ C} SOLUCIÓN G' = ~G = A v B v C Registramos la información de S0, S1, S2, en la siguiente base de datos: S0 S1/A Ø G' ______________ A, B, ~C AvBvC DvR ~D v A _______________ B, ~C vacío DvR ~D _______________ S1 es vacío, lo que significa que: G no es una consecuencia lógica de Ø Este resultado se puede comprobar usando R1L de Davis: S0 = {A, B,~C, D v R, ~D v A, A v B v C} S1/A = { B, ~C, D v R} = S2/~A = So S1/B = {~C, D v R} = S2/~B = So S1/~C = {D v R} = S2/C S0 = {D v R} Como S0 es un conjunto puro de cláusulas, S0 es satisfactible. En consecuencia, G no es una consecuencia lógica de Ø. Nótese la conveniencia de contar con un procedimiento que detecte conjuntos de cláusulas puros. Obsérvese también que R1L estructurada se aplica cuando Ø cuenta con cláusulas unitarias y, que en el momento que S0 (incluyendo desde el principio), no cuente con cláusulas unitarias, habrá que utilizar otro método. EJEMPLO So = { A v L, ~B v D, A v B, B} G=DvA SOLUCIÓN G'= ~G = {~D, ~A} Registramos la información de S0, S1, S2, en la siguiente base de datos: Ø G' ______________ S0 A v L, ~D, ~A ~B v D, A v B, B _______________ AvL ~D, ~A S1/B ~B v D S2/~B _______________ AvL ~D, ~A D ________________ Aplicando resolución unitaria, encontramos que S2 es insatisfactible, debido a la presencia de las cláusulas unitarias D y ~D. Esto significa que: G es una consecuencia lógica de Ø Este resultado se puede comprobar usando el método de conjunto de soporte con resolución unitaria y eliminando cláusulas repetidas: (1) A v L (2) ~B v D (3) A v B (4) B (5) ~ D (6) ~A {6,1} (7) L {6,3} repetida {5,2}(8) ~B {4,8}(9) nil Es posible extender la Regla R1L de Davis, para eliminar a la vez varias cláusulas unitarias. Para ello exponemos primero algunos teoremas relacionados. TEOREMA 5 Sea Aij cláusulas de 1 ó mas literales y L1, L2, ...,Lm son cláusulas unitarias tal que ni Li ni su complemento existen en ninguna Aij. Entonces todo conjunto de cláusulas S0 ={ A11 v L1, A12 v L1, ... , A1n v L1, L1, A21 v L2, A22 v L1,... A2n v L2, L2, ................................................................ ................................................................ Am1 v L1, Am2 v L2, ... , Amn v Lm, Lm } es satisfactible. DEMOSTRACIÓN S0 está formado por conjuntos de cláusulas de la forma: Ai1 v Li, Ai2 v Li, ..., Ain v Li, Li; i =1, .., m En el primer paso de R1L de Davis, eliminamos L1 para obtener S1 igual a S2 excepto que no contiene el primer renglón. Es decir: S1: {A21 v L2, A22 v L2,..., A2n v L2, L2, ............................................................. .............................................................. Am1 v L1, Am2 v L2, ... , Amn v Lm } Aplicamos ahora el segundo paso de R1L. Puesto que no existe ~L2 en S1, se obtiene S2 igual al conjunto S1 anterior. Se hace ahora S0 igual al último S2. Repitiendo este proceso para todas las Li’s, obtenemos finalmente un conjunto S1 vacío. Por lo tanto S0 es satisfactible. [] COROLARIO Para el paso 1 de R1l, si se eliminan todas las cláusulas que contengan literales Li que sean cláusulas unitarias en Ø, Si el conjunto S1 resultante es vacío, S0 es satisfactible. Cuando se conforme el conjunto S1 de la manera descrita en este corolario, se dirá que éste se obtiene de manera distribuida. De otra manera se dirá que S1 se obtiene de manera simple. Para el siguiente teorema (teorema 6), consideraremos que S1 se ha formado de manera distribuida y fué diferente de vacío. En consecuencia, no se pudo concluir que S0 sea insatisfactible. Supondremos como antes que Sa es cualquier conjunto de cláusulas. Como S1 resultó diferente de vacío, se procede a construir conjuntos S2 como sigue. Para la literal L1, se buscan todas las cláusulas en S1 que contengan la literal ~L1, se les quita dicha literal y se agrupan en el conjunto S21. Se procede de manera similar para L2, ... , Lm, formando los conjuntos S22, ...S2m. Como veremos en el teorema 6, S0 es insatisfactible si existe algún subconjunto S2i que sea insatisfactible. TEOREMA 6 Sea Aij cláusulas de 1 ó mas literales y sean L1, L2, ... ,Lm cláusulas unitarias tales que ninguna de ellas ni su complemento existen en ninguna Aij. Sea el conjunto de cláusulas: S0 ={ A11 v L1, A12 v L1, ... , A1n v L1, L1, A21 v L2, A22 v L2,... A2n v L2, L2, ................................................................ Ak1 v Li, Ak2 v Li, ... , Akr v Li, Li ................................................................ Am1 v Lm, Am2 v Lm, ... , Amn v Lm, Lm, Sa } Considere que se forma el conjunto S1 en forma distribuida, y resulta que este no es vacío y, se toman de S1 las cláusulas que contengan las literales ~L1, ~L2, ... , ~Lm, para obtener respectivamente los subconjuntos S21, S22, ...S2m a partir de ésas cláusulas pero sin la literal ~Li correspondiente. Si existe uno o mas subconjuntos S21, S22, ... , S2m que sea insatisfactible, S0 es insatisfactible. DEMOSTRACIÓN El conjunto Sa debe, forzosamente, contener una literal complementaria ~Li, ya que de otra manera los conjuntos S2i no se pueden formar. Aplicamos el primer paso de la regla R1l de Davis eliminado el renglón Li de S0, para obtener el conjunto S1 y todas las cláusulas en Sa que contengan Li: S1 ={ A11 v L1, A12 v L1, ... , A1n v L1, L1, A21 v L2, A22 v L2,... A2n v L2, L2, ................................................................ ................................................................ Am1 v Lm, Am2 v Lm, ... , Amn v Lm, Lm, Sai } Donde Sai, es el conjunto Sa pero sin las cláusulas que tengan Li. Puesto que S1 no es vacío, aplicamos el segundo paso de R1l de Davis, para formar el conjunto S2. En ese conjunto las cláusulas sin ~Li, las colocamos en el subconjunto S2i. Se repite este procedimiento para todas las cláusulas unitarias Li. S2 es entonces la conjunción de todas las cláusulas de los subconjuntos S2i. Entonces, resulta que si S2i es insatisfactible, S2 lo es y, por la regla R1L de Davis, S0 también lo es. [] TEOREMA 7 Sea el conjunto S0 ={ A11 v L1, A12 v L1, ... , A1n v L1, L1, A21 v L2, A22 v L2,... A2n v L2, L2, ................................................................ ................................................................ Am1 v Lm, Am2 v Lm, ... , Amn v Lm, Lm, Sa } Si Sa no contiene ninguna literal complementaria ~Li, S0 es satisfactible si Sa también lo es. DEMOSTRACIÓN Note que no podemos aplicar el teorema 6 ya que no podemos formar los subconjutnos S2i. En este caso todas las Li son literales puras de modo que al aplicar sucesivamente la regla RIL de Davis, se encuentra que S1 = Sa en consecuencia si Sa es insatisfactible, S1 también lo es. Aplicando la regla de una literal pura, se obtiene entonces que si Sa es insatisfactible, So también lo es. [] Con estos elementos podemos enunciar una primera regla R1l estructurada. REGLA R1L ESTRUCTURADA PARA N LITERALES Sea un conjunto S0 = { Ø, G’} de cláusulas con n literales L1, L2, ..., Ln en Ø. Entonces se puede determinar la satisfactibilidad de S0 en dos pasos: PASO 1: Formar el conjunto S1 en forma distribuida, eliminando de S0, todas las cláusulas que contengan alguna literal Li. S0 es satisfactible si S1 lo es. Si S1 no es vacío pasar al paso 2. PASO 2: Si S1 construido en forma distribuida y no es vacío se procede como sigue. Se toman de S1 las cláusulas que contengan las literales ~L1, ~L2, ... , ~Lm, para obtener respectivamente los subconjuntos S21, S22, ...S2m, conformados con esas cláusulas, pero sin la literal ~Li correspondiente. Si existe uno o mas subconjuntos S21, S22, ... S2m que sean insatisfactible, S0 es insatisfactible. REGLA DE PARTICIÓN En ocasiones no se puede aplicar la Regla de una literal (en ninguna de sus versiones) debido a que el conjunto S0 no contiene cláusulas unitarias. Por otro lado puede resultar que el conjunto S0 sea demasiado grande y por lo tanto, es conveniente encontrar un proceso distribuido que permita buscar la satisfactibilidad de S0 en varios conjuntos de cláusulas, simultáneamente. Para estos caso la Regla de Partición de Davis & Putnam es ideal. Esta regla se enuncia a continuación. REGLA DE PARTICION DE DAVIS & PUTNAM: Sea el conjunto: S0 = { A1 v L, A2 v L, ... , An v L, B1 v ~L, B2 v L, ..., Bm v ~ L, Ra} Donde Ra son cláusulas que no tienen L ni ~L. Se forman lo conjuntos S(L) "sin L" y S(~L) sin ~L: S(L) = {A1, A2, ..., An, Ra} S(~L)={B1, B2, ...., Bm, Ra} Entonces S0 es insatisfactible si S(L) y S(~L) son ambos insatisfactibles. La regla de partición se puede combinar con la Regla de una literal (en cualquiera de sus versiones) para producir un algoritmo eficiente. ESPECIFICACIÓN FORMAL INTRODUCCION Los métodos formales para el desarrollo de software (sw) o, simplemente métodos formales, son métodos que se utilizan para todas las etapas del ciclo de desarrollo de software y que tienen la característica que usan formalismos matemáticos para la representación o derivación de los elementos involucrados en cada etapa. El punto de arranque en la mayoria de los proyectos de sw es un Documento de Requerimientos del Sistema (DRS), en el cual se plazman lo que el usuario desea que haga el sw que desea adquirir. Este documento se escribe por lo general en lenguaje natural (español, inglés, frances, etc.) y, si es necesario, se utilizan también gráficas, tablas y figuras que ayuden a describir con mayor precisión lo que el usuario desea. De esta manera, el lenguaje empleado para escribir un DRS es un lenguaje informal, pero amigable. Los lenguajes informales (como el español), son de naturaleza ambigua, es decir, una misma expresión puede tener más de un significado. El lenguaje informal en que se describe un DRS es mas cercano al usuario y, se describe más en términos de su entorno de aplicación que en términos computacionales. De esta manera empleará expresiones como la siguiente: "El sistema deberá calcular la caida de presión de agua de cada tubería del sistema" "el sistema de control de alarmas para cada centro de control de energía deberá desplegar informes resumidos en forma ejecutiva cada día, según el anexo de este documento" De esta manera, términos computacionales ajenos al lenguaje del usuario, son por lo general evitados en un DRS. De esta forma se evitan términos como "tipo entero", "modulo", etc. El DRS, por lo general se elabora con la (evidente) participación del usuario. A menudo, el usuario es asistido para la escritura del DRS por uno ó más miembros del grupo de desarrollo del sistema. En el DRS, se describen los requerimientos funcionales y no funcionales del sistema de sw que se desea. Los requerimientos funcionales describen al sistema en términos de entrada-salida, mientras que los no-funcionales, en téminos de cualidades deseables del sistema. Por ejemplo, los siguientes son requerimientos funcionales: "Cuando el operador central teclee el comando DOWN, todos los mensajes de alarma almacenados en la pantalla desaparecerán del monitor principal, apareciendo en su lugar el diagrama unifilar de la subestación eléctrica correspondiente" "Cuando se selecciona la opción RESUMEN en el munú 1825, se desplegarán los promedios de energía generada por cada planta generadora perteneciente al centro del control correspondiente". Son ejemplos de requerimientos no funcionales, los siguientes: "El sistema de manejo de eventos no deberá tardar mas de 10 segundos en proporcionar resumenes de información ejecutiva" "El sistema será desarrollado en java e integrado en un estación de trabajo en tiempo real IDM tipo 6890-56". A menudo los DRS se escriben sin la participacion diseñadores de sistemas de cómputo, de modo que no presentan directivas que conlleven a un diseño eficiente. Por otro lado contienen imprecisiones, de manera que se requiere una tarea de analisis que especifique, claramente y sin ambiguedades, el sistema a realizar. El DRS está dirigido para una relación entre el lider y analistas del proyecto de sw y el usuario, mientras la especificación es un documento de trabajo de uso casi exclusivo para el grupo de desarrollo de sw. Esta situación desde luego que debe cambiar ya que la participación del usuario en todas las etapas de desarrollo del sistema. Los métodos formales se pueden utilizar tanto para la especificación como para la verificación formal de programas y, en principio, para la construcción (de código) formal de programas; esta última da lugar a programación automática y derivación formal de programas; sin embargo, en sistemas reales, es mucho más frecuente encontrar aplicaciones de métodos formales para la etapa de especificación que para la verificación formal y, prácticamente nula para el caso de construcción formal de programas. En esta sección trataremos sobre los métodos de especificación formal. LÓGICA DE HOARE INTRODUCCIÓN En 1969, C.A.R Hoare presentó un artículo [HOARE69] que iniciaba textualmente así: "Programación es una ciencia exacta en la que todas las propiedades de un programa y todas las consecuencias de ejecutarlo en un ambiente dado, pueden ser determinadas, en principio, a partir del texto mismo del programa a través de razonamiento inductivo puro" Hoare presentó, en ese entonces, un sistema axiomático para los constructores (o instrucciones) principales de un programa. Desde entonces ha sido desarrollada una gran cantidad de investigaciones, aplicaciones y extensiones, por muchos investigadores (incluyendo las realizadas por el propio Hoare), a tal grado que, en la Enciclopedia de la Computación, a ese artículo, se le considera el más referenciado en las Ciencias Computacionales. Entre las áreas de aplicación más importantes se encuentran, especificación y verificación de sistemas distribuidos y en tiempo real y entre las principales líneas de investigación se encuentran lo que se denomina como Lógica de Hoare, la cual es objeto de esta sección. La Lógica de Hoare ha dado origen a diversos lenguajes de especificación, entre los que destaca CSP (Communicating Secuencial Process), un lenguaje orientado a procesos que desarrolló Hoare, el cual se usa hasta el momento para la especificación de sistemas concurrentes. CSP ha servido de base para otros lenguajes de especificación formal orientados a procesos como LOTOS (un lenguaje de la ISO para especificar sistemas concurrentes). Por otro lado la Lógica de Hoare se puede utilizar para especificación y verificación de programas secuenciales, distribuidos o concurrentes. De esta forma el conocimiento de la lógica de Hoare es importante no sólo por las aplicaciones que se derivan directamente de ella, sino también para comprender y posteriormente aplicar diversos formalismos que de ella se derivan. LA LOGICA DE HOARE La lógica de Hoare, emplea: a) la tripleta {P} S {Q} denominada aserción inductiva, donde {P} se denomina la precondición S es un programa o fragmento de programa {Q} se denomina la poscondición b) Un sistema axiomático La tripleta {P} S {Q} de la lógica de Hoare se debe a Floyd quien la utilizó para la verificación formal de diagramas de flujo [FLOYD67]. La idea sustentada por Hoare es que todo programa debería estar documentado con estas tripletas a lo largo de todo el programa y en diferentes puntos estratégicos. De esta manera cada sección S de programa debe estar acompañada por su documentación conformada por su precondición {P} y su postcondición {Q}. La idea de documentar programas no es nueva, no obstante, Hoare exige que tanto {P} como {Q}, estén escritos en lógica de primer orden. La notación {P} S {Q} es tal que: 1) Representa la especificación funcional del programa, donde: {P} representa el estado de las variables antes de que S se ejecute {Q} representa el estado de las variables después de que S se ha ejecutado. Si el programa no se ha escrito, S es el nombre del programa. De otra manera, S está documentado formalmente con su especificación formal. 2) Representa la correctividad parcial del programa S. Esto significa que el programa S satisface su especificación (la cual es precisamente {P} S {Q} Para propositos de verificación, un programa S constituido por fragmentos S1,S2,..,Sn, se documenta formalmente con aserciones A1, A2,...,An como se ilustra a continuación. {A1} S1 {A2} S2 {A3} ........ ...... { An} Cada fragmento {Ai} Si {Aj}, es tal que Ai es la precondición de Si y, Aj su postcondición, de manera que Aj es a la vez la precondición del siguiente fragmento Si+1. Cada Ai se denomina una aserción. SISTEMA AXIOMÁTICO DE HOARE LA INSTRUCCIÓN DE ASIGNACIÓN La principal diferencia entre las Matemáticas Computacionales y el resto de las matemáticas radica en la instrucción de asignación. En el caso de computación la asignación se refiere a localidades de memoria, de manera que cuando se escribe por ajemplo x = x +1, significa que en la localidad de memoria se incrementará en una unidad, mientras que en Algebra, representa a la indetidad 0 = 1. Para efectuar una distinción el signo igual de la expresión anterior se escribe x:= x +1. Cuando se tiene una instrucción de asignación está podrá ser documentada con sus dos aserciones, su precondición y su postcondición: P(x) x := E(x,y) Q(x) Donde E(x,y) = Expresión tal que y representa todos los términos diferentes de x (es decir no contienen a x). Para propósitos de verificación es posible: * Obtener una precondicón derivada (Pder) de la postcondición y de la instrucción de asignación efectuando una sustitución hacia atrás. Es decir, * Pder se obtiene reemplazando en Q todas las ocurrencias de x por E. Por otra parte, la precondición P(x) representa la precondición proporcionada por el usuario. En esta sección a una precondición porporcionada por el usuario se le representara por Pdada. EJEMPLO 1. Determinar la precondición derivada para el siguiente fragmento de código: {P} x:= 2*y + 1 {x < 11} SOLUCIÓN Sustituyendo hacia atrás: Pder == {x <11} [x = 2*y + 1] =={ 2*y + 1 < 11} =={y <5} REGLA DE PRUEBA EN REVERSA (backward testing) La regla de prueba en reversa (RPR) se fundamenta en el siguiente teorema: TEOREMA Todo fragmento de código {P} S {Q}, se puede verificar de la siguiente manera. Dado que {P} representa la precondición dada por el usuario Pdada, S es correcto si dada una precondición derivada Pder, a partir de {S,Q}, se cumple que: Pdada => Pder es válida. La regla de prueba en reversa, establece que para determinar que un programa S es válido se efectuan los siguientes pasos: PASO 1. Identificar la Precondición dada por el usuario Pdada. PASO 2: Obtener la precondición derivada Pder. PASO 3: Determinar si Pdada => Pder es una fórmula válida, en cuyo caso el programa S es correcto. REGLA DE PRUEBA DE IF THEN Sea una instrucción IF-THEN: {P} IF B THEN S {Q} Es decir la Instrucción IF-THEN tiene dos partes, para las cuales se debe realizar lo que a continuación se indica: a) El lado Then: Que ocurre cuando B se cumple y, se ejecuta la instrucción S terminando el estado de las variables de acuerdo con Q. Esta parte tiene como precondición dada {P & B} la cual representa el estado de las variables antes de que S se ejecute. Una vez que S se ejecuta, se tiene como postcondición a {Q}, es decir la postcondición de toda la instrucción IF-THEN. Esto significa que una condición necesaria (pero no suficiente) para que sea correcta la instrucción {P} IF THEN S {Q} es que la instrucción {P & B} S {Q} sea correcta. Esto puede verificarse, siguiendo los tres pasos de la Regla de Prueba en Reversa (RPR). El primer paso de RPR es simple, ya que Pdada es simplemente {P&B}. La obtención de la precondición derivada Pder para el lado del Then, se obtiene entonces a partir del conjunto {S,Q}. La verificación de Pdada => Pder se puede realizar entonces usando una tabla de verdad o, por resolución. b) El lado Falso: Que ocurre cuando B no se cumple. Esta parte los programadores, por lo general, no la consideran como parte del Then, no obstante que formalmente está presente. Puesto que el lado falso de la instrucción IF-THEN, no contiene ninguna instrucción, no tenemos fragmento de código a verificar. Sin embargo se debe cumplir la fórmula P & ~B =>Q. Esto se debe a que para que el control de ejecución tome el camino de lado falso se debe haber cumplido la fórmula P y luego la fórmula ~B; de esta forma durante el camino del lado falso se debe cumplir P & ~B. Una vez que se llega al final del Then se debe cumplir la postcondición Q, de modo que la implicación de P &~B => debe ser una fórmula válida. En resumen, de acuerdo con lo anterior un IF-THEN se verifica de la siguiente manera PASO1: VERIFICACION DEL LADO DEL THEN. 1-A: IDENTIFICACION Pdada: Pdada == { P & B} 1-B: DETERMINACION DE Pder. Pder se obtiene con Q y el fragmento de código S del lado del then. Esto se expresa en la forma: {Q, S} |- Pder que significa que a partir de la postcondición Q y el fragmento de código S del lado del Then se deduce (o debe deducirse) la precondición derivada Pder del lado del Then (el símbolo |- se lee se "se deduce"). 1-C: VERIFICAR SI ES VALIDO: Pdado |- Pder PASO 2: VERIFICACION DEL LADO ELSE. Cuando la condición B no se cumple, no se entra al lado then, de modo que se debe verificar si es válido: (P & ~B) -> Q EJEMPLO Verificar si el siguiente fragmento de código es correcto: P = = { X = X'} IF X < 0 then X = -X Q= = { (X' < 0 => X = - X') & (X' >= 0 => X = X') } SOLUCION PASO 1:PRUEBA P1(VERIFICACION DEL LADO DEL THEN) 1-A Pdada = = {P & B} == { (X = X' & X <0} 1-B: Pder = = { (X' < 0 => X = - X') & (X' >= 0 => X = X') } [X := -X] = = { (X' < 0 => -X = - X') & (X' > =0 => -X = X') } 1-C Verificar Pdada -> Pder Construimos una tabla de verdad con 1-A y con una 1-B: (X = X' & X <0) => (X' < 0 =>-X = - X') & (X' >= 0 => -X = X') V V V V V F V V V V V PASO 2: VERIFICAR P & ~B => Q X = X' & ~( X <0) => (X' < 0 => X = - X') & (X' >= 0 => X = X') V V F V F V V V V V V V V V En consecuencia, este programa es correcto. REGLA DE PRUEBA DE IF THEN ELSE Dada una instrucción if-then-else, de la forma: {P} IF B THEN S1 ELSE S2 {Q} Para verificar esta instrucción se deben realizar dos pruebas: PASO1: VERIFICAR {P & B } S1 {Q} PASO 2: VERIFICAR {P & ~B} S2 {Q} EJEMPLO {TRUE} IF X>= Y THEN MAX := X ELSE MAX:= Y {X >=Y & MAX = X) OR (X<Y & MAX = Y) SOLUCION PRUEBA 1: Se debe probar si el siguiente programa es correcto: {TRUE & X>= Y } MAX := X {X >= Y & MAX = X) OR (X<Y & MAX = Y) donde: Pdada =={ X>=Y} y Pder se obtiene reemplazando X en lugar de MAX en la postcondición, es decir: Pder = = {{X >= Y & X= X) OR (X<Y & X = Y)} Ahora verificamos si Pdada => Pder es una fórmula válida. Para ello usamos la tabla de verdad: [X>= Y ] => {X >= Y & X= X) OR (X<Y & X = Y} V V V F V V F V V V En consecuencia el programa es correcto. DETERMINACION DE UNA PRECONDICION DE UN IF-THEN-ELSE Dada una instrucción IF-THEN-ELSE para la cual no contamos con su precondición: {?} IF B THEN S1 ELSE S2 {Q} La precondición se obtiene como sigue: P= {(P1 & B) OR (P2 & ~B)} Donde: P1= precondición derivada del lado del then. P2= precondición derivada del lado del else. EJEMPLO: {?} If x <0 then y := x else y := x-2 {-1 < = y < = 4} Solución: La precondición derivada del lado se obtiene reemplazando en la postcondición x por y para obtener P1 del lado del then, mientras que se reemplaza y por x-2 para obtener P2 del lado del else. Es decir: P1 == {-1 < = y < = 4} [y:=x] =={-1 < = x < = 4} P2 =={-1 < = y < = 4} [y:=x-2] == {-1 < = x-2 < = 4} == {1 < = x < = 6} De esta forma la precondición buscada es: P =={-1 < = x < = 4} or {1 < = x < = 6} EJERCICIO: Verificar si es correcto el siguiente fragmento de programa: { 3 < = |X| < = 4} IF X <0 THEN Y := -X ELSE Y:= X {2 < = Y < = 4} REFERENCIAS [FLOYD67} Floyd R. W. Assignment Meaning to programs?, Proc. American Mathematical Society Sym. on Applied Mathematics, Vol. 19. [HOARE69] Hoare C.A.R., An Axiomatic basis for computer programming?, Commm. ACM, 12 (10), pp. 576-580 [FRAUSTO] Frausto Solís J, Sánchez Ante G., "Fundamentos de Lógica Computacional", Editorial Trillas, Enero 2000. ISBN 968-24-6100-6