Commit 79cc5242 authored by Guillaume Sabbagh's avatar Guillaume Sabbagh
Browse files

Remaniement de catégorie aléatoire

parent 96972d7a
from GrapheDeComposition import GC,MGC from GrapheDeComposition import GC,MGC
from Monoide import MonoideAleatoire
import random import random
import copy import copy
import itertools import itertools
...@@ -8,7 +9,7 @@ class GrapheCompositionAleatoire(GC): ...@@ -8,7 +9,7 @@ class GrapheCompositionAleatoire(GC):
"""Construit un graphe de composition aléatoire.""" """Construit un graphe de composition aléatoire."""
def __init__(self, nb_objets = None, nb_morph = None, proba_brancher:float=1/100): def __init__(self, nb_objets = None, nb_morph = None, proba_brancher:float=1/100):
"""`nb_morph` est le nombre de morphismes élémentaires à ajouter aléatoirement, certains seront supprimés après. """`nb_morph` est le nombre de morphismes élémentaires à ajouter aléatoirement.
`proba_brancher` est la probabilité de brancher lors de la création de l'arbre de composition des cycles, `proba_brancher` est la probabilité de brancher lors de la création de l'arbre de composition des cycles,
Plus la probabilité est grande plus il y aura de cycles et plus la loi de composition ne sera pas triviale. Plus la probabilité est grande plus il y aura de cycles et plus la loi de composition ne sera pas triviale.
Si la probabilité est 0, tous les cycles seront des isomorphismes Si la probabilité est 0, tous les cycles seront des isomorphismes
...@@ -22,61 +23,28 @@ class GrapheCompositionAleatoire(GC): ...@@ -22,61 +23,28 @@ class GrapheCompositionAleatoire(GC):
print("Création d'une catégorie avec "+str(nb_objets)+" objets et "+str(nb_morph)+" morphismes") print("Création d'une catégorie avec "+str(nb_objets)+" objets et "+str(nb_morph)+" morphismes")
for i in range(nb_objets): #ajout des objets for i in range(nb_objets): #ajout des objets
self |= i self |= {i}
for i in range(nb_morph): # ajout des morphismes for i in range(nb_morph): # ajout des morphismes
source = random.randint(0,nb_objets-1) source = random.randint(0,nb_objets-1)
cible = random.randint(0,nb_objets-1) cible = random.randint(0,nb_objets-1)
self |= MGC(source,cible) self |= {MGC(source,cible)}
## on définit la loi de composition pour les cycles ## on définit la loi de composition pour les cycles
for obj in sorted(self.objets): for obj in self.objets:
cycles = sorted(self.trouver_cycles_minimaux(obj,inclure_id=False)) cycles_minimaux = self.trouver_cycles_minimaux(obj,inclure_id=False)
arbre_composition = {cycle:"a determiner" for cycle in cycles} cycles_finaux = cycles_minimaux
# {noeud_arbre : image_cycle} cycles_graines = set(cycles_minimaux) # cycles qui ont un chance de brancher
profondeur_cycle = {self.identite(obj):0} #cycle: profondeur dans l'arbre de composition while len(cycles_graines) > 0:
for cycle in cycles: cycle = cycles_graines.pop()
profondeur_cycle[cycle] = 1 if random.random() < proba_brancher:
while list(arbre_composition.values()).count("a determiner") > 0: #on branche
for cle in copy.copy(arbre_composition): nouveaux_cycles = {c@cycle for c in cycles_minimaux}
if arbre_composition[cle] == "a determiner": cycles_finaux |= nouveaux_cycles
if random.random() < proba_brancher**(profondeur_cycle[cle]-(1 if len(cle) == 1 else 0)): cycles_graines |= nouveaux_cycles
# ici on branche, plus la profondeur est grande, plus la proba de brancher est petite #maintenant on a tous les cycles finaux
print("on branche ",proba_brancher**(profondeur_cycle[cle]-(1 if len(cle) == 1 else 0))) nb_cycles = len(cycles_finaux)+1
arbre_composition[cle] = None monoide_alea = MonoideAleatoire()
for cycle in cycles:
arbre_composition[cycle@cle]="a determiner"
profondeur_cycle[cycle@cle] = profondeur_cycle[cle]+1
else: # ici on doit simplifier le cycle
print("on simplifie")
cycles_candidats = [cycle for cycle in profondeur_cycle if profondeur_cycle[cycle] < profondeur_cycle[cle]]
arbre_composition[cle]=random.choice(cycles_candidats)
for cycle in arbre_composition:
if arbre_composition[cycle] != None:
assert(len(cycle) != 1)
MGC.identifier_morphismes(cycle,arbre_composition[cycle])
print(obj,cycles)
print("=======")
for cle in arbre_composition:
print(cle," : ",arbre_composition[cle])
## On retire les doubles isomorphismes (fog = fog'= Id et gof = g'of = Id)
for source,cible in itertools.product(self.objets,repeat=2):
suppression_inverses = True
while suppression_inverses:
suppression_inverses = False
for f in sorted(self(source,cible)-{self.identite(source)}): #on retire les identités si source == cible
inverses = {g for g in self(cible,source) if (f@g).is_identite and (g@f).is_identite}
if len(inverses) > 1:
#on doit retirer des inverses
suppression_inverses = True
inverse_a_suppr = sorted(list(inverses),key=len)[0]
if len(inverse_a_suppr) == 1:
print("suppression inverse ",inverse_a_suppr)
self -= inverse_a_suppr
else:
print("suppression inverse ",inverse_a_suppr[0])
self -= inverse_a_suppr[0]
break
if PRINT_AVANCEMENT_CREATION_CAT_ALEA: if PRINT_AVANCEMENT_CREATION_CAT_ALEA:
......
...@@ -44,7 +44,6 @@ class CategorieProduit(Categorie,tuple): ...@@ -44,7 +44,6 @@ class CategorieProduit(Categorie,tuple):
result = set() result = set()
for source in sources: for source in sources:
for cible in cibles: for cible in cibles:
print(source,cible)
if len(source) != len(cible): if len(source) != len(cible):
raise Exception("Source et cible de taille différente "+str(source)+" "+str(cible)) raise Exception("Source et cible de taille différente "+str(source)+" "+str(cible))
for nuplet in itertools.product(*tuple(self[i]({source[i]},{cible[i]}) for i in range(len(source)))): for nuplet in itertools.product(*tuple(self[i]({source[i]},{cible[i]}) for i in range(len(source)))):
......
...@@ -25,16 +25,16 @@ class Monoide(CategorieLibre): ...@@ -25,16 +25,16 @@ class Monoide(CategorieLibre):
- elements(self) -> set : renvoie l'ensemble des éléments du Monoïde où chaque élément est un ElementMonoide. - elements(self) -> set : renvoie l'ensemble des éléments du Monoïde où chaque élément est un ElementMonoide.
ces deux méthodes définissent le graphe sous-jacent avec les objets de la catégorie""" ces deux méthodes définissent le graphe sous-jacent avec les objets de la catégorie"""
def __init__(self, nom:str = "Monoide"): def __init__(self, objet:any = 1, nom:str = "Monoide"):
CategorieLibre.__init__(self,{1},nom) CategorieLibre.__init__(self,{objet},nom)
def __ior__(self, objets:any): def __ior__(self, objets:set):
if objets == {1}: if objets == {1}:
CategorieLibre.__ior__(self,{1}) CategorieLibre.__ior__(self,{1})
return self return self
raise Exception("Tentative d'ajout d'un objet à un monoide : "+str(objets)) raise Exception("Tentative d'ajout d'un objet à un monoide : "+str(objets))
def __isub__(self, objets:any): def __isub__(self, objets:set):
raise Exception("Tentative de retirer un objet à un monoide : "+str(objets)) raise Exception("Tentative de retirer un objet à un monoide : "+str(objets))
def existe_morphisme(self, source:any, cible:any) -> bool: def existe_morphisme(self, source:any, cible:any) -> bool:
...@@ -64,7 +64,7 @@ class MonoideGC(GrapheDeComposition,Monoide): ...@@ -64,7 +64,7 @@ class MonoideGC(GrapheDeComposition,Monoide):
def __init__(self,nom:str = "MonoïdeGC"): def __init__(self,nom:str = "MonoïdeGC"):
GrapheDeComposition.__init__(self,{1},nom) GrapheDeComposition.__init__(self,{1},nom)
Monoide.__init__(self,nom) Monoide.__init__(self,nom=nom)
def identite(self, objet:any = None) -> ElementMonoideGC: def identite(self, objet:any = None) -> ElementMonoideGC:
return GrapheDeComposition.identite(self,1) return GrapheDeComposition.identite(self,1)
...@@ -159,31 +159,34 @@ def facteurs_premiers(n): ...@@ -159,31 +159,34 @@ def facteurs_premiers(n):
yield n yield n
break break
class MonoideAleatoire(Monoide): class MonoideAleatoire(CategorieProduit,Monoide):
"""Monoïde dont la table de loi de composition interne est tirée aléatoirement. """Monoïde dont la table de loi de composition interne est tirée aléatoirement.
Si le nombre d'éléments du monoïde est supérieur à 5, on créé un produit de `PetitMonoideAleatoire`. Si le nombre d'éléments du monoïde est supérieur à 5, on créé un produit de `PetitMonoideAleatoire`.
Si le (grand) nombre d'éléments est premier ou peu décomposable, on se réserve le droit de changer Si le (grand) nombre d'éléments est premier ou peu décomposable, on se réserve le droit de changer
le nombre d'élément pour qu'il soit factorisable en facteurs inferieurs ou égaux à 5.""" le nombre d'élément pour qu'il soit factorisable en facteurs inferieurs ou égaux à 5."""
def __init__(self, nb_elements:int = random.randint(1,20), nom:str = "Monoïde aléatoire"): def __new__(cls, nb_elements:int = random.randint(1,20), nom:str = "Monoïde aléatoire"):
if DEBUG_MONOIDE_ALEATOIRE: if DEBUG_MONOIDE_ALEATOIRE:
print("Début de création d'un monoïde à "+str(nb_elements)+" éléments") print("Début de création d'un monoïde à "+str(nb_elements)+" éléments")
while max(facteurs_premiers(nb_elements)) > 5: while max(facteurs_premiers(nb_elements)) > 5:
nb_elements -= 1 nb_elements -= 1
if DEBUG_MONOIDE_ALEATOIRE: if DEBUG_MONOIDE_ALEATOIRE:
print("Simplification du nombre d'éléments à "+str(nb_elements)) print("Simplification du nombre d'éléments à "+str(nb_elements))
petits_monoides = [PetitMonoideAleatoire(x) for x in facteurs_premiers(nb_elements)] petits_monoides = tuple(PetitMonoideAleatoire(x) for x in facteurs_premiers(nb_elements))
Monoide.__init__(self,nom) instance = super().__new__(cls,*petits_monoides)
self.__produit = CategorieProduit(*petits_monoides)
if DEBUG_MONOIDE_ALEATOIRE: if DEBUG_MONOIDE_ALEATOIRE:
print("Fin de création d'un monoïde à "+str(nb_elements)+" éléments") print("Fin de création d'un monoïde à "+str(nb_elements)+" éléments")
return instance
def identite(self, objet:any) -> Morphisme: def __init__(self, nb_elements:int = random.randint(1,20), nom:str = "Monoïde aléatoire"):
print(objet) CategorieProduit.__init__(self,*self)
return self.__produit.identite(tuple(objet for i in range(len(self.__produit)))) Monoide.__init__(self,tuple(1 for i in range(len(self))),nom)
def __call__(self, sources:set, cibles:set) -> set: def __ior__(self, objets:set):
return self.__produit({tuple(source for i in range(len(self.__produit))) for source in sources}, if objets == {tuple(1 for i in range(len(self)))}:
{tuple(cible for i in range(len(self.__produit))) for cible in cibles}) CategorieLibre.__ior__(self,{tuple(1 for i in range(len(self)))})
return self
raise Exception("Tentative d'ajout d'un objet à un monoide : "+str(objets))
def test_MonoideGC(): def test_MonoideGC():
random.seed(22453) random.seed(22453)
...@@ -191,9 +194,9 @@ def test_MonoideGC(): ...@@ -191,9 +194,9 @@ def test_MonoideGC():
mon.transformer_graphviz() mon.transformer_graphviz()
mon.loi_de_composition_to_csv() mon.loi_de_composition_to_csv()
mon = MonoideAleatoire(27) mon = MonoideAleatoire(7)
mon.transformer_graphviz() mon.transformer_graphviz()
mon.loi_de_composition_to_csv() mon.loi_de_composition_to_csv(destination="lois de composition/monoide.csv")
if __name__ == '__main__': if __name__ == '__main__':
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment