from Morphisme import Morphisme from Categorie import Categorie, mise_en_cache_call, mise_en_cache_getitem from CategorieLibre import CategorieLibre from Foncteur import Foncteur from Diagramme import DiagrammeIdentite, DiagrammeObjets from config import * from typing import * class ObjetCommaCategorie(Morphisme): """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. (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) Objet : e d D1| |D2 V f V D1(e) --> D2(d) On peut aussi voir ObjetCommaCategorie comme un morphisme, on peut alors composer deux objets de comma-catégorie et si d1=e2, on a alors o = e1 d1=e2 d2 D1| |D2 |D3 V f1 V f2 V D1(e1) --> D2(d1) --> D3(d2) """ def __init__(self, e:Any, f:Morphisme, d:Any): self.__e = e #attribut read-only self.__f = f #attribut read-only self.__d = d #attribut read-only Morphisme.__init__(self,self.e,self.d,'('+str(self.e)+','+str(self.f)+','+str(self.d)+')',self.f.is_identite and self.e == self.d) @property def e(self) -> any: return self.__e @property def f(self) -> Morphisme: return self.__f @property def d(self) -> any: return self.__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 __matmul__(self, other:'ObjetCommaCategorie') -> 'ObjetCommaCategorie': if self.e != other.d: raise Exception("Tentative de composer deux ObjetCommaCategorie pas composables : "+str(self)+" o "+str(other)) return ObjetCommaCategorie(other.e, self.f@other.f, self.d) class FlecheCommaCategorie(Morphisme): """Soit C une catégorie, T et S deux foncteurs de E dans C et D dans C. Une flèche de la comma-categorie (T|S) entre deux objets (e,f,d) et (e',f',d') est un couple (k,h) où k est une flèche de E(e,e') et h est une flèche de D(d,d') tel que la carré T(e) -T(k)-> T(e') | | f f' | | v v S(d) -S(h)-> S(d') commute. (cf. Mac Lane "Categories for the working mathematician" P.45) """ def __init__(self, source:Any, cible:Any, k:Morphisme, h:Morphisme): self.__k = k #attribut read-only self.__h = h #attribut read-only Morphisme.__init__(self,source,cible,str(source)+" "+'('+str(self.k)+','+str(self.h)+')'+" "+str(cible),source == cible and k.is_identite and h.is_identite) @property def k(self) -> Morphisme: return self.__k @property def h(self) -> Morphisme: return self.__h def __repr__(self) -> str: return str(source)+" "+str(self)+" "+str(cible) def verifier_coherence(self, T:Foncteur, S:Foncteur): if T.cible != S.cible: raise Exception("Incoherence FlecheCommaCategorie : T et S de cibles differentes : "+str(T)+" != "+str(S)) categorie = T.cible 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)) def __matmul__(self,other:'FlecheCommaCategorie') -> 'FlecheCommaCategorie': return FlecheCommaCategorie(other.source,self.cible,self.k@other.k,self.h@other.h) def __eq__(self,other:'FlecheCommaCategorie') -> bool: if not issubclass(type(other),FlecheCommaCategorie): return False return self.source == other.source and self.cible == other.cible and self.k == other.k and self.h == other.h def __hash__(self) -> int: return hash((self.k,self.h)) class CommaCategorie(CategorieLibre): """ Soit C une catégorie, T et S deux foncteurs de E dans C et D dans C. Cette catégorie est (T|S). Voir Mac Lane "Categories for the working mathematician" P.45 """ def __init__(self, T:Foncteur, S:Foncteur, nom:str = None): Categorie.__init__(self,set(),"Comma-catégorie ("+str(T)+'|'+str(S)+')' if nom == None else nom) if T.cible != S.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 __eq__(self, other:'CommaCategorie') -> bool: return self._T == other._T and self._S == other._S def __hash__(self) -> int: return hash((self._T,self._S)) 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._T.source.identite(objet.e),self._S.source.identite(objet.d)) def __getitem__(self, couple_sources_cibles:tuple) -> Generator[FlecheCommaCategorie, None, None]: sources,cibles = couple_sources_cibles for obj_comma_source in sources: for obj_comma_cible in cibles: for k in self._T.source[{obj_comma_source.e},{obj_comma_cible.e}]: for h in self._S.source[{obj_comma_source.d},{obj_comma_cible.d}]: if obj_comma_cible.f@self._T(k) == self._S(h)@obj_comma_source.f: yield FlecheCommaCategorie(obj_comma_source,obj_comma_cible,k,h) def __call__(self, sources:set, cibles:set) -> Generator[FlecheCommaCategorie, None, None]: for obj_comma_source in sources: for obj_comma_cible in cibles: for k in self._T.source({obj_comma_source.e},{obj_comma_cible.e}): for h in self._S.source({obj_comma_source.d},{obj_comma_cible.d}): if obj_comma_cible.f@self._T(k) == self._S(h)@obj_comma_source.f: yield FlecheCommaCategorie(obj_comma_source,obj_comma_cible,k,h) 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 (b|C) (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 CategorieFSous(CommaCategorie): """Soit C une catégorie, b un objet de C et F un foncteur de I vers C CategorieFSous est la catégorie F-en-dessous de b (b|F) (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|F) c'est-à-dire la comma-catégorie du diagramme qui associe à un objet unique b avec le foncteur F. Les objets de cette comma-catégorie sont de la forme <0,f,d>. """ def __init__(self, F:Foncteur, objet:Any, nom:str = None): CommaCategorie.__init__(self,DiagrammeObjets(F.cible,{objet}),F,str(F)+" 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 (C|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 class CategorieFSur(CommaCategorie): """Soit C une catégorie, b un objet de C et F un foncteur de I vers C. CategorieFSur est la catégorie F-au-dessus de b (F|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 (F|1_b) c'est-à-dire la comma-catégorie de F avec le diagramme qui associe à un objet unique b . Les objets de cette comma-catégorie sont de la forme . """ def __init__(self, F:Foncteur, objet:Any, nom:str = None): CommaCategorie.__init__(self,F,DiagrammeObjets(F.cible,{objet}),str(F)+" sur "+str(objet) if nom == None else nom) def test_CategorieFleches(): from GrapheDeComposition import GC,MGC 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 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 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()