L'utilisation de l'IA pour programmer nous libère d'une tache fastidieuse qu'est l'application de la syntaxe de programmation, et nous permet de nous concentrer sur les algorithmes et les structures mises en oeuvre.
Elle permet d'entreprendre facilement des recherches mathématiques empiriques. De telles recherches s'accompagnent de la création de frameworks et de bibliothèques spécialisées, autrement-dit, d'une implémentation de structures et d'algorithmes, dont la pertinence peut égaler voir dépasser les objets mathématiques qu'elles veulent sonder. L'IA change donc d'une certaine façon notre vision des mathématiques, donnant davantage de pertinence aux constructions intermédiaires qu'aux l'objets finaux.
On l'expérimente dans l'étude des monoïdes bis-gènes de façon empirique en utilisant le langage de programmation Python. On représente le monoïde engendré par deux éléments `a,b`, par un graphe orienté où les sommets sont les éléments du monoïde. Chaque sommet possède deux arrètes partantes libéllées `a` et `b`. Le sommet racine est l'élément neutre du monoïde. Et pour chaque sommet `x`, l'arrête libéllée `a` partant de `x` arrive sur le sommet `x"*"a`, et l'arrête libéllée `b` partant de `x` arrive sur le sommet `x"*"b`, où `"*"` est la loi du monoïde.
Créer un dossier Python1 et exécuter la commande : python -m venv env1
Une foix créée. Pour activer l'environnement virtuel : source env1/bin/activate
Pour desactiver l'environnement virtuel : deactivate
Pour installer le module python numpy dans l'environnement virtuel, activez-le et exécuter : pip install numpy
Pour lister les modules installés : pip list.
Pour lancer Python : python
Pour exécuter un script python a.py et ouvrir l'interpéteur qui l'a exécuté : python -i a.py
Pour exécuter un script python a.py dans l'interpéteur :
with open("a.py") as f:
exec(f.read())
Pour exécuter le code python (qui contient le bloc if __name__ == "__main__":) :
from a import *
L'IA progresse par les analogies qu'elle tisse. C'est pourquoi on commence par solliciter ses compètences sur le domaine concerné ce qui nous renseigne sur le langage qu'utilise l'IA :
Donnes-nous la définition concise d'un monoïde bis-gène ? |
Un monoïde bis-gène est un monoïde engendré par deux éléments, c’est-à-dire un ensemble muni d’une opération associative avec un élément neutre, dans lequel tous les éléments peuvent s’écrire comme des combinaisons finies (par l’opération) de deux générateurs. |
Puis on fait remarquer une autre analogie où les éléments générateurs correspondent à des voies (des transitions) possibles à partir de chaque élément. Indiquer cette analogie est importante. Elle permet à l'IA de prolonger cette analogie presque naturellement.
A partir d'un élément quelconque `x`, si on empreinte une voix `a`, alors on arrive sur l'élément `xa`, produit de `x` par `a` selon la loi du monoïde. Ainsi la combinaison finie (par l'opération) telle que par exemple `aaba`, désigne un chemin précis partant de `1` pour aboutire à l'élément `aaba`
On considère les éléments générateurs comme des voies possibles. Une combinaison finie (par l'opération) constitue un chemin partant de l'élément neutre pour aller sur l'élément correspondant à la combinaison en question |
Exactement, et cette interprétation permet une visualisation naturelle du monoïde bis-gène sous forme de graphe orienté.
Voici la reformulation dans ce cadre :
Cela en fait une structure navigable :
Souhaites-tu qu’on exprime cela sous forme mathématique, graphique ou en code ? |
On reprend la terminologie utilisé par l'IA. On définit la structure de données. C'est une immense liste de cellules, et chaque cellule contient 4 index et 16 flags. On choisit comme index des nombres entiers non-signés tenant sur 4 octets. La cellule occupe donc 18 octets. On utilise ChatGPT pour faire la programmation :
Le monoïde est mémorisé sous forme d'un graphe. Chaque sommet possède deux arêtes partantes libellées `a` et `b`. Le sommet racine est l'élément neutre du monoïde. Et pour chaque sommet `x`, l'arête libellée `a` partant de `x` arrive sur le sommet `x"*"a`, et l'arête libellée `b` partant de `x` arrive sur le sommet `x"*"b`, où `"*"` est la loi du monoïde.
On commence par étape un programme en python qui aura pour but de construire ce graphe en mémoire. On utilise le module numpy qui permet de manipuler des tableaux de façon efficace. On définit le type cellule, structuré comme suit, et qui doit être de taille minimale :
On crée un tableau `M` uni-dimensionnel de 100_000 cellules libres initialisées comme suit : Chaque cellule est désignée par son Indexe dans `M`. La cellule `M[0]` n'est pas utilisée. L'index `0` qui est la valeur minimal représente le rien. Pour chaque cellule libre, l'attribut `L` contient l'indexe de la cellule libre suivante, et la dernière cellule contient comme attribut `L` la valeur `0` qui représente le rien. On crée le premier noeud qui correspond à l'élément neutre du monoïde en `M[1]`.
Les enfants `M[1]"."a` et `M[1]"."b` n'étant pas encore définit, ils ont la valeur `0`. Les cellules occupées sont appelées des nœuds, et correspondent au sommet du graphe, et correspondent aux éléments du monoïde. |
||
Parfait, tu as déjà posé les bases très précisément. Voici l’implémentation Python correspondant à cette première étape de la construction du graphe du monoïde bis-gène :
Résumé :
Souhaites-tu que l’on continue avec l’étape suivante, c’est-à-dire l’ajout dynamique de nouveaux nœuds à partir du neutre en suivant les générateurs `a` et `b` ? |
||
Programme la fonctions `"get_u"(x,i)` qui retourne la valeur du `i` ième bit du champ `u` de la cellule `M[x]` | ||
Voici la fonction `"get_u"(x, i)` en Python, qui retourne la valeur du `i`ᵉ bit du champ `u` de la cellule `M[x]` :
Détails :
Exemple d’utilisation :
Souhaites-tu que je code aussi la fonction complémentaire `"set_u"(x, i, "value")` pour modifier un bit ? |
||
Oui | ||
Voici la fonction `"set_u"(x, i, "value")` qui modifie le `i`ᵉ bit du champ `u` de la cellule `M[x]`, selon que `"value"` vaut `0` ou `1` :
Exemple d’utilisation :
Souhaites-tu une fonction pour basculer (inverser) un bit (toggle_u) aussi ? |
||
Oui | ||
Voici la fonction toggle_u`(x, i)` qui inverse (bascule) le `i`ᵉ bit du champ `u` de la cellule `M[x]` :
Exemple d’utilisation :
Tu as maintenant un trio de fonctions pour manipuler efficacement les flags dans le champ `u` :
Souhaites-tu maintenant ajouter une fonction pour allouer dynamiquement un nouveau nœud (c’est-à-dire sortir une cellule de la liste libre et l’initialiser) ? |
||
Oui | ||
Voici la fonction alloc() qui alloue dynamiquement un nouveau nœud (cellule) depuis la liste libre, l’initialise, et met à jour la variable globale `L` :
Exemple d’utilisation :
Résumé des effets :
Souhaites-tu que je code aussi la fonction free`(x)` pour libérer une cellule (la remettre dans la liste libre) ? |
||
Oui | ||
Voici la fonction free`(x)` qui libère une cellule occupée (nœud) et la remet en tête de la liste chaînée des cellules libres :
Exemple d’utilisation :
Résumé :
|
La génération de code par petites étapes, permet à l'IA de générer une description détaillée qui peut être enrichie d'analogies. Ainsi nous l'encourageons à causer. Cela nous permet de désigner nos souhaits de développement en utilisant les bons mots, ceux utilisés par l'IA, pour établir la correspondance et désigner les bonnes analogies.
On crée une fonction pour se déplacer dans le graphe à partir d'un noeud `x`, et en choisissant une voie `a` ou `b`
On crée une fonction pour se déplacer dans le graphe à partir d'un noeud `x`, et en choisissant une voie `a` ou `b`, et si le noeud n'existe pas on le crée. | ||
Voici la fonction move(`x`, label) qui permet de se déplacer dans le graphe à partir d’un nœud `x` selon la voie 'a' ou 'b', et de créer dynamiquement le nœud destination si nécessaire :
Exemple d’utilisation :
Comportement :
Souhaites-tu maintenant une fonction pour construire automatiquement tous les éléments du monoïde jusqu’à une certaine profondeur ? |
||
Crée une fonction générique qui prend un nœud `x` de départ et un mot complet (ex: `abaab`) et construit le chemin correspondant dans le graphe partant du nœud `x` | ||
Voici la fonction build_path(`x`, mot) qui, à partir d’un nœud de départ `x` et d’un mot sur les lettres 'a' et 'b', construit (si nécessaire) et retourne l’index du nœud d’arrivée après avoir suivi ce mot dans le graphe :
Exemple d’utilisation :
Ce que fait la fonction :
Souhaites-tu ajouter une fonction inverse, pour retrouver le mot menant à un nœud donné à partir du neutre (si le graphe est construit jusque-là) ? |