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

Catégorie transformations naturelles finie

parent 1022c308
......@@ -57,7 +57,7 @@ class Categorie:
NotImplementedError("Les categories filles doivent implementer cette methode.")
def __eq__(self,other: 'Categorie') -> bool:
return self.nom == other.nom and self.objets == other.objets and type(self) == type(other)
return issubclass(type(other),Categorie) and self.nom == other.nom and self.objets == other.objets and type(self) == type(other)
def __hash__(self) -> int:
return hash((self.nom,self.objets))
......@@ -85,7 +85,7 @@ class Categorie:
Soit C une catégorie.
C -= {a_1,a_2,...} supprime les objets a_i de la catégorie C.
"""
self -= other
self.objets -= other
return self
def verifier_coherence(self):
......
......@@ -4,6 +4,7 @@ from GrapheDeComposition import GrapheDeComposition, MorphismeGrapheDeCompositio
from Categorie import CategorieDiscrete, Categorie
import itertools
from config import *
from copy import deepcopy
if GRAPHVIZ_ENABLED:
from graphviz import Digraph
......@@ -17,7 +18,7 @@ class Diagramme(Foncteur):
def __init__(self, categorie_indexante:Categorie, categorie_indexee:Categorie,
application_objets:dict, application_morphismes:dict, representant:any = None):
Foncteur.__init__(self,categorie_indexante,categorie_indexee, application_objets,
application_morphismes,representant=representant if representant != None else "Diagramme "+str(Morphisme._id))
application_morphismes,representant=representant+' '+str(self._id) if representant != None else "Diagramme "+str(self._id))
def faire_commuter(self):
"""
......@@ -55,16 +56,13 @@ class Diagramme(Foncteur):
else:
MorphismeGrapheDeComposition.identifier_morphismes(composee_depart, composee_arrivee)
def implementation(self) -> GrapheDeComposition:
def implementation(self) -> Categorie:
"""
Renvoie la sous-catégorie atteinte par le diagramme.
Le diagramme doit cibler un `GrapheDeComposition`.
"""
if type(self.cible) != GrapheDeComposition:
raise Exception("Appel d'implementation sur un diagramme dont la cible n'est pas un graphe de composition.")
result = GrapheDeComposition("Implementation de "+str(self))
for obj in self._app_objets:
result |= self(obj)
result = deepcopy(self.cible)
result.nom = "Implementation du diagramme "+str(self)
result -= {obj for obj in self.cible.objets if obj not in self._app_objets.values()}
return result
......@@ -380,6 +378,9 @@ def test_Triangle():
diag = Triangle(cat,['A','B','C'],[f,g,g@f])
diag.transformer_graphviz()
impl = diag.implementation()
impl.transformer_graphviz()
class Carre(Diagramme):
_cat = GrapheDeComposition({1,2,3,4},"Carre")
......
......@@ -64,8 +64,9 @@ class Application(Morphisme):
import os
os.remove(destination)
class EnsFinis(Categorie):
"""Catégorie des ensembles finis, cette catégorie est infinie, on ajoute uniquement les ensembles dont on a besoin."""
class CategorieEnsemblesFinis(Categorie):
"""CategorieEnsFinis peut être abrégé en EnsFinis
Catégorie des ensembles finis, cette catégorie est infinie, on ajoute uniquement les ensembles dont on a besoin."""
def __init__(self, objets:set = None, nom:str = "Catégorie d'ensembles finis"):
Categorie.__init__(self,objets,nom)
......@@ -77,9 +78,14 @@ class EnsFinis(Categorie):
result = frozenset()
for a in source:
for b in cible:
if not issubclass(type(a),frozenset):
raise Exception("On s'attend à avoir des frozenset dans l'ensemble source, pas un "+str(type(a))+'\n'+str(source))
if not issubclass(type(b),frozenset):
raise Exception("On s'attend à avoir des frozenset dans l'ensemble cible, pas un "+str(type(b))+'\n'+str(cible))
result |= {Application(a,b,dict(zip(a,prod))) for prod in itertools.product(b,repeat=len(a))}
return result
EnsFinis = CategorieEnsemblesFinis
def test_EnsFinis():
......
......@@ -145,8 +145,7 @@ class GrapheDeComposition(CategorieLibre):
def identite(self,objet:any) -> MorphismeGrapheDeComposition:
if objet not in self.__identites:
print(objet)
print(self.__identites)
raise Exception("Tentative d'acceder a l'identite d'un objet qui n'est pas dans la categorie, "+str(objet)+" n'est pas dans "+str(self.__identites))
return self.__identites[objet]
def __ior__(self,ensemble_objet_ou_morphisme:set):
......@@ -183,8 +182,14 @@ class GrapheDeComposition(CategorieLibre):
self.__morph_entrants[objet_ou_morphisme.cible] -= {objet_ou_morphisme}
self.__morph_sortants[objet_ou_morphisme.source] -= {objet_ou_morphisme}
else:
self.objets -= {objet}
del self.__identites[objet]
CategorieLibre.__isub__(self,{objet_ou_morphisme})
del self.__identites[objet_ou_morphisme]
for m in self.__morph_entrants[objet_ou_morphisme]:
self.__morph_sortants[m] -= {objet_ou_morphisme}
for m in self.__morph_sortants[objet_ou_morphisme]:
self.__morph_entrants[m] -= {objet_ou_morphisme}
del self.__morph_entrants[objet_ou_morphisme]
del self.__morph_sortants[objet_ou_morphisme]
if TOUJOURS_VERIFIER_COHERENCE:
self.verifier_coherence()
return self
......
......@@ -6,6 +6,7 @@ from Interaction import Interaction
from CommaCategorie import ObjetCommaCategorie
from Categorie import Categorie
from Diagramme import Diagramme
from EnsFinis import Application, EnsFinis
if GRAPHVIZ_ENABLED:
from graphviz import Digraph
......@@ -19,7 +20,7 @@ class TransformationNaturelle(Morphisme):
nb_viz = 0
__id = 0
def __init__(self, foncteur_source:Foncteur, foncteur_cible:Foncteur, composantes:dict):
def __init__(self, foncteur_source:Foncteur, foncteur_cible:Foncteur, composantes:Application):
"""
`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`)."""
......@@ -28,7 +29,7 @@ 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]):
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
......@@ -44,7 +45,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):
......@@ -52,13 +53,18 @@ 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,frozenset(self._composantes.items())))
return hash((self.source,self.cible,self._composantes))
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})
return Interaction(self.__F,self.__G,{ObjetCommaCategorie(c,self(c),c) for c in self._composantes.source})
def verifier_coherence(self):
if self.source.source != self.cible.source:
......@@ -66,12 +72,12 @@ class TransformationNaturelle(Morphisme):
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.keys()) != self.__C.objets:
if set(self._composantes.source) != 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))
for source,cible in itertools.product(self.__C.objets,repeat=2):
for f in self.__C(source,cible):
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"+\
......@@ -101,10 +107,15 @@ def test_TransfoNat():
d1.transformer_graphviz()
d2.transformer_graphviz()
tn = TransfoNat(d1,d2,{1:j,2:k,3:l})
tn = TransfoNat(d1,d2,Application(d1.source.objets,gc(abs(gc),abs(gc)),{1:j,2:k,3:l}))
tn.transformer_graphviz()
tn2 = TransfoNat(d1,d2,{2:k,3:l,1:j})
print(hash(tn)==hash(tn2))
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.transformer_graphviz()
tn3 = tn2@tn
tn3.transformer_graphviz()
class CategorieTransformationsNaturelles(Categorie):
"""CategorieTransformationsNaturelles peut être abrégé en CatTransfoNat.
......@@ -118,12 +129,57 @@ class CategorieTransformationsNaturelles(Categorie):
def __call__(self, source:set, cible:set) -> set:
result = set()
if len(source) > 0:
C = list(source)[0].source
D = list(source)[0].cible
for a in source:
for b in cible:
# on cherche toutes les transformations naturelles du diagramme a:C->D vers le diagramme b:C->D
obj_index = C.objets
fleches_arrivee = frozenset(D(abs(D),abs(D)))
ens = EnsFinis({obj_index,fleches_arrivee})
for app in ens({obj_index},{fleches_arrivee}):
for fleche_index in C(abs(C),abs(C)):
if app(fleche_index.source).cible != b(fleche_index).source:
break
if a(fleche_index).cible != app(fleche_index.cible).source:
break
if b(fleche_index)@app(fleche_index.source) != app(fleche_index.cible)@a(fleche_index):
break
else:
result |= {TransfoNat(a,b,app)}
return result
CatTransfoNat = CategorieTransformationsNaturelles
def test_CatTransfoNat():
from GrapheDeComposition import GC,MGC
from Diagramme import Triangle,DiagrammeIdentite
CatTransfoNat = CategorieTransformationsNaturelles
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,"ABC",[f,g,g@f])
d2 = Triangle(gc,"DEF",[h,i,i@h])
d1.transformer_graphviz()
d2.transformer_graphviz()
ctn = CatTransfoNat({d1,d2})
ctn.transformer_graphviz()
d3 = Triangle(gc,"EEF",[gc.identite('E'),i,i])
ctn |= {d3}
ctn.transformer_graphviz()
for t_n in ctn(abs(ctn),abs(ctn)):
t_n.transformer_graphviz()
if __name__ == '__main__':
test_TransfoNat()
test_CatTransfoNat()
\ No newline at end of file
......@@ -41,3 +41,6 @@ documentation (@, return)
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
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