domingo, 26 de agosto de 2007

Definiciones básicas

Estuve escribiendo definiciones básicas a partir de las cuales formalizar algunas de las cosas que estuvimos haciendo.

Por ahora tengo:
  • Sintaxis básica del lenguaje Pest:
    • Expresiones.
    • Términos.
    • Predicados.
    • Parámetros.
    • Sentencias (sin incluir map, find, for).
    • Procedimientos.
    • Programas.
  • Concepto de expresión válida, término válido, ..., programa válido.
  • Semántica operacional para un programa. Esto requiere definir semántica para los predicados, los términos, las expresiones.
Con todo ya suman más o menos 11 páginas de definiciones.

Faltan explicaciones que complementen las definiciones formales. Pero hasta que no esté seguro de qué cosas quedan y qué cosas cambian no tiene sentido invertir tiempo en eso.

viernes, 24 de agosto de 2007

Escribiendo

Después de varios meses programando estuve por fin escribiendo un poco el documento final. Formalizando, decidiendo algunas cosas de formato, etc.

Además estuve muy colgado porque el jueves amanecí con fiebre. Por suerte ahora ya estoy mejor y con pilas.

Con respecto a la imple simplemente corregí algún que otro bug.

domingo, 19 de agosto de 2007

Buenas y malas

(Copiado de un mail a mis directores)

Las buenas:
- Ahora PEST tiene "For" (for var from low to high do {...}) que no necesitan de proveer invariante y tampoco variante.

- Me maté programando y cambie casi toda la estructura que usaba para almacenar las VC's. ahora se hace en dos pasadas:

1) se recorre el programa PEST de arriba hacia abajo haciendo dynamic single assignment. Se obtiene algo que llamo "lenguaje intermedio" que sería similar a boogie: tiene assume, assert, if, lemma (para simular el assume false de boogie).

El lenguaje intermedio también tiene una construccion especial llamada "For" que, como su nombre lo indica, representa de forma temporaria los For's no resueltos del lenguaje Pest. o sea, durante la primera pasada no se generan VC's para la correctitud del For, solamente se generan para la correctitud de su cuerpo (recursivamente).

2) Se recorre el lenguaje intermedio de ABAJO hacia arriba para remover los For's no resueltos. Esto permite que en cada paso ya tener la cola resuelta, es decir con todos sus For's reemplazados por lemmas que deberían probar que son correctos.

