Download - aed3
Tipos de Dados Abstractos
Fac. Ciências Univ. Lisboa Luis Antunes
Algoritmos e Estruturas de Dados 2010-2011
Hoje
! Especificação da pilha: géneros, assinaturas, domínios das operações.
! Relação entre as operações construtoras e as observadoras.
! Especificação da pilha: axiomas.
! Da especificação para uma classe Java.
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011
Construção e observação
! As especificações definem tipos de dados, chamados géneros (sorts).
! Cada especificação define exactamente um género.
! Vamos definir o género pilha (Stack)
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011
Especificação de um Stack specification sorts Stack constructors make: −−> Stack; push : Stack Element −−> Stack ; observers top: Stack −−>? Element ; pop: Stack −−>? Stack; isEmpty: Stack ; domains S: Stack ; top (S) if not isEmpty (S); pop (S) if not isEmpty (S); axioms S: Stack ; E: Element ; top (push (S, E)) = E; pop (push (S, E)) = S; isEmpty (make ()) ; not isEmpty (push (S, E)); end specification"
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011
! Após sorts, especificamos as assinaturas de todas as operações que a especificação define.
! Por exemplo: ! push: Stack Element à Stack ! afirma que push é o nome de uma operação que requer dois
parâmetros (de géneros Stack e Element) e devolve um valor (de género Stack).
! a especificação de Element tem que ser feita separadamente
! Outro exemplo ! make: à Stack ! Constrói um Stack sem elementos, não requer input
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011
Tipos de operações
! Há 3 secções separadas de operações: ! constructors
! observers
! others
! Constructors: conjunto minimal de operações para construir qualquer valor do género
! Género Stack tem 2 construtores: um para construir um novo Stack, outro para construir um novo Stack dado um Stack e um Element
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011
Observers
! Observers: operações usadas para analisar (dissecar, separar, desconstruir) um dado valor do género.
! Os observers têm que ter pelo menos um parâmetro.
! O primeiro parâmetro tem que ser do género a ser especificado, no exemplo Stack.
! Dois observers: ! top, que devolve o elemento de topo no Stack ! Pop, que devolve o Stack obtido por remoção do
elemento de topo no Stack
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011
Predicates (predicados)
! Predicates são operações usadas não para construir elementos de um sort, mas para avaliar uma condição.
! Como os predicados não devolvem nada, omite-se a seta: ! isEmpty: Stack;
! serve para inquirir se um Stack não contém elementos
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011
Operações parciais ! Nem todas as operações são totais.
! Algumas operações podem não estar definidas para todos os valores possíveis dos parâmetros
! Exemplo: não podemos obter o elemento de topo num Stack vazio.
! Usamos à? a seta de função parcial ! top: Stack −−>? Element ;#
! Definimos para cada função parcial o seu domínio ! domains#
! S: Stack#! top(S) if not isEmpty(S);#
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011
Axiomas
! Axiomas descrevem as dependências entre as diferentes operações.
! Ex: se empilharmos um elemento E num Stack e a seguir examinarmos o topo do Stack temos que ter E.
! Esta secção começa por declarar as variáveis necessárias aos axiomas. Estas são distintas das declaradas para os domínios (âmbito diferente).
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011
Definição de Axiomas
! Nesta secção, é descrita a semântica (i.e., o significado) de cada uma das operações anteriores. ! Esta descrição não deve ser explícita, ou seja, não deve
usar nenhuma representação do objecto (é precisamente isso que queremos evitar). Não nos interessa a estrutura dos resultados.
! A descrição deve ser implícita. Uma descrição implícita é focada nas propriedades relevantes do objecto. Assim, não se diz como devem ser representadas, diz-se o que as eventuais representações devem satisfazer.
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011
Axiomas
! Nos casos simples, precisamos de um axioma por obervador por construtor. ! top(make()) não faz sentido (o domains exclui-o)
! Este ! top (push(S, E)) = E;#! Diz precisamente que E é o topo do Stack onde se
empilhou E
! Outro: ! pop (push(S, E)) = S;#
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011
Mais axiomas
! Mais 2 axiomas para relacionar o observador isEmpty com os construtores make e push. ! isEmpty(make());#
! not isEmpty(push(S,E));#
! O primeiro diz que um Stack acabado de fazer é vazio#
! O segundo diz que é falso que o resultado de empilhar um Element num Stack dado dê um Stack vazio.
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011
Adicionar uma operação Size
! size: Stack à int;#
! O género int é primitivo
! Inclui, por ordem crescente de preferência: ! Dois operadores de igualdade (=, !=) ! Quatro operadores relacionais (<, >, <=, >=) ! Dois operadores aditivos (+, —) ! Três operadores multiplicativos (*, /, %) ! Um operador unário (—)
! E ainda min(_, _) e max(_, _)
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011
Esp. Stack com size specification sorts Stack constructors make: −−> Stack; push : Stack Element −−> Stack ; observers top: Stack −−>? Element ; pop: Stack −−>? Stack; size: Stack --> int; others isEmpty: Stack ; domains S: Stack ; top (S) if not isEmpty (S); pop (S) if not isEmpty (S); axioms S: Stack ; E: Element ; top (push (S, E)) = E; pop (push (S, E)) = S; size(make()) = 0; size(push(S, E)) = 1 + size(S); isEmpty(S) iff size(S)=0; end specification"
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011
Size: que categoria?
! Não é construtor, pois não devolve um Stack
! Como permite observar uma propriedade do Stack (o número de elementos) fica debaixo do título observers.
! Definir o domínio minimal: podemos aplicar size a qualquer Stack? Sim: logo a função é total à
! size está definido para Stacks arbitrários, logo precisamos de tantos axiomas como construtores: ! size (make()) = 0;#! size (push(S, E)) = 1 + size(S);#
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011
Algum observer redundante?
! Podemos definir top em termos de size? Ou pop? Não.
! Mas isEmpty tem relação próxima com size.
! Usamos a categoria others. Em vez de deitar fora o isEmpty, re-classificamo-lo como others, e substituímos os dois axiomas de isEmpty com um só axioma: ! isEmpty(S) iff size(S) = 0;#
! iff ! isEmpty(S) if size(S) = 0;#! not isEmpty(S) if size(S) != 0;#
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011
Observers ou Others?
! size à observers #isEmpty à others#! Axioma mais conciso ! isEmpty(S) iff size(S) = 0;
! size à observers #isEmptyàobservers#! Mas as propriedades dos observers têm que ser expressas
contra os constructors: ! isEmpty(make());#! not isEmpty(push(S,E));#
! isEmpty é uma operação derivada (de size()=0)#
! Então normalmente isEmpty à others
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011
Especificação de Element
! O que se pede ao género (sort) Element?
! Na verdade nada, apenas que exista.
! A especificação de Element pode ser a mais simples possível:
! specification sorts Element end specification"
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011
Funcionalidade vs. Estrutura
! Pelo que foi dito anteriormente: ! A especificação é um método formal que descreve
abstractamente o que o programa deve fazer para ser considerado correcto e não como deve ser feito.
! Do ponto de vista do programador, a especificação representa um conjunto de implementações possíveis (i.e., as funções descritas nos axiomas podem ser computadas por diferentes instruções). ! Ao separar o “o quê” do “como” focam‑se os aspectos
relevantes da especificação, mesmo sem qualquer informação sobre a linguagem a ser utilizada no desenvolvimento. Quem cria a especificação define implicitamente a dimensão desse conjunto de implementações, ficando ao cargo daquele que implementa escolher a mais apropriada.
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011
Módulos (modules)
! O significado dos símbolos externos a uma especificação (ex. O género Element na spc Stack) só fica definido quando a componente está inserida num Módulo.
! Módulo é uma função sobrejectiva de um conjunto de nomes (N) para especificações, de forma a que todos os símbolos (géneros, operações e predicados) tenham uma especificação.
! Uma directoria de ficheiros implicitamente define um módulo, com N o conjunto dos ficheiros com extensão .spc nessa directoria, e as especificações associadas os respectivos conteúdos desses ficheiros.
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011
Das especificações para classes Java ! Já temos uma especificação de Stacks de Elements
! Vejamos agora uma implementação revolucionária:
! public class RevolutionaryStack implements Cloneable { public RevolutionaryStack () {...}; public void push (Object e) {...}; public void pop () {...}; public Object peek () {...}; public int Size () {...}; public boolean empty () {...}; public boolean equals (Object other) {...}; public boolean empty () {...}; public void clone () {...}; ... }#
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011
Verificação
! Suponhamos que queremos verificar que a implementação está conforme à especificação.
! Como relacionar Stack.spc + Element.spc com RevolutionaryStack.java e Object ?
! Mais, dentro delas, como relacionar as operações (eg. pop e top) com os métodos da classe (pop e peek)?
! Isto faz-se no refinement binding
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011
Refinement binding
refinement Element is class Object Stack is class RevolutionaryStack { make: à Stack is RevolutionaryStack(); push: Stack e: Element −−> Stack is void push(Object e) ; pop: Stack à? Stack is void pop(); top: Stack à? Element is Object peek(); isEmpty: Stack is boolean isEmpty(); size: Stack à int is int size (); end refinement
Fac. Ciências Univ. Lisboa
Luis Antunes Algoritmos e Estruturas de Dados 2010-2011