Interaction.py 7.92 KB
Newer Older
1
from Morphisme import Morphisme
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
2
3
from Diagramme import DiagrammeObjets
from Categorie import Categorie
4
from CommaCategorie import ObjetCommaCategorie
5
from Foncteur import Foncteur
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
6
import itertools
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
7
8
import config
if config.GRAPHVIZ_ENABLED:
9
    from graphviz import Digraph
10
11
12

class Interaction(Morphisme):
    """
13
14
    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).
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
15
16
17
    (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.
    """
18
    
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
19
    def __init__(self, D1:Foncteur, D2:Foncteur, ensemble_fleches:set, nom:str = None):
20
21
22
        """ensemble_fleches est un ensemble d'objets de la comma-category (D1|D2)"""
        self.__fleches = ensemble_fleches
        self.__C = D1.cible
23
24
        self.__D1 = D1
        self.__D2 = D2
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
25
        Morphisme.__init__(self,D1,D2,','.join(map(lambda x:str(x.f),self.__fleches)) if nom == None else nom,
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
26
        is_identite= (D1==D2) and (self.__fleches == {ObjetCommaCategorie(j,self.__C.identite(D1(j)),j) for j in D1.source.objets}))
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
27
        if config.TOUJOURS_VERIFIER_COHERENCE:
28
29
30
            self.verifier_coherence()
        
    def verifier_coherence(self):
31
        if self.__D1.cible != self.__D2.cible:
32
            raise Exception("Incoherence Interaction : les deux diagrammes d'une interaction n'ont pas la meme categorie cible.")
33
34
        for f in self.__fleches:
            if not issubclass(type(f),ObjetCommaCategorie):
35
                raise TypeError("Incoherence Interaction : les fleches de l'interaction ne sont pas des objets de comma categorie.")
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
36
37
            if f.e not in self.__D1.source.objets:    
                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))
38
            if f.d not in self.__D2.source.objets:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
39
                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))
40
    
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
41
42
43
    def __iter__(self):
        for f in self.__fleches:
            yield f
44
45
46
            
    def __len__(self) -> int:
        return len(self.__fleches)
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
47
    
48
    def __matmul__(self, other:'Interaction') -> 'Interaction':
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
49
        return Interaction(other.source,self.cible,{f2@f1 for f1 in other for f2 in self if f1.cible == f2.source})
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
50
51
52
53
54
55
56
57
        
    def __eq__(self, other:'Interaction') -> bool:
        if not issubclass(type(other),Interaction):
            return False
        return self.source == other.source and self.cible == other.cible and {f for f in self} == {f for f in other}
        
    def __hash__(self) -> int:
        return hash((self.source,self.cible,frozenset(self.__fleches)))
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
58
        
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
59
    def transformer_graphviz(self, destination:str = None, afficher_identites:bool = True):
60
61
62
63
64
65
66
67
68
        """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:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
69
            destination = "graphviz/"+type(self).__name__+str(CategorieInteractions.nb_viz)
70
        graph = Digraph('interaction')
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
71
        graph.attr(concentrate="true" if config.GRAPHVIZ_CONCENTRATE_GRAPHS else "false")
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
72
        graph.attr(label=str(self))
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
        
        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)
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
100
        if config.CLEAN_GRAPHVIZ_MODEL:
101
102
103
            import os
            os.remove(destination)
        
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
104
        
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
105
class CategorieInteractions(Categorie):
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
106
    """
107
108
109
110
111
112
    Soit U une catégorie qui constitue notre univers.
    On s'intéresse aux diagrammes qui représentent les organisations de notre univers et
    aux interactions entre nos organisations.
    CategorieInteractions est la catégorie dont les objets sont des diagrammes de cible U et les morphismes sont des interactions.
    Par défaut, on considère pour chaque objet O le diagramme 1_O qui associe à un objet l'objet O.
    On retrouve ainsi l'univers dans la catégorie des interactions.
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
113
114
    """
    
115
    nb_viz = 0
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
116
117
118
119
120
121
122
123
    def __init__(self, univers:Categorie ,diagrammes:set = set(), nom:str = None):
        """
        CategorieInteractions est la catégorie dont les objets sont des diagrammes de cible `univers` et les morphismes sont des interactions.
        Par défaut, on considère pour chaque objet O de U le diagramme 1_O qui associe à un objet l'objet O.
        On retrouve ainsi l'`univers` dans la catégorie des interactions.
        `diagrammes` est un ensemble de diagrammes d'intérêts à ajouter à la catégorie.
        """
        Categorie.__init__(self,diagrammes,"Catégorie des diagrammes et interactions sur "+str(univers) if nom == None else nom)
124
        self.univers = univers
Guillaume Sabbagh's avatar
stash    
Guillaume Sabbagh committed
125
        self |= {DiagrammeObjets(univers,{obj}) for obj in univers.objets }
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
126
        if config.TOUJOURS_VERIFIER_COHERENCE:
127
128
129
130
131
132
133
            self.verifier_coherence()
            
    def verifier_coherence(self):
        Categorie.verifier_coherence(self)
        for diag in self.objets:
            if diag.cible != self.univers:
                raise Exception("Incoherence CategorieInteractions : le diagramme "+str(diag)+" n'a pas pour cible l'univers.")
134
    
135
    def __call__(self, sources:set, cibles:set) -> set:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
136
        result = set()
137
138
        for a in sources:
            for b in cibles:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
139
140
                if a.cible != b.cible:
                    raise Exception("Les deux diagrammes n'ont pas la même catégorie cible")
Guillaume Sabbagh's avatar
stash    
Guillaume Sabbagh committed
141
142
                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)})}
                print(len(fleches)+1)
143
144
145
                for k in range(1,len(fleches)+1): 
                    for combi in itertools.combinations(fleches,k):
                        result |= {Interaction(a,b,set(combi))}
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
        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()
    
164
    for interact in c_i({DiagrammeObjets(gc,{'A','B'})},{DiagrammeObjets(gc,{'C'})}):
165
166
        interact.transformer_graphviz(afficher_identites=True)
    
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
167
168
if __name__ == '__main__':
    test_CategorieInteractions()