Categorie.py 37 KB
Newer Older
1
2
3
#!/usr/bin/env python
# -*- coding: utf-8 -*-

4
from Morphisme import Morphisme, Composition
5
from config import *
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
6

Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
7
8
if GRAPHVIZ_ENABLED:
    from graphviz import Digraph
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
9
from collections import defaultdict
10
import itertools
11
import Diagramme
12
import copy
13

Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
14

15
class Categorie:
16
17
18
19
    """Catégorie libre par défaut, on peut spécifier les contraintes
    de composition en ajoutant des diagrammes commutatifs.
    Les compositions de morphismes ne sont pas ajoutées par défaut,
    elles existent en potentialité."""
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
20
21
22
23

    nb_viz = 0  # nombre de graphes graphviz générés

    def __init__(self, nom="CategorieFinie"):
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
24
        self.nom = nom
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
25
26
27
28
29
30
31
32
        self.objets = []  # les objets doivent être hashable
        self.morphismes = []  # liste des morphismes de base (pas les composes)
        self.identites = dict()  # à chaque objet on associe son morphisme identité, ce dernier doit aussi être
        # présent dans morphismes
        self.morph_sortants = defaultdict(list)  # Liste des morphismes sortant non triviaux d'un objet
        self.morph_entrants = defaultdict(list)
        self.diagrammes = []  # liste des diagrammes commutatifs

33
34
35
        class Composee(Composition):
            """La loi de composition est inclus dans la construction de la composee : 
            en construisant la composee de deux morphismes identifiés, le résultat sera le même."""
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
36
37
38
39
40
            loi_de_composition = {}  # dico Composition:Composition

            # /!\ La loi de composition doit être un graphe acyclique simplificateur /!\

            def verifier_coherence(noeuds_visites=tuple()):
41
42
                for noeud in Composee.loi_de_composition:
                    if noeud not in noeuds_visites:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
43
44
                        if not noeud.is_identite and not Composee.loi_de_composition[noeud].is_identite and len(
                                noeud.composee) == 1 and len(Composee.loi_de_composition[noeud]) == 1:
45
                            raise Exception("Loi de composition associe deux fleches elementaires")
46
                        if len(noeud) < len(Composee.loi_de_composition[noeud]):
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
47
48
49
                            raise Exception(
                                "Loi de composition pas simplificatrice (image d'une composition est une composition de taille superieure) : " +
                                str(Composition(*noeud)) + " -> " + str(Composee.loi_de_composition[noeud]))
50
                        noeuds_visites += tuple([noeud])
51
                        if Composee.loi_de_composition[noeud] in noeuds_visites:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
52
53
54
                            raise Exception(
                                "Loi de composition n'est pas acyclique : " + str(Composition(*noeud)) + " -> " + str(
                                    Composee.loi_de_composition[noeud]))
55
                        Composee.verifier_coherence(noeuds_visites)
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
56

57
            def _simplifier_composee(morphismes):
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
58
59
60
61
                morphismes2 = [m for compo in morphismes for m in compo]
                for i in range(len(morphismes2), 1, -1):
                    for j in range(0, len(morphismes2) - i + 1):
                        sous_composee = Composition(*morphismes2[j:j + i])
62
                        if sous_composee in self.Composee.loi_de_composition:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
63
64
65
66
                            morphismes2 = morphismes2[0:j] + [
                                self.Composee.loi_de_composition[sous_composee]] + morphismes2[j + i:]
                            return Composee._simplifier_composee(morphismes2)
                return morphismes2
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
67
68

            def __new__(cls, *morphismes):
69
70
                morphismes = Composee._simplifier_composee(morphismes)
                composition = Composition(*morphismes)
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
71
72
                if type(composition) is Composition:  # si la composition n'est pas simplifiée en morphisme
                    instance = super(Composee, cls).__new__(cls, *morphismes)
73
                    return instance
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
74
                else:  # si la composition est simplifiée en morphisme unitaire
75
                    return composition
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
76
77

            def __init__(self, *morphismes):
78
                morphismes = Composee._simplifier_composee(morphismes)
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
79
                Composition.__init__(self, *morphismes)
80
81

        self.Composee = Composee
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
82

83
    def __copy__(self):
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
84
        newone = Categorie(self.nom)
85
86
87
        newone.objets = copy.copy(self.objets)
        newone.morphismes = copy.copy(self.morphismes)
        newone.identites = copy.copy(self.identites)
88
89
90
91
92
93
        newone.morph_sortants = defaultdict(list)
        newone.morph_entrants = defaultdict(list)
        for cle in self.morph_sortants:
            newone.morph_sortants[cle] = copy.copy(self.morph_sortants[cle])
        for cle in self.morph_entrants:
            newone.morph_entrants[cle] = copy.copy(self.morph_entrants[cle])
94
        newone.diagrammes = copy.copy(self.diagrammes)
95
        newone.Composee.loi_de_composition = copy.copy(self.Composee.loi_de_composition)
96
        return newone
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
97
98
99
100
101
102
103

    def __eq__(self, other):
        return self.objets == other.objets and self.morphismes == other.morphismes and \
               self.identites == other.identites and self.morph_sortants == other.morph_sortants \
               and self.morph_entrants == other.morph_entrants and self.diagrammes == other.diagrammes \
               and self.Composee.loi_de_composition == other.Composee.loi_de_composition

104
105
    def __hash__(self):
        return super().__hash__()
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
106
107
108
        
    def __str__(self):
        return str(self.nom)
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
109

110
    def fleches_elem(self, source, cible, inclure_id = True):
Guillaume Sabbagh's avatar
Limite    
Guillaume Sabbagh committed
111
        """Renvoie la liste de flèches élémentaires de source à cible."""
112
        return [morph for morph in self.morph_sortants[source] if morph.cible == cible and (inclure_id or not morph.is_identite)]
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
113

114
115
116
117
118
    def verifier_coherence(self):
        """Vérifie la cohérence de la structure (tous les axiomes des catégories sont vérifiés)."""
        m = self.morphismes
        if len(self.objets) == 0:
            ## S'il n'y a aucun objet, on vérifie que tout le reste est vide aussi
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
119
120
            assert (len(m) == len(self.morph_sortants) == len(self.morph_entrants) == len(self.diagrammes) == len(
                self.Composee.loi_de_composition) == 0)
121
122
123
        else:
            ## On vérifie l'existence de l'identité pour tous les objets (O(n))
            for o in self.objets:
124
                if o not in self.identites:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
125
126
                    raise Exception("Pas de morphisme identite pour l'objet " + str(o))

127
128
            ## L'associativité est vérifiée par construction de la composee
            ## On vérifie que les morphismes identifiés ont les mêmes sources et cibles
129
130
            for morph in self.Composee.loi_de_composition:
                if morph.source != self.Composee.loi_de_composition[morph].source:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
131
132
133
                    raise Exception(
                        "Morphismes identifies avec des sources differentes : " + ''.join(map(str, m)) + "," + str(
                            self.Composee.loi_de_composition[m]))
134
                if morph.cible != self.Composee.loi_de_composition[morph].cible:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
135
136
137
138
                    raise Exception(
                        "Morphismes identifies avec des cibles differentes : " + ''.join(map(str, m)) + "," + str(
                            self.Composee.loi_de_composition[m]))

139
140
141
142
            ## L'axiome d'identité est vérifié par construction de la composee
            ## On vérifie qu'il n'y a pas trop d'identités
            ident = [morph for morph in m if morph.is_identite]
            if len(ident) > len(self.objets):
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
143
                raise Exception("Trop d'identites : " + ','.join(map(str, ident)))
144

145
146
147
148
149
150
            ## On vérifie que la liste morph_sortants est correcte
            for obj in self.objets:
                for morph in m:
                    if not morph.is_identite:
                        if morph.source == obj:
                            if morph not in self.morph_sortants[obj]:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
151
152
                                # print(' , '.join(map(str,self.morphismes)))
                                print(' , '.join(map(str, m)))
153
                                print(morph)
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
154
                                raise Exception("Erreur morph_sortants : morphisme manquant " + str(morph))
155
156
                        if morph.source != obj:
                            if morph in self.morph_sortants[obj]:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
157
158
                                raise Exception("Erreur morph_sortants : morphisme en trop " + str(morph))

159
160
161
162
163
164
            ## On vérifie que la liste morph_entrants est correcte
            for obj in self.objets:
                for morph in m:
                    if not morph.is_identite:
                        if morph.cible == obj:
                            if morph not in self.morph_entrants[obj]:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
165
                                raise Exception("Erreur morph_entrants : morphisme manquant " + str(morph))
166
167
                        if morph.cible != obj:
                            if morph in self.morph_entrants[obj]:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
168
                                raise Exception("Erreur morph_entrants : morphisme en trop " + str(morph))
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
169
170
            if TOUJOURS_VERIFIER_COHERENCE_COMPOSEE:
                self.Composee.verifier_coherence()
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
171

172
    def ajouter_objet(self, objet):
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
173
        if objet in self.objets:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
174
175
            raise Exception("Objet deja present dans la categorie : tentative d'ajout de " + str(objet) + " echoue")

Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
176
        ##on ajoute l'objet et l'identité associée
177
        self.objets += [objet]
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
178
        self.identites[objet] = Morphisme(objet, objet, "Id" + str(objet), True)
179
        self.morphismes += [self.identites[objet]]
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
180

181
182
        if TOUJOURS_VERIFIER_COHERENCE:
            self.verifier_coherence()
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
183

184
    def ajouter_objets(self, objets):
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
185
        for i in range(len(objets)):
186
            self.ajouter_objet(objets[i])
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
187
188

    def supprimer_objet(self, objet):
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
189
        for morph in copy.copy(self.morph_entrants[objet]):
190
            self.supprimer_morphisme(morph)
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
191
        for morph in copy.copy(self.morph_sortants[objet]):
192
193
194
            self.supprimer_morphisme(morph)
        self.supprimer_morphisme(self.identites[objet])
        self.objets.remove(objet)
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
195
196
197
198
199
200
201
202
203
204
205
        del self.morph_entrants[objet]
        del self.morph_sortants[objet]
        del self.identites[objet]
        for d in self.diagrammes:
            if objet in d.cat_source.objets:
                if len(d.cat_source.morph_entrants[objet]) == len(d.cat_source.morph_sortants[objet]) == 0:
                    d.cat_source.supprimer_objet(objet)
                else:
                    d.transformer_graphviz()
                    d.cat_source.transformer_graphviz(destination="graphviz/debug",complet=False)
                    raise Exception("Il reste des morphismes sortants ou entrants d'un objet supprime "+str(objet))
