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
sage/graphs/isgci.py
ADDED
@@ -0,0 +1,1033 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-graphs
|
2
|
+
# sage.doctest: needs database_graphs
|
3
|
+
r"""
|
4
|
+
ISGCI: Information System on Graph Classes and their Inclusions
|
5
|
+
|
6
|
+
This module implements an interface to the
|
7
|
+
`ISGCI <http://www.graphclasses.org/>`_ database in Sage.
|
8
|
+
|
9
|
+
This database gathers information on graph classes and their inclusions in each
|
10
|
+
other. It also contains information on the complexity of several computational
|
11
|
+
problems.
|
12
|
+
|
13
|
+
It is available on the `GraphClasses.org <http://www.graphclasses.org/>`_
|
14
|
+
website maintained by H.N. de Ridder et al.
|
15
|
+
|
16
|
+
How to use it?
|
17
|
+
--------------
|
18
|
+
|
19
|
+
Presently, it is possible to use this database through the variables and methods
|
20
|
+
present in the :obj:`graph_classes <GraphClasses>` object.
|
21
|
+
For instance::
|
22
|
+
|
23
|
+
sage: Trees = graph_classes.Tree
|
24
|
+
sage: Chordal = graph_classes.Chordal
|
25
|
+
|
26
|
+
Inclusions
|
27
|
+
^^^^^^^^^^
|
28
|
+
|
29
|
+
It is then possible to check the inclusion of classes inside of others, if the
|
30
|
+
information is available in the database::
|
31
|
+
|
32
|
+
sage: Trees <= Chordal
|
33
|
+
True
|
34
|
+
|
35
|
+
And indeed, trees are chordal graphs.
|
36
|
+
|
37
|
+
The ISGCI database is not all-knowing, and so comparing two classes can return
|
38
|
+
``True``, ``False``, or ``Unknown`` (see the :mod:`documentation of the Unknown
|
39
|
+
truth value <sage.misc.unknown>`).
|
40
|
+
|
41
|
+
An *unknown* answer to ``A <= B`` only means that ISGCI cannot deduce from the
|
42
|
+
information in its database that ``A`` is a subclass of ``B`` nor that it is
|
43
|
+
not. For instance, ISGCI does not know at the moment that some chordal graphs
|
44
|
+
are not trees::
|
45
|
+
|
46
|
+
sage: graph_classes.Chordal <= graph_classes.Tree
|
47
|
+
Unknown
|
48
|
+
|
49
|
+
Descriptions
|
50
|
+
^^^^^^^^^^^^
|
51
|
+
|
52
|
+
Given a graph class, one can obtain its associated information in the ISGCI
|
53
|
+
database with the :meth:`~GraphClass.description` method::
|
54
|
+
|
55
|
+
sage: Chordal.description()
|
56
|
+
Class of graphs : Chordal
|
57
|
+
-------------------------
|
58
|
+
id : gc_32
|
59
|
+
name : chordal
|
60
|
+
...
|
61
|
+
Problems :
|
62
|
+
-----------
|
63
|
+
3-Colourability : Linear
|
64
|
+
Clique : Polynomial
|
65
|
+
Clique cover : Polynomial
|
66
|
+
...
|
67
|
+
|
68
|
+
It is possible to obtain the complete list of the classes stored in ISGCI by
|
69
|
+
calling the :meth:`~GraphClasses.show_all` method (beware -- long output)::
|
70
|
+
|
71
|
+
sage: graph_classes.show_all()
|
72
|
+
id | name | type | smallgraph
|
73
|
+
----------------------------------------------------------------------------------------------------------------------
|
74
|
+
gc_309 | $K_4$--minor--free | base |
|
75
|
+
gc_541 | $N^*$ | base |
|
76
|
+
gc_215 | $N^*$--perfect | base |
|
77
|
+
gc_5 | $P_4$--bipartite | base |
|
78
|
+
gc_3 | $P_4$--brittle | base |
|
79
|
+
gc_6 | $P_4$--comparability | base |
|
80
|
+
gc_7 | $P_4$--extendible | base |
|
81
|
+
...
|
82
|
+
|
83
|
+
Until a proper search method is implemented, this lets one find classes which do
|
84
|
+
not appear in :obj:`graph_classes.* <GraphClasses>`.
|
85
|
+
|
86
|
+
To retrieve a class of graph from its ISGCI ID one may use
|
87
|
+
the :meth:`~GraphClasses.get_class` method::
|
88
|
+
|
89
|
+
sage: GC = graph_classes.get_class("gc_5")
|
90
|
+
sage: GC
|
91
|
+
$P_4$--bipartite graphs
|
92
|
+
|
93
|
+
Recognition of graphs
|
94
|
+
^^^^^^^^^^^^^^^^^^^^^
|
95
|
+
|
96
|
+
The graph classes represented by the ISGCI database can alternatively be used to
|
97
|
+
access recognition algorithms. For instance, in order to check that a given
|
98
|
+
graph is a tree one has the following the options ::
|
99
|
+
|
100
|
+
sage: graphs.PathGraph(5) in graph_classes.Tree
|
101
|
+
True
|
102
|
+
|
103
|
+
or::
|
104
|
+
|
105
|
+
sage: graphs.PathGraph(5).is_tree()
|
106
|
+
True
|
107
|
+
|
108
|
+
Furthermore, all ISGCI graph classes which are defined by the exclusion of a
|
109
|
+
finite sequence of induced subgraphs benefit from a generic recognition
|
110
|
+
algorithm. For instance ::
|
111
|
+
|
112
|
+
sage: g = graphs.PetersenGraph()
|
113
|
+
sage: g in graph_classes.ClawFree
|
114
|
+
False
|
115
|
+
sage: g.line_graph() in graph_classes.ClawFree
|
116
|
+
True
|
117
|
+
|
118
|
+
Or directly from ISGCI ::
|
119
|
+
|
120
|
+
sage: gc = graph_classes.get_class("gc_441")
|
121
|
+
sage: gc
|
122
|
+
diamond--free graphs
|
123
|
+
sage: graphs.PetersenGraph() in gc
|
124
|
+
True
|
125
|
+
|
126
|
+
Predefined classes
|
127
|
+
------------------
|
128
|
+
|
129
|
+
:obj:`graph_classes <GraphClasses>` currently predefines the following graph classes
|
130
|
+
|
131
|
+
.. list-table::
|
132
|
+
:widths: 20 30
|
133
|
+
:header-rows: 1
|
134
|
+
|
135
|
+
* - Class
|
136
|
+
- Related methods
|
137
|
+
|
138
|
+
* - Apex
|
139
|
+
|
140
|
+
- :meth:`~sage.graphs.graph.Graph.is_apex`,
|
141
|
+
:meth:`~sage.graphs.graph.Graph.apex_vertices`
|
142
|
+
|
143
|
+
* - AT_free
|
144
|
+
|
145
|
+
- :meth:`~sage.graphs.graph.Graph.is_asteroidal_triple_free`
|
146
|
+
|
147
|
+
* - Biconnected
|
148
|
+
|
149
|
+
- :meth:`~sage.graphs.graph.Graph.is_biconnected`,
|
150
|
+
:meth:`~sage.graphs.generic_graph.GenericGraph.blocks_and_cut_vertices`,
|
151
|
+
:meth:`~sage.graphs.generic_graph.GenericGraph.blocks_and_cuts_tree`
|
152
|
+
|
153
|
+
* - BinaryTrees
|
154
|
+
|
155
|
+
- :meth:`~sage.graphs.graph_generators.GraphGenerators.BalancedTree`,
|
156
|
+
:meth:`~sage.graphs.graph.Graph.is_tree`
|
157
|
+
|
158
|
+
* - Bipartite
|
159
|
+
|
160
|
+
- :meth:`~sage.graphs.graph_generators.GraphGenerators.BalancedTree`,
|
161
|
+
:meth:`~sage.graphs.generic_graph.GenericGraph.is_bipartite`
|
162
|
+
|
163
|
+
* - Block
|
164
|
+
|
165
|
+
- :meth:`~sage.graphs.graph.Graph.is_block_graph`,
|
166
|
+
:meth:`~sage.graphs.generic_graph.GenericGraph.blocks_and_cut_vertices`,
|
167
|
+
:meth:`~sage.graphs.graph_generators.GraphGenerators.RandomBlockGraph`
|
168
|
+
|
169
|
+
* - Chordal
|
170
|
+
|
171
|
+
- :meth:`~sage.graphs.generic_graph.GenericGraph.is_chordal`
|
172
|
+
|
173
|
+
* - Claw-Free
|
174
|
+
- :meth:`~sage.graphs.graph_generators.GraphGenerators.ClawGraph`
|
175
|
+
|
176
|
+
* - Comparability
|
177
|
+
-
|
178
|
+
|
179
|
+
* - Gallai
|
180
|
+
|
181
|
+
- :meth:`~sage.graphs.generic_graph.GenericGraph.is_gallai_tree`
|
182
|
+
|
183
|
+
* - Grid
|
184
|
+
|
185
|
+
- :meth:`~sage.graphs.graph_generators.GraphGenerators.Grid2dGraph`,
|
186
|
+
:meth:`~sage.graphs.graph_generators.GraphGenerators.GridGraph`
|
187
|
+
|
188
|
+
* - Interval
|
189
|
+
|
190
|
+
- :meth:`~sage.graphs.graph_generators.GraphGenerators.RandomIntervalGraph`,
|
191
|
+
:meth:`~sage.graphs.graph_generators.GraphGenerators.IntervalGraph`,
|
192
|
+
:meth:`~sage.graphs.generic_graph.GenericGraph.is_interval`
|
193
|
+
|
194
|
+
* - Line
|
195
|
+
|
196
|
+
- :meth:`~sage.graphs.graph_generators.GraphGenerators.line_graph_forbidden_subgraphs`,
|
197
|
+
:meth:`~sage.graphs.graph.Graph.is_line_graph`
|
198
|
+
|
199
|
+
* - Modular
|
200
|
+
|
201
|
+
- :meth:`~sage.graphs.graph.Graph.modular_decomposition`
|
202
|
+
|
203
|
+
* - Outerplanar
|
204
|
+
|
205
|
+
- :meth:`~sage.graphs.generic_graph.GenericGraph.is_circular_planar`
|
206
|
+
|
207
|
+
* - Perfect
|
208
|
+
|
209
|
+
- :meth:`~sage.graphs.graph.Graph.is_perfect`
|
210
|
+
|
211
|
+
* - Planar
|
212
|
+
|
213
|
+
- :meth:`~sage.graphs.generic_graph.GenericGraph.is_planar`
|
214
|
+
|
215
|
+
* - Polyhedral
|
216
|
+
|
217
|
+
- :meth:`~sage.graphs.graph.Graph.is_polyhedral`
|
218
|
+
|
219
|
+
* - Split
|
220
|
+
|
221
|
+
- :meth:`~sage.graphs.graph.Graph.is_split`
|
222
|
+
|
223
|
+
* - Tree
|
224
|
+
|
225
|
+
- :meth:`~sage.graphs.graph_generators.GraphGenerators.trees`,
|
226
|
+
:meth:`~Graph.is_tree`
|
227
|
+
|
228
|
+
* - UnitDisk
|
229
|
+
- :meth:`~sage.graphs.graph_generators.GraphGenerators.IntervalGraph`
|
230
|
+
|
231
|
+
* - UnitInterval
|
232
|
+
- :meth:`~sage.graphs.generic_graph.GenericGraph.is_interval`
|
233
|
+
|
234
|
+
Sage's view of ISGCI
|
235
|
+
--------------------
|
236
|
+
|
237
|
+
The database is stored by Sage in two ways.
|
238
|
+
|
239
|
+
**The classes**: the list of all graph classes and their properties is stored
|
240
|
+
in a huge dictionary (see :meth:`~sage.graphs.isgci.GraphClasses.classes`).
|
241
|
+
Below is what Sage knows of ``gc_249``::
|
242
|
+
|
243
|
+
sage: graph_classes.classes()['gc_249'] # random
|
244
|
+
{'problem':
|
245
|
+
{'Independent set': 'Polynomial',
|
246
|
+
'Treewidth': 'Unknown',
|
247
|
+
'Weighted independent set': 'Polynomial',
|
248
|
+
'Cliquewidth expression': 'NP-complete',
|
249
|
+
'Weighted clique': 'Polynomial',
|
250
|
+
'Clique cover': 'Unknown',
|
251
|
+
'Domination': 'NP-complete',
|
252
|
+
'Clique': 'Polynomial',
|
253
|
+
'Colourability': 'NP-complete',
|
254
|
+
'Cliquewidth': 'Unbounded',
|
255
|
+
'3-Colourability': 'NP-complete',
|
256
|
+
'Recognition': 'Linear'},
|
257
|
+
'type': 'base',
|
258
|
+
'id': 'gc_249',
|
259
|
+
'name': 'line'}
|
260
|
+
|
261
|
+
**The class inclusion digraph**: Sage remembers the class inclusions through
|
262
|
+
the inclusion digraph (see :meth:`~sage.graphs.isgci.GraphClasses.inclusion_digraph`).
|
263
|
+
Its nodes are ID of ISGCI classes::
|
264
|
+
|
265
|
+
sage: d = graph_classes.inclusion_digraph()
|
266
|
+
sage: d.vertices(sort=True)[-10:]
|
267
|
+
['gc_990', 'gc_991', 'gc_992', 'gc_993', 'gc_994', 'gc_995', 'gc_996', 'gc_997', 'gc_998', 'gc_999']
|
268
|
+
|
269
|
+
An arc from ``gc1`` to ``gc2`` means that ``gc1`` is a superclass of ``gc2``.
|
270
|
+
This being said, not all edges are stored ! To ensure that a given class is
|
271
|
+
included in another one, we have to check whether there is in the digraph a
|
272
|
+
``path`` from the first one to the other::
|
273
|
+
|
274
|
+
sage: bip_id = graph_classes.Bipartite._gc_id
|
275
|
+
sage: perfect_id = graph_classes.Perfect._gc_id
|
276
|
+
sage: d.has_edge(perfect_id, bip_id)
|
277
|
+
False
|
278
|
+
sage: d.distance(perfect_id, bip_id)
|
279
|
+
2
|
280
|
+
|
281
|
+
Hence bipartite graphs are perfect graphs. We can see how ISGCI obtains this
|
282
|
+
result ::
|
283
|
+
|
284
|
+
sage: p = d.shortest_path(perfect_id, bip_id)
|
285
|
+
sage: len(p) - 1
|
286
|
+
2
|
287
|
+
sage: print(p) # random
|
288
|
+
['gc_56', 'gc_76', 'gc_69']
|
289
|
+
sage: for c in p:
|
290
|
+
....: print(graph_classes.get_class(c))
|
291
|
+
perfect graphs
|
292
|
+
...
|
293
|
+
bipartite graphs
|
294
|
+
|
295
|
+
What ISGCI knows is that perfect graphs contain unimodular graph which contain
|
296
|
+
bipartite graphs. Therefore bipartite graphs are perfect !
|
297
|
+
|
298
|
+
.. NOTE::
|
299
|
+
|
300
|
+
The inclusion digraph is **NOT ACYCLIC**. Indeed, several entries exist in
|
301
|
+
the ISGCI database which represent the same graph class, for instance
|
302
|
+
Perfect graphs and Berge graphs::
|
303
|
+
|
304
|
+
sage: graph_classes.inclusion_digraph().is_directed_acyclic()
|
305
|
+
False
|
306
|
+
sage: Berge = graph_classes.get_class("gc_274"); Berge
|
307
|
+
Berge graphs
|
308
|
+
sage: Perfect = graph_classes.get_class("gc_56"); Perfect
|
309
|
+
perfect graphs
|
310
|
+
sage: Berge <= Perfect
|
311
|
+
True
|
312
|
+
sage: Perfect <= Berge
|
313
|
+
True
|
314
|
+
sage: Perfect == Berge
|
315
|
+
True
|
316
|
+
|
317
|
+
Information for developers
|
318
|
+
--------------------------
|
319
|
+
|
320
|
+
* The database is loaded not *so* large, but it is still preferable to
|
321
|
+
only load it on demand. This is achieved through the cached methods
|
322
|
+
:meth:`~sage.graphs.isgci.GraphClasses.classes` and
|
323
|
+
:meth:`~sage.graphs.isgci.GraphClasses.inclusion_digraph`.
|
324
|
+
|
325
|
+
* Upon the first access to the database, the information is extracted
|
326
|
+
from the XML file and stored in the cache of three methods:
|
327
|
+
|
328
|
+
* ``sage.graphs.isgci._classes`` (dictionary)
|
329
|
+
* ``sage.graphs.isgci._inclusions`` (list of dictionaries)
|
330
|
+
* ``sage.graphs.isgci._inclusion_digraph`` (DiGraph)
|
331
|
+
|
332
|
+
Note that the digraph is only built if necessary (for instance if
|
333
|
+
the user tries to compare two classes).
|
334
|
+
|
335
|
+
.. TODO::
|
336
|
+
|
337
|
+
Technical things:
|
338
|
+
|
339
|
+
* Query the database for non-inclusion results so that comparisons can
|
340
|
+
return ``False``, and implement strict inclusions.
|
341
|
+
|
342
|
+
* Implement a proper search method for the classes not listed in
|
343
|
+
:obj:`graph_classes <GraphClasses>`
|
344
|
+
|
345
|
+
.. SEEALSO:: :func:`sage.graphs.isgci.show_all`.
|
346
|
+
|
347
|
+
* Some of the graph classes appearing in :obj:`graph_classes
|
348
|
+
<GraphClasses>` already have a recognition
|
349
|
+
algorithm implemented in Sage. It would be so nice to be able to
|
350
|
+
write ``g in Trees``, ``g in Perfect``, ``g in Chordal``, ... :-)
|
351
|
+
|
352
|
+
Long-term stuff:
|
353
|
+
|
354
|
+
* Implement simple accessors for all the information in the ISGCI
|
355
|
+
database (as can be done from the website)
|
356
|
+
|
357
|
+
* Implement intersection of graph classes
|
358
|
+
|
359
|
+
* Write generic recognition algorithms for specific classes (when a graph
|
360
|
+
class is defined by the exclusion of subgraphs, one can write a generic
|
361
|
+
algorithm checking the existence of each of the graphs, and this method
|
362
|
+
already exists in Sage).
|
363
|
+
|
364
|
+
* Improve the performance of Sage's graph library by letting it take
|
365
|
+
advantage of the properties of graph classes. For example,
|
366
|
+
:meth:`Graph.independent_set` could use the library to detect that a given
|
367
|
+
graph is, say, a tree or a planar graph, and use a specialized algorithm
|
368
|
+
for finding an independent set.
|
369
|
+
|
370
|
+
AUTHORS:
|
371
|
+
--------
|
372
|
+
|
373
|
+
* H.N. de Ridder et al. (ISGCI database)
|
374
|
+
* Nathann Cohen (Sage implementation)
|
375
|
+
|
376
|
+
Methods
|
377
|
+
-------
|
378
|
+
"""
|
379
|
+
|
380
|
+
from sage.structure.sage_object import SageObject
|
381
|
+
from sage.structure.unique_representation import CachedRepresentation, UniqueRepresentation
|
382
|
+
from sage.misc.unknown import Unknown
|
383
|
+
from sage.features.databases import DatabaseGraphs
|
384
|
+
from sage.misc.cachefunc import cached_method
|
385
|
+
|
386
|
+
import os
|
387
|
+
import zipfile
|
388
|
+
from urllib.request import urlopen
|
389
|
+
from ssl import create_default_context as default_context
|
390
|
+
|
391
|
+
# ****************************************************************************
|
392
|
+
# Copyright (C) 2011 Nathann Cohen <nathann.cohen@gmail.com>
|
393
|
+
#
|
394
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
395
|
+
# https://www.gnu.org/licenses/
|
396
|
+
# ****************************************************************************
|
397
|
+
|
398
|
+
_XML_FILE = "isgci_sage.xml"
|
399
|
+
_SMALLGRAPHS_FILE = "smallgraphs.txt"
|
400
|
+
|
401
|
+
|
402
|
+
class GraphClass(SageObject, CachedRepresentation):
|
403
|
+
r"""
|
404
|
+
An instance of this class represents a Graph Class, matching some entry in
|
405
|
+
the ISGCI database.
|
406
|
+
|
407
|
+
EXAMPLES:
|
408
|
+
|
409
|
+
Testing the inclusion of two classes::
|
410
|
+
|
411
|
+
sage: Chordal = graph_classes.Chordal
|
412
|
+
sage: Trees = graph_classes.Tree
|
413
|
+
sage: Trees <= Chordal
|
414
|
+
True
|
415
|
+
sage: Chordal <= Trees
|
416
|
+
Unknown
|
417
|
+
|
418
|
+
TESTS::
|
419
|
+
|
420
|
+
sage: Trees >= Chordal
|
421
|
+
Unknown
|
422
|
+
sage: Chordal >= Trees
|
423
|
+
True
|
424
|
+
"""
|
425
|
+
def __init__(self, name, gc_id, recognition_function=None):
|
426
|
+
r"""
|
427
|
+
Class constructor.
|
428
|
+
|
429
|
+
INPUT:
|
430
|
+
|
431
|
+
- ``gc_id`` -- the ISGCI class ID
|
432
|
+
|
433
|
+
- ``recognition_function`` -- a function of one argument `g`, which
|
434
|
+
return boolean answers to the question : *does ``g`` belong to the
|
435
|
+
class represented by ``gc_id`` ?*
|
436
|
+
|
437
|
+
EXAMPLES::
|
438
|
+
|
439
|
+
sage: graph_classes.Chordal # indirect doctest
|
440
|
+
Chordal graphs
|
441
|
+
"""
|
442
|
+
self._name = name
|
443
|
+
self._gc_id = gc_id
|
444
|
+
|
445
|
+
if recognition_function is not None:
|
446
|
+
self._recognition_function = recognition_function
|
447
|
+
|
448
|
+
def _repr_(self):
|
449
|
+
r"""
|
450
|
+
Return a short description of the class.
|
451
|
+
|
452
|
+
EXAMPLES::
|
453
|
+
|
454
|
+
sage: graph_classes.Chordal # indirect doctest
|
455
|
+
Chordal graphs
|
456
|
+
"""
|
457
|
+
return self._name + " graphs"
|
458
|
+
|
459
|
+
def __hash__(self):
|
460
|
+
r"""
|
461
|
+
Return the class' ID hash.
|
462
|
+
|
463
|
+
EXAMPLES::
|
464
|
+
|
465
|
+
sage: hash(graph_classes.Chordal) == hash(graph_classes.Chordal)
|
466
|
+
True
|
467
|
+
"""
|
468
|
+
return hash(self._gc_id)
|
469
|
+
|
470
|
+
def __le__(self, other):
|
471
|
+
r"""
|
472
|
+
<= operator.
|
473
|
+
|
474
|
+
EXAMPLES::
|
475
|
+
|
476
|
+
sage: graph_classes.Chordal <= graph_classes.Tree
|
477
|
+
Unknown
|
478
|
+
"""
|
479
|
+
return other >= self
|
480
|
+
|
481
|
+
def __ge__(self, other):
|
482
|
+
r"""
|
483
|
+
>= operator.
|
484
|
+
|
485
|
+
EXAMPLES::
|
486
|
+
|
487
|
+
sage: graph_classes.Chordal >= graph_classes.Tree
|
488
|
+
True
|
489
|
+
"""
|
490
|
+
inclusion_digraph = GraphClasses().inclusion_digraph()
|
491
|
+
if inclusion_digraph.shortest_path(self._gc_id, other._gc_id):
|
492
|
+
return True
|
493
|
+
else:
|
494
|
+
return Unknown
|
495
|
+
|
496
|
+
def __eq__(self, other):
|
497
|
+
r"""
|
498
|
+
== operator.
|
499
|
+
|
500
|
+
EXAMPLES::
|
501
|
+
|
502
|
+
sage: graph_classes.Chordal == graph_classes.Tree
|
503
|
+
Unknown
|
504
|
+
"""
|
505
|
+
return self >= other >= self
|
506
|
+
|
507
|
+
def __lt__(self, other):
|
508
|
+
r"""
|
509
|
+
>, !=, and < operators.
|
510
|
+
|
511
|
+
EXAMPLES::
|
512
|
+
|
513
|
+
sage: graph_classes.Chordal > graph_classes.Tree
|
514
|
+
Traceback (most recent call last):
|
515
|
+
...
|
516
|
+
NotImplementedError
|
517
|
+
sage: graph_classes.Chordal < graph_classes.Tree
|
518
|
+
Traceback (most recent call last):
|
519
|
+
...
|
520
|
+
NotImplementedError
|
521
|
+
sage: graph_classes.Chordal != graph_classes.Tree
|
522
|
+
Traceback (most recent call last):
|
523
|
+
...
|
524
|
+
NotImplementedError
|
525
|
+
"""
|
526
|
+
raise NotImplementedError
|
527
|
+
|
528
|
+
__gt__ = __ne__ = __lt__
|
529
|
+
|
530
|
+
def forbidden_subgraphs(self):
|
531
|
+
r"""
|
532
|
+
Return the list of forbidden induced subgraphs defining the class.
|
533
|
+
|
534
|
+
If the graph class is not defined by a *finite* list of forbidden
|
535
|
+
induced subgraphs, ``None`` is returned instead.
|
536
|
+
|
537
|
+
EXAMPLES::
|
538
|
+
|
539
|
+
sage: graph_classes.Perfect.forbidden_subgraphs()
|
540
|
+
sage: gc = graph_classes.get_class('gc_62')
|
541
|
+
sage: gc
|
542
|
+
claw--free graphs
|
543
|
+
sage: gc.forbidden_subgraphs()
|
544
|
+
[Graph on 4 vertices]
|
545
|
+
sage: gc.forbidden_subgraphs()[0].is_isomorphic(graphs.ClawGraph())
|
546
|
+
True
|
547
|
+
"""
|
548
|
+
classes = GraphClasses().classes()
|
549
|
+
gc = classes[self._gc_id]
|
550
|
+
|
551
|
+
if gc.get("type", None) != "forbidden":
|
552
|
+
return None
|
553
|
+
|
554
|
+
excluded = gc.get("smallgraph", None)
|
555
|
+
|
556
|
+
if not excluded:
|
557
|
+
return None
|
558
|
+
|
559
|
+
if not isinstance(excluded, list):
|
560
|
+
excluded = [excluded]
|
561
|
+
|
562
|
+
smallgraphs = GraphClasses().smallgraphs()
|
563
|
+
|
564
|
+
if not all(g in smallgraphs for g in excluded):
|
565
|
+
return None
|
566
|
+
|
567
|
+
return [smallgraphs[g] for g in excluded]
|
568
|
+
|
569
|
+
def __contains__(self, g):
|
570
|
+
r"""
|
571
|
+
Check if ``g`` belongs to the graph class represented by ``self``.
|
572
|
+
|
573
|
+
EXAMPLES::
|
574
|
+
|
575
|
+
sage: graphs.CompleteBipartiteGraph(3,3) in graph_classes.Bipartite
|
576
|
+
True
|
577
|
+
sage: graphs.CompleteGraph(4) in graph_classes.Chordal
|
578
|
+
True
|
579
|
+
sage: graphs.CompleteGraph(4) in graph_classes.Comparability
|
580
|
+
True
|
581
|
+
sage: graphs.CompleteGraph(4) in graph_classes.Interval
|
582
|
+
True
|
583
|
+
sage: graphs.CompleteGraph(4) in graph_classes.Line
|
584
|
+
True
|
585
|
+
sage: graphs.CompleteGraph(4) in graph_classes.Perfect
|
586
|
+
True
|
587
|
+
sage: graphs.CompleteGraph(4) in graph_classes.Planar # needs planarity
|
588
|
+
True
|
589
|
+
sage: graphs.CompleteGraph(4) in graph_classes.Split
|
590
|
+
True
|
591
|
+
sage: graphs.PathGraph(4) in graph_classes.Tree
|
592
|
+
True
|
593
|
+
"""
|
594
|
+
from sage.graphs.graph import Graph
|
595
|
+
|
596
|
+
if not isinstance(g, Graph):
|
597
|
+
return False
|
598
|
+
|
599
|
+
if hasattr(self, "_recognition_function"):
|
600
|
+
return self._recognition_function(g)
|
601
|
+
|
602
|
+
excluded = self.forbidden_subgraphs()
|
603
|
+
|
604
|
+
if excluded is None:
|
605
|
+
raise NotImplementedError("No recognition algorithm is available "
|
606
|
+
"for this class.")
|
607
|
+
|
608
|
+
for gg in excluded:
|
609
|
+
if g.subgraph_search(gg, induced=True):
|
610
|
+
return False
|
611
|
+
|
612
|
+
return True
|
613
|
+
|
614
|
+
def description(self):
|
615
|
+
r"""
|
616
|
+
Print the information of ISGCI about the current class.
|
617
|
+
|
618
|
+
EXAMPLES::
|
619
|
+
|
620
|
+
sage: graph_classes.Chordal.description()
|
621
|
+
Class of graphs : Chordal
|
622
|
+
-------------------------
|
623
|
+
id : gc_32
|
624
|
+
name : chordal
|
625
|
+
...
|
626
|
+
Problems :
|
627
|
+
-----------
|
628
|
+
3-Colourability : Linear
|
629
|
+
Clique : Polynomial
|
630
|
+
Clique cover : Polynomial
|
631
|
+
...
|
632
|
+
Recognition : Linear
|
633
|
+
...
|
634
|
+
"""
|
635
|
+
classes = GraphClasses().classes()
|
636
|
+
cls = classes[self._gc_id]
|
637
|
+
|
638
|
+
print("Class of graphs : " + self._name)
|
639
|
+
print("-" * (len(self._name) + 18))
|
640
|
+
|
641
|
+
for key, value in sorted(cls.items()):
|
642
|
+
if value != "" and key != "problem":
|
643
|
+
print("{:30} : {}".format(key, value))
|
644
|
+
|
645
|
+
print("\nProblems :")
|
646
|
+
print("-" * 11)
|
647
|
+
|
648
|
+
for pbname, data in sorted(cls["problem"].items()):
|
649
|
+
if "complexity" in data:
|
650
|
+
print("{:30} : {}".format(pbname, data["complexity"]))
|
651
|
+
|
652
|
+
|
653
|
+
class GraphClasses(UniqueRepresentation):
|
654
|
+
def get_class(self, id):
|
655
|
+
r"""
|
656
|
+
Return the class corresponding to the given id in the ISGCI database.
|
657
|
+
|
658
|
+
INPUT:
|
659
|
+
|
660
|
+
- ``id`` -- string; the desired class' ID
|
661
|
+
|
662
|
+
.. SEEALSO::
|
663
|
+
|
664
|
+
:meth:`~sage.graphs.isgci.GraphClasses.show_all`
|
665
|
+
|
666
|
+
EXAMPLES:
|
667
|
+
|
668
|
+
With an existing id::
|
669
|
+
|
670
|
+
sage: Cographs = graph_classes.get_class("gc_151")
|
671
|
+
sage: Cographs
|
672
|
+
cograph graphs
|
673
|
+
|
674
|
+
With a wrong id::
|
675
|
+
|
676
|
+
sage: graph_classes.get_class(-1)
|
677
|
+
Traceback (most recent call last):
|
678
|
+
...
|
679
|
+
ValueError: The given class id does not exist in the ISGCI database. Is the db too old ? You can update it with graph_classes.update_db().
|
680
|
+
"""
|
681
|
+
classes = self.classes()
|
682
|
+
if id in classes:
|
683
|
+
c = classes[id]
|
684
|
+
|
685
|
+
if c.get("name", ""):
|
686
|
+
name = c["name"]
|
687
|
+
else:
|
688
|
+
name = "class " + str(id)
|
689
|
+
|
690
|
+
return GraphClass(name, id)
|
691
|
+
else:
|
692
|
+
raise ValueError("The given class id does not exist in the ISGCI "
|
693
|
+
"database. Is the db too old ? You can update it "
|
694
|
+
"with graph_classes.update_db().")
|
695
|
+
|
696
|
+
@cached_method
|
697
|
+
def classes(self):
|
698
|
+
r"""
|
699
|
+
Return the graph classes, as a dictionary.
|
700
|
+
|
701
|
+
Upon the first call, this loads the database from the local XML
|
702
|
+
file. Subsequent calls are cached.
|
703
|
+
|
704
|
+
EXAMPLES::
|
705
|
+
|
706
|
+
sage: t = graph_classes.classes()
|
707
|
+
sage: type(t)
|
708
|
+
<... 'dict'>
|
709
|
+
sage: sorted(t["gc_151"].keys())
|
710
|
+
['id', 'name',... 'problem',... 'type']
|
711
|
+
sage: t["gc_151"]['name']
|
712
|
+
'cograph'
|
713
|
+
sage: t["gc_151"]['problem']['Clique']
|
714
|
+
{'complexity': 'Linear'}
|
715
|
+
"""
|
716
|
+
self._get_ISGCI()
|
717
|
+
return self.classes()
|
718
|
+
|
719
|
+
@cached_method
|
720
|
+
def inclusions(self):
|
721
|
+
r"""
|
722
|
+
Return the graph class inclusions.
|
723
|
+
|
724
|
+
OUTPUT: list of dictionaries
|
725
|
+
|
726
|
+
Upon the first call, this loads the database from the local XML file.
|
727
|
+
Subsequent calls are cached.
|
728
|
+
|
729
|
+
EXAMPLES::
|
730
|
+
|
731
|
+
sage: t = graph_classes.inclusions()
|
732
|
+
sage: type(t)
|
733
|
+
<... 'list'>
|
734
|
+
sage: t[0]
|
735
|
+
{'sub': 'gc_1', 'super': 'gc_2'}
|
736
|
+
"""
|
737
|
+
self._get_ISGCI()
|
738
|
+
return self.inclusions()
|
739
|
+
|
740
|
+
@cached_method
|
741
|
+
def smallgraphs(self):
|
742
|
+
r"""
|
743
|
+
Return a dictionary associating a graph to a graph description string.
|
744
|
+
|
745
|
+
Upon the first call, this loads the database from the local XML files.
|
746
|
+
Subsequent calls are cached.
|
747
|
+
|
748
|
+
EXAMPLES::
|
749
|
+
|
750
|
+
sage: t = graph_classes.smallgraphs()
|
751
|
+
sage: t['2C_4']
|
752
|
+
Graph on 8 vertices
|
753
|
+
sage: t['2K_3 + e']
|
754
|
+
Graph on 6 vertices
|
755
|
+
sage: t['fish']
|
756
|
+
Graph on 6 vertices
|
757
|
+
sage: t['bull']
|
758
|
+
Graph on 5 vertices
|
759
|
+
"""
|
760
|
+
self._get_ISGCI()
|
761
|
+
return self.smallgraphs()
|
762
|
+
|
763
|
+
@cached_method
|
764
|
+
def inclusion_digraph(self):
|
765
|
+
r"""
|
766
|
+
Return the class inclusion digraph.
|
767
|
+
|
768
|
+
Upon the first call, this loads the database from the local XML file.
|
769
|
+
Subsequent calls are cached.
|
770
|
+
|
771
|
+
EXAMPLES::
|
772
|
+
|
773
|
+
sage: g = graph_classes.inclusion_digraph(); g
|
774
|
+
Digraph on ... vertices
|
775
|
+
"""
|
776
|
+
classes = self.classes()
|
777
|
+
inclusions = self.inclusions()
|
778
|
+
|
779
|
+
from sage.graphs.digraph import DiGraph
|
780
|
+
inclusion_digraph = DiGraph()
|
781
|
+
inclusion_digraph.add_vertices(classes.keys())
|
782
|
+
|
783
|
+
for edge in inclusions:
|
784
|
+
if edge.get("confidence", "") == "unpublished":
|
785
|
+
continue
|
786
|
+
inclusion_digraph.add_edge(edge['super'], edge['sub'])
|
787
|
+
|
788
|
+
return inclusion_digraph
|
789
|
+
|
790
|
+
def _download_db(self):
|
791
|
+
r"""
|
792
|
+
Download the current version of the ISGCI db.
|
793
|
+
|
794
|
+
EXAMPLES::
|
795
|
+
|
796
|
+
sage: graph_classes._download_db() # optional - internet
|
797
|
+
"""
|
798
|
+
import tempfile
|
799
|
+
data_dir = os.path.dirname(DatabaseGraphs().absolute_filename())
|
800
|
+
u = urlopen('https://www.graphclasses.org/data.zip',
|
801
|
+
context=default_context())
|
802
|
+
with tempfile.NamedTemporaryFile(suffix='.zip') as f:
|
803
|
+
f.write(u.read())
|
804
|
+
z = zipfile.ZipFile(f.name)
|
805
|
+
|
806
|
+
# Save a systemwide updated copy whenever possible
|
807
|
+
try:
|
808
|
+
z.extract(_XML_FILE, data_dir)
|
809
|
+
z.extract(_SMALLGRAPHS_FILE, data_dir)
|
810
|
+
except OSError:
|
811
|
+
pass
|
812
|
+
|
813
|
+
def _parse_db(self):
|
814
|
+
r"""
|
815
|
+
Parse the ISGCI database and stores its content in ``self``.
|
816
|
+
|
817
|
+
EXAMPLES::
|
818
|
+
|
819
|
+
sage: graph_classes._parse_db()
|
820
|
+
"""
|
821
|
+
import xml.etree.ElementTree as ET
|
822
|
+
from sage.graphs.graph import Graph
|
823
|
+
|
824
|
+
data_dir = os.path.dirname(DatabaseGraphs().absolute_filename())
|
825
|
+
xml_file = os.path.join(data_dir, _XML_FILE)
|
826
|
+
tree = ET.ElementTree(file=xml_file)
|
827
|
+
root = tree.getroot()
|
828
|
+
DB = _XML_to_dict(root)
|
829
|
+
|
830
|
+
classes = {c['id']: c for c in DB['GraphClasses']["GraphClass"]}
|
831
|
+
for c in classes.values():
|
832
|
+
c["problem"] = {pb.pop("name"): pb for pb in c["problem"]}
|
833
|
+
|
834
|
+
inclusions = DB['Inclusions']['incl']
|
835
|
+
|
836
|
+
# Parses the list of ISGCI small graphs
|
837
|
+
smallgraph_file = open(os.path.join(data_dir, _SMALLGRAPHS_FILE))
|
838
|
+
smallgraphs = {}
|
839
|
+
|
840
|
+
for line in smallgraph_file.readlines():
|
841
|
+
key, string = line.split("\t")
|
842
|
+
smallgraphs[key] = Graph(string)
|
843
|
+
|
844
|
+
smallgraph_file.close()
|
845
|
+
|
846
|
+
self.inclusions.set_cache(inclusions)
|
847
|
+
self.classes.set_cache(classes)
|
848
|
+
self.smallgraphs.set_cache(smallgraphs)
|
849
|
+
|
850
|
+
def update_db(self):
|
851
|
+
r"""
|
852
|
+
Update the ISGCI database by downloading the latest version from
|
853
|
+
internet.
|
854
|
+
|
855
|
+
This method downloads the ISGCI database from the website
|
856
|
+
`GraphClasses.org <http://www.graphclasses.org/>`_. It then extracts the
|
857
|
+
zip file and parses its XML content. The XML file is saved in the directory
|
858
|
+
controlled by the :class:`DatabaseGraphs` class (usually, ``$HOME/.sage/db``).
|
859
|
+
|
860
|
+
EXAMPLES::
|
861
|
+
|
862
|
+
sage: graph_classes.update_db() # optional - internet
|
863
|
+
Database downloaded
|
864
|
+
"""
|
865
|
+
self._download_db()
|
866
|
+
|
867
|
+
print("Database downloaded")
|
868
|
+
|
869
|
+
self.classes.clear_cache()
|
870
|
+
self.inclusions.clear_cache()
|
871
|
+
self.inclusion_digraph.clear_cache()
|
872
|
+
|
873
|
+
def _get_ISGCI(self):
|
874
|
+
r"""
|
875
|
+
Return the contents of the ISGCI database.
|
876
|
+
|
877
|
+
This method is mostly for internal use, but often provides useful
|
878
|
+
information during debugging operations.
|
879
|
+
|
880
|
+
OUTPUT:
|
881
|
+
|
882
|
+
A pair ``(classes, inclusions)`` where ``classes`` is a dict of dict,
|
883
|
+
and ``inclusions`` is a list of dicts.
|
884
|
+
|
885
|
+
.. NOTE::
|
886
|
+
|
887
|
+
This method returns the data contained in the most recent ISGCI
|
888
|
+
database present on the computer. See :meth:`update_db` to update
|
889
|
+
the latter.
|
890
|
+
|
891
|
+
EXAMPLES::
|
892
|
+
|
893
|
+
sage: graph_classes._get_ISGCI() # long time (4s on sage.math, 2012)
|
894
|
+
"""
|
895
|
+
self._parse_db()
|
896
|
+
|
897
|
+
def show_all(self):
|
898
|
+
r"""
|
899
|
+
Print all graph classes stored in ISGCI.
|
900
|
+
|
901
|
+
EXAMPLES::
|
902
|
+
|
903
|
+
sage: graph_classes.show_all()
|
904
|
+
id | name | type | smallgraph
|
905
|
+
----------------------------------------------------------------------------------------------------------------------
|
906
|
+
gc_309 | $K_4$--minor--free | base |
|
907
|
+
gc_541 | $N^*$ | base |
|
908
|
+
gc_215 | $N^*$--perfect | base |
|
909
|
+
gc_5 | $P_4$--bipartite | base |
|
910
|
+
gc_3 | $P_4$--brittle | base |
|
911
|
+
gc_6 | $P_4$--comparability | base |
|
912
|
+
gc_7 | $P_4$--extendible | base |
|
913
|
+
...
|
914
|
+
"""
|
915
|
+
classes = self.classes()
|
916
|
+
|
917
|
+
# We want to print the different fields, and this dictionary stores the
|
918
|
+
# maximal number of characters of each field.
|
919
|
+
MAX = {
|
920
|
+
"id": 0,
|
921
|
+
"type": 0,
|
922
|
+
"smallgraph": 0,
|
923
|
+
"name": 0
|
924
|
+
}
|
925
|
+
|
926
|
+
# We sort the classes alphabetically, though we would like to display
|
927
|
+
# the meaningful classes at the top of the list
|
928
|
+
def sort_key(x):
|
929
|
+
name = x.get("name", "zzzzz")
|
930
|
+
return "{}{:4}".format(name, int(x["id"].split('_')[1]))
|
931
|
+
|
932
|
+
classes_list = sorted(classes.values(), key=sort_key)
|
933
|
+
|
934
|
+
# Maximum width of a field
|
935
|
+
MAX_LEN = 40
|
936
|
+
|
937
|
+
# Computing the max of each field with the database
|
938
|
+
for key in MAX:
|
939
|
+
MAX[key] = len(max((str(x.get(key, "")) for x in classes_list), key=len))
|
940
|
+
|
941
|
+
# At most MAX characters per field
|
942
|
+
for key, length in MAX.items():
|
943
|
+
MAX[key] = min(length, MAX_LEN)
|
944
|
+
|
945
|
+
# Head of the table
|
946
|
+
st = ("{:" + str(MAX["id"]) + "}").format("id")
|
947
|
+
st += (" | {:" + str(MAX["name"]) + "}").format("name")
|
948
|
+
st += (" | {:" + str(MAX["type"]) + "}").format("type")
|
949
|
+
st += (" | {:" + str(MAX["smallgraph"]) + "}").format("smallgraph")
|
950
|
+
print(st)
|
951
|
+
print("-" * (sum(MAX.values())+9))
|
952
|
+
|
953
|
+
# Entries
|
954
|
+
for entry in classes_list:
|
955
|
+
ID = entry.get("id", "")
|
956
|
+
name = entry.get("name", "")
|
957
|
+
typ = entry.get("type", "")
|
958
|
+
smallgraph = entry.get("smallgraph", "")
|
959
|
+
st = ("{:" + str(MAX["id"]) + "}").format(ID)
|
960
|
+
st += (" | {:" + str(MAX["name"]) + "}").format(name[:MAX_LEN])
|
961
|
+
st += (" | {:" + str(MAX["type"]) + "}").format(typ[:MAX_LEN])
|
962
|
+
st += " | " + str(smallgraph)[:MAX_LEN]
|
963
|
+
print(st)
|
964
|
+
|
965
|
+
|
966
|
+
def _XML_to_dict(root):
|
967
|
+
r"""
|
968
|
+
Return the XML data as a dictionary.
|
969
|
+
|
970
|
+
INPUT:
|
971
|
+
|
972
|
+
- ``root`` -- an ``xml.etree.cElementTree.ElementTree`` object
|
973
|
+
|
974
|
+
OUTPUT: a dictionary representing the XML data
|
975
|
+
|
976
|
+
EXAMPLES::
|
977
|
+
|
978
|
+
sage: graph_classes.Perfect.description() # indirect doctest
|
979
|
+
Class of graphs : Perfect
|
980
|
+
-------------------------
|
981
|
+
id : gc_56
|
982
|
+
name : perfect
|
983
|
+
...
|
984
|
+
"""
|
985
|
+
ans = root.attrib.copy()
|
986
|
+
for child in root:
|
987
|
+
if child.tag in ans:
|
988
|
+
if not isinstance(ans[child.tag], list):
|
989
|
+
ans[child.tag] = [ans[child.tag]]
|
990
|
+
ans[child.tag].append(_XML_to_dict(child))
|
991
|
+
else:
|
992
|
+
ans[child.tag] = _XML_to_dict(child)
|
993
|
+
|
994
|
+
# If the dictionary is empty, perhaps the only content is a text, and we
|
995
|
+
# return this instead. Useful sometimes in the ISGCI db, for graph names.
|
996
|
+
if not ans:
|
997
|
+
return root.text
|
998
|
+
return ans
|
999
|
+
|
1000
|
+
|
1001
|
+
graph_classes = GraphClasses()
|
1002
|
+
|
1003
|
+
# Any object added to this list should also appear in the class' documentation, at the top of the file.
|
1004
|
+
graph_classes.Apex = GraphClass("Apex", "gc_1181", recognition_function=lambda x: x.is_apex())
|
1005
|
+
graph_classes.AT_free = GraphClass("AT-free", "gc_61", recognition_function=lambda x: x.is_asteroidal_triple_free())
|
1006
|
+
graph_classes.Biconnected = GraphClass("Biconnected", "gc_771", recognition_function=lambda x: x.is_biconnected())
|
1007
|
+
graph_classes.BinaryTrees = GraphClass("BinaryTrees", "gc_847")
|
1008
|
+
graph_classes.Bipartite = GraphClass("Bipartite", "gc_69", recognition_function=lambda x: x.is_bipartite())
|
1009
|
+
graph_classes.Block = GraphClass("Block", "gc_93", recognition_function=lambda x: x.is_block_graph())
|
1010
|
+
graph_classes.Cactus = GraphClass("Cactus", "gc_108", recognition_function=lambda x: x.is_cactus())
|
1011
|
+
graph_classes.Chordal = GraphClass("Chordal", "gc_32", recognition_function=lambda x: x.is_chordal())
|
1012
|
+
graph_classes.ClawFree = GraphClass("Claw-free", "gc_62")
|
1013
|
+
graph_classes.CoGraph = GraphClass("CoGraph", "gc_151", recognition_function=lambda x: x.is_cograph())
|
1014
|
+
graph_classes.Comparability = GraphClass("Comparability", "gc_72", recognition_function=lambda x: x.is_comparability())
|
1015
|
+
graph_classes.DistanceRegular = GraphClass("Distance Regular", "gc_1148", recognition_function=lambda x: x.is_distance_regular())
|
1016
|
+
graph_classes.Gallai = GraphClass("Gallai", "gc_73")
|
1017
|
+
graph_classes.Grid = GraphClass("Grid", "gc_464")
|
1018
|
+
graph_classes.Hamiltonian = GraphClass("Hamiltonian", "gc_1092", recognition_function=lambda x: x.is_hamiltonian())
|
1019
|
+
graph_classes.Interval = GraphClass("Interval", "gc_234", recognition_function=lambda x: x.is_interval())
|
1020
|
+
graph_classes.Line = GraphClass("Line", "gc_249", recognition_function=lambda x: x.is_line_graph())
|
1021
|
+
graph_classes.Modular = GraphClass("Modular", "gc_50")
|
1022
|
+
graph_classes.Outerplanar = GraphClass("Outerplanar", "gc_110")
|
1023
|
+
graph_classes.Perfect = GraphClass("Perfect", "gc_56", recognition_function=lambda x: x.is_perfect())
|
1024
|
+
graph_classes.Permutation = GraphClass("Permutation", "gc_23", recognition_function=lambda x: x.is_permutation())
|
1025
|
+
graph_classes.Planar = GraphClass("Planar", "gc_43", recognition_function=lambda x: x.is_planar())
|
1026
|
+
graph_classes.Polyhedral = GraphClass("Polyhedral", "gc_986", recognition_function=lambda x: x.is_polyhedral())
|
1027
|
+
graph_classes.Split = GraphClass("Split", "gc_39", recognition_function=lambda x: x.is_split())
|
1028
|
+
graph_classes.StronglyRegular = GraphClass("Strongly Regular", "gc_1185", recognition_function=lambda x: x.is_strongly_regular())
|
1029
|
+
graph_classes.Tree = GraphClass("Tree", "gc_342", recognition_function=lambda x: x.is_tree())
|
1030
|
+
graph_classes.TriangleFree = GraphClass("Triangle Free", "gc_371", recognition_function=lambda x: x.is_triangle_free())
|
1031
|
+
graph_classes.UnitDisk = GraphClass("UnitDisk", "gc_389")
|
1032
|
+
graph_classes.UnitInterval = GraphClass("UnitInterval", "gc_299")
|
1033
|
+
graph_classes.WeaklyChordal = GraphClass("Weakly Chordal", "gc_14", recognition_function=lambda x: x.is_weakly_chordal())
|