Commit 5b87dfc9 authored by Guillaume Sabbagh's avatar Guillaume Sabbagh
Browse files

Correction __eq__ de FlecheCommaCategorie

parent 6f200014
__pycache__/ __pycache__/
graphviz/ graphviz/
.vs/
*.pdf *.pdf
*.png *.png
.idea/ .idea/
......
...@@ -6,6 +6,7 @@ import itertools ...@@ -6,6 +6,7 @@ import itertools
from Morphisme import Morphisme from Morphisme import Morphisme
from config import * from config import *
import typing import typing
from MiseEnCache import call_mis_en_cache
if GRAPHVIZ_ENABLED: if GRAPHVIZ_ENABLED:
from graphviz import Digraph from graphviz import Digraph
...@@ -172,9 +173,20 @@ class Categorie: ...@@ -172,9 +173,20 @@ class Categorie:
for o in self.objets: for o in self.objets:
graph.node(str(o)) graph.node(str(o))
for fleche in self(self.objets,self.objets): toutes_les_fleches = self(self.objets,self.objets)
for fleche in toutes_les_fleches:
if afficher_identites or not fleche.is_identite: if afficher_identites or not fleche.is_identite:
graph.edge(str(fleche.source), str(fleche.cible), label=str(fleche), weight="1000") if fleche.source not in self.objets:
raise Exception("Source d'une fleche pas dans les objets de la categorie.")
if fleche.cible not in self.objets:
raise Exception("Source d'une fleche pas dans les objets de la categorie.")
if len({obj for obj in self.objets if obj == fleche.source}) > 1:
raise Exception("Plus d'un objet de la catégorie est source de la fleche.")
if len({obj for obj in self.objets if obj == fleche.cible}) > 1:
raise Exception("Plus d'un objet de la catégorie est cible de la fleche.")
source = {obj for obj in self.objets if obj == fleche.source}.pop() #permet d'avoir toujours un objet de la catégorie comme source
cible = {obj for obj in self.objets if obj == fleche.cible}.pop() #permet d'avoir toujours un objet de la catégorie comme cible
graph.edge(str(source), str(cible), label=str(fleche), weight="1000")
graph.render(destination) graph.render(destination)
if CLEAN_GRAPHVIZ_MODEL: if CLEAN_GRAPHVIZ_MODEL:
......
from Categorie import Categorie
from Foncteur import Foncteur
from CatFinies import CatFinies
from EnsFinis import EnsFinis,Application
from ChampActif import ChampActif
from collections import defaultdict
import itertools
class FoncteurOubli(Foncteur):
"""Foncteur d'oubli du champ perceptif.
Associe à chaque cône sont nadir et à chaque flèche entre cône la flèche d'où elle vient."""
def __init__(self, champ_actif:ChampActif):
univers = champ_actif.foncteur_diagonal.source
Foncteur.__init__(self, champ_actif, univers, {obj:obj.d for obj in abs(champ_actif)},
{f:f.h for f in champ_actif(abs(champ_actif),abs(champ_actif))})
class CategorieHomologue(CatFinies):
"""Catégorie dont les objets sont des champs actifs et les morphismes sont des foncteurs qui commutent avec le foncteur d'oubli."""
def verifier_coherence(self):
CatFinies.verifier_coherence(self)
for f in self(abs(self),abs(self)):
fonct_oubli_source = FoncteurOubli(f.source)
fonct_oubli_cible = FoncteurOubli(f.cible)
if fonct_oubli_source != fonct_oubli_cible@f:
raise Exception("Incoherence CategorieHomologue : "+str(f)+" ne commute pas avec les foncteurs d'oublis")
def identite(self, objet:ChampActif) -> Foncteur:
return Foncteur(objet,objet,{o:o for o in abs(objet)},{f:f for f in objet(abs(objet),abs(objet))})
def __call__(self, sources:set, cibles:set) -> set:
result = set()
for source in sources:
for cible in cibles:
dict_nadir_cocone_source = defaultdict(frozenset)
for obj in abs(source):
dict_nadir_cocone_source[obj.d] |= {obj}
dict_nadir_cocone_cible = defaultdict(frozenset)
for obj in abs(cible):
dict_nadir_cocone_cible[obj.d] |= {obj}
if set(dict_nadir_cocone_source.keys()) != set(dict_nadir_cocone_cible.keys()):
continue
applications_objets = set() # applications entre cocônes de même nadir
ens_objets = EnsFinis()
for nadir in dict_nadir_cocone_source:
ens_objets |= {dict_nadir_cocone_source[nadir]}
ens_objets |= {dict_nadir_cocone_cible[nadir]}
applications_objets |= {ens_objets({dict_nadir_cocone_source[nadir]},{dict_nadir_cocone_cible[nadir]})}
for application_objet in itertools.product(*applications_objets):
app_obj = dict([x for app in application_objet for x in app.as_dict().items()])
app_fleche_foncteur = dict() # à chaque couple d'objets on associe un ensemble d'applications
for c,d in itertools.product(source.objets, repeat=2):
ens_fleches = EnsFinis({frozenset(source({c},{d})),frozenset(cible({app_obj[c]},{app_obj[d]}))})
app_fleches_c_vers_d = ens_fleches({frozenset(source({c},{d}))},{frozenset(cible({app_obj[c]},{app_obj[d]}))})
app_fleche_foncteur[(c,d)] = app_fleches_c_vers_d
if len(app_fleches_c_vers_d) == 0:
break
if len(app_fleche_foncteur[(c,d)]) == 0: #la dernière recherche d'applications à échouée, on passe à l'application objet suivante
continue
for applications_fleches in itertools.product(*app_fleche_foncteur.values()):
app_fleches = dict()
for app in applications_fleches:
app_fleches.update(app.as_dict())
for f in source(abs(source),abs(source)):
for g in source(abs(source),{f.source}):
if app_fleches[f@g] != app_fleches[f]@app_fleches[g]:
break
else:
continue
break
else:
result |= {Foncteur(source,cible,app_obj,app_fleches)}
return result
def test_FoncteurOubli():
from GrapheDeComposition import GC,MGC
from Diagramme import Triangle,DiagrammeIdentite
gc = GC()
gc |= set("ABCDEF")
f,g,h,i,j,k,l = [MGC('A','B','f'),MGC('B','C','g'),MGC('D','E','h'),MGC('E','F','i'),MGC('A','D','j'),MGC('B','E','k'),MGC('C','F','l')]
gc |= {f,g,h,i,j,k,l}
# diag_identite = DiagrammeIdentite(gc)
# diag_identite.faire_commuter()
d1 = Triangle(gc,"DEF",[h,i,i@h])
c_p = ChampActif(d1)
foncteur_oubli = FoncteurOubli(c_p)
foncteur_oubli.transformer_graphviz()
def test_CategorieHomologue():
from GrapheDeComposition import GC,MGC
from Diagramme import Fleche,DiagrammeIdentite
gc = GC()
gc |= set("ABCDEFGH")
f,g,h,i,j,k,l,m,n = [MGC('A','B','f'),MGC('B','C','g'),MGC('D','E','h'),MGC('E','F','i'),MGC('A','D','j'),MGC('B','E','k'),MGC('C','F','l'),MGC('G','A','m'),MGC('H','A','n')]
gc |= {f,g,h,i,j,k,l,m,n}
diag_identite = DiagrammeIdentite(gc)
diag_identite.faire_commuter()
d1 = Fleche(gc,m)
c_p1 = ChampActif(d1)
d2 = Fleche(gc,n)
c_p2 = ChampActif(d2)
cph = CategorieHomologue({c_p1,c_p2})
cph.transformer_graphviz()
f,g = cph.isomorphismes(c_p1,c_p2).pop()
f.transformer_graphviz()
g.transformer_graphviz()
if __name__ == '__main__':
test_FoncteurOubli()
test_CategorieHomologue()
\ No newline at end of file
from CommaCategorie import CommaCategorie from CommaCategorie import CommaCategorie, ObjetCommaCategorie
from TransformationNaturelle import CatTransfoNat,TransfoNat from TransformationNaturelle import CatTransfoNat,TransfoNat
from Foncteur import Foncteur from Foncteur import Foncteur
from Diagramme import DiagrammeConstant,DiagrammeObjets from Diagramme import DiagrammeConstant,DiagrammeObjets
class Cocone(TransfoNat):
"""Un cocône sur D de nadir N est une transformation naturelle de D vers le foncteur constant Δ_N."""
def __init__(self, objet_champ_actif:ObjetCommaCategorie):
self.__nadir = objet_champ_actif.d # attribut read-only
f = objet_champ_actif.f
TransfoNat.__init__(self,f.source,f.cible,f._composantes,f.nom)
@property
def nadir(self):
return self.__nadir
def as_ObjetCommaCategorie(self) -> ObjetCommaCategorie:
return ObjetCommaCategorie(0,self,self.nadir)
class ChampActif(CommaCategorie): class ChampActif(CommaCategorie):
"""Le champ actif d'un diagramme(ou foncteur) D:P->Q est défini comme étant la comma-catégorie (D|Δ) """Le champ actif d'un diagramme(ou foncteur) D:P->Q est défini comme étant la comma-catégorie (D|Δ)
(cf. https://en.wikipedia.org/wiki/Cone_(category_theory)#Equivalent_formulations) (cf. https://en.wikipedia.org/wiki/Cone_(category_theory)#Equivalent_formulations)
...@@ -27,15 +41,17 @@ class ChampActif(CommaCategorie): ...@@ -27,15 +41,17 @@ class ChampActif(CommaCategorie):
CommaCategorie.__init__(self,self.foncteur_vers_D,self.foncteur_diagonal, "Champ actif de "+str(diagramme) if nom == None else nom) CommaCategorie.__init__(self,self.foncteur_vers_D,self.foncteur_diagonal, "Champ actif de "+str(diagramme) if nom == None else nom)
def cocones(self,nadirs:set) -> set: def objets_cocones(self,nadirs:set) -> set:
"""`nadirs` est un ensemble d'objets de Q """`nadirs` est un ensemble d'objets de Q
Cette fonction renvoie l'ensemble tous les cocônes de nadir un objets d'`nadirs`. Cette fonction renvoie l'ensemble tous les cocônes de nadir un objets d'`nadirs`.
Un cocône est une transformation naturelle de D vers le diagramme constant sur le nadir.""" Un cocône est une transformation naturelle de D vers le diagramme constant sur le nadir.
return {obj.f for obj in self.objets for nadir in nadirs if obj.d == nadir} Cette fonction renvoie les objets de la comma-catégorie qui contiennent ces cocônes."""
return {obj for obj in self.objets for nadir in nadirs if obj.d == nadir}
def colimites(self) -> set: def objets_colimites(self) -> set:
"""Renvoie un ensemble de cocônes colimites. """Renvoie un ensemble de cocônes colimites.
Les cocônes colimites sont des objets initiaux dans le champ actif.""" Les cocônes colimites sont des objets initiaux dans le champ actif.
Cette fonction renvoie les objets de la comma-catégorie qui contiennent ces cocônes."""
if len(self.objets) == 0: if len(self.objets) == 0:
return set() return set()
cocones = list(self.objets) cocones = list(self.objets)
...@@ -43,14 +59,14 @@ class ChampActif(CommaCategorie): ...@@ -43,14 +59,14 @@ class ChampActif(CommaCategorie):
cocones_visites = {cocone_courant} cocones_visites = {cocone_courant}
cocones_restants = self.objets-cocones_visites cocones_restants = self.objets-cocones_visites
fleches_accessibles = self(cocones_restants,{cocone_courant}) fleches_accessibles = self(cocones_restants,{cocone_courant})
while len(fleches_accessibles) > 0: while len(fleches_accessibles) > 0:
fleche_choisie = list(fleches_accessibles)[0] fleche_choisie = list(fleches_accessibles)[0]
cocone_courant = fleche_choisie.source cocone_courant = fleche_choisie.source
cocones_visites |= {cocone_courant} cocones_visites |= {cocone_courant}
cocones_restants = self.objets-cocones_visites cocones_restants = self.objets-cocones_visites
fleches_accessibles = self({cocone_courant},cocones_restants) fleches_accessibles = self(cocones_restants,{cocone_courant})
# ici cocone_courant est un objet initial de la catégorie # ici cocone_courant est un objet initial de la catégorie
return {cocone.f for cocone in self.objets if len(self.isomorphismes(cocone_courant,cocone)) > 0} return {cocone for cocone in self.objets if len(self.isomorphismes(cocone_courant,cocone)) > 0}
def test_ChampActif(): def test_ChampActif():
from GrapheDeComposition import GC,MGC from GrapheDeComposition import GC,MGC
...@@ -64,7 +80,7 @@ def test_ChampActif(): ...@@ -64,7 +80,7 @@ def test_ChampActif():
diag_identite = DiagrammeIdentite(gc) diag_identite = DiagrammeIdentite(gc)
diag_identite.faire_commuter() diag_identite.faire_commuter()
d1 = Triangle(gc,"DEF",[h,i,i@h]) d1 = Triangle(gc,"ABC",[f,g,g@f])
c_p = ChampActif(d1) c_p = ChampActif(d1)
for cocone in c_p.cocones(gc.objets): for cocone in c_p.cocones(gc.objets):
...@@ -77,6 +93,6 @@ def test_ChampActif(): ...@@ -77,6 +93,6 @@ def test_ChampActif():
colimites[i].nom = "Colimite "+str(i) colimites[i].nom = "Colimite "+str(i)
print(str(colimites)) print(str(colimites))
colimites[i].transformer_graphviz() colimites[i].transformer_graphviz()
if __name__ == '__main__': if __name__ == '__main__':
test_ChampActif() test_ChampActif()
\ No newline at end of file
from Categorie import Categorie from Categorie import Categorie
from CommaCategorie import CommaCategorie, CategorieSur from CommaCategorie import CommaCategorie, ObjetCommaCategorie
from TransformationNaturelle import CatTransfoNat,TransfoNat from TransformationNaturelle import CatTransfoNat,TransfoNat
from Foncteur import Foncteur from Foncteur import Foncteur
from Diagramme import DiagrammeConstant,DiagrammeObjets from Diagramme import DiagrammeConstant,DiagrammeObjets
class Cone(TransfoNat):
"""Un cône sur D d'apex A est une transformation naturelle du foncteur constant Δ_A vers D."""
def __init__(self, objet_champ_perceptif:ObjetCommaCategorie):
self.__apex = objet_champ_perceptif.e # attribut read-only
f = objet_champ_perceptif.f
TransfoNat.__init__(self,f.source,f.cible,f._composantes,f.nom)
@property
def apex(self):
return self.__apex
def as_ObjetCommaCategorie(self) -> ObjetCommaCategorie:
return ObjetCommaCategorie(self.apex,self,0)
class ChampPerceptif(CommaCategorie): class ChampPerceptif(CommaCategorie):
"""Le champ perceptif d'un diagramme(ou foncteur) D:P->Q est défini comme étant la comma-catégorie (Δ|D) """Le champ perceptif d'un diagramme(ou foncteur) D:P->Q est défini comme étant la comma-catégorie (Δ|D)
(cf. https://en.wikipedia.org/wiki/Cone_(category_theory)#Equivalent_formulations) (cf. https://en.wikipedia.org/wiki/Cone_(category_theory)#Equivalent_formulations)
...@@ -28,15 +42,17 @@ class ChampPerceptif(CommaCategorie): ...@@ -28,15 +42,17 @@ class ChampPerceptif(CommaCategorie):
CommaCategorie.__init__(self,self.foncteur_diagonal,self.foncteur_vers_D, "Champ perceptif de "+str(diagramme)+" ("+str(Categorie._id)+")" if nom == None else nom) CommaCategorie.__init__(self,self.foncteur_diagonal,self.foncteur_vers_D, "Champ perceptif de "+str(diagramme)+" ("+str(Categorie._id)+")" if nom == None else nom)
def cones(self,apices:set) -> set: def objets_cones(self,apices:set) -> set:
"""`apices` est un ensemble d'objets de Q """`apices` est un ensemble d'objets de Q
Cette fonction renvoie l'ensemble tous les cônes d'apex un objets d'`apices`. Cette fonction renvoie l'ensemble tous les cônes d'apex un objets d'`apices`.
Un cône est une transformation naturelle du diagramme constant sur l'apex vers D.""" Un cône est une transformation naturelle du diagramme constant sur l'apex vers D.
return {obj.f for obj in self.objets for apex in apices if obj.e == apex} Cette fonction renvoie les objets de la comma-catégorie qui contiennent ces cônes."""
return {obj for obj in self.objets for apex in apices if obj.e == apex}
def limites(self) -> set: def objets_limites(self) -> set:
"""Renvoie un ensemble de cônes limites. """Renvoie un ensemble de cônes limites.
Les cônes limites sont des objets finaux dans le champ perceptif.""" Les cônes limites sont des objets finaux dans le champ perceptif.
Cette fonction renvoie les objets de la comma-catégorie qui contiennent ces cônes."""
if len(self.objets) == 0: if len(self.objets) == 0:
return set() return set()
cones = list(self.objets) cones = list(self.objets)
...@@ -51,7 +67,7 @@ class ChampPerceptif(CommaCategorie): ...@@ -51,7 +67,7 @@ class ChampPerceptif(CommaCategorie):
cones_restants = self.objets-cones_visites cones_restants = self.objets-cones_visites
fleches_accessibles = self({cone_courant},cones_restants) fleches_accessibles = self({cone_courant},cones_restants)
# ici cone_courant est un objet final de la catégorie # ici cone_courant est un objet final de la catégorie
return {cone.f for cone in self.objets if len(self.isomorphismes(cone_courant,cone)) > 0} return {cone for cone in self.objets if len(self.isomorphismes(cone_courant,cone)) > 0}
def test_ChampPerceptif(): def test_ChampPerceptif():
...@@ -66,7 +82,10 @@ def test_ChampPerceptif(): ...@@ -66,7 +82,10 @@ def test_ChampPerceptif():
diag_identite = DiagrammeIdentite(gc) diag_identite = DiagrammeIdentite(gc)
diag_identite.faire_commuter() diag_identite.faire_commuter()
gc.transformer_graphviz()
d1 = Triangle(gc,"DEF",[h,i,i@h]) d1 = Triangle(gc,"DEF",[h,i,i@h])
d1.transformer_graphviz()
c_p = ChampPerceptif(d1) c_p = ChampPerceptif(d1)
for cone in c_p.cones(gc.objets): for cone in c_p.cones(gc.objets):
......
...@@ -3,6 +3,7 @@ from Categorie import Categorie ...@@ -3,6 +3,7 @@ from Categorie import Categorie
from Foncteur import Foncteur from Foncteur import Foncteur
from Diagramme import DiagrammeIdentite, DiagrammeObjets from Diagramme import DiagrammeIdentite, DiagrammeObjets
from config import * from config import *
from MiseEnCache import call_mis_en_cache
class ObjetCommaCategorie(Morphisme): class ObjetCommaCategorie(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.
...@@ -91,7 +92,7 @@ class FlecheCommaCategorie(Morphisme): ...@@ -91,7 +92,7 @@ class FlecheCommaCategorie(Morphisme):
return FlecheCommaCategorie(other.source,self.cible,self.k@other.k,self.h@other.h) return FlecheCommaCategorie(other.source,self.cible,self.k@other.k,self.h@other.h)
def __eq__(self,other:'FlecheCommaCategorie') -> bool: def __eq__(self,other:'FlecheCommaCategorie') -> bool:
return self.k == other.k and self.h == other.h return self.source == other.source and self.cible == other.cible and self.k == other.k and self.h == other.h
def __hash__(self) -> int: def __hash__(self) -> int:
return hash((self.k,self.h)) return hash((self.k,self.h))
...@@ -122,7 +123,7 @@ class CommaCategorie(Categorie): ...@@ -122,7 +123,7 @@ class CommaCategorie(Categorie):
def identite(self, objet:ObjetCommaCategorie) -> FlecheCommaCategorie: 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).''' '''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))) return FlecheCommaCategorie(objet,objet,self.__C.identite(self._T(objet.e)),self.__C.identite(self._S(objet.d)))
def __call__(self, sources:set, cibles:set) -> set: def __call__(self, sources:set, cibles:set) -> set:
result = set() result = set()
for a in sources: for a in sources:
......
...@@ -39,7 +39,7 @@ class Application(Morphisme): ...@@ -39,7 +39,7 @@ class Application(Morphisme):
return self._app[element] return self._app[element]
def __matmul__(self, other:'Application') -> 'Application': def __matmul__(self, other:'Application') -> 'Application':
return Application(other.source,self.cible,frozenset({e:self(other(e)) for e in other.source})) return Application(other.source,self.cible,{e:self(other(e)) for e in other.source})
def __repr__(self): def __repr__(self):
return "\n".join(map(lambda x:str(x[0])+':'+str(x[1]),self._app.items()))+'\n' return "\n".join(map(lambda x:str(x[0])+':'+str(x[1]),self._app.items()))+'\n'
...@@ -78,8 +78,8 @@ class CategorieEnsemblesFinis(Categorie): ...@@ -78,8 +78,8 @@ class CategorieEnsemblesFinis(Categorie):
def __init__(self, objets:set = set(), nom:str = "Catégorie d'ensembles finis"): def __init__(self, objets:set = set(), nom:str = "Catégorie d'ensembles finis"):
Categorie.__init__(self,objets,nom) Categorie.__init__(self,objets,nom)
def identite(self, ensemble:frozenset()) -> Application: def identite(self, ensemble:frozenset) -> Application:
return Application(ensemble,ensemble,frozenset({e:e for e in ensemble})) return Application(ensemble,ensemble,{e:e for e in ensemble})
def __call__(self, sources:set, cibles:set) -> frozenset: def __call__(self, sources:set, cibles:set) -> frozenset:
result = frozenset() result = frozenset()
...@@ -93,6 +93,15 @@ class CategorieEnsemblesFinis(Categorie): ...@@ -93,6 +93,15 @@ class CategorieEnsemblesFinis(Categorie):
return result return result
EnsFinis = CategorieEnsemblesFinis EnsFinis = CategorieEnsemblesFinis
class CategorieEnsembleParties(EnsFinis):
"""CategorieEnsembleParties peut être abrégé en EnsParties
Catégorie de l'ensemble des parties d'un ensemble, les morphismes sont des applications."""
def __init__(self, ensemble:set, nom:str = None):
EnsFinis.__init__(self,{frozenset(ens) for i in range(len(ensemble)+1) for ens in itertools.combinations(ensemble,i)},"Catégorie des parties de "+str(ensemble) if nom == None else nom)
EnsParties = CategorieEnsembleParties
def test_EnsFinis(): def test_EnsFinis():
...@@ -105,7 +114,10 @@ def test_EnsFinis(): ...@@ -105,7 +114,10 @@ def test_EnsFinis():
print("fleche de {1,2} vers {}") print("fleche de {1,2} vers {}")
fleche.transformer_graphviz() fleche.transformer_graphviz()
def test_EnsParties():
cat = EnsParties({1,2,3})
cat.transformer_graphviz()
if __name__ == '__main__': if __name__ == '__main__':
test_EnsFinis() test_EnsFinis()
\ No newline at end of file test_EnsParties()
\ No newline at end of file
from GrapheDeComposition import GC,MGC from EnsFinis import EnsParties
from Diagramme import Triangle,DiagrammeIdentite from Diagramme import DiagrammeObjets
from ChampActif import ChampActif,Cocone
from CommaCategorie import ObjetCommaCategorie
gc1 = GC() from Categorie import SousCategoriePleine
gc1 |= set("ABCDEF") from CategorieHomologue import CategorieHomologue
f,g,h,i,j,k,l = [MGC('A','B','f'),MGC('B','C','g'),MGC('D','E','h'),MGC('E','F','i'),MGC('A','D','j'),MGC('B','E','k'),MGC('C','F','l')]
gc1 |= {f,g,h,i,j,k,l} cat = EnsParties({1,2,3})
cat.transformer_graphviz()
diag_identite = DiagrammeIdentite(gc1)
diag_identite.faire_commuter() d1 = DiagrammeObjets(cat,{frozenset({1,2}),frozenset({3})})
\ No newline at end of file d2 = DiagrammeObjets(cat,{frozenset({3,2}),frozenset({1})})
d1.transformer_graphviz()
#d2.transformer_graphviz()
c_p1 = ChampActif(d1)
c_p2 = ChampActif(d2)
sous_c_p1 = SousCategoriePleine(c_p1,c_p1.objets_colimites())
sous_c_p1.transformer_graphviz()
sous_c_p2 = SousCategoriePleine(c_p2,c_p2.objets_colimites())
sous_c_p2.transformer_graphviz()
cat_hom = CategorieHomologue({sous_c_p1,sous_c_p2}) #on cherche simplement un isomoprhisme entre les colimites pour dire qu'ils ont les mêmes colimites
print("cat_hom")
cat_hom.transformer_graphviz()
\ No newline at end of file
from collections import defaultdict
# Décorateurs qui permettent de mettre en cache le résultat de certaines fonctions
def call_mis_en_cache(func):
"""Stocke le résultat de __call__ dans un cache et cherche dans le cache lors de l'appel de __call__.
/!\ Attention si la catégorie à changée entre temps, les couples d'objets mis en cache renverront les même morphismes."""
if func.__name__ != '__call__':
raise Exception("Mise en cache d'une fonction differente de __call__ : "+str(func))
def wrapper(self, sources:set, cibles:set) -> set:
if not hasattr(self,"__cache__call__"):
self.__cache__call__ = defaultdict(set)
nouvelles_sources = set()
nouvelles_cibles = set()
result = set()
for source in sources:
for cible in cibles:
if (source,cible) in self.__cache__call__:
result |= self.__cache__call__[(source,cible)]
else:
nouvelles_sources |= {source}
nouvelles_cibles |= {cible}
nouveaux_resultats = set()
for s in nouvelles_sources:
for c in nouvelles_cibles:
nouveau_r = func(self,{s},{c})
nouveaux_resultats |= nouveau_r
self.__cache__call__[(s,c)] |= nouveau_r
return nouveaux_resultats|result
return wrapper
\ No newline at end of file
...@@ -35,7 +35,7 @@ class Morphisme: ...@@ -35,7 +35,7 @@ class Morphisme:
return str(self.nom)+' : '+str(self.source)+" -> "+str(self.cible) return str(self.nom)+' : '+str(self.source)+" -> "+str(self.cible)
def __repr__(self) -> str: def __repr__(self) -> str:
return self.pretty_print()#+","+super().__repr__().split('object at ')[-1].split('>')[0] return self.pretty_print()+","+super().__repr__().split('object at ')[-1].split('>')[0]
def __matmul__(self,other:'Morphisme') -> 'Morphisme': def __matmul__(self,other:'Morphisme') -> 'Morphisme':
raise NotImplementedError("Les classes filles doivent implémenter la composition des morphismes.") raise NotImplementedError("Les classes filles doivent implémenter la composition des morphismes.")
......
...@@ -7,6 +7,7 @@ from Categorie import Categorie ...@@ -7,6 +7,7 @@ from Categorie import Categorie
from Morphisme import Morphisme from Morphisme import Morphisme
from Diagramme import Diagramme from Diagramme import Diagramme
from EnsFinis import Application, EnsFinis from EnsFinis import Application, EnsFinis
from MiseEnCache import call_mis_en_cache
if GRAPHVIZ_ENABLED: if GRAPHVIZ_ENABLED:
from graphviz import Digraph from graphviz import Digraph
...@@ -115,6 +116,7 @@ class CategorieTransformationsNaturelles(Categorie): ...@@ -115,6 +116,7 @@ class CategorieTransformationsNaturelles(Categorie):
def identite(self, diag:Diagramme) -> TransfoNat: def identite(self, diag:Diagramme) -> TransfoNat:
return TransfoNat(diag,diag,{o:diag.cible.identite(diag(o)) for o in diag.source.objets}) return TransfoNat(diag,diag,{o:diag.cible.identite(diag(o)) for o in diag.source.objets})
def __call__(self, sources:set, cibles:set) -> set: def __call__(self, sources:set, cibles:set) -> set:
result = set() result = set()
if len(sources) > 0: if len(sources) > 0:
......