• Aucun résultat trouvé

Exemple d’expressions d’amalgame purs

Éléments d’implémentation et exemples de calculs sur les amalgames

XI.2 Exemple d’expressions d’amalgame purs

XI.2.1 Exemple du calcul de fonctions booléennes

Le calcul d’une fonction booléenne peut être effectué en utilisant uniquement les opérateurs de conjonction et de négation. Il est aussi possible de définir ces opérateurs à partir de leur tables de vérité [Aum77]. Nous donnons ici un exemple de traduction des opérations logiques not et and en amalgames.

XI.2.1.1 La fonction booléenne not

L’expression suivante3définit une fonction booléenne not où valeur est une donnée du premier système défini, la négation de valeur apparaissant comme la valeur de la seconde expression :

N OT ≡ {valeur = vrai0,

premier ={vrai = f0, f aux = v0

}  valeur1, second ={f = faux0, v = vrai0}  premier1}

Le calcul de la négation de valeur (qui appartient à l’ensemble {vrai, faux}) s’effectue séquentiellement en deux temps :

1. Deux équations sont définies dans le premier système. Ces équations définissent deux definiens f et v accessibles respectivement par leur definiendum vrai et faux. Si valeur est égal à vrai, alors c’est la référence f qui est sélectionnée, v sinon.

2. Une fois que le premier système s’est évalué en v ou f en fonction de valeur, la sélection de premier dans le second système permet de convertir la référence en un élément de l’ensemble des booléens {vrai, faux}.

1. Cette construction est similaire à la fonctionML: let f = function x -> x+1 où le paramètre de la fonction f est identifié à la variable x.

2. La notation « /. » est synonyme de ReplaceAll qui applique une liste de règles de réécriture à un argument et a pour valeur le membre droit de la règle qui peut s’appliquer sur cet argument (s’il existe) ; l’expression l[[n]] a pour résultat le neélément de la liste l.

L’algorithme utilise une conversion de valeur en un terme de {v, f} en associant à une valeur vraie un terme qui représente la valeur fausse, et inversement, puis une conversion en un terme correct des booléens. Nous donnons les réductions de l’expression où valeur est instanciée avec vrai :

N OT −→ {V, premier = {vrai = f0, f aux= v0}  vrai0, second= {f = f aux0, v= vrai0}  premier1} −→ {V, premier = {vrai = f0, f aux= v0}  f0, second= {f = f aux0, v= vrai0}  premier1} −→ {V, premier = f0 , second= {f = f aux0 , v= vrai0 }  premier1} −→ {V, premier = f0 , second= {f = f aux0 , v= vrai0 }  f0} −→ {V, premier = f0, second= {f = f aux0, v= vrai0}  faux0} −→ {V, premier = f0, second= f aux0}

où V représente l’expression valeur = vrai0.

XI.2.1.2 La fonction booléenne and

En utilisant un schéma de traitement similaire à celui adopté pour l’exemple précédent, nous montrons comment utiliser les amalgames pour représenter le calcul de la fonction logique dyadique and. L’expression suivante :

AN D ≡ {r = { {v1 = faux,

v2 = vrai,

prem ={faux = f, vrai = autre}  v1, et ={f = faux, autre = v2}  prem}}}}

définit les definiendum v1 et v2 qui sont les paramètres de l’expression. L’expression utilise le codage de la fonction and pour effectuer l’opération entre les deux valeurs : si v1 est faux alors le résultat (donné par et) est égal a f qui est ensuite converti en la valeur booléenne f aux, sinon c’est la valeur de v1 (à travers le definiens autre) qui est sélectionné. Nous donnons les réductions pour des valeurs de (v1, v2) égales à (f aux, vrai) : AN D −→ {r = {V, prem = {f aux = f0 , vrai= autre0 }  faux0, et= {f = f aux0 , autre= vrai0 }  prem1}} −→ {r = {V, prem = {f aux = f0, vrai= autre0}  f0, et= {f = f aux0, autre= vrai0}  prem1}} −→ {r = {V, prem = f0, et= {f = f aux0, autre= vrai0}  prem1}}

−→ {r = {V, prem = f0, et= {f = f aux0, autre= vrai0}  f0}} −→ {r = {V, prem = f0, et= {f = f aux0, autre= vrai0}  faux0}} −→ {r = {V, prem = f0

, et= f aux0 }}

où V représente les définitions v1 = faux, v2 = vrai. Pour les valeurs (vrai, vrai), nous avons :

AN D −→ {r = {V, prem = {f aux = f0, vrai= autre0}  vrai0, et= {f = f aux0, autre= vrai0}  prem1}} −→ {r = {V, prem = {f aux = f0, vrai= autre0}  autre0, et= {f = f aux0, autre= vrai0}  prem1}} −→ {r = {V, prem = autre0, et= {f = f aux0, autre= vrai0}  prem1}}

−→ {r = {V, prem = autre0, et= {f = f aux0, autre= vrai0}  autre0}} −→ {r = {V, prem = autre0 , et= {f = f aux0 , autre= vrai0 }  vrai0 }} −→ {r = {V, prem = autre0 , et= vrai0 }} où V représente les définitions v1 = vrai, v2 = vrai.

