Commit c98d3bad authored by Guillaume Sabbagh's avatar Guillaume Sabbagh
Browse files

ChampPerceptif terminé

parent 95862442
from Categorie import Categorie
from Diagramme import DiagrammeObjets
from config import *
class CategorieDiagrammes(Categorie):
"""
Classe abstraite qui définit ce qu'est une catégorie de diagrammes sur une catégorie C.
La catégorie des diagrammes dans une catégorie est infinie, nous nous intéressons à des sous-catégories finies de cette catégorie.
Pour cela, la catégorie des diagrammes de C contient par défaut les diagrammes constants 1->x pour tout objet x dans C.
On peut ensuite ajouter les diagrammes d'intérêt qui nous intéressent comme on ajouterait un objet à un catégorie (avec |=).
/!\ si on ajoute un objet à la catégorie C après la création de la catégorie des diagrammes, cet objet n'aura pas de diagramme constant associé /!\
"""
def __init__(self, C:Categorie, objets:set = set(), nom:str = None):
Categorie.__init__(self,objets,"Categorie des diagrammes sur "+str(C) if nom == None else nom)
self.categorie_initiale = C
self |= {DiagrammeObjets(C,obj) for obj in C.objets }
\ No newline at end of file
from CommaCategorie import CommaCategorie
from TransformationNaturelle import CatTransfoNat,TransfoNat
from Foncteur import Foncteur
from Diagramme import DiagrammeConstant,DiagrammeObjets
class ChampPerceptif(CommaCategorie):
"""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)
Un objet (A,C,Id) du champ perceptif nous donne un cône C d'apex A sur le diagramme D.
Δ:Q -> (P->Q) est un foncteur dans une catégorie infinie, on ne s'intéresse qu'aux diagrammes constants Δq : P->Q, _|->q,_|->1q avec q \in Q
et au diagramme D.
En ne s'intéressant qu'à ces diagrammes, on obtient quand même tous les cônes sur D.
"""
def __init__(self, diagramme:Foncteur):
P = diagramme.source
Q = diagramme.cible
self.categorie_diagrammes = CatTransfoNat({DiagrammeConstant(P,Q,o) for o in Q.objets},
"Categorie de diagrammes du champ perceptif de "+str(diagramme))
self.categorie_diagrammes |= {diagramme}
self.foncteur_diagonal = Foncteur(Q,self.categorie_diagrammes,{o:DiagrammeConstant(P,Q,o) for o in Q.objets},
{f: TransfoNat(DiagrammeConstant(P,Q,f.source),DiagrammeConstant(P,Q,f.cible),{p:f for p in P.objets}) for f in Q(abs(Q),abs(Q))})
## on associe à chaque objet son diagramme constant et à chaque flèche F:a->b la transformation naturelle qui va de Δa à Δb
self.foncteur_vers_D = DiagrammeObjets(self.categorie_diagrammes,{diagramme})
CommaCategorie.__init__(self,self.foncteur_diagonal,self.foncteur_vers_D)
def cones(self,apices:set) -> set:
"""`apices` est un ensemble d'objets de Q
Cette fonction renvoie l'ensemble tous les cônes d'apex un objets d'`apices`."""
return {obj.f for obj in self.objets for apex in apices if obj.e == apex}
def test_ChampPerceptif():
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 = ChampPerceptif(d1)
for cone in c_p.cones(gc.objets):
cone.transformer_graphviz()
c_p.transformer_graphviz()
if __name__ == '__main__':
test_ChampPerceptif()
\ No newline at end of file
......@@ -78,7 +78,7 @@ class CommaCategorie(Categorie):
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
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
......@@ -110,7 +110,7 @@ class CategorieFleches(CommaCategorie):
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
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.
......@@ -123,7 +123,7 @@ 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
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 .
......
......@@ -431,7 +431,22 @@ def test_DiagrammeIdentite():
cat.transformer_graphviz()
diag.transformer_graphviz()
class DiagrammeConstant(Diagramme):
"""Diagramme constant vers un objet noté Δ.
Un diagramme constant Δ(A) envoie tous les objets d'une catégorie indexante sur un objet A et toutes
les flèches de la catégorie indexante vers 1A.
"""
def __init__(self, categorie_indexante:Categorie, categorie_indexee:Categorie, objet:any):
Diagramme.__init__(self,categorie_indexante,categorie_indexee,{o:objet for o in categorie_indexante.objets},
{f:categorie_indexee.identite(objet) for f in categorie_indexante(abs(categorie_indexante),abs(categorie_indexante))},
'C('+str(objet)+')')
def test_DiagrammeConstant():
cat = GC(set("ABCD"))
f,g,h,i = [MGC('A','B','f'),MGC('B','C','g'),MGC('A','D','h'),MGC('D','C','i')]
cat |= {f,g,h,i}
diag = DiagrammeConstant(cat,cat,'B')
diag.transformer_graphviz()
if __name__ == '__main__':
test_Diagramme()
......@@ -441,4 +456,5 @@ if __name__ == '__main__':
test_Parallele()
test_Triangle()
test_Carre()
test_DiagrammeIdentite()
\ No newline at end of file
test_DiagrammeIdentite()
test_DiagrammeConstant()
\ No newline at end of file
......@@ -16,7 +16,10 @@ class Application(Morphisme):
self._app = application
if TOUJOURS_VERIFIER_COHERENCE:
self.verifier_coherence()
def as_dict(self) -> dict:
return self._app
def verifier_coherence(self):
if len(frozenset(self._app.keys())) != len(self._app.keys()):
raise Exception("Incoherence Application : un element a plusieurs images "+str(self._app))
......@@ -38,6 +41,10 @@ class Application(Morphisme):
def __matmul__(self, other:'Application') -> 'Application':
return Application(other.source,self.cible,frozenset({e:self(other(e)) for e in other.source}))
def __repr__(self):
return "\n".join(map(lambda x:str(x[0])+':'+str(x[1]),self._app.items()))+'\n'
def transformer_graphviz(self, destination:any=None):
Application.nb_viz += 1
if destination == None:
......
......@@ -91,6 +91,7 @@ class Foncteur(Morphisme):
return functools.reduce(lambda x,y:x@y,[self._app_morph[morph] for morph in param])
def transformer_graphviz(self, destination:any=None, afficher_identites:bool = False):
from GrapheDeComposition import MGC
Foncteur.nb_viz += 1
if destination == None:
destination = "graphviz/foncteur"+str(Foncteur.nb_viz)
......@@ -124,7 +125,7 @@ class Foncteur(Morphisme):
cluster.node(str(o)+suffixe2_objet)
for morph in self.cible(self.cible.objets,self.cible.objets):
if not morph.is_identite or afficher_identites:
couleur = 'black' if len(morph) == 1 else 'grey70'
couleur = 'black' if not issubclass(type(morph),MGC) or len(morph) == 1 else 'grey70'
cluster.node(str(morph)+suffixe2_morph,style="invis",shape="point")
graph.edge(str(morph.source)+suffixe2_objet,str(morph)+suffixe2_morph,color=couleur,label=str(morph)+suffixe2_morph,headclip="False",arrowhead="none")
graph.edge(str(morph)+suffixe2_morph,str(morph.cible)+suffixe2_objet,color=couleur,tailclip="false")
......
from Morphisme import Morphisme
from CategorieDiagrammes import CategorieDiagrammes
from Diagramme import DiagrammeObjets
from Categorie import Categorie
from CommaCategorie import ObjetCommaCategorie
from Foncteur import Foncteur
import itertools
......@@ -86,12 +87,16 @@ class Interaction(Morphisme):
os.remove(destination)
class CategorieInteractions(CategorieDiagrammes):
class CategorieInteractions(Categorie):
"""
Categorie dont les objets sont des diagrammes et les morphismes sont des interactions.
"""
nb_viz = 0
def __init__(self, objets:set = set(), nom:str = None):
Categorie.__init__(self,objets,"Catégorie des diagrammes et interactions sur "+str(C) if nom == None else nom)
self.categorie_initiale = C
self |= {DiagrammeObjets(C,obj) for obj in C.objets }
def __call__(self, source:set, cible:set) -> set:
result = set()
......
from Morphisme import Morphisme
from Foncteur import Foncteur
from config import *
import itertools
from Interaction import Interaction
from CommaCategorie import ObjetCommaCategorie
from Categorie import Categorie
from Morphisme import Morphisme
from Diagramme import Diagramme
from EnsFinis import Application, EnsFinis
if GRAPHVIZ_ENABLED:
from graphviz import Digraph
class TransformationNaturelle(Morphisme):
class TransformationNaturelle(Interaction):
"""TransformationNaturelle peut être abrégé TransfoNat.
Une transformation naturelle d'un foncteur à un autre.
Soit F et G deux foncteurs de C dans D.
......@@ -20,7 +20,7 @@ class TransformationNaturelle(Morphisme):
nb_viz = 0
__id = 0
def __init__(self, foncteur_source:Foncteur, foncteur_cible:Foncteur, composantes:Application):
def __init__(self, foncteur_source:Foncteur, foncteur_cible:Foncteur, composantes:dict):
"""
`foncteur_source` et `foncteur_cible` deux foncteurs de C vers D.
`composantes` est un dictionnaire {`c`:`morph`} où `c` est un objet de C, `morph` un morphisme de B de foncteur_source(`c`) vers foncteur_cible(`c`)."""
......@@ -29,15 +29,10 @@ class TransformationNaturelle(Morphisme):
self.__F = foncteur_source
self.__G = foncteur_cible
if self.__F == self.__G and all([composantes(e)==self.__D.identite(self.__F(e)) for e in composantes.source]):
is_identite = True
else:
is_identite = False
Morphisme.__init__(self,foncteur_source, foncteur_cible,\
'('+str(self.__F.representant)+')=>('+str(self.__G.representant)+')', is_identite)
self._composantes = composantes
Interaction.__init__(self,foncteur_source, foncteur_cible, {ObjetCommaCategorie(c,composantes[c],c) for c in composantes})
self.__id = TransfoNat.__id #pour la transformation en str
TransfoNat.__id += 1
self._composantes = composantes
if TOUJOURS_VERIFIER_COHERENCE:
self.verifier_coherence()
......@@ -45,7 +40,7 @@ class TransformationNaturelle(Morphisme):
"""Renvoie l'image d'un objet de C."""
if obj not in self.__C.objets:
raise Exception("L'objet "+str(obj)+" n'appartient pas à la categorie C = "+str(self.__C))
return self._composantes(obj)
return self._composantes[obj]
def __eq__(self, other:'TransformationNaturelle') -> bool:
if not issubclass(type(other),TransformationNaturelle):
......@@ -53,26 +48,22 @@ class TransformationNaturelle(Morphisme):
return self.source == other.source and self.cible == other.cible and self._composantes == other._composantes
def __hash__(self) -> int:
return hash((self.source,self.cible,self._composantes))
return hash((self.source,self.cible,frozenset(self._composantes.items())))
def __str__(self):
return "TN"+str(self.__id)
def __matmul__(self, other:'TransformationNaturelle') -> 'TransformationNaturelle':
"""Composition verticale des transformations naturelles."""
return TransformationNaturelle(other.source,self.cible,
Application(other._composantes.source,self._composantes.cible,{c:self(c)@other(c) for c in self.__C.objets}))
def as_interaction(self) -> Interaction:
return Interaction(self.__F,self.__G,{ObjetCommaCategorie(c,self(c),c) for c in self._composantes.source})
return TransformationNaturelle(other.source,self.cible,{c:self(c)@other(c) for c in self.__C.objets})
def verifier_coherence(self):
if self.source.source != self.cible.source:
raise Exception("Incoherence TransformationNaturelle : foncteur sources et cible n'ont pas la meme categorie source "+str(self.source)+' '+str(self.cible))
if self.source.cible != self.cible.cible:
raise Exception("Incoherence TransformationNaturelle : les foncteurs source et cible n'ont pas la meme categorie cible "++str(self.source)+' '+str(self.cible))
if set(self._composantes.source) != self.__C.objets:
if set(self._composantes.keys()) != self.__C.objets:
raise Exception("Incoherence TransformationNaturelle : les objets de la categorie C ne sont pas les memes que les antecedants des composantes\n"+\
str(self._composantes)+"\n"+str(self.__C.objets))
......@@ -84,8 +75,6 @@ class TransformationNaturelle(Morphisme):
"Sf = "+str(self.__F(f))+"\ntC' = "+str(self(c2))+"\ntC = "+str(self(c1))+"\nTf = "+str(self.__G(f))+\
"tC' o Sf != Tf o tC : "+str(self(c2)@self.__F(f)) + " != "+str(self.__G(f)@self(c1)))
def transformer_graphviz(self, destination = None, afficher_identites = False):
self.as_interaction().transformer_graphviz(destination,afficher_identites)
TransfoNat = TransformationNaturelle
......@@ -107,11 +96,11 @@ def test_TransfoNat():
d1.transformer_graphviz()
d2.transformer_graphviz()
tn = TransfoNat(d1,d2,Application(d1.source.objets,gc(abs(gc),abs(gc)),{1:j,2:k,3:l}))
tn = TransfoNat(d1,d2,{1:j,2:k,3:l})
tn.transformer_graphviz()
d3 = Triangle(gc,"EEF",[gc.identite('E'),i,i])
tn2 = TransfoNat(d2,d3,Application(d1.source.objets,gc(abs(gc),abs(gc)),{1:h,2:gc.identite('E'),3:gc.identite('F')}))
tn2 = TransfoNat(d2,d3,{1:h,2:gc.identite('E'),3:gc.identite('F')})
tn2.transformer_graphviz()
tn3 = tn2@tn
......@@ -147,7 +136,7 @@ class CategorieTransformationsNaturelles(Categorie):
if b(fleche_index)@app(fleche_index.source) != app(fleche_index.cible)@a(fleche_index):
break
else:
result |= {TransfoNat(a,b,app)}
result |= {TransfoNat(a,b,app.as_dict())}
return result
CatTransfoNat = CategorieTransformationsNaturelles
......
......@@ -43,4 +43,9 @@ type helpers
Changer les cluster de transformer_graphviz de Application pour des ovales
Corriger le cas où on supprime un morphisme alors qu'une composée était mappé dessus.
(par exemple gof = ioh, on supprime h, ioh n'existe plus, il faut que gof soit delinké)
\ No newline at end of file
(par exemple gof = ioh, on supprime h, ioh n'existe plus, il faut que gof soit delinké)
optimiser la recherche des transformations naturelles.
faire un ficher avec des catégories de test
tester la comma categorie avec une cat de diagrammes plutôt qu'un foncteur diagonal
et un objet plutôt qu'un diagramme objet(faire une categorie sous) voir si ça donne la même chose
\ 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