206
207
        if TOUJOURS_VERIFIER_COHERENCE:
            self.verifier_coherence()
208
209
210
211
            
    def supprimer_objets(self,objets):
        for obj in copy.copy(objets):
            self.supprimer_objet(obj)
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
212
213
214
215

    def supprimer_morphisme(self, morphisme):
        for elem_a_del in [e for e in self.Composee.loi_de_composition if
                           morphisme in self.Composee.loi_de_composition[e]]:
216
217
218
219
220
221
222
223
224
225
226
227
228
229
            del self.Composee.loi_de_composition[elem_a_del]
        if morphisme in self.Composee.loi_de_composition:
            del self.Composee.loi_de_composition[morphisme]
        self.morphismes.remove(morphisme)
        if not morphisme.is_identite:
            self.morph_entrants[morphisme.cible].remove(morphisme)
            self.morph_sortants[morphisme.source].remove(morphisme)
            while len(self.diagrammes) > 0:
                for i in range(len(self.diagrammes)):
                    d = self.diagrammes[i]
                    if morphisme in [e for compo in d.app_morph.values() for e in compo]:
                        self.diagrammes.pop(i)
                        nouveau_sketch = Categorie()
                        nouveau_sketch.ajouter_objets(d.cat_source.objets)
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
230
231
232
233
234
235
                        nouveau_sketch.ajouter_morphismes([morph for morph in d.cat_source.morphismes if
                                                           morphisme not in d.app_morph[
                                                               morph] and not morph.is_identite])
                        nouveau_diagramme = Diagramme.Diagramme(nouveau_sketch, self, d.app_objets,
                                                                {cle: d.app_morph[cle] for cle in
                                                                 nouveau_sketch.morphismes if not cle.is_identite})
236
237
238
239
240
241
                        nouveau_diagramme.faire_commuter()
                        break
                else:
                    break
        if TOUJOURS_VERIFIER_COHERENCE:
            self.verifier_coherence()
242
243
244
245
    
    def supprimer_morphismes(self, morphismes):
        for morph in copy.copy(morphismes):
            self.supprimer_morphisme(morph)
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
246

247
248
249
250
    def ajouter_morphisme(self, morphisme):
        self.morphismes += [morphisme]
        self.morph_entrants[morphisme.cible] += [morphisme]
        self.morph_sortants[morphisme.source] += [morphisme]
251
252
        if morphisme.is_identite:
            self.remplacer_identite(morphisme)
253
        self.verifier_coherence()
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
254

255
256
257
    def ajouter_morphismes(self, morphismes):
        for m in morphismes:
            self.ajouter_morphisme(m)
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
258
259

    def remplacer_identite(self, morphisme):
260
261
        """Remplace l'identité d'un objet par le morphisme."""
        if not morphisme.is_identite:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
262
263
            raise Exception(
                "Tentative de remplacer une identite par un morphisme qui n'est pas une identite " + str(morphisme))
264
265
        objet = morphisme.source
        if objet != morphisme.cible:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
266
267
            raise Exception(
                "Tentative de remplacer une identite par un morphisme qui n'est pas une identite." + str(morphisme))
268
269
        self.morphismes.remove(self.identites[objet])
        self.identites[objet] = morphisme
270
271
        self.morph_sortants[objet].remove(morphisme)
        self.morph_entrants[objet].remove(morphisme)
272

Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
273
    def enumerer_composees_sans_cycle(self, source, cible, noeuds_deja_visites=tuple()):
274
275
        """Renvoie tous les morphismes composés allant de source à cible ne contenant aucun cycle (on ne passe jamais deux fois par le même noeud).
        Si la loi de composition est mal définie pour un cycle de morphismes, cette fonction ne boucle pas à l'infini."""
276
        if source == cible:
277
278
            return [self.identites[source]]
        if source not in noeuds_deja_visites:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
279
            noeuds_deja_visites = noeuds_deja_visites + (source,)
280
281
            composees_resultat = []
            for morph in self.morph_sortants[source]:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
282
283
284
                for composition_candidate in self.enumerer_composees_sans_cycle(morph.cible, cible,
                                                                                noeuds_deja_visites):
                    composee = self.Composee(morph, composition_candidate)
285
286
287
288
                    if composee not in composees_resultat:
                        composees_resultat += [composee]
            return composees_resultat
        return []
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
289
290

    def trouver_cycles_elementaires(self, objet):
291
292
        """Renvoie tous les cycles de morphismes élémentaires (qui ne contiennent aucun cycle) 
        de objet à objet qui n'est pas l'identité."""
293
294
295
        cycles = []
        for morph_pred in self.morph_entrants[objet]:
            pred = morph_pred.source
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
296
            cycles_tronques = self.enumerer_composees_sans_cycle(objet, pred)
297
            for cycle_tronque in cycles_tronques:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