XI.2.2 Codage de l’arithmétique en amalgames

Nous allons illustrer le fait qu’on peut traduire les fonctions arithmétiques récursives en une expression des amalgames. Cela montre la puissance d’expression formelle du calcul sur les amalgames. Cependant, nous ne démontrerons pas ce résultat de manière rigoureuse.

Nous nous restreindrons à la classe des fonctions totales. En effet, le schéma de traduction que nous proposons n’assure pas la non-terminaison du calcul de l’amalgame associé à l’application d’une fonction sur des arguments n’appartenant pas au domaine de définition. Par contre, rien ne permet d’affirmer qu’il n’est pas possible de spécifier une autre notion de définissabilité par amalgame qui permettrait de faire coïncider fonctions « qui bouclent » et expressions n’ayant pas de forme normale.

Nous commençons par rappeler la définition des fonctions arithmétiques récursives4, puis nous définirons une notion de définissabilité par les amalgames et nous esquisserons le codage des fonctions arithmétiques par les amalgames. Le codage proposé a été implémenté sous Mathematicapar une fonction qui traduit une fonction arithmétique récursive en un terme de ΣI, lui-même traduisible en un terme de ΣC. L’exemple de l’addition est détaillé. Nous détaillons dans l’annexe C le sourceMathematicadu traducteur de l’arithmétique dans les amalgames.

XI.2.2.1 Rappel : les fonctions arithmétiques récursives

Définition XI.1 Une fonction numérique est une fonction (totale) ϕ :N p 7→N. Les fonctions numériques de base Up

i, S, Z sont définies par : Uip(n0, . . . , np) = ni, 0≤ i ≤ p

S(n) = n + 1 Z() = 0

Notations : on abrège n1, . . . , np par ~n. Avec cette notation, Up

i(n0, . . . , np) devient Uip(~n). Définition XI.2 Soit A un ensemble de fonctions numériques.

A est clos par composition si pour tout ϕ défini par ϕ(~n) = φ(ψ1(~n), . . . , ψm(~n))

avec φ, ψi∈ A, alors on a aussi ϕ ∈ A.

A est clos par récursion primitive si pour tout ϕ défini par ϕ(0, ~n) = φ(~n)

ϕ(x + 1, ~n) = ψ(x, ϕ(x, ψ1(~n), . . . , ψp(~n))) avec φ, ψ, ψi∈ A, alors on a aussi ϕ ∈ A.

A est clos par minimisation si pour tout ϕ défini par ϕ(~n) = Min{x : φ(x, ~n) = 0}

avec φ ∈ A et tel que ∀~n, ∃m, φ(m, ~n) = 0, alors on a aussi ϕ ∈ A.

Définition XI.3 La classe R des fonctions arithmétiques récursives est le plus petit ensemble contenant les fonctions numériques de base. Il est clos par composition, récursion primitive et minimisation.

XI.2.2.2 Définissabilité par amalgames

Définition XI.4 (Représentation des entiers dans Σ) Pour chaque n ∈ N un terme pnq ∈ Σ est

défini de la manière suivante : p0q≡ {b = vrai0

}

pn + 1q≡ {p = pnq, b = faux0}

Définition XI.5 (Définissabilité par amalgames) Soit ϕ une fonction numérique d’arité p. On dit

que ϕ est définissable par amalgame, ou encore a-définissable, si il existe un système s tel que : ∀~n, s[pn1q, . . . , pnpq]≡ {a1 = pn1q, . . . , ap = pnpq}  s ։ {valeur = pϕ(~n)q, . . . }

Les . . . dans le résultat indiquent que s doit être un système qui doit spécifier au moins une définition pour valeur et qui peut contenir d’autres définitions si cela est nécessaire. Les noms a1, a2... sont, par convention les noms donnés aux arguments de ϕ et qui ne sont pas définis par ailleurs. Le terme s peut dépendre de ces noms.

4. La définition que nous donnons diffère dans les détails de la définition usuelle mais elle est équivalente. Nous adoptons cette définition car elle est plus pratique à traduire.

XI.2.2.3 Le codage de l’arithmétique

Les fonctions arithmétiques de base sont définissables par amalgame : il suffit de prendre les termes Uip

UUiipp ≡ {valeur = ai} S

SS ≡ {valeur = {p = a1, b = faux0}} Z

ZZ ≡ {valeur = p0q}

La fonction numérique P , telle que P (n + 1) = n est définissable par amalgame, on prend : P

PP≡ {valeur = a1  p}

Les fonctions définissables par amalgames sont closes par composition. En effet, soient φ, ψ1, . . . ψp a-définies par G, H1, . . . , Hm, alors

ϕ(~n) = φ(ψ1(~n), . . . , ψm(~n)) est définie par :

{ valeur = args  G,

args = {a1 = H1  valeur, . . . , am = Hm  valeur} }

