Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Guillaume Sabbagh
Modification de categories
Commits
c54c6b35
Commit
c54c6b35
authored
Jun 29, 2021
by
Guillaume Sabbagh
Browse files
Début correction CatégorieAléatoire pour inclure les identités dans la table de loi de composition
parent
1afafa6b
Changes
9
Hide whitespace changes
Inline
Side-by-side
CatFinies.py
View file @
c54c6b35
from
Categorie
import
Categorie
from
Foncteur
import
Foncteur
from
EnsFinis
import
EnsFinis
,
Application
from
ProduitGenerateurs
import
produit_cartesien_generateurs
import
itertools
from
typing
import
*
...
...
@@ -17,19 +18,17 @@ class CatFinies(Categorie):
# cat_source et cat_cible sont des catégories, on cherche tous les foncteurs de cat_source vers cat_cible
ens_objets
=
EnsFinis
({
cat_source
.
objets
,
cat_cible
.
objets
})
for
app_obj
in
ens_objets
({
cat_source
.
objets
},{
cat_cible
.
objets
}):
print
(
app_obj
)
app_fleche_foncteur
=
dict
()
# à chaque couple d'objets on associe un ensemble d'applications
for
c
,
d
in
itertools
.
product
(
cat_source
.
objets
,
repeat
=
2
):
ens_fleches
=
EnsFinis
({
frozenset
(
cat_source
[{
c
},{
d
}]),
frozenset
(
cat_cible
({
app_obj
(
c
)},{
app_obj
(
d
)}))})
app_fleches_c_vers_d
=
set
(
ens_fleches
({
frozenset
(
cat_source
[{
c
},{
d
}])},{
frozenset
(
cat_cible
({
app_obj
(
c
)},{
app_obj
(
d
)}))})
)
app_fleches_c_vers_d
=
ens_fleches
({
frozenset
(
cat_source
[{
c
},{
d
}])},{
frozenset
(
cat_cible
({
app_obj
(
c
)},{
app_obj
(
d
)}))})
app_fleche_foncteur
[(
c
,
d
)]
=
app_fleches_c_vers_d
if
len
(
app_fleches_c_vers_d
)
==
0
:
break
if
len
(
app_fleche_foncteur
[(
c
,
d
)])
==
0
:
continue
for
applications_fleches
in
itertools
.
product
(
*
app_fleche_foncteur
.
values
()):
for
applications_fleches
in
produit_cartesien_generateurs
(
*
app_fleche_foncteur
.
values
()):
app_fleches
=
dict
()
for
app
in
applications_fleches
:
app_fleches
.
update
(
app
.
as_dict
())
print
(
app_fleches
)
for
f
in
cat_source
[
abs
(
cat_source
),
abs
(
cat_source
)]:
for
g
in
cat_source
[
abs
(
cat_source
),{
f
.
source
}]:
if
f
@
g
in
app_fleches
and
app_fleches
[
f
@
g
]
!=
app_fleches
[
f
]
@
app_fleches
[
g
]:
...
...
@@ -38,6 +37,7 @@ class CatFinies(Categorie):
continue
break
else
:
print
(
"yield"
)
yield
Foncteur
(
cat_source
,
cat_cible
,
app_obj
.
as_dict
(),
app_fleches
)
def
test_CatFinies
():
...
...
Categorie.py
View file @
c54c6b35
...
...
@@ -132,6 +132,8 @@ class Categorie:
On peut surcharger la méthode __call__ de CategorieLibre pour optimiser les calculs quand c'est pertinent. Il faut alors
s'assurer que la nouvelle méthode renvoie les mêmes morphismes que l'ancienne méthode aurait renvoyée.
Il est aussi recommandé de surcharger decomposition_morphisme pour optimiser les calculs.
Si on surcharge __getitem__, on peut aussi surcharger __iter__ des morphismes associés à la catégorie pour itérer sur les constituants
élémentaires du morphisme.
"""
...
...
@@ -139,6 +141,16 @@ class Categorie:
raise
Exception
(
"On s'attend à avoir un couple : "
+
str
(
couple_sources_cibles
))
return
self
(
*
couple_sources_cibles
)
def
decomposition_morphisme
(
self
,
morphisme
:
Morphisme
)
->
Generator
[
Morphisme
,
None
,
None
]:
"""Renvoie un générateur de morphismes élémentaires qui composés donnent le `morphisme`.
Si __getitem__ n'a pas été surchargé, tous les morphismes sont des morphismes élémentaires.
On le renvoie donc simplement.
Si une classe fille surcharge __getitem__ il faut surcharger decomposition_morphisme aussi."""
if
TOUJOURS_VERIFIER_COHERENCE_COMPOSEE
:
if
morphisme
not
in
self
[{
morphisme
.
source
},{
morphisme
.
cible
}]:
raise
Exception
(
"Le morphisme fourni n'est pas un morphisme elementaire et la methode decomposition_morphisme n'a pas ete surchargee : "
+
str
(
morphisme
))
yield
morphisme
def
identite
(
self
,
objet
:
Any
)
->
Morphisme
:
"""
...
...
CategorieAleatoire.py
View file @
c54c6b35
...
...
@@ -3,6 +3,8 @@ from Monoide import Monoide,ElementMonoideGC,MonoideGC
from
Categorie
import
Categorie
from
CategorieProduit
import
CategorieProduit
from
CategorieLibre
import
CategorieLibre
from
CatFinies
import
CatFinies
from
Foncteur
import
Foncteur
import
random
import
copy
import
itertools
...
...
@@ -15,55 +17,103 @@ if PROGRESS_BAR:
from
graphviz
import
Digraph
class
GrapheCompositionAleatoire
(
GC
):
"""Construit un graphe de composition aléatoire."""
def
__init__
(
self
,
nb_fleches
:
Union
[
int
,
None
]
=
None
,
nb_tentatives_complexification_loi_de_compo
:
int
=
100
,
nom
:
str
=
"Catégorie Aléatoire"
):
def
__init__
(
self
,
nb_fleches
:
Union
[
int
,
None
]
=
None
,
nb_tentatives_complexification_loi_de_compo
:
Union
[
int
,
None
]
=
None
,
nom
:
str
=
"Catégorie Aléatoire"
):
"""`nb_fleches` est le nombre de flèches élémentaires dans la catégorie aléatoire.
`nb_tentatives_complexification_loi_de_compo` détermine à quel point la loi de composition sera complexifiée,
si le nombre est faible on obtient une catégorie où les flèches sont isolées."""
if
nb_fleches
==
None
:
nb_fleches
=
random
.
randint
(
1
,
20
)
nb_fleches
=
10
if
nb_tentatives_complexification_loi_de_compo
==
None
:
nb_tentatives_complexification_loi_de_compo
=
random
.
randint
(
0
,
10
*
nb_fleches
)
GC
.
__init__
(
self
,
nom
=
nom
)
class
LoiDeComposition
:
def
__init__
(
self
):
self
.
table
=
defaultdict
(
lambda
:
None
)
for
i
in
range
(
1
,
2
*
nb_fleches
+
1
):
for
j
in
range
(
1
,
2
*
nb_fleches
+
1
):
self
.
table
[(
-
j
,
i
)]
=
self
.
table
[(
i
,
-
j
)]
=
i
# les identités sont neutres
self
.
table
[(
-
j
,
-
j
)]
=
-
j
# une classe par source et target de flèches initiales (soit 2*nb_fleches classes initiales)
# la source d'une flèche est représentée par le numéro de la flèche
# la cible d'une flèche est représentée par le numero de la flèche plus le nombre de flèches
self
.
classe_equiv_vers_fleche
=
{
i
:{
i
}
for
i
in
range
(
nb_fleches
*
2
)}
# {numero_classe: {fleche1,fleche2,...}}
self
.
fleche_vers_classe_equiv
=
{
i
:
i
for
i
in
range
(
nb_fleches
*
2
)}
# {fleche:numero_classe}
self
.
obj_vers_fleche
=
defaultdict
(
set
)
# {numero_objet: {fleche1,fleche2,...}}
self
.
fleche_vers_obj
=
dict
()
# {fleche:numero_obj}
for
fleche
in
self
.
fleches
:
self
.
obj_vers_fleche
[
fleche
]
|=
{
fleche
,
self
.
identite_source_fleche
(
fleche
)}
self
.
obj_vers_fleche
[
fleche
+
nb_fleches
]
|=
{
fleche
,
self
.
identite_cible_fleche
(
fleche
)}
self
.
fleche_vers_obj
[
fleche
]
=
fleche
self
.
fleche_vers_obj
[
fleche
+
nb_fleches
]
=
fleche
+
nb_fleches
self
.
fleche_vers_obj
[
self
.
identite_source_fleche
(
fleche
)]
=
fleche
self
.
fleche_vers_obj
[
self
.
identite_cible_fleche
(
fleche
)]
=
fleche
+
nb_fleches
print
(
nb_fleches
)
print
(
self
.
obj_vers_fleche
)
print
(
self
.
fleche_vers_obj
)
@
property
def
fleches
(
self
)
->
list
:
'''Renvoie la liste des flèches.'''
return
list
(
range
(
1
,
nb_fleches
+
1
))
def
source_fleche
(
self
,
i
:
int
)
->
int
:
'''Renvoie la représentation de la source de la flèche i.'''
assert
(
i
!=
0
)
return
self
.
fleche_vers_obj
[
abs
(
i
)]
def
cible_fleche
(
self
,
i
:
int
)
->
int
:
'''Renvoie la représentation de la cible de la flèche i.'''
assert
(
i
!=
0
)
if
i
>
0
:
return
self
.
fleche_vers_obj
[
i
+
nb_fleches
]
else
:
return
self
.
fleche_vers_obj
[
abs
(
i
)]
def
identite_source_fleche
(
self
,
i
:
int
)
->
int
:
'''Renvoie la représentation de la flèche identité sur la source de la flèche i.'''
return
-
abs
(
i
)
def
identite_cible_fleche
(
self
,
i
:
int
)
->
int
:
'''Renvoie la représentation de la flèche identité sur la cible de la flèche i.'''
return
-
((
abs
(
i
)
+
nb_fleches
-
1
)
%
(
2
*
nb_fleches
)
+
1
)
def
linker_sources_fleches
(
self
,
fleche1
,
fleche2
):
classe1
,
classe2
=
self
.
fleche_vers_
classe_equiv
[
fleche1
],
self
.
fleche_vers_
classe_equiv
[
fleche2
]
classe1
,
classe2
=
self
.
fleche_vers_
obj
[
self
.
source_fleche
(
fleche1
)
],
self
.
fleche_vers_
obj
[
self
.
source_fleche
(
fleche2
)
]
if
classe1
!=
classe2
:
#on fusionne les deux classes dans classe1
for
fleche
in
self
.
classe_equiv_vers_fleche
[
classe2
]:
self
.
fleche_vers_classe_equiv
[
fleche
]
=
classe1
self
.
classe_equiv_vers_fleche
[
classe1
]
|=
self
.
classe_equiv_vers_fleche
[
classe2
]
del
self
.
classe_equiv_vers_fleche
[
classe2
]
for
fleche
in
self
.
obj_vers_fleche
[
classe2
]:
self
.
fleche_vers_obj
[
self
.
source_fleche
(
fleche
)]
=
classe1
self
.
fleche_vers_obj
[
self
.
source_fleche
(
self
.
identite_source_fleche
(
fleche
))]
=
classe1
self
.
fleche_vers_obj
[
self
.
cible_fleche
(
self
.
identite_source_fleche
(
fleche
))]
=
classe1
self
.
obj_vers_fleche
[
classe1
]
|=
self
.
obj_vers_fleche
[
classe2
]
del
self
.
obj_vers_fleche
[
classe2
]
def
linker_cibles_fleches
(
self
,
fleche1
,
fleche2
):
fleche1
,
fleche2
=
fleche1
+
nb_fleches
,
fleche2
+
nb_fleches
classe1
,
classe2
=
self
.
fleche_vers_classe_equiv
[
fleche1
],
self
.
fleche_vers_classe_equiv
[
fleche2
]
classe1
,
classe2
=
self
.
fleche_vers_obj
[
self
.
source_fleche
(
fleche1
)],
self
.
fleche_vers_obj
[
self
.
cible_fleche
(
fleche2
)]
if
classe1
!=
classe2
:
#on fusionne les deux classes dans classe1
for
fleche
in
self
.
classe_equiv_vers_fleche
[
classe2
]:
self
.
fleche_vers_classe_equiv
[
fleche
]
=
classe1
self
.
classe_equiv_vers_fleche
[
classe1
]
|=
self
.
classe_equiv_vers_fleche
[
classe2
]
del
self
.
classe_equiv_vers_fleche
[
classe2
]
for
fleche
in
self
.
obj_vers_fleche
[
classe2
]:
self
.
fleche_vers_obj
[
self
.
cible_fleche
(
fleche
)]
=
classe1
self
.
fleche_vers_obj
[
self
.
source_fleche
(
self
.
identite_cible_fleche
(
fleche
))]
=
classe1
self
.
fleche_vers_obj
[
self
.
cible_fleche
(
self
.
identite_cible_fleche
(
fleche
))]
=
classe1
self
.
obj_vers_fleche
[
classe1
]
|=
self
.
obj_vers_fleche
[
classe2
]
del
self
.
obj_vers_fleche
[
classe2
]
def
linker_cible_source_fleches
(
self
,
fleche1
,
fleche2
):
'''link la cible de `fleche1` à la source de `fleche2`'''
fleche1
+=
nb_fleches
classe1
,
classe2
=
self
.
fleche_vers_classe_equiv
[
fleche1
],
self
.
fleche_vers_classe_equiv
[
fleche2
]
classe1
,
classe2
=
self
.
fleche_vers_obj
[
self
.
cible_fleche
(
fleche1
)],
self
.
fleche_vers_obj
[
self
.
source_fleche
(
fleche2
)]
if
classe1
!=
classe2
:
#on fusionne les deux classes dans classe1
for
fleche
in
self
.
classe_equiv_vers_fleche
[
classe2
]:
self
.
fleche_vers_classe_equiv
[
fleche
]
=
classe1
self
.
classe_equiv_vers_fleche
[
classe1
]
|=
self
.
classe_equiv_vers_fleche
[
classe2
]
del
self
.
classe_equiv_vers_fleche
[
classe2
]
for
fleche
in
self
.
obj_vers_fleche
[
classe2
]:
self
.
fleche_vers_obj
[
fleche
]
=
classe1
self
.
fleche_vers_obj
[
self
.
source_fleche
(
self
.
identite_source_fleche
(
fleche
))]
=
classe1
self
.
fleche_vers_obj
[
self
.
cible_fleche
(
self
.
identite_source_fleche
(
fleche
))]
=
classe1
self
.
obj_vers_fleche
[
classe1
]
|=
self
.
obj_vers_fleche
[
classe2
]
del
self
.
obj_vers_fleche
[
classe2
]
def
tentative_complexification
(
loi
:
LoiDeComposition
,
i
:
int
,
j
:
int
,
nb_tentatives
:
int
=
3
)
->
Union
[
LoiDeComposition
,
None
]:
"""Tente de complexifier la loi de composition en définissant la composition j o i.
...
...
@@ -71,9 +121,16 @@ class GrapheCompositionAleatoire(GC):
nouvelle_loi
=
copy
.
deepcopy
(
loi
)
if
nouvelle_loi
.
table
[(
i
,
j
)]
!=
None
:
return
None
nouvelle_loi
.
table
[(
i
,
j
)]
=
random
.
randint
(
0
,
nb_fleches
-
1
)
nouvelle_loi
.
linker_sources_fleches
(
i
,
nouvelle_loi
.
table
[(
i
,
j
)])
nouvelle_loi
.
linker_cibles_fleches
(
j
,
nouvelle_loi
.
table
[(
i
,
j
)])
if
nouvelle_loi
.
fleche_vers_obj
[
nouvelle_loi
.
source_fleche
(
i
)]
==
nouvelle_loi
.
fleche_vers_obj
[
nouvelle_loi
.
cible_fleche
(
j
)]:
# si la source de i et la cible de j sont dans la même classe d'équivalence
# une issue possible est j o i = Id
nouvelle_loi
.
table
[(
i
,
j
)]
=
random
.
randint
(
0
,
nb_fleches
)
if
nouvelle_loi
.
table
[(
i
,
j
)]
==
0
:
nouvelle_loi
.
table
[(
i
,
j
)]
=
nouvelle_loi
.
identite_source_fleche
(
i
)
else
:
nouvelle_loi
.
table
[(
i
,
j
)]
=
random
.
randint
(
1
,
nb_fleches
)
nouvelle_loi
.
linker_sources_fleches
(
i
,
nouvelle_loi
.
table
[(
i
,
j
)])
nouvelle_loi
.
linker_cibles_fleches
(
j
,
nouvelle_loi
.
table
[(
i
,
j
)])
nouvelle_loi
.
linker_cible_source_fleches
(
i
,
j
)
while
True
:
for
a
,
b
,
c
in
itertools
.
product
(
range
(
nb_fleches
),
repeat
=
3
):
...
...
@@ -104,11 +161,11 @@ class GrapheCompositionAleatoire(GC):
probleme_composition
=
True
while
probleme_composition
:
probleme_composition
=
False
for
classe_equiv
in
nouvelle_loi
.
classe_equiv
_vers_fleche
:
for
fleche1
in
nouvelle_loi
.
classe_equiv
_vers_fleche
[
classe_equiv
]:
if
fleche1
>
=
nb_fleches
:
for
fleche2
in
nouvelle_loi
.
classe_equiv
_vers_fleche
[
classe_equiv
]:
if
fleche2
<
nb_fleches
:
for
obj
in
nouvelle_loi
.
obj
_vers_fleche
:
for
fleche1
in
nouvelle_loi
.
obj
_vers_fleche
[
obj
]:
if
fleche1
>
nb_fleches
:
for
fleche2
in
nouvelle_loi
.
obj
_vers_fleche
[
obj
]:
if
0
<
fleche2
<
nb_fleches
:
# fleche1 et fleche2 sont censées être composables
if
nouvelle_loi
.
table
[(
fleche1
-
nb_fleches
,
fleche2
)]
==
None
:
# problème de composition
...
...
@@ -137,29 +194,33 @@ class GrapheCompositionAleatoire(GC):
else
:
iterator
=
range
(
nb_tentatives_complexification_loi_de_compo
)
for
tentative
in
iterator
:
i
,
j
=
random
.
randint
(
0
,
nb_fleches
-
1
),
random
.
randint
(
0
,
nb_fleches
-
1
)
i
,
j
=
random
.
randint
(
1
,
nb_fleches
),
random
.
randint
(
1
,
nb_fleches
)
loi2
=
tentative_complexification
(
loi
,
i
,
j
)
if
loi2
!=
None
:
loi
=
loi2
#on a une table de loi de composition aléatoire
for
classe
in
loi
.
classe_equiv
_vers_fleche
:
self
|=
{
classe
}
for
obj
in
loi
.
obj
_vers_fleche
:
self
|=
{
obj
}
#on va retirer les flèches qui peuvent être trouvées par composition de flèches élémentaires
fleches_composites
=
{
loi
.
table
[(
i
,
j
)]
for
i
,
j
in
itertools
.
product
(
range
(
nb_fleches
),
repeat
=
2
)
if
loi
.
table
[(
i
,
j
)]
not
in
[
i
,
j
]
if
loi
.
table
[(
i
,
j
)]
!=
None
}
fleches
=
{
i
:
MGC
(
loi
.
fleche_vers_classe_equiv
[
i
],
loi
.
fleche_vers_classe_equiv
[
i
+
nb_fleches
])
for
i
in
range
(
nb_fleches
)}
fleches_composites
=
{
loi
.
table
[(
i
,
j
)]
for
i
,
j
in
itertools
.
product
(
loi
.
fleches
,
repeat
=
2
)
if
loi
.
table
[(
i
,
j
)]
!=
None
and
loi
.
table
[(
i
,
j
)]
not
in
[
i
,
j
]
and
loi
.
table
[(
i
,
j
)]
>
0
}
print
(
loi
.
fleches
)
print
(
list
(
map
(
lambda
x
:
str
(
loi
.
source_fleche
(
x
)),
loi
.
fleches
)))
fleches
=
{
i
:
MGC
(
loi
.
fleche_vers_obj
[
loi
.
source_fleche
(
i
)],
loi
.
fleche_vers_obj
[
loi
.
cible_fleche
(
i
)])
for
i
in
loi
.
fleches
}
self
|=
set
(
fleches
.
values
())
self
.
_fleches_elem
=
{
fleches
[
i
]
for
i
in
set
(
range
(
nb_
fleches
)
)
-
fleches_composites
}
for
i
,
j
in
itertools
.
product
(
range
(
nb_
fleches
)
,
repeat
=
2
):
self
.
_fleches_elem
=
{
fleches
[
i
]
for
i
in
set
(
loi
.
fleches
)
-
fleches_composites
}
for
i
,
j
in
itertools
.
product
(
loi
.
fleches
,
repeat
=
2
):
if
loi
.
table
[(
i
,
j
)]
!=
None
:
if
fleches
[
loi
.
table
[(
i
,
j
)]]
!=
fleches
[
j
]
@
fleches
[
i
]:
if
loi
.
table
[(
i
,
j
)]
<
0
:
MGC
.
identifier_morphismes
(
fleches
[
j
]
@
fleches
[
i
],
self
.
identite
(
loi
.
fleche_vers_obj
[
loi
.
source_fleche
(
i
)]))
elif
fleches
[
loi
.
table
[(
i
,
j
)]]
!=
fleches
[
j
]
@
fleches
[
i
]:
MGC
.
identifier_morphismes
(
fleches
[
j
]
@
fleches
[
i
],
fleches
[
loi
.
table
[(
i
,
j
)]])
with
open
(
"out.csv"
,
"w"
)
as
f
:
f
.
write
(
","
+
","
.
join
(
map
(
str
,
range
(
nb_fleches
)))
+
"
\n
"
)
for
a
in
range
(
nb_fleches
):
f
.
write
(
","
+
","
.
join
(
map
(
str
,
range
(
-
2
*
nb_fleches
,
nb_fleches
+
1
)))
+
"
\n
"
)
for
a
in
range
(
-
2
*
nb_fleches
,
nb_fleches
+
1
):
f
.
write
(
str
(
a
))
for
b
in
range
(
nb_fleches
):
for
b
in
range
(
-
2
*
nb_fleches
,
nb_fleches
+
1
):
f
.
write
(
','
+
str
(
loi
.
table
[(
a
,
b
)]))
f
.
write
(
'
\n
'
)
...
...
@@ -290,13 +351,34 @@ def test_MonoideGC():
mon
.
transformer_graphviz
()
mon
.
loi_de_composition_to_csv
(
destination
=
"lois de composition/monoide.csv"
)
# def DiagrammeAleatoire(Diagramme):
# """Diagramme aléatoire sur une catégorie."""
# def __init__(self, categorie_indexante:Categorie = GrapheCompositionAleatoire(), categorie_cible:Categorie, nom:str = None):
class
FoncteurAleatoire
(
Foncteur
):
"""Foncteur aléatoire sur une catégorie."""
def
__new__
(
cls
,
categorie_indexante
:
Categorie
=
GrapheCompositionAleatoire
(),
categorie_cible
:
Categorie
=
GrapheCompositionAleatoire
(),
nom
:
str
=
None
):
if
nom
==
None
:
nom
=
"Foncteur aléatoire sur "
+
str
(
categorie_cible
)
cat
=
CatFinies
({
categorie_indexante
,
categorie_cible
},
"Catégorie des foncteurs pour génération de foncteur aléatoire"
)
foncteur
=
random
.
choice
(
list
(
cat
({
categorie_indexante
},{
categorie_cible
})))
foncteur
.
nom
=
nom
return
foncteur
# class FoncteurAleatoire(Foncteur):
# """Foncteur aléatoire sur une catégorie."""
# def __init__(self, categorie_indexante:Categorie = GrapheCompositionAleatoire(), categorie_cible:Categorie = GrapheCompositionAleatoire(), nom:str = None):
# if nom == None:
# nom = "Diagramme aléatoire sur "+str(categorie_cible)
# nom = "Foncteur aléatoire sur "+str(categorie_cible)
# cat = CatFinies({categorie_indexante,categorie_cible}, "Catégorie des foncteurs pour génération de foncteur aléatoire")
# foncteur = random.choice(cat({categorie_indexante},{categorie_cible}))
# Foncteur.__init__(self,categorie_indexante,categorie_cible,foncteur._app_obj,foncteur._app_morph,foncteur.is_identite)
def
test_FoncteurAleatoire
():
for
i
in
range
(
20
):
f
=
FoncteurAleatoire
()
f
.
source
.
transformer_graphviz
()
f
.
cible
.
transformer_graphviz
()
f
.
transformer_graphviz
()
if
__name__
==
'__main__'
:
test_GrapheCompositionAleatoire
()
test_MonoideGC
()
\ No newline at end of file
# test_MonoideGC()
# test_FoncteurAleatoire()
\ No newline at end of file
CategorieLibre.py
View file @
c54c6b35
...
...
@@ -35,6 +35,9 @@ class CategorieLibre(Categorie):
"""Soit C est une catégorie:
C({a_i},{b_i}) renvoie l'ensemble des flèches d'un élément de {a_i} vers un élément de {b_i}.
Pour la catégorie libre, on doit énumérer tous les chemins et les composer.
Les classes filles peuvent surcharger cette méthode pour optimiser les calculs. Il faut alors s'assurer que les morphismes
générés sont les mêmes.
"""
for
source
in
sources
:
for
cible
in
cibles
:
...
...
@@ -42,7 +45,9 @@ class CategorieLibre(Categorie):
yield
morph
def
decomposition_morphisme
(
self
,
morphisme
:
Morphisme
)
->
Generator
[
Morphisme
,
None
,
None
]:
'''Renvoie un générateur de morphismes élémentaires qui composés donnent le `morphisme`.'''
'''Renvoie un générateur de morphismes élémentaires qui composés donnent le `morphisme`.
Les classes filles peuvent surcharger cette méthode pour optimiser les calculs.'''
if
morphisme
in
self
[{
morphisme
.
source
},{
morphisme
.
cible
}]:
yield
morphisme
else
:
...
...
@@ -58,7 +63,7 @@ class CategorieLibre(Categorie):
return
composees_resultat
return
frozenset
()
for
chemin
in
enumerer_chemin_elem_sans_cycle
(
morphisme
.
source
,
morphisme
.
cible
):
resultat
=
functools
.
reduce
(
lambda
x
,
y
:
y
@
x
,
chemin
)
resultat
=
functools
.
reduce
(
lambda
x
,
y
:
x
@
y
,
chemin
)
if
resultat
==
morphisme
:
for
morph_elem
in
chemin
:
yield
morph_elem
...
...
EnsFinis.py
View file @
c54c6b35
...
...
@@ -75,7 +75,7 @@ class Application(Morphisme):
os
.
remove
(
destination
)
class
CategorieEnsemblesFinis
(
Categorie
):
class
CategorieEnsemblesFinis
(
Categorie
Libre
):
"""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.
/!\ __call__ n'appelle pas __getitem__ /!\ """
...
...
@@ -211,7 +211,7 @@ def test_EnsFinis():
def
test_EnsParties
():
cat
=
EnsParties
({
1
,
2
,
3
})
cat
.
transformer_graphviz
(
complet
=
Fals
e
)
cat
.
transformer_graphviz
(
complet
=
Tru
e
)
for
app
in
cat
({
frozenset
({
1
,
2
,
3
})},{
frozenset
({
1
,
2
})}):
app
.
transformer_graphviz
()
...
...
@@ -224,5 +224,5 @@ def test_CategorieBijections():
if
__name__
==
'__main__'
:
test_EnsFinis
()
# test_EnsParties()
# test_CategorieBijections()
\ No newline at end of file
test_EnsParties
()
test_CategorieBijections
()
\ No newline at end of file
Foncteur.py
View file @
c54c6b35
...
...
@@ -94,12 +94,15 @@ class Foncteur(Morphisme):
str
(
self
(
g
@
f
))
+
' != '
+
str
(
self
(
g
)
@
self
(
f
)))
def
__call__
(
self
,
param
:
Any
)
->
Any
:
'''Applique le foncteur à un objet ou un morphisme de la catégorie source.'''
'''Applique le foncteur à un objet ou un morphisme de la catégorie source.
Si le morphisme $h = g o f$ avec g et f des morphismes élémentaires, préferer calculer foncteur(g) o foncteur(f)
plutôt que foncteur(h) (évite l'appel à la fonction decomposition_morphisme).'''
if
param
in
self
.
_app_objets
:
return
self
.
_app_objets
[
param
]
if
param
in
self
.
_app_morph
:
return
self
.
_app_morph
[
param
]
decompo
=
self
.
source
.
decomposition_morphisme
(
param
)
decompo
=
self
.
source
.
decomposition_morphisme
(
param
)
return
functools
.
reduce
(
lambda
x
,
y
:
x
@
y
,[
self
.
_app_morph
[
morph
]
for
morph
in
decompo
])
def
transformer_graphviz
(
self
,
destination
:
Union
[
str
,
None
]
=
None
,
afficher_identites
:
bool
=
False
):
...
...
GrapheDeComposition.py
View file @
c54c6b35
...
...
@@ -147,6 +147,17 @@ class GrapheDeComposition(CategorieLibre):
for
cible
in
cibles
:
for
fleche
in
self
.
morph_sortants
(
source
)
&
self
.
morph_entrants
(
cible
):
yield
fleche
def
decomposition_morphisme
(
self
,
morphisme
:
Morphisme
)
->
Generator
[
Morphisme
,
None
,
None
]:
'''Renvoie un générateur de morphismes élémentaires qui composés donnent le `morphisme`.
Les classes filles peuvent surcharger cette méthode pour optimiser les calculs.'''
for
m
in
morphisme
:
if
m
in
self
[{
m
.
source
},{
m
.
cible
}]:
yield
m
else
:
for
morph
in
CategorieLibre
.
decomposition_morphisme
(
self
,
m
):
yield
morph
def
__eq__
(
self
,
other
:
'GrapheDeComposition'
)
->
bool
:
return
type
(
other
)
==
type
(
self
)
and
self
.
__identites
==
other
.
__identites
and
\
...
...
config.py
View file @
c54c6b35
...
...
@@ -6,4 +6,7 @@ GRAPHVIZ_CONCENTRATE_GRAPHS = False
WARNING_LIMITE_FLECHES_ATTEINTE
=
True
PRINT_AVANCEMENT_CREATION_CAT_ALEA
=
True
CLEAN_GRAPHVIZ_MODEL
=
True
PROGRESS_BAR
=
True
\ No newline at end of file
PROGRESS_BAR
=
True
import
random
random
.
seed
(
1
)
\ No newline at end of file
todo.txt
View file @
c54c6b35
...
...
@@ -59,4 +59,16 @@ utiliser existe_morphisme plutôt que self({cocone_courant},cocones_restants) da
faire une seule classe catégorie homologue en créant une méthode sommet dans cone et cocone;
faire un test avec la catégorie de foncteurs avec pour objets CatégorieBij(1,2,3) et CatégorieBij(a,b,c)
\ No newline at end of file
faire un test avec la catégorie de foncteurs avec pour objets CatégorieBij(1,2,3) et CatégorieBij(a,b,c)
optimiser CatFinies et la recherche de foncteurs entre deux catégories :
- réunir les objets en classes d'équivalence selon la relation o1 ~ o2 ssi il existe f:o1->o2 et g:o2->o1.
- faire un graphe des classes d'équivalence avec comme noeuds les classes d'équivalence. Il y a une flèche
entre deux classes d'équivalence s'il existe au moins une flèche d'un objet d'une classe vers un objet de l'autre classe.
- ce graphe est acyclique.
- un foncteur doit préserver la structure de graphe acyclique -> (faire la catégorie des graphes acycliques ?)
Catégorie aléatoire : laisser la possibilité que la composition donne l'identité.
-1 donne les morphismes eux même lorsque composés (identité)
si source et target dans même classes d'équivalence, alors ajouter l'outcome -1
Guillaume Sabbagh
@gsabbagh
mentioned in commit
a9242fcf
·
Jul 05, 2021
mentioned in commit
a9242fcf
mentioned in commit a9242fcfc0ab39f7b87f98a6728ac14568800f02
Toggle commit list
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment