Commit 3a861906 authored by Guillaume Sabbagh's avatar Guillaume Sabbagh
Browse files

correction Catégorie aléatoire

parent cdc556a0
from GrapheDeComposition import GC,MGC
from Monoide import MonoideAleatoire
from Monoide import Monoide,ElementMonoideGC,MonoideGC
from CategorieProduit import CategorieProduit
from CategorieLibre import CategorieLibre
import random
import copy
import itertools
from collections import defaultdict
from config import *
from typing import *
from graphviz import Digraph
class GrapheCompositionAleatoire(GC):
"""Construit un graphe de composition aléatoire."""
def __init__(self, nb_fleches:int = None, proba_arreter_generation_loi_de_compo:float = 1/100,nom:str = "Catégorie Aléatoire"):
def __init__(self, nb_fleches:Union[int,None] = None, nb_tentatives_complexification_loi_de_compo:int = 1000,nom:str = "Catégorie Aléatoire"):
"""`nb_fleches` est le nombre de flèches élémentaires dans la catégorie aléatoire.
`nb_tentatives_complexification_loi_de_compo` détermine à quel point la loi de composition sera complexifiée,
si le nombre est faible on obtient une catégorie où les flèches sont isolées."""
if nb_fleches == None:
nb_fleches = random.randint(1,30)
nb_fleches = random.randint(1,20)
GC.__init__(self,nom=nom)
table = defaultdict(lambda:None)
i,j = random.randint(0,nb_fleches-1),random.randint(0,nb_fleches-1)
cases_modifiees = set()
while random.random() > proba_arreter_generation_loi_de_compo:
for tentative in range(nb_tentatives_complexification_loi_de_compo):
cases_modifiees |= {(i,j)}
if table[(i,j)] == None:
table[(i,j)] = random.randint(0,nb_fleches-1)
......@@ -32,24 +40,36 @@ class GrapheCompositionAleatoire(GC):
if cases_modifiees == set():
# l'associativité n'est pas vérifiée
continue
erreur_compo = False
for a,b in itertools.product(range(nb_fleches),repeat=2):
if table[(a,b)] != None:
for c in range(nb_fleches):
if table[(table[(a,b)],c)] != None and table[(b,c)] == None:
# les compositions ne sont pas respectées
i,j = b,c
erreur_compo = True
break
if table[(table[(a,b)],c)] == None and table[(b,c)] != None:
# les compositions ne sont pas respectées
i,j = table[(a,b)],c
erreur_compo = True
break
else:
continue
break
else:
if table[(c,table[(a,b)])] != None and table[(c,a)] == None:
# les compositions ne sont pas respectées
i,j = c,a
erreur_compo = True
break
if table[(c,table[(a,b)])] == None and table[(c,a)] != None:
# les compositions ne sont pas respectées
i,j = c,table[(a,b)]
erreur_compo = True
break
if not erreur_compo:
#il n'y a eu aucune erreur de composition on valide les changements
cases_modifiees = set()
i,j = random.randint(0,nb_fleches-1),random.randint(0,nb_fleches-1)
i,j = random.randint(0,nb_fleches-1),random.randint(0,nb_fleches-1)
else:
i,j = random.randint(0,nb_fleches-1),random.randint(0,nb_fleches-1)
#on a une table de loi de composition aléatoire
graphe_equiv = defaultdict(set)
......@@ -87,10 +107,9 @@ class GrapheCompositionAleatoire(GC):
for i,j in itertools.product(range(nb_fleches),repeat=2):
if table[(i,j)] != None:
MGC.identifier_morphismes(fleches[j]@fleches[i],fleches[table[(i,j)]])
def test_GrapheCompositionAleatoire():
random.seed(1)
for i in range(20):
......@@ -99,7 +118,243 @@ def test_GrapheCompositionAleatoire():
GCA.loi_de_composition_to_csv('lois de composition/loi_de_compo.csv')
return GCA
class PetitMonoideAleatoire(MonoideGC):
"""Monoïde fini dont la table de loi de composition interne est choisie aléatoirement.
Les éléments du monoïde seront des flèches nommées par des nombres allant de 1
jusqu'au nombre d'éléments moins un sauf l'identité qui représente l'élément neutre.
La taille maximale de ce monoïde est 5, sinon le temps de calcul est trop grand.
Pour un monoïde aléatoire plus grand, faire un produit de `PetitMonoideAleatoire`."""
def __init__(self, nb_elements:Union[int,None] = None, nom:str = "Petit monoïde aléatoire"):
"""`nb_elements` est le nombre d'éléments du monoïde, si `nb_elements` = 1, alors il n'y a que l'identité dans le monoïde.
`nb_elements` doit être inférieur à 5, sinon le temps de calcul est trop long.
Pour un monoïde plus grand, utiliser `MonoideAleatoire`."""
if DEBUG_MONOIDE_ALEATOIRE:
print("Début de création d'un monoïde à "+str(nb_elements)+" éléments")
if nb_elements == None:
nb_elements = random.randint(1,5)
if nb_elements > 5:
raise Exception("Le nombre d'elements d'un PetitMonoideAleatoire doit etre inferieur ou egal a 5.")
elements = list(range(nb_elements)) #le 0 va représenter l'identité
associativite_verifiee = False
while not associativite_verifiee:
table = dict()
associativite_verifiee = True
for a,b in itertools.product(elements,repeat=2):
if (a,b) not in table:
table[(a,b)] = random.choice(elements) if a*b != 0 else a+b
# si a ou b est 0 (le produit est 0) alors on renvoie l'autre element (a+b vaut l'autre element puisque 0 est neutre par l'addition)
# on force l'associativité si on peut
for c in elements:
if (table[(a,b)],c) in table and (b,c) in table:
if (a,table[(b,c)]) not in table:
table[(a,table[(b,c)])] = table[(table[(a,b)],c)]
elif table[(table[(a,b)],c)] != table[(a,table[(b,c)])]:
associativite_verifiee = False
table[(a,table[(b,c)])] = table[(table[(a,b)],c)]
break
if (c,table[(a,b)]) in table and (c,a) in table:
if (table[(c,a)],b) not in table:
table[(table[(c,a)],b)] = table[(c,table[(a,b)])]
elif table[(table[(c,a)],b)] != table[(c,table[(a,b)])]:
associativite_verifiee = False
break
else:
continue
break
if not associativite_verifiee:
continue
#on a une table aléatoire
#maintenant on vérifie l'associativité
associativite_verifiee = False
for a,b,c in itertools.product(elements,repeat=3):
if table[(table[(a,b)],c)] != table[(a,table[(b,c)])]:
break
else:
associativite_verifiee = True
# on a notre table de composition
MonoideGC.__init__(self,nom)
fleches = {i:ElementMonoideGC(str(i)) for i in range(1,nb_elements)}
fleches[0] = self.identite()
self |= {fleches[i] for i in range(1,nb_elements)}
for a,b in itertools.product(elements,repeat=2):
if fleches[a]@fleches[b] != fleches[table[(a,b)]]:
MGC.identifier_morphismes(fleches[a]@fleches[b],fleches[table[(a,b)]])
if DEBUG_MONOIDE_ALEATOIRE:
print("Fin de création d'un monoïde à "+str(nb_elements)+" éléments")
def facteurs_premiers(n):
while n > 1:
for i in range(2, int(n**0.5)+1):
if not n % i:
n //= i
yield i
break
else:
yield n
break
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 __new__(cls, nb_elements:Union[int,None] = None, 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")
if nb_elements == None:
nb_elements = random.randint(1,20)
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 = tuple(PetitMonoideAleatoire(x) for x in facteurs_premiers(nb_elements))
instance = CategorieProduit.__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,nom)
def __ior__(self, objets:set) -> 'MonoideAleatoire':
if objets == {tuple(1 for i in range(len(self)))}:
return CategorieLibre.__ior__(self,{tuple(1 for i in range(len(self)))})
elif objets == {1}:
return CategorieLibre.__ior__(self,{tuple(1 for i in range(len(self)))})
raise Exception("Tentative d'ajout d'objet dans un monoide "+str(objets))
def test_MonoideGC():
random.seed(22453)
mon = PetitMonoideAleatoire(5)
mon.transformer_graphviz()
mon.loi_de_composition_to_csv()
mon = MonoideAleatoire(7)
mon.transformer_graphviz()
mon.loi_de_composition_to_csv(destination="lois de composition/monoide.csv")
class GroupoideAleatoire(GrapheCompositionAleatoire):
"""Un groupoïde est une catégorie où tous les morphismes sont des isomorphismes.
C'est-à-dire, pour tout morphisme f:A->B, il existe un morphisme g:B->A tel que
gof = IdA et fog = IdB."""
def __init__(self, nb_fleches:Union[int,None] = None, nb_tentatives_complexification_loi_de_compo:int = 1000,nom:str = "Catégorie Aléatoire"):
"""`nb_fleches` est le nombre de flèches élémentaires dans la catégorie, elles seront doublées pour la création des inverses.
`nb_tentatives_complexification_loi_de_compo` détermine à quel point la loi de composition sera complexifiée,
si le nombre est faible on obtient une catégorie où les flèches sont isolées."""
if nb_fleches == None:
nb_fleches = random.randint(1,20)
nb_fleches *= 2
GC.__init__(self,nom=nom)
table = defaultdict(lambda:None)
for i in range(nb_fleches):
table[(i,i+1)] = -i
table[(i+1,i)] = -i
table[(-i,i)] = i
table[(i,-i)] = i
table[(-i,i+1)] = i+1
table[(i+1,-i)] = i+1
i,j = random.randint(0,nb_fleches-1),random.randint(0,nb_fleches-1)
cases_modifiees = set()
for tentative in range(nb_tentatives_complexification_loi_de_compo):
cases_modifiees |= {(i,j)}
if table[(i,j)] == None:
table[(i,j)] = random.randint(0,nb_fleches-1)
for a,b,c in itertools.product(range(nb_fleches),repeat=3):
if table[(table[(a,b)],c)] != table[(a,table[(b,c)])]:
# l'associativité n'est pas vérifiée
for case in cases_modifiees:
table[case] = None
print("revert")
cases_modifiees = set()
i,j = random.randint(0,nb_fleches-1),random.randint(0,nb_fleches-1)
break
if cases_modifiees == set():
# l'associativité n'est pas vérifiée
continue
for a,b in itertools.product(range(nb_fleches),repeat=2):
if table[(a,b)] != None:
for c in range(nb_fleches):
if table[(table[(a,b)],c)] != None and table[(b,c)] == None:
# les compositions ne sont pas respectées
i,j = b,c
break
if table[(table[(a,b)],c)] == None and table[(b,c)] != None:
# les compositions ne sont pas respectées
i,j = table[(a,b)],c
break
else:
continue
break
else:
#il n'y a eu aucune erreur de composition on valide les changements
cases_modifiees = set()
i,j = random.randint(0,nb_fleches-1),random.randint(0,nb_fleches-1)
else:
i,j = random.randint(0,nb_fleches-1),random.randint(0,nb_fleches-1)
print(table)
#on a une table de loi de composition aléatoire
graphe_equiv = defaultdict(set)
#la source d'une flèche i est représentée par le nombre 2*i
#la cible d'une flèche i est représentée par le nombre 2*i+1
#on va faire le graphe d'équivalence entre ces nombres
for a,b in itertools.product(range(nb_fleches),repeat=2):
if table[(a,b)] != None:
# b o a = talbe[(a,b)]
graphe_equiv[2*b] |= {2*a+1}
graphe_equiv[2*a+1] |= {2*b}
graphe_equiv[2*a] |= {2*table[(a,b)]}
graphe_equiv[2*table[(a,b)]] |= {2*a}
graphe_equiv[2*b+1] |= {2*table[(a,b)]+1}
graphe_equiv[2*table[(a,b)]+1] |= {2*b+1}
graph = Digraph('categorie')
for i in range(nb_fleches*2):
graph.node(str(i))
for j in graphe_equiv[i]:
graph.edge(str(i),str(j))
graph.render("classe")
elem_a_mapper = {i for i in range(nb_fleches*2)}
application = dict()
dernier_element = 0
while len(elem_a_mapper) > 0:
elem = elem_a_mapper.pop()
dernier_element += 1
self |= {dernier_element}
elem_visites = set()
file = {elem}
while len(file) > 0:
elem = file.pop()
application[elem] = dernier_element
elem_visites |= {elem}
file |= {e for e in graphe_equiv[elem] if e >= 0} - elem_visites
elem_a_mapper -= elem_visites
fleches = {i:MGC(application[2*i],application[2*i+1]) for i in range(nb_fleches)}
self |= set(fleches.values())
for i,j in itertools.product(range(nb_fleches),repeat=2):
if table[(i,j)] != None:
if table[(i,j)] >= 0:
MGC.identifier_morphismes(fleches[j]@fleches[i],fleches[table[(i,j)]])
else:
MGC.identifier_morphismes(fleches[j]@fleches[i],self.identite(fleches[i].source))
def test_GroupoideAleatoire():
random.seed(1)
for i in range(20):
GCA = GroupoideAleatoire()
GCA.transformer_graphviz(complet=False)
GCA.transformer_graphviz()
if __name__ == '__main__':
test_GrapheCompositionAleatoire()
\ No newline at end of file
test_GrapheCompositionAleatoire()
# test_MonoideGC()
# test_GroupoideAleatoire()
\ No newline at end of file
......@@ -86,122 +86,3 @@ class MonoideGC(GrapheDeComposition,Monoide):
raise Exception("Tentative de suppression d'un element de monoide de type inconnu "+str(elem))
GrapheDeComposition.__isub__(self,{elem})
return self
class PetitMonoideAleatoire(MonoideGC):
"""Monoïde fini dont la table de loi de composition interne est choisie aléatoirement.
Les éléments du monoïde seront des flèches nommées par des nombres allant de 1
jusqu'au nombre d'éléments moins un sauf l'indentité qui représente l'élément neutre.
La taille maximale de ce monoïde est 5, sinon le temps de calcul est trop grand.
Pour un monoïde aléatoire plus grand, utiliser un `MonoideAleatoire` qui sera un produit de `PetitMonoideAleatoire`."""
def __init__(self, nb_elements:int = random.randint(1,5), nom:str = "Petit monoïde aléatoire"):
"""`nb_elements` est le nombre d'éléments du monoïde, si `nb_elements` = 1, alors il n'y a que l'identité dans le monoïde.
`nb_elements` doit être inférieur à 5, sinon le temps de calcul est trop long.
Pour un monoïde plus grand, utiliser `MonoideAleatoire`."""
if DEBUG_MONOIDE_ALEATOIRE:
print("Début de création d'un monoïde à "+str(nb_elements)+" éléments")
if nb_elements > 5:
raise Exception("Le nombre d'elements d'un PetitMonoideAleatoire doit etre inferieur ou egal a 5.")
elements = list(range(nb_elements)) #le 0 va représenter l'identité
associativite_verifiee = False
while not associativite_verifiee:
table = dict()
associativite_verifiee = True
for a,b in itertools.product(elements,repeat=2):
if (a,b) not in table:
table[(a,b)] = random.choice(elements) if a*b != 0 else a+b
# si a ou b est 0 (le produit est 0) alors on renvoie l'autre element (a+b vaut l'autre element puisque 0 est neutre par l'addition)
# on force l'associativité si on peut
for c in elements:
if (table[(a,b)],c) in table and (b,c) in table:
if (a,table[(b,c)]) not in table:
table[(a,table[(b,c)])] = table[(table[(a,b)],c)]
elif table[(table[(a,b)],c)] != table[(a,table[(b,c)])]:
associativite_verifiee = False
table[(a,table[(b,c)])] = table[(table[(a,b)],c)]
break
if (c,table[(a,b)]) in table and (c,a) in table:
if (table[(c,a)],b) not in table:
table[(table[(c,a)],b)] = table[(c,table[(a,b)])]
elif table[(table[(c,a)],b)] != table[(c,table[(a,b)])]:
associativite_verifiee = False
break
else:
continue
break
if not associativite_verifiee:
continue
#on a une table aléatoire
#maintenant on vérifie l'associativité
associativite_verifiee = False
for a,b,c in itertools.product(elements,repeat=3):
if table[(table[(a,b)],c)] != table[(a,table[(b,c)])]:
break
else:
associativite_verifiee = True
# on a notre table de composition
MonoideGC.__init__(self,nom)
fleches = {i:ElementMonoideGC(str(i)) for i in range(1,nb_elements)}
fleches[0] = self.identite()
self |= {fleches[i] for i in range(1,nb_elements)}
for a,b in itertools.product(elements,repeat=2):
if fleches[a]@fleches[b] != fleches[table[(a,b)]]:
MGC.identifier_morphismes(fleches[a]@fleches[b],fleches[table[(a,b)]])
if DEBUG_MONOIDE_ALEATOIRE:
print("Fin de création d'un monoïde à "+str(nb_elements)+" éléments")
def facteurs_premiers(n):
while n > 1:
for i in range(2, int(n**0.5)+1):
if not n % i:
n //= i
yield i
break
else:
yield n
break
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 __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 = tuple(PetitMonoideAleatoire(x) for x in facteurs_premiers(nb_elements))
instance = CategorieProduit.__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,nom)
def __ior__(self, objets:set) -> 'MonoideAleatoire':
if objets == {tuple(1 for i in range(len(self)))}:
return CategorieLibre.__ior__(self,{tuple(1 for i in range(len(self)))})
elif objets == {1}:
return CategorieLibre.__ior__(self,{tuple(1 for i in range(len(self)))})
raise Exception("Tentative d'ajout d'objet dans un monoide "+str(objets))
def test_MonoideGC():
random.seed(22453)
mon = PetitMonoideAleatoire(5)
mon.transformer_graphviz()
mon.loi_de_composition_to_csv()
mon = MonoideAleatoire(7)
mon.transformer_graphviz()
mon.loi_de_composition_to_csv(destination="lois de composition/monoide.csv")
if __name__ == '__main__':
test_MonoideGC()
\ No newline at end of file
Markdown is supported
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