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 Monoide import MonoideAleatoire
import random
import copy
import itertools
......@@ -8,7 +9,7 @@ class GrapheCompositionAleatoire(GC):
"""Construit un graphe de composition aléatoire."""
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,
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
......@@ -22,61 +23,28 @@ class GrapheCompositionAleatoire(GC):
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
self |= i
self |= {i}
for i in range(nb_morph): # ajout des morphismes
source = 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
for obj in sorted(self.objets):
cycles = sorted(self.trouver_cycles_minimaux(obj,inclure_id=False))
arbre_composition = {cycle:"a determiner" for cycle in cycles}
# {noeud_arbre : image_cycle}
profondeur_cycle = {self.identite(obj):0} #cycle: profondeur dans l'arbre de composition
for cycle in cycles:
profondeur_cycle[cycle] = 1
while list(arbre_composition.values()).count("a determiner") > 0:
for cle in copy.copy(arbre_composition):
if arbre_composition[cle] == "a determiner":
if random.random() < proba_brancher**(profondeur_cycle[cle]-(1 if len(cle) == 1 else 0)):
# ici on branche, plus la profondeur est grande, plus la proba de brancher est petite
print("on branche ",proba_brancher**(profondeur_cycle[cle]-(1 if len(cle) == 1 else 0)))
arbre_composition[cle] = None
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
for obj in self.objets:
cycles_minimaux = self.trouver_cycles_minimaux(obj,inclure_id=False)
cycles_finaux = cycles_minimaux
cycles_graines = set(cycles_minimaux) # cycles qui ont un chance de brancher
while len(cycles_graines) > 0:
cycle = cycles_graines.pop()
if random.random() < proba_brancher:
#on branche
nouveaux_cycles = {c@cycle for c in cycles_minimaux}
cycles_finaux |= nouveaux_cycles
cycles_graines |= nouveaux_cycles
#maintenant on a tous les cycles finaux
nb_cycles = len(cycles_finaux)+1
monoide_alea = MonoideAleatoire()
if PRINT_AVANCEMENT_CREATION_CAT_ALEA:
......
......@@ -44,7 +44,6 @@ class CategorieProduit(Categorie,tuple):
result = set()
for source in sources:
for cible in cibles:
print(source,cible)
if len(source) != len(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)))):
......
......@@ -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.
ces deux méthodes définissent le graphe sous-jacent avec les objets de la catégorie"""
def __init__(self, nom:str = "Monoide"):
CategorieLibre.__init__(self,{1},nom)
def __init__(self, objet:any = 1, nom:str = "Monoide"):
CategorieLibre.__init__(self,{objet},nom)
def __ior__(self, objets:any):
def __ior__(self, objets:set):
if objets == {1}:
CategorieLibre.__ior__(self,{1})
return self
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))
def existe_morphisme(self, source:any, cible:any) -> bool:
......@@ -64,7 +64,7 @@ class MonoideGC(GrapheDeComposition,Monoide):
def __init__(self,nom:str = "MonoïdeGC"):
GrapheDeComposition.__init__(self,{1},nom)
Monoide.__init__(self,nom)
Monoide.__init__(self,nom=nom)
def identite(self, objet:any = None) -> ElementMonoideGC:
return GrapheDeComposition.identite(self,1)
......@@ -159,31 +159,34 @@ def facteurs_premiers(n):
yield n
break
class MonoideAleatoire(Monoide):
class MonoideAleatoire(CategorieProduit,Monoide):
"""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 (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."""
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:
print("Début de création d'un monoïde à "+str(nb_elements)+" éléments")
while max(facteurs_premiers(nb_elements)) > 5:
nb_elements -= 1
if DEBUG_MONOIDE_ALEATOIRE:
print("Simplification du nombre d'éléments à "+str(nb_elements))
petits_monoides = [PetitMonoideAleatoire(x) for x in facteurs_premiers(nb_elements)]
Monoide.__init__(self,nom)
self.__produit = CategorieProduit(*petits_monoides)
petits_monoides = tuple(PetitMonoideAleatoire(x) for x in facteurs_premiers(nb_elements))
instance = super().__new__(cls,*petits_monoides)
if DEBUG_MONOIDE_ALEATOIRE:
print("Fin de création d'un monoïde à "+str(nb_elements)+" éléments")
return instance
def __init__(self, nb_elements:int = random.randint(1,20), nom:str = "Monoïde aléatoire"):
CategorieProduit.__init__(self,*self)
Monoide.__init__(self,tuple(1 for i in range(len(self))),nom)
def identite(self, objet:any) -> Morphisme:
print(objet)
return self.__produit.identite(tuple(objet for i in range(len(self.__produit))))
def __ior__(self, objets:set):
if objets == {tuple(1 for i in range(len(self)))}:
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 __call__(self, sources:set, cibles:set) -> set:
return self.__produit({tuple(source for i in range(len(self.__produit))) for source in sources},
{tuple(cible for i in range(len(self.__produit))) for cible in cibles})
def test_MonoideGC():
random.seed(22453)
......@@ -191,9 +194,9 @@ def test_MonoideGC():
mon.transformer_graphviz()
mon.loi_de_composition_to_csv()
mon = MonoideAleatoire(27)
mon = MonoideAleatoire(7)
mon.transformer_graphviz()
mon.loi_de_composition_to_csv()
mon.loi_de_composition_to_csv(destination="lois de composition/monoide.csv")
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