Commit 1feb2b01 authored by Guillaume Sabbagh's avatar Guillaume Sabbagh
Browse files

Comma catégorie transformée

parent 7a27a1ec
...@@ -147,23 +147,24 @@ class Categorie: ...@@ -147,23 +147,24 @@ class Categorie:
raise Exception("Incoherence Categorie : le morphisme "+str(morphisme)+" est modifie par une identite.") raise Exception("Incoherence Categorie : le morphisme "+str(morphisme)+" est modifie par une identite.")
## On vérifie l'associativité ## On vérifie l'associativité
for m1,m2,m3 in itertools.product(self.__morphismes,repeat=3): for m1,m2,m3 in itertools.product(sorted(self.__morphismes),repeat=3):
if m1.source == m2.cible and m2.source == m3.cible: if m1.source == m2.cible and m2.source == m3.cible:
if (m1@m2)@m3 != m1@(m2@m3): if (m1@m2)@m3 != m1@(m2@m3):
raise Exception("Incoherence Categorie : associativite pas respectee pour "+str(m3)+", "+str(m2)+", "+str(m1)+\ raise Exception("Incoherence Categorie : associativite pas respectee pour "+str(m1)+", "+str(m2)+", "+str(m3)+\
"\n(m1@m2)@m3 = "+str((m1@m2)@m3)+" m1@(m2@m3) = "+str(m1@(m2@m3))) "\n(m1@m2)@m3 = "+str((m1@m2)@m3)+" m1@(m2@m3) = "+str(m1@(m2@m3))+
"\nm1@m2 = "+str(m1@m2)+" m2@m3 = "+str(m2@m3))#+"\nm2@m1 = "+str(m2@m1)+" m3@m2 = "+str(m3@m2))
def table_loi_de_composition(self): def table_loi_de_composition(self):
""" """
Renvoie un dico de dico tel que table[f][g] = g o f, table[f][g] = None si f et g ne sont pas composables. Renvoie un dico de dico tel que table[f][g] = f o g, table[f][g] = None si f et g ne sont pas composables.
La table contient les compositions triviales f o Id = f, f o g = f o g, f o (g o h) = (f o g) o h etc. La table contient les compositions triviales f o Id = f, f o g = f o g, f o (g o h) = (f o g) o h etc.
O(m²) O(m²)
""" """
table = defaultdict(dict()) table = defaultdict(dict)
for A,B in itertools.product(abs(self), repeat=2): for A,B in itertools.product(abs(self), repeat=2):
for f in self(A,B): for f in self(A,B):
for g in self(B,abs(self)): for g in self(B,abs(self)):
table[f][g] = g@f table[g][f] = g@f
return table return table
def loi_de_composition_to_csv(self, destination:str=None, sep: str=','): def loi_de_composition_to_csv(self, destination:str=None, sep: str=','):
...@@ -296,10 +297,8 @@ def test_CategorieDiscrete(): ...@@ -296,10 +297,8 @@ def test_CategorieDiscrete():
cat_discrete += set("ABCDE") cat_discrete += set("ABCDE")
cat_discrete.transformer_graphviz(afficher_identites=True) cat_discrete.transformer_graphviz(afficher_identites=True)
def main():
test_Categorie()
test_CategorieDiscrete()
test_SousCategoriePleine()
if __name__ == '__main__': if __name__ == '__main__':
main() test_Categorie()
\ No newline at end of file test_CategorieDiscrete()
test_SousCategoriePleine()
\ No newline at end of file
...@@ -7,10 +7,12 @@ from config import * ...@@ -7,10 +7,12 @@ from config import *
class GrapheCompositionAleatoire(GC): 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_branchement_cycle=1/10): 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. """`nb_morph` est le nombre de morphismes élémentaires à ajouter aléatoirement, certains seront supprimés après.
proba_branchement_cycle permet de gérer le cas de la composition des différents cycles, `proba_brancher` est la probabilité de brancher lors de la création de l'arbre de composition des cycles,
la proba est celle de brancher sur l'arbre de composition.""" 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
et les flèches de obj vers obj seront idempotents."""
GC.__init__(self,"Graphe de composition aléatoire") GC.__init__(self,"Graphe de composition aléatoire")
if nb_objets == None: if nb_objets == None:
nb_objets = random.randint(5,20) nb_objets = random.randint(5,20)
...@@ -18,48 +20,76 @@ class GrapheCompositionAleatoire(GC): ...@@ -18,48 +20,76 @@ class GrapheCompositionAleatoire(GC):
nb_morph = random.randint(0,30) nb_morph = random.randint(0,30)
if PRINT_AVANCEMENT_CREATION_CAT_ALEA: if PRINT_AVANCEMENT_CREATION_CAT_ALEA:
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")
self += set(range(nb_objets)) #ajout des objets
for i in range(nb_objets): #ajout des objets
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
for obj in self.objets: ## on définit la loi de composition pour les cycles
cycles = self.trouver_cycles_minimaux(obj,inclure_id=False) 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} arbre_composition = {cycle:"a determiner" for cycle in cycles}
# {noeud_arbre : image_cycle} # {noeud_arbre : image_cycle}
profondeur_cycle = {self.identite(obj):0} #cycle: profondeur dans l'arbre de composition profondeur_cycle = {self.identite(obj):0} #cycle: profondeur dans l'arbre de composition
for cycle in cycles: for cycle in cycles:
profondeur_cycle[cycle] = 1 profondeur_cycle[cycle] = 1
continuer = True while list(arbre_composition.values()).count("a determiner") > 0:
while continuer:
continuer = False
for cle in copy.copy(arbre_composition): for cle in copy.copy(arbre_composition):
if arbre_composition[cle] == "a determiner": if arbre_composition[cle] == "a determiner":
continuer=True if random.random() < proba_brancher**(profondeur_cycle[cle]-(1 if len(cle) == 1 else 0)):
if random.random() < proba_branchement_cycle: # ici on branche # 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 arbre_composition[cle] = None
for cycle in cycles: for cycle in cycles:
arbre_composition[cycle@cle]="a determiner" arbre_composition[cycle@cle]="a determiner"
profondeur_cycle[cycle@cle] = profondeur_cycle[cle]+1 profondeur_cycle[cycle@cle] = profondeur_cycle[cle]+1
else: # ici on doit simplifier le cycle 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]] cycles_candidats = [cycle for cycle in profondeur_cycle if profondeur_cycle[cycle] < profondeur_cycle[cle]]
arbre_composition[cle]=random.choice(cycles_candidats) arbre_composition[cle]=random.choice(cycles_candidats)
for cycle in arbre_composition: for cycle in arbre_composition:
if arbre_composition[cycle] != None: if arbre_composition[cycle] != None:
if len(cycle) == 1 and len(arbre_composition[cycle]) == 1: # si on identifie deux cycles élémentaires on en retire un assert(len(cycle) != 1)
self -= cycle MGC.identifier_morphismes(cycle,arbre_composition[cycle])
else: print(obj,cycles)
MGC.identifier_morphismes(cycle,arbre_composition[cycle]) print("=======")
print(arbre_composition) 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:
print("Fin création") print("Fin création")
if TOUJOURS_VERIFIER_COHERENCE: if TOUJOURS_VERIFIER_COHERENCE:
self.verifier_coherence() self.verifier_coherence()
def test_GrapheCompositionAleatoire(): def test_GrapheCompositionAleatoire():
GCA = GrapheCompositionAleatoire(5,10) random.seed(1)
GCA = GrapheCompositionAleatoire()
GCA.transformer_graphviz() GCA.transformer_graphviz()
GCA.loi_de_composition_to_csv('lois de composition/loi_de_compo.csv')
return GCA
# class CategorieAleaIsomorph(Categorie): # class CategorieAleaIsomorph(Categorie):
# """Construit une catégorie aléatoire où tous les cycles sont des isomorphismes.""" # """Construit une catégorie aléatoire où tous les cycles sont des isomorphismes."""
...@@ -148,13 +178,9 @@ def test_GrapheCompositionAleatoire(): ...@@ -148,13 +178,9 @@ def test_GrapheCompositionAleatoire():
# if retirer_objets_isoles and len([obj for obj in cat_source.objets if not(len(cat_source.morph_sortants[obj]) == len(cat_source.morph_entrants[obj]) == 0)]) != 0: # if retirer_objets_isoles and len([obj for obj in cat_source.objets if not(len(cat_source.morph_sortants[obj]) == len(cat_source.morph_entrants[obj]) == 0)]) != 0:
# cat_source.supprimer_objets([obj for obj in cat_source.objets if len(cat_source.morph_sortants[obj]) == len(cat_source.morph_entrants[obj]) == 0]) # cat_source.supprimer_objets([obj for obj in cat_source.objets if len(cat_source.morph_sortants[obj]) == len(cat_source.morph_entrants[obj]) == 0])
# Diagramme.__init__(self,cat_source,cat_cible,{o:o for o in cat_source.objets},{m:m for m in cat_source.morphismes}) # Diagramme.__init__(self,cat_source,cat_cible,{o:o for o in cat_source.objets},{m:m for m in cat_source.morphismes})
def main():
random.seed(2579)
test_GrapheCompositionAleatoire()
if __name__ == '__main__': if __name__ == '__main__':
main() random.seed(2579)
\ No newline at end of file test_GrapheCompositionAleatoire()
\ No newline at end of file
...@@ -126,7 +126,7 @@ class CategorieLibre(Categorie): ...@@ -126,7 +126,7 @@ class CategorieLibre(Categorie):
return cycles|{self.identite(objet)} return cycles|{self.identite(objet)}
return cycles-{self.identite(objet)} return cycles-{self.identite(objet)}
def enumerer_cycles(self, objet:any, limite_profondeur:int = 4) -> frozenset: def enumerer_cycles(self, objet:any, limite_profondeur:int = 6) -> frozenset:
"""Enumère toutes les compositions de `objet` à `objet`. """Enumère toutes les compositions de `objet` à `objet`.
Si f et g sont des cycles minimaux, on doit énumérer tous les mots d'alphabet {f,g}. Si f et g sont des cycles minimaux, on doit énumérer tous les mots d'alphabet {f,g}.
Pour ça on s'intéresse aux compositions qui se réduisent en composition déjà générées. Pour ça on s'intéresse aux compositions qui se réduisent en composition déjà générées.
...@@ -165,9 +165,8 @@ class CategorieLibre(Categorie): ...@@ -165,9 +165,8 @@ class CategorieLibre(Categorie):
noeud = chemin[i] noeud = chemin[i]
if i < len(chemin)-1: if i < len(chemin)-1:
noeud_suivant = chemin[i+1] noeud_suivant = chemin[i+1]
for fleche in self.fleches_elem(noeud,noeud_suivant): composees_obtenues = {fleche@composee for composee in composees_obtenues for fleche in self.fleches_elem(noeud,noeud_suivant)}
nouvelles_composees_obtenues = {fleche@composee for composee in composees_obtenues}
composees_obtenues = copy(nouvelles_composees_obtenues)
if len(chemin) > 1: #pour que noeud_suivant soit defini if len(chemin) > 1: #pour que noeud_suivant soit defini
for composee in copy(composees_obtenues): for composee in copy(composees_obtenues):
for cycle in cycles[noeud_suivant]: for cycle in cycles[noeud_suivant]:
...@@ -202,9 +201,10 @@ class CategorieLibre(Categorie): ...@@ -202,9 +201,10 @@ class CategorieLibre(Categorie):
else: else:
graph.edge(str(fleche.source), str(fleche.cible), label=str(fleche), color="grey77") graph.edge(str(fleche.source), str(fleche.cible), label=str(fleche), color="grey77")
else: else:
for fleche in self.morphismes: for source,cible in itertools.product(self.objets,repeat=2):
if afficher_identites or not fleche.is_identite: for fleche in self.fleches_elem(source,cible):
graph.edge(str(fleche.source), str(fleche.cible), label=str(fleche)) if afficher_identites or not fleche.is_identite:
graph.edge(str(fleche.source), str(fleche.cible), label=str(fleche))
graph.render(destination) graph.render(destination)
if CLEAN_GRAPHVIZ_MODEL: if CLEAN_GRAPHVIZ_MODEL:
import os import os
......
...@@ -51,9 +51,6 @@ def test_CategoriePreordre(): ...@@ -51,9 +51,6 @@ def test_CategoriePreordre():
cat.transformer_graphviz() cat.transformer_graphviz()
cat.transformer_graphviz() cat.transformer_graphviz()
def main():
test_CategoriePreordre()
if __name__ == '__main__': if __name__ == '__main__':
main() test_CategoriePreordre()
from Morphisme import Morphisme from Morphisme import Morphisme
from Categorie import Categorie from Categorie import Categorie
from Foncteur import Foncteur
from Diagramme import DiagrammeIdentite, DiagrammeObjets
from config import *
class ObjetCommaCategorie: class ObjetCommaCategorie:
"""Soit C une catégorie, T et S deux foncteurs de E dans C et D dans C. """Soit C une catégorie, T et S deux foncteurs de E dans C et D dans C.
Un objet de la comma-categorie (T|S) est un triplet (e,f,d) où e est un objet de E, f une flèche de T(e) vers S(d) et d un objet de D. Un objet de la comma-categorie (T|S) est un triplet (e,f,d) où e est un objet de E, f une flèche de T(e) vers S(d) et d un objet de D.
(cf. Mac Lane "Categories for the working mathematician" P.45) (cf. Mac Lane "Categories for the working mathematician" P.45)
On a changé l'ordre par rapport au texte de MacLane qui considérait plutôt les triplets (e,d,f)
""" """
def __init__(self,e,f,d): def __init__(self, e:any, f:any, d:any):
self.e = e self.e = e
self.f = f self.f = f
self.d = d self.d = d
def __eq__(self,other:'ObjetCommaCategorie') -> bool:
if not issubclass(type(other),ObjetCommaCategorie):
raise TypeError("Tentative de comparaison avec un objet de type inconnu "+str(other))
return self.e == other.e and self.f == other.f and self.d == other.d
def __hash__(self) -> int:
return hash((self.e,self.f,self.d))
def __repr__(self): def __str__(self):
return '('+str(self.e)+','+str(self.f)+','+str(self.d)+')' return '('+str(self.e)+','+str(self.f)+','+str(self.d)+')'
def __repr__(self):
str(self)
class FlecheCommaCategorie(Morphisme): class FlecheCommaCategorie(Morphisme):
"""Soit C une catégorie, T et S deux foncteurs de E dans C et D dans C. """Soit C une catégorie, T et S deux foncteurs de E dans C et D dans C.
...@@ -27,21 +42,20 @@ class FlecheCommaCategorie(Morphisme): ...@@ -27,21 +42,20 @@ class FlecheCommaCategorie(Morphisme):
commute. commute.
(cf. Mac Lane "Categories for the working mathematician" P.45) (cf. Mac Lane "Categories for the working mathematician" P.45)
""" """
def __init__(self,source,cible,k,h): def __init__(self, source:any, cible:any, k:Morphisme, h:Morphisme):
self.k = k self.k = k
self.h = h self.h = h
Morphisme.__init__(self,source,cible,'('+str(self.k)+','+str(self.h)+')') Morphisme.__init__(self,source,cible,'('+str(self.k)+','+str(self.h)+')',source == cible and k.is_identite and h.is_identite)
def __repr__(self): def verifier_coherence(self, T:Foncteur, S:Foncteur):
return '('+str(self.k)+','+str(self.h)+')' if T.cible != S.cible:
def verifier_coherence(self,T,S):
if T.cat_cible != S.cat_cible:
raise Exception("Incoherence FlecheCommaCategorie : T et S de cibles differentes : "+str(T)+" != "+str(S)) raise Exception("Incoherence FlecheCommaCategorie : T et S de cibles differentes : "+str(T)+" != "+str(S))
categorie = T.cat_cible categorie = T.cible
if categorie.Composee(T(self.k),self.cible.f) != categorie.Composee(self.source.f,S(self.h)): if self.cible.f@T(self.k) != S(self.h)@self.source.f:
raise Exception("Incoherence FlecheCommaCategorie : le carre ne commute pas, "+str(self.cible.f)+" o "+str(T(self.k))+" != "+str(S(self.h))+" o "+str(self.source.f)) raise Exception("Incoherence FlecheCommaCategorie : le carre ne commute pas, "+str(self.cible.f)+" o "+str(T(self.k))+" != "+str(S(self.h))+" o "+str(self.source.f))
def __matmul__(self,other:'FlecheCommaCategorie') -> 'FlecheCommaCategorie':
return FlecheCommaCategorie(other.source,self.cible,self.k@other.k,self.h@other.h)
class CommaCategorie(Categorie): class CommaCategorie(Categorie):
...@@ -51,9 +65,114 @@ class CommaCategorie(Categorie): ...@@ -51,9 +65,114 @@ class CommaCategorie(Categorie):
Voir Mac Lane "Categories for the working mathematician" P.45 Voir Mac Lane "Categories for the working mathematician" P.45
""" """
def __init__(self,T,S): def __init__(self, T:Foncteur, S:Foncteur, nom:str = None):
if T.cat_cible != S.cat_cible: Categorie.__init__(self,"Comma-catégorie ("+str(T)+'|'+str(S)+')' if nom == None else nom)
raise Exception("Incoherence CommaCategorie : T et S de cibles differentes : "+str(T)+" != "+str(S)) if T.cible != S.cible:
self.C = T.cat_cible raise Exception("Incoherence CommaCategorie : T et S de cibles differentes : "+str(T)+" vs "+str(S))
self.__C = T.cible
self.__T = T
self.__S = S
self += {ObjetCommaCategorie(e,f,d) for e in T.source.objets for d in S.source.objets for f in self.__C(T(e),S(d))} # on ajoute tous les objets
def identite(self, objet:ObjetCommaCategorie) -> FlecheCommaCategorie:
'''L'identité pour un objet (e,f,d) est la paire d'identité de T(e) et S(d).'''
return FlecheCommaCategorie(objet,objet,self.__C.identite(self.__T(objet.e)),self.__C.identite(self.__S(objet.d)))
def __call__(self, source:ObjetCommaCategorie, cible:ObjetCommaCategorie) -> set:
\ No newline at end of file if source in self.objets:
# source est de type a
source = {source}
if cible in self.objets:
# cible est de type b
cible = {cible}
#maintenant tout est de la forme {a_i} vers {b_i}
result = set()
for a in source:
for b in cible:
for k in self.__T.source(a.e,b.e):
for h in self.__S.source(a.d,b.d):
if b.f@self.__T(k) == self.__S(h)@a.f:
result |= {FlecheCommaCategorie(a,b,k,h)}
return result
class CategorieFleches(CommaCategorie):
"""Catégorie des flèches d'une catégorie C.
(cf. https://en.wikipedia.org/wiki/Comma_category#Arrow_category)
"""
def __init__(self, C:Categorie, nom:str = None):
CommaCategorie.__init__(self,DiagrammeIdentite(C),DiagrammeIdentite(C),"Categorie des flèches de "+str(C) if nom == None else nom)
class CategorieSous(CommaCategorie):
"""CategorieSous peut aussi être appelée CosliceCategorie.
Soit C une catégorie, et b un objet de C.
CategorieSous est la catégorie en-dessous de b
(cf. Mac Lane "Categories for the working mathematician" P.45)
On construit la catégorie sous b en créant la comma-catégorie (1_b|Id(C)) c'est-à-dire
la comma-catégorie du diagramme qui associe à un objet unique b avec le diagramme identité de C.
"""
def __init__(self, C:Categorie, objet:any, nom:str = None):
CommaCategorie.__init__(self,DiagrammeObjets(C,{objet}),DiagrammeIdentite(C),str(C)+" sous "+str(objet) if nom == None else nom)
CosliceCategorie = CategorieSous
class CategorieSur(CommaCategorie):
"""CategorieSur peut aussi être appelée SliceCategorie.
Soit C une catégorie, et b un objet de C.
CategorieSur est la catégorie au-dessus de b
(cf. Mac Lane "Categories for the working mathematician" P.45)
On construit la catégorie sur b en créant la comma-catégorie (Id(C)|1_b) c'est-à-dire
la comma-catégorie du diagramme identité de C avec le diagramme qui associe à un objet unique b .
"""
def __init__(self, C:Categorie, objet:any, nom:str = None):
CommaCategorie.__init__(self,DiagrammeIdentite(C),DiagrammeObjets(C,{objet}),str(C)+" sur "+str(objet) if nom == None else nom)
SliceCategorie = CategorieSur
def test_CategorieFleches():
from GrapheDeComposition import GC,MGC
from Diagramme import DiagrammeIdentite
cat = GC('C')
cat += {'A','B','C'}
morphismes = [MGC('A','B','f'),MGC('B','C','g')]
cat += morphismes
cat.transformer_graphviz()
cat_fleches = CategorieFleches(cat)
cat_fleches.transformer_graphviz()
def test_CategorieSous():
from GrapheDeComposition import GC,MGC
from Diagramme import DiagrammeIdentite
cat = GC('C')
cat += {'A','B','C','D','E'}
morphismes = [MGC('A','B','f'),MGC('B','C','g'),MGC('C','D','h'),MGC('E','C','i'),MGC('E','A','j')]
cat += morphismes
cat.transformer_graphviz()
cat_sous = CategorieSous(cat,'B')
cat_sous.transformer_graphviz()
def test_CategorieSur():
from GrapheDeComposition import GC,MGC
from Diagramme import DiagrammeIdentite
cat = GC('C')
cat += {'A','B','C','D','E'}
morphismes = [MGC('A','B','f'),MGC('B','C','g'),MGC('C','D','h'),MGC('E','C','i'),MGC('E','A','j')]
cat += morphismes
cat.transformer_graphviz()
cat_sur = CategorieSur(cat,'B')
cat_sur.transformer_graphviz()
if __name__ == '__main__':
test_CategorieFleches()
test_CategorieSous()
test_CategorieSur()
\ No newline at end of file
...@@ -15,12 +15,9 @@ class Diagramme(Foncteur): ...@@ -15,12 +15,9 @@ class Diagramme(Foncteur):
nb_viz = 0 nb_viz = 0
def __init__(self, categorie_indexante:Categorie, categorie_indexee:Categorie, def __init__(self, categorie_indexante:Categorie, categorie_indexee:Categorie,
application_objets:dict, application_morphismes:dict, representant:any=None): application_objets:dict, application_morphismes:dict, representant:any = None):
Foncteur.__init__(self,categorie_indexante,categorie_indexee, application_objets, application_morphismes,representant=representant) Foncteur.__init__(self,categorie_indexante,categorie_indexee, application_objets,
application_morphismes,representant=representant if representant != None else "Diagramme "+str(Morphisme._id))
def __str__(self) -> str:
return "Diag"+Foncteur.__str__(self)
def faire_commuter(self): def faire_commuter(self):
""" """
Change la loi de composition de `MorphismeGrapheDeComposition` pour que le diagramme commute. Change la loi de composition de `MorphismeGrapheDeComposition` pour que le diagramme commute.
...@@ -231,7 +228,7 @@ class Diagramme(Foncteur): ...@@ -231,7 +228,7 @@ class Diagramme(Foncteur):
destination = "graphviz/diagramme"+str(Diagramme.nb_viz) destination = "graphviz/diagramme"+str(Diagramme.nb_viz)
graph = Digraph('diagramme') graph = Digraph('diagramme')
graph.attr(concentrate="true" if GRAPHVIZ_CONCENTRATE_GRAPHS else "false") graph.attr(concentrate="true" if GRAPHVIZ_CONCENTRATE_GRAPHS else "false")
graph.attr(label="Diagramme sur "+self.cible.nom) graph.attr(label=str(self))
image_objets = [self(obj) for obj in self._app_objets] image_objets = [self(obj) for obj in self._app_objets]
image_objets_count = {obj : image_objets.count(obj) for obj in image_objets} image_objets_count = {obj : image_objets.count(obj) for obj in image_objets}
...@@ -308,7 +305,7 @@ class Fleche(Diagramme): ...@@ -308,7 +305,7 @@ class Fleche(Diagramme):
_cat += _f _cat += _f
def __init__(self, categorie_indexee:Categorie, fleche_a_selectionner:Morphisme): def __init__(self, categorie_indexee:Categorie, fleche_a_selectionner:Morphisme):
Diagramme.__init__(self,Fleche._cat,categorie_indexee,{1:fleche_a_selectionner.source,2:fleche_a_selectionner.cible},{Fleche._f:fleche_a_selectionner},representant="D"+str(fleche_a_selectionner)) Diagramme.__init__(self,Fleche._cat,categorie_indexee,{1:fleche_a_selectionner.source,2:fleche_a_selectionner.cible},{Fleche._f:fleche_a_selectionner},representant="Fleche "+str(fleche_a_selectionner))
def test_Fleche(): def test_Fleche():
cat = GC() cat = GC()
...@@ -327,7 +324,8 @@ class Chemins(Diagramme): ...@@ -327,7 +324,8 @@ class Chemins(Diagramme):
chemins = list(categorie_indexee(source,cible)) chemins = list(categorie_indexee(source,cible))
morphismes = list(map(lambda x:MorphismeGrapheDeComposition(1,2,x),range(len(chemins)))) morphismes = list(map(lambda x:MorphismeGrapheDeComposition(1,2,x),range(len(chemins))))
cat += morphismes cat += morphismes
Diagramme.__init__(self,cat,categorie_indexee,{1:source,2:cible},{morphismes[i]:chemins[i] for i in range(len(chemins))}) Diagramme.__init__(self,cat,categorie_indexee,{1:source,2:cible},
{morphismes[i]:chemins[i] for i in range(len(chemins))}, 'Chemins de '+str(source)+' vers '+str(cible))
def test_Chemins(): def test_Chemins():
cat = GC() cat = GC()
...@@ -353,7 +351,8 @@ class Parallele(Diagramme): ...@@ -353,7 +351,8 @@ class Parallele(Diagramme):
""" """
app_objets = {i+1:image_objets[i] for i in range(len(image_objets))} app_objets = {i+1:image_objets[i] for i in range(len(image_objets))}
app_morph = {Parallele.morphismes[i]:image_morphismes[i] for i in range(len(image_morphismes))} app_morph = {Parallele.morphismes[i]:image_morphismes[i] for i in range(len(image_morphismes))}
Diagramme.__init__(self,Parallele._cat,categorie_indexee,app_objets,app_morph) Diagramme.__init__(self,Parallele._cat,categorie_indexee,app_objets,app_morph,
'Paralleles '+str(image_morphismes[0])+' et '+str(image_morphismes[1]))
def test_Parallele(): def test_Parallele():
cat = GC() cat = GC()
...@@ -384,7 +383,7 @@ class Triangle(Diagramme): ...@@ -384,7 +383,7 @@ class Triangle(Diagramme):
""" """
app_objets = {i+1:image_objets[i] for i in range(len(image_objets))} app_objets = {i+1:image_objets[i] for i in range(len(image_objets))}
app_morph = {Triangle.morphismes[i]:image_morphismes[i] for i in range(len(image_morphismes))} app_morph = {Triangle.morphismes[i]:image_morphismes[i] for i in range(len(image_morphismes))}
Diagramme.__init__(self,Triangle._cat,categorie_indexee,app_objets,app_morph) Diagramme.__init__(self,Triangle._cat,categorie_indexee,app_objets,app_morph,"Triangle sur "+str(categorie_indexee))
def test_Triangle(): def test_Triangle():
cat = GC() cat = GC()
...@@ -418,7 +417,7 @@ class Carre(Diagramme): ...@@ -418,7 +417,7 @@ class Carre(Diagramme):
""" """
app_objets = {i+1:image_objets[i] for i in range(len(image_objets))} app_objets = {i+1:image_objets[i] for i in range(len(image_objets))}
app_morph = {Carre.morphismes[i]:image_morphismes[i] for i in range(len(image_morphismes))} app_morph = {Carre.morphismes[i]:image_morphismes[i] for i in range(len(image_morphismes))}
Diagramme.__init__(self,