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

Interactions finies

parent d37adedd
......@@ -38,6 +38,9 @@ class Categorie:
def __init__(self,nom: str = "Catégorie"):
self.nom = nom
self.objets = frozenset()
def __hash__(self) -> int:
return hash(self.objets)
def __call__(self, source: any, cible: any) -> set:
"""
......@@ -59,7 +62,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
return self.nom == other.nom and self.objets == other.objets and type(self) == type(other)
def __hash__(self) -> int:
return hash((self.nom,self.objets))
......
from Categorie import Categorie
from TransformationNaturelle import TransfoNat
import Diagramme
import copy
import itertools
from Diagramme import DiagrammeObjets
from config import *
if GRAPHVIZ_ENABLED:
from graphviz import Digraph
class CategorieDiagrammes(Categorie):
"""C^J : catégorie des diagrammes de forme J dans une catégorie C.
|C^J| majoré par |C|^|J|"""
"""
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é /!\
"""
nb_viz = 0
def __init__(self,C,J):
Categorie.__init__(self, "Categorie des diagrammes de forme "+str(J)+" dans "+str(C))
for im_obj in itertools.product(C.objets,repeat=len(J.objets)):
app_obj = dict(zip(J.objets,im_obj))
for im_morph in itertools.product(*[C.enumerer_composees(app_obj[morph.source],app_obj[morph.cible]) for morph in J.morphismes if not morph.is_identite]):
app_morph = dict(zip([e for e in J.morphismes if not e.is_identite],im_morph))
diagramme = Diagramme.Diagramme(J,C,app_obj,app_morph)
self.ajouter_objet(diagramme)
for source,cible in itertools.product(self.objets,repeat=2):
if MONTRER_AVANCEMENT_CATEGORIE_DIAGRAMMES:
print(source,cible)
for im_morph in itertools.product(*[C.enumerer_composees(source(obj),cible(obj)) for obj in J.objets]):
composantes = dict(zip(J.objets,im_morph))
transfo_nat = TransfoNat(source,cible,composantes)
if not transfo_nat.is_identite:
self.ajouter_morphisme(transfo_nat)
#reste à faire commuter les graphes
def transformer_graphviz(self, destination=None):
"""Permet de visualiser la catégorie avec graphviz"""
CategorieDiagrammes.nb_viz += 1
if destination == None:
destination = "graphviz/categorieDiagrammes"+str(CategorieDiagrammes.nb_viz)
graph = Digraph('categorieDiagrammes')
graph.attr(concentrate="true" if GRAPHVIZ_CONCENTRATE_GRAPHS else "false")
graph.attr(label=str(self))
for i in range(len(self.objets)):
diag = self.objets[i]
image = diag.implementation()
with graph.subgraph(name='cluster'+str(i)) as cluster:
cluster.attr(label=str(diag))
for o in diag.cat_cible.objets:
if o in image.objets:
cluster.node(str(o)+str(i), color="orange")
else:
cluster.node(str(o)+str(i),color="grey60")
for f in set(list(diag.app_morph.values())+diag.cat_cible.morphismes):
if not f.is_identite:
if f in diag.app_morph.values():
cluster.edge(str(f.source)+str(i),str(f.cible)+str(i),label=str(f.representant)+str(i), weight="1000", color="orange")
else:
cluster.edge(str(f.source)+str(i),str(f.cible)+str(i),label=str(f.representant)+str(i),color="grey60")
for t_n in self.morphismes:
graph.edge(str(t_n.source),str(t_n.cible),label=str(t_n))
graph.render(destination)
def main():
from Morphisme import Morphisme
cat = Categorie("Catégorie acyclique")
cat.ajouter_objets("ABCDEF")
f,g,h,i,j,k = [Morphisme('A','B','f'),Morphisme('A','C','g'),Morphisme('B','D','h'),Morphisme('B','E','i'),
Morphisme('C','E','j'),Morphisme('C','F','k')]
cat.ajouter_morphismes([f,g,h,i,j,k])
cat.transformer_graphviz()
diag = Diagramme.Carre(cat,"ABCE",[f,i,g,j])
diag.faire_commuter()
diag.transformer_graphviz()
cat.transformer_graphviz()
cat2 = Categorie("2 flèche")
cat2.ajouter_objets("XY")
z,k = [Morphisme('X','Y','z'),Morphisme('X','Z','k')]
cat2.ajouter_morphisme(z)
cat2.ajouter_morphisme(k)
cat2.supprimer_morphisme(k)
cat_diag = CategorieDiagrammes(cat,cat2)
cat_diag.transformer_graphviz()
if __name__ == '__main__':
main()
\ No newline at end of file
def __init__(self, C:Categorie, nom:str = None):
Categorie.__init__(self,"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 Categorie import Categorie
from copy import copy
import itertools
from Morphisme import Morphisme, Composition
from Diagramme import Parallele,DiagrammeIdentite
class ObjetCategorieFSous:
"""Soit C une catégorie, S un foncteur de I dans C et b un objet de C.
CategorieFSous est la catégorie S-en-dessous de b
(cf. Mac Lane "Categories for the working mathematician" P.45)
Ses objets sont les couples de flèches C(f,S(d)) et d
Ses flèches sont des flèches telles que les triangles formés commutent.
"""
def __init__(self,f,d):
self.f = f
self.d = d
def __repr__(self):
return '('+str(self.f)+','+str(self.d)+')'
class CategorieFSous(Categorie):
"""Soit C une catégorie, S un foncteur de I dans C et b un objet de C.
CategorieFSous est la catégorie S-en-dessous de b
(cf. Mac Lane "Categories for the working mathematician" P.45)
Ses objets sont les couples de flèches C(f,S(d)) et d
Ses flèches sont des flèches telles que les triangles formés commutent.
"""
def __init__(self, foncteur, objet):
Categorie.__init__(self, "Categorie "+str(foncteur.representant)+"-en-dessous l'objet "+str(objet))
categorie = foncteur.cat_cible
self.foncteur = foncteur
self.objet = objet
self.app_index_obj = {} #associe à chaque objet de la catégorie indexante les objets qui ont été générés à partir de lui
# {d : [<f \in C(a,Sd),d>]}
self.app_morph_index = {} #associe à chaque morphisme de cette catégorie le morphisme de la catégorie indexante qui l'a généré
# {f':<f \in C(a,Sd),d>-><f'\in C(a,Sd'),d'> : f:d->d'}
self.app_index_morph = {} #inverse de l'application précédente, on ajoute le couple (<C(a,Sd),d>,<C(a,Sd'),d'>) pour rendre l'application bijective
# {(f:d->d',(<f \in C(a,Sd),d>,<f'\in C(a,Sd'),d'>)) : f':<f \in C(a,Sd),d>-><f'\in C(a,Sd'),d'>}
#on ajoute les objets
for d in foncteur.app_objets:
Sd = foncteur(d)
fleches = categorie.enumerer_composees(objet,Sd)
nouveaux_objets = list(map(lambda f:ObjetCategorieFSous(f,d),fleches))
self.ajouter_objets(nouveaux_objets) #on ajoute les couples (f,d) en tant qu'objets
self.app_index_obj[d] = nouveaux_objets
for obj in nouveaux_objets:
self.app_morph_index[self.identites[obj]] = foncteur.cat_source.identites[d]
self.app_index_morph[(foncteur.cat_source.identites[d],(obj,obj))] = self.identites[obj]
#on ajoute les flèches
for fleche in foncteur.cat_source.morphismes:
for source in self.app_index_obj[fleche.source]:
for cible in self.app_index_obj[fleche.cible]:
if not (source == cible and fleche.is_identite) :
Sh = foncteur(fleche)
if categorie.Composee(source.f,Sh) == cible.f:
morph = Morphisme(source,cible,Sh.representant)
self.ajouter_morphisme(morph)
self.app_morph_index[morph] = fleche
if fleche in self.app_index_morph:
raise Exception(str(fleche)+" deja dans app_index_morph "+str(self.app_index_morph))
self.app_index_morph[(fleche,(source,cible))] = morph
#on fait commuter les flèches
for A,B in itertools.product(self.objets,repeat=2):
for g in self.morph_sortants[B]:
C = g.cible
for f in self.fleches_elem(A,B,inclure_id=False):
composee_cat_indexante = foncteur.cat_source.Composee(self.app_morph_index[f],self.app_morph_index[g]) #composee de f et g dans la catégorie indexante
if Composition(self.app_morph_index[f],self.app_morph_index[g]) != composee_cat_indexante:
diag = Parallele(self,[A,C],[self.Composee(f,g),self.app_index_morph[(composee_cat_indexante,(A,C))]])
diag.faire_commuter()
class CategorieSous(CategorieFSous):
"""Soit C une catégorie, b un objet de C.
CategorieSous est la catégorie en-dessous de b
(cf. Mac Lane "Categories for the working mathematician" P.45)
Ses objets sont les couples de flèches C(b,c) et c
Ses flèches sont des flèches telles que les triangles formés commutent.
"""
def __init__(self,categorie,objet):
CategorieFSous.__init__(self,DiagrammeIdentite(categorie),objet)
# def __new__(cls,categorie,objet):
# if objet not in categorie.objets:
# categorie.transformer_graphviz(complet=False)
# raise Exception("Incohérence CategorieSous : objet "+str(objet)+" pas dans la categorie.")
# result = copy(categorie)
# for obj in categorie.objets:
# if len(categorie.enumerer_composees_sans_cycle(objet,obj)) == 0:
# result.supprimer_objet(obj)
# return result
def main():
import CategorieAleatoire
import random
random.seed(14896488564964)
cat = CategorieAleatoire.CategorieAleaPreOrdre()
cat.transformer_graphviz()
cat.csv_loi_de_composition('lois de composition/loi.csv')
obj = random.choice(cat.objets)
print(obj)
cat2 = CategorieSous(cat,obj)
cat2.transformer_graphviz()
obj = random.choice(cat.objets)
print(obj)
cat2 = CategorieSous(cat,obj)
cat2.transformer_graphviz()
if __name__ == '__main__':
main()
\ No newline at end of file
from Categorie import Categorie
from copy import copy
class CategorieSur(Categorie):
"""Soit C une catégorie, et a un objet de C.
CategorieSur n'est pas la catégorie T-au-dessus de a (
(cf. Mac Lane "Categories for the working mathematician" P.46)
C'est plutôt la sous-catégorie C' de C telle que pour tout objet b de la catégorie C' il existe une flèche de b à a"""
def __new__(cls,categorie,objet):
if objet not in categorie.objets:
raise Exception("Incohérence CategorieSur : objet "+str(objet)+" pas dans la categorie.")
result = copy(categorie)
for obj in categorie.objets:
if len(categorie.enumerer_composees_sans_cycle(obj, objet)) == 0:
result.supprimer_objet(obj)
return result
def main():
import CategorieAleatoire
import random
random.seed(14896488564964)
cat = CategorieAleatoire.CategorieAleaIsomorph()
cat.transformer_graphviz()
obj = random.choice(cat.objets)
print(obj)
cat2 = CategorieSur(cat,obj)
cat2.transformer_graphviz()
obj = random.choice(cat.objets)
print(obj)
cat2 = CategorieSur(cat,obj)
cat2.transformer_graphviz()
if __name__ == '__main__':
main()
\ No newline at end of file
from Morphisme import Morphisme
from Categorie import Categorie
from CategorieDiagrammes import CategorieDiagrammes
from CommaCategorie import ObjetCommaCategorie
from Foncteur import Foncteur
import itertools
from config import *
class Interaction(Morphisme):
"""
Soit D1 et D2 deux diagrammes (ou foncteurs) sur C.
Une interaction est une partie de l'ensemble des objets de la comma-category (D1|D2).
(cf. Modélisation catégorielle des organisations Vincent Robin et Guillaume Sabbagh Printemps 2021.)"""
(cf. Modélisation catégorielle des organisations Vincent Robin et Guillaume Sabbagh Printemps 2021.)
On peut itérer sur une intéraction, auquel cas on obtient toutes les flèches de l'intéraction les unes après les autres.
"""
def __init__(self, D1:Foncteur, D2:Foncteur, ensemble_fleches:set):
"""ensemble_fleches est un ensemble d'objets de la comma-category (D1|D2)"""
self.__fleches = ensemble_fleches
self.__C = D1.cible
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()
Morphisme.__init__(self,D1,D2,','.join(map(lambda x:str(x.f),self.__fleches)),
is_identite=(self.__fleches == {self.__C.identite(D1(j)) for j in D1.source.objets}))
def verifier_coherence(self):
if self.source.cible != self.cible.cible:
......@@ -26,5 +29,55 @@ class Interaction(Morphisme):
if not issubclass(type(f),ObjetCommaCategorie):
raise TypeError("Les fleches de l'interaction ne sont pas des objets de comma categorie.")
def __iter__(self):
for f in self.__fleches:
yield f
def __matmul__(self, other:'Interaction') -> 'Interaction':
\ No newline at end of file
return Interaction(other.source,self.cible,{f1@f2 for f1 in other for f2 in self})
class CategorieInteractions(CategorieDiagrammes):
"""
Categorie dont les objets sont des diagrammes et les morphismes sont des interactions.
"""
def __call__(self, source:Foncteur, cible:Foncteur) -> set:
if source in self.objets:
# source est de type a
source = {source}
if cible in self.objets:
# cible est de type b
cible = {cible}
#maintenant tout est de la forme {a_i} vers {b_i}
result = set()
for a in source:
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)))}
return result
def test_CategorieInteractions():
from GrapheDeComposition import GC,MGC
from Diagramme import DiagrammeObjets
gc = GC()
gc |= {'A','B','C'}
morphismes = [MGC('A','B','f'),MGC('B','C','g'),MGC('A','C','h')]
gc |= morphismes
gc.transformer_graphviz()
c_i = CategorieInteractions(gc)
c_i.transformer_graphviz()
c_i |= {DiagrammeObjets(gc,{'A','B'})}
c_i.transformer_graphviz()
if __name__ == '__main__':
test_CategorieInteractions()
\ No newline at end of file
......@@ -3,6 +3,5 @@ TOUJOURS_VERIFIER_COHERENCE_COMPOSEE = 0
DEBUG_LOI_DE_COMPOSITION = False
GRAPHVIZ_ENABLED = True # booléen qui indique s'il faut charger la bibliothèque graphviz
GRAPHVIZ_CONCENTRATE_GRAPHS = False
MONTRER_AVANCEMENT_CATEGORIE_DIAGRAMMES = True
PRINT_AVANCEMENT_CREATION_CAT_ALEA = True
CLEAN_GRAPHVIZ_MODEL = True
\ 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