Composition d’Informatique
Les Principes des Langages de Programmation (INF 321) Promotion 2011
Corrig´ e propos´ e par Eric Goubault et Xavier Rival 12 juillet 2012
1 Types de donn´ ees et constructeurs
1.a) D´efinir une classe Javaconcr`ete AExpr qui impl´emente le type correspondant aux expres- sions arithm´etiques.
public enum o p e r a t o r { Plus , Times , Div }
public enum k i n d { Bot ,
Cst , C e l l , Neg , Bin }
c l a s s AExpr { k i n d k ; f l o a t v a l ; i n t i ; i n t j ; o p e r a t o r op ;
AExpr l ; // s t o r e s t h e o n l y sub−e x p r o f ”−e ” AExpr r ; // s h o u l d b e n u l l f o r Neg
}
Barˆeme: 2 points
1.b) D´efinir les constructeurs:
AExpr ( )
AExpr (f l o a t n ) AExpr (i n t i , i n t j )
AExpr ( o p e r a t o r op , l e x p r , r e x p r ) AExpr ( e x p r )
qui rendent respectivement ⊥, un AExpr repr´esentant le flottant n, ci,j, l’op´eration binaire op appliqu´e `a une sous-expression gauchelexpr et `a une sous-expression droiterexpr, et le moins appliqu´e `a la sous-expressionexpr.
AExpr ( ) { k = k i n d . Bot ; }
AExpr (f l o a t f ) { k = k i n d . Cst ; v = f ;
}
AExpr (i n t i , i n t j ) { k = k i n d . C e l l ;
t h i s. i = i ; t h i s. j = j ; }
AExpr ( o p e r a t o r op , AExpr l e x p r , AExpr r e x p r ) { k = k i n d . Bin ;
o = op ; l = l e x p r ; r = r e x p r ; }
AExpr ( AExpr e x p r ){ k = k i n d . Neg ;
l = e x p r ; }
Barˆeme: .5 point par constructeur (2.5 points en tout)
1.c) D´efinir une classe permettant de stocker une feuille de calcul. On l’appelleraFeuille.
c l a s s F e u i l l e{ AExpr [ ] [ ] c e l l s ; }
Barˆeme: 1 point
2 S´ emantique et ´ evaluation
2.a) On consid`ere dans cette question la feuille:
D= c1,1+c0,1 3∗c1,0 2 c0,0+c0,1
Quelles en sont les cellules d´efinies ? (On donnera pour ce faire le grapheGρD).
Les arˆetes du graphe sont:
c0,0 → c0,1
c0,0 → c1,1
c0,1 → c1,0
c1,1 → c0,0
c1,1 → c0,1
Les cellules d´efinies sont doncc1,0et c0,1. Barˆeme: 2 points.
2.b) Ecrire la s´´ emantique d´enotationnelle [[expr]] des expressions arithm´etiquesa∈AExpr, par r´ecurrence structurelle sur AExpr. Expliquer bri`evement pourquoi cette r´ecurrence structurelle est bien d´efinie.
• si e n’est pas d´efinie, [[e]](p) =⊥
• [[⊥]](p) =⊥
• [[f]](p) =f
• [[ci,j]](p) = [[p(i, j)]](p)
• [[−e]](p) =−[[e]](p)
• [[e0 o e1]](p) = [[e0]](p)◦[[e1]](p) sio∈ {+,−,∗}
La s´emantique des expressions non d´efinies est bien d´efinie. Si e est une expression d´efinie, le sous-graphe de d´ependance obtenu en ne consid´erant que les noeuds atteignables `a partir des cellules apparaissant dans l’expression est un arbre ; de plus, le sous-graphe d´efini de la mˆeme mani`ere pour chacun des appels r´ecursifs dans l’´evaluation deecorrespond `a un sous arbre strict de l’arbre initial. La r´ecurrence est donc bien fond´ee.
Barˆeme: 2 points pour la s´emantique, 1 point pour l’explication de la correction de cette d´efinition.
2.c) Ecrire le code de la m´´ ethode dynamique et r´ecursive Eval de la classe AExpr prenant en argument une feuillep, et permettant d’´evaluer l’expression sur laquelle elle s’applique.
AExpr Eval ( F e u i l l e p ) { i f ( D e f i n e d (t h i s) ) {
switch( k ) { case Bot :
return t h i s; case Cst :
return t h i s; case C e l l :
return p . c e l l s [ i ] [ j ] . e v a l ( p ) ; case Neg :
return new AExpr(−l . e v a l ( p ) . v ) ; case Bin :
switch( o ) { case P l u s :
return new AExpr ( l . e v a l ( p ) . v+r . e v a l ( p ) . v ) ; case Times :
return new AExpr ( l . e v a l ( p ) . v∗r . e v a l ( p ) . v ) ; case Div :
f l o a t den = r . e v a l ( p ) . v ; i f ( den != 0 )
return new AExpr ( l . e v a l ( p ) . v / den ) ; e l s e
return new AExpr ( ) ; }
} } e l s e {
return new AExpr ( ) ; }
}
Barˆeme: 2.5 points.
2.d) optionnel Comment faire pour se passer de la m´ethodeDefinedpour programmerEval?
AExpr Eval (boolean [ ] [ ] d e j a v u , F e u i l l e p ){ switch( k ) {
case Bot : return t h i s; case Cst :
return t h i s; case C e l l :
i f ( d e j a v u [ i ] [ j ] ) return new AExpr ( ) ; e l s e {
d e j a v u [ i ] [ j ] = true;
return p . c e l l s [ i ] [ j ] . e v a l ( p ) ; }
case Neg :
return new AExpr(−l . e v a l ( p ) . v ) ; case Bin :
switch( o ) { case P l u s :
return new AExpr ( l . e v a l ( p ) . v+r . e v a l ( p ) . v ) ; case Times :
return new AExpr ( l . e v a l ( p ) . v∗r . e v a l ( p ) . v ) ; case Div :
f l o a t den = r . e v a l ( p ) . v ; i f ( den != 0 )
return new AExpr ( l . e v a l ( p ) . v / den ) ; e l s e
return new AExpr ( ) ; }
} }
AExpr Eval ( F e u i l l e p ) {
boolean[ ] [ ] d e j a v u = new boolean[ p . c e l l s . l e n g t h ] [ ] ; f o r (i n t i = 0 ; i < p . c e l l s . l e n g t h ; i ++) {
d e j a v u [ i ] = new boolean[ p . c e l l s [ i ] . l e n g t h ] ; }
return e v a l ( d e j a v u , p ) ; }
Barˆeme: 2 points.
3 Gestion de la feuille de calcul
3.a) Ecrire une m´´ ethode dynamiqueCompute, de la classeFeuille, qui ´evalue chaque cellule de la feuille courante.
Compute ( ) {
f o r ( i =0; i < c e l l s . l e n g t h ; i ++)
f o r ( j =0; j < c e l l s [ i ] . l e n g t h ; j ++) { c e l l s [ i ] [ j ] = c e l l s [ i ] [ j ] . e v a l (t h i s) ; }
}
Barˆeme: 2 points.
3.b) Que doit donnerComputesurC? et surD?
Sur C, seulc0,0est d´efini ´egal `a 1, les trois autres cellules sont `a bottom.
Sur D, on a vu que seules c0,1 et c1,0 sont d´efinis, respectivement `a 6 et `a 2, les deux autres cellules sont `a bottom.
Barˆeme: 1 point pour chaque cas (2 points en tout).
3.c) Par quel m´ecanisme peut-on traiter simplement ces cas de division par z´ero ? Par le m´ecanisme d’exception, disponible en Java.
Barˆeme: 1 point.
3.d) Dire comment modifier le code d’Eval(sans tout r´e´ecrire) de la question (2.c) et le code de Computede la question (3.a) afin d’impl´ementer ce m´ecanisme.
Par exemple, on peut se souvenir de l’expression de la feuille responsable de la division par z´ero (indicatif, non n´ecessaire pour avoir les points de cette question):
c l a s s A r i t h E x c e p t i o n extends E x c e p t i o n { AExpr d ;
. . . }
AExpr Eval ( F e u i l l e p ) throws A r i t h E x c e p t i o n { i f ( D e f i n e d (t h i s) ) {
switch( k ) { case Bot :
return t h i s; case Cst :
return t h i s; case C e l l :
return p . c e l l s [ i ] [ j ] . e v a l ( p ) ; case Neg :
return new AExpr(−l . e v a l ( p ) . v ) ; case Bin :
switch( o ) { case P l u s :
return new AExpr ( l . e v a l ( p ) . v+r . e v a l ( p ) . v ) ; case Times :
return new AExpr ( l . e v a l ( p ) . v∗r . e v a l ( p ) . v ) ; case Div :
AExpr e x p r d e n = r . e v a l ( p ) ; f l o a t den = e x p r d e n . v ; i f ( den != 0 )
return new AExpr ( l . e v a l ( p ) . v / den ) ; e l s e
throw new A r i t h E x c e p t i o n ( e x p r d e n ) ; return new AExpr ( ) ;
} } } e l s e {
return new AExpr ( ) ; }
}
Compute ( ) {
f o r ( i =0; i < c e l l s . l e n g t h ; i ++)
f o r ( j =0; j < c e l l s [ i ] . l e n g t h ; j ++) { try {
c e l l s [ i ] [ j ] = c e l l s [ i ] [ j ] . e v a l (t h i s) ; } catch ( A r i t h E x c e p t i o n e ) {
// I d e a l l y , s h o u l d p r e t t y p r i n t t h e e x p r e s s i o n e . d
System . o u t . p r i n l n ( ” E x p r e s s i o n au d e n o m i n a t e u r ”+e . d+” e s t n u l l e ! ” ) }
} }
Barˆeme: 2 points (1 pour la d´efinition d’une exception, mˆeme vide, et pour la modification dansEval, 1 pour letry/catchde la m´ethodeCompute).
4 M´ ethode alternative d’´ evaluation
4.a) Quels sont les points fixes du FC particulier d´efini ci-dessus ? De mˆeme pourFD la fonc- tionnelle induite par la feuilleDde la question 2.a.
On a
FC
c0,0
c0,1 c1,0 c1,1
=
1 c1,1
⊥ c0,0−c0,1
Les points fixes deFC sont donc tels que: c0,0= 1,c0,1=c1,1,c1,0=⊥etc1,1=c0,0−c0,1= 1−c1,1. Donc on a deux solutions:
• c0,1=c1,1=c1,0=⊥etc0,0= 1
• c0,1=c1,1=12,c0,0= 1 etc1,0=⊥ On a
FD
c0,0 c0,1 c1,0 c1,1
=
c1,1+c0,1 3c1,0
2 c0,0+c0,1
Les points fixes deFDsont donc tels que: c0,0=c1,1+c0,1,c0,1= 3c1,0,c1,0= 2 etc1,1=c0,0+c0,1. Doncc0,0=c0,0+ 2c0,1=c0,0+ 6c1,0=c0,0+ 12,c0,1= 6,c1,0= 2 etc1,1=c0,0+ 6. Donc on n’a qu’une plus petite solution (plus petit point fixe): c0,1=⊥,c0,1= 6,c1,0= 2 etc1,1=⊥.
Barˆeme: 1 point par fonctionnelle (2 points en tout). Pour la fonctionnelle FC un demi-point par cas trouv´e (2 points fixes).
4.b) Quel est le plus petit point fixe deFC ? deFD ?
Pour FC: c0,1=c1,1=c1,0=⊥et c0,0= 1. PourFD: c0,1=⊥,c0,1= 6, c1,0= 2 etc1,1=⊥.
Barˆeme: .5 point par plus petit point fixe (1 point en tout).
4.c) Donner les it´er´ees successives du calcul de plus petit point fixe de FC et de FD par le th´eor`eme de Kleene.
On calcule:
FC1(⊥) =
1
⊥
⊥
⊥
FC2(⊥) =
1
⊥
⊥
⊥
Donc le plus petit point fixe deFC est (1,⊥,⊥,⊥).
Maintenant pour FD:
FD1(⊥) =
⊥
⊥ 2
⊥
FD2(⊥) =
⊥ 6 2
⊥
FD3(⊥) =
⊥ 6 2
⊥
et on atteint le plus petit (et unique) point fixe.
Barˆeme: 1 point par fonctionnelle (2 points en tout).
4.d) Prouver que sici,j n’est pas d´efini dans la feuilleρ, alors pour toutk∈N, (Fk)i,j(⊥) =⊥, o`u (Fk)i,j est la composante (i, j) de l’it´er´eeki`eme deF.
Une celluleci,jn’est pas d´efinie si elle est dans un cycle de d´ependance, ou si elle d´epend d’une valeur⊥. Dans tous les cas, l’evaluation en ⊥de la fonctionnelle correspondant au calcul deci,j, Fi,j, et mˆeme de la fonctionnelle it´er´ee kfois, utilise au moins une valeur `a ⊥(ci,j mˆeme, si dans un cycle de d´ependance, sinon une cellule `a⊥), or les fonctions arithm´etiques sont toutes strictes, donc par induction structurelle simple, le r´esultat est toujours⊥.
Barˆeme: 1 point.
4.e) Prouver maintenant que si tous lesci,j sont d´efinis dans la feuilleρ,Fk(⊥),k≥1, donne la valeur num´erique (donc diff´erente de⊥, au sens de la s´emantique d´enotationnelle de la question (2.a)) de l’ensembleCk des cellules ci,j telles quek > kic0i,j,j0 pour toutes cellulesci0,j0 ∈C1.
Soit donc C1 l’ensemble des cellules ci,j telles queρ(ci,j) est une constante num´erique, et de fa¸con g´en´eraleCk l’ensemble des cellulesci,jde profondeur inf´erieure strictement `akpar rapport aux cellules deC1. On effectue une r´ecurrence surk.
Le cas de base estk= 1: l’ensemble des cellules deC1est pr´ecis´ement celui calcul´e parF1(⊥).
On suppose que l’ensemble des cellules deCk est calcul´e parFk(⊥), et on calculeFk+1(⊥) = F(Fk(⊥)). On voit ais´ement que les cellulesci,j deCk+1 sont `a profondeur inf´erieure ou ´egale `a 1 par rapport aux cellules deCk. Pour les cellules de profondeur 0, ce sont des cellules deCk donc sont d´ej`a calcul´ees par Fk(⊥), a fortiori par Fk+1(⊥) (pour s’en convaincre facilement, on peut utiliser la monotonie deF). Pour les cellules de profondeur 1 par rapport `a Ck, elles d´ependent directement de la valeur des cellules deCk, qui sont donn´ees parFk(⊥): ainsiFk+1(⊥) les calcule.
Barˆeme: 1 point.
4.f ) En d´eduire que le plus petit point fixe de la fonctionnelle F est ´egal `a la s´emantique d´enotationnelle donn´ee `a la question (2.a).
Pour les cellules ci,j non-d´efinies, par la question 4.d), on sait queFi,jk (⊥) est ⊥pour toutk, donc leur valeur dans la s´emantique de plus petit point fixe (deF) est⊥. Cela correspond `a la s´emantique d´enotationnelle de la question 2.a).
Pour les cellules ci,j d´efinies, par la question 4.e), on sait qu’il existe ktel queFi,jk (⊥) donne la valeur num´erique deci,j, car le graphe de d´ependance est fini, donc toutes les profondeurs sont finies. Donc leur valeur est calcul´ee (par la mˆeme s´emantique que la s´emantique d´enotationnelle de la question 2.a) par le plus petit point fixe deF.
Barˆeme: 1 point.
4.g) Ecrire une version it´´ erative de la m´ethodeEvalde la question (2.c), impl´ementant l’it´eration de Kleene, que l’on sait donner le mˆeme r´esultat que la m´ethode r´ecursive de la question (2.c), grˆace `a la question (4.f).
En fait, on doit d’abord ´ecrireCompute()avantEval.
AExpr EvalAExpr ( F e u i l l e p , F e u i l l e c u r ) {
// E v a l u a t i n g e x p r e s s i o n t h i s , w i t h f u n c t i o n a l p , under c o n t e x t c u r AExpr r e s l , r e s r ;
switch( k ) { case Bot :
return new AExpr ( ) ; case Cst :
return t h i s; case C e l l :
return EvalAExpr ( c u r . c e l l s [ i ] [ j ] , p ) ; case Neg :
r e s l = EvalAExpr ( l , p ) ;
i f ( r e s l . k == Bot ) return new AExpr ( ) ; e l s e return new AExpr(−r e s l . v ) ;
case Bin :
r e s l = EvalAExpr ( l , p ) ; r e l r = EvalAExpr ( r , p ) ;
i f ( r e s l . k == Bot ) return new AExpr ( ) ; i f ( r e s r . k == Bot ) return new AExpr ( ) ; switch( e . o ) {
case P l u s :
return new AExpr ( r e s l . v+r e s r . v ) ; case Times :
return new AExpr ( r e s l . v∗. r e s r . v ) ; case Div :
f l o a t den = r e s r . v ; i f ( den != 0 )
return new AExpr ( r e s l . v / den ) ; e l s e
return new AExpr ( ) ; }
} }
// A u x i l i a r y f u n c t i o n s
s t a t i c boolean equalAExpr ( AExpr e0 , AExpr e1 ) { // s u p p o s i n g a l l e x p r e s s i o n s a r e a l l o c a t e d
i f ( e0 . k != e1 . k ) return f a l s e;
switch( e0 . k ) { case Bot :
return true; case Cst :
return ( e0 . k == e1 . k ) ; case C e l l :
return ( ( e0 . i == e1 . i ) && ( e0 . j == e1 . j ) ) ; case Neg :
return equalAExpr ( e0 . l , e1 . l ) ; case Bin :
i f ( e0 . o != e1 . o ) return f a l s e;
return ( equalAExpr ( e0 . l , e1 . l ) && equalAExpr ( e0 . r , e1 . r ) ) ; }
}
s t a t i c boolean e q u a l F e u i l l e ( F e u i l l e cur , F e u i l l e n e x t ) { // s u p p o s i n g t h e y h a v e t h e same s i z e , and w e l l a l l o c a t e d
boolean r e s = true;
f o r (i n t i =0; i<c u r . c e l l s . l e n g t h ; i ++) f o r (i n t j =0; j<c u r . c e l l s [ i ] . l e n g t h ; j ++)
i f ( ! equalAExpr ( c u r . c e l l s [ i ] [ j ] , n e x t . c e l l s [ i ] [ j ] ) ) r e s = f a l s e;
return r e s ; }
s t a t i c c o p y c e l l s ( AExpr [ ] [ ] from , AExpr [ ] [ ] t o ) {
// s u p p o s i n g same s i z e and w e l l a l l o c a t e d s q u a r e c e l l a r r a y s f o r (i n t i =0; i<from . l e n g t h ; i ++)
f o r (i n t j =0; i<from [ i ] . l e n g t h ; j ++) t o . c e l l s [ i ] [ j ] = from . c e l l s [ i ] [ j ] ; }
Compute ( ) {
AExpr p r e v = new AExpr ( ) ; b o o l u n s t a b l e = true;
F e u i l l e c u r = new F e u i l l e ( ) ; F e u i l l e n e x t = new F e u i l l e ( ) ;
// s u p p o s e p . c e l l s c o n t a i n s a t l e a s t one c e l l , and t h a t t h e s h e e t i s s q u a r e c u r . c e l l s = new AExpr [ c e l l s . l e n g t h ] [ p . c e l l s [ 0 ] . l e n g t h ] ;
n e x t . c e l l s = new AExpr [ c e l l s . l e n g t h ] [ p . c e l l s [ 0 ] . l e n g t h ] ;
// i n i t i a l i z i n g c u r r e n t i t e r a t e t o b o t f o r (i n t i =0; i<c e l l s . l e n g t h ; i ++)
f o r (i n t j =0; i<c e l l s [ i ] . l e n g t h ; j ++) c u r . c e l l s [ i ] [ j ] = new AExpr ( ) ;
// K l e e n e i t e r a t e while ( u n s t a b l e ) {
f o r (i n t i =0; i<c e l l s . l e n g t h ; i ++) f o r (i n t j =0; i<c e l l s [ i ] . l e n g t h ; j ++)
n e x t . c e l l s [ i ] [ j ] = c e l l s [ i ] [ j ] . EvalAExpr (t h i s, c u r ) ;
// t e s t w h e t h e r f i x p o i n t
i f ( e q u a l F e u i l l e ( cur , n e x t ) ) u n s t a b l e = f a l s e; e l s e u n s t a b l e = true;
// c o p y i t e r a t e k+1 i n t o c u r
c o p y c e l l s ( n e x t . c e l l s , c u r . c e l l s ) ; }
// c o p y i n g r e s u l t i n t o t h i s c o p y c e l l s ( c u r . c e l l s , c e l l s ) ; }
AExpr Eval ( F e u i l l e p ) { p . Compute ( ) ;
return EvalAexpr ( p , p ) ; }
Barˆeme: 2 points d`es que la structure de l’it´er´ee de Kleene est correcte (mˆeme si le code des fonctions auxiliairesequalAExpr,copycellsetc. est absent). +1 point si plus complet.
4.h) optionnel SoitP le pr´edicat suivant sur lesa∈AExpr et les feuilles ρ: P(a, ρ) est vrai si aest d´efinie dansρ. Donner les assertions n´ecessaires `a la preuve `a la Hoare du code it´eratif d’Eval de la question (4.d), `a chaque ligne du code, permettant de prouver
{¬P(a, ρ)}x=a.Eval(ρ){x=⊥}
V´erifier les assertions de preuve en utilisant les r`egles de preuve `a la Hoare du cours.
Barˆeme: 2 points d`es que l’id´ee est l`a.