298
                cycle = self.Composee(cycle_tronque, morph_pred)
299
300
                if cycle not in cycles:
                    cycles += [cycle]
301
        return cycles
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
302
303

    def enumerer_cycles(self, objet):
304
        """Enumère toutes les compositions de objet à objet qui ne sont pas l'identité.
305
306
307
308
309
        Si f et g sont des cycles élémentaires, on doit énumérer tous les mots d'alphabet {f,g}.
        Pour ça on s'intéresse aux compositions qui se réduisent en composition avec un nombre de morphismes strictement inférieurs.
        Si f ne se réduit pas, on regarde ff et fg, puis si ceux là non plus fff, ffg, fgf,fgg etc récursivement.
        """
        cycles = self.trouver_cycles_elementaires(objet)
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
310
311

        def trouver_reductions(mot=tuple()):
312
            if DEBUG_LOI_DE_COMPOSITION:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
313
314
                print(' , '.join(map(str, mot)))
                print(list(map(lambda x: cycles.index(x), mot)))
315
            if len(mot) > 0:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
316
                # composition = Composition(*mot)
317
                composee = self.Composee(*mot)
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
318
                if len(composee) < len(mot) or composee.is_identite:  # l'identité est une composition de 0 morphisme
319
320
321
322
                    return [composee]
                resultat = [composee]
            else:
                resultat = []
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
323

324
            for c in cycles:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
325
                reductions = trouver_reductions(mot + (c,))
326
327
                resultat += [e for e in reductions if e not in resultat]
            return resultat
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
328

329
        return [morph for morph in trouver_reductions() if not morph.is_identite]
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
330
331

    def enumerer_composees(self, source, cible):
332
333
334
335
336
        """Renvoie tous les morphismes composés allant de source à cible.
        Si la loi de composition est mal définie pour un cycle de morphismes, cette fonction boucle à l'infini.
        1) On trouve les chemins sans cycle.
        2) Pour tous les noeuds U du chemin on énumère les cycles de U à U.
        3) Pour chaque chemin sans cycle, pour chaque noeud qui a au moins un cycle, on duplique le chemin d'autant de cycles que nécessaires."""
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
337
        chemins_sans_cycles = self.enumerer_composees_sans_cycle(source, cible)
338
        noeuds = list(set([e for c in chemins_sans_cycles for e in c.objets_traverses()]))
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
339
        cycles = list(map(lambda x: self.enumerer_cycles(x), noeuds))
340
        tous_les_chemins = []
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
341

342
343
344
345
346
347
        for c in chemins_sans_cycles:
            noeuds_impliques = []
            cycles_impliques = []
            for noeud in c.objets_traverses():
                if len(cycles[noeuds.index(noeud)]) > 0:
                    noeuds_impliques += [noeud]
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
348
349
                    cycles_impliques += [[self.identites[noeud]] + cycles[
                        noeuds.index(noeud)]]  # on rajoute une identité pour la possibilité de pas rajouter le cycle
350
351
352
353
354
355
            if len(cycles_impliques) > 0:
                for prod in itertools.product(*cycles_impliques):
                    morphismes = []
                    k = 0
                    for i in range(len(noeuds_impliques)):
                        noeud = noeuds_impliques[i]
356
357
                        while k < len(c) and c[k].source != noeud:
                            morphismes += [c[k]]
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
358
                            k += 1
359
                        morphismes += [prod[i]]
360
                    while k < len(c):
361
                        morphismes += [c[k]]
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
362
                        k += 1
363
364
365
366
                    comp = self.Composee(*morphismes)
                    if comp not in tous_les_chemins:
                        tous_les_chemins += [comp]
            else:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
367
                tous_les_chemins += [c]
368
369
        return tous_les_chemins

370
    def enumerer_composees_sortantes(self, source):
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
371
372
        return [morph for cible in self.objets for morph in self.enumerer_composees(source, cible)]

373
374
375
    def enumerer_toutes_composees(self):
        """Renvoie un dictionnaire de la forme (source,cible):[composees]."""
        result = dict()
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
376
377
378
379
        cycles_noeuds = {noeud: [self.identites[noeud]] + self.enumerer_cycles(noeud) for noeud in self.objets}
        for couple in itertools.product(self.objets, repeat=2):
            source, cible = couple
            chemins_sans_cycles = self.enumerer_composees_sans_cycle(source, cible)
380
381
            noeuds = list(set([e for c in chemins_sans_cycles for e in c.objets_traverses()]))
            tous_les_chemins = []
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
382

383
384
385
386
387
388
            for c in chemins_sans_cycles:
                noeuds_impliques = []
                cycles_impliques = []
                for noeud in c.objets_traverses():
                    if len(cycles_noeuds[noeud]) > 0:
                        noeuds_impliques += [noeud]
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
389
                        cycles_impliques += [cycles_noeuds[noeud]]  # on rajoute une identité pour la possibilité de pas rajouter le cycle
390
391
392
393
394
395
                if len(cycles_impliques) > 0:
                    for prod in itertools.product(*cycles_impliques):
                        morphismes = []
                        k = 0
                        for i in range(len(noeuds_impliques)):
                            noeud = noeuds_impliques[i]
