Commit 62b5bdf7 authored by Guillaume Sabbagh's avatar Guillaume Sabbagh
Browse files

On ne conserve plus les diagrammes commutatifs dans les catégories,...

On ne conserve plus les diagrammes commutatifs dans les catégories, suppression de la catégorieAléatoireIsomorphismes qui est équivalente à celle pré-ordre (entre deux objets il ne peut y avoir qu'un seul isomorphisme), et correction de limites et colimites
parent 8468d55f
......@@ -28,7 +28,6 @@ class Categorie:
# présent dans morphismes
self.morph_sortants = defaultdict(list) # Liste des morphismes sortant non triviaux d'un objet
self.morph_entrants = defaultdict(list)
self.diagrammes = [] # liste des diagrammes commutatifs
class Composee(Composition):
"""La loi de composition est inclus dans la construction de la composee :
......@@ -91,7 +90,6 @@ class Categorie:
newone.morph_sortants[cle] = copy.copy(self.morph_sortants[cle])
for cle in self.morph_entrants:
newone.morph_entrants[cle] = copy.copy(self.morph_entrants[cle])
newone.diagrammes = copy.copy(self.diagrammes)
newone.Composee.loi_de_composition = copy.copy(self.Composee.loi_de_composition)
return newone
......@@ -100,7 +98,7 @@ class Categorie:
return False
return self.objets == other.objets and self.morphismes == other.morphismes and \
self.identites == other.identites and self.morph_sortants == other.morph_sortants \
and self.morph_entrants == other.morph_entrants and self.diagrammes == other.diagrammes \
and self.morph_entrants == other.morph_entrants\
and self.Composee.loi_de_composition == other.Composee.loi_de_composition
def __hash__(self):
......@@ -111,15 +109,16 @@ class Categorie:
def fleches_elem(self, source, cible, inclure_id = True):
"""Renvoie la liste de flèches élémentaires de source à cible."""
return [morph for morph in self.morph_sortants[source] if morph.cible == cible and (inclure_id or not morph.is_identite)]
if source == cible and inclure_id:
return [morph for morph in self.morph_sortants[source] if morph.cible == cible]+[self.identites[source]]
return [morph for morph in self.morph_sortants[source] if morph.cible == cible]
def verifier_coherence(self):
"""Vérifie la cohérence de la structure (tous les axiomes des catégories sont vérifiés)."""
m = self.morphismes
if len(self.objets) == 0:
## S'il n'y a aucun objet, on vérifie que tout le reste est vide aussi
assert (len(m) == len(self.morph_sortants) == len(self.morph_entrants) == len(self.diagrammes) == len(
self.Composee.loi_de_composition) == 0)
assert (len(m) == len(self.morph_sortants) == len(self.morph_entrants) == len(self.Composee.loi_de_composition) == 0)
else:
## On vérifie l'existence de l'identité pour tous les objets (O(n))
for o in self.objets:
......@@ -197,13 +196,6 @@ class Categorie:
del self.morph_entrants[objet]
del self.morph_sortants[objet]
del self.identites[objet]
for d in self.diagrammes:
if objet in d.cat_source.objets:
if len(d.cat_source.morph_entrants[objet]) == len(d.cat_source.morph_sortants[objet]) == 0:
d.cat_source.supprimer_objet(objet)
else:
raise Exception("Il reste des morphismes sortants ou entrants d'un objet auquel on a supprime tous les morphismes adjacents "+str(objet)+"\n"+\
'\n'.join(map(str,d.cat_source.morph_entrants[objet]))+"\n\n"+'\n'.join(map(str,d.cat_source.morph_sortants[objet])))
if TOUJOURS_VERIFIER_COHERENCE:
self.verifier_coherence()
......@@ -217,27 +209,14 @@ class Categorie:
del self.Composee.loi_de_composition[elem_a_del]
if morphisme in self.Composee.loi_de_composition:
del self.Composee.loi_de_composition[morphisme]
for elem_a_del in [ante for ante,im in self.Composee.loi_de_composition.items() if morphisme in im]:
del self.Composee.loi_de_composition[ante]
self.morphismes.remove(morphisme)
if not morphisme.is_identite:
self.morph_entrants[morphisme.cible].remove(morphisme)
self.morph_sortants[morphisme.source].remove(morphisme)
while len(self.diagrammes) > 0:
for i in range(len(self.diagrammes)):
d = self.diagrammes[i]
if morphisme in [e for compo in d.app_morph.values() for e in compo]:
self.diagrammes.pop(i)
nouveau_sketch = Categorie()
nouveau_sketch.ajouter_objets(d.cat_source.objets)
nouveau_sketch.ajouter_morphismes([morph for morph in d.cat_source.morphismes if
morphisme not in d.app_morph[
morph] and not morph.is_identite])
nouveau_diagramme = Diagramme.Diagramme(nouveau_sketch, self, d.app_objets,
{cle: d.app_morph[cle] for cle in
nouveau_sketch.morphismes if not cle.is_identite})
nouveau_diagramme.faire_commuter()
break
else:
break
if TOUJOURS_VERIFIER_COHERENCE:
self.verifier_coherence()
......@@ -598,7 +577,6 @@ def main():
cat = CategoriePreordre.CategoriePreordre(cat)
cat.transformer_graphviz()
cat.diagrammes[-1].transformer_graphviz()
cat2 = Categorie("1 flèche")
cat2.ajouter_objets("XY")
......
......@@ -47,35 +47,7 @@ class CategorieAlea(Categorie):
diag.faire_commuter()
if PRINT_AVANCEMENT_CREATION_CAT_ALEA:
print("Fin création")
class CategorieAleaIsomorph(Categorie):
"""Construit une catégorie aléatoire où tous les cycles sont des isomorphismes."""
def __init__(self, nb_objets = None, nb_morph = None):
"""nb_morph est le nombre de morphismes élémentaires à ajouter aléatoirement."""
Categorie.__init__(self,"Catégorie aléatoire")
if nb_objets == None:
nb_objets = random.randint(5,20)
if nb_morph == None:
nb_morph = random.randint(0,30)
if PRINT_AVANCEMENT_CREATION_CAT_ALEA:
print("Création d'une catégorie avec "+str(nb_objets)+" objets et "+str(nb_morph)+" morphismes")
self.ajouter_objets(list(range(nb_objets))) #ajout des objets
i=1
while len(self.morphismes) < nb_morph+nb_objets: # ajout des morphismes
source = random.randint(0,nb_objets-1)
cible = random.randint(0,nb_objets-1)
if source != cible:
self.ajouter_morphisme(Morphisme(source,cible,str(i)))
i+=1
#on définit la loi de composition pour les cycles
for obj in self.objets:
cycles = self.trouver_cycles_elementaires(obj)
for c in cycles:
diag = Parallele(self,[obj]*2,[c,self.identites[obj]])
diag.faire_commuter()
if PRINT_AVANCEMENT_CREATION_CAT_ALEA:
print("Fin création")
class CategorieAleaPreOrdre(Categorie):
"""Construit une catégorie pré-ordre aléatoire."""
......
......@@ -72,7 +72,7 @@ class CategorieCocones(Categorie):
if f2 == f:
im_nouveau += [f1]
if len(im_nouveau) == 0:
raise Exception("Pas d'image a la fleche "+str(f))
raise Exception("Pas d'image a la fleche "+str(f)+"\n"+'\n'.join(map(lambda x:':'.join(map(str,x)),self.app_morph_fleche_cocone.items())))
image_nouveau += [im_nouveau]
for im in product(*image_nouveau):
if im[0].source == antecedant_nouveau[0].source and im[-1].cible == antecedant_nouveau[-1].cible: #on vérifie que ça part et ça arrive au bon endroit
......@@ -98,22 +98,42 @@ class CategorieCocones(Categorie):
"""Trouve la/les colimite(s) si elle(s) existe(nt), renvoie une liste vide si aucune colimite trouvée
une liste de cocônes isomorphes sinon"""
if len(self.objets) > 0:
noeuds_visites = [self.objets[0]]
noeud = self.objets[0]
while True:
predecesseurs = [morph.source for morph in self.morph_entrants[noeud] if morph.source not in noeuds_visites]
if len(predecesseurs) == 0:
break
else:
noeud = predecesseurs[0]
noeuds_visites += [noeud]
graphe = defaultdict(list)
for cle,val in self.morph_entrants.items():
graphe[cle] = list(map(lambda x:x.cible,val))
noeuds_visites = []
noeud_courant = self.objets[0]
while len(graphe[noeud_courant]) > 0:
noeuds_visites += [noeud_courant]
if graphe[noeud_courant][0] in noeuds_visites:
while noeuds_visites[0] != graphe[noeud_courant][0]:
noeuds_visites.pop(0)
nouveau_noeud = tuple(noeuds_visites)
graphe[nouveau_noeud]
for cle,val in graphe.items():
if cle in noeuds_visites:
graphe[nouveau_noeud] += [e for e in val if e not in noeuds_visites]
else:
noeuds_a_del = [cible for cible in val if cible in noeuds_visites]
if len(noeuds_a_del) > 0:
graphe[cle] += [nouveau_noeud]
graphe[cle] = [e for e in graphe[cle] if e not in noeuds_a_del]
for noeud in noeuds_visites:
del graphe[noeud]
noeuds_visites = []
noeud_courant = nouveau_noeud
continue
noeud_courant = graphe[noeud_courant][0]
while type(noeud_courant) == tuple:
noeud_courant = noeud_courant[0]
noeud_initial = noeud_courant
#on est arrivé au bout du chemin
for cocone in self.objets:
fleches = self.enumerer_composees(noeud,cocone)
fleches = self.enumerer_composees(noeud_initial,cocone)
if len(fleches) != 1:
break
else:
result = [cocone for cocone in self.objets if len(self.enumerer_composees(cocone,noeud)) > 0]
result = [cocone for cocone in self.objets if len(self.enumerer_composees(cocone,noeud_initial)) > 0]
if TOUJOURS_VERIFIER_COHERENCE:
for colim in result:
for cocone in self.objets:
......
......@@ -56,7 +56,6 @@ class CategorieCones(Categorie):
print("CategorieCones l.48 : On a echappe a la creation du diagramme superflu "+str(self.Composee(*antecedant_nouveau))+" => "+str(self.Composee(*image_nouveau)))
# On retire ensuite les chemins en double
self.transformer_graphviz(complet=False)
composees = self.enumerer_toutes_composees()
for cone1,cone2 in composees:
comp = sorted([e for e in composees[(cone1,cone2)] if not e.is_identite],key=len)
......@@ -99,22 +98,45 @@ class CategorieCones(Categorie):
"""Trouve la/les limite(s) si elle(s) existe(nt), renvoie une liste vide si aucune limite trouvée
une liste de cônes isomorphes sinon"""
if len(self.objets) > 0:
noeuds_visites = [self.objets[0]]
noeud = self.objets[0]
while True:
successeurs = [morph.cible for morph in self.morph_sortants[noeud] if morph.cible not in noeuds_visites]
if len(successeurs) == 0:
break
else:
noeud = successeurs[0]
noeuds_visites += [noeud]
# On essaie d'aller au bout du graphe, si on boucle, on a trouvé un cycle qu'on doit condenser en un seul noeud
graphe = defaultdict(list)
for cle,val in self.morph_sortants.items():
graphe[cle] = list(map(lambda x:x.cible,val))
noeuds_visites = []
noeud_courant = self.objets[0]
while len(graphe[noeud_courant]) > 0:
noeuds_visites += [noeud_courant]
if graphe[noeud_courant][0] in noeuds_visites:
while noeuds_visites[0] != graphe[noeud_courant][0]:
noeuds_visites.pop(0)
nouveau_noeud = tuple(noeuds_visites)
graphe[nouveau_noeud]
for cle,val in graphe.items():
if cle in noeuds_visites:
graphe[nouveau_noeud] += [e for e in val if e not in noeuds_visites]
else:
noeuds_a_del = [cible for cible in val if cible in noeuds_visites]
if len(noeuds_a_del) > 0:
graphe[cle] += [nouveau_noeud]
graphe[cle] = [e for e in graphe[cle] if e not in noeuds_a_del]
for noeud in noeuds_visites:
del graphe[noeud]
noeuds_visites = []
noeud_courant = nouveau_noeud
continue
noeud_courant = graphe[noeud_courant][0]
while type(noeud_courant) == tuple:
noeud_courant = noeud_courant[0]
noeud_final = noeud_courant
#on est arrivé au bout du chemin
for cone in self.objets:
fleches = self.enumerer_composees(cone,noeud)
fleches = self.enumerer_composees(cone,noeud_final)
if len(fleches) != 1:
for f in fleches:
print(f.pretty_print())
break
else:
result = [cone for cone in self.objets if len(self.enumerer_composees(noeud,cone)) > 0]
result = [cone for cone in self.objets if len(self.enumerer_composees(noeud_final,cone)) > 0]
if TOUJOURS_VERIFIER_COHERENCE:
for lim in result:
for cone in self.objets:
......
......@@ -27,33 +27,18 @@ class Diagramme(Foncteur.Foncteur):
return "Diag"+str(self._id)
def faire_commuter(self):
"""Change la catégorie indexée par le diagramme pour que ce dernier commute."""
ajout_loi_de_compo = False #booleen qui indique si on a ajouter qqch dans la loi de compo
"""Change la catégorie indexée par le diagramme pour que ce dernier commute."""
##on s'occupe d'abord des cycles
cat_index = copy.copy(self.categorie_indexante)
for objet in cat_index.objets:
for cycle in cat_index.trouver_cycles_elementaires(objet):
cat_index.Composee.loi_de_composition[cycle] = cat_index.identites[objet]
self.categorie_indexee.Composee.loi_de_composition[self(cycle)] = cat_index.identites[objet]
ajout_loi_de_compo = True
composees = cat_index.enumerer_toutes_composees()
for couple in composees:
composees_sans_id = [e for e in composees[couple] if not e.is_identite]
# morph_elem = [e for e in composees_sans_id if len(e.composee) == 1]
# if len(morph_elem) > 1: #deux morphismes élémentaires identifiés
# for e in morph_elem:
# print(e)
# on supprime les flèches en trop
# for m in morph_elem[1:]:
# cat_index.supprimer_morphisme(m)
# if self(m) != morph_elem[0]:
# self.categorie_indexee.supprimer_morphisme(self(m))
# composees = cat_index.enumerer_toutes_composees()
# composees_sans_id = [e for e in composees[couple] if not e.is_identite]
composees_sans_id = [e for e in composees[couple] if not e.is_identite]
if len(composees_sans_id) >= 2:
ajout_loi_de_compo = True
composees_triees = sorted(list(map(lambda x:self.categorie_indexee.Composee(*[self.app_morph[e] for e in x]),composees_sans_id)), key=len)
for c in composees_triees[1:]:
composee_depart = c
......@@ -69,10 +54,6 @@ class Diagramme(Foncteur.Foncteur):
self.categorie_indexee.supprimer_morphisme(composee_depart)
else:
self.categorie_indexee.Composee.loi_de_composition[composee_depart] = composee_arrivee
if self not in self.categorie_indexee.diagrammes and ajout_loi_de_compo:
self.categorie_indexee.diagrammes += [self]
if TOUJOURS_VERIFIER_COHERENCE:
self.categorie_indexee.verifier_coherence()
......
......@@ -4,9 +4,9 @@ import CategorieCones,CategorieCocones
import Bouquet
import random
random.seed(123455)
random.seed(1215451)
cat = CategorieAleatoire.CategorieAleaIsomorph()
cat = CategorieAleatoire.CategorieAleaPreOrdre()
cat.transformer_graphviz(complet=False)
cat.transformer_graphviz(complet=True)
......
- Ajouter morphisme -> renvoyer la liste des cycles créés ?
- Mettre en cache les composées enumérées dans catégorie
- tester catégorie cones avec un diagramme où la catégorie indexante n'a pas de flèches (on est censé avoir toutes les permutations de jambes)
- L200-205 Catégorie -> investiguer à quoi ça sert ?
\ No newline at end of file
- L200-205 Catégorie -> investiguer à quoi ça sert ?
- Problème dans catégorie aléatoire : un morphisme peut avoir deux inverses (voir s'il y a pas d'autres problèmes du genre)
\ No newline at end of file
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