Presentaciones de teoría de la asignatura “Especificación y Desarrollo de Sistemas de Software” Grado en Matemáticas y Grado en Ingeniería Informática Ana Romero Ibáñez Universidad de La Rioja Curso 2011/2012 Todo este material está disponible en la página web: www.unirioja.es/cu/anromero/edss.html Índice Tema 1 - Abstracción y formalismo en Programación……………… 3 Tema 2 - Especificación/Implementación de tipos de datos……….21 Tema 3 - Tipos abstractos y orientación a objetos………………….57 Tema 4 - Especificación de algoritmos……………………………….77 Tema 5 - Sintaxis y semántica de un lenguaje imperativo sencillo…………………………………………100 Tema 6 - Nociones sobre eficiencia. Verificación formal de la corrección de algoritmos……………………132 Tema 1: Introducción. Abstracción y formalismo en Programación Especificación y Desarrollo de Sistemas de Software Universidad de La Rioja Ana Romero Ibáñez Programa de la asignatura Introducción: "Abstracción y formalismo en Programación". Especificación/Implementación de tipos de datos. Tipos abstractos y orientación a objetos. Especificación de algoritmos. Sintaxis y semántica de un lenguaje imperativo sencillo. Nociones sobre eficiencia. Verificación formal de la corrección de algoritmos. Métodos formales y abstracción en Programación 2 Proceso de abstracción Destacar algunos aspectos relevantes del objeto de estudio Ignorar detalles no relevantes Objetivo: obtener una visión más simple y formal del objeto de estudio (generalmente proporciona un conocimiento más profundo del mismo). 3 Proceso de abstracción 4 Abstracción en Programación Programación: tarea compleja y altamente proclive a errores, difícil de depurar, costoso de modificar. A partir de la crisis del software (60’s, 70’s), se empiezan a introducir algunas técnicas y métodos de corte formal (por ejemplo formalismos matemáticos). Uso de métodos formales para definir objetos (datos) y procesos (acciones). 5 Abstracción a nivel de acciones Lenguajes de alto nivel frente a lenguaje máquina o ensamblador. Subalgoritmos. Especificación, cabeceras, interfaces. Programación funcional y programación lógica. Derivación automática de código. Esquemas algorítmicos, patrones. 6 Abstracción a nivel de datos Tipos predefinidos. Constructores de estructuras. Especificación de tipos, tipo abstracto. Mecanismos de ocultación de información y de encapsulamiento. Clases, parametrización, polimorfismo. 7 Abstracción en Programación 8 Abstracción en Programación “La historia de la Programación es un camino hacia un grado creciente de abstracción, que se usa como un mecanismo para disminuir la complejidad”. 9 Abstracción a nivel de datos Es deseable poder manejar los tipos definidos por el programador igual que los predefinidos: Definir y crear variables del tipo Manipular los datos con las operaciones definidas Conocer su comportamiento 10 Primera aproximación a la noción de Tipo Abstracto de Datos Un Tipo Abstracto de Datos (TAD) consta de uno o varios conjuntos (dominios del tipo) y un conjunto de funciones entre dichos conjuntos (operaciones del tipo) definidos mediante una especificación sin hacer referencia a ningún detalle de implementación. 11 Primera aproximación a la noción de Tipo Abstracto de Datos Para implementar un tipo de datos habrá que dar: Una representación de los datos de los dominios. Programas que implementen las operaciones. 12 Especificación frente a implementación Especificación: ¿QUÉ? Implementación: ¿CÓMO? EXTERIOR (abstracto) Dominio INTERIOR (concreto) Representación de los datos (instancias del tipo) + Datos Programas que implementan las operaciones 13 Especificación frente a implementación El usuario sólo debe conocer la “capa externa” (especificación). El programador debe preocuparse de las dos capas: Tener bien especificado el tipo y bien descrito su comportamiento. Buscar representaciones adecuadas para los dominios y desarrollar programas que implementen las operaciones. 14 Especificación frente a implementación El programador tiene que tener muy clara la función de abstracción: función que determina qué dato externo está representado por cada dato interno. 15 Ejemplo: especificación de pilas de enteros Especificación PILASENTEROS - usa BOOL, ENT // especificaciones previas - géneros pila - operaciones pVacia : pila apilar : pila ent pila (parcial) desapilar : pila pila (parcial) cima : pila ent (parcial) estaVacia : pila bool - propiedades: desapilar(apilar(p,n)) p nm apilar(apilar(p,n),m) apilar(apilar(p,m),n) 16 Ejemplo: implementación de pilas de enteros Una pila de enteros se puede representar mediante una pareja (registro) <v,n> donde v es un vector de enteros y n es un entero ( 0 (visto en Tecnología de la Programación). … v= 17 n= 4 -3 0 8 … Función de abstracción 8 0 -3 17 17 Bibliografía R. Peña. “Diseño de programas: formalismo y abstracción”. Prentice Hall, 1997. 18 Tema 2: Especificación e Implementación de Tipos de Datos Especificación y Desarrollo de Sistemas de Software Universidad de La Rioja Ana Romero Ibáñez Aproximación a la noción de Tipo Abstracto de Datos Un Tipo Abstracto de Datos (TAD) es una colección de valores y de operaciones que se definen mediante una especificación que es independiente de cualquier representación. 2 Aproximación a la noción de Tipo Abstracto de Datos En realidad este concepto es similar a los tipos predefinidos. Ejemplo: Definición del tipo de datos de los enteros en C++/Java valores: los del intervalo [MIN_VALUE,MAX_VALUE] operaciones: +, -, *, /, resto, … propiedades de las operaciones: a+b=b+a, ... No hay que saber nada sobre implementación 3 Aproximación a la noción de Tipo Abstracto de Datos La manipulación de un TAD sólo debe depender de su especificación, nunca de su implementación. Para manipular los enteros nos olvidamos de cómo se representan los valores y de cómo están implementadas las operaciones. 4 Aproximación a la noción de Tipo Abstracto de Datos De este modo conseguiremos: Privacidad: los usuarios no conocen la representación de los valores. Protección: sólo se pueden utilizar las operaciones definidas en la especificación. En particular, el conjunto de operaciones ha de permitir generar cualquier valor del tipo. 5 Aproximación a la noción de Tipo Abstracto de Datos Dada una especificación de TAD hay muchas implementaciones válidas. Un cambio de implementación de un TAD es transparente a los programas que lo utilizan. 6 Aproximación a la noción de Tipo Abstracto de Datos El programador debe crear: Especificación: dominios + operaciones + comportamiento. Implementación: representación de los dominios + implementación de las operaciones en términos de la representación dada. 7 Aproximación a la noción de Tipo Abstracto de Datos Abstracción: Se destacan los detalles de la especificación (el comportamiento observable del tipo, qué hace). Se ocultan los detalles de la implementación (cómo lo hace). 8 Especificación de tipos de datos El documento de especificación de un tipo de datos debe contener el interfaz del tipo (nombre y cabecera de los operadores) y una descripción del comportamiento (significado) de esos operadores, sin ninguna referencia a detalles de implementación. La idea es que la especificación de un tipo de datos debe servir para determinar un “modelo abstracto” externo que corresponda al comportamiento deseado. 9 Especificación de tipos de datos Tanto para dar la especificación como para determinar el modelo usaremos herramientas del “mundo de las matemáticas”. 10 Especificación de tipos de datos Una especificación constará de: Nombres de los dominios del tipo. Nombres y cabeceras de los operadores. Comportamiento esperado de las dos partes anteriores. 11 Especificación de tipos de datos Formalizando lo anterior: Definición : Una signatura está formada por dos conjuntos S, . El primero de ellos se denomina conjunto de géneros de la signatura, y el segundo se denomina conjunto de operadores. Cada operador lleva asociado además una secuencia no vacía de géneros (cabecera del operador). 12 Especificación de tipos de datos Signatura de pilas p S p , p Sp a, e, b vac : a; op1 : a e a p op2 : a a; op3 : a e op 4 : a b ¡OJO! Sólo se trata de símbolos (sintaxis). Falta dar significado a lo anterior. 13 Especificación de tipos de datos Definición : dada una signatura S, , un álgebra o modelo Α para consta de : - Para cada género g S, un conjunto A g ( soporte para el género g). - Para cada operación w ,w : g1 ... gk g, una función w : A g1 A gk A g (interpretación del operador w en Α). Α (A g )gS , (w )w 14 Especificación de tipos de datos En el ejemplo de la signatura de pilas, un álgebra puede ser: a={pilas de enteros}= e= (enteros) b= (booleanos) vac=pVacia: op1=apilar: x ((x1,…xk),n) (x1,…xk,n) op2=desapilar: (x1,…xk) con k (x1,…xk-1) op3=cima: (x1,…xk) con k xk op4=estaVacia: (x1,…xk)0 si k=0, 1 en otro caso 15 Especificación de tipos de datos Otro modelo para p puede ser: a={colas de enteros}= e= (enteros) b= (booleanos) vac=cVacia: op1=encolar: x op2=desencolar: op3=primero: op4=estaVacia: 16 Especificación de tipos de datos Más ejemplos: Signatura + modelo(s) para las listas con posición. Signatura + modelo(s) para los naturales. Signatura + modelo(s) para los booleanos. Signatura + modelo(s) para las fichas de dominó. 17 Especificación de tipos de datos s o t a D e d o t c a r t s b A o p i T Definición : Un (TAD) está formado por una signatura S , y una clase (" familia" ) de modelos de . 18 Especificación de tipos de datos Problemas: Pocas veces podemos dar una descripción precisa de un modelo. Lo habitual es utilizar algún tipo de técnica de definición en matemáticas para dar la clase de modelos. La más usada es la especificación algebraica (ecuacional). 19 Especificación de tipos de datos Definición : Una Especificación Algebraica es una pareja E ( , Ec ) donde es una signatura y Ec es un conjunto de " ecuaciones" sobre los géneros y operaciones de . 20 Especificación de tipos de datos Distintas formas de dar significado a una especificación: Todos los modelos de la signatura que satisfacen las ecuaciones. Modelo inicial: Generado por las operaciones (sin basura). Las únicas propiedades que se cumplen son las ecuaciones y los teoremas que se deducen de ellas. 21 Especificación de tipos de datos Nuestra forma de especificar será semiformal: Seremos rígidos al escribir las signaturas. Para el comportamiento nos basaremos en modelos conocidos, de la forma más precisa posible. Nuestras especificaciones no serán válidas para probar la corrección de programas que utilicen el TAD. 22 Especificación de tipos de datos Ejemplo: conjuntos finitos de enteros Especificación CONJENTEROS usa ENTERO, BOOL géneros conj operaciones vacío : conj estáVacio : conj bool pertenece : conj ent bool unión : conj conj conj intersección : conj conj conj eliminar : conj ent conj cardinal : conj ent atomo : ent conj 23 Especificación de tipos de datos Ejemplo: conjuntos finitos de enteros comportamiento “Responde al modelo de los conjuntos finitos de enteros”. finEsp 24 Especificación de tipos de datos Ejercicios: Dar una especificación para: Las cadenas (finitas) de caracteres. Los números racionales. Polinomios con coeficientes enteros. Tabla de frecuencias absolutas. 25 Especificación de tipos de datos Ejercicios: Dar una especificación para: Agenda personal (fecha, hora y tarea). Ventas discográficas (utilizando tipos para autores y discos). Baraja de cartas española. 26 Implementación de tipos de datos El usuario (los programas) que utilizan un tipo de datos sólo se fijan en la especificación. Se supone que la realización de ese tipo en la máquina satisface la especificación (responde al comportamiento que se fija en ella). 27 Implementación de tipos de datos Implementación de un TAD: Representación: representar los datos de los dominios en términos de datos de tipos “más concretos”, que se suponen ya implementados. Operadores: dar programas que implementen los operadores (basados en operadores de los “tipos concretos” de la representación) que sean coherentes con el comportamiento esperado. 28 Implementación de tipos de datos El esquema es: Modelo A Alto nivel, abstracto Función de abstracción Modelo A’ Bajo nivel, concreto 29 Implementación de tipos de datos Función de abstracción: : Modelo A’ Modelo A “Modelo de bajo nivel” “Modelo abstracto” Ejemplo: representación de pilas de enteros … v= 17 n= 4 -3 0 8 … 8 0 -3 17 30 Implementación de tipos de datos Ejemplo: implementar los conjuntos finitos de enteros (con operaciones vacío, estáVacio, pertenece, unión, intersección, eliminar, cardinal, átomo). Implementación 1: Representación: v vector de enteros v , n con n número entero positivo (puede haber repetidos) 31 Implementación de tipos de datos Función de abstracción: 1 k Ζ i 1,..., n tq v [i ] k v , n ¿Implementación de los operadores? Implementación 2: Representación: v , n con n 0 y sin repetidos Función de abstracción: 1 v [1], v[2],..., v[n] v , n ¿Implementación de los operadores? 32 Implementación de tipos de datos La función de abstracción: Puede ser parcial (no tiene que estar definida sobre todos los datos de bajo nivel). Puede no ser sobreyectiva. Puede no ser inyectiva. Debe “conmutar con los operadores”. 33 Implementación de tipos de datos Ejercicios: especificar (sólo signatura) y diseñar implementaciones para: pilas y colas listas de enteros con posición doble colas montículos y colas con prioridad 34 Implementación de tipos de datos Ejercicios: especificar (sólo signatura) y diseñar implementaciones para baraja de cartas española cartón de bingo monedero 35 Bibliografía R. Peña. “Diseño de programas: formalismo y abstracción”. Prentice Hall, 1997. R.D. Tennent. “Specifying software”. Cambridge University Press, 2002. 36 Tema 3: Tipos abstractos y orientación a objetos. Especificación y Desarrollo de Sistemas de Software Universidad de La Rioja Ana Romero Ibáñez Contenidos del tema 1. Comentar la importancia de la noción de TAD para la programación a mediana/gran escala. 2. Mostrar mediante ejemplos cómo trasladar especificaciones de TADs a clases Java. 2 Importancia de los TADs La programación con TADs es la base para el diseño modular. La estrategia fundamental para diseñar programas de tamaño medio/grande es la descomposición en módulos (piezas “cuasiindependientes” en que se descompone una aplicación). 3 Importancia de los TADs Requisitos para un módulo: Conexiones sencillas (y pocas) con el resto de módulos. Tamaño razonable. Descomposición que facilite futuras modificaciones y ampliaciones. 4 Importancia de los TADs Un TAD es un buen candidato a módulo: Las conexiones vienen dadas por la especificación (son pocas y sencillas). El tamaño suele ser adecuado (representación + colección de procedimientos y funciones). Se puede cambiar la implementación sin que afecte al funcionamiento de los demás módulos. 5 Importancia de los TADs Los TADs suponen una “generalización natural” del método de los refinamientos sucesivos (añadiendo el refinamiento a nivel de tipos). Idea del método: “deja para mañana lo que puedas hacer hoy” 6 Importancia de los TADs La programación con TADs permite el uso de tipos genéricos (o parametrizados), lo que resulta de gran utilidad para construir programas generales con alto grado de usabilidad (con la flexibilidad que produce la instanciación de los parámetros). 7 Importancia de los TADs Problemas de los TADs: No hay un mecanismo para la inicialización y finalización automática de un tipo dado. No hay una forma sencilla de ampliar una abstracción de datos añadiendo operaciones nuevas. 8 TADs y Prog. Orientada a Objetos Los dos problemas anteriores se solucionaron con la idea de clase, la noción fundamental del paradigma de programación orientada a objetos. POO= TADs + herencia + polimorfismo +… 9 TADs y Prog. Orientada a Objetos ¿Cómo pasar de un TAD a una clase Java? No hay un método que funcione siempre. No hay una solución única. 10 TADs y Prog. Orientada a Objetos Ejemplo 1: (fácil) Especificación EMPLEADO usa CADENA, BOOLEANO, ENTERO género empleado operadores creaEmpleado : cad ent ent empleado nombre : empleado cadena activo : empleado bool sueldo : empleado ent numHijos : empleado ent descuento : empleado ent incrementarSueldo : empleado ent empleado modificarNombre : empleado cad empleado modificarActivo : empleado bool empleado finEspec constructor observadores modificadores 11 TADs y Prog. Orientada a Objetos ¿Cómo sería la versión Java? clase Empleado Empleado (String s, int numHijos, int sueldo) String getNombre ( ) boolean getActivo ( ) int getSueldo ( ) int getNumHijos ( ) int descuento ( ) void incrementarSueldo (int cantidad) void modificarNombre (String cadena) void modificarActivo (boolean estado) constructor observadores modificadores 12 TADs y Prog. Orientada a Objetos Parece que, salvo para el constructor, basta con eliminar los argumentos de tipo empleado en todas las cabeceras. Esto va a ser así en muchos casos, PERO no siempre la transformación es tan directa. 13 TADs y Prog. Orientada a Objetos Ejemplo 2: (no sale tan directo) Especificación LISTACONPOSICION usa NATURAL, BOOLEANO, TELEMENTO género listacp operadores vacía : listacp añadir : listacp telemento nat listacp eliminar : listacp nat listacp elementoEn : listacp nat telemento estaVacia : listacp bool longitud : listacp nat concatenar : listacp listacp listacp finEspec 14 TADs y Prog. Orientada a Objetos ¿Cómo sería la versión Java? clase ListaCP ListaCP ( ) ClaseElemento elementoEn (int posicion) boolean estaVacia ( ) int longitud ( ) void anadir (ClaseElemento e, int posicion) void eliminar (int posicion ) constructor observadores modificadores ¿Y qué hacemos con “concatenar”? 15 TADs y Prog. Orientada a Objetos Varias opciones para “concatenar”: ListaCP concatenar (ListaCP lista1,ListaCP lista2) Método de clase (static) ListaCP concatenar (ListaCP lista) Concatena lista al objeto y devuelve un objeto nuevo void concatenar (ListaCP lista) Método de instancia (cambia el estado del objeto concatenándolo con otra lista) 16 TADs y Prog. Orientada a Objetos Varias opciones para la clase ListaCP: interfaz con una (o varias) clases que lo implementen. El método concatenar no podría ser estático. clase abstracta, con todos los métodos abstractos excepto concatenar (que se puede construir a partir de los anteriores), y una (o varias) clases que extiendan esa clase e implementen los métodos. 17 TADs y Prog. Orientada a Objetos Ejercicios: diseñar la versión orientada a objetos (Java) de los TADs Pila y cola Doble cola Cola con prioridad y montículo 18 TADs y Prog. Orientada a Objetos Ejercicios: diseñar un TAD y pensar en la versión orientada a objetos (Java) de Mesa del juego del dominó Mesa del juego de la guerra Baraja de cartas española Agenda personal 19 Bibliografía R. Peña. “Diseño de programas: formalismo y abstracción”. Prentice Hall, 1997. A. Tucker y R. Noonan. “Lenguajes de programación. Principios y paradigmas”. Mc Graw Hill, 2003. F. Gutiérrez, F. Durán, E. Pimentel. “Programación orientada a objetos con Java”. Thomson, 2007. J. Lewis, J. Chase. “Estructuras de datos con Java. Diseño de estructuras y algoritmos”. Pearson Addison Wesley, 2006. 20 Tema 4: Especificación de algoritmos Especificación y Desarrollo de Sistemas de Software Universidad de La Rioja Ana Romero Ibáñez Algoritmos y programas Un algoritmo es la descripción precisa de una sucesión de instrucciones que permiten llevar a cabo un trabajo en un número finito de pasos. Un buen algoritmo debe ser: correcto, eficiente, reutilizable, fácil de mantener. Un programa es la codificación en un lenguaje de programación concreto de un algoritmo. 2 Algoritmos y programas A la hora de desarrollar un algoritmo, podemos distinguir dos fases: Especificar - ¿Qué hace? (de forma clara y precisa) Implementar - ¿Cómo lo hace? Un buen desarrollador debe garantizar que ambas piezas queden bien separadas. El usuario del programa sólo necesita conocer la especificación (forma de usarlo y significado). 3 Especificación de algoritmos Para especificar un algoritmo podemos usar: Lenguaje natural Lenguaje formal (lógica de predicados) ¿Por qué especificar formalmente? Evitar ambigüedades Poder dar pruebas de corrección (testing no garantiza la corrección). 4 Especif. con lenguaje natural Ejemplo: el siguiente texto pretende “especificar” el problema de la búsqueda en un vector: “Dado un vector y un elemento, decidir si ese elemento está o no en el vector” ( 7 0 -4 23 … , -4) true ( 7 0 -4 23 … , 9) false 5 Especif. con lenguaje natural Problemas: no se concreta tamaño del espacio de búsqueda ¿está ordenado el vector? ¿puede haber repetidos? ¿qué pasa si el vector está vacío? ¿puede haber cambios en los parámetros? … 6 Especificación formal Para escribir especificaciones claras y precisas necesitamos un lenguaje formal, con sintaxis y semántica perfectamente definidos (el lenguaje natural no es adecuado). Usaremos lo que se denomina Especificación Pre/Post. 7 Especificación formal Notación: {Q} s {R} Q (precondición): predicado que servirá para establecer las condiciones que se exigen a los parámetros de entrada. R (postcondición): predicado que establece la relación entre datos y resultados (entradas y las salidas). s será una cabecera de tipo “acción” o “función”: función nombre(x1:t1; ... ; xn:tn) devuelve (y1:t′1; ... ; ym:t′m) acción nombre(ent/sal x1:t1;…; ent/sal xn:tn; ent y1:t’1; ... ; ent ym:t’m) 8 Predicados Un predicado será: 1) una fórmula atómica: o o o o las constantes booleanas, cierto y falso; una variable booleana, b; expresiones aritméticas como 2∗x=y, a>0, i ≤ j... una función matemática conocida, o especificada formalmente, que devuelva un resultado booleano, como primo(x), divide(x,y), vacia(p)… 2) una negación, ¬P, siendo P un predicado. 3) una conjunción, P Q (P AND Q) 9 Predicados Un predicado será: 4) una disyunción, P Q (P OR Q) 5) un condicional P Q 6) un bicondicional P Q 7) un cuantificador universal, x.P(x) 8) un cuantificador existencial, x.P(x) 10 Especificación formal Significado de {Q} s {R}: “siempre que s se ejecuta comenzando en un estado inicial que verifica Q, el algoritmo termina y se alcanza un estado que verifica R” estado inicial . s {Q} s {R} . estado final 11 Especificación formal Si se parte de un estado que no verifica Q, no es posible afirmar qué sucederá (puede no terminar, terminar con un resultado absurdo o terminar de forma razonable). Las variables libres de Q estarán entre los parámetros de entrada y entrada/salida. Las variables libres de R estarán entre los parámetros de entrada, salida y ent/sal. 12 Especificación formal Ejemplo: problema de la búsqueda en un vector Constante MAX=200 Tipo tVector=Vector[1..MAX] de entero {0 n MAX} función está? (v:tVector; n:entero; x:entero) devuelve (b:booleano) {b x{v[1],…,v[n]})} O también: {b i{1..n}.(v[i]=x))} 13 Especificación formal Respuestas a las preguntas no claras en la especificación en lenguaje natural: Espacio de búsqueda: [1..n] En principio no está ordenado el vector. Puede haber repetidos. Admitimos el caso n=0. Devuelve falso. Por ser función, podemos garantizar que no se van a producir cambios sobre los parámetros reales. 14 Especificación formal Ejemplos y ejercicios: Mínimo de dos números enteros { } //Es lo mismo que poner Q true función mínimo (x:entero; y:entero) devuelve (m:entero) {(m x) (m y) ((m=x) (m=y))} O también: {((m=x) (m y)) ((m=y) (m x} Potencia de exponente natural {n 1} función potencia (x:real; n:entero) devuelve (pot:real) n {pot=x ∗ … ∗ x} O también {pot= n x} i 1 15 Especificación formal Cociente y resto de la división de dos números naturales {(divid 0) (divis 0)} función divisiónEntera (divid:entero; divis:entero) devuelve (coc:entero; resto:entero) {(divid=divis ∗ coc + resto) (0 resto divis)} Frecuencia de aparición de un dato en un vector de enteros {0 n MAX} función frecuencia (v:tVector; n:entero; x:entero) devuelve (f:entero) 1 si v [i ] x {f (i ) donde (i ) } v i x 0 si [ ] i 1 n Notación : n f N (v [i ] x) i1 16 Especificación formal Máximo de un vector de enteros {1 n MAX} (pensar por qué n no puede ser igual a 0) función máximoVector (v:tVector; n:entero) devuelve (max:entero) {(i {1..n}.(max v[i])) (i {1..n}.(max=v[i]))} Cambiar en un vector todas las apariciones Se añade en la precondición para cada de un valor por otro parámetro de ent/sal para poder hacer referencia a su valor inicial {(0 n MAX) (v=V)} acción sustituir (ent/sal v:tVector; ent n:entero; ent x:entero; ent y:entero) {(i {1..n}.((V[i]=x v[i]=y) (V[i] x v[i]=V[i]))} 17 Especificación formal Decidir si un vector está ordenado en orden creciente {0 n MAX} función ordenCreciente (v:tVector; n:entero) devuelve (b:booleano) {b (i {1..n-1}.(v[i] v[i+1]))} Ordenar un vector Se añade en la precondición para cada parámetro de ent/sal para poder hacer referencia a su valor inicial {(0 n MAX) (v=V)} acción ordenar (ent/sal v:tVector; ent n:entero) {ordenCreciente(v,n) (i {1..n}.(frecuencia(V,n,V[i])= frecuencia(v,n,V[i])))} 18 Especificación formal Decidir si en un vector de booleanos hay más true que false (usar frecuencia) {0 n MAX} función gananVerdaderos (v:tVector; n:entero) devuelve (b:booleano) {b frecuencia(v,n,true) > frecuencia(v,n,false))} Añadir un dato a un vector {(0 n < MAX) (v=V) (n=N)} acción añadir (ent/sal v:tVector; ent/sal n:entero; ent x:entero) {(n=N+1) (frecuencia(v,n,x)=frecuencia(V,N,x)+1) (i {1..n}.((v[i] x) (frecuencia(v,n,v[i])= frecuencia(V,N,v[i])))} No estoy exigiendo 19 nada sobre el orden Especificación formal Añadir un dato a un vector ordenado {(0 n MAX) ordenCreciente(v,n) (v=V) (n=N)} acción añadirOrd (ent/sal v:tVector; ent/sal n:entero; ent x: entero) {(n=N+1) (frecuencia(v,n,x)=frecuencia(V,N,x)+1) (i {1..n}.((v[i] x) (frecuencia(v,n,v[i])= frecuencia(V,N,v[i]))) ordenCreciente(v,n)} Eliminar todas las apariciones de un dato en un vector No estoy exigiendo nada sobre el orden {0 n MAX (v=V) (n=N)} acción eliminar (ent/sal v:tVector; ent/sal n:entero; ent x:entero) {(n=N-frecuencia(V,N,x)) (frecuencia(v,n,x)=0) (i {1..n}.(frecuencia(v,n,v[i])=frecuencia(V,N,v[i])))} 20 Especificación formal Calcular la imagen especular de un vector. Eliminar de un vector de enteros todas las componentes que superen un determinado valor. Modificar un vector de enteros cambiando cada una de sus componentes por 0 ó 1 según sea par o impar (usar los predicados EsPar y EsImpar). Modificar un vector de enteros duplicando cada una de sus componentes. 21 Especificación formal Dados dos vectores de enteros, decidir si todos los elementos del primero están en el segundo. Dado un vector de enteros, sin elementos repetidos y no vacío, eliminar su máximo. Dados dos vectores de enteros, decidir si uno de ellos es permutación del otro. Dado un vector de enteros ordenado, modificarlo para eliminar todas las componentes negativas (manteniendo el orden). 22 Bibliografía R. Peña. “Diseño de programas: formalismo y abstracción”. Prentice Hall, 1997. R.D. Tennent. “Specifying software”. Cambridge University Press, 2002. 23 Tema 5: Sintaxis y semántica de un lenguaje imperativo sencillo Especificación y Desarrollo de Sistemas de Software Universidad de La Rioja Ana Romero Ibáñez Ideas sobre la corrección En este tema vamos a ver una serie de reglas básicas que nos van a permitir probar la corrección (verificar formalmente) de algunos algoritmos. Un algoritmo con especificación {Q}s{R} será correcto si: siempre que se ejecuta comenzando en un estado que verifica Q, el programa termina y se llega a un estado que satisface R 2 Ideas sobre la corrección El programa estará formado por una secuencia de instrucciones: P s1;…;sn Para dar la corrección de {Q}s{R}, consideramos predicados que determinan los estados válidos en los puntos intermedios del programa, denominados asertos o aserciones. {Q}s1{P1}s2{P2}…{Pn-1}sn{R} 3 Ideas sobre la corrección {Q=P0}s1{P1}s2{P2}…{Pn-1}sn{Pn=R} Si el aserto inicial Q (precondición) se satisface, y cada “programa” elemental sk, consistente en una sola instrucción, satisface su especificación {Pk-1}sk{Pk}, entonces se satisface finalmente la postcondición y el programa es correcto. Necesitamos reglas para decidir si una instrucción elemental s satisface una especificación dada {Q}s{R}. 4 Ideas sobre la corrección Para cada instrucción elemental del lenguaje, daremos una regla o axioma que se usará para probar la corrección de especificaciones básicas donde aparezca esa sentencia. Al conjunto de todos esos axiomas o reglas se le denomina semántica axiomática del lenguaje. 5 Ideas sobre la corrección Las reglas o axiomas tendrán la forma: premisas conclusiones donde las premisas y las conclusiones son predicados o especificaciones de algoritmos. El axioma garantiza que si se cumplen las <premisas> entonces son ciertas las <conclusiones>. 6 Sentencia de asignación Sintaxis: var = expres Semántica: true {R [expres|var] } var = expres {R} r a v Sustituir en R todas las apariciones libres de la variable var por expres. También lo puedo denotar R expres Idea intuitiva: para que al realizar una asignación var = expres se satisfaga un predicado R, antes de hacerla se debe satisfacer el mismo predicado R, pero sustituyendo todas las apariciones libres de var por expres. 7 Sentencia de asignación Ejemplos: Calcular una precondición válida para: {Q}={¿?} x=x+8 {R}={x>10} R[x+8|x] (x+8 >10) (x >2) Solución: Q x > 2 Calcular una precondición válida para: {Q} ={¿?} x=y-3 R[y-3|x] ((z 0) AND ((y<z) OR (y 3))) {R}={(z 0) AND ((y<z) OR (x 0))} Solución: Q z 0) AND ((y<z) OR (y 3)) 8 Sentencia de asignación Calcular una precondición válida para: {Q}={¿?} n=y-1 {R}={ n {1..x} tal que y=2n } Aquí no hay que sustituir nada porque la aparición de la variable n en la postcondición es ligada Solución: Q n {1..x} tal que y=2n 9 Composición secuencial Sintaxis: s1;s2 ó s1 s 2 Semántica: {Q}s1{P} {P}s2{R} {Q}s1;s2{R} Idea intuitiva: si sé que partiendo de un estado que satisface Q, al ejecutar s1 se llega a un estado que verifica P, y que si parto de un estado que verifica P, al realizar s2 se llega a un estado que verifica R, entonces si parto de Q y ejecuto la composición secuencial s1;s2 llegaré a un estado que verifica R. 10 Composición secuencial Ejemplos: Calcular una precondición válida para: {Q}={¿?} y=x+3 x=x-1 {R}={(x<0) AND (x y)} 1) Según el axioma de la asignación para la sentencia x=x-1: P R[x-1|x] R xx-1 ((x<1) AND (x-1 y)) 2) Tomo lo anterior como postcondición para la primera asignación y vuelvo a aplicar el axioma: Solución: Q x<1 Q Pyx 3 ((x<1) AND (x-1 x+3)) x<1) 11 Composición secuencial Calcular una precondición válida para: {Q}={¿?} x=x-5 y=x+3 {R}={(0 x y) AND Par(y)} 1) Axioma de la asignación para la sentencia y=x+3: x 3 P R[x+3|y] Ry ((0 x x+3) AND Par(x+3)) ((0 x) AND Par(x+3)) 2) Vuelvo a aplicar el Axioma para la primera asignación: Q Pxx 5 ((0 x-5) AND Par(x-2)) ((5 x) AND Par(x)) Solución: Q 5 x) AND Par(x) 12 Sentencia condicional Sintaxis: si B entonces sentEnt si_no sentSiNo fsi Semántica: Axioma 1 {B AND Q} sentEnt {R} {(NOT B) AND Q} sentSiNo {R} {Q} si B ………. fsi {R} 13 Sentencia condicional Idea intuitiva del Axioma 1: si somos capaces de encontrar un predicado Q que cumpla que: si se cumple Q y B entonces tras hacer lo que marque la rama entonces se llega a R, y si se cumple Q y NOT B entonces tras hacer lo que marque la rama si_no se llega a R, entonces el axioma garantiza que, si se cumple Q, tras ejecutarse el condicional se llega a R. Problema: necesitamos un predicado Q que nos sirva para las dos ramas del condicional. En la práctica resulta más fácil el siguiente Axioma 2, que es equivalente al anterior. 14 Sentencia condicional Axioma 2 {Q1} sentEnt {R} {Q2} sentSiNo {R} {(Q1 AND B) OR (Q2 AND (NOT B))} si B ………. fsi {R} Idea intuitiva del Axioma 2: Si tenemos una precondición Q1 para la rama entonces y otra Q2 para la rama si_no, podemos tomar {(Q1 AND B) OR (Q2 AND (NOT B))} como precondición del condicional. Queda una precondición complicada, pero es más fácil de calcular que con el Axioma 1. 15 Sentencia condicional Ejemplo: Calcular una precondición válida para: {Q}={¿?} si (x<1) entonces y=x si_no y=y+1 x=x-1 fsi {R}={x y} 1) Rama entonces: {Q1}={¿?} y=x {R}= {x y} Q1 Ryx (x x) true 16 Sentencia condicional 2) Rama si_no: {Q2}={¿?} y=y+1 x=x-1 {R}= {x y} 2 1 y 1 Q2 Py (x-1 y+1) (x y+2) P R xx 1 (x-1 y) Según el Axioma 2, una precondición válida será Q=(Q1 AND B) OR (Q2 AND (NOT B)). En nuestro caso: Q=((x<1) OR ((x y+2) AND (x 1))) 17 Sentencia condicional Ejercicio: Calcular una precondición válida para: {Q}={¿?} si (x<0) entonces x=x+1 si_no x=x-1 fsi {R}={x 0} 18 Condicional degenerado Sintaxis: si B entonces sentEnt fsi Semántica: {Q1} sentEnt {R} {(Q1 AND B) OR (R AND (NOT B))} si … sentEnt fsi {R} 19 Composición iterativa Sintaxis: mientras que B hacer cuerpo fmq Semántica: No es sencillo dar una regla que permita calcular la precondición a partir de la postcondición. Se necesita definir un predicado especial denominado invariante. 20 Composición iterativa: Invariante Invariante: predicado lógico P que tiene la propiedad de ser cierto antes de entrar en el bucle, tras cada iteración y después del bucle. Idea: las variables cambian su valor dentro del bucle, pero se mantienen invariantes ciertas relaciones entre ellas (suele reflejar la idea con la que se ha diseñado el bucle). 21 Composición iterativa: Invariante El invariante P debe cumplir: {P B} cuerpo {P} es decir, si P se cumple y entra en el bucle (se cumple B), tras realizar el “cuerpo del bucle” se vuelve a cumplir P. Si somos capaces de garantizar que el bucle termina, a la salida del bucle se cumplirá {P ¬B}. 22 Composición iterativa Ejemplo: Buscar el invariante del bucle: i=0; q=0; p=1; mientras que (i < n) hacer i=i+1 q=q+p p=p+2 fmq i q p 0 1 2 3 4 5 0 1 4 9 16 25 1 3 5 7 9 11 Invariante: P ((0 ≤ i ≤ n) q=i2 p=2*i+1) (Intuimos que) se cumple {P (i<n)} cuerpo {P} 23 Composición iterativa Ejemplo: Buscar el invariante del bucle (factorial): i=0 f=1 mientras que (i < n) hacer i++ f=f*i fmq i f Iteración 0 1 2 3 4 5 1 1 2 6 24 120 Invariante: P ((0 ≤ i ≤ n) (f=i!)) Al salir se cumple f=n! 24 Composición iterativa ¿Cómo pruebo que P ((0 ≤ i ≤ n) (f=i!)) es un invariante? {P B} i++ f=f*i {P} Tengo una composición secuencial de dos asignaciones. 1) Precondición válida para la primera asignación: H P ff * i ((0 ≤ i ≤ n) (f*i=i!)) 2) Precondición válida para la segunda asignación: Q H ii 1 ((0 ≤ i+1 ≤ n) (f * (i+1)=(i+1)!)) Como P B Q, se cumple {P B} cuerpo {P} 25 Composición iterativa Ejemplo: Buscar el invariante del bucle (búsqueda secuencial): b=falso; i=1 mientras que (i ≤ n) hacer si (v[i]=x) entonces b=cierto fsi i++ fmq P ((b x{v[1],…,v[i-1]}) AND (1 ≤ i ≤ n+1)) ¿Es invariante? 26 Composición iterativa Pruebo que P ((b x{v[1],…,v[i-1]}) AND (1 ≤ i ≤ n+1)) es un invariante: {P B} si (v[i]=x) entonces b=cierto fsi i++ {P} Tengo una composición secuencial de un condicional y una asignación. Precondición para la asignación: i1 H Pi ((b x{v[1],…,v[i]}) AND (1 ≤ i+1 ≤ n+1)) Precondición para la rama entonces: Q1 H bcierto ((cierto x{v[1],…,v[i]}) AND (1 ≤ i+1 ≤ n+1)) 27 Composición iterativa Precondición para la rama si_no: Q2=H Precondición para el condicional: (Q1 AND B) OR (H AND (NOT B)) Q ((x{v[1],…,v[i]}) AND (1 ≤ i+1 ≤ n+1) AND (v[i]=x)) OR ((b x{v[1],…,v[i]}) AND (1 ≤ i+1 ≤ n+1)) AND (v[i] x)) Faltaría ver que P B Q (Q es más débil que P B) 28 Composición iterativa Con la noción de invariante ya podemos dar la semántica (axioma) para la composición iterativa: {P B} cuerpo {P} {P} mientras que B… fmq {P AND (NOT B)} Idea intuitiva: si el predicado P sirve como invariante del bucle, el axioma nos asegura que si llegamos al bucle y se cumple P, a la salida del bucle se cumple P AND (NOT B) Para hacer la corrección de algoritmos habrá que asegurar que el bucle termina (probar que la condición B llega a fallar) 29 Otras estructuras iterativas Nota: Para las estructuras iterativas repetir cuerpo hasta B para i desde E1 hasta E2 hacer cuerpo fpara para i bajando desde E1 hasta E2 hacer cuerpo fpara pueden encontrarse programas equivalentes basados en una estructura “mientras que” (no hace falta dar axiomas). 30 Otros dos axiomas para la semántica Fortalecer la precondición: {Q’}s{R} Q Q’ {Q}s{R} Debilitar la postcondición {Q}s{R’} R’ R {Q}s{R} 31 Bibliografía R. Peña. “Diseño de programas: formalismo y abstracción”. Prentice Hall, 1997. A. Tucker y R. Noonan. “Lenguajes de programación. Principios y paradigmas”. Mc Graw Hill, 2003. 32 Tema 6: Verificación formal de la corrección de algoritmos Especificación y Desarrollo de Sistemas de Software Universidad de La Rioja Ana Romero Ibáñez Corrección de algoritmos n En este tema vamos a hacer pruebas completas de corrección de algoritmos, utilizando las reglas (axiomas) vistos en el Tema 5 para las distintas instrucciones elementales del lenguaje. 2 Corrección de algoritmos n Nos vamos a “limitar” a programas que respondan al siguiente esquema: {Q} <inicializar> mientras que B hacer <cuerpo> fmq devuelve (<var>) {R} 3 Corrección de algoritmos n En realidad esto no supone ninguna restricción: ¡ ¡ Si hay varios bucles “hermanos” puede pensarse que los otros están en <inicializar>. Si hay bucles anidados puede pensarse que los bucles internos están en <cuerpo>. 4 Esquema para la corrección de algoritmos n Según la axiomática, para verificar un programa que tenga el esquema dado hace falta: 1. Encontrar un invariante P para el bucle. 2. Probar que se cumple {Q}<inicializar>{P}. 3. Probar que P es invariante, es decir: {P ∧ B} <cuerpo> {P}. 4. Probar que {P ∧ NOT(B)} es más fuerte que la postcondición {R}. 5. Asegurar que el bucle termina. 5 Ejemplo Potencia de exponente natural: Q ≡ {n ≥ 0} función potencia (x:real; n:entero) devuelve (pot:real) variables i: entero; pot: real principio i=0 pot = 1 mientras que (i<n) hacer pot = pot ∗ x i++ fmq devuelve (pot) fin n ∪ R ≡ {pot=x ∗ … ∗ x} ≡ {pot=xn} 6 Ejemplo 1. Encontrar un invariante P para el bucle: Tomo P ≡ (0 ≤ i ≤ n) AND (pot=xi) 2. Probar que se cumple {Q}<inicializar>{P}: H i0 ≡ (0 ≤ 0 ≤ n) AND (1=x0) ≡ (0 ≤ n) ≡ Q {¿?} 2 1 i=0 1 H ≡ Ppot ≡ (0 ≤ i ≤ n) AND (1=xi) pot=1 {P}= {(0 ≤ i ≤ n) AND (pot=xi)} 4. Probar que {P ∧ NOT(B)} es más fuerte que la postcondición {R}: P ∧ NOT(B) ≡ (0 ≤ i ≤ n) AND (pot=xi) AND (i ≥ n) ≡ (i=n) AND (pot=xi) → (pot=xn ) ≡ R 7 Ejemplo 5. Asegurar que el bucle termina: “La variable i crece y n se mantiene luego i llegará a igualar o superar a n y entonces se saldrá del bucle”. 3. Probar que P es invariante: {P ∧ B} <cuerpo> {P} pot*x {¿?} 2 J ≡ H pot ≡ (0 ≤ i+1 ≤ n) AND (pot*x=xi+1) pot = pot ∗ x i +1 1 H ≡ Pi ≡ (0 ≤ i+1 ≤ n) AND (pot=xi+1) i++ {P} P ∧ B ≡ (0 ≤ i ≤ n) AND (pot=xi) AND (i<n) → J, luego se tiene {P ∧ B} <cuerpo> {P} 8 Ejemplos Especificar, diseñar y probar la corrección de algoritmos que permitan n calcular el factorial de un número natural n decidir si un elemento está o no en un vector (búsqueda secuencial) 9 Ejemplos Especificar, diseñar y probar la corrección de algoritmos que permitan n calcular la raíz cuadrada entera de un número entero positivo n calcular la suma de las componentes de un vector de enteros 10 Bibliografía n n R. Peña. “Diseño de programas: formalismo y abstracción”. Prentice Hall, 1997. A. Tucker y R. Noonan. “Lenguajes de programación. Principios y paradigmas”. Mc Graw Hill, 2003. 11