Il est maintenant nécessaire de définir une forme conditionnelle : λx, y, z.(si x = 0 alors y sinon z). Cela se fait grâce au champ b de la représentation d’un nombre qui nous permet d’extraire une référence libre servant d’aiguillage. Mais attention : il ne faut pas que cette référence libre soit capturée et devienne liée. Par convention, le terme ifZx,y,z représente

{ codeCond = x  b

codeVrai = y,

codeFaux = z,

valIf = aiguillage0  codeCond1 } sachant que aiguillage sera défini plus tard comme :

Branchement≡ {vrai = stop0

 codeVrai2, faux = stop0  codeFaux2}

une fois qu’on a extrait valIf de ifZ. La référence libre stop a pour but d’empêcher la liaison des réfé-rences libres vrai0et faux0qui apparaissent dans codeVrai et codeFaux . On s’en débarrasse en fournissant une définition inoffensive à stop, par exemple stop = {}.

La méthode utilisée pour définir un schéma d’appel récursif consiste à créer une expression correspondant au terme traduisant la fonction mais ne contenant aucune référence liée et à fournir la liaison de ces références au moment de l’appel de la fonction.

Les fonctions définissables par amalgames sont closes par récursion primitive. Nous allons détailler le schéma pour une fonction ϕ à deux variables, en utilisant la conditionnelle et le schéma récursif : soit la fonction ϕ définie par ϕ(0, y) = φ(y) et ϕ(x + 1, y) = ψ(x, ϕ(x, ψ1(y))) avec φ a-défini par F , ψ a-défini par G et ψ1 a-défini par H. Alors ϕ est a-défini par (x et y sont les noms utilisés pour les arguments de ϕ) :

{valeur = value  finalval

value = { finalval = {stop = {}}  (recval  valIf ), fct = ifZx0, G[y0], F [x0, parameter  (call  valIf )]

recval ={call = {X = x1  p, Y = H}, aiguillage = Branchement} 

({x = pn1q, y = pn2q, parameter ={x = X, y = Y }}  fct)}} De la façon dont nous avons présenté les choses, il doit être évident au lecteur qu’il nous importe peu de décrémenter x ou de l’incrémenter dans le schéma de la récursion primitive : cela donne lieu naturellement à l’implémentation de la minimisation.

XI.2.2.4 Exemples de calcul d’expressions arithmétiques

À cause de l’imbrication des définitions, il est nécessaire de générer un nouveau nom pour les arguments lors de chaque application de fonction, ou bien de gérer les accès par des exposants. Ceci explique les numéros arbitraires derrière les noms de variables. Voici, à titre d’exemple, la traduction de U2

1(S(U2 1), S(U2

2))(1, 0) : {valeur = {val21 = arg51, arg50 = {p = arg49, b = faux0}, arg51 = {p = arg48, b = faux0}}  val21,

arg48 = {p = {b = vrai0}, b = faux0},

arg49 = {b = vrai0}}

terme dont le résultat de l’évaluation est :

{valeur = {p = {p = {b = vrai0}, b = faux0}, b = faux0},

arg48 = {p = {b = vrai0

}, b = faux0},

arg49 = {b = vrai0}}

comme on s’y attendait.

La définition de l’addition prend la forme suivante : add(0, n) = n

add(n + 1, m) = add (n, S(m)) d’où les fonctions φ = U1

1, ψ = U2

2, ψ1= S. La traduction de add(2, 1)

donne le terme (les variables Tmpx sont des méta-variables utilisées pour afficher le terme par morceaux, ce ne sont pas des identificateurs de Id) :

add(2, 1) ≡ {valeur = Tmp1

arg82 = {p = {p = {b = vrai0}, b = faux0}, b = faux0}, arg83 = {p = {b = vrai0}, b = faux0}}

Tmp1 ≡ {recval = Tmp2,

f inalval = {stop6 = {}}  recval1, f ct6 = {valif = aiguillage0

 codeCond1, codeCond= x60  b0,

codeVrai= {val36 = arg860, arg86 = y60}  val360,

codeFaux = {val37 = arg880, arg87 = x60, arg88 = call0  retvalue0}  val370 }}  finalval0

Tmp2 ≡ {call = {X6 = x61  p0, Y6 = T mp3, retvalue = param0  f ct60  valif0}, aiguillage = {vrai = stop60

 codevrai1, faux = stop60

 codefaux1}}  {x6 = arg823, y6 = arg833, param= {x6 = X60

, y6 = Y 60

}}  fct62  valif0 Tmp3 ≡ {val34 = {comp6 = arg851, val35 = {p = comp61, b= faux0}}  val350,

arg84 = x61

,

arg85 = y61

}  val340 qui s’évalue5en le terme attendu :

{valeur = {p = {p = {p = {b = vrai0}, b = faux0}, b = faux0}, b = faux0},

a82 = {p = {p = {b = vrai0

}, b = faux0}, b = faux0},

a83 = {p = {b = vrai0

}, b = faux0}}

5. L’évaluation nécessite 37 pas d’évaluation et 450 secondes environ sur une HP 9000/770 avecMathematica (2.2). Évidement, ce n’est pas très efficace, mais le codage de l’arithmétique dans les amalgames purs est surtout un exercice formel.