396
397
                            while k < len(c) and c[k].source != noeud:
                                morphismes += [c[k]]
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
398
                                k += 1
399
                            morphismes += [prod[i]]
400
                        while k < len(c):
401
                            morphismes += [c[k]]
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
402
                            k += 1
403
404
405
406
                        comp = self.Composee(*morphismes)
                        if comp not in tous_les_chemins:
                            tous_les_chemins += [comp]
                else:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
407
                    tous_les_chemins += [c]
408
            result[couple] = tous_les_chemins
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
409
410
        return result

Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
411
412
413
414
    def est_cyclique(self):
        """Renvoie un booléen qui indique si le graphe sous-jacent est cyclique"""
        noeuds_suspects = []
        noeuds_safe = []
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
415

Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
        def marquer_descendants(noeud):
            """Renvoie true si cycle trouvé, false sinon.
            Ajoute le noeud aux noeuds suspects et étend la liste des noeuds suspects en propageant aux descendants."""
            nonlocal noeuds_suspects
            nonlocal noeuds_safe
            if noeud in noeuds_suspects:
                return True
            if noeud in noeuds_safe:
                return False
            noeuds_suspects += [noeud]
            for morph in self.morph_sortants[noeud]:
                succ = morph.cible
                if marquer_descendants(succ):
                    return True
            noeuds_suspects.remove(noeud)
            noeuds_safe += [noeud]
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
432

Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
433
434
435
436
437
438
439
440
        noeuds_non_visites = [e for e in self.objets if e not in noeuds_safe]
        while len(noeuds_non_visites) > 0:
            noeud = noeuds_non_visites[0]
            if marquer_descendants(noeud):
                return True
            noeuds_safe += noeuds_suspects
            noeuds_suspects = []
            noeuds_non_visites = [e for e in self.objets if e not in noeuds_safe]
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
441

Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
442
        return False
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
443
444

    def nb_composees_borne_sup(self, source, cible, noeuds_deja_visites=tuple()):
445
446
447
448
449
450
451
        """Renvoie une borne sup du nombre de composées entre source et cible.
        Dans le cas acyclique, borne_inf = borne_sup.
        Boucle à l'infini si la loi de composition est mal définie."""
        if source in noeuds_deja_visites:
            return 0
        noeuds_deja_visites += tuple([source])
        if source == cible:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
452
            return 1 + len(self.enumerer_cycles(source))
453
        if len(self.morph_sortants[source]) > 0:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
454
455
            result = sum([self.nb_composees_borne_sup(morph.cible, cible, noeuds_deja_visites) for morph in
                          self.morph_sortants[source]])
456
            for c in self.enumerer_cycles(source):
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
457
458
459
                noeuds_deja_visites2 = noeuds_deja_visites + tuple([m.cible for m in c])
                result += sum([self.nb_composees_borne_sup(morph.cible, cible, noeuds_deja_visites2) for morph in
                               self.morph_sortants[source]])
460
461
            return result
        return 0
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
462
463

    def nb_composees_borne_inf(self, source, cible, noeuds_deja_visites=tuple()):
464
465
466
467
468
469
470
471
        """Renvoie une borne inf du nombre de composées entre source et cible.
        Dans le cas acyclique, borne_inf = borne_sup."""
        if source in noeuds_deja_visites:
            return 0
        noeuds_deja_visites += tuple([source])
        if source == cible:
            return 1
        if len(self.morph_sortants[source]) > 0:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
472
473
            return sum([self.nb_composees_borne_inf(morph.cible, cible, noeuds_deja_visites) for morph in
                        self.morph_sortants[source]])
474
        return 0
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
475

476
    def compter_toutes_composees(self):
477
478
479
        """Renvoie un intervalle qui contient le nombre de composées de toute la catégorie.
        Dans le cas acyclique, borne_inf = borne_sup.
        Boucle à l'infini si la loi de composition est mal définie."""
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
480
481
482
        return (sum([self.nb_composees_borne_inf(a, b) for a, b in itertools.product(self.objets, repeat=2)]),
                sum([self.nb_composees_borne_sup(a, b) for a, b in itertools.product(self.objets, repeat=2)]))

Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
    def table_loi_de_composition(self):
        """Renvoie un dico de dico tel que table[f][g] = g o f, table[f][g] = None si f et g ne sont pas composables.
        La table contient les compositions triviales f o Id = f, f o g = f o g, f o (g o h) = (f o g) o h etc.
        Appel à  enumerer_toutes_composees, préferer accéder au dico Composee.loi_de_composition si possible."""
        table = defaultdict(defaultdict)
        composees = self.enumerer_toutes_composees()
        fleches = list(set([e for liste in composees.values() for e in liste]))
        print(fleches)
        for f,g in itertools.product(fleches, repeat=2):
            if f.cible == g.source:
                table[f][g] = self.Composee(f,g)
        return table

    def pretty_print_loi_de_composition(self,destination=None):
        """Si destination == None, alors on le print sinon on l'écrit dans un fichier"""
        composees = self.enumerer_toutes_composees()
        fleches = list(set([e for liste in composees.values() for e in liste]))
        fleches.sort(key = str)
        fleches.sort(key = lambda x:len(str(x)))
        result = "\t"+'\t'.join(map(lambda x:str(x).replace(' >> ','>'),fleches))+"\n"
        for f in fleches:
            result += str(f).replace(' >> ','>')+"\t"
            for g in fleches:
                if f.cible == g.source:
                    result += str(self.Composee(f, g)).replace(' >> ','>')+"\t"
                else:
                    result += "X\t"
            result += '\n'
        if destination != None:
            with open(destination, 'w') as f:
                f.write(result)
        else:
            print(result)

