Commit 9303d85b authored by Guillaume Sabbagh's avatar Guillaume Sabbagh
Browse files

Transformation naturelle transformée

parent e76dc9e2
......@@ -27,7 +27,7 @@ class ObjetCommaCategorie:
return '('+str(self.e)+','+str(self.f)+','+str(self.d)+')'
def __repr__(self):
str(self)
return '('+str(self.e)+','+str(self.f)+','+str(self.d)+')'
class FlecheCommaCategorie(Morphisme):
"""Soit C une catégorie, T et S deux foncteurs de E dans C et D dans C.
......
......@@ -236,9 +236,6 @@ class Diagramme(Foncteur):
image_morph_count = {morph:image_morph.count(morph) for morph in image_morph}
# {morph : nb_occurence} pour avoir la nuance d'orange en fonction du nombre de fois où le morph est indexé
implem = self.implementation()
fleches_implem = implem(implem.objets,implem.objets)
for o in self.cible.objets:
if o in image_objets:
couleur = [max(255-(image_objets_count[o]-1)*75,0),max(165-(image_objets_count[o]-1)*50,0),0]
......@@ -251,8 +248,6 @@ class Diagramme(Foncteur):
if f in image_morph:
couleur = [max(255-(image_morph_count[f]-1)*75,0),max(165-(image_morph_count[f]-1)*50,0),0]
graph.edge(str(f.source),str(f.cible),label=str(f), weight="1000", color="#"+''.join(map(lambda x:(2-len(str(hex(x))[2:]))*"0"+str(hex(x))[2:],couleur)))
elif f in fleches_implem:
graph.edge(str(f.source),str(f.cible),label=str(f), weight="1000", color='orange')
else:
graph.edge(str(f.source),str(f.cible),label=str(f),color="grey85")
graph.render(destination)
......
......@@ -4,6 +4,8 @@ from CommaCategorie import ObjetCommaCategorie
from Foncteur import Foncteur
import itertools
from config import *
if GRAPHVIZ_ENABLED:
from graphviz import Digraph
class Interaction(Morphisme):
"""
......@@ -17,13 +19,15 @@ class Interaction(Morphisme):
"""ensemble_fleches est un ensemble d'objets de la comma-category (D1|D2)"""
self.__fleches = ensemble_fleches
self.__C = D1.cible
self.__D1 = D1
self.__D2 = D2
Morphisme.__init__(self,D1,D2,','.join(map(lambda x:str(x.f),self.__fleches)),
is_identite= (D1==D2) and (self.__fleches == {ObjetCommaCategorie(j,self.__C.identite(D1(j)),j) for j in D1.source.objets}))
if TOUJOURS_VERIFIER_COHERENCE:
self.verifier_coherence()
def verifier_coherence(self):
if self.source.cible != self.cible.cible:
if self.__D1.cible != self.__D2.cible:
raise Exception("Les deux diagrammes d'une interaction n'ont pas la meme categorie cible.")
for f in self.__fleches:
if not issubclass(type(f),ObjetCommaCategorie):
......@@ -36,12 +40,59 @@ class Interaction(Morphisme):
def __matmul__(self, other:'Interaction') -> 'Interaction':
return Interaction(other.source,self.cible,{f1@f2 for f1 in other for f2 in self})
def transformer_graphviz(self, destination:str = None, afficher_identites:bool = False):
"""Permet de visualiser l'interaction avec graphviz
Composante rouge : diagramme 1
Composante verte : diagramme 2
Composante bleue: interaction
On ne peut pas voir si un même objet est indexé par deux objets différents
"""
CategorieInteractions.nb_viz += 1
if destination == None:
destination = "graphviz/interaction"+str(CategorieInteractions.nb_viz)
graph = Digraph('interaction')
graph.attr(concentrate="true" if GRAPHVIZ_CONCENTRATE_GRAPHS else "false")
graph.attr(label="Interaction entre "+str(self.__D1)+" et "+str(self.__D2))
noeuds = {o: [0,0,0] for o in self.__C.objets} # associe à chaque noeud une couleur
for i in self.__D1.source.objets:
noeuds[self.__D1(i)][0] = 200
for j in self.__D2.source.objets:
noeuds[self.__D2(j)][1] = 200
##on affiche les objets
for o in noeuds:
graph.node(str(o),color="#"+''.join(map(lambda x:(2-len(str(hex(x))[2:]))*"0"+str(hex(x))[2:],noeuds[o])))
fleches = {f: [0,0,0] for f in self.__C(self.__C.objets,self.__C.objets)} # associe à chaque flèche une couleur
for f_i in self.__D1.source(self.__D1.source.objets,self.__D1.source.objets):
fleches[self.__D1(f_i)][0] = 200
for f_j in self.__D2.source(self.__D2.source.objets,self.__D2.source.objets):
fleches[self.__D2(f_j)][1] = 200
for f in self.__fleches:
f = f.f # f est de type ObjetCommaCategorie
fleches[f][2] = 200
##on affiche les flèches
for f in fleches:
if not f.is_identite or afficher_identites:
graph.edge(str(f.source),str(f.cible),label=str(f), color="#"+''.join(map(lambda x:(2-len(str(hex(x))[2:]))*"0"+str(hex(x))[2:],fleches[f])))
graph.render(destination)
if CLEAN_GRAPHVIZ_MODEL:
import os
os.remove(destination)
class CategorieInteractions(CategorieDiagrammes):
"""
Categorie dont les objets sont des diagrammes et les morphismes sont des interactions.
"""
nb_viz = 0
def __call__(self, source:Foncteur, cible:Foncteur) -> set:
if source in self.objets:
# source est de type a
......@@ -55,12 +106,10 @@ class CategorieInteractions(CategorieDiagrammes):
for b in cible:
if a.cible != b.cible:
raise Exception("Les deux diagrammes n'ont pas la même catégorie cible")
for i in a.source.objets:
for j in b.source.objets:
fleches = a.cible(a(i),b(j))
for k in range(1,len(fleches)+1):
for combi in itertools.combinations(fleches,k):
result |= {Interaction(a,b,set(map(lambda x:ObjetCommaCategorie(i,x,j),combi)))}
fleches = {ObjetCommaCategorie(i,f,j) for i in a.source.objets for j in b.source.objets for f in a.cible(a(i),b(j))}
for k in range(1,len(fleches)+1):
for combi in itertools.combinations(fleches,k):
result |= {Interaction(a,b,set(combi))}
return result
def test_CategorieInteractions():
......@@ -79,5 +128,8 @@ def test_CategorieInteractions():
c_i |= {DiagrammeObjets(gc,{'A','B'})}
c_i.transformer_graphviz()
for interact in c_i(DiagrammeObjets(gc,{'A','B'}),DiagrammeObjets(gc,{'C'})):
interact.transformer_graphviz(afficher_identites=True)
if __name__ == '__main__':
test_CategorieInteractions()
\ No newline at end of file
import Morphisme
from Morphisme import Morphisme
from Foncteur import Foncteur
from config import *
import itertools
from Interaction import Interaction
from CommaCategorie import ObjetCommaCategorie
if GRAPHVIZ_ENABLED:
from graphviz import Digraph
class TransfoNat(Morphisme.Morphisme):
"""Une transformation naturelle d'un foncteur à un autre."""
class TransformationNaturelle(Morphisme):
"""TransformationNaturelle peut être abrégé TransfoNat.
Une transformation naturelle d'un foncteur à un autre.
Soit F et G deux foncteurs de C dans D.
Une transformation naturelle t de F vers G est une fonction des objets c de C vers les flèches D(F(c),G(c)) telle que
pour deux objets de C, c et c', et pour toute flèche f de c à c', on a G(f) o t(c) = t(c') o F(f)
(cf. Mac Lane "Categories for the working mathematician" p.16)"""
nb_viz = 0
_id = 0
__id = 0
def __init__(self,foncteur_source,foncteur_cible, composantes):
"""foncteurs1 et foncteurs2 deux foncteurs de C vers B.
composantes est un dico {c:morph} où c est un objet de C, morph un morphisme de B de foncteur_source(c) vers foncteur_cible(c)."""
cat_cible = foncteur_source.cat_cible
if foncteur_source == foncteur_cible and all([composantes[e]==cat_cible.identites[foncteur_source(e)] for e in composantes]):
def __init__(self, foncteur_source:Foncteur, foncteur_cible:Foncteur, composantes:dict):
"""
`foncteurs1` et `foncteurs2` 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`)."""
self.__C = foncteur_source.source
self.__D = foncteur_source.cible
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]):
is_identite = True
else:
is_identite = False
Morphisme.Morphisme.__init__(self,foncteur_source, foncteur_cible,\
'('+str(foncteur_source.representant)+')=>('+str(foncteur_cible.representant)+')', is_identite)
self._id = TransfoNat._id
TransfoNat._id += 1
self.composantes = composantes
self.foncteur_source = foncteur_source
self.foncteur_cible = foncteur_cible
self._sketch = self.foncteur_source.cat_source #catégorie C (source des foncteurs)
self._image = self.foncteur_source.cat_cible #catégorie B (cible des foncteurs)
self.verifier_coherence()
Morphisme.__init__(self,foncteur_source, foncteur_cible,\
'('+str(self.__F.representant)+')=>('+str(self.__G.representant)+')', is_identite)
self.__id = TransfoNat.__id #pour la transformation en str
TransfoNat.__id += 1
self._composantes = composantes
if TOUJOURS_VERIFIER_COHERENCE:
self.verifier_coherence()
def __call__(self, obj:any) -> 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]
def __str__(self):
return "TN"+str(self._id)
return "TN"+str(self.__id)
def verifier_coherence(self):
for cle in self.composantes:
if cle not in self.foncteur_source.cat_source.objets:
raise Exception("Incoherence TransformationNaturelle : une composante n'est pas associee a un objet de la categorie de depart du foncteur source : "+str(cle)+" : "+str(self.composantes[cle]))
if cle not in self.foncteur_cible.cat_source.objets:
raise Exception("Incoherence TransformationNaturelle : une composante n'est pas associee a un objet de la categorie de depart du foncteur cible : "+str(cle)+" : "+str(self.composantes[cle]))
if self.foncteur_source.cat_source != self.foncteur_cible.cat_source:
raise Exception("Incoherence TransformationNaturelle : foncteur sources et cible n'ont pas la meme categorie source "+str(self.foncteur_source)+' '+str(self.foncteur_cible))
if self.foncteur_source.cat_cible != self.foncteur_cible.cat_cible:
raise Exception("Incoherence TransformationNaturelle : foncteur sources et cible n'ont pas la meme categorie cible "+str(self.foncteur_source)+' '+str(self.foncteur_cible))
for fleche in self.foncteur_cible.cat_source.morphismes:
c1,c2 = [fleche.source,fleche.cible]
if self._image.Composee(self.foncteur_source(fleche),self.composantes[c2]) != self._image.Composee(self.composantes[c1],self.foncteur_cible(fleche)):
raise Exception("Incoherence TransformationNaturelle : la commutativité des diagrammes est pas respectee"+\
"Sf = "+str(self.foncteur_source(fleche))+"\ntC' = "+str(self.composantes[c2])+"\ntC = "+str(self.composantes[c1])+"\nTf = "+str(self.foncteur_cible(fleche))+\
"tC' o Sf != Tf o tC : "+str(self._image.Composee(self.foncteur_source(fleche),self.composantes[c2])) + " != "+str(self._image.Composee(self.composantes[c1],self.foncteur_cible(fleche))))
def transformer_graphviz(self, destination=None, afficher_identites = False):
"""Permet de visualiser la catégorie avec graphviz"""
TransfoNat.nb_viz += 1
if destination == None:
destination = "graphviz/transformation_naturelle"+str(TransfoNat.nb_viz)
impl1 = self.foncteur_source.categorie_image()
impl2 = self.foncteur_cible.categorie_image()
suffixe1 = "-1"
suffixe2 = "-2"
graph = Digraph('transformation_naturelle')
graph.attr(concentrate="true" if GRAPHVIZ_CONCENTRATE_GRAPHS else "false")
graph.attr(label="Transformation naturelle "+self.representant)
def as_interaction(self) -> Interaction:
return Interaction(self.__F,self.__G,{ObjetCommaCategorie(c,self(c),c) for c in self._composantes})
for o in self._image.objets:
couleur = "black"
if o in impl1.objets and o in impl2.objets:
couleur = "yellow"
elif o in impl1.objets:
couleur = "red"
elif o in impl2.objets:
couleur = "green"
graph.node(str(o), color=couleur)
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))
fleches = self.foncteur_source.cat_cible.enumerer_toutes_composees()
for couple in fleches:
composees = fleches[couple]
for c in composees:
if afficher_identites or not c.is_identite:
if c in self.composantes.values():
graph.edge(str(couple[0]),str(couple[1]),label=str(c.representant), weight="1000", color="blue")
elif c in impl1.morphismes and c in impl2.morphismes:
graph.edge(str(couple[0]),str(couple[1]),label=str(c.representant), weight="1000", color="yellow")
elif c in impl1.morphismes:
graph.edge(str(couple[0]),str(couple[1]),label=str(c.representant), weight="1000", color="red")
elif c in impl2.morphismes:
graph.edge(str(couple[0]),str(couple[1]),label=str(c.representant), weight="1000", color="green")
else:
graph.edge(str(couple[0]),str(couple[1]),label=str(c.representant),color="grey70")
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))
graph.render(destination)
if CLEAN_GRAPHVIZ_MODEL:
import os
os.remove(destination)
for source,cible in itertools.product(self.__C.objets,repeat=2):
for f in self.__C(source,cible):
c1,c2 = [f.source,f.cible]
if self.__G(f)@self(c1) != self(c2)@self.__F(f):
raise Exception("Incoherence TransformationNaturelle : la commutativité des diagrammes est pas respectee"+\
"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
def main():
from Categorie import Categorie
def test_TransfoNat():
from GrapheDeComposition import GC,MGC
from Diagramme import Triangle,DiagrammeIdentite
from Morphisme import Morphisme
from Foncteur import Foncteur
cat = Categorie()
cat.ajouter_objets("ABC")
f,g,h = [Morphisme('A','B','f'),Morphisme('B','C','g'),Morphisme('C','A','h')]
cat.ajouter_morphismes([f,g,h])
triangle = Triangle(cat,"AAA",[cat.Composee(f,g,h),cat.identites['A'],cat.identites['A']])
triangle.faire_commuter()
cat.transformer_graphviz()
diag_id = DiagrammeIdentite(cat)
fonct = Foncteur(cat,cat,{'A':'B','B':'C','C':'A'},{f:g,g:h,h:f})
diag_id.transformer_graphviz()
fonct.transformer_graphviz()
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}
gc.transformer_graphviz()
t_n = TransfoNat(diag_id,fonct,{'A':f,'B':g,'C':h})
print(t_n)
print(t_n.is_identite)
diag_identite = DiagrammeIdentite(gc)
diag_identite.faire_commuter()
t_n.transformer_graphviz()
d1 = Triangle(gc,"ABC",[f,g,g@f])
d2 = Triangle(gc,"DEF",[h,i,i@h])
d1.transformer_graphviz()
d2.transformer_graphviz()
tn = TransfoNat(d1,d2,{1:j,2:k,3:l})
tn.transformer_graphviz()
if __name__ == '__main__':
main()
\ No newline at end of file
test_TransfoNat()
\ No newline at end of file
......@@ -38,4 +38,6 @@ on a la syntaxe g@f <=> gof
envoyer lien
documentation (@, return)
type helpers
\ No newline at end of file
type helpers
laisser la possiblité de fournir des objets au constructeur de Catégorie
\ 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