En cada paso que se encuentra un For se calcula la wp de la cola (que como no tiene for's, se puede obtener tranquilamente). Se la debilita y se usa eso como invariante. Es decir: se pregunta si vale antes de entrar, si se preserva y se asume al final, una vez terminado el for.

Una vez eliminado el For, se reemplaza por un lema muy similar a lo que hubiera quedado si en vez de un For era un While común (con invariante, etc.). La diferencia es que no es necesario ver la terminación, está garantizada por la estructura misma.

- Esto lo probé únicamente en el caso para calcular el máximo de un arreglo y parece funcionar. Pero quiero probarlo en casos donde haya código entre el fin del for y el fin del procedimiento, de manera tal de tener que calcular una wp más compleja que simplemente la postcondicion del procedimiento.

- Otros cambios pequeños: ahora PEST tiene como nativos comandos assume y assert. yo no los dejaría en el lenguaje final, pero para testear cosas son útiles. esta caracteristica, junto con los procedimientos hizo que los bloques con pre y post sean obsoletos, así que los saqué.

Las malas:

Al cambiar la estructura necesité retocar bastante fuertemente la forma en la que trabajo con predicados internamente. Para calcular wp's necesito a veces cuantificar arreglos y ahora los arreglos son ciudadanos de primer nivel en los predicados. Es decir un store sobre un arreglo es un término. Y todo eso los provers de primer orden no lo soportan así que temporariamente los desconecté.

Se me ocurre que con algún tipo de preproceso a los predicados se pueden eliminar las cuantificaciones de arreglos (esto no se puede hacer en el caso general, pero la pinta de las cuantificaciones que aparecen parecería ser simple). Y cambiar los update terms por renombres y axiomas que digan como se relacionan.

Pero considerando que los provers de primer orden no habían aportado nada (o sea, no encontré ningún caso donde puedan probar algo que los SMT solvers no pudieran, sino más bien todo lo contrario) por ahora no quiero invertir tiempo en hacer toda esta traducción que parece ser nada trivial.

Pero por ahora me parece más interesante ver qué potencia y limitaciones tiene nuestro brand-new For y el cálculo de wp's.

miércoles, 15 de agosto de 2007

Varias cosas nuevas

Entre ayer y hoy implementé varias cosas interesantes:
  • Los dos patrones de iteración que tengo por ahora son map y find. Ambos ahora aceptan cotas opciones sobre el ranto de operación. Por ejemplo:
    • map e in a[..k..10] { ... }
    • find first x in a[j..k..i+1] { ... }
  • Ahora find también soporta búsqueda desde atrás.
    • find first ...
    • find last ...
  • Se pueden crear arreglos en cualquier punto, así como antes se podían crear variables.
    • local b[|a| - 10] <- .. a[0] ..
      • inicializa un arreglo de tamaño |a|-10 con todos elementos iguales a a[0]
  • Diseñé una clase genérica ProverOrchestrator que permite implementar distintas estrategias para combinar provers. Por ahora hay dos estrategias:
    • Simple: usar un prover en particular, si anda anda, si no no.
    • Lista: usar una serie de provers en un orden prefijado. Mientras la respuesta sea unknown se va pasando al siguiente.
Con esta segunda estrategia pude demostrar que bubbleSort es correcto y preserva los elementos en el caso de arreglos sin repetidos.

martes, 14 de agosto de 2007

Map y Find

Hice algunos cambios:
  • Ahora multiassign se llama map, es un poco más marketinero.
  • Modularice un poquito la semántica de (ahora llamado) map.
  • No se generan nombres nuevos para las variables al entrar a un if. En cambio se espera a que sean modificadas por primera vez para hacerlo.
  • Rompí un poco la estructura lineal de los Proofplans, de esta manera se pueden ir olvidando las cosas que se probaron dentro de un lema, dejando sólamente la conclusión de ese lema, para evitar enviarle al prover axiomas que no usará.
  • Ahora los procedimientos deben indicar explícitamente que parámetros tocan. Esto genera chequeos sintácticos que prohiben la asignación sobre los mismos. Esto permite usar procedimientos dentro de los bloques que de map (y otras construcciones de alto nivel) que restringen qué cosas se pueden tocar.
También implementé una nueva construcción, llamada find first. Más tarde los detalles.

domingo, 12 de agosto de 2007

Procedimientos

Hoy implementé los detalles que faltaban para el soporte de procedimientos. Ahora se puede utilizar la sentencia:

nombre(p1,...,pn)

La semántica de pasaje de parámetros es la siguiente:
  • Si un parámetro es de tipo arreglo, entonces se espera un arreglo, denotado nombre_arreglo[]
  • Si un parámetro es de tipo entero, se espera una variable entera.
  • Adicionalmente, cuando un parámetro es de tipo entero, se puede esperar una expresión como por ejemplo un número entero. La misma es evaluada y pasada como parámetro. La salida de ese parámetro no es observable.
Dado que todos los parámetros se manejan como inout, o referencias, y no queremos generar aliasing, se espera que todos los parámetros sean distintos entre si.

Un día de estos tengo que implementar un chequeo que restrinja todo tipo de recursividad. Para eso hay que construir un grafo de llamados y ver que no tenga ciclos.

sábado, 11 de agosto de 2007

Multiassign, (casi) procedimientos

Entre ayer y hoy implementé la primer estructura de iteración de alto nivel. Es algo así:

for e in a[..k..] {
e <- e + k - |a|
}

La semántica es ejecutar el bloque de código reemplazando a "e" por cada uno de los elementos en el arreglo "a". Este bloque no puede leer directamente elementos de "a" (sólo puede hacerlo mediante la variable "e"). Tampoco puede modificar variables (a excepción de "e" y cualquier otra variable local que se cree dentro del mismo bloque).

Esta estructura permite simplificar muchísimo la escritura y verificación de programas como: resetear un arreglo a 0, poner números de 1...N en un arreglo, poner números de N...1 en un arreglo, etc.

Por otra parte estuve empezando a implementar procedimientos. Esto está incompleto, cuando lo tenga andando comento los detalles.

jueves, 9 de agosto de 2007

Inferencia de postcondiciones

Hoy implementé una versión básica de inferencia de postcondiciones. Esto es necesario para poder contar con estructuras de iteración relativamente piolas como por ejemplo la asignación simultánea. Todavía hay varias cosas que pulir.

También estoy cada vez más seguro de que necesito una capa extra de abstracción entre los predicados que utilizo y los provers. Esto puede ser un poco denso de implementar pero hay varios indicios que marcan que sería el camino correcto a seguir, aunque por ahora (mientras no me trabe) es algo que voy a patear...

miércoles, 8 de agosto de 2007

Plan

Nos juntamos con Diego y Dani. Charlamos de que venimos avanzando bastante bien y que podemos llegar a que me reciba en noviembre. Por supuesto que para eso hay que meterle porque faltan cerrar algunas cosas y además escribir todo.

De lo que falta hacer (en orden de prioridad) están las siguientes cosas:
  • Implementar la idea de patrones de iteración que tienen un invariante conocido. De la mano de esto hay que buscar ejemplos donde estos patrones tienen sentido y evitan la escritura de un invariante potencialmente engorroso.
  • Estrategias para elegir qué prover usar. Esto involucra probar varios demostradores distintos sobre cada fórmula, hasta que alguno pueda verificar la propiedad.
  • Procedimientos.
  • Syntax sugar para cuatificación más cómoda sobre elementos de arreglos, etc.
Además está la idea de escribir la tesis en inglés así ya se puede reutilizar una parte para armar algún artículo y presentarlo.

Esto hace que la idea de armar un plugin de eclipse quede postergada para después de que me reciba.

martes, 7 de agosto de 2007

Avanzo en mi TODO list

De mi lista del post anterior pude implementar hablar con provers de primer orden y verificar accesos a arreglos son en rango.

Mañana tenemos con Diego y Dani una reunión donde definir un poco mejor cómo seguimos, de todas formas algunas cosas que quiero hacer en estos días son:

  • cambiar la estructura de iteración
  • inferir postcondiciones
  • procedimientos
  • plugin de eclipse, basado en el código fuente del plugin de javaCC
Una buena nueva es que pude demostrar la corrección de bubblesort, antes no podía porque un invariante tenía un error. Y ahora estoy tratando de demostrar el hecho de que el arreglo es permutación del original (asumiendo que no hay repetidos).

viernes, 3 de agosto de 2007

BubbleSort, TODO

Hoy programé un BubbleSort y casi casi lo verifico completo. De 38 VC's pude verificar 37.

Tengo que revisar, quizás algún invariante está un poco débil.

También tengo una pequeña lista de cosas interesantes para hacer con respecto a la implementación:
  • hablar con first-order provers
  • verificar que los accesos a arreglos siempre son correctos
  • inferir postcondiciones
  • inferir precondiciones (wp)
  • más benchmarks
  • procedimientos
  • construcciones de alto nivel (foreach, acum, select, etc.)
  • ¿plugin de eclipse?

Arrays

Estuve aumentando el lenguaje PEST para que pueda hablar de arreglos. Además, ya que estaba tocando el parser, mejoré la sintaxis de expresiones para que se puedan escribir cosas complejas en una misma sentencia como:

x <- a[i] + 3*i


Por otra parte reimplementé el output a SMT-lib porque la traducción que ofrecía CVC era muy mala para lidiar con operadores aritméticos no lineales.

Para poder soportar aritmética no lineal en Z3 y Yices lo que hice fue crear operadores no interpretados para la suma y la división. La idea es axiomatizarlos lo más posible (sin que pinche) y demostrar algunas cosas... que siempre es mejor que nada.

Con todo esto pude demostrar la corrección de programas como el máximo de un arreglo, el arreglo 1...N, incrementar en 1 cada posición de un arreglo, ver si un arreglo está ordenado, etc.