LOG3300. Requis et spécification du logiciel Spécification des types

publicité
LOG3300. Requis et spécification du logiciel
Spécification des types de données abstraits
Alaaeddine Fellah
Sommaire
Spécification algébrique
Signature
Variables et termes
Corps de la spécification
Modèles initiaux
Axiomes conditionnels positifs
Dérivation de systèmes de réécriture
Raffinement d’une spécification
Sommaire
Spécification algébrique
Signature
Variables et termes
Corps de la spécification
Modèles initiaux
Axiomes conditionnels positifs
Dérivation de systèmes de réécriture
Raffinement d’une spécification
Sommaire
Spécification algébrique
Signature
Variables et termes
Corps de la spécification
Modèles initiaux
Axiomes conditionnels positifs
Dérivation de systèmes de réécriture
Raffinement d’une spécification
Sommaire
Spécification algébrique
Signature
Variables et termes
Corps de la spécification
Modèles initiaux
Axiomes conditionnels positifs
Dérivation de systèmes de réécriture
Raffinement d’une spécification
Sommaire
Spécification algébrique
Signature
Variables et termes
Corps de la spécification
Modèles initiaux
Axiomes conditionnels positifs
Dérivation de systèmes de réécriture
Raffinement d’une spécification
Introduction
I Les TDA sont nés de préoccupations de génie logiciel telles que
l’abstraction, l’encapsulation et la vérification de type.
I Les TDA généralisent ainsi les types prédéfinis (ou types simples) :
integer, float, boolean, array, etc.
I Les concepteurs peuvent ainsi définir un nouveau type et les opérations
agissant sur ce type.
I Le but est de gérer un ensemble fini d’éléments dont le nombre n’est
pas fixé a priori. Les éléments de cet ensemble peuvent être de
différentes sortes: nombres entiers ou réels, chaı̂ne de caractères, ou
des données plus complexes.
Introduction
Définitions
I Un TDA est un ensemble de données et d’opérations sur ces données.
I Un TDA est une vue logique (abstraite) d’un ensemble de données,
associée à la spécification des opérations nécessaires à la création, à
l’accès et à la modification de ces données.
I La spécification algébrique d’un type de données abstraits est
caractérisée par :
I
I
I
Son identité
Sa signature
Son corps
Définition
I La signature d’une spécification algébrique est la donnée des
ensembles de base de la spécification ainsi que des opérations définies
sur ces ensembles. Une signature comporte:
I
I
Les noms des sortes (ou types)
Les noms des opérations et de leur profil donné par leur domaine et leur
co-domaine
Définition
Une signature Σ est un ensemble fini de symboles de fonctions (ou
opérateurs) f , g, . . . où chaque symbole f a une arité ar (f ) correspondant à
son nombre d’arguments.
Un symbole de fonction a, b, c, . . . d’arité zéro est appelé constante, un
symbole de fonction d’arité un est appelé unaire et un symbole de fonction
d’arité deux est appelé binaire.
Exemple
AdtString
Interface
Use character, natural, boolean;
Sorts string;
Operations
new:
()
→
string, string
→
append :
character, string →
add to :
#:
string
→
→
isEmpty? : string
= :
string, string
→
first :
string
→
string;
string;
string;
natural;
boolean;
boolean;
character;
Quelques conventions
I Notation préfixe des opérateurs
append : string, string → string;
qui détermine la syntaxe des termes algébriques de la forme:
append x y ou append (x y) ou (append x y)
où x et y sont des termes algébriques de type string générés par la
signature de sting.
I Notation infixe des opérateurs
= : string, string → boolean;
qui détermine la syntaxe des termes algébriques de la forme:
x = y ou (x = y)
où x et y sont des termes algébriques de type string générés par la
signature de sting.
Quelques conventions
I Notation mixte des opérateurs
add to : character, string → string;
qui détermine la syntaxe des termes algébriques de la forme:
add c to append(x y)
où x et y sont des termes algébriques de type char et string
générés par la signature de sting.
Classification des opérateurs
I Les opérations sont classifiés en constructeur, générateur, destructeur,
sélecteur ou observateur.
I Observateur :
#:
isEmpty? :
= :
string
string
string, string
→ natural;
→ boolean;
→ boolean;
I Sélecteur:
first :
string
→ character;
I Générateur:
new:
append :
add to :
()
string, string
character, string
→ string;
→ string;
→ string;
Variables
I On suppose l’existence d’un ensemble infini de variables et qu’elles
sont distinctes de tous les symboles considérés par ailleurs comme les
constantes, les dénotations de fonctions ou de sortes.
I Pour utiliser une variable on a besoin de déclarer ses sortes (types).
Définition
Une affectation de sorte est donc un ensemble de paires ordonnées
variables : sorte dans lequel aucune variable n’a plus d’une sorte.
I Exemple:
x:
string; y:
string; c:
character;
Termes
I On définit l’ensemble des termes algébriques par induction sur les
opérations de la signature, à partir des variables.
Définition
L’ensemble des termes algébriques T(Σ) est le plus petit ensemble tel que
I
I
x : s ∈ T(Σ)
pour chaque x : s dans Γ,
ft1 t2 . . . tn : s ∈ T(Σ),
pour chaque opérateur f : s1 , s2 , . . . , sn → s de Σ et
n-tuple de termes algébriques t1 : s1 , t2 : s2 , . . . , tn : sn de
T(Σ).
Un terme est dit clos ou fermé s’il ne contient pas de variables. On note par
TΣ , l’ensemble des termes clos.
Termes
Exemple
soit f , un symbole de fonction binaire, g, un symbole de fonction unaire et a
une constante alors les termes clos que l’on peut typiquement construire sur
cette signature sont les termes suivants:
1. a 2. f (a, a) 3. g(a) 4. f (f (a, a), f (a, a)) 5. f (f (a, a), g(a)) 6. f (g(a), f (a, a))
7. f (g(a), g(a)) 8. g(f (a, a)) 9. g(g(a)) 10. f (g(f (a, a)), g(g(a))) . . .
Substitution de termes
I La substitution est une opération sur les termes permettant de
remplacer des variables contenues dans un terme par d’autres termes.
I Plus exactement:
Définition
Soit Σ, une signature et x : s ∈ Γ et TΣ . L’opération de substitution dans un
terme t des occurrences de la variable x par le terme u : s, notée t[u/x],
consiste simplement à remplacer toutes les occurrences de x par u dans t.
I On peut définir la substitution par induction sur la structure de u comme
suit:
(ft1 t2 . . . tn )[u/x]
=
y[u/x]
=
ft1 [u/x]t2 [u/x] . . . tn [u/x]
u
y
si y = x
sinon
Substitution de termes
Exemple
Soit f un symbole de fonction binaire et a, b, des constantes alors
I f (x, y )[a/x, b/y ] ≡ f (a, b)
I Il n’y a pas de substitution telle que f (x, x)[u/x] ≡ f (a, b)
I f (x, y )[b/x, b/y , b/z] ≡ f (z, z)[b/x, b/y , b/z]
I Il n’y a pas de substitution telle que g(x)[u/x] ≡ x[u/x]
Axiomatisation
Définition
Une axiomatisation de Σ est un ensemble d’équations bien formées de la
forme t = t 0 où t, t 0 ∈ T(Σ) appelées axiomes. Une équation est bien formée
si le membre de gauche et le membre de droite sont deux termes du même
type.
Exemple
Axioms
isEmpty?(new) = true;
isEmpty?(add c to x) = false;
#(new) = 0;
#(add c to x) = #(x) + 1;
append(x, new) = x
append(x, add c to y) = add c to (append x y);
(new
(add
(new
(add
=
c
=
c
new) = true;
to x = new) = false;
add c to x) = false;
to x = add d to y) = (c = d) and (x = y);
where
x, y: string;
c, d: char;
End String;
La spécification algébrique du type Booleen
AdtBooleans
Interface
Sorts boolean;
Operations
true:
()
false:
()
not :
and :
or :
xor :
= :
boolean
boolean,
boolean,
boolean,
boolean,
→ boolean;
→ boolean;
boolean
boolean
boolean
boolean
→
→
→
→
→
boolean;
boolean;
boolean;
boolean;
boolean;
La spécification algébrique du type Booleen
Body
Axioms
not (true)
not (false)
(true and b)
(false and b)
(true or b)
(false or b)
(false xor b)
(true xor b)
(true = true)
(true = false)
(false = true)
(false = false)
where
b: boolean;
End Booleans;
=
=
=
=
=
=
=
=
=
=
=
=
false;
true;
b;
false;
true;
b;
b;
not(b);
true;
false;
false;
true;
Axiomatisation
Définition
Une axiomatisation sur une signature Σ induit une relation binaire = sur T(Σ)
comme suit:
I Substitution Si t1 = t2 est un axiome alors t1 [u/x] = t2 [u/x].
I Équivalence la relation = est une relation d’équivalence:
I
I
I
t = t pour tout terme t (réflexivité)
si s = t alors t = s (symétrie)
si s = t et t = u alors s = u (transitivité)
I Passage au contexte Si t = u et f ∈ Σ alors
ft1 t2 . . . ti−1 tti+1 . . . tn = ft1 t2 . . . ti−1 uti+1 . . . tn
Axiomatisation
Exemple
Soit a, b, c, des constantes, f un symbole de fonction d’arité 3 avec
l’axiomatisation
fxyz
=
fzxy
fxyz
=
fyxz
fxcy
=
x
alors
I fbca = fbcb car fbca = b = fbcb
I facb = b car facb = fcab = fbca = b
I fcc(fccb) = b car fcc(fccb) = fcc(fbcc) = fccb = fbcc = b
Cohérence vs Complétude
I À partir d’une spécification on peut soit :
1. utiliser un raisonnement équationnel pour dériver d’autres équations entre
les termes ou bien,
2. se demander quelles représentations concrètes de structures de données
implantent cette spécification abstraite.
I Cependant ou doit toujours avoir que :
1. les équations dérivées doivent être satisfaites dans toute implantation de
la spécification. Cette propriété s’appelle la cohérence.
2. Réciproquement, toutes les équations satisfaites dans une implantation de
la spécification doivent être dérivables de la spécification. Cette propriété
s’appelle complétude.
Cohérence vs Complétude
Définition
Soit une signature Σ et un ensemble d’axiomes sur Σ (axiomatisation)
induisant une relation d’égalité = sur T(Σ). Un modèle de la spécification est
donné par un ensemble M et une application φ : TΣ → M.
I (M, φ) est cohérent si s = t implique φ(s) ≡ φ(t), pour tout s, t ∈ TΣ
I (M, φ) est complet si φ(s) ≡ φ(t) implique s = t, pour tout s, t ∈ TΣ
I Intuitivement φ donne une interprétation à chaque terme fermé dans
M. Par exemple, deux modèles possibles de boolean sont
1. Une implémentation correcte de boolean sur un byte.
2. Une implémentation correcte de boolean sur un bit.
Exemple
Exemple
Soit la signature formée d’une constante a et d’un symbole de fonction unaire
f muni de l’axiome f (x) = f (f (x)) alors
Def
I M Def
= {0} et φ(f k (a)) = 0 pour tout k ∈ N est cohérent mais pas
complet
Def
Def
I M Def
= {0, 1}, φ(f 2k (a)) = 0 et φ(f 2k+1 (a)) = 1 pour tout k ∈ N n’est
ni cohérent ni complet
Def
Def
I M Def
= {0, 1}, φ(a) = 0 et φ(f k+1 (a)) = 1 pour tout k ∈ N est
cohérent et complet
Def
I M Def
= N, φ(f k (a)) = k pour tout k ∈ N est complet mais pas cohérent.
Modèle initial
I La relation d’égalité induite par les axiomes est une relation
d’équivalence.
I Par conséquent, elle divise l’ensemble des termes clos TΣ en classes
d’équivalence où les termes clos s et t sont dans la même classe si et
seulement si s = t.
I L’expression [t]] dénote la classe d’équivalence de t c’est-à-dire [s]] = [t]]
si et seulement si s = t.
I L’ensemble {[[t]] : t ∈ TΣ } et l’application φ(t) Def
= [t]] pour tout t ∈ TΣ ,
forme un modèle cohérent et complet pour l’axiomatisation.
I On appelle ce modèle le modèle initial pour l’axiomatisation.
Exemple
Exemple
Soit une spécification des entiers naturels de signature formée de la
constante 0, de la fonction unaire successeur S et des fonctions binaires
addition + et multiplication ·. Leur sémantique est spécifiée par les axiomes
suivants:
1. x + 0 = x
2. x + S(y ) = S(x + y )
3. x · 0 = 0
4. x · S(y ) = (x · y ) + x
Le modèle initial pour cette axiomatisation est composé des classes
[0]], [S(0)]], [S 2 (0)]], [S 3 (0)]], . . . .
où
[0]]
=
{0, 0 · S(0), 0 + 0, 0 + (0 + 0), S(0) · 0, S(S(0)) · 0 · · · }
[S(0)]]
=
{S(0), S(0) · S(0), 0 + S(0), (0 + S(0)) + 0, (S(0) · S(0)) · S(0) · · · }
[S(S((0))]]
=
{S(S(0)), S(0) · S(S(0)), S(0) + S(0), (S(0) + S(0)) + S(0), · · · }
Exemple
Exemple
Soit a, b, des constantes et f un symbole de fonction unaire alors:
I {[[a]], [b]]} est un modèle initial de l’axiomatisation {x = f (x)} pour la
signature {a, b, f }
I {[[a]]} est un modèle initial de l’axiomatisation {x = f (x)} pour la
signature {a, f }
I {[[f k (a)]] : k ∈ N} est un modèle initial de l’axiomatisation vide ∅ pour la
signature {a, f }
Modèle initial
I Étant donnée une axiomatisation pour une signature, les symboles de
fonctions préservent les classes d’équivalence du modèle initial
I Si si = ti alors fs1 s2 . . . sn = ft1 t2 . . . tn pour tout f d’arité n de la
signature.
I Par conséquent [ft1 t2 . . . tn] est entièrement défini par [t1], [t2], . . . [tn]:
[ft1 t2 . . . tn] = f [t1][t2] . . . [tn].
Modèle initial
I Le modèle initial correspond à ce que devrait être une implantation
standard de la spécification.
I Intuitivement, le modèle initial contient seulement les éléments qui sont
minimalement requis.
I Par opposition, un modèle arbitraire de cette spécification pourrait
contenir des éléments en sus.
I De tels éléments sont parfois appelés junk puisqu’ils ne sont pas
définissables par des termes et que par conséquent, ne seront jamais
des valeurs “calculées” dans le modèle.
I Par contre, un modèle qui contiendrait moins d’éléments devrait
identifier des éléments distincts (dont l’égalité n’est pas dérivable).
I Ces modèles créent ce qu’on appelle de la confusion.
I On peut donc résumer les deux propriétés principales des modèles
initiaux : Pas de junk; et Pas de confusion.
Axiomes conditionnels positifs
I Les axiomes conditionnels positifs sont une extensions des équations.
Ce sont des formules de la forme:
t1 = t10 ∧ t2 = t20 ∧ . . . tn = tn0 ⇒ t = t 0 .
I La logique ainsi obtenue, restreinte relativement à la logique du premier
ordre, a l’avantage d’être décidable et de pouvoir aisément se combiner
avec les axiomes par des règles dites de réécriture.
I La liste d’axiomes suivante complète l’axiomatisation de string:
isEmpty?(x) = false ⇒ first(add c to x) = first x;
isEmpty?(x) = true ⇒ first (add c to x) = c;
Spécification des entiers naturels
I Exemple donné dans le fichier entier.pdf
Dérivation d’équations entre termes algébrique
Exemple
succ(0) + succ(succ(0)) = succ(succ(succ(0)))
1.
succ(0) + succ(succ(0)) = succ(0 + succ(succ(0)))
axiome succ(x) + y = succ(x+y) et
substitution avec x=0 et y = succ(succ(0))
2.
0 + succ(succ(0)) = succ(succ(0))
axiome 0 + x = x et
substitution avec x= succ(succ(0))
3.
succ(0 + succ(succ(0))) = succ(succ(succ(0)))
passage au contexte avec succ sur (2)
4.
succ(0) + succ(succ(0)) = succ(succ(succ(0)))
transitivité sur (1) et (3)
Dérivation d’équations entre termes algébrique
I On ne pourrait pas déduire :
succ(succ(succ(0))) − succ(succ(0)) = 0.
I Il est toutefois à remarquer que, par exemple, x − x = 0 n’est pas
déductible des axiomes de natural bien que toutes ses instantiations
fermées e.g.
succ(succ(0)) − succ(succ(0))
=
0 ou
succ(succ(succ(0))) − succ(succ(succ(0)))
=
0
Axiomatisation ω-complète
Définition
Une axiomatisation sur une signature est ω-complète si toute équation s = t
avec s, t ∈ T(Σ) peut être dérivée de l’axiomatisation si toutes ses
instantiations fermées le sont.
Exemple
Pour chacune des trois axiomatisations de l’exemple de l’acétate 29, on a:
I l’axiomatisation {x = f (x)} pour la signature {a, b, f } est ω-complète
I l’axiomatisation {x = f (x)} pour la signature {a, f } n’est pas
ω-complète. Par exemple, x = y n’est pas dérivable bien que toutes
ses instantiations fermées le soient.
I l’axiomatisation vide ∅ pour la signature {a, f } est ω-complète.
Réécriture de termes
Définition
Un système de réécriture de termes est composé d’un ensemble de règles
de la forme s → t avec s, t ∈ T(Σ) où
1. s n’est pas une variable seule;
2. toutes les variables de t sont des variables de s.
I L’idée intuitive est d’orienter les axiomes s = t de la spécifications puis
d’appliquer ces règles de gauche à droite pour réduire les termes sans
que l’application de la reg̀le n’introduise de nouvelles variables jusqu’à
l’obtention d’une forme irréductible appelée forme normale.
Réécriture de termes
I La relation → induit sur T(Σ) une relation semblable à celle de = induit
sur TΣ , sauf que cette relation n’est pas symétrique puisque les règles
sont orientées de gauche à droite.
I Notons t →∗ t 0 une suite t → . . . → t 0 où t 0 est irréductible. Alors t = t 0
est démontrable par réécriture s’il existe un terme t0 tel que t →∗ t0 et
t 0 →∗ t0 .
Réécriture de termes
I Par exemple, dans le cas de boolean, en orientant les axiomes de
gauche à droite:
1. not(true)
2. not(false)
3. (true and b)
4. (false and b)
5. (true or b)
6. (false or b)
→
→
→
→
→
→
false;
true;
b;
false;
true;
b;
I Nous pouvons démontrer par réécriture des termes de Boolean:
not(false or (true and false)) = true
par l’application des suites de règles (6, 3, 2) et (3, 6, 2).
I Il est à noter que pour trouver une dérivation à s = t, il est suffisant de
réduire s et t à un même terme u: s → s1 → · · · → sk → u et
t → t1 → · · · → tl → u.
Système de réécriture
I Un système de réécriture est convergent s’il n’induit pas de suites
divergentes i.e. de suites infinies de réductions t0 → t1 → t2 · · · .
I Il est à remarquer que les deux conditions :
1. s n’est pas une variable seule;
2. toutes les variables de t sont des variables de s.
sont nécessaires à la convergence.
Système de réécriture
I Les conditions d’utilisation de ce principe d’orientation des règles sont
toutefois moins robustes qu’il n’y parait:
1. Ce principe n’est satisfaisant que si le système de preuves obtenue est
convergent et le problème de convergence est en général très difficile.
2. Ce principe n’est pas suffisant pour démontrer toutes les équations
déductibles d’une spécification comme l’illustre l’exemple suivant:
Système de réécriture
AdtMachintrucs
Interface
Sorts machintruc;
Operations
0:
()
machintruc
- :
+ : machintruc machintruc
Body
Axioms
1. 0 + x
= x;
2. x + (-x) = 0;
End Machintrucs;
→ machintruc;
→ machintruc;
→ machintruc
I Les règles obtenues en orientant les axiomes de gauche à droite ne
suffisent pas à démontrer par exemple que - 0 = 0.
I Il est en effet nécessaire pour ce faire, d’appliquer l’axiome 1 de droite à
gauche puis l’axiome 2 de gauche à droite.
I Ce mécanisme d’orientation est clairement insuffisant, en particulier
pour les axiomes des opérations génératrices. En pratique, ce
mécanisme est néanmoins suffisant dans de nombreuses situations.
Raffinement d’une spécification
I La décomposition hiérarchique des spécifications par raffinement est
basée sur le principe suivant : Le modèle initial de la spécification
raffinée doit respecter, relativement au modèle initial de la spécification
de départ
I On doit toujours avoir les slogans:
I
I
Pas de junk (complétude hiérarchique)
Pas de confusion (cohérence hiérarchique)
Définition
Nous dirons qu’une spécification Spec0 raffine la spécification Spec1 si:
I La signature de Spec1 est incluse dans celle de Spec0
I L’axiomatisation de Spec1 est incluse dans celle de Spec0
Complétude hiérarchique
I L’exemple qui suit illustre la situation de junk.
I La spécification suivante raffine celles de Naturals et de Booleans.
I Elle est en quelque sorte la spécification d’un module formé des
modules de Naturals et de Booleans.
I
AdtIncomplétude
Interface
Use Naturals, Booleans;
Sorts incomlétude;
Operations
f : natural → boolean;
Body
Axioms
f(succ(x)) = false;
where
x: natural;
End Incomplétude;
Cohérence hiérarchique
I Cette contrainte interdit l’écrasement de valeurs
AdtIncohérence
Interface
Use Naturals, Booleans;
Sorts incohérence;
Operations
f : boolean → boolean;
Body
Axioms
f(succ(x)) = false;
f(0) = true;
f(succ(succ(x))) = true;
where
x: natural;
End Incohérence;
Comment raffiner des spécifications?
I Dans le cadre de la logique du premier ordre, les problèmes de
cohérence et de complétude hiérarchique sont indécidables.
I Il existe toutefois une méthode d’écriture des axiomes applicable dans
des cas simples qui permet de garantir la complétude hiérarchique.
I L’idée est la suivante: une décomposition systématique dans les
axiomes des domaines des fonctions selon les opérations génératrice
de la spécification, permet de couvrir tous les cas d’évaluation d’une
fonction et donc, de ne pas introduire de nouvelles valeurs dans la sorte
du co-domaine.
Comment raffiner des spécifications?
1. Pour chaque opération f : s1 , s2 , . . . , sn → s on écrit f (x1 , x2 , . . . xn )
comme coté gauche de l’équation de l’axiome où
x1 : s1 , x2 : s2 , . . . , xn : sn .
2. Pour chaque variable, on écrit un axiome valide pour toutes les valeurs
du domaine de cette variable.
3. Si ce n’est pas possible, on partitionne le domaine au moyen des
générateurs et, pour chaque élément de la partition du domaine, on
écrit un axiome valide pour toutes les valeurs de cet élément de
partition.
4. Si le générateur du domaine ne suffit pas à partitionner le domaine, on
introduit une série de sous-cas exprimés en termes de préconditions
pour partitionner le domaine et, pour chaque élément de la partition, on
écrit un axiome valide pour toutes les valeurs de cet élément de
partition.
Exemple
Exemple point 3)
Dans le cas de l’opérateur add to de string:
(new = new) = true;
(add c to x = new) = false;
(new = add c to x) = false;
(add c to x = add d to y) = (c = d) and (x = y);
Exemple point 4)
Dans le cas de l’opérateur div de natural:
x div 0 = 0;
(x < y) = true ⇒ (x div y) = 0;
((x >= y) = true) and ((y = 0) = false) ⇒
(x div y) = succ((x - y) div y);
Téléchargement