Méthode B
La Méthode B est une méthode formelle de développement logiciel qui permet de modéliser de façon abstraite en langage B le comportement d'un programme, puis par raffinements successifs, d'aboutir à un modèle concret, sous-ensemble du langage transcodable en Ada ou en C.
Une activité de preuve formelle permet de vérifier la cohérence du modèle abstrait et la conformité de chaque raffinement avec le modèle supérieur (prouvant ainsi la conformité de l'ensemble des implantations concrètes avec le modèle abstrait).
On distingue le « B classique » du « B événementiel », ce dernier étant proche des « Actions Systems ».
| Sommaire |
Historique de B
B, une déjà longue histoire (source : cours vidéo de J.R. Abrial)
- 1949 Alan M. Turing, Checking a large routine, Cambridge University
- 1967 Robert Floyd, Assigning meanings to programs, AMS
- 1969 C.A.R. Hoare, An axiomatic basis for computer programming,
CACM - 1972 D.L. Parnas, A Technique for Software Module Specification with Examples, CACM
- 1975 Edsger Dijkstra, Guarded commands, nondeterminacy and formal derivation of programs, CACM
- 1981 David Gries, The Science of Programming, Springer, 1981
- 1986 Roland Backhouse, Program Construction and Verification, Prentice-Hall, 1986
- 1986 Cliff B. Jones, Systematic Software Development using VDM, Prentice-Hall
- 1988 C.A.R. Hoare, Jifeng He, Natural transformations and data refinement, PRG, Oxford
- 1990 C. Morgan, Programming from Specifications, Prentice-Hall
- 1996 J.R. Abrial, The B-Book, Assigning programs to meanings, Cambridge University Press
- 1996 25-26-27 novembre, First B conference in Nantes (France)
- Pour la suite voir la liste des conférences internationales B et ZB.
- A été conçu par J.R.Abrial (un des principaux concepteurs de Z dans les années 80).
- Concours de : G. Laffitte, F. Meija et I. Mc Neal.
- Basé sur les travaux scientifiques de E.W. Dijkstra,C.A.R. Hoare, C.B. Jones, C. Morgan, He Jifeng (Programming Research Group Université d'Oxford).
Buts de B
- Formaliser la spécification,
- Expliciter la conception,
- Simplifier la programmation.
B méthode formelle
- Car toutes les activités sont validées par des preuves formelles.
Couverture de B
B couvre :
- La spécification,
- La conception par raffinements successifs,
- L'architecture en couches,
- La génération du code exécutable.
La notation B par l'exemple
Une première machine abstraite en B
Cette machine est écrite en notation B Ascii. Il existe aussi une « notation mathématiques », fournie plus loin, qui utilise les symboles usuels de la mathématique ensembliste et de la logique des prédicats.
MACHINE
- reservation (max_siege)
/* Le nom de la machine est réservation. On lui passe en paramètre la variable max_sieges. */
CONSTRAINTS
- max_sieges : NAT
/* Prédicat d'appartenance. max_sieges appartient à l'ensemble des nombres naturels implantables */
VARIABLES
- nb_sieges_dispos
/* nb_sieges_dispos est une variable. On va apprendre dans la rubrique INVARIANT quel est son type. */
INVARIANT
- nb_sieges_dispos : 0..max_sieges
/* L'invariant est un prédicat qui doit respecter l'état de la machine. On apprend ici que nb_sieges_dispos est un élément (: est la notation ascii pour l'appartenance ensembliste) de l'ensemble qui va de 0 à max_sieges, max_sieges ayant été passé en paramètre à la machine. nb_sieges_dispos est donc un nombre entier. C'est le nombre de sièges disponibles. On le comprendra avec l'opération réserver.*/
INITIALISATION
- nb_sieges_dispos := max_siege
/* La rubrique INITIALISATION permet de vérifier que la spécification a au moins un modèle, une instanciation qui satisfait l'invariant
L'opérateur := se lit devient égal à.
Il s'agit de la spécification d'une opération. Il s'agit également d'une substitution simple. Cette opération, lorsqu'elle est appliquée au prédicat qui représente la contrainte que l'état de la machine doit respecter, modélise la transformation de la mémoire opérée par l'initialisation :
[ nb_sieges_dispos := max_sieges] (siege : 0..max_sieges) <=> max_siege : 0..max_sieges
et produit le prédicat qui représente la condition minimale que l'état doit vérifier avant l'exécution de l'opération pour que, après l'exécution, les propriétés de l'état soient toujours vérifiées.
[ nb_sieges_dispos := max_sieges] (nb_sieges_dispos : 0..max_sieges)
se lit : « nb_sieges_dispos devient égal à max_sieges établit que nb_sieges_dispos : 0.. max_sieges. »
Plus généralement, si I désigne un prédicat qui doit être respecté par l'état de la machine et si x := E modélise une des opérations de la machine, alors [x := E] I représente la plus faible condition pour que l'exécution x := E se termine et établisse I.
Explications :
- [x := E] I remplace les occurrences libres de x dans I par l'expression E.
- Par exemple, [x := x+1] (x : N) donne x+1 : N ;
- [S] I est interprété ainsi :
- I est la condition désirée « après » (on dit aussi post-condition). C'est un prédicat.
- [S] I est la condition nécessaire et suffisante « avant ».
Ainsi toute substitution S définit ce qu'on appelle un « transformateur de prédicat » qui associe à toute post-condition R la plus faible pré-condition, notée [S] I, permettant de garantir que R est vraie juste après l'exécution de l'opération. Lorsque c'est bien le cas (R est vraie après l'exécution de l'opération S), on dit que S établit R. La notion de plus faible précondition (weakest precondition) a été introduite par E.W. Dijkstra avec la notation wp(S,I).
Exemple : condition désirée après : x <=10 substitution : x := x+1 condition nécessaire et suffisante « avant » :
- [x := x+1] (x<=9)
- x+1 <= 10
- x <= 9
- x<=9 est la condition nécessaire et suffisante pour que x <= 10 soit vrai après la substitution.*/
OPERATIONS
/* Cette rubrique (en B, on dit aussi clause) contient la définition des opérations offertes par la machine abstraite (on dit aussi, opérations faisant partie du répertoire d'instructions de la machine, ou encore, services offerts par la machine abstraite). Une opération a une en-tête qui a la forme générale suivante : Nom des paramètres de sortie <-- Nom de l'opération (Nom des paramètres d'entrée)
On a donc 4 cas possibles :
- Nom de l'opération
- Nom de l'opération (nom des paramètres d'entrée)
- Nom des paramètres de sortie <-- nom de l'opération (nom des paramètres d'entrée)
Dans cet exemple, nous n'avons que le premier cas. */
reserver =
- PRE
- 0 < nb_sieges_dispos
- THEN
- nb_sieges_dispos := nb_sieges_dispos - 1
- END;
/* Le symbole égal surmonté d'un chapeau se lit « se définit ainsi ». Il se différencie ainsi du symbole d'égalité. Ici, il est noté par « = » en notation ascii.
Vous voyez apparaître un PRE...THEN... . A quoi cela sert-il ? Supposons qu'on ait écrit seulement nb_sieges_dispos := nb_sieges_dispos - 1 On doit avoir : (voir l'exemple précédent)
- [nb_sieges_dispos := nb_sieges_dispos - 1] (nb_sieges_dispos : 0..max-sieges) et donc
- nb_sieges_dispos - 1 : 0..max-sieges,
prédicat qui ne peut être vérifié si nb_sieges_dispos vaut 0. Or on veut que l'invariant soit respecté par les opérations. On utilise pour ça une précondition d'emploi de l'opération.
Si P est un prédicat et S une substitution, P | S, qui se lit : le prédicat P qui préconditionne la substitution S, est défini par :
- [P | S] I <=> P & [S] I qui se lit :
La substitution conditionnée [P | S] établit I si et seulement si P et ("et" logique) la substitution S établit que I est vrai. Du fait du &, si la précondition P est fausse, P & [S] I est faux. Ce cas est celui de l'avortement (on dit aussi du crash). Il modélise un programme dont on n'est jamais garanti qu'il se termine et même quand il se termine, il peut faire n'importe quoi. P | S a une forme « littéraire » : PRE P THEN S END */
annuler =
- PRE
- nb_sieges_dispos < max_sieges
- THEN
- nb_sieges_dispos := nb_sieges_dispos + 1
- END;
/* Annuler une réservation consiste à additionner 1 au nombre de sièges disponibles. On a mis une précondition pour s'assurer qu'on ne dépassera pas sa limite. */
END
/* cela montre la fin de la spécification de cette machine. */
Une autre machine abstraite B
MACHINE
- maPetiteEntreprise
/* rédige par Dudule le 06-04-2005 */
SETS
- PROJET; SERVICE; EMPLOYE
VARIABLES
- employe, service, projet, est_affecte, est_responsable_de_projet, est_responsable_de_service
INVARIANT /* Voici les contraintes à satisfaire :
- Tout employé est affecté à un service.
- Un service a au plus un responsable et un employé ne peut être responsable de plus d'un service.
- Un employé responsable d'un service est affecté au service dont il est responsable.
- Un employé est au plus responsable d'un seul projet et un projet n'a au plus qu'un employé qui en est responsable.
- Les employés responsables de projet ne peuvent être responsables de service. */
- employe <: EMPLOYE &
- service <: SERVICE &
- projet <: PROJET &
- est_affecte : employe --> service &
/* employe --> service est l'ensemble des fonctions totales d'employe vers service */
- est_responsable_de_service : employe >+> service &
/* +-> est mis pour l'ensemble des fonctions partielles. La partialité est exprimée par le trait vertical coupant la flèche de totalité. Comme l'ensemble des relations quelconques est exprimé par <-->, l'on ne pouvait utiliser < pour exprimer une fonction de la partie droite vers la partie gauche, d'où l'utilisation de >. Ainsi >+> représente une fonction partielle de la gauche vers la droite et une fonction de ma droite vers la gauche. */
- est_responsable_de_service <: est_affecte &
- est_responsable_de_projet : employe >+> projet &
- dom(est_responsable_de_projet) /\
/* /\ est le symbole Ascii de l'intersection ensembliste */
dom(est_responsable_de_service)={}
INITIALISATION
employe, service, projet, est_affecte, est_responsable_de_service,est_responsable_de_projet := {},{},{},{},{},{}
OPERATIONS
ajout_employe(ss)=
PRE
ss : SERVICE &
ss : service &
(EMPLOYE - employe) /= {}
THEN
ANY ee WHERE
ee : (EMPLOYE - employe)
THEN
employe := employe \/ { ee } ||
est_affecte := est_affecte \/ { ee|->ss }
END
END;
ajout_service=
PRE
(SERVICE-service) /= {}
THEN
ANY ss WHERE
ss : (SERVICE-service)
THEN
service:=service \/ {ss}
END
END;
ajout_responsable_service(ee,ss)=
PRE
ss : SERVICE &
ss : service &
ee : EMPLOYE &
ee : employe &
ee /: dom (est_responsable_de_service) &
ee /: dom(est_responsable_de_projet) &
ss /: ran (est_responsable_de_service) &
ee|->ss: est_affecte
THEN
est_responsable_de_service:=est_responsable_de_service \/ {ee|->ss}
END;
ajout_projet=
PRE
(PROJET - projet) /: { }
THEN
ANY pp WHERE
pp : (PROJET - projet)
THEN
projet:=projet \/ {pp}
END
END;
ajout_responsable_projet(pp, ee)=
PRE
pp : PROJET &
pp : projet &
ee : EMPLOYE &
ee : employe &
ee /: dom (est_responsable_de_service) &
ee /: dom (est_responsable_de_projet) &
pp /: ran (est_responsable_de_projet)
THEN
est_responsable_de_projet := est_responsable_de_projet \/ { ee|->pp }
END;
suppression_employe(ee)=
PRE
ee : EMPLOYE &
ee : employe &
ee : dom (est_affecte) &
ee /: dom (est_responsable_de_service) &
ee /: dom(est_responsable_de_projet)
THEN
employe := employe - {ee} ||
est_affecte := {ee} <<| est_affecte
END;
suppression_responsable_service(ss)=
PRE
ss : SERVICE &
ss : service &
ss : ran (est_responsable_de_service) &
est_responsable_de_service~(ss) |-> ss: est_affecte
THEN
est_responsable_de_service:= {est_responsable_de_service~(ss)} <<|est_responsable_de_service
END;
suppression_service(ss)=
PRE
ss : SERVICE &
ss : service &
ss /: ran (est_responsable_de_service)
THEN
service := service - {ss}
END;
suppression_responsable_projet(pp)=
PRE
pp : PROJET &
pp : projet &
pp : ran (est_responsable_de_projet)
THEN
est_responsable_de_projet := {est_responsable_de_projet~(pp)}<<|est_responsable_de_projet
END;
suppression_projet(pp)=
PRE
pp : PROJET &
pp : projet &
pp /: ran (est_responsable_de_projet)
THEN
projet := projet - {pp}
END
END
Le concept de précondition
Soit la machine suivante :
MACHINE
Calculette
...
OPERATIONS
cc <-- plus (aa, bb) =
/* avec l'Atelier B, les noms des variables
et des constantes doivent faire au moins
deux caractères */
PRE
a : NAT &
b : NAT &
a + b : NAT
THEN
cc := aa + bb
END;
...
END
- Quel est le sens de a + b : (appartient) ENTIER que l'on trouve dans la précondition ?
- Quand on passera de la machine abstraite au code exécutable, la précondition de l'opération plus ne sera pas présente dans le code exécutable de cette opération.
- La précondition veut dire que, lorsqu'on utilisera la machine abstraite (lorsqu'on l'appellera), si l'on respecte la précondition, la machine se comportera comme spécifiée.
- Si on ne respecte pas la précondition, on n'a aucune garantie de bon fonctionnement.
Exemple de la calculette :
Le concepteur du logiciel démontrera, une fois pour toute, que si la précondition est remplie, la calculette fonctionnera correctement.
ATTENTION :
Bien différencier l'approche B (programmation offensive) de la programmation défensive !
Exemple de mon enrouleur de câble électrique :
J'ai un enrouleur de câble électrique qui porte l'étiquette suivante : « Puissance maximale sous 200 V = 2000 W avec le câble déroulé, 1000 W avec le câble enroulé. » J'ai utilisé ma tondeuse électrique de 12000 W avec le câble enroulé.
- Le câble a fondu.
- L'enrouleur ne m'a pas prévenu.
- Il ne disposait pas d'un composant testant si le câble était déroulé.
- C'est lorsque le fabricant a conçu l'enrouleur qu'il a « démontré » qu'il fonctionne correctement si l'utilisateur respecte les conditions d'emploi écrites sur l'étiquette.
Cette démonstration a été faite une fois pour toute en utilisant les lois de la physique. Le vendeur ne m'a pas remboursé l'enrouleur.
C'est alors à l'utilisateur à ne faire appel à l'enrouleur qu'en respectant les conditions d'emploi. Ces conditions d'emploi ne peuvent être vérifiées dans le « code » de l'opération.
B et spécifications algébriques
MACHINE
VARIABLE (VALEUR)
VARIABLES
vrb
INVARIANT
vrb : VALEUR
OPERATIONS
v <-- valeur =
BEGIN
v:= vrb
END ;
changer (v) =
PRE
v : VALEUR
THEN
vrb := v
END
END
En spécification algébrique, on écrit des AXIOMES :
- valeur (changer (v)) = v
- en B, un tel axiome serait un théorème sur le modèle.
- en B, on fait la preuve que si on appelle une opération sous sa précondition, on établit l'invariant :
- I /\ P => [S] I
- (vrb : VALEUR) /\ (v: VALEUR) => [vrb : v] vrb : VALEUR
Différence fondamentale entre Z et B
nota : nous avons utilisé aussi bien pour Z que pour B la notation ASCII B.
[NOM, ADRESSE]
_____CarnetDAdresses___________________ NomConnu : F NOM APourAdresse : NOM -+> ADRESSE __________ dom (APourAdresse) = NomConnu ____________________________________
_____AjoutDAdresse_______________________
Δ CarnetDAdresses
nom? : NOM
adr? : ADRESSE
___________
nom? : NomConnu ?
APourAdresse' = APourAdresse <+ {(nom? |-> adr?)}
_________________________________________
A-t-on besoin, en Z, de spécifier que : NomConnu' = NomConnu \/ {nom?}
Réfléchissez bien à cette question.
Et lisez ensuite ce qui suit :
MACHINE
CarnetDAdresses
SETS
NOM; ADRESSE
VARIABLES
NomConnu, APourAdresse
INVARIANT
NomConnu <: NOM &
ApourAdresse: NomConnu +->ADRESSE
INITIALISATION
NomConnu := {} ||
APour Adresse := {}
OPERATIONS
AjoutDAdresse(nom, adr) =
PRE
nom : NOM - NomConnu &
adr : ADRESSE
THEN
APourAdresse := APourAdresse <+ {nom |-> adr} ||
NomConnu := NomConnu \/{nom}
END
END
- En B n'est modifié que ce que l'on spécifie explicitement être modifié.
- En Z, la spécification est un prédicat. Notez que le := n'est pas utilisé en Z.
Partie de la notation ASCII utilisée en B (vocabulaire français)
Bien pratique pour les échanges sur Internet et pour saisir une machine B avec un clavier de monsieur tout le monde !
Logique
| Code | Libellé | Notation Mathématique |
| P & Q | Conjonction |
|
| P or Q | Disjonction |
|
| P => Q | Implication |
|
| P <=> Q | Equivalence |
|
| not P | Négation |
|
| !(x).(P=>Q) | Quantification universelle |
|
| #(x).(P) | Quantification existentielle |
|
Egalité-Inégalité
| Code | Libellé | Notation Mathématique |
| E = F | Egalité | E = F |
| E /= F | Inégalité |
|
| M <= N | Inférieur ou égal |
|
| M < N | Strictement inférieur | M < N |
| M >= N | Supérieur ou égal |
|
| M > N | Strictement supérieur | M > N |
Prédicats sur les ensembles
Code Libellé
E : S Appartenance
E /: S N'appartient pas
S <: T Sous-ensemble (inclusion)
S /< T non inclus
S <<: T sous ensemble strict ⊂
Ensembles
Code Libellé
E |-> F Couple
S * T Produit cartésien
pow (S) Ensemble des parties de S
S \/ T Union ∪
S /\ T Intersection ∩
S - T Différence
{ } Ensemble vide
Nombres
Code Libellé
NAT Les nombres naturels implantables
card (S)Cardinal de S
Relations
Code Libellé
S <-> T Relations quelconques
dom (r) Domaine de r
ran (r) Codomaine de r
id (r) Identité de r
S <| r Restriction de domaine
S <<| r Corestriction de domaine
r |> T Restriction de codomaine
r ~ Relation inverse de r
r [S] Image de S par r (on dit aussi image relationnelle)
r1 +> r2 Ecrasement de r2 par r1
Fonctions
Code Libellé
S +-> T ensemble des Fonctions partielles de S vers T
S --> T ensemble des Fonctions totales de S vers T
S >+> T ensemble des Injections
S >-> T ensemble des Injections totales
S +->> T ensemble des Surjections
S -->> T ensemble des Surjections totales
S >->> T ensemble des Bijections
f(E) Application de fonction
Suites (séquences en anglais)
Code Libellé
<> Suite vide
seq (S) Ensemble des Suites de S
iseq (S) Ensemble des Suites injectives
j ^k Concaténation
E -> J Ajout en début
J <- E Ajout en fin
[E] Suite singleton
size (J) Taille de la suite J
first (J) Premier élément de la suite J
last (J) Dernier élément de la suite J
Substitutions
Code Libellé
x := E Substitution simple
x,y := E,F Substitution multiple
G;H Séquence
skip Skip
x :: S Choix indéterministe de x parmi les éléments de S
x : P Choix par prédicat
Bibliographie
- Jean-Raymond Abrial, The B-Book, Assigning Programs to Meanings , Cambridge University Press, 1996, ISBN 0521496195
- Steve Schneider, The B-method, an introduction, Palgrave, 2001, ISBN 033379284X, site web : http://www.palgrave.com/resources
- E. Sekerinski and K. Sere (editors ), Case Studies Using the B Method, Springer, ISBN : 0-52149619-5
- John Wordsworth, Software Engineering with B, Addison-Wesley, ISBN : 0201403560
- Kevin Lano, The B Language and Method: A guide to Practical Formal Development, Springer Verlag London Ltd., ISBN : 3-540-76033-4
- Henri Habrias et al., Introduction à la méthode B, Lavoisier Hermes, 2001, ISBN 2746203022, site web :
Qui enseigne B dans le monde ?
voir : [2]
Liens externes
- http://www.atelierb.societe.com/ : l'outil de développement en B
- http://www.clearsy.com/html/b.htm : la société assurant le développement de cet outil
- http://www-lsr.imag.fr/B/ : le site B de Grenoble
Les conférences internationales B
- Après la conférence Z2B de Nantes (oct. 10-12 1995) ,
- puis la première conférence B de Nantes (nov. 25-27 1996),
- puis la deuxième à Montpellier (avril 22-24 1998),
- il y a eu des conférences à peu près tous les 18 mois, ZB'2000 à York (U.K.) 28 août, 2 sept. 2000), ZB'2002 Grenoble (F) (23-25 janv. 2002), ZB'2003, Turku (Finlande) (4-6 juin), ZB'05, Guildford (U.K.)