517
    def pretty_print(self):
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
518
519
520
        result = "Objets de la categorie : \n" + ', '.join(
            map(str, self.objets)) + "\n\nMorphismes de la categorie : \n"
        result += '\n'.join(map(lambda x: x.pretty_print(), self.morphismes)) + "\n\n"
521
        return result
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
522
523

    def transformer_graphviz(self, complet=True, objets=None, destination=None, afficher_identites=False):
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
524
525
        """Permet de visualiser la catégorie avec graphviz"""
        Categorie.nb_viz += 1
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
526
        if destination == None:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
527
            destination = "graphviz/categorie" + str(Categorie.nb_viz)
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
528

Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
529
        graph = Digraph('categorie')
530
        graph.attr(concentrate="true" if GRAPHVIZ_CONCENTRATE_GRAPHS else "false")
531
        graph.attr(label=self.nom)
532
533
        if objets == None:
            objets = self.objets
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
534

535
536
        for o in objets:
            graph.node(str(o))
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
537
        if complet:
538
            fleches = self.enumerer_toutes_composees()
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
539
            for couple in itertools.product(objets, objets):
540
541
                composees = fleches[couple]
                for c in composees:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
542
543
                    if afficher_identites or not c.is_identite:
                        if c in self.morphismes:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
544
                            graph.edge(str(couple[0]), str(couple[1]), label=str(c.representant), weight="1000")
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
545
                        else:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
546
                            graph.edge(str(couple[0]), str(couple[1]), label=str(c.representant), color="grey77")
547
548
        else:
            for morphisme in self.morphismes:
549
                if afficher_identites or not morphisme.is_identite:
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
550
                    graph.edge(str(morphisme.source), str(morphisme.cible), label=str(morphisme.representant))
551
        graph.render(destination)
552
553
        if CLEAN_GRAPHVIZ_MODEL:
            import os
554
            os.remove(destination)
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
555
556


557
def main():
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
    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()
    cat4 = cat.__copy__()

    diag = Diagramme.Carre(cat,"ABCE",[f,i,g,j])
    diag.faire_commuter()
    diag.transformer_graphviz()
    cat.transformer_graphviz()

    m = Morphisme('B', 'C', 'm')
    cat4.ajouter_morphisme(m)
    import CategoriePreordre
    cat4 = CategoriePreordre.CategoriePreordre(cat4)

    a = Morphisme('A','A','a')
    cat.ajouter_morphisme(a)
    cat4.ajouter_morphisme(a)
    diag = Diagramme.Triangle(cat,"AAA",[a,a,a])
    diag2 = Diagramme.Triangle(cat4,"AAA",[a,a,a])
    diag.faire_commuter()
    diag2.faire_commuter()
    cat.nom = "Catégorie"
    cat4.nom = "Catégorie"
    cat.transformer_graphviz()

    b = Morphisme('E','A','b')
    cat.ajouter_morphisme(b)
    diag = Diagramme.Triangle(cat, "AAA", [cat.Composee(f,i,b), cat.Composee(f,i,b), cat.Composee(f,i,b)])
    diag.faire_commuter()
    diag = Diagramme.Triangle(cat, "AAA", [cat.Composee(f,i,b), a, cat.identites['A']])
    diag.faire_commuter()
    cat.transformer_graphviz()

    cat.transformer_graphviz(False)
    import CategoriePreordre
    cat = CategoriePreordre.CategoriePreordre(cat)
    cat.transformer_graphviz()

    cat.diagrammes[-1].transformer_graphviz()

    cat2 = Categorie("1 flèche")
    cat2.ajouter_objets("XY")
    z = Morphisme('X','Y','z')
    cat2.ajouter_morphisme(z)

    import Foncteur
    cat4.transformer_graphviz()
    fonct = Foncteur.Foncteur(cat2,cat4,{'X':'C','Y':'F'},{z:k})
    fonct.transformer_graphviz()

    for obj in cat.objets:
        cones = fonct.enumerer_cones(obj)
        for c in cones:
            c.transformer_graphviz()
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
616
617
    from CategorieCones import CategorieCones
    cat3 = CategorieCones(fonct)
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
    cat3.transformer_graphviz()

    cat = Categorie("Test table loi de composition")
    cat.ajouter_objets("ABCDE")
    f, g, h, i, j, k, l, m = [Morphisme('A', 'B', 'f'), Morphisme('A', 'E', 'g'), Morphisme('A', 'E', 'h'),
                              Morphisme('B', 'E', 'i'),
                              Morphisme('C', 'D', 'j'), Morphisme('B', 'E', 'k'), Morphisme('C', 'A', 'l'),
                              Morphisme('D', 'E', 'm')]
    cat.ajouter_morphismes([f, g, h, i, j, k, l, m])
    cat.transformer_graphviz()
    import CategoriePreordre
    cat2 = CategoriePreordre.CategoriePreordre(cat)
    cat2.transformer_graphviz()
    n = Morphisme('A', 'A', 'n')
    cat2.ajouter_morphisme(n)
    diag = Diagramme.Triangle(cat2, "AAA", [Composition(n,n), n, n])
    diag.faire_commuter()
    cat2.transformer_graphviz()


