Commit 0ac440f2 authored by Guillaume Sabbagh's avatar Guillaume Sabbagh
Browse files

Cluster corrigé

parent 801cea03
......@@ -5,6 +5,7 @@ from CommaCategorie import ObjetCommaCategorie,CategorieFSous
from CategoriePreordreZigZag import CatPZigZag
from Interaction import CategorieInteractions
from config import *
from copy import copy
class ProtoClusterActif(Interaction):
"""
......@@ -33,8 +34,10 @@ class ProtoClusterActif(Interaction):
comma_categorie = CategorieFSous(D2,D1(i))
cat_cc = CatPZigZag(comma_categorie)
# on vérifie que tous les E(e) sont isomorphes dans la catégorie des composantes connexes de la catégorie sous D(d)
composante_reference = G_i.pop()
temp = G_i.pop()
composante_reference = ObjetCommaCategorie(0,temp.f,temp.d) #on met un 0 dans e puisque c'est un objet à gauche de la comma catégorie (D1(i)|D2)
for composante in G_i:
composante = ObjetCommaCategorie(0,composante.f,composante.d) #on met un 0 dans e puisque c'est un objet à gauche de la comma catégorie (D1(i)|D2)
if not cat_cc.existe_morphisme(composante,composante_reference):
return False,Exception("Incoherence ProtoClusterActif : la composante"+str(composante)+" n'est pas dans la même composante connexe que "+str(composante_reference))
......@@ -51,9 +54,10 @@ class ProtoClusterActif(Interaction):
return False,Exception("Incoherence ProtoClusterActif : la composee de la fleche "+str(D1(h))+" de D1 avec la composante "+str(composante)+" n'est pas dans le cluster")
return True,None
def __init__(self, D1:Foncteur, D2:Foncteur, composantes:set):
def __init__(self, D1:Foncteur, D2:Foncteur, composantes:set, nom:str = None):
"""composantes est un ensemble d'objets de la comma-catégorie (D1|D2)"""
Interaction.__init__(self,D1, D2, composantes)
Interaction.__init__(self,D1, D2, composantes,nom)
self.__categorie_cluster = None
if TOUJOURS_VERIFIER_COHERENCE:
ProtoClusterActif.verifier_coherence(self)
......@@ -63,6 +67,60 @@ class ProtoClusterActif(Interaction):
if not coherence:
raise exception_levee
def __matmul__(self,other:'ProtoClusterActif') -> 'ProtoClusterActif':
"""La composition de deux clusters G1 et G2 est le cluster engendré par la composition de G1 et G2 vus comme des interactions."""
import config
if self.__categorie_cluster == None:
backup = config.TOUJOURS_VERIFIER_COHERENCE
config.TOUJOURS_VERIFIER_COHERENCE = 0 # on empêche la vérification de la cohérence de CategorieClusters qui ferait une boucle infinie
self.__categorie_cluster = CategorieClusters(self.source.cible,{self.cible},"Catégorie cluster de "+str(self))
config.TOUJOURS_VERIFIER_COHERENCE = backup
composition_interaction = Interaction.__matmul__(self,other) # on calcule la composition des interactions
#on doit trouver le cluster engendré par la composition_interaction
self.__categorie_cluster |= {other.source}
clusters_candidats = self.__categorie_cluster({other.source},{self.cible})
clusters_finaux = set()
for cluster in clusters_candidats:
for obj_comma in composition_interaction:
if obj_comma not in cluster:
break
else:
clusters_finaux |= {cluster}
if len(clusters_finaux) > 1:
raise Exception("Plus d'une composition possible "+str(self)+"o"+str(other)+"\n"+str(clusters_finaux))
if len(clusters_finaux) == 0:
raise Exception("Aucune composition trouvee pour "+str(self)+"o"+str(other)+"\n"+str(clusters_candidats))
return ProtoClusterActif(other.source,self.cible,{composante for composante in clusters_finaux.pop()},str(self)+'o'+str(other))
def __lt__(self, other:'ProtoClusterActif') -> bool:
'''G1 < G2 si G1 est inclus strictement dans G2'''
for composante in self:
if composante not in other:
return False
return self != other
def __gt__(self, other:'ProtoClusterActif') -> bool:
'''G1 > G2 si G2 est inclus strictement dans G1'''
for composante in other:
if composante not in self:
return False
return self != other
def __lte__(self, other:'ProtoClusterActif') -> bool:
'''G1 <= G2 si G1 est inclus dans G2'''
for composante in self:
if composante not in other:
return False
return True
def __gte__(self, other:'ProtoClusterActif') -> bool:
'''G1 >= G2 si G2 est inclus dans G1'''
for composante in other:
if composante not in self:
return False
return True
class CategorieClusters(CategorieInteractions):
"""
CategorieClusters est une catégorie d'organisations où les intéractions sont des clusters.
......@@ -78,33 +136,45 @@ class CategorieClusters(CategorieInteractions):
CategorieInteractions.__init__(self,univers,diagrammes,"Catégorie des diagrammes et clusters sur "+str(univers) if nom == None else nom)
def identite(self,objet:Foncteur) -> ProtoClusterActif:
interactions = sorted(CategorieInteractions.__call__(self,{objet},{objet}),key=len,reverse=True)
identite_candidate = None
for interact in interactions:
if ProtoClusterActif.verifier_struct(interact)[0]:
if identite_candidate != None:
if len(interact) < identite_candidate:
return identite_candidate
else:
raise Exception("Plusieurs identites possibles pour "+str(objet)+" :\n"+str(identite_candidate)+"\n"+str(interact))
clusters_candidats = self({objet},{objet})
clusters_finaux = set()
for cluster in clusters_candidats:
for obj_indexant in objet.source.objets:
if ObjetCommaCategorie(obj_indexant,objet.cible.identite(objet(obj_indexant)),obj_indexant) not in cluster:
break
else:
identite_candidate = interact
if identite_candidate == None:
raise Exception("Pas d'identite trouvee pour "+str(objet))
return identite_candidate
clusters_finaux |= {cluster} # on a tous les clusters qui contiennent toutes les identités dans clusters_finaux
if len(clusters_finaux) > 1:
raise Exception("Plus d'une identite possible pour l'objet "+str(objet)+"\n"+str(clusters_finaux))
if len(clusters_finaux) == 0:
raise Exception("Aucune identite trouvee pour l'objet "+str(objet)+"\n"+str(clusters_candidats))
return clusters_finaux.pop()
def __call__(self, sources:set, cibles:set) -> set:
result = set()
for source in sources:
for cible in cibles:
interactions = sorted(CategorieInteractions.__call__(self,{source},{cible}),key=len,reverse=True)
proto_cluster_maximaux = []
for interact in interactions:
if len(proto_cluster_maximaux) > 0 and len(interact) < len(proto_cluster_maximaux[0]):
# on a trouvé des proto-clusters et on examine maintenant des proto-clusters plus petits (qui ne seront pas maximaux)
interactions = CategorieInteractions.__call__(self,{source},{cible})
proto_cluster_maximaux = set()
while len(interactions) > 0:
interact = interactions.pop()
if not ProtoClusterActif.verifier_struct(interact)[0]:
continue
else:
proto_cluster_candidat = ProtoClusterActif(source,cible,{composante for composante in interact})
for proto_cluster_maximal in proto_cluster_maximaux:
assert(proto_cluster_maximal != proto_cluster_candidat)
if proto_cluster_maximal < proto_cluster_candidat:
proto_cluster_maximaux -= {proto_cluster_maximal}
proto_cluster_maximaux |= {proto_cluster_candidat}
break
if proto_cluster_maximal > proto_cluster_candidat:
break
if ProtoClusterActif.verifier_struct(interact)[0]:
proto_cluster_maximaux += [interact]
else:
# ici on n'a jamais break, ce qui signifie que le proto_cluster_candidat était incomparable avec tous les proto_cluster_maximaux
proto_cluster_maximaux |= {proto_cluster_candidat}
result |= set(proto_cluster_maximaux)
return result
......@@ -118,9 +188,11 @@ def main():
gc = GC()
gc |= {'A','B','C'}
morphismes = [MGC('A','B','f'),MGC('B','C','g'),MGC('A','C','h')]
gc |= morphismes
f,g,h = [MGC('A','B','f'),MGC('B','C','g'),MGC('A','C','h')]
gc |= {f,g,h}
gc.transformer_graphviz()
ProtoClusterActif(Fleche(gc,f),Fleche(gc,f),{ObjetCommaCategorie(1,f,2),ObjetCommaCategorie(1,gc.identite('A'),1),
ObjetCommaCategorie(2,gc.identite('B'),2)})
c_i = CategorieClusters(gc)
c_i.transformer_graphviz(afficher_identites=True)
......@@ -129,12 +201,24 @@ def main():
c_i |= {DiagrammeObjets(gc,{'A','B'})}
c_i.transformer_graphviz(afficher_identites=True)
c_i |= {Fleche(gc,morphismes[0])}
c_i |= {Fleche(gc,f)}
c_i.transformer_graphviz(afficher_identites=True)
c_i.identite(Fleche(gc,morphismes[0])).transformer_graphviz(afficher_identites=True)
# c_i.identite(Fleche(gc,f)).transformer_graphviz(afficher_identites=True)
# c_i.identite(DiagrammeObjets(gc,{'A','B'})).transformer_graphviz(afficher_identites=True)
a = c_i({Fleche(gc,f)},{DiagrammeObjets(gc,{'A','B'})}).pop()
a.transformer_graphviz()
b = c_i({DiagrammeObjets(gc,{'A','B'})},{Fleche(gc,f)}).pop()
b.transformer_graphviz()
for cluster in c_i({DiagrammeObjets(gc,{'A','B'})},{DiagrammeObjets(gc,{'C'})}):
(a@b).transformer_graphviz()
for cluster in c_i({DiagrammeObjets(gc,{'A','B'})},{DiagrammeObjets(gc,{'A','B'})}):
cluster.nom="AB vers AB"
cluster.transformer_graphviz(afficher_identites=True)
(b@a).transformer_graphviz()
for cluster in c_i({Fleche(gc,f)},{Fleche(gc,f)}):
cluster.nom="f vers f"
cluster.transformer_graphviz(afficher_identites=True)
if __name__ == '__main__':
......
......@@ -17,7 +17,7 @@ class ObjetCommaCategorie(Morphisme):
V f V
D1(e) --> D2(d)
ObjetCommaCategorie est aussi un morphisme, on peut composer deux objets de comma-catégorie <e1,f1,d1> et <e2,f2,d2> si d1=e2,
On peut aussi voir ObjetCommaCategorie comme un morphisme, on peut alors composer deux objets de comma-catégorie <e1,f1,d1> et <e2,f2,d2> si d1=e2,
on a alors <e2,f2,d2>o<e1,f1,d1> = <e1,f2of1,d2>
e1 d1=e2 d2
......@@ -26,9 +26,21 @@ class ObjetCommaCategorie(Morphisme):
D1(e1) --> D2(d1) --> D3(d2)
"""
def __init__(self, e:any, f:any, d:any):
self.e = e
self.f = f
self.d = d
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):
return self._e
@property
def f(self):
return self._f
@property
def d(self):
return self._d
def __eq__(self,other:'ObjetCommaCategorie') -> bool:
if not issubclass(type(other),ObjetCommaCategorie):
......@@ -38,14 +50,8 @@ class ObjetCommaCategorie(Morphisme):
def __hash__(self) -> int:
return hash((self.e,self.f,self.d))
def __str__(self):
return '('+str(self.e)+','+str(self.f)+','+str(self.d)+')'
def __repr__(self):
return '('+str(self.e)+','+str(self.f)+','+str(self.d)+')'
def __matmul__(self, other:'ObjetCommaCategorie') -> 'ObjetCommaCategorie':
if self.d != other.e:
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)
......@@ -146,6 +152,8 @@ class CategorieFSous(CommaCategorie):
(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)
......@@ -171,8 +179,9 @@ class CategorieFSur(CommaCategorie):
(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 <e,f,0>.
"""
def __init__(self, C:Categorie, objet:any, nom:str = None):
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)
......
......@@ -4,8 +4,8 @@ from Categorie import Categorie
from CommaCategorie import ObjetCommaCategorie
from Foncteur import Foncteur
import itertools
from config import *
if GRAPHVIZ_ENABLED:
import config
if config.GRAPHVIZ_ENABLED:
from graphviz import Digraph
class Interaction(Morphisme):
......@@ -24,7 +24,7 @@ class Interaction(Morphisme):
self.__D2 = D2
Morphisme.__init__(self,D1,D2,','.join(map(lambda x:str(x.f),self.__fleches)) if nom == None else nom,
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:
if config.TOUJOURS_VERIFIER_COHERENCE:
self.verifier_coherence()
def verifier_coherence(self):
......@@ -34,9 +34,9 @@ class Interaction(Morphisme):
if not issubclass(type(f),ObjetCommaCategorie):
raise TypeError("Incoherence Interaction : les fleches de l'interaction ne sont pas des objets de comma categorie.")
if f.e not in self.__D1.source.objets:
raise Exception("Incoherence Interaction : la fleche "+str(f)+" ne prend pas sa source dans l'image de D1.")
raise Exception("Incoherence Interaction : la fleche "+str(f)+" ne prend pas sa source dans la categorie indexante de D1.\n"+str(self.__D1.source.objets))
if f.d not in self.__D2.source.objets:
raise Exception("Incoherence Interaction : la fleche "+str(f)+" n'a pas pour cible un objet dans l'image de D2.")
raise Exception("Incoherence Interaction : la fleche "+str(f)+" n'a pas pour cible un objet dans la categorie indexante de D2.\n"+str(self.__D2.source.objets))
def __iter__(self):
for f in self.__fleches:
......@@ -46,7 +46,7 @@ class Interaction(Morphisme):
return len(self.__fleches)
def __matmul__(self, other:'Interaction') -> 'Interaction':
return Interaction(other.source,self.cible,{f2@f1 for f1 in other for f2 in self})
return Interaction(other.source,self.cible,{f2@f1 for f1 in other for f2 in self if f1.cible == f2.source})
def __eq__(self, other:'Interaction') -> bool:
if not issubclass(type(other),Interaction):
......@@ -56,7 +56,7 @@ class Interaction(Morphisme):
def __hash__(self) -> int:
return hash((self.source,self.cible,frozenset(self.__fleches)))
def transformer_graphviz(self, destination:str = None, afficher_identites:bool = False):
def transformer_graphviz(self, destination:str = None, afficher_identites:bool = True):
"""Permet de visualiser l'interaction avec graphviz
Composante rouge : diagramme 1
Composante verte : diagramme 2
......@@ -68,7 +68,7 @@ class Interaction(Morphisme):
if destination == None:
destination = "graphviz/"+type(self).__name__+str(CategorieInteractions.nb_viz)
graph = Digraph('interaction')
graph.attr(concentrate="true" if GRAPHVIZ_CONCENTRATE_GRAPHS else "false")
graph.attr(concentrate="true" if config.GRAPHVIZ_CONCENTRATE_GRAPHS else "false")
graph.attr(label=str(self))
noeuds = {o: [0,0,0] for o in self.__C.objets} # associe à chaque noeud une couleur
......@@ -97,7 +97,7 @@ class Interaction(Morphisme):
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:
if config.CLEAN_GRAPHVIZ_MODEL:
import os
os.remove(destination)
......@@ -123,7 +123,7 @@ class CategorieInteractions(Categorie):
Categorie.__init__(self,diagrammes,"Catégorie des diagrammes et interactions sur "+str(univers) if nom == None else nom)
self.univers = univers
self |= {DiagrammeObjets(univers,obj) for obj in univers.objets }
if TOUJOURS_VERIFIER_COHERENCE:
if config.TOUJOURS_VERIFIER_COHERENCE:
self.verifier_coherence()
def verifier_coherence(self):
......
......@@ -55,4 +55,7 @@ Limite et colimite methode de champ perceptif et champt actif
ajouter la convention cat[a,b] pour obtenir les flèches élementaires de a vers b
cat[a,b] appelle cat(a,b) par défaut sauf pour le graphe de composition
Identité de CatégorieCluster pas correcte
Il faudrait le cluster engendré par le proto-cluster contenant IdA,IdB
faire le matmul de cluster
en fait il faudrait pouvoir construire le cluster egendré par un proto-cluster
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