Une catégories est une structure vue d'une façon plus générale, en faisant abstraction des objets possédant cette structure, et en ne retenant que ce qui est générale et s'applique à tous ses objets.
Nous allons construire plusieurs structures, et essayer de mettre à jour un procédé de construction implémentable informatiquement. Une structure possède deux versants, l'un théorique comprenant son langage et sa théorie, l'autre algorithmique comprenant son implémentation.
On définie au départ le méta-ensemble W de tous les éléments. Une fonction f faisant parti d'un langage que l'on ajoute à W, est définie sur W selon le principe de construction des structures libres. A savoir en l'absence d'algorithme de calcul, on choisie par défaut la structure libre. Par exemple, si la variable x, contient l'élément d'expression développée g(a,h(b)) dans l'univers de Herbrand, alors f(x) se développe, et est égale à l'élément f(g(a,h(b))) dans l'univers de Herbrand.
Une structure est définie par un langage et une théorie du premier ordre. Par exemple, la structure de monoïde est définie par le langage {K,*} constitué de :
La théorie est : {K(a*b), (a*b)*c = a*(b*c)}
La théorie est constituée par la conjonction des propriétées suivantes :
Pour tout a,b,c tel que K(a) et K(b) et K(c) nous avons :
Axiome |
Axiome sous forme de skolème |
Description |
K(a*b) |
K(a*b) ou ¬K(a) ou ¬K(b) |
L'opération * est interne dans K |
(a*b)*c = a*(b*c) |
(a*b)*c = a*(b*c) ou ¬K(a) ou ¬K(b) ou ¬K(c) |
L'opération * est associative dans K |
L'autre versant de la structure, le versant algorithmique, contient une implémentation des éléments. Les éléments d'un monoïde sont implémentés sous forme de suite. Par exemple, étant donné trois éléments a,b,c appartenant au monoïde, la suite (a,b,a,a,c,b) désigne l'élément a*b*a*a*c*b. Cette implémentation intègre les deux axiomes du monoïde, le fait que l'operation * soit interne et associative.
Nous voulons programmer des algorithmes sur cette structure. Il nous faut une matière pour faire des algorithmes, et cette matière s'appelle les entiers naturels. C'est une structure incontournable qui est à la base de la programmation.
La structure de péano est définie par le langage {N,0,s} constitué de :
La théorie est constituée par les 5 propriétées suivantes :
Pour tout a,b tel que N(a) et N(b) nous avons :
Axiome du premier ordre |
Description |
N(s(a)) |
La fonction s est interne dans N |
s(a)=s(b) => a=b |
La fonction s est injective dans N |
N(0) |
0 appartient à N |
¬( s(a) = 0 ) |
0 n'est pas dans s(N) |
Axiome du second ordre |
|
<0,s> = N |
L'élément 0 et la fonction s engendre N |
Le versant algorithmique de cette structure est la base de la programmation. Les entiers possèdent une implémentation, une forme normale (représentation binaires par exemple), et l'opérations successeur s possède un algorithmes de calcul qui s'appliquent à cette forme normale.
On construit une représentation des entiers (en binaire), et on construit l'operation successeur s par son algorithme de calcul sur les entiers binaires (ajout d'un bit avec retenue). Puis on construit de même l'opération + par son algorithme de calcul sur les entiers binaires (ajout bit à bit avec retenue), et de même pour l'opération * avec un algorithme de calcul un peu plus compliqué.
On construit l'élément 1 comme égale à s(0).
Les opérateurs 1, + et * sont définie par leurs algorithmes.
Les propriétés relatives à ces nouveaux opérateurs sont recherchées.
Pour tout a,b,c tel que N(a) et N(b) et N(c) nous avons :
Axiome |
Déscription |
Description groupée |
a+s(b) = s(a+b) | Propriété liant s et + | Propriété liant s et + |
N(a+b) |
L'opération + est interne dans N | (N,+) est un monoïde commutatif unitaire |
(a+b)+c = a+(b+c) |
L'opération + est associative dans N | |
N(0) | L'opération + possède un élément neutre nommé 0 dans N | |
a+0 = 0+a = a |
||
a+b = b+a |
L'opération + est commutative dans N | |
(a<>0 et b<>0) => N(a*b) |
L'opération * est une opération interne dans N-{0} | (N-{0},*) est un monoïde unitaire |
(a<>0 et b<>0) => (a*b)*c = a*(b*c) |
L'opération * est associative dans N-{0} | |
1<>0 et N(1) | L'opération * possède un élément neutre nommé 1 dans N-{0} | |
a<>0 => a*1 = 1*a = a |
||
a*b = b*a |
L'opération * est commutative dans N | |
c*(a+b) = (c*a) + (c*b) |
L'opération * est distributive à droite sur l'opération + dans N | * est distributive sur + dans N |
(a+b)*c = (a*c) + (b*c) |
L'opération * est distributive à gauche sur l'opération + dans N |
A partir d'une structure, c'est à dire d'un langage et d'une théorie, on construit de nouvelles fonctions en programmant des algorithmes de calcul utilisant les fonctions et prédicats préalablement définis dans de la structure. Le langage de programmation comprent le langage de la structure et les opérations de programmation.
Noter que ces nouvelles fonctions sont une émanation de la catégorie. Il sont propre à la catégorie, et ne sont pas propre à un objet particulier de la catégorie. Il s'applique donc à tous les objets de la categorie.
Par exemple définissons l'opération externe, d'élévation à la puissance, d'un élément du monoïde par un entier, notée sous forme fonctionnelle P(x,n) = x^n. Cette fonction a un type, un schéma qui précise la structure des éléments de départ et la structure des éléments d'arrivé. La construction des types se fait en parallèle à la construction des structures et des fonctions. Le type de la fonction P est le suivant :
(K, N) --> K
La fonction P(x,n)=x^n peut se programmer en ruby comme suit :
def P(x,n) s=1 loop do break if n==0 s=s*x
n=n-1 end end
L'opération ^ est ainsi programmée dans le langage de la catégorie des monoïde, c'est à dire programmé à partir de la seul fonction * de la catégorie des monoïdes et sans utiliser aucune propriété du monoïde spécifique tel que l'ensemble sous-jacent K. Mais elle utilise les opérations de récursion propre à la programmation des fonctions récurcives et appartenan à la structure des entiers.
L'opérateur ^ possède des propriétés que l'on décompose en skolèmes :
(x^n)*(x^m) = x^(n+m) ou ¬K(x) ou ¬N(n) ou ¬N(m)
(x^n)^m = x^(n*m) ou ¬K(x) ou ¬N(n) ou ¬N(m)
(x^n)*(y^n) = (x*y)^n ou ¬K(x) ou ¬K(y) ou ¬N(n)
On appellera émanations de la structures, les nouvelles fonctions et prédicats construits de cette façon. Toute sorte de construction sont délors possible, et nous devrons définir un critère de pertinence.
Le langage de Herbrand de la structure contient toutes les constantes obtenues par emboitement clos de fonctions de base de la structure.
Le langage propositionnel de la structure contient toutes les propositions du premier ordre utilisant les prédicats et fonction de base de la structures et utilisant le prédicat d'égalité.
Le langage propositionnel admet une forme normale, dite de skolème, dans laquelle les propositions ont la forme suivante :
Par exemple la proposition suivante :
∀x ∃y K(x) et K(y) => K(x+y)
Admet comme forme normale de skolème :
∃f(.) ∀x K(x+f(x)) ou ¬K(x) ou ¬K(f(x))
La théorie de la structure se met sous forme normale de skolème. On définie alors le langage de la structure en y ajoutant les variables existancielles postulées dans sa théorie. Et on supprime les quantificateurs existentiels qui délors n'ont pu lieu d'être puisque leur variables sont maintenant définie dans le langage. Les axiomes ne contiennent alors que des quantificateurs universelles, les variables existentiel ayant était enlevées de la théorie et rajoutées au langage, de tel sorte que toute variable qui ne figure pas dans le langage de la structure est obligatoirement une variable universelle.
La théorie d'une structure après skolémisation ne comprend que des variables universelles. Mais la théorie admet plusieurs représentations possibles équivalentes.
Repartons des fondements pour construire nos structures.
On définie le méta-ensemble W de tous les éléments. On considère qu'un élément peut avoir plusieurs représentations et que l'ensemble N des représentation est identifiable aux entiers naturels. De plus on considère que le prédicats Ident : (N,N) -->{vrai, faux} décidant si deux représentations représentent le même éléments est totalement calculable, et que nous possèdons un algorithme calculant Ident(x,y) toujours en un temps fini. Le choix de ce prédicat Ident est arbitraire. Nous avons :
W = N / Ident
Une fonction f, ou un prédicat, faisant parti du langage, est définie de fait sur W selon le principe de construction des structures libres. A savoir en l'absence d'information sur l'algorithme de calcul, on choisie par défaut la structure libre qui permet de définir l'image de n'importe quel élément x par f comme suit : Par exemple, si la variable local x, telle qu'elle est mentionnée dans ce paragraphe, contient l'élément d'expression "g(a,a,h(b))" dans l'univers de Herbrand, alors f(x) est égale à l'élément qui admet comme représentation "f(g(a,a,h(b)))" dans l'univers de Herbrand.
La fonction, ou le prédicat, n'à de sense mathématique commun que définie sur un ensemble. Or W n'est pas un ensemble, c'est un méta-ensemble qui transporte des choix de constructivité arbitraires, des méthodes arbitraires, que nous avons choisie pour construire notre mathématique. Aussi toute propriété fonction ou prédicat relative à W est entachée d'arbitraire. Ce n'est que lorsque le domaine de définition est circonscrit à un ensemble, que la propriété, la fonction, le prédicat ainsi construit, peut prendre un sense commun.
A partir d'une structure, c'est à dire d'un langage et d'une théorie, on peut programmer de nouvelles fonctions en utilisant les fonctions et prédicats de la structure, c'est à dire écrit dans le langage de la structure et complété par les opérations de récursion propre à la programmation des fonctions récurcives. Ces programmes définissent, par des moyens effectifs, de nouvelles fonctions et prédicats que l'on ajoutent au langage de la structure. Néamoins pour chaque fonction et prédicat programmée ainsi, il faut fixer le sense de l'Infinit de Turing, à savoir un autre calcul, tel une valeur particulière par exemple, ou bien l'absence de calcul c'est à dire par défaut l'élément de la structure libre associée. La théorie de la structure enrichie par ces nouvelles fonctions devra pouvoir déduire des propriétés les concernant. On peut construire de nouvelles structures en construisant leurs éléments de la même manière. Et on peut construire dans ces nouvelles structures des fonctions et prédicats de la même manière.
La création de structure généralise la création d'un ensemble. Un ensemble énumérable est créé par une machine qui l'énumère. Un ensemble décidable est créé par un ensemble mère et un prédicat calculable. L'ensemble mère est une structure libre engendré par un nombre fini d'éléments, c'est donc un ensemble énumérable.
On ajoute dans le langage toutes les variables existentiels mentionnées dans les axiomes initiaux de la catégorie des Groupes. Cela consiste à ajouter un élément 1, un prédicat unaire G(.), une fonction binaire *(.,.) et une fonction unaire inverse inv(x). La structure de groupe utilise le langage {G,*,inv,1}. Ces fonctions ou opérateurs, que nous appelons également méthodes en analogie à la programmation object, n'ont aucune implémentation autre que celle par défaut de la composition libre non évaluée.
Nous complétons la structure de groupe en implémentant ses opérateurs. Cela constitue une sorte de conctrétisation de la structure. Mais les algorithmes, pour pouvoir s'effectuer, doivent obligatoirement s'appuyer sur des structures de base sous-jacente préexistantes. Prenons un exemple simple de produit directe. On suppose que le groupe est le produit directe de deux groupes A et B, et on implémente alors ses différentes méthodes comme suit :
1 = (1A, 1B)
x * y = ( PA(x) *A PA(y), PB(x) *B PB(y))
inv(x) = ( invA(PA(x)), invB(PB(x)) )
La représentation d'un élément x du groupe G est décomposé en un couple d'éléments (xA, x B) où xA∈ A et xB∈ B. Les projections sont définies par :
PA((xA, x B)) = xA
PB((xA, x B)) = xB
L'implémention constitue le lien effectif entre les deux structures de groupes A et B, et la structure de groupe G. Si les méthodes des groupes A et B sont calculables et possèdent une complexité, alors l'implémentation rend les méthodes du groupe G calculables et de complexité évaluable. On dira que l'implémentation est paramétrique, qu'elle possède deux parmètres d'entré que sont les groupes A et B.
Et il peut y avoir plusieur implémentions différentes calculant la même chose. La même chose signifiant un lien isomorphique appelé une traduction. Une autre complexité apparait alors, qui est celle des traductions passant d'une implémentation à une autres, et toutes ne sont pas forcement possibles.
La structure de corps est définie par le langage {K,+,-,*,inv,0,1} constitué de :
La théorie est constituée par la conjonction des propriétées suivantes :
Pour tout a,b,c tel que K(a) et K(b) et K(c) nous avons :
Axiome |
Description |
Description groupée |
K(a+b)
|
L'opération + est interne dans K | (K,+) est un groupe commutatif |
(a+b)+c = a+(b+c)
|
L'opération + est associative dans K | |
K(0) | L'opération + possède un élément neutre nommé 0 dans K | |
a+0 = 0+a = a
|
||
K(-a) | Chaque élément possède un symétrique : x-->(-x) dans K | |
a+(-a) = (-a)+a = 0
|
||
a+b = b+a
|
L'opération + est commutative dans K | |
(a<>0 et b<>0) => K(a*b) |
L'opération * est une opération interne dans K-{0} | (K-{0},*) est un groupe |
(a<>0 et b<>0) => (a*b)*c = a*(b*c)
|
L'opération * est associative dans K-{0} | |
1<>0 et K(1) | L'opération * possède un élément neutre nommé 1 dans K-{0} | |
a<>0 => a*1 = 1*a = a
|
||
a<>0 => (K(a-1) et a-1<>0) | Chaque élément possède un symétrique : x-->(x-1) dans K-{0} | |
a<>0 => a*(a-1) = (a-1)*a = 1
|
||
c*(a+b) = (c*a) + (c*b)
|
L'opération * est distributive à droite sur l'opération + dans K | * est
distributive sur + dans K |
(a+b)*c = (a*c) + (b*c)
|
L'opération * est distributive à gauche sur l'opération + dans K |
Noter que inv(a) = a-1
Noter que a+(-a) = (-a)+a = 0 signifie : ∀a ∀b a+b = 0 et b+a = 0
Noter que a<>0 => a*(a-1) = (a-1)*a = 1 signifie : ∀a, ∀c a<>0 => a*c = 1 et c*a = 1.
La structure de corps comprend deux parties que sont le langage et la théorie, et on suppose l'existence de différentes implémentation coexistantes. Cela pourrait ressembler à cela :
I) Langage :
Type |
Arité |
Complexité dans l'implémentation n°1 |
Complexité dans l'implémentation n°2 |
Complexité dans l'implémentation n°3 |
Description |
|
K |
Prédicat |
1 |
10 |
15 |
50 |
Ensemble sous-jacent |
0 |
Fonction |
0 |
1 |
1 |
20 |
Zéro |
1 |
Fonction |
0 |
1 |
5 |
30 |
Un |
+ |
Fonction |
2 |
5 |
2 |
30 |
Addition |
* |
Fonction |
2 |
6 |
8 |
1 |
Multiplication |
- |
Fonction |
1 |
2 |
5 |
55 |
Opposé |
^-1 |
Fonction |
1 |
7
|
20
|
1
|
Inverse |
Complexité des traductions |
Implémentation n°1 |
Implémentation n°2 |
Implémentation n°3 |
Implémentation n°1 |
0 |
10 |
Infinit |
Implémentation n°2 |
5 |
0 |
Infinit |
Implémentation n°3 |
Infinit |
Infinit |
0 |
II) Axiomes :
Axiome |
Description des disjonctions |
Description groupée n°1 |
Déscription groupée n°2 |
Déscription groupée n°3 |
K(a+b) ou ¬K(a) ou ¬K(b) |
Opération interne + dans K | Opération interne + dans K |
(K,+) est un monoïde |
(K,+, -) est un groupe |
(a+b)+c = a+(b+c) ou ¬K(a) ou ¬K(b) ou ¬K(c) |
Associativité de + dans K | Associativité de + dans K |
||
K(0) | 0 appartient à K | 0 est l'élément neutre pour + dans K |
||
a+0 = a ou ¬K(a) |
0 est l'élément neutre à droite pour + dans K | |||
0+a = a ou ¬K(a) | 0 est l'élément neutre à gauche pour + dans K | |||
K(-a) ou ¬K(a) | Opération interne - dans K | (-x) est l'opposé de x pour + dans K |
(-x) est l'opposé de x pour + dans K |
|
a+(-a) = 0 ou ¬K(a) |
(-x) est l'opposé de x à droite pour + dans K | |||
(-a)+a = 0 ou ¬K(a) | (-x) est l'opposé de x à gauche pour + dans K | |||
a+b = b+a ou ¬K(a) ou ¬K(b) |
Commutativité de + dans K | Commutativité de + dans K |
Commutativité de + dans K |
Commutativité de + dans K |
K(a*b) ou ¬K(a) ou ¬K(b) |
Opération interne * dans K | Opération interne * dans K |
(K,+) est un monoïde |
(K-{0},+,-) est un groupe |
(a*b)*c = a*(b*c) ou ¬K(a) ou ¬K(b) ou ¬K(c) |
Associativité de * dans K | Associativité de * dans K |
||
K(1) | 1 appartient à K | 1 est l'élément neutre pour * dans K |
||
a*1 = a ou ¬K(a) |
1 est l'élément neutre à droite pour * dans K | |||
1*a = a ou ¬K(a) | 1 est l'élément neutre à gauche pour * dans K | |||
a*(a-1) = 1 ou a=0 ou ¬K(a) |
(x-1) est l'inverse de x à droite pour * dans K-{0} | (x-1) est l'inverse de x pour * dans K-{0} |
(x-1) est l'inverse de x pour * dans K-{0} |
|
(a-1)*a = 1 ou a=0 ou ¬K(a) | (x-1) est l'inverse de x à gauche pour * dans K-{0} | |||
c*(a+b) = (c*a) + (c*b) ou ¬K(a) ou ¬K(b) ou ¬K(c) |
Distributivité à droite de * sur + dans K | Distributivité de * sur + dans K |
Distributivité de * sur + dans K |
Distributivité de * sur + dans K |
(a+b)*c = (a*c) + (b*c) ou ¬K(a) ou ¬K(b) ou ¬K(c) |
Distributivité à gauche de * sur + dans K |
L'aspect implémentation (en marron) apporte des informations sur les différents algorithmes de calculs mis à dispositions par la structure. L'aspect descriptif (en vert) apporte des informations intuitives sur les axiomes qui peuvent être groupés de différentes façons et qui prédisposent à une hiérarchie.
On peut construire à partir d'une ou plusieurs structures, de nouvelles structures. Les éléments de la nouvelle structure sont calculés à l'aide d'une fonction qu'il faut programmé dans le langage des structures initiales. Et le opérateurs de la nouvelle structure peuvent être programmés également dans le langage des structures initiales. La nouvelle structure est alors une émanation des structures initiales.
Par exemple définissons la structure des matrices 2 fois 2 sur un corps K. Les éléments sont des quadruplet d'éléments du corps K tel que par exemple :
(x00, x01, x10, x11)
L'opérations d'adition est définie par :
(x00, x01, x10, x11) + (y00, y01, y10, y11) = (x00+y00, x01+y01, x10+y10, x11+y11)
L'opérations de multiplication est définie par
(x00, x01, x10, x11) * (y00, y01, y10, y11) = (x00*y00 + x01*y10, x00*y01 + x01*y11, x10*y00 + x11*y10, x10*y01 + x11*y11)
Les opérations matriciels + et * sont programmés dans le langage de la catégorie des corps, et plus exactement programmés à partir de la seul fonction * et + de la catégorie des corps et sans utiliser aucune propriété du corps, mais par contre utilise la structure (Z/2Z)² et d'une manière plus générale, utilise la structure des entiers. La programmation utilise nécessairement la structure des entiers, et cette structure contient l'arithmétique effective et donc contient toutes les mathématiques effectives.
Par contre pour que la nouvelle structure possède les propriétés suivantes :
Il suffit d'avoir dans la structure K, l'associativité de *, l'associativité de +, la distributivité à droite de * sur + et la distributivité à gauche de * sur +. Et cela est contenue dans la catégorie des corps.
On appellera émanations de la structures, les nouvelles structures construites de cette façon. Toute sorte de construction sont délors possible, et nous devrons définir un critère de pertinence.