638
639
640
641
642
643
644
645
646
647
648
649
    # cat = Categorie("Acyclique")
    # cat.ajouter_objets("ABCDEF")
    # f,g,h,i,j,k,l = [Morphisme('A','B','f'),Morphisme('A','C','g'),Morphisme('A','E','h'),Morphisme('B','D','i'),Morphisme('B','E','j'),Morphisme('C','E','k'),Morphisme('C','F','l')]
    # cat.ajouter_morphismes([f,g,h,i,j,k,l])
    # cat.transformer_graphviz()
    # t = Diagramme.Triangle(cat,"ABE",[f,j,h])
    # t.faire_commuter()
    # cat.transformer_graphviz()
    # t = Diagramme.Triangle(cat,"ACE",[g,k,h])
    # t.faire_commuter()
    # cat.transformer_graphviz()
    # print("est_cyclique : "+str(cat.est_cyclique()))
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
650

651
652
653
654
655
656
    # cat = Categorie("Test Isomorphisme")
    # cat.ajouter_objets("ABC")
    # f,g,h,i = [Morphisme('A','B','f'),Morphisme('B','A','g'),Morphisme('A','C','h'),Morphisme('C','A','i')]
    # cat.ajouter_morphismes([f,g,h,i])
    # t = Diagramme.Triangle(cat,"ABA",[f,g,cat.identites['A']])
    # t.faire_commuter()
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
657
658
    # t = Diagramme.Triangle(cat,"ACA",[h,i,cat.identites['A']])
    # t.faire_commuter()
659
660
661
662
663
664
665
    # t = Diagramme.Triangle(cat,"BAB",[g,f,cat.identites['B']])
    # t.faire_commuter()
    # t = Diagramme.Triangle(cat,"CAC",[cat.Composee(i,h,i),h,cat.Composee(i,h)])
    # t.faire_commuter()
    # cat.transformer_graphviz()
    # t.transformer_graphviz()
    # print("est_cyclique : "+str(cat.est_cyclique()))
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
666

667
    cat = Categorie("Test cycles")
668
    cat.ajouter_objets("ABCDE")
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
669
670
671
672
673
674
    a1, a2, a3 = [Morphisme('A', 'B', 'a1'), Morphisme('B', 'C', 'a2'), Morphisme('C', 'A', 'a3')]
    b1, b2, b3 = [Morphisme('A', 'D', 'b1'), Morphisme('D', 'E', 'b2'), Morphisme('E', 'A', 'b3')]
    cat.ajouter_morphismes([a1, a2, a3, b1, b2, b3])
    a = cat.Composee(a1, a2, a3)
    b = cat.Composee(b1, b2, b3)
    t = Diagramme.Triangle(cat, "AAA", [a, cat.identites['A'], cat.identites['A']])
675
    t.faire_commuter()
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
676
    t = Diagramme.Triangle(cat, "AAA", [b, cat.identites['A'], cat.identites['A']])
677
    t.faire_commuter()
678
679
680
681
    # t = Diagramme.Triangle(cat,"AAA",[c,cat.identites['A'],cat.identites['A']])
    # t.faire_commuter()
    # t = Diagramme.Triangle(cat,"AAA",[a,c,cat.identites['A']])
    # t.faire_commuter()
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
682
    t = Diagramme.Triangle(cat, "AAA", [a, b, cat.identites['A']])
683
    t.faire_commuter()
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
684
    t = Diagramme.Triangle(cat, "AAA", [b, a, cat.identites['A']])
685
    t.faire_commuter()
686
687
688
689
690
691
    # t = Diagramme.Triangle(cat,"AAA",[c,a,cat.identites['A']])
    # t.faire_commuter()
    # t = Diagramme.Triangle(cat,"AAA",[b,c,cat.identites['A']])
    # t.faire_commuter()
    # t = Diagramme.Triangle(cat,"AAA",[c,b,cat.identites['A']])
    # t.faire_commuter()
692
693
    cat.transformer_graphviz()
    print(cat.enumerer_cycles('D')[0])
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
694
695

    print("est_cyclique : " + str(cat.est_cyclique()))
696
    print(cat.compter_toutes_composees())
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
697
698
    print(sum(map(len, cat.enumerer_toutes_composees().values())))

699
700
701
702
703
    # cat = Categorie("Test")
    # cat.ajouter_objets("AB")
    # f,g = [Morphisme('A','B','f'),Morphisme('A','B','g')]
    # cat.ajouter_morphismes([f,g])
    # cat.transformer_graphviz()
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
704

705
706
707
708
    # diag = Diagramme.DiagrammeIdentite(cat)
    # diag.faire_commuter()
    # print(cat.morph_sortants)
    # cat.transformer_graphviz()
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
709

710
711
    cat = Categorie("Test comptage composees")
    cat.ajouter_objets("ABCDE")
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
712
713
714
715
716
    f, g, h, i, j, k, l, m = [Morphisme('A', 'B', 'f'), Morphisme('A', 'E', 'g'), Morphisme('A', 'E', 'h'),
                              Morphisme('B', 'E', 'i'),
                              Morphisme('C', 'D', 'j'), Morphisme('B', 'E', 'k'), Morphisme('C', 'A', 'l'),
                              Morphisme('D', 'E', 'm')]
    cat.ajouter_morphismes([f, g, h, i, j, k, l, m])
717
    cat.transformer_graphviz()
718
    print(cat.compter_toutes_composees())
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
719
720
    print(sum(map(len, cat.enumerer_toutes_composees().values())))

721
722
    cat = Categorie("Test comptage composees")
    cat.ajouter_objets("ABCD")
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
723
724
725
726
727
    f, g, h, i, j, k = [Morphisme('A', 'B', 'f'), Morphisme('B', 'A', 'g'), Morphisme('A', 'C', 'h'),
                        Morphisme('C', 'B', 'i'),
                        Morphisme('B', 'D', 'j'), Morphisme('C', 'D', 'k')]
    cat.ajouter_morphismes([f, g, h, i, j, k])
    diag = Diagramme.Triangle(cat, "AAA", [cat.Composee(f, g), cat.Composee(f, g), cat.Composee(f, g)])
728
    diag.faire_commuter()
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
729
    diag = Diagramme.Triangle(cat, "AAA", [cat.Composee(h, i, g), cat.identites['A'], cat.identites['A']])
730
    diag.faire_commuter()
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
731

732
733
    cat.transformer_graphviz()
    print(cat.compter_toutes_composees())
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
734
735
    print(sum(map(len, cat.enumerer_toutes_composees().values())))

736
737
    cat = Categorie("Test comptage composees borne sup atteinte")
    cat.ajouter_objets("ABC")
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
738
739
740
741
    f, g, h, i, j = [Morphisme('A', 'A', 'f'), Morphisme('A', 'B', 'g'), Morphisme('B', 'B', 'h'),
                     Morphisme('B', 'C', 'i'), Morphisme('C', 'C', 'j')]
    cat.ajouter_morphismes([f, g, h, i, j])
    diag = Diagramme.Triangle(cat, "AAA", [cat.Composee(f), cat.Composee(f), cat.Composee(f)])
742
    diag.faire_commuter()
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
743
    diag = Diagramme.Triangle(cat, "BBB", [cat.Composee(h), cat.Composee(h), cat.Composee(h)])
744
    diag.faire_commuter()
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
745
    diag = Diagramme.Triangle(cat, "CCC", [cat.Composee(j), cat.Composee(j), cat.Composee(j)])
746
    diag.faire_commuter()
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
747

748
749
    cat.transformer_graphviz()
    print(cat.compter_toutes_composees())
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
750
751
    print(sum(map(len, cat.enumerer_toutes_composees().values())))

752
753
    cat.transformer_graphviz()
    print(cat.compter_toutes_composees())
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
754
755
    print(sum(map(len, cat.enumerer_toutes_composees().values())))

756
757
    cat = Categorie("Test cycles")
    cat.ajouter_objets("ABC")
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
758
759
760
761
762
763
    a1, a2 = [Morphisme('A', 'B', 'a1'), Morphisme('B', 'A', 'a2')]
    b1, b2 = [Morphisme('A', 'C', 'b1'), Morphisme('C', 'A', 'b2')]
    cat.ajouter_morphismes([a1, a2, b1, b2])
    a = cat.Composee(a1, a2)
    b = cat.Composee(b1, b2)
    t = Diagramme.Triangle(cat, "AAA", [a, a, cat.identites['A']])
764
    t.faire_commuter()
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
765
    t = Diagramme.Triangle(cat, "AAA", [b, b, cat.identites['A']])
766
767
768
769
770
    t.faire_commuter()
    # t = Diagramme.Triangle(cat,"AAA",[c,cat.identites['A'],cat.identites['A']])
    # t.faire_commuter()
    # t = Diagramme.Triangle(cat,"AAA",[a,c,cat.identites['A']])
    # t.faire_commuter()
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
771
    t = Diagramme.Triangle(cat, "AAA", [a, b, cat.identites['A']])
772
    t.faire_commuter()
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
773
    t = Diagramme.Triangle(cat, "AAA", [b, a, cat.identites['A']])
774
775
776
777
778
779
780
781
    t.faire_commuter()
    # t = Diagramme.Triangle(cat,"AAA",[c,a,cat.identites['A']])
    # t.faire_commuter()
    # t = Diagramme.Triangle(cat,"AAA",[b,c,cat.identites['A']])
    # t.faire_commuter()
    # t = Diagramme.Triangle(cat,"AAA",[c,b,cat.identites['A']])
    # t.faire_commuter()
    cat.transformer_graphviz()
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
782
783
784
    print(cat.nb_composees_borne_sup("A", "A"))
    print(len(cat.enumerer_toutes_composees()[("A", "A")]))

785
if __name__ == '__main__':
Guillaume Sabbagh's avatar
Guillaume Sabbagh committed
786
    main()