Commit 0bb248cb authored by Francois Mares's avatar Francois Mares
Browse files
parents abd60667 22f5f907
...@@ -12,9 +12,9 @@ from typing import * ...@@ -12,9 +12,9 @@ from typing import *
def unique_generator(func): def unique_generator(func):
"""Décorateur qui permet de renvoyer les flèches une seule fois par générateur.""" """Décorateur qui permet de renvoyer les flèches une seule fois par générateur."""
def wrapper(self, *args) -> Generator[any,None,None]: def wrapper(self, *args, **kwargs) -> Generator[any,None,None]:
elem_generes = set() elem_generes = set()
for elem in func(self,*args): for elem in func(self,*args,**kwargs):
if elem not in elem_generes: if elem not in elem_generes:
elem_generes |= {elem} elem_generes |= {elem}
yield elem yield elem
...@@ -218,6 +218,10 @@ class Categorie: ...@@ -218,6 +218,10 @@ class Categorie:
"""Renvoie un morphisme de `source` à `cible` s'il existe, renvoie None sinon.""" """Renvoie un morphisme de `source` à `cible` s'il existe, renvoie None sinon."""
return next(self({source},{cible}),None) return next(self({source},{cible}),None)
def existe_morphisme_elementaire(self, source:Any, cible:Any) -> Union[Morphisme,None]:
"""Renvoie un morphisme élémentaire de `source` à `cible` s'il existe, renvoie None sinon."""
return next(self[{source},{cible}],None)
def existe_isomorphisme(self, source:Any, cible:Any) -> Union[tuple,None]: def existe_isomorphisme(self, source:Any, cible:Any) -> Union[tuple,None]:
"""Renvoie un isomorphisme de `source` à `cible` s'il existe sous la forme d'un couple (f,g) avec f:source->cible, et g:cible->source """Renvoie un isomorphisme de `source` à `cible` s'il existe sous la forme d'un couple (f,g) avec f:source->cible, et g:cible->source
renvoie None sinon.""" renvoie None sinon."""
...@@ -263,7 +267,7 @@ class Categorie: ...@@ -263,7 +267,7 @@ class Categorie:
result = result.replace(',','\t,') result = result.replace(',','\t,')
print(result) print(result)
def transformer_graphviz(self, destination:Union[str,None] = None, afficher_identites:bool = True, complet:bool = True, limite_fleches:int = 50): def transformer_graphviz(self, destination:Union[str,None] = None, afficher_identites:bool = True, complet:bool = True, limite_fleches:int = 30):
"""Permet de visualiser la catégorie avec graphviz. """Permet de visualiser la catégorie avec graphviz.
`complet` indique s'il faut afficher toutes les flèches ou seulement les flèches élémentaires. `complet` indique s'il faut afficher toutes les flèches ou seulement les flèches élémentaires.
`limite_fleches` est le nombre maximal de flèches entre deux objets qu'on s'autorise à afficher.""" `limite_fleches` est le nombre maximal de flèches entre deux objets qu'on s'autorise à afficher."""
......
...@@ -78,7 +78,6 @@ class CategorieHomologue(CatFinies): ...@@ -78,7 +78,6 @@ class CategorieHomologue(CatFinies):
bijections_fleches |= {bijections} bijections_fleches |= {bijections}
for bijection_fleche in produit_cartesien_generateurs(*bijections_fleches): for bijection_fleche in produit_cartesien_generateurs(*bijections_fleches):
bij_fleche = dict([x for bij in bijection_fleche for x in bij.as_dict().items()]) bij_fleche = dict([x for bij in bijection_fleche for x in bij.as_dict().items()])
print("yield")
yield Foncteur(source,cible,bij_obj,bij_fleche) yield Foncteur(source,cible,bij_obj,bij_fleche)
......
from Categorie import Categorie, unique_generator from Categorie import Categorie, unique_generator
from Morphisme import Morphisme from Morphisme import Morphisme
from ProduitGenerateurs import produit_cartesien_generateurs
from copy import copy from copy import copy
import itertools import itertools
import functools import functools
...@@ -57,7 +58,7 @@ class CategorieLibre(Categorie): ...@@ -57,7 +58,7 @@ class CategorieLibre(Categorie):
return composees_resultat return composees_resultat
return frozenset() return frozenset()
for chemin in enumerer_chemin_elem_sans_cycle(morphisme.source,morphisme.cible): for chemin in enumerer_chemin_elem_sans_cycle(morphisme.source,morphisme.cible):
resultat = functools.reduce(lambda x,y:x@y,chemin) resultat = functools.reduce(lambda x,y:y@x,chemin)
if resultat == morphisme: if resultat == morphisme:
for morph_elem in chemin: for morph_elem in chemin:
yield morph_elem yield morph_elem
...@@ -77,89 +78,157 @@ class CategorieLibre(Categorie): ...@@ -77,89 +78,157 @@ class CategorieLibre(Categorie):
if morph not in self[self.objets,{morph.cible}]: if morph not in self[self.objets,{morph.cible}]:
raise Exception("Incoherence CategorieLibre : le morphisme "+str(morph)+" n'entre pas dans "+str(morph.cible)) raise Exception("Incoherence CategorieLibre : le morphisme "+str(morph)+" n'entre pas dans "+str(morph.cible))
def enumerer_composees_sans_cycle(self, source:Any, cible:Any, noeuds_deja_visites:tuple=tuple()) -> frozenset(): def enumerer_composees_sans_cycle(self, source:Any, cible:Any) -> Generator[Morphisme,None,None]:
""" """
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). Génère tous les morphismes composés allant de `source` à `cible` ne contenant aucun cycle (on ne passe jamais deux fois par le même noeud).
""" """
if source == cible: for chemin in self.enumerer_chemins_sans_cycle(source,cible):
return frozenset({self.identite(source)}) if len(chemin) == 1:
if source not in noeuds_deja_visites: for e in self[{chemin[0]},{chemin[0]}]:
noeuds_deja_visites = noeuds_deja_visites + (source,) yield e
composees_resultat = frozenset() else:
for morph in self[{source},self.objets]: generateurs = [self[{chemin[i]},{chemin[i+1]}] for i in range(len(chemin)-1)]
for composition_candidate in self.enumerer_composees_sans_cycle(morph.cible, cible, noeuds_deja_visites): for prod in produit_cartesien_generateurs(*generateurs):
composees_resultat |= {composition_candidate@morph} yield functools.reduce(lambda x,y : y@x, prod)
return composees_resultat
return frozenset()
def enumerer_chemins_sans_cycle(self, source:Any, cible:Any) -> Generator[tuple,None,None]:
def enumerer_chemins_sans_cycle(self, source:Any, cible:Any, noeuds_deja_visites:tuple=tuple()) -> frozenset:
""" """
Renvoie tous les chemins (liste de noeuds) allant de `source` à `cible` ne contenant aucun cycle (on ne passe jamais deux fois par le même noeud). Génère tous les chemins (liste de noeuds) allant de `source` à `cible` ne contenant aucun cycle (on ne passe jamais deux fois par le même noeud).
""" """
if source == cible: # on fait un parcours en largeur
return frozenset({(cible,)}) file_chemins = [(source,)]
if source not in noeuds_deja_visites: while len(file_chemins) > 0:
noeuds_deja_visites = noeuds_deja_visites + (source,) chemin = file_chemins.pop(0)
chemins_resultat = frozenset() if chemin[-1] == cible:
for morph in self[{source},self.objets]: yield chemin
for chemin_candidat in self.enumerer_chemins_sans_cycle(morph.cible, cible, noeuds_deja_visites): else:
chemins_resultat |= {(source,)+chemin_candidat} for obj in self.objets:
return chemins_resultat if obj not in chemin:
return frozenset() if self.existe_morphisme_elementaire(chemin[-1],obj):
file_chemins += [chemin+(obj,)]
def trouver_cycles_minimaux(self, objet:Any, inclure_id:bool=True) -> frozenset(): @unique_generator
"""Renvoie tous les cycles minimaux de morphismes élémentaires (qui ne contiennent aucun cycle) def trouver_cycles_minimaux(self, objet:Any) -> Generator[Morphisme,None,None]:
de `objet` à `objet` (à l'exception de l'identité si `inclure_id` = False).""" """Génère tous les cycles minimaux de morphismes élémentaires (qui ne contiennent aucun cycle)
cycles = frozenset() de `objet` à `objet` différent de l'identité."""
for morph_pred in self[self.objets,{objet}]: for morph_pred in self[self.objets,{objet}]:
pred = morph_pred.source if morph_pred.source == objet:
cycles_tronques = self.enumerer_composees_sans_cycle(objet, pred) yield morph_pred
for cycle_tronque in cycles_tronques: else:
cycle = morph_pred@cycle_tronque pred = morph_pred.source
if cycle not in cycles: for cycle_tronque in self.enumerer_composees_sans_cycle(objet, pred):
cycles |= {cycle} cycle = morph_pred@cycle_tronque
if inclure_id: if not cycle.is_identite:
return cycles|{self.identite(objet)} yield cycle
return cycles-{self.identite(objet)}
def enumerer_cycles(self, objet:Any, limite_profondeur:int = 27) -> frozenset: def enumerer_cycles(self, objet:Any, limite_profondeur:int = 10) -> Generator[Morphisme,None,None]:
"""Enumère toutes les compositions de `objet` à `objet`. """Enumère toutes les compositions de `objet` à `objet`.
Si f et g sont des cycles minimaux, on doit énumérer tous les mots d'alphabet {f,g}. Si f et g sont des cycles minimaux, 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 déjà générées. Pour ça on s'intéresse aux compositions qui se réduisent en composition déjà générées.
Si f ne se réduit pas, on regarde ff et fg, puis si ceux là non plus fff, ffg, fgf,fgg etc. Si f ne se réduit pas, on regarde ff et fg, puis si ceux là non plus fff, ffg, fgf,fgg etc.
On s'arrête à la limite de profondeur spécifiée. On s'arrête à la limite de profondeur spécifiée.
""" """
cycles = self.trouver_cycles_minimaux(objet,inclure_id=False) cycles = set(self.trouver_cycles_minimaux(objet))
cycles_a_reduire = copy(cycles) cycles_a_reduire = copy(cycles)
cycles_minimaux = copy(cycles) cycles_minimaux = copy(cycles)
cycles |= {self.identite(objet)} cycles |= {self.identite(objet)}
for cycle in cycles:
yield cycle
for profondeur in range(limite_profondeur): for profondeur in range(limite_profondeur):
for cycle_a_reduire in copy(cycles_a_reduire): for cycle_a_reduire in copy(cycles_a_reduire):
for cycle_minimal in cycles_minimaux: for cycle_minimal in cycles_minimaux:
if cycle_minimal@cycle_a_reduire not in cycles: if cycle_minimal@cycle_a_reduire not in cycles:
cycles_a_reduire |= {cycle_minimal@cycle_a_reduire} new_cycle = cycle_minimal@cycle_a_reduire
cycles |= {cycle_minimal@cycle_a_reduire} cycles_a_reduire |= {new_cycle}
cycles |= {new_cycle}
yield new_cycle
cycles_a_reduire -= {cycle_a_reduire} cycles_a_reduire -= {cycle_a_reduire}
if len(cycles_a_reduire) > 0: if len(cycles_a_reduire) > 0:
print("Warning CategorieLibre : limite de profondeur atteinte dans l'enumeration des cycles") print("Warning CategorieLibre : limite de profondeur atteinte dans l'enumeration des cycles")
if DEBUG_LOI_DE_COMPOSITION: if DEBUG_LOI_DE_COMPOSITION:
print(cycles_a_reduire) print(cycles_a_reduire)
return cycles
def enumerer_composees(self, source:Any, cible:Any) -> Generator[Morphisme,None,None]: def enumerer_composees(self, source:Any, cible:Any) -> Generator[Morphisme,None,None]:
"""Renvoie tous les morphismes composés allant de `source` à `cible`. """Génère tous les morphismes composés allant de `source` à `cible`.
1) On trouve les chemins sans cycle. 1) On trouve les chemins sans cycle.
2) Pour tous les noeuds U du chemin on énumère les cycles de U à U. 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.""" 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."""
chemins_sans_cycles = self.enumerer_chemins_sans_cycle(source, cible) chemins_sans_cycles = self.enumerer_chemins_sans_cycle(source, cible)
noeuds = list(frozenset([e for chemin in chemins_sans_cycles for e in chemin])) dict_noeuds_cycles = dict() # {noeud : set(cycles)}
cycles = {x: self.enumerer_cycles(x) for x in noeuds}
for chemin in chemins_sans_cycles: for chemin in chemins_sans_cycles:
cycles_concernes = [cycles[noeud] for noeud in chemin] cycles_concernes = []
fleches_concernees = [set(self[{chemin[i]},{chemin[i+1]}]) for i in range(len(chemin)-1)] for noeud in chemin:
for combinaison_fleches in itertools.product(*fleches_concernees): if noeud not in dict_noeuds_cycles:
for combinaison_cycle in itertools.product(*cycles_concernes): dict_noeuds_cycles[noeud] = set(self.enumerer_cycles(noeud))
composee = combinaison_cycle[0] cycles_concernes += [dict_noeuds_cycles[noeud]]
for i in range(len(combinaison_fleches)): if len(chemin) >= 2:
composee = combinaison_cycle[i+1]@combinaison_fleches[i]@composee fleches_concernees = [self[{chemin[i]},{chemin[i+1]}] for i in range(len(chemin)-1)]
yield composee for combinaison_fleches in produit_cartesien_generateurs(*fleches_concernees):
for combinaison_cycle in itertools.product(*cycles_concernes):
composee = combinaison_cycle[0]
for i in range(len(combinaison_fleches)):
composee = combinaison_cycle[i+1]@combinaison_fleches[i]@composee
yield composee
else:
# taille du chemin == 1
for e in cycles_concernes[0]:
yield e
def test_enumerer_chemins_sans_cycle():
from GrapheDeComposition import GC,MGC
GC = GC({'A','B','C','D','E','F'})
f,g,h,i,j,k,l,m,n = [MGC('A','B','f'),MGC('B','C','g'),MGC('A','A','h'),MGC('C','D','i'),
MGC('C','E','j'),MGC('E','F','k'),MGC('D','F','l'),MGC('D','D','m'),MGC('C','D','n')]
MGC.identifier_morphismes(h@h@h,h)
MGC.identifier_morphismes(m@m,m)
GC |= {f,g,h,i,j,k,l,m,n}
GC.transformer_graphviz()
for composee in GC.enumerer_chemins_sans_cycle('A','F'):
print(composee)
print()
def test_enumerer_composees_sans_cycle():
from GrapheDeComposition import GC,MGC
GC = GC({'A','B','C','D','E','F'})
f,g,h,i,j,k,l,m,n = [MGC('A','B','f'),MGC('B','C','g'),MGC('A','A','h'),MGC('C','D','i'),
MGC('C','E','j'),MGC('E','F','k'),MGC('D','F','l'),MGC('D','D','m'),MGC('C','D','n')]
MGC.identifier_morphismes(h@h@h,h)
MGC.identifier_morphismes(m@m,m)
GC |= {f,g,h,i,j,k,l,m,n}
GC.transformer_graphviz()
for composee in GC.enumerer_composees_sans_cycle('A','F'):
print(composee)
print()
def test_trouver_cycles_minimaux():
from GrapheDeComposition import GC,MGC
GC = GC({'A','B','C','D','E','F'})
f,g,h,i,j,k,l,m,n,o = [MGC('A','B','f'),MGC('B','C','g'),MGC('A','A','h'),MGC('C','D','i'),
MGC('C','E','j'),MGC('E','F','k'),MGC('D','F','l'),MGC('D','D','m'),MGC('C','D','n'),MGC('D','A','o')]
MGC.identifier_morphismes(h@h@h,h)
MGC.identifier_morphismes(m@m,m)
MGC.identifier_morphismes(o@i@g@f@o@i@g@f,o@i@g@f)
MGC.identifier_morphismes(o@i@g@f@o@n@g@f,o@i@g@f)
MGC.identifier_morphismes(o@n@g@f@o@i@g@f,o@n@g@f)
MGC.identifier_morphismes(o@n@g@f@o@n@g@f,o@n@g@f)
GC |= {f,g,h,i,j,k,l,m,n,o}
GC.transformer_graphviz(complet=False)
for composee in GC.trouver_cycles_minimaux('D'):
print(composee)
print()
def test_enumerer_composees():
from EnsFinis import EnsFinis
cat = EnsFinis({frozenset("ABCD"),frozenset("ABC")})
print(len(list(cat({frozenset("ABCD")},{frozenset("ABC")}))))
cat.transformer_graphviz()
if __name__ == '__main__':
test_enumerer_chemins_sans_cycle()
test_enumerer_composees_sans_cycle()
test_trouver_cycles_minimaux()
test_enumerer_composees()
\ No newline at end of file
...@@ -2,6 +2,7 @@ from CommaCategorie import CommaCategorie, ObjetCommaCategorie ...@@ -2,6 +2,7 @@ from CommaCategorie import CommaCategorie, ObjetCommaCategorie
from TransformationNaturelle import CatTransfoNat,TransfoNat from TransformationNaturelle import CatTransfoNat,TransfoNat
from Foncteur import Foncteur from Foncteur import Foncteur
from Diagramme import DiagrammeConstant,DiagrammeObjets from Diagramme import DiagrammeConstant,DiagrammeObjets
from Cluster import ClusterActif,ProtoClusterActif
from typing import * from typing import *
class Cocone(TransfoNat): class Cocone(TransfoNat):
...@@ -17,6 +18,9 @@ class Cocone(TransfoNat): ...@@ -17,6 +18,9 @@ class Cocone(TransfoNat):
def as_ObjetCommaCategorie(self) -> ObjetCommaCategorie: def as_ObjetCommaCategorie(self) -> ObjetCommaCategorie:
return ObjetCommaCategorie(0,self,self.nadir) return ObjetCommaCategorie(0,self,self.nadir)
def as_Cluster(self) -> ClusterActif:
return ClusterActif(ProtoClusterActif(self.source,self.cible,self._composantes,"Cluster issu du cocône "+str(self)))
class ChampActif(CommaCategorie): class ChampActif(CommaCategorie):
"""Le champ actif d'un diagramme(ou foncteur) D:P->Q est défini comme étant la comma-catégorie (D|Δ) """Le champ actif d'un diagramme(ou foncteur) D:P->Q est défini comme étant la comma-catégorie (D|Δ)
......
from Categorie import Categorie
from CommaCategorie import CommaCategorie, ObjetCommaCategorie from CommaCategorie import CommaCategorie, ObjetCommaCategorie
from TransformationNaturelle import CatTransfoNat,TransfoNat from TransformationNaturelle import CatTransfoNat,TransfoNat
from Foncteur import Foncteur from Foncteur import Foncteur
from Diagramme import DiagrammeConstant,DiagrammeObjets from Diagramme import DiagrammeConstant,DiagrammeObjets
# from Cluster import ClusterActif,ProtoClusterActif
from typing import *
class Cone(TransfoNat): class Cone(TransfoNat):
"""Un cône sur D d'apex A est une transformation naturelle du foncteur constant Δ_A vers D.""" """Un cône sur D d'apex A est une transformation naturelle du foncteur constant Δ_A vers D."""
...@@ -36,11 +37,11 @@ class ChampPerceptif(CommaCategorie): ...@@ -36,11 +37,11 @@ class ChampPerceptif(CommaCategorie):
self.foncteur_diagonal = Foncteur(Q,self.categorie_diagrammes,{o:DiagrammeConstant(P,Q,o) for o in Q.objets}, self.foncteur_diagonal = Foncteur(Q,self.categorie_diagrammes,{o:DiagrammeConstant(P,Q,o) for o in Q.objets},
{f: TransfoNat(DiagrammeConstant(P,Q,f.source),DiagrammeConstant(P,Q,f.cible),{p:f for p in P.objets}) for f in Q(abs(Q),abs(Q))}) {f: TransfoNat(DiagrammeConstant(P,Q,f.source),DiagrammeConstant(P,Q,f.cible),{p:f for p in P.objets}) for f in Q(abs(Q),abs(Q))})
## on associe à chaque objet son diagramme constant bite et à chaque flèche F:a->b la transformation naturelle qui va de Δa à Δb ## on associe à chaque objet son diagramme constant et à chaque flèche F:a->b la transformation naturelle qui va de Δa à Δb
self.foncteur_vers_D = DiagrammeObjets(self.categorie_diagrammes,{diagramme}) self.foncteur_vers_D = DiagrammeObjets(self.categorie_diagrammes,{diagramme})
CommaCategorie.__init__(self,self.foncteur_diagonal,self.foncteur_vers_D, "Champ perceptif de "+str(diagramme)+" ("+str(Categorie._id)+")" if nom == None else nom) CommaCategorie.__init__(self,self.foncteur_diagonal,self.foncteur_vers_D, "Champ perceptif de "+str(diagramme) if nom == None else nom)
def objets_cones(self,apices:set) -> set: def objets_cones(self,apices:set) -> set:
"""`apices` est un ensemble d'objets de Q """`apices` est un ensemble d'objets de Q
...@@ -59,12 +60,16 @@ class ChampPerceptif(CommaCategorie): ...@@ -59,12 +60,16 @@ class ChampPerceptif(CommaCategorie):
cone_courant = cones[0] cone_courant = cones[0]
cones_visites = {cone_courant} cones_visites = {cone_courant}
cones_restants = self.objets-cones_visites cones_restants = self.objets-cones_visites
fleche_accessible = next(self({cone_courant},cones_restants),None) fleche_accessible = next(self[{cone_courant},cones_restants],None)
if fleche_accessible == None:
fleche_accessible = next(self({cone_courant},cones_restants),None)
while fleche_accessible != None: while fleche_accessible != None:
cone_courant = fleche_accessible.cible cone_courant = fleche_accessible.cible
cones_visites |= {cone_courant} cones_visites |= {cone_courant}
cones_restants = self.objets-cones_visites cones_restants = self.objets-cones_visites
fleche_accessible = next(self({cone_courant},cones_restants),None) fleche_accessible = next(self[{cone_courant},cones_restants],None)
if fleche_accessible == None:
fleche_accessible = next(self({cone_courant},cones_restants),None)
# ici cone_courant est un objet final de la catégorie # ici cone_courant est un objet final de la catégorie
return {cone for cone in self.objets if self.existe_isomorphisme(cone_courant,cone) != None} return {cone for cone in self.objets if self.existe_isomorphisme(cone_courant,cone) != None}
......
...@@ -130,7 +130,6 @@ class CommaCategorie(CategorieLibre): ...@@ -130,7 +130,6 @@ class CommaCategorie(CategorieLibre):
'''L'identité pour un objet (e,f,d) est la paire d'identité de T(e) et S(d).''' '''L'identité pour un objet (e,f,d) est la paire d'identité de T(e) et S(d).'''
return FlecheCommaCategorie(objet,objet,self._T.source.identite(objet.e),self._S.source.identite(objet.d)) return FlecheCommaCategorie(objet,objet,self._T.source.identite(objet.e),self._S.source.identite(objet.d))
@mise_en_cache_getitem
def __getitem__(self, couple_sources_cibles:tuple) -> Generator[FlecheCommaCategorie, None, None]: def __getitem__(self, couple_sources_cibles:tuple) -> Generator[FlecheCommaCategorie, None, None]:
sources,cibles = couple_sources_cibles sources,cibles = couple_sources_cibles
for obj_comma_source in sources: for obj_comma_source in sources:
...@@ -140,7 +139,6 @@ class CommaCategorie(CategorieLibre): ...@@ -140,7 +139,6 @@ class CommaCategorie(CategorieLibre):
if obj_comma_cible.f@self._T(k) == self._S(h)@obj_comma_source.f: if obj_comma_cible.f@self._T(k) == self._S(h)@obj_comma_source.f:
yield FlecheCommaCategorie(obj_comma_source,obj_comma_cible,k,h) yield FlecheCommaCategorie(obj_comma_source,obj_comma_cible,k,h)
@mise_en_cache_call
def __call__(self, sources:set, cibles:set) -> Generator[FlecheCommaCategorie, None, None]: def __call__(self, sources:set, cibles:set) -> Generator[FlecheCommaCategorie, None, None]:
for obj_comma_source in sources: for obj_comma_source in sources:
for obj_comma_cible in cibles: for obj_comma_cible in cibles:
......
from Categorie import Categorie
from Foncteur import Foncteur
from Morphisme import Morphisme
from GrapheDeComposition import GC,MGC from GrapheDeComposition import GC,MGC
from Diagramme import Diagramme, DiagrammeIdentite from Diagramme import Diagramme, DiagrammeIdentite, Fleche
from ChampActif import ChampActif from ChampActif import ChampActif,Cocone
from ChampPerceptif import ChampPerceptif,Cone
from copy import copy from copy import copy
from TransformationNaturelle import TransfoNat
from typing import *
cat = GC(set("ABC")) cat = GC(set("ABC"))
f,g = [MGC('A','B','f'),MGC('A','C','g')] f,g = [MGC('A','B','f'),MGC('C','B','g')]
cat |= {f,g} cat |= {f,g}
diag = DiagrammeIdentite(cat)
c_a = ChampActif(diag)
diag.transformer_graphviz()
c_a.transformer_graphviz()
cat2 = copy(cat) def modification(gc: GC, option_ajout:Tuple[Sequence[Any],Sequence[Morphisme]] = (set(),set()), option_elimination:Sequence[Diagramme] = set(), option_complex_agissante:Sequence[Diagramme] = set(), option_complex_classifiante:Sequence[Diagramme] = set()) -> Tuple[GC,Foncteur]:
cat2 |= {'L'} nouveau_gc = copy(gc)
h,i,j = [MGC('A','L','h'),MGC('B','L','i'),MGC('C','L','j')] fonct = Foncteur(gc,nouveau_gc,{o:o for o in gc.objets},{m:m for m in gc[gc.objets,gc.objets]})
cat2 |= {h,i,j} nouveaux_obj, nouvelles_fleches = option_ajout
nouveau_gc |= set(nouveaux_obj)
nouveau_gc |= set(nouvelles_fleches)
nouveau_gc -= set(option_elimination)
while True:
for diag in option_complex_agissante:
c_a = ChampActif(fonct@diag)
colimites = c_a.objets_colimites()
if len(colimites) == 0:
# S'il n'y avait pas de colimite, on la créé
nouvel_objet = "Colimite de "+str(diag)
while nouvel_objet in nouveau_gc.objets:
nouvel_objet += "'"
nouveau_gc |= {nouvel_objet}
dico_index_jambe = dict() # {i:jambe}
for i in diag.source.objets:
jambe = MGC(diag(i),nouvel_objet)
dico_index_jambe[i] = jambe
nouveau_gc |= {jambe}
for fleche_i in diag.source[diag.source.objets, diag.source.objets]:
if dico_index_jambe[fleche_i.source] != dico_index_jambe[fleche_i.cible]@diag(fleche_i):
MGC.identifier_morphismes(dico_index_jambe[fleche_i.cible]@diag(fleche_i),dico_index_jambe[fleche_i.source])
#ajouter les flèches vers les autres cocônes
for cocone in c_a.objets:
cocone = Cocone(cocone)
nouvelle_fleche = MGC(nouvel_objet,cocone.nadir)
for fleche_i in diag.source[diag.source.objets, diag.source.objets]:
if dico_index_jambe[fleche_i.source] != cocone(fleche_i.cible)@diag(fleche_i):
MGC.identifier_morphismes(cocone(fleche_i.cible)@diag(fleche_i),dico_index_jambe[fleche_i.source])
break
else:
for diag in option_complex_classifiante:
c_p = ChampPerceptif(fonct@diag)
limites = c_p.objets_limites()
if len(limites) == 0:
# S'il n'y avait pas de limite, on la créé
nouvel_objet = "Limite de "+str(diag)
while nouvel_objet in nouveau_gc.objets:
nouvel_objet += "'"
nouveau_gc |= {nouvel_objet}
dico_index_jambe = dict() # {i:jambe}
for i in diag.source.objets:
jambe = MGC(nouvel_objet,diag(i))
dico_index_jambe[i] = jambe
nouveau_gc |= {jambe}
for fleche_i in diag.source[diag.source.objets, diag.source.objets]:
if dico_index_jambe[fleche_i.cible] != diag(fleche_i)@dico_index_jambe[fleche_i.source]:
MGC.identifier_morphismes(diag(fleche_i)@dico_index_jambe[fleche_i.source],dico_index_jambe[fleche_i.cible])
#ajouter les flèches depuis les autres cônes
for cone in c_p.objets:
cone = Cone(cone)
nouvelle_fleche = MGC(cocone.apex,nouvel_objet)
for fleche_i in diag.source[diag.source.objets, diag.source.objets]:
if cone(fleche_i.source) != dico_index_jambe[fleche_i.cible]@diag(fleche_i):
MGC.identifier_morphismes(dico_index_jambe[fleche_i.cible]@diag(fleche_i),cone(fleche_i.source))
break
else:
break # si on a rien ajouté on peut enfin sortir
return nouveau_gc,fonct
cat.transformer_graphviz()
h = MGC('S','T','h')
diag = DiagrammeIdentite(cat)
cat2,fonct = modification(cat,({'S','T'},{h}),{},{diag},{diag})
cat2.transformer_graphviz()
fonct.transformer_graphviz()
diag2 = Diagramme(cat,cat2,{'A':'A','B':'B','C':'C'},{f:f,g:g}) diag = fonct@diag
MGC.identifier_morphismes(i@f,h) diag.transformer_graphviz()
MGC.identifier_morphismes(j@g,h) ChampPerceptif(diag).transformer_graphviz()
for cone in ChampPerceptif(diag).objets:
Cone(cone).transformer_graphviz()
diag2.transformer_graphviz()
c_a2 = ChampActif(diag2) \ No newline at end of file
c_a2.transformer_graphviz()
...@@ -73,7 +73,8 @@ class Application(Morphisme): ...@@ -73,7 +73,8 @@ class Application(Morphisme):
if CLEAN_GRAPHVIZ_MODEL: if CLEAN_GRAPHVIZ_MODEL:
import os import os
os.remove(destination) os.remove(destination)
class CategorieEnsemblesFinis(Categorie): class CategorieEnsemblesFinis(Categorie):
"""CategorieEnsFinis peut être abrégé en EnsFinis """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. Catégorie des ensembles finis, cette catégorie est infinie, on ajoute uniquement les ensembles dont on a besoin.
...@@ -194,9 +195,9 @@ class CategorieBijections(EnsFinis): ...@@ -194,9 +195,9 @@ class CategorieBijections(EnsFinis):
yield Bijection(source,cible,{source_liste[j]:rotation[j] for j in range(len(source_liste))}) yield Bijection(source,cible,{source_liste[j]:rotation[j] for j in range(len(source_liste))})
def test_EnsFinis(): def test_EnsFinis():
cat = EnsFinis(set(map(frozenset,[{},{1,2},{3,4,5},{6,7,8,9,10}]))) cat = EnsFinis(set(map(frozenset,[{},{1,2},{3,4,5}])))
cat.transformer_graphviz(limite_fleches=243,complet=False)
cat.transformer_graphviz(limite_fleches=243,complet=False) cat.transformer_graphviz(limite_fleches=243,complet=False)
cat.transformer_graphviz(limite_fleches=243,complet=True)
# for source,cible in itertools.product(cat.objets,repeat=2):