La semántica de transformadores de predicados fue introducida por Edsger Dijkstra en su artículo fundamental " Guarded commands, nondeterminacy and formal derivation of programs ". Define la semántica de un paradigma de programación imperativa asignando a cada instrucción de este lenguaje un transformador de predicados correspondiente : una función total entre dos predicados en el espacio de estados de la instrucción. En este sentido, la semántica de transformadores de predicados es una especie de semántica denotacional . De hecho, en "Guarded commands" , Dijkstra utiliza solo un tipo de transformador de predicados: las conocidas precondiciones más débiles (véase más adelante).
Además, la semántica de transformadores de predicados es una reformulación de la lógica de Floyd-Hoare . Mientras que la lógica de Hoare se presenta como un sistema deductivo , la semántica de transformadores de predicados (ya sea mediante precondiciones más débiles o postcondiciones más fuertes , véase más adelante) ofrece estrategias completas para construir deducciones válidas de la lógica de Hoare. En otras palabras, proporciona un algoritmo eficaz para reducir el problema de verificar una tripleta de Hoare al problema de demostrar una fórmula de primer orden . Técnicamente, la semántica de transformadores de predicados realiza una especie de ejecución simbólica de enunciados en predicados: la ejecución se realiza hacia atrás en el caso de precondiciones más débiles, o hacia adelante en el caso de postcondiciones más fuertes.
precondiciones más débiles
Definición
Para una proposición S y una postcondición R , una precondición más débil es un predicado Q tal que para cualquier precondición P ,si y solo siEn otras palabras, es el requisito "más laxo" o menos restrictivo necesario para garantizar que R se cumpla después de S. La unicidad se deduce fácilmente de la definición: si tanto Q como Q' son precondiciones más débiles, entonces por definiciónentoncesyentoncesy por lo tantoA menudo usamospara denotar la precondición más débil para la afirmación S con respecto a una postcondición R.
Convenciones
Usamos T para denotar el predicado que es verdadero en todas partes y F para denotar el que es falso en todas partes. No deberíamos confundirnos, al menos conceptualmente, con una expresión booleana definida por la sintaxis de algún lenguaje, que también podría contener verdadero y falso como escalares booleanos. Para tales escalares, necesitamos realizar una conversión de tipo tal que tengamos T = predicado(verdadero) y F = predicado(falso). Esta conversión se realiza a menudo de forma informal, por lo que la gente tiende a considerar T como verdadero y F como falso.
Saltar
Abortar
Asignación
A continuación, presentamos dos precondiciones más débiles equivalentes para la declaración de asignación. En estas fórmulas,es una copia de R donde las ocurrencias libres de x se reemplazan por E. Por lo tanto, aquí, la expresión E se convierte implícitamente en un término válido de la lógica subyacente: es, por lo tanto, una expresión pura , totalmente definida, terminante y sin efectos secundarios.
- versión 1:
- versión 2:
Siempre que E esté bien definido, aplicamos la llamada regla de un punto a la versión 1. Entonces
La primera versión evita una posible duplicación de x en R , mientras que la segunda versión es más simple cuando hay como máximo una sola aparición de x en R. La primera versión también revela una profunda dualidad entre la precondición más débil y la postcondición más fuerte (véase más abajo).
Un ejemplo de cálculo válido de wp (usando la versión 2) para asignaciones con la variable x de valor entero es:
Esto significa que, para que la postcondición x > 10 sea verdadera después de la asignación, la precondición x > 15 debe ser verdadera antes de la asignación. Esta es también la "precondición más débil", ya que es la restricción "más débil" sobre el valor de x que hace que x > 10 sea verdadera después de la asignación.
Secuencia
Por ejemplo,
Condicional
Por ejemplo:
Bucle while
Corrección parcial
Ignorando la terminación por un momento, podemos definir la regla para la precondición liberal más débil , denotada wlp , utilizando un predicado INV , llamado ariant INV de bucle , normalmente proporcionado por un programador:
Corrección total
Para demostrar la corrección total, también debemos demostrar que el bucle termina. Para ello, definimos una relación bien fundamentada en el espacio de estados, denotada como ( wfs , <), y definimos una función variante vf , de tal manera que tenemos:
De manera informal, en la combinación anterior de tres fórmulas:
- La primera significa que la variante debe ser parte de la relación bien fundamentada antes de entrar en el bucle;
- La segunda significa que el cuerpo del bucle (es decir, la instrucción S ) debe preservar el invariante y reducir el variante;
- La última significa que la postcondición del bucle R debe establecerse cuando el bucle finaliza.
Sin embargo, la conjunción de esos tres no es una condición necesaria. Exactamente, tenemos
Comandos protegidos no deterministas
En realidad, el lenguaje de comandos protegidos (GCL) de Dijkstra es una extensión del lenguaje imperativo simple presentado hasta ahora con enunciados no deterministas. De hecho, GCL pretende ser una notación formal para definir algoritmos. Los enunciados no deterministas representan opciones que quedan a la implementación real (en un lenguaje de programación efectivo): las propiedades demostradas en los enunciados no deterministas se garantizan para todas las posibles opciones de implementación. En otras palabras, las precondiciones más débiles de los enunciados no deterministas garantizan
- que existe una ejecución que termina (por ejemplo, existe una implementación),
- y que el estado final de toda ejecución que termina satisface la postcondición.
Las definiciones de precondición más débil dadas anteriormente (en particular para el bucle while ) preservan esta propiedad.
Selección
La selección es una generalización de la instrucción if :
Aquí, cuando dos guardiasySi ambas condiciones son verdaderas simultáneamente, entonces la ejecución de esta instrucción puede ejecutar cualquiera de las instrucciones asociadas.o.
Repetición
La repetición es una generalización de la instrucción while de manera similar.
Declaración de especificaciones
El cálculo de refinamiento extiende GCL con la noción de declaración de especificación . Sintácticamente, preferimos escribir una declaración de especificación como
que especifica un cálculo que comienza en un estado que satisface pre y está garantizado que terminará en un estado que satisface post cambiando solo x . Lo llamamosuna constante lógica empleada para ayudar en una especificación. Por ejemplo, podemos especificar un cálculo que incremente x en 1 como
Otro ejemplo es el cálculo de la raíz cuadrada de un número entero.
La declaración de especificación se presenta como una instrucción primitiva en el sentido de que no contiene otras instrucciones. Sin embargo, es muy expresiva, ya que pre y post son predicados arbitrarios. Su precondición más débil es la siguiente.
Combina la idea sintáctica de Morgan con la idea de nitidez de Bijlsma, Matthews y Wiltink. [ 1 ] La principal ventaja de esto es su capacidad para definir wp de goto L y otras sentencias de salto. [ 2 ]
Ir a la instrucción
La formalización de sentencias de salto como goto L requiere un proceso largo y accidentado. Una creencia común parece indicar que la sentencia goto solo podría argumentarse operacionalmente. Esto probablemente se deba a la falta de reconocimiento de que goto L es en realidad milagroso (es decir, no estricto) y no sigue la Ley de Exclusión de Milagros acuñada por Dijkstra, tal como se presenta en sí misma. Pero goza de una visión operacional extremadamente simple desde la perspectiva de la precondición más débil, lo cual fue inesperado. Definimos
Para la ejecución goto L, el control se transfiere a la etiqueta L en la que debe cumplirse la precondición más débil. La forma en que se hace referencia a wpL en la regla no debería ser una gran sorpresa. Es solo para alguna Q calculada hasta ese punto. Esto es como cualquier regla wp, que utiliza sentencias constituyentes para dar definiciones wp, aunque goto L parezca una primitiva. La regla no requiere la unicidad para las ubicaciones donde wpL se cumple dentro de un programa, por lo que teóricamente permite que la misma etiqueta aparezca en múltiples ubicaciones siempre que la precondición más débil en cada ubicación sea la misma wpL. La sentencia goto puede saltar a cualquiera de dichas ubicaciones. Esto justifica que podríamos colocar las mismas etiquetas en la misma ubicación varias veces, ya que , que es lo mismo que Además , no implica ninguna regla de ámbito, lo que permite, por ejemplo, un salto dentro del cuerpo de un bucle. Calculemos wp del siguiente programa S, que tiene un salto dentro del cuerpo del bucle.
wp(do x > 0 → L: x := x-1 od; if x < 0 → x := -x; goto L ⫿ x ≥ 0 → skip fi, post) = { reglas de composición y alternancia secuenciales } wp(do x > 0 → L: x := x-1 od, (x<0 ∧ wp(x := -x; goto L, post)) ∨ (x ≥ 0 ∧ post) = { composición secuencial, ir a, reglas de asignación } wp(do x > 0 → L: x := x-1 od, x<0 ∧ wpL(x ← -x) ∨ x≥0 ∧ post) = { regla de repetición } la solución más fuerte de Z: [ Z ≡ x > 0 ∧ wp(L: x := x-1, Z) ∨ x < 0 ∧ wpL(x ← -x) ∨ x=0 ∧ post ] = { regla de asignación, encontrado wpL = Z(x ← x-1) } la solución más fuerte de Z: [ Z ≡ x > 0 ∧ Z(x ← x-1) ∨ x < 0 ∧ Z(x ← x-1) (x ← -x) ∨ x=0 ∧ post] = { sustitución } la solución más fuerte de Z:[ Z ≡ x > 0 ∧ Z(x ← x-1) ∨ x < 0 ∧ Z(x ← -x-1) ∨ x=0 ∧ post ] = { resolver la ecuación por aproximación } post(x ← 0)Por lo tanto,
wp(S, post) = post(x ← 0).
Otros transformadores de predicados
Precondición liberal más débil
Una variante importante de la condición previa más débil es la condición previa liberal más débil., que produce la condición más débil bajo la cual S no termina o establece R. Por lo tanto, difiere de wp en que no garantiza la terminación. De ahí que corresponda a la lógica de Hoare en corrección parcial: para el lenguaje de sentencias dado anteriormente, wlp difiere de wp solo en el bucle while , en que no requiere una variante (ver más arriba).
Postacondicionamiento más fuerte
Dado S una proposición y R una precondición (un predicado sobre el estado inicial), entonces es su postcondición más fuerte : implica cualquier postcondición satisfecha por el estado final de cualquier ejecución de S, para cualquier estado inicial que satisfaga R. En otras palabras, una tripleta de Hoarees demostrable en lógica de Hoare si y solo si se cumple el predicado siguiente:
Por lo general, las postcondiciones más fuertes se utilizan en la corrección parcial. Por lo tanto, tenemos la siguiente relación entre las precondiciones liberales más débiles y las postcondiciones más fuertes:
Por ejemplo, en la tarea tenemos:
Arriba, la variable lógica y representa el valor inicial de la variable x . Por lo tanto,
En la secuencia, parece que sp avanza (mientras que wp retrocede):
transformadores de predicados de victoria y pecado
Leslie Lamport ha sugerido win y sin como transformadores de predicados para la programación concurrente . [ 3 ]
Propiedades de los transformadores de predicados
Esta sección presenta algunas propiedades características de los transformadores de predicados. [ 4 ] A continuación, S denota un transformador de predicados (una función entre dos predicados en el espacio de estados) y P un predicado. Por ejemplo, S(P) puede denotar wp(S,P) o sp(S,P) . Mantenemos x como la variable del espacio de estados.
Monótono
Los transformadores de predicados de interés ( wp , wlp y sp ) son monótonos . Un transformador de predicados S es monótono si y solo si:
Esta propiedad está relacionada con la regla de consecuencia de la lógica de Hoare .
Estricto
Un transformador de predicados S es estricto si y solo si:
Por ejemplo, wp se hace artificialmente estricto, mientras que wlp generalmente no lo es. En particular, si la instrucción S no puede terminar entonces es satisfactorio. Tenemos
En efecto, T es un invariante válido de ese bucle.
Los transformadores de predicados no estrictos pero monótonos o conjuntivos se denominan milagrosos y también pueden usarse para definir una clase de construcciones de programación, en particular, las sentencias de salto, que a Dijkstra le importaban menos. Estas sentencias de salto incluyen goto L directo, break y continue en un bucle y sentencias return en el cuerpo de un procedimiento, manejo de excepciones, etc. Resulta que todas las sentencias de salto son milagrosos ejecutables, [ 5 ] es decir, pueden implementarse pero no son estrictas.
Terminando
Un transformador de predicados S termina si:
En realidad, esta terminología solo tiene sentido para los transformadores de predicados estrictos: de hecho,es la condición previa más débil que garantiza la terminación de S.
Parece más apropiado denominar a esta propiedad "no abortiva" : en su corrección total, la no terminación es aborto, mientras que en su corrección parcial, no lo es.
Conjuntivo
Un transformador de predicados S es conjuntivo si y solo si:
Este es el caso de, incluso si la declaración S no es determinista como una declaración de selección o una declaración de especificación.
Disyuntivo
Un transformador de predicados S es disyuntivo si y solo si:
Este no suele ser el caso decuando S no es determinista. De hecho, consideremos una proposición no determinista S que elige un valor booleano arbitrario. Esta proposición se presenta aquí como la siguiente proposición de selección :
Entonces,se reduce a la fórmula.
Por eso,se reduce a la tautología
Mientras que la fórmula reduce a la proposición errónea.
Aplicaciones
- Los cálculos de precondiciones más débiles se utilizan en gran medida para comprobar estáticamente las aserciones en programas que utilizan un demostrador de teoremas (como un solucionador de satisfacibilidad módulo teorías (SMT) o un asistente interactivo de demostración de teoremas ): véase Frama-C o ESC/Java 2.
- A diferencia de muchos otros formalismos semánticos, la semántica de transformadores de predicados no se diseñó como una investigación sobre los fundamentos de la computación. Más bien, su propósito era proporcionar a los programadores una metodología para desarrollar sus programas como "correctos por construcción" en un "estilo de cálculo". Este estilo "de arriba hacia abajo" fue defendido por Dijkstra [ 6 ] y N. Wirth [ 7 ] . R.-J. Back y otros lo formalizaron aún más en el cálculo de refinamiento . Algunas herramientas, como B-Method, ahora proporcionan razonamiento automatizado para promover esta metodología.
- En la metateoría de la lógica de Hoare , las precondiciones más débiles aparecen como una noción clave en la prueba de completitud relativa . [ 8 ]
Más allá de los transformadores de predicados
Precondiciones más débiles y postcondiciones más fuertes de las expresiones imperativas
En la semántica de transformadores de predicados, las expresiones se restringen a los términos de la lógica (véase más arriba). Sin embargo, esta restricción parece demasiado fuerte para la mayoría de los lenguajes de programación existentes, donde las expresiones pueden tener efectos secundarios (llamada a una función con efecto secundario), pueden no terminar o abortar (como la división por cero ). Existen muchas propuestas para extender las precondiciones más débiles o las postcondiciones más fuertes para lenguajes de expresiones imperativas y, en particular, para mónadas .
Entre ellas, la teoría de tipos de Hoare combina la lógica de Hoare para un lenguaje similar a Haskell , la lógica de separación y la teoría de tipos . [ 9 ] Este sistema se implementa como una biblioteca Rocq llamada Ynot . [ 10 ] En este lenguaje, la evaluación de expresiones corresponde a cálculos de postcondiciones más fuertes .
transformadores de predicados probabilísticos
Los transformadores de predicados probabilísticos son una extensión de los transformadores de predicados para programas probabilísticos . Dichos programas tienen muchos usos en criptografía (ocultar información mediante ruido aleatorio) y computación distribuida (ruptura de simetría). [ 11 ]
Véase también
- Semántica axiomática : incluye la semántica de transformadores de predicados.
- Lógica dinámica : donde los transformadores de predicados aparecen como modalidades.
- Semántica formal de los lenguajes de programación : una visión general
Notas
- ↑ Chen, Wei y Udding, Jan Tijmen, "The Specification Statement Refined" WUCS-89-37 (1989). https://openscholarship.wustl.edu/cse_research/749
- ↑ Chen, Wei, "Una caracterización wp de las sentencias de salto", Simposio Internacional de 2021 sobre Aspectos Teóricos de la Ingeniería de Software (TASE), 2021, pp. 15-22. doi: 10.1109/TASE52547.2021.00019.
- ↑ Lamport, Leslie (julio de 1990). " win and sin : Predicate Transformers for Concurrency" . ACM Transactions on Programming Languages and Systems . 12 (3): 396–428 . CiteSeerX 10.1.1.33.90 . doi : 10.1145/78969.78970 . S2CID 209901 .
- ↑ Back, Ralph-Johan; Wright, Joakim (2012) [1978]. Cálculo de refinamiento: una introducción sistemática . Textos en informática. Springer. ISBN 978-1-4612-1674-2.
- ↑ Chen, Wei, "Las sentencias de salida son milagros ejecutables" WUCS-91-53 (1991). https://openscholarship.wustl.edu/cse_research/671
- ↑ Dijkstra, Edsger W. (1968). "Un enfoque constructivo al problema de la corrección de programas". BIT Numerical Mathematics . 8 (3): 174– 186. doi : 10.1007/bf01933419 . S2CID 62224342 .
- ↑ Wirth, N. (abril de 1971). "Desarrollo de programas mediante refinamiento por etapas" (PDF) . Comm. ACM . 14 (4): 221– 7. doi : 10.1145/362575.362577 . hdl : 20.500.11850/80846 . S2CID 13214445 .
- ↑ Un tutorial sobre cómo reflejar en Coq la generación de obligaciones de prueba de Hoare (tutorial sobre lógica de Hoare) : una biblioteca de Rocq (computación) , que proporciona una prueba simple pero formal de que la lógica de Hoare es sólida y completa con respecto a una semántica operacional .
- ↑ Nanevski, Aleksandar; Morrisett, Greg; Birkedal, Lars (septiembre de 2008). "Hoare Type Theory, Polymorphism and Separation" (PDF) . Journal of Functional Programming . 18 ( 5–6 ): 865–911 . doi : 10.1017/S0956796808006953 . S2CID 6956622 .
- ↑ Ynot es una biblioteca de Rocq que implementa la teoría de tipos de Hoare.
- ↑ Morgan, Carroll; McIver, Annabelle ; Seidel, Karen (mayo de 1996). "Probabilistic Predicate Transformers" (PDF) . ACM Transactions on Programming Languages and Systems . 18 (3): 325–353 . CiteSeerX 10.1.1.41.9219 . doi : 10.1145/229542.229547 . S2CID 5812195 .
Referencias
- de Bakker, JW (1980). Teoría matemática de la corrección de programas . Prentice-Hall. ISBN 978-0-13-562132-5.
- Bonsangue, Marcello M.; Kok, Joost N. (noviembre de 1994). "El cálculo de precondiciones más débiles: recursión y dualidad". Aspectos formales de la computación . 6 (6): 788– 800. CiteSeerX 10.1.1.27.8491 . doi : 10.1007/BF01213603 . S2CID 40323488 .
- Dijkstra, Edsger W. (agosto de 1975). "Comandos protegidos, indeterminación y derivación formal de programas" . Comm. ACM . 18 (8): 453–7 . doi : 10.1145/360933.360975 . S2CID 1679242 .
- Dijkstra, Edsger W. (1976). Una disciplina de programación . Prentice Hall. ISBN 978-0-613-92411-5.– Una introducción sistemática a una versión del lenguaje de comandos protegidos con muchos ejemplos resueltos.
- Dijkstra, Edsger W.; Scholten, Carel S. (1990). Cálculo de predicados y semántica de programas . Textos y Monografías en Informática. Springer-Verlag. ISBN 978-0-387-96957-2.– Un tratamiento más abstracto, formal y definitivo
- Gries, David (1981). La ciencia de la programación . Springer-Verlag. ISBN 978-0-387-96480-5.
!-- Categorías ocultas a continuación -->
- Métodos formales
- Lógica del programa
- Edsger W. Dijkstra