passagemath-graphs 10.6.1rc1__cp310-cp310-musllinux_1_2_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- passagemath_graphs-10.6.1rc1.dist-info/METADATA +292 -0
- passagemath_graphs-10.6.1rc1.dist-info/RECORD +260 -0
- passagemath_graphs-10.6.1rc1.dist-info/WHEEL +5 -0
- passagemath_graphs-10.6.1rc1.dist-info/top_level.txt +2 -0
- passagemath_graphs.libs/libgcc_s-69c45f16.so.1 +0 -0
- passagemath_graphs.libs/libgmp-8e78bd9b.so.10.5.0 +0 -0
- passagemath_graphs.libs/libstdc++-1f1a71be.so.6.0.33 +0 -0
- sage/all__sagemath_graphs.py +39 -0
- sage/combinat/abstract_tree.py +2723 -0
- sage/combinat/all__sagemath_graphs.py +34 -0
- sage/combinat/binary_tree.py +5306 -0
- sage/combinat/cluster_algebra_quiver/all.py +22 -0
- sage/combinat/cluster_algebra_quiver/cluster_seed.py +5208 -0
- sage/combinat/cluster_algebra_quiver/interact.py +124 -0
- sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
- sage/combinat/cluster_algebra_quiver/mutation_type.py +1555 -0
- sage/combinat/cluster_algebra_quiver/quiver.py +2290 -0
- sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +2468 -0
- sage/combinat/designs/MOLS_handbook_data.py +570 -0
- sage/combinat/designs/all.py +58 -0
- sage/combinat/designs/bibd.py +1655 -0
- sage/combinat/designs/block_design.py +1071 -0
- sage/combinat/designs/covering_array.py +269 -0
- sage/combinat/designs/covering_design.py +530 -0
- sage/combinat/designs/database.py +5615 -0
- sage/combinat/designs/design_catalog.py +122 -0
- sage/combinat/designs/designs_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/designs_pyx.pxd +21 -0
- sage/combinat/designs/designs_pyx.pyx +993 -0
- sage/combinat/designs/difference_family.py +3951 -0
- sage/combinat/designs/difference_matrices.py +279 -0
- sage/combinat/designs/evenly_distributed_sets.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/evenly_distributed_sets.pyx +661 -0
- sage/combinat/designs/ext_rep.py +1064 -0
- sage/combinat/designs/gen_quadrangles_with_spread.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/gen_quadrangles_with_spread.pyx +339 -0
- sage/combinat/designs/group_divisible_designs.py +361 -0
- sage/combinat/designs/incidence_structures.py +2357 -0
- sage/combinat/designs/latin_squares.py +581 -0
- sage/combinat/designs/orthogonal_arrays.py +2244 -0
- sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
- sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +967 -0
- sage/combinat/designs/resolvable_bibd.py +815 -0
- sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
- sage/combinat/designs/subhypergraph_search.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/subhypergraph_search.pyx +530 -0
- sage/combinat/designs/twographs.py +306 -0
- sage/combinat/finite_state_machine.py +14874 -0
- sage/combinat/finite_state_machine_generators.py +2006 -0
- sage/combinat/graph_path.py +448 -0
- sage/combinat/interval_posets.py +3908 -0
- sage/combinat/nu_tamari_lattice.py +269 -0
- sage/combinat/ordered_tree.py +1446 -0
- sage/combinat/posets/all.py +46 -0
- sage/combinat/posets/bubble_shuffle.py +247 -0
- sage/combinat/posets/cartesian_product.py +493 -0
- sage/combinat/posets/d_complete.py +182 -0
- sage/combinat/posets/elements.py +273 -0
- sage/combinat/posets/forest.py +30 -0
- sage/combinat/posets/hasse_cython.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/posets/hasse_cython.pyx +174 -0
- sage/combinat/posets/hasse_diagram.py +3672 -0
- sage/combinat/posets/hochschild_lattice.py +158 -0
- sage/combinat/posets/incidence_algebras.py +794 -0
- sage/combinat/posets/lattices.py +5117 -0
- sage/combinat/posets/linear_extension_iterator.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/posets/linear_extension_iterator.pyx +292 -0
- sage/combinat/posets/linear_extensions.py +1037 -0
- sage/combinat/posets/mobile.py +275 -0
- sage/combinat/posets/moebius_algebra.py +776 -0
- sage/combinat/posets/poset_examples.py +2178 -0
- sage/combinat/posets/posets.py +9360 -0
- sage/combinat/rooted_tree.py +1070 -0
- sage/combinat/shard_order.py +239 -0
- sage/combinat/tamari_lattices.py +384 -0
- sage/combinat/yang_baxter_graph.py +923 -0
- sage/databases/all__sagemath_graphs.py +1 -0
- sage/databases/knotinfo_db.py +1231 -0
- sage/ext_data/all__sagemath_graphs.py +1 -0
- sage/ext_data/graphs/graph_plot_js.html +330 -0
- sage/ext_data/kenzo/CP2.txt +45 -0
- sage/ext_data/kenzo/CP3.txt +349 -0
- sage/ext_data/kenzo/CP4.txt +4774 -0
- sage/ext_data/kenzo/README.txt +49 -0
- sage/ext_data/kenzo/S4.txt +20 -0
- sage/graphs/all.py +42 -0
- sage/graphs/asteroidal_triples.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/asteroidal_triples.pyx +320 -0
- sage/graphs/base/all.py +1 -0
- sage/graphs/base/boost_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/boost_graph.pxd +106 -0
- sage/graphs/base/boost_graph.pyx +3045 -0
- sage/graphs/base/c_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/c_graph.pxd +106 -0
- sage/graphs/base/c_graph.pyx +5096 -0
- sage/graphs/base/dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/dense_graph.pxd +28 -0
- sage/graphs/base/dense_graph.pyx +801 -0
- sage/graphs/base/graph_backends.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/graph_backends.pxd +5 -0
- sage/graphs/base/graph_backends.pyx +797 -0
- sage/graphs/base/overview.py +85 -0
- sage/graphs/base/sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/sparse_graph.pxd +90 -0
- sage/graphs/base/sparse_graph.pyx +1653 -0
- sage/graphs/base/static_dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_dense_graph.pxd +5 -0
- sage/graphs/base/static_dense_graph.pyx +1032 -0
- sage/graphs/base/static_sparse_backend.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_sparse_backend.pxd +27 -0
- sage/graphs/base/static_sparse_backend.pyx +1583 -0
- sage/graphs/base/static_sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_sparse_graph.pxd +37 -0
- sage/graphs/base/static_sparse_graph.pyx +1375 -0
- sage/graphs/bipartite_graph.py +2732 -0
- sage/graphs/centrality.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/centrality.pyx +1038 -0
- sage/graphs/cographs.py +519 -0
- sage/graphs/comparability.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/comparability.pyx +851 -0
- sage/graphs/connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/connectivity.pxd +157 -0
- sage/graphs/connectivity.pyx +4813 -0
- sage/graphs/convexity_properties.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/convexity_properties.pxd +16 -0
- sage/graphs/convexity_properties.pyx +870 -0
- sage/graphs/digraph.py +4754 -0
- sage/graphs/digraph_generators.py +1993 -0
- sage/graphs/distances_all_pairs.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/distances_all_pairs.pxd +12 -0
- sage/graphs/distances_all_pairs.pyx +2938 -0
- sage/graphs/domination.py +1363 -0
- sage/graphs/dot2tex_utils.py +100 -0
- sage/graphs/edge_connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/edge_connectivity.pyx +1215 -0
- sage/graphs/generators/all.py +1 -0
- sage/graphs/generators/basic.py +1769 -0
- sage/graphs/generators/chessboard.py +538 -0
- sage/graphs/generators/classical_geometries.py +1611 -0
- sage/graphs/generators/degree_sequence.py +235 -0
- sage/graphs/generators/distance_regular.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/generators/distance_regular.pyx +2846 -0
- sage/graphs/generators/families.py +4759 -0
- sage/graphs/generators/intersection.py +565 -0
- sage/graphs/generators/platonic_solids.py +262 -0
- sage/graphs/generators/random.py +2623 -0
- sage/graphs/generators/smallgraphs.py +5741 -0
- sage/graphs/generators/world_map.py +724 -0
- sage/graphs/generic_graph.py +26867 -0
- sage/graphs/generic_graph_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/generic_graph_pyx.pxd +34 -0
- sage/graphs/generic_graph_pyx.pyx +1673 -0
- sage/graphs/genus.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/genus.pyx +622 -0
- sage/graphs/graph.py +9645 -0
- sage/graphs/graph_coloring.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_coloring.pyx +2284 -0
- sage/graphs/graph_database.py +1177 -0
- sage/graphs/graph_decompositions/all.py +1 -0
- sage/graphs/graph_decompositions/bandwidth.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
- sage/graphs/graph_decompositions/clique_separators.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/clique_separators.pyx +616 -0
- sage/graphs/graph_decompositions/cutwidth.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
- sage/graphs/graph_decompositions/fast_digraph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
- sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
- sage/graphs/graph_decompositions/graph_products.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/graph_products.pyx +508 -0
- sage/graphs/graph_decompositions/modular_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
- sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
- sage/graphs/graph_decompositions/slice_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
- sage/graphs/graph_decompositions/slice_decomposition.pyx +1106 -0
- sage/graphs/graph_decompositions/tree_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
- sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
- sage/graphs/graph_decompositions/vertex_separation.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
- sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
- sage/graphs/graph_editor.py +82 -0
- sage/graphs/graph_generators.py +3314 -0
- sage/graphs/graph_generators_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_generators_pyx.pyx +95 -0
- sage/graphs/graph_input.py +812 -0
- sage/graphs/graph_latex.py +2064 -0
- sage/graphs/graph_list.py +410 -0
- sage/graphs/graph_plot.py +1756 -0
- sage/graphs/graph_plot_js.py +338 -0
- sage/graphs/hyperbolicity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/hyperbolicity.pyx +1704 -0
- sage/graphs/hypergraph_generators.py +364 -0
- sage/graphs/independent_sets.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/independent_sets.pxd +13 -0
- sage/graphs/independent_sets.pyx +402 -0
- sage/graphs/isgci.py +1033 -0
- sage/graphs/isoperimetric_inequalities.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/isoperimetric_inequalities.pyx +489 -0
- sage/graphs/line_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/line_graph.pyx +743 -0
- sage/graphs/lovasz_theta.py +77 -0
- sage/graphs/matching.py +1633 -0
- sage/graphs/matching_covered_graph.py +3590 -0
- sage/graphs/orientations.py +1489 -0
- sage/graphs/partial_cube.py +459 -0
- sage/graphs/path_enumeration.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/path_enumeration.pyx +2040 -0
- sage/graphs/pq_trees.py +1129 -0
- sage/graphs/print_graphs.py +201 -0
- sage/graphs/schnyder.py +865 -0
- sage/graphs/spanning_tree.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/spanning_tree.pyx +1457 -0
- sage/graphs/strongly_regular_db.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/strongly_regular_db.pyx +3340 -0
- sage/graphs/traversals.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/traversals.pxd +9 -0
- sage/graphs/traversals.pyx +1872 -0
- sage/graphs/trees.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/trees.pxd +15 -0
- sage/graphs/trees.pyx +310 -0
- sage/graphs/tutte_polynomial.py +713 -0
- sage/graphs/views.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/views.pyx +794 -0
- sage/graphs/weakly_chordal.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/weakly_chordal.pyx +604 -0
- sage/groups/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
- sage/knots/all.py +6 -0
- sage/knots/free_knotinfo_monoid.py +507 -0
- sage/knots/gauss_code.py +291 -0
- sage/knots/knot.py +682 -0
- sage/knots/knot_table.py +284 -0
- sage/knots/knotinfo.py +2900 -0
- sage/knots/link.py +4715 -0
- sage/sandpiles/all.py +13 -0
- sage/sandpiles/examples.py +225 -0
- sage/sandpiles/sandpile.py +6365 -0
- sage/topology/all.py +22 -0
- sage/topology/cell_complex.py +1214 -0
- sage/topology/cubical_complex.py +1976 -0
- sage/topology/delta_complex.py +1806 -0
- sage/topology/filtered_simplicial_complex.py +744 -0
- sage/topology/moment_angle_complex.py +823 -0
- sage/topology/simplicial_complex.py +5160 -0
- sage/topology/simplicial_complex_catalog.py +92 -0
- sage/topology/simplicial_complex_examples.py +1680 -0
- sage/topology/simplicial_complex_homset.py +205 -0
- sage/topology/simplicial_complex_morphism.py +836 -0
- sage/topology/simplicial_set.py +4102 -0
- sage/topology/simplicial_set_catalog.py +55 -0
- sage/topology/simplicial_set_constructions.py +2954 -0
- sage/topology/simplicial_set_examples.py +865 -0
- sage/topology/simplicial_set_morphism.py +1464 -0
@@ -0,0 +1,923 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-graphs
|
2
|
+
r"""
|
3
|
+
Yang-Baxter Graphs
|
4
|
+
"""
|
5
|
+
# ****************************************************************************
|
6
|
+
# Copyright (C) 2009 Franco Saliola <saliola@gmail.com>
|
7
|
+
#
|
8
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
9
|
+
#
|
10
|
+
# This code is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
# General Public License for more details.
|
14
|
+
#
|
15
|
+
# The full text of the GPL is available at:
|
16
|
+
#
|
17
|
+
# https://www.gnu.org/licenses/
|
18
|
+
# ****************************************************************************
|
19
|
+
from copy import copy
|
20
|
+
|
21
|
+
from sage.graphs.digraph import DiGraph
|
22
|
+
from sage.structure.sage_object import SageObject
|
23
|
+
from sage.misc.lazy_attribute import lazy_attribute
|
24
|
+
from sage.misc.lazy_import import lazy_import
|
25
|
+
from sage.combinat.permutation import Permutation
|
26
|
+
|
27
|
+
lazy_import('sage.combinat.partition', 'Partition')
|
28
|
+
|
29
|
+
|
30
|
+
def YangBaxterGraph(partition=None, root=None, operators=None):
|
31
|
+
r"""
|
32
|
+
Construct the Yang-Baxter graph from ``root`` by repeated application of
|
33
|
+
``operators``, or the Yang-Baxter graph associated to ``partition``.
|
34
|
+
|
35
|
+
INPUT:
|
36
|
+
|
37
|
+
The user needs to provide either ``partition`` or both ``root`` and
|
38
|
+
``operators``, where
|
39
|
+
|
40
|
+
- ``partition`` -- a partition of a positive integer
|
41
|
+
|
42
|
+
- ``root`` -- the root vertex
|
43
|
+
|
44
|
+
- ``operator`` -- a function that maps vertices `u` to a list of
|
45
|
+
tuples of the form `(v, l)` where `v` is a successor of `u` and `l` is
|
46
|
+
the label of the edge from `u` to `v`.
|
47
|
+
|
48
|
+
OUTPUT: either:
|
49
|
+
|
50
|
+
- :class:`YangBaxterGraph_partition` -- if partition is defined
|
51
|
+
- :class:`YangBaxterGraph_generic` -- if partition is ``None``
|
52
|
+
|
53
|
+
EXAMPLES:
|
54
|
+
|
55
|
+
The Yang-Baxter graph defined by a partition `[p_1,\dots,p_k]` is
|
56
|
+
the labelled directed graph with vertex set obtained by
|
57
|
+
bubble-sorting `(p_k-1,p_k-2,\dots,0,\dots,p_1-1,p_1-2,\dots,0)`;
|
58
|
+
there is an arrow from `u` to `v` labelled by `i` if `v` is
|
59
|
+
obtained by swapping the `i`-th and `(i+1)`-th elements of `u`.
|
60
|
+
For example, if the partition is `[3,1]`, then we begin with
|
61
|
+
`(0,2,1,0)` and generate all tuples obtained from it by swapping
|
62
|
+
two adjacent entries if they are increasing::
|
63
|
+
|
64
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
65
|
+
sage: bubbleswaps = [SwapIncreasingOperator(i) for i in range(3)]
|
66
|
+
sage: Y = YangBaxterGraph(root=(0,2,1,0), operators=bubbleswaps); Y
|
67
|
+
Yang-Baxter graph with root vertex (0, 2, 1, 0)
|
68
|
+
sage: Y.vertices(sort=True)
|
69
|
+
[(0, 2, 1, 0), (2, 0, 1, 0), (2, 1, 0, 0)]
|
70
|
+
|
71
|
+
The ``partition`` keyword is a shorthand for the above construction::
|
72
|
+
|
73
|
+
sage: Y = YangBaxterGraph(partition=[3,1]); Y # needs sage.combinat
|
74
|
+
Yang-Baxter graph of [3, 1], with top vertex (0, 2, 1, 0)
|
75
|
+
sage: Y.vertices(sort=True)
|
76
|
+
[(0, 2, 1, 0), (2, 0, 1, 0), (2, 1, 0, 0)]
|
77
|
+
|
78
|
+
The permutahedron can be realized as a Yang-Baxter graph::
|
79
|
+
|
80
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
81
|
+
sage: swappers = [SwapIncreasingOperator(i) for i in range(3)]
|
82
|
+
sage: Y = YangBaxterGraph(root=(1,2,3,4), operators=swappers); Y
|
83
|
+
Yang-Baxter graph with root vertex (1, 2, 3, 4)
|
84
|
+
sage: Y.plot() # needs sage.plot
|
85
|
+
Graphics object consisting of 97 graphics primitives
|
86
|
+
|
87
|
+
The Cayley graph of a finite group can be realized as a Yang-Baxter graph::
|
88
|
+
|
89
|
+
sage: # needs sage.groups
|
90
|
+
sage: def left_multiplication_by(g):
|
91
|
+
....: return lambda h: h*g
|
92
|
+
sage: G = CyclicPermutationGroup(4)
|
93
|
+
sage: operators = [ left_multiplication_by(gen) for gen in G.gens() ]
|
94
|
+
sage: Y = YangBaxterGraph(root=G.identity(), operators=operators); Y
|
95
|
+
Yang-Baxter graph with root vertex ()
|
96
|
+
sage: Y.plot(edge_labels=False) # needs sage.plot
|
97
|
+
Graphics object consisting of 9 graphics primitives
|
98
|
+
|
99
|
+
sage: # needs sage.groups
|
100
|
+
sage: G = SymmetricGroup(4)
|
101
|
+
sage: operators = [left_multiplication_by(gen) for gen in G.gens()]
|
102
|
+
sage: Y = YangBaxterGraph(root=G.identity(), operators=operators); Y
|
103
|
+
Yang-Baxter graph with root vertex ()
|
104
|
+
sage: Y.plot(edge_labels=False) # needs sage.plot
|
105
|
+
Graphics object consisting of 96 graphics primitives
|
106
|
+
|
107
|
+
AUTHORS:
|
108
|
+
|
109
|
+
- Franco Saliola (2009-04-23)
|
110
|
+
"""
|
111
|
+
if partition is None:
|
112
|
+
return YangBaxterGraph_generic(root=root, operators=operators)
|
113
|
+
return YangBaxterGraph_partition(partition=Partition(partition))
|
114
|
+
|
115
|
+
# *********** General class for Yang-Baxter Graphs ***********
|
116
|
+
|
117
|
+
|
118
|
+
class YangBaxterGraph_generic(SageObject):
|
119
|
+
def __init__(self, root, operators):
|
120
|
+
r"""
|
121
|
+
A class to model the Yang-Baxter graph defined by ``root`` and
|
122
|
+
``operators``.
|
123
|
+
|
124
|
+
INPUT:
|
125
|
+
|
126
|
+
- ``root`` -- the root vertex of the graph
|
127
|
+
|
128
|
+
- ``operators`` -- list of callables that map vertices to (new)
|
129
|
+
vertices
|
130
|
+
|
131
|
+
.. NOTE::
|
132
|
+
|
133
|
+
This is a lazy implementation: the digraph is only computed
|
134
|
+
when it is needed.
|
135
|
+
|
136
|
+
EXAMPLES::
|
137
|
+
|
138
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
139
|
+
sage: ops = [SwapIncreasingOperator(i) for i in range(4)]
|
140
|
+
sage: Y = YangBaxterGraph(root=(1,0,2,1,0), operators=ops); Y
|
141
|
+
Yang-Baxter graph with root vertex (1, 0, 2, 1, 0)
|
142
|
+
sage: loads(dumps(Y)) == Y
|
143
|
+
True
|
144
|
+
|
145
|
+
AUTHORS:
|
146
|
+
|
147
|
+
- Franco Saliola (2009-04-23)
|
148
|
+
"""
|
149
|
+
self._root = root
|
150
|
+
self._operators = operators
|
151
|
+
|
152
|
+
def _successors(self, u):
|
153
|
+
r"""
|
154
|
+
Return an iterator of tuples for the form ``(op(u), op)``, where ``op``
|
155
|
+
is one of the operators defining ``self``.
|
156
|
+
|
157
|
+
EXAMPLES::
|
158
|
+
|
159
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
160
|
+
sage: ops = [SwapIncreasingOperator(i) for i in range(4)]
|
161
|
+
sage: Y = YangBaxterGraph(root=(1,0,2,1,0), operators=ops)
|
162
|
+
sage: list(Y._successors((1,0,2,1,0)))
|
163
|
+
[((1, 2, 0, 1, 0), Swap-if-increasing at position 1)]
|
164
|
+
"""
|
165
|
+
for op in self._operators:
|
166
|
+
v = op(u)
|
167
|
+
if v != u:
|
168
|
+
yield (v, op)
|
169
|
+
|
170
|
+
def __repr__(self) -> str:
|
171
|
+
r"""
|
172
|
+
EXAMPLES::
|
173
|
+
|
174
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
175
|
+
sage: ops = [SwapIncreasingOperator(i) for i in range(2)]
|
176
|
+
sage: Y = YangBaxterGraph(root=(1,2,3), operators=ops)
|
177
|
+
sage: Y.__repr__()
|
178
|
+
'Yang-Baxter graph with root vertex (1, 2, 3)'
|
179
|
+
"""
|
180
|
+
return f"Yang-Baxter graph with root vertex {self._root}"
|
181
|
+
|
182
|
+
@lazy_attribute
|
183
|
+
def _digraph(self):
|
184
|
+
r"""
|
185
|
+
Construct the underlying digraph and store the result as an
|
186
|
+
attribute.
|
187
|
+
|
188
|
+
EXAMPLES::
|
189
|
+
|
190
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
191
|
+
sage: ops = [SwapIncreasingOperator(i) for i in range(2)]
|
192
|
+
sage: Y = YangBaxterGraph(root=(1,2,3), operators=ops)
|
193
|
+
sage: Y._digraph
|
194
|
+
Digraph on 6 vertices
|
195
|
+
"""
|
196
|
+
digraph = DiGraph()
|
197
|
+
digraph.add_vertex(self._root)
|
198
|
+
queue = [self._root]
|
199
|
+
while queue:
|
200
|
+
u = queue.pop()
|
201
|
+
for v, l in self._successors(u):
|
202
|
+
if v not in digraph:
|
203
|
+
queue.append(v)
|
204
|
+
digraph.add_edge(u, v, l)
|
205
|
+
return digraph
|
206
|
+
|
207
|
+
def __hash__(self) -> int:
|
208
|
+
r"""
|
209
|
+
TESTS::
|
210
|
+
|
211
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
212
|
+
sage: ops = [SwapIncreasingOperator(i) for i in range(2)]
|
213
|
+
sage: Y = YangBaxterGraph(root=(1,2,3), operators=ops)
|
214
|
+
sage: H = hash(Y)
|
215
|
+
"""
|
216
|
+
# TODO: this is ugly but unavoidable: the Yang Baxter graphs are being
|
217
|
+
# used in containers but are mutable.
|
218
|
+
return hash(self._digraph.copy(immutable=True))
|
219
|
+
|
220
|
+
def __eq__(self, other) -> bool:
|
221
|
+
r"""
|
222
|
+
EXAMPLES::
|
223
|
+
|
224
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
225
|
+
sage: ops = [SwapIncreasingOperator(i) for i in range(4)]
|
226
|
+
sage: Y1 = YangBaxterGraph(root=(1,0,2,1,0), operators=ops)
|
227
|
+
sage: Y2 = YangBaxterGraph(root=(2,0,2,1,0), operators=ops)
|
228
|
+
sage: Y3 = YangBaxterGraph(root=(1,0,2,1,0), operators=ops)
|
229
|
+
sage: Y1.__eq__(Y2)
|
230
|
+
False
|
231
|
+
sage: Y2.__eq__(Y2)
|
232
|
+
True
|
233
|
+
sage: Y1.__eq__(Y1)
|
234
|
+
True
|
235
|
+
sage: Y3.__eq__(Y1)
|
236
|
+
True
|
237
|
+
sage: Y3.__eq__(Y2)
|
238
|
+
False
|
239
|
+
"""
|
240
|
+
return isinstance(other, YangBaxterGraph_generic) and self._digraph == other._digraph
|
241
|
+
|
242
|
+
def __ne__(self, other) -> bool:
|
243
|
+
r"""
|
244
|
+
Test non-equality.
|
245
|
+
|
246
|
+
EXAMPLES::
|
247
|
+
|
248
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
249
|
+
sage: ops = [SwapIncreasingOperator(i) for i in range(4)]
|
250
|
+
sage: Y1 = YangBaxterGraph(root=(1,0,2,1,0), operators=ops)
|
251
|
+
sage: Y2 = YangBaxterGraph(root=(2,0,2,1,0), operators=ops)
|
252
|
+
sage: Y3 = YangBaxterGraph(root=(1,0,2,1,0), operators=ops)
|
253
|
+
sage: Y1.__ne__(Y2)
|
254
|
+
True
|
255
|
+
sage: Y2.__ne__(Y2)
|
256
|
+
False
|
257
|
+
sage: Y1.__ne__(Y1)
|
258
|
+
False
|
259
|
+
sage: Y3.__ne__(Y1)
|
260
|
+
False
|
261
|
+
sage: Y3.__ne__(Y2)
|
262
|
+
True
|
263
|
+
"""
|
264
|
+
return not self == other
|
265
|
+
|
266
|
+
def __iter__(self):
|
267
|
+
r"""
|
268
|
+
Return an iterator of the vertices in ``self``.
|
269
|
+
|
270
|
+
EXAMPLES::
|
271
|
+
|
272
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
273
|
+
sage: ops = [SwapIncreasingOperator(i) for i in range(4)]
|
274
|
+
sage: Y = YangBaxterGraph(root=(1,0,2,1,0), operators=ops)
|
275
|
+
sage: sorted(set(Y))
|
276
|
+
[(1, 0, 2, 1, 0), (1, 2, 0, 1, 0), (1, 2, 1, 0, 0), (2, 1, 0, 1, 0), (2, 1, 1, 0, 0)]
|
277
|
+
"""
|
278
|
+
return self._digraph.vertex_iterator()
|
279
|
+
|
280
|
+
def __len__(self):
|
281
|
+
r"""
|
282
|
+
Return the number of vertices in ``self``.
|
283
|
+
|
284
|
+
EXAMPLES::
|
285
|
+
|
286
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
287
|
+
sage: ops = [SwapIncreasingOperator(i) for i in range(4)]
|
288
|
+
sage: Y = YangBaxterGraph(root=(1,0,2,1,0), operators=ops)
|
289
|
+
sage: Y.__len__()
|
290
|
+
5
|
291
|
+
sage: ops = [SwapIncreasingOperator(i) for i in range(5)]
|
292
|
+
sage: Y = YangBaxterGraph(root=(0,1,0,2,1,0), operators=ops)
|
293
|
+
sage: Y.__len__()
|
294
|
+
16
|
295
|
+
"""
|
296
|
+
return self._digraph.num_verts()
|
297
|
+
|
298
|
+
def __copy__(self):
|
299
|
+
r"""
|
300
|
+
Return a copy of ``self``.
|
301
|
+
|
302
|
+
EXAMPLES::
|
303
|
+
|
304
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
305
|
+
sage: ops = [SwapIncreasingOperator(i) for i in range(3)]
|
306
|
+
sage: Y = YangBaxterGraph(root=(1,0,2,1,0), operators=ops); Y
|
307
|
+
Yang-Baxter graph with root vertex (1, 0, 2, 1, 0)
|
308
|
+
sage: B = copy(Y); B
|
309
|
+
Yang-Baxter graph with root vertex (1, 0, 2, 1, 0)
|
310
|
+
sage: Y is B
|
311
|
+
False
|
312
|
+
sage: Y == B
|
313
|
+
True
|
314
|
+
"""
|
315
|
+
Y = self.__class__(self._root, self._operators)
|
316
|
+
Y._digraph = copy(self._digraph)
|
317
|
+
return Y
|
318
|
+
|
319
|
+
def _edges_in_bfs(self):
|
320
|
+
r"""
|
321
|
+
Return an iterator of the edges of the digraph traversed in a
|
322
|
+
breadth-first search of the vertices beginning at ``self.root()``.
|
323
|
+
|
324
|
+
EXAMPLES::
|
325
|
+
|
326
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
327
|
+
sage: ops = [SwapIncreasingOperator(i) for i in range(4)]
|
328
|
+
sage: Y = YangBaxterGraph(root=(1,0,2,1,0), operators=ops)
|
329
|
+
sage: list(Y._edges_in_bfs())
|
330
|
+
[((1, 0, 2, 1, 0), (1, 2, 0, 1, 0), Swap-if-increasing at position 1), ((1, 2, 0, 1, 0), (1, 2, 1, 0, 0), Swap-if-increasing at position 2), ((1, 2, 0, 1, 0), (2, 1, 0, 1, 0), Swap-if-increasing at position 0), ((2, 1, 0, 1, 0), (2, 1, 1, 0, 0), Swap-if-increasing at position 2)]
|
331
|
+
"""
|
332
|
+
digraph = self._digraph
|
333
|
+
seen = {}
|
334
|
+
queue = [self._root]
|
335
|
+
seen[self._root] = True
|
336
|
+
while queue:
|
337
|
+
u = queue.pop()
|
338
|
+
l = sorted(digraph.neighbor_out_iterator(u))
|
339
|
+
for w in l:
|
340
|
+
if w not in seen:
|
341
|
+
seen[w] = True
|
342
|
+
queue.append(w)
|
343
|
+
yield (u, w, digraph.edge_label(u, w))
|
344
|
+
|
345
|
+
def root(self):
|
346
|
+
r"""
|
347
|
+
Return the root vertex of ``self``.
|
348
|
+
|
349
|
+
If ``self`` is the Yang-Baxter graph of the partition
|
350
|
+
`[p_1,p_2,\dots,p_k]`, then this is the vertex
|
351
|
+
`(p_k-1,p_k-2,\dots,0,\dots,p_1-1,p_1-2,\dots,0)`.
|
352
|
+
|
353
|
+
EXAMPLES::
|
354
|
+
|
355
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
356
|
+
sage: ops = [SwapIncreasingOperator(i) for i in range(4)]
|
357
|
+
sage: Y = YangBaxterGraph(root=(1,0,2,1,0), operators=ops)
|
358
|
+
sage: Y.root()
|
359
|
+
(1, 0, 2, 1, 0)
|
360
|
+
sage: Y = YangBaxterGraph(root=(0,1,0,2,1,0), operators=ops)
|
361
|
+
sage: Y.root()
|
362
|
+
(0, 1, 0, 2, 1, 0)
|
363
|
+
sage: Y = YangBaxterGraph(root=(1,0,3,2,1,0), operators=ops)
|
364
|
+
sage: Y.root()
|
365
|
+
(1, 0, 3, 2, 1, 0)
|
366
|
+
sage: Y = YangBaxterGraph(partition=[3,2]) # needs sage.combinat
|
367
|
+
sage: Y.root() # needs sage.combinat
|
368
|
+
(1, 0, 2, 1, 0)
|
369
|
+
"""
|
370
|
+
return self._root
|
371
|
+
|
372
|
+
def successors(self, v) -> list:
|
373
|
+
r"""
|
374
|
+
Return the successors of the vertex ``v``.
|
375
|
+
|
376
|
+
EXAMPLES::
|
377
|
+
|
378
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
379
|
+
sage: ops = [SwapIncreasingOperator(i) for i in range(4)]
|
380
|
+
sage: Y = YangBaxterGraph(root=(1,0,2,1,0), operators=ops)
|
381
|
+
sage: Y.successors(Y.root())
|
382
|
+
[(1, 2, 0, 1, 0)]
|
383
|
+
sage: sorted(Y.successors((1, 2, 0, 1, 0)))
|
384
|
+
[(1, 2, 1, 0, 0), (2, 1, 0, 1, 0)]
|
385
|
+
"""
|
386
|
+
return [a for a, _ in self._successors(v)]
|
387
|
+
|
388
|
+
def plot(self, *args, **kwds):
|
389
|
+
r"""
|
390
|
+
Plot ``self`` as a digraph.
|
391
|
+
|
392
|
+
EXAMPLES::
|
393
|
+
|
394
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
395
|
+
sage: ops = [SwapIncreasingOperator(i) for i in range(4)]
|
396
|
+
sage: Y = YangBaxterGraph(root=(1,0,2,1,0), operators=ops)
|
397
|
+
sage: Y.plot() # needs sage.plot
|
398
|
+
Graphics object consisting of 16 graphics primitives
|
399
|
+
sage: Y.plot(edge_labels=False) # needs sage.plot
|
400
|
+
Graphics object consisting of 11 graphics primitives
|
401
|
+
"""
|
402
|
+
if "edge_labels" not in kwds:
|
403
|
+
kwds["edge_labels"] = True
|
404
|
+
if "vertex_labels" not in kwds:
|
405
|
+
kwds["vertex_labels"] = True
|
406
|
+
return self._digraph.plot(*args, **kwds)
|
407
|
+
|
408
|
+
def vertices(self, sort=False) -> list:
|
409
|
+
r"""
|
410
|
+
Return the vertices of ``self``.
|
411
|
+
|
412
|
+
INPUT:
|
413
|
+
|
414
|
+
- ``sort`` -- boolean (default: ``False``); whether to sort the vertices
|
415
|
+
|
416
|
+
EXAMPLES::
|
417
|
+
|
418
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
419
|
+
sage: ops = [SwapIncreasingOperator(i) for i in range(3)]
|
420
|
+
sage: Y = YangBaxterGraph(root=(0,2,1,0), operators=ops)
|
421
|
+
sage: Y.vertices(sort=True)
|
422
|
+
[(0, 2, 1, 0), (2, 0, 1, 0), (2, 1, 0, 0)]
|
423
|
+
"""
|
424
|
+
return sorted(self) if sort else list(self)
|
425
|
+
|
426
|
+
def edges(self):
|
427
|
+
r"""
|
428
|
+
Return the (labelled) edges of ``self``.
|
429
|
+
|
430
|
+
EXAMPLES::
|
431
|
+
|
432
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
433
|
+
sage: ops = [SwapIncreasingOperator(i) for i in range(3)]
|
434
|
+
sage: Y = YangBaxterGraph(root=(0,2,1,0), operators=ops)
|
435
|
+
sage: Y.edges()
|
436
|
+
[((0, 2, 1, 0), (2, 0, 1, 0), Swap-if-increasing at position 0), ((2, 0, 1, 0), (2, 1, 0, 0), Swap-if-increasing at position 1)]
|
437
|
+
"""
|
438
|
+
return self._digraph.edges(sort=True)
|
439
|
+
|
440
|
+
def vertex_relabelling_dict(self, v, relabel_operator) -> dict:
|
441
|
+
r"""
|
442
|
+
Return a dictionary pairing vertices ``u`` of ``self`` with
|
443
|
+
the object obtained from ``v`` by applying the
|
444
|
+
``relabel_operator`` along a path from the root to ``u``.
|
445
|
+
|
446
|
+
Note that the root is paired with ``v``.
|
447
|
+
|
448
|
+
INPUT:
|
449
|
+
|
450
|
+
- ``v`` -- an object
|
451
|
+
|
452
|
+
- ``relabel_operator`` -- function mapping a vertex and a label to
|
453
|
+
the image of the vertex
|
454
|
+
|
455
|
+
OUTPUT: dictionary pairing vertices with the corresponding image of ``v``
|
456
|
+
|
457
|
+
EXAMPLES::
|
458
|
+
|
459
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
460
|
+
sage: ops = [SwapIncreasingOperator(i) for i in range(3)]
|
461
|
+
sage: Y = YangBaxterGraph(root=(0,2,1,0), operators=ops)
|
462
|
+
sage: def relabel_operator(op, u):
|
463
|
+
....: i = op.position()
|
464
|
+
....: return u[:i] + u[i:i+2][::-1] + u[i+2:]
|
465
|
+
sage: Y.vertex_relabelling_dict((1,2,3,4), relabel_operator)
|
466
|
+
{(0, 2, 1, 0): (1, 2, 3, 4),
|
467
|
+
(2, 0, 1, 0): (2, 1, 3, 4),
|
468
|
+
(2, 1, 0, 0): (2, 3, 1, 4)}
|
469
|
+
"""
|
470
|
+
relabelling = {self._root: v}
|
471
|
+
for u, w, i in self._edges_in_bfs():
|
472
|
+
relabelling[w] = relabel_operator(i, relabelling[u])
|
473
|
+
return relabelling
|
474
|
+
|
475
|
+
def relabel_vertices(self, v, relabel_operator, inplace=True):
|
476
|
+
r"""
|
477
|
+
Relabel the vertices ``u`` of ``self`` by the object obtained
|
478
|
+
from ``u`` by applying the ``relabel_operator`` to ``v`` along
|
479
|
+
a path from ``self.root()`` to ``u``.
|
480
|
+
|
481
|
+
Note that the ``self.root()`` is paired with ``v``.
|
482
|
+
|
483
|
+
INPUT:
|
484
|
+
|
485
|
+
- ``v`` -- tuple, Permutation, etc.
|
486
|
+
|
487
|
+
- ``inplace`` -- if ``True``, modifies ``self``; otherwise returns a
|
488
|
+
modified copy of ``self``
|
489
|
+
|
490
|
+
EXAMPLES::
|
491
|
+
|
492
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
493
|
+
sage: ops = [SwapIncreasingOperator(i) for i in range(3)]
|
494
|
+
sage: Y = YangBaxterGraph(root=(0,2,1,0), operators=ops)
|
495
|
+
sage: def relabel_op(op, u):
|
496
|
+
....: i = op.position()
|
497
|
+
....: return u[:i] + u[i:i+2][::-1] + u[i+2:]
|
498
|
+
sage: d = Y.relabel_vertices((1,2,3,4), relabel_op, inplace=False); d
|
499
|
+
Yang-Baxter graph with root vertex (1, 2, 3, 4)
|
500
|
+
sage: Y.vertices(sort=True)
|
501
|
+
[(0, 2, 1, 0), (2, 0, 1, 0), (2, 1, 0, 0)]
|
502
|
+
sage: e = Y.relabel_vertices((1,2,3,4), relabel_op); e
|
503
|
+
sage: Y.vertices(sort=True)
|
504
|
+
[(1, 2, 3, 4), (2, 1, 3, 4), (2, 3, 1, 4)]
|
505
|
+
"""
|
506
|
+
relabelling = self.vertex_relabelling_dict(v, relabel_operator)
|
507
|
+
Y = self if inplace else copy(self)
|
508
|
+
Y._root = relabelling[Y._root]
|
509
|
+
Y._digraph.relabel(relabelling, inplace=True)
|
510
|
+
if inplace is False:
|
511
|
+
return Y
|
512
|
+
|
513
|
+
def relabel_edges(self, edge_dict, inplace=True):
|
514
|
+
r"""
|
515
|
+
Relabel the edges of ``self``.
|
516
|
+
|
517
|
+
INPUT:
|
518
|
+
|
519
|
+
- ``edge_dict`` -- dictionary keyed by the (unlabelled) edges
|
520
|
+
|
521
|
+
EXAMPLES::
|
522
|
+
|
523
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
524
|
+
sage: ops = [SwapIncreasingOperator(i) for i in range(3)]
|
525
|
+
sage: Y = YangBaxterGraph(root=(0,2,1,0), operators=ops)
|
526
|
+
sage: def relabel_op(op, u):
|
527
|
+
....: i = op.position()
|
528
|
+
....: return u[:i] + u[i:i+2][::-1] + u[i+2:]
|
529
|
+
sage: Y.edges()
|
530
|
+
[((0, 2, 1, 0), (2, 0, 1, 0), Swap-if-increasing at position 0), ((2, 0, 1, 0), (2, 1, 0, 0), Swap-if-increasing at position 1)]
|
531
|
+
sage: d = {((0,2,1,0),(2,0,1,0)):17, ((2,0,1,0),(2,1,0,0)):27}
|
532
|
+
sage: Y.relabel_edges(d, inplace=False).edges()
|
533
|
+
[((0, 2, 1, 0), (2, 0, 1, 0), 17), ((2, 0, 1, 0), (2, 1, 0, 0), 27)]
|
534
|
+
sage: Y.edges()
|
535
|
+
[((0, 2, 1, 0), (2, 0, 1, 0), Swap-if-increasing at position 0), ((2, 0, 1, 0), (2, 1, 0, 0), Swap-if-increasing at position 1)]
|
536
|
+
sage: Y.relabel_edges(d, inplace=True)
|
537
|
+
sage: Y.edges()
|
538
|
+
[((0, 2, 1, 0), (2, 0, 1, 0), 17), ((2, 0, 1, 0), (2, 1, 0, 0), 27)]
|
539
|
+
"""
|
540
|
+
Y = self if inplace else copy(self)
|
541
|
+
digraph = Y._digraph
|
542
|
+
for u, v in digraph.edges(sort=False, labels=False):
|
543
|
+
digraph.set_edge_label(u, v, edge_dict[u, v])
|
544
|
+
if not inplace:
|
545
|
+
return Y
|
546
|
+
|
547
|
+
|
548
|
+
# *********** Yang-Baxter Graphs defined by a partition ***********
|
549
|
+
|
550
|
+
class YangBaxterGraph_partition(YangBaxterGraph_generic):
|
551
|
+
def __init__(self, partition):
|
552
|
+
r"""
|
553
|
+
A class to model the Yang-Baxter graph of a partition.
|
554
|
+
|
555
|
+
The Yang-Baxter graph defined by a partition `[p_1,\dots,p_k]`
|
556
|
+
is the labelled directed graph with vertex set obtained by
|
557
|
+
bubble-sorting `(p_k-1,p_k-2,\dots,0,\dots,p_1-1,p_1-2,\dots,0)`;
|
558
|
+
there is an arrow from `u` to `v` labelled by `i` if `v` is
|
559
|
+
obtained by swapping the `i`-th and `(i+1)`-th elements of `u`.
|
560
|
+
|
561
|
+
.. NOTE::
|
562
|
+
|
563
|
+
This is a lazy implementation: the digraph is only computed
|
564
|
+
when it is needed.
|
565
|
+
|
566
|
+
EXAMPLES::
|
567
|
+
|
568
|
+
sage: Y = YangBaxterGraph(partition=[3,2,1]); Y # needs sage.combinat
|
569
|
+
Yang-Baxter graph of [3, 2, 1], with top vertex (0, 1, 0, 2, 1, 0)
|
570
|
+
sage: loads(dumps(Y)) == Y # needs sage.combinat
|
571
|
+
True
|
572
|
+
|
573
|
+
AUTHORS:
|
574
|
+
|
575
|
+
- Franco Saliola (2009-04-23)
|
576
|
+
"""
|
577
|
+
self._partition = partition
|
578
|
+
beta = sorted(self._partition, reverse=True)
|
579
|
+
root = sum((tuple(range(b)) for b in beta), ())[::-1]
|
580
|
+
operators = [SwapIncreasingOperator(i)
|
581
|
+
for i in range(sum(partition) - 1)]
|
582
|
+
super().__init__(root, operators)
|
583
|
+
|
584
|
+
def __repr__(self) -> str:
|
585
|
+
r"""
|
586
|
+
EXAMPLES::
|
587
|
+
|
588
|
+
sage: Y = YangBaxterGraph(partition=[3,2]) # needs sage.combinat
|
589
|
+
sage: Y.__repr__() # needs sage.combinat
|
590
|
+
'Yang-Baxter graph of [3, 2], with top vertex (1, 0, 2, 1, 0)'
|
591
|
+
"""
|
592
|
+
return f"Yang-Baxter graph of {self._partition}, with top vertex {self._root}"
|
593
|
+
|
594
|
+
def __copy__(self):
|
595
|
+
r"""
|
596
|
+
Return a copy of ``self``.
|
597
|
+
|
598
|
+
EXAMPLES::
|
599
|
+
|
600
|
+
sage: # needs sage.combinat
|
601
|
+
sage: Y = YangBaxterGraph(partition=[3,2]); Y
|
602
|
+
Yang-Baxter graph of [3, 2], with top vertex (1, 0, 2, 1, 0)
|
603
|
+
sage: B = copy(Y); B
|
604
|
+
Yang-Baxter graph of [3, 2], with top vertex (1, 0, 2, 1, 0)
|
605
|
+
sage: Y is B
|
606
|
+
False
|
607
|
+
sage: Y == B
|
608
|
+
True
|
609
|
+
"""
|
610
|
+
Y = self.__class__(self._partition)
|
611
|
+
Y._digraph = copy(self._digraph)
|
612
|
+
return Y
|
613
|
+
|
614
|
+
@lazy_attribute
|
615
|
+
def _digraph(self):
|
616
|
+
r"""
|
617
|
+
Construct the underlying digraph and store the result as an
|
618
|
+
attribute.
|
619
|
+
|
620
|
+
EXAMPLES::
|
621
|
+
|
622
|
+
sage: Y = YangBaxterGraph(partition=[2,1]) # needs sage.combinat
|
623
|
+
sage: Y._digraph # needs sage.combinat
|
624
|
+
Digraph on 2 vertices
|
625
|
+
sage: Y.edges() # needs sage.combinat
|
626
|
+
[((0, 1, 0), (1, 0, 0), Swap positions 0 and 1)]
|
627
|
+
"""
|
628
|
+
digraph = super()._digraph
|
629
|
+
for u, v, op in digraph.edges():
|
630
|
+
digraph.set_edge_label(u, v, SwapOperator(op.position()))
|
631
|
+
return digraph
|
632
|
+
|
633
|
+
@lazy_attribute
|
634
|
+
def _vertex_ordering(self):
|
635
|
+
r"""
|
636
|
+
Return a list of the vertices of ``self``, sorted using
|
637
|
+
Python's ``sorted`` method.
|
638
|
+
|
639
|
+
EXAMPLES::
|
640
|
+
|
641
|
+
sage: Y = YangBaxterGraph(partition=[3,2]) # needs sage.combinat
|
642
|
+
sage: Y._vertex_ordering # needs sage.combinat
|
643
|
+
[(1, 0, 2, 1, 0), (1, 2, 0, 1, 0), (1, 2, 1, 0, 0), (2, 1, 0, 1, 0), (2, 1, 1, 0, 0)]
|
644
|
+
"""
|
645
|
+
return self._digraph.vertices(sort=True)
|
646
|
+
|
647
|
+
def __iter__(self):
|
648
|
+
r"""
|
649
|
+
Iterate over the vertices ``self``.
|
650
|
+
|
651
|
+
.. NOTE::
|
652
|
+
|
653
|
+
The vertices are first sorted using Python's ``sorted`` command.
|
654
|
+
|
655
|
+
EXAMPLES::
|
656
|
+
|
657
|
+
sage: Y = YangBaxterGraph(partition=[3,2]) # needs sage.combinat
|
658
|
+
sage: list(Y.__iter__()) # needs sage.combinat
|
659
|
+
[(1, 0, 2, 1, 0), (1, 2, 0, 1, 0), (1, 2, 1, 0, 0), (2, 1, 0, 1, 0), (2, 1, 1, 0, 0)]
|
660
|
+
"""
|
661
|
+
yield from self._vertex_ordering
|
662
|
+
|
663
|
+
def _swap_operator(self, operator, u):
|
664
|
+
r"""
|
665
|
+
Return the image of ``u`` under ``operator``.
|
666
|
+
|
667
|
+
INPUT:
|
668
|
+
|
669
|
+
- ``i`` -- positive integer between ``1`` and ``len(u)-1``, inclusive
|
670
|
+
|
671
|
+
- ``u`` -- tuple, list, permutation, etc.
|
672
|
+
|
673
|
+
EXAMPLES::
|
674
|
+
|
675
|
+
sage: # needs sage.combinat
|
676
|
+
sage: Y = YangBaxterGraph(partition=[3,1])
|
677
|
+
sage: from sage.combinat.yang_baxter_graph import SwapOperator
|
678
|
+
sage: ops = [SwapOperator(i) for i in range(3)]
|
679
|
+
sage: [Y._swap_operator(op, (1,2,3,4)) for op in ops]
|
680
|
+
[(2, 1, 3, 4), (1, 3, 2, 4), (1, 2, 4, 3)]
|
681
|
+
sage: [Y._swap_operator(op, [4,3,2,1]) for op in ops]
|
682
|
+
[[3, 4, 2, 1], [4, 2, 3, 1], [4, 3, 1, 2]]
|
683
|
+
sage: [Y._swap_operator(op, Permutation([1,2,3,4])) for op in ops]
|
684
|
+
[[2, 1, 3, 4], [1, 3, 2, 4], [1, 2, 4, 3]]
|
685
|
+
"""
|
686
|
+
return operator(u)
|
687
|
+
|
688
|
+
def vertex_relabelling_dict(self, v) -> dict:
|
689
|
+
r"""
|
690
|
+
Return a dictionary pairing vertices ``u`` of ``self`` with the object
|
691
|
+
obtained from ``v`` by applying transpositions corresponding to the
|
692
|
+
edges labels along a path from the root to ``u``.
|
693
|
+
|
694
|
+
Note that the root is paired with ``v``.
|
695
|
+
|
696
|
+
INPUT:
|
697
|
+
|
698
|
+
- ``v`` -- an object
|
699
|
+
|
700
|
+
OUTPUT: dictionary pairing vertices with the corresponding image of ``v``
|
701
|
+
|
702
|
+
EXAMPLES::
|
703
|
+
|
704
|
+
sage: Y = YangBaxterGraph(partition=[3,1]) # needs sage.combinat
|
705
|
+
sage: Y.vertex_relabelling_dict((1,2,3,4)) # needs sage.combinat
|
706
|
+
{(0, 2, 1, 0): (1, 2, 3, 4),
|
707
|
+
(2, 0, 1, 0): (2, 1, 3, 4),
|
708
|
+
(2, 1, 0, 0): (2, 3, 1, 4)}
|
709
|
+
sage: Y.vertex_relabelling_dict((4,3,2,1)) # needs sage.combinat
|
710
|
+
{(0, 2, 1, 0): (4, 3, 2, 1),
|
711
|
+
(2, 0, 1, 0): (3, 4, 2, 1),
|
712
|
+
(2, 1, 0, 0): (3, 2, 4, 1)}
|
713
|
+
"""
|
714
|
+
return super().vertex_relabelling_dict(v, self._swap_operator)
|
715
|
+
|
716
|
+
def relabel_vertices(self, v, inplace=True):
|
717
|
+
r"""
|
718
|
+
Relabel the vertices of ``self`` with the object obtained from
|
719
|
+
``v`` by applying the transpositions corresponding to the edge
|
720
|
+
labels along some path from the root to the vertex.
|
721
|
+
|
722
|
+
INPUT:
|
723
|
+
|
724
|
+
- ``v`` -- tuple, Permutation, etc.
|
725
|
+
|
726
|
+
- ``inplace`` -- if ``True``, modifies ``self``; otherwise
|
727
|
+
returns a modified copy of ``self``
|
728
|
+
|
729
|
+
EXAMPLES::
|
730
|
+
|
731
|
+
sage: # needs sage.combinat
|
732
|
+
sage: Y = YangBaxterGraph(partition=[3,1]); Y
|
733
|
+
Yang-Baxter graph of [3, 1], with top vertex (0, 2, 1, 0)
|
734
|
+
sage: d = Y.relabel_vertices((1,2,3,4), inplace=False); d
|
735
|
+
Digraph on 3 vertices
|
736
|
+
sage: Y.vertices(sort=True)
|
737
|
+
[(0, 2, 1, 0), (2, 0, 1, 0), (2, 1, 0, 0)]
|
738
|
+
sage: e = Y.relabel_vertices((1,2,3,4)); e
|
739
|
+
sage: Y.vertices(sort=True)
|
740
|
+
[(1, 2, 3, 4), (2, 1, 3, 4), (2, 3, 1, 4)]
|
741
|
+
"""
|
742
|
+
relabelling = self.vertex_relabelling_dict(v)
|
743
|
+
if inplace:
|
744
|
+
Y = self
|
745
|
+
Y._root = relabelling[Y._root]
|
746
|
+
Y._digraph.relabel(relabelling, inplace=inplace)
|
747
|
+
Y._vertex_ordering = Y._digraph.vertices(sort=True)
|
748
|
+
return
|
749
|
+
|
750
|
+
Y = copy(self)
|
751
|
+
Y._root = relabelling[Y._root]
|
752
|
+
return Y._digraph.relabel(relabelling, inplace=inplace)
|
753
|
+
|
754
|
+
# ------------- Some Yang-Baxter operators ------------------
|
755
|
+
|
756
|
+
|
757
|
+
class SwapOperator(SageObject):
|
758
|
+
def __init__(self, i):
|
759
|
+
r"""
|
760
|
+
The operator that swaps the items in positions ``i`` and ``i+1``.
|
761
|
+
|
762
|
+
EXAMPLES::
|
763
|
+
|
764
|
+
sage: from sage.combinat.yang_baxter_graph import SwapOperator
|
765
|
+
sage: s3 = SwapOperator(3)
|
766
|
+
sage: s3 == loads(dumps(s3))
|
767
|
+
True
|
768
|
+
"""
|
769
|
+
self._position = i
|
770
|
+
|
771
|
+
def __hash__(self) -> int:
|
772
|
+
r"""
|
773
|
+
TESTS::
|
774
|
+
|
775
|
+
sage: from sage.combinat.yang_baxter_graph import SwapOperator
|
776
|
+
sage: s = [SwapOperator(i) for i in range(3)]
|
777
|
+
sage: [hash(t) for t in s]
|
778
|
+
[0, 1, 2]
|
779
|
+
"""
|
780
|
+
return hash(self._position)
|
781
|
+
|
782
|
+
def __eq__(self, other) -> bool:
|
783
|
+
r"""
|
784
|
+
Compare two swap operators.
|
785
|
+
|
786
|
+
The comparison is done by comparing the positions.
|
787
|
+
|
788
|
+
EXAMPLES::
|
789
|
+
|
790
|
+
sage: from sage.combinat.yang_baxter_graph import SwapOperator
|
791
|
+
sage: s = [SwapOperator(i) for i in range(3)]
|
792
|
+
sage: s[0] == s[0]
|
793
|
+
True
|
794
|
+
sage: s[1] == s[0]
|
795
|
+
False
|
796
|
+
"""
|
797
|
+
if not isinstance(other, SwapOperator):
|
798
|
+
return False
|
799
|
+
return self._position == other._position
|
800
|
+
|
801
|
+
def __ne__(self, other) -> bool:
|
802
|
+
"""
|
803
|
+
Check whether ``self`` is not equal to ``other``.
|
804
|
+
|
805
|
+
EXAMPLES::
|
806
|
+
|
807
|
+
sage: from sage.combinat.yang_baxter_graph import SwapOperator
|
808
|
+
sage: s = [SwapOperator(i) for i in range(3)]
|
809
|
+
sage: s[0] != s[0]
|
810
|
+
False
|
811
|
+
sage: s[1] != s[0]
|
812
|
+
True
|
813
|
+
"""
|
814
|
+
return not (self == other)
|
815
|
+
|
816
|
+
def __repr__(self) -> str:
|
817
|
+
r"""
|
818
|
+
Representation string.
|
819
|
+
|
820
|
+
EXAMPLES::
|
821
|
+
|
822
|
+
sage: from sage.combinat.yang_baxter_graph import SwapOperator
|
823
|
+
sage: s3 = SwapOperator(3)
|
824
|
+
sage: s3.__repr__()
|
825
|
+
'Swap positions 3 and 4'
|
826
|
+
"""
|
827
|
+
pos = self._position
|
828
|
+
return f"Swap positions {pos} and {pos + 1}"
|
829
|
+
|
830
|
+
def __str__(self) -> str:
|
831
|
+
r"""
|
832
|
+
A short str representation (used, for example, in labelling edges of
|
833
|
+
graphs).
|
834
|
+
|
835
|
+
EXAMPLES::
|
836
|
+
|
837
|
+
sage: from sage.combinat.yang_baxter_graph import SwapOperator
|
838
|
+
sage: s3 = SwapOperator(3)
|
839
|
+
sage: s3.__str__()
|
840
|
+
'3'
|
841
|
+
"""
|
842
|
+
return "%s" % self._position
|
843
|
+
|
844
|
+
def __call__(self, u):
|
845
|
+
r"""
|
846
|
+
Return the object obtained from swapping the items in positions
|
847
|
+
``i`` and ``i+1`` of ``u``.
|
848
|
+
|
849
|
+
EXAMPLES::
|
850
|
+
|
851
|
+
sage: from sage.combinat.yang_baxter_graph import SwapOperator
|
852
|
+
sage: s3 = SwapOperator(3)
|
853
|
+
sage: s3((1,2,3,4,5))
|
854
|
+
(1, 2, 3, 5, 4)
|
855
|
+
sage: s3([1,2,3,4,5])
|
856
|
+
[1, 2, 3, 5, 4]
|
857
|
+
"""
|
858
|
+
i = self._position
|
859
|
+
if isinstance(u, Permutation):
|
860
|
+
return Permutation(u[:i] + u[i:i + 2][::-1] + u[i + 2:])
|
861
|
+
return type(u)(u[:i] + u[i:i + 2][::-1] + u[i + 2:])
|
862
|
+
|
863
|
+
def position(self):
|
864
|
+
r"""
|
865
|
+
Return ``i`` where ``self`` is the operator that swaps positions ``i``
|
866
|
+
and ``i+1``.
|
867
|
+
|
868
|
+
EXAMPLES::
|
869
|
+
|
870
|
+
sage: from sage.combinat.yang_baxter_graph import SwapOperator
|
871
|
+
sage: s3 = SwapOperator(3)
|
872
|
+
sage: s3.position()
|
873
|
+
3
|
874
|
+
"""
|
875
|
+
return self._position
|
876
|
+
|
877
|
+
|
878
|
+
class SwapIncreasingOperator(SwapOperator):
|
879
|
+
def __repr__(self) -> str:
|
880
|
+
r"""
|
881
|
+
Representation string.
|
882
|
+
|
883
|
+
EXAMPLES::
|
884
|
+
|
885
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
886
|
+
sage: s3 = SwapIncreasingOperator(3)
|
887
|
+
sage: s3.__repr__()
|
888
|
+
'Swap-if-increasing at position 3'
|
889
|
+
"""
|
890
|
+
return "Swap-if-increasing at position %s" % self._position
|
891
|
+
|
892
|
+
def __call__(self, u):
|
893
|
+
r"""
|
894
|
+
Return a copy of ``u`` with ``u[i-1]`` and ``u[i]`` swapped if
|
895
|
+
``u[i-1] > u[i]``; otherwise returns ``u``.
|
896
|
+
|
897
|
+
INPUT:
|
898
|
+
|
899
|
+
- ``i`` -- positive integer between ``1`` and ``len(u)-1``, inclusive
|
900
|
+
|
901
|
+
- ``u`` -- tuple, list, permutation, etc.
|
902
|
+
|
903
|
+
EXAMPLES::
|
904
|
+
|
905
|
+
sage: Y = YangBaxterGraph(partition=[2,2]) # needs sage.combinat
|
906
|
+
sage: from sage.combinat.yang_baxter_graph import SwapIncreasingOperator
|
907
|
+
sage: operators = [SwapIncreasingOperator(i) for i in range(3)]
|
908
|
+
sage: [op((1,2,3,4)) for op in operators]
|
909
|
+
[(2, 1, 3, 4), (1, 3, 2, 4), (1, 2, 4, 3)]
|
910
|
+
sage: [op([4,3,2,1]) for op in operators]
|
911
|
+
[[4, 3, 2, 1], [4, 3, 2, 1], [4, 3, 2, 1]]
|
912
|
+
sage: [op(Permutation([1,3,2,4])) for op in operators]
|
913
|
+
[[3, 1, 2, 4], [1, 3, 2, 4], [1, 3, 4, 2]]
|
914
|
+
"""
|
915
|
+
i = self._position
|
916
|
+
j = i + 1
|
917
|
+
if u[i] < u[j]:
|
918
|
+
v = list(u)
|
919
|
+
v[j], v[i] = v[i], v[j]
|
920
|
+
if isinstance(u, Permutation):
|
921
|
+
return Permutation(v)
|
922
|
+
return type(u)(v)
|
923
|
+
return u
|