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,1653 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-graphs
|
2
|
+
r"""
|
3
|
+
Fast sparse graphs
|
4
|
+
|
5
|
+
For an overview of graph data structures in sage, see
|
6
|
+
:mod:`~sage.graphs.base.overview`.
|
7
|
+
|
8
|
+
Usage Introduction
|
9
|
+
------------------
|
10
|
+
|
11
|
+
::
|
12
|
+
|
13
|
+
sage: from sage.graphs.base.sparse_graph import SparseGraph
|
14
|
+
|
15
|
+
Sparse graphs are initialized as follows::
|
16
|
+
|
17
|
+
sage: S = SparseGraph(nverts = 10, expected_degree = 3, extra_vertices = 10)
|
18
|
+
|
19
|
+
This example initializes a sparse graph with room for twenty vertices, the first
|
20
|
+
ten of which are in the graph. In general, the first ``nverts`` are "active."
|
21
|
+
For example, see that 9 is already in the graph::
|
22
|
+
|
23
|
+
sage: S.verts()
|
24
|
+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
25
|
+
sage: S.add_vertex(9)
|
26
|
+
9
|
27
|
+
sage: S.verts()
|
28
|
+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
29
|
+
|
30
|
+
But 10 is not, until we add it::
|
31
|
+
|
32
|
+
sage: S.add_vertex(10)
|
33
|
+
10
|
34
|
+
sage: S.verts()
|
35
|
+
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
36
|
+
|
37
|
+
You can begin working with unlabeled arcs right away as follows::
|
38
|
+
|
39
|
+
sage: S.add_arc(0,1)
|
40
|
+
sage: S.add_arc(1,2)
|
41
|
+
sage: S.add_arc(1,0)
|
42
|
+
sage: S.has_arc(7,3)
|
43
|
+
False
|
44
|
+
sage: S.has_arc(0,1)
|
45
|
+
True
|
46
|
+
sage: S.in_neighbors(1)
|
47
|
+
[0]
|
48
|
+
sage: S.out_neighbors(1)
|
49
|
+
[0, 2]
|
50
|
+
sage: S.del_all_arcs(0,1)
|
51
|
+
sage: S.all_arcs(0,1)
|
52
|
+
[]
|
53
|
+
sage: S.all_arcs(1,2)
|
54
|
+
[0]
|
55
|
+
sage: S.del_vertex(7)
|
56
|
+
sage: S.all_arcs(7,3)
|
57
|
+
Traceback (most recent call last):
|
58
|
+
...
|
59
|
+
LookupError: vertex (7) is not a vertex of the graph
|
60
|
+
|
61
|
+
Sparse graphs support multiple edges and labeled edges, but requires that the
|
62
|
+
labels be positive integers (the case label = 0 is treated as no label).
|
63
|
+
|
64
|
+
::
|
65
|
+
|
66
|
+
sage: S.add_arc_label(0,1,-1)
|
67
|
+
Traceback (most recent call last):
|
68
|
+
...
|
69
|
+
ValueError: Label (-1) must be a nonnegative integer.
|
70
|
+
sage: S.add_arc(0,1)
|
71
|
+
sage: S.arc_label(0,1)
|
72
|
+
0
|
73
|
+
|
74
|
+
Note that ``arc_label`` only returns the first edge label found in the specified
|
75
|
+
place, and this can be in any order (if you want all arc labels, use
|
76
|
+
``all_arcs``)::
|
77
|
+
|
78
|
+
sage: S.add_arc_label(0,1,1)
|
79
|
+
sage: S.arc_label(0,1)
|
80
|
+
1
|
81
|
+
sage: S.all_arcs(0,1)
|
82
|
+
[0, 1]
|
83
|
+
|
84
|
+
Zero specifies only that there is no labeled arc::
|
85
|
+
|
86
|
+
sage: S.arc_label(1,2)
|
87
|
+
0
|
88
|
+
|
89
|
+
So do not be fooled::
|
90
|
+
|
91
|
+
sage: S.all_arcs(1,2)
|
92
|
+
[0]
|
93
|
+
sage: S.add_arc(1,2)
|
94
|
+
sage: S.arc_label(1,2)
|
95
|
+
0
|
96
|
+
|
97
|
+
Instead, if you work with unlabeled edges, be sure to use the right functions::
|
98
|
+
|
99
|
+
sage: T = SparseGraph(nverts = 3, expected_degree = 2)
|
100
|
+
sage: T.add_arc(0,1)
|
101
|
+
sage: T.add_arc(1,2)
|
102
|
+
sage: T.add_arc(2,0)
|
103
|
+
sage: T.has_arc(0,1)
|
104
|
+
True
|
105
|
+
|
106
|
+
Sparse graphs are by their nature directed. As of this writing, you need to do
|
107
|
+
operations in pairs to treat the undirected case (or use a backend or a Sage
|
108
|
+
graph)::
|
109
|
+
|
110
|
+
sage: T.has_arc(1,0)
|
111
|
+
False
|
112
|
+
|
113
|
+
Multiple unlabeled edges are also possible::
|
114
|
+
|
115
|
+
sage: for _ in range(10): S.add_arc(5,4)
|
116
|
+
sage: S.all_arcs(5,4)
|
117
|
+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
118
|
+
|
119
|
+
The curious developer is encouraged to check out the ``unsafe`` functions,
|
120
|
+
which do not check input but which run in pure C.
|
121
|
+
|
122
|
+
Underlying Data Structure
|
123
|
+
-------------------------
|
124
|
+
|
125
|
+
The class ``SparseGraph`` contains the following variables which are inherited
|
126
|
+
from ``CGraph`` (for explanation, refer to the documentation there)::
|
127
|
+
|
128
|
+
cdef int num_verts
|
129
|
+
cdef int num_arcs
|
130
|
+
cdef int *in_degrees
|
131
|
+
cdef int *out_degrees
|
132
|
+
cdef bitset_t active_vertices
|
133
|
+
|
134
|
+
It also contains the following variables::
|
135
|
+
|
136
|
+
cdef int hash_length
|
137
|
+
cdef int hash_mask
|
138
|
+
cdef SparseGraphBTNode **vertices
|
139
|
+
cdef SparseGraphBTNode **vertices_rev
|
140
|
+
cdef bint _directed
|
141
|
+
|
142
|
+
For each vertex ``u``, a hash table of length ``hash_length`` is instantiated.
|
143
|
+
An arc ``(u, v)`` is stored at ``u * hash_length + hash(v)`` of the array
|
144
|
+
``vertices``, where ``hash`` should be thought of as an arbitrary but fixed hash
|
145
|
+
function which takes values in ``0 <= hash < hash_length``. Each address may
|
146
|
+
represent different arcs, say ``(u, v1)`` and ``(u, v2)`` where
|
147
|
+
``hash(v1) == hash(v2)``. Thus, a binary tree structure is used at this step to
|
148
|
+
speed access to individual arcs, whose nodes (each of which represents a pair
|
149
|
+
``(u,v)``) are instances of the following type::
|
150
|
+
|
151
|
+
cdef struct SparseGraphBTNode:
|
152
|
+
int vertex
|
153
|
+
int number
|
154
|
+
SparseGraphLLNode *labels
|
155
|
+
SparseGraphBTNode *left
|
156
|
+
SparseGraphBTNode *right
|
157
|
+
|
158
|
+
Which range of the ``vertices`` array the root of the tree is in determines
|
159
|
+
``u``, and ``vertex`` stores ``v``. The integer ``number`` stores only the
|
160
|
+
number of unlabeled arcs from ``u`` to ``v``.
|
161
|
+
|
162
|
+
Currently, labels are stored in a simple linked list, whose nodes are instances
|
163
|
+
of the following type::
|
164
|
+
|
165
|
+
cdef struct SparseGraphLLNode:
|
166
|
+
int label
|
167
|
+
int number
|
168
|
+
SparseGraphLLNode *next
|
169
|
+
|
170
|
+
The int ``label`` must be a positive integer, since 0 indicates no label, and
|
171
|
+
negative numbers indicate errors. The int ``number`` is the number of arcs with
|
172
|
+
the given label.
|
173
|
+
|
174
|
+
TODO: Optimally, edge labels would also be represented by a binary tree, which
|
175
|
+
would help performance in graphs with many overlapping edges. Also, a more
|
176
|
+
efficient binary tree structure could be used, although in practice the trees
|
177
|
+
involved will usually have very small order, unless the degree of vertices
|
178
|
+
becomes significantly larger than the ``expected_degree`` given, because this is
|
179
|
+
the size of each hash table. Indeed, the expected size of the binary trees is
|
180
|
+
`\frac{\text{actual degree}}{\text{expected degree}}`. Ryan Dingman, e.g., is
|
181
|
+
working on a general-purpose Cython-based red black tree, which would be optimal
|
182
|
+
for both of these uses.
|
183
|
+
"""
|
184
|
+
|
185
|
+
# ****************************************************************************
|
186
|
+
# Copyright (C) 2008-9 Robert L. Miller <rlmillster@gmail.com>
|
187
|
+
#
|
188
|
+
# This program is free software: you can redistribute it and/or modify
|
189
|
+
# it under the terms of the GNU General Public License as published by
|
190
|
+
# the Free Software Foundation, either version 2 of the License, or
|
191
|
+
# (at your option) any later version.
|
192
|
+
# https://www.gnu.org/licenses/
|
193
|
+
# ****************************************************************************
|
194
|
+
|
195
|
+
|
196
|
+
from libc.string cimport memset
|
197
|
+
from cysignals.memory cimport check_malloc, check_allocarray, sig_free
|
198
|
+
from memory_allocator cimport MemoryAllocator
|
199
|
+
|
200
|
+
from sage.data_structures.bitset_base cimport *
|
201
|
+
from sage.data_structures.bitset cimport *
|
202
|
+
|
203
|
+
|
204
|
+
cdef enum:
|
205
|
+
BT_REORDERING_CONSTANT = 145533211
|
206
|
+
# Since the binary tree will often see vertices coming in already sorted,
|
207
|
+
# we don't use the normal ordering on integers, instead multiplying by a
|
208
|
+
# randomly chosen number and (after reducing mod the size of integers)
|
209
|
+
# comparing the result. This isn't necessarily the most efficient way to do
|
210
|
+
# things, but it may just be on binary trees that are never bigger than two
|
211
|
+
# or three nodes.
|
212
|
+
|
213
|
+
|
214
|
+
cdef inline int compare(int a, int b) noexcept:
|
215
|
+
# Here we rely on the fact that C performs arithmetic on unsigned
|
216
|
+
# ints modulo 2^wordsize.
|
217
|
+
cdef unsigned int aa = a, bb = b # signed ints lead to badness like a>b>c>a...
|
218
|
+
if aa*BT_REORDERING_CONSTANT > bb*BT_REORDERING_CONSTANT:
|
219
|
+
return 1
|
220
|
+
elif aa*BT_REORDERING_CONSTANT < bb*BT_REORDERING_CONSTANT:
|
221
|
+
return -1
|
222
|
+
return 0
|
223
|
+
|
224
|
+
|
225
|
+
cdef class SparseGraph(CGraph):
|
226
|
+
"""
|
227
|
+
Compiled sparse graphs.
|
228
|
+
|
229
|
+
::
|
230
|
+
|
231
|
+
sage: from sage.graphs.base.sparse_graph import SparseGraph
|
232
|
+
|
233
|
+
Sparse graphs are initialized as follows::
|
234
|
+
|
235
|
+
sage: S = SparseGraph(nverts = 10, expected_degree = 3, extra_vertices = 10)
|
236
|
+
|
237
|
+
INPUT:
|
238
|
+
|
239
|
+
- ``nverts`` -- nonnegative integer, the number of vertices
|
240
|
+
|
241
|
+
- ``expected_degree`` -- nonnegative integer (default: 16); expected upper
|
242
|
+
bound on degree of vertices
|
243
|
+
|
244
|
+
- ``extra_vertices`` -- nonnegative integer (default: 0); how many extra
|
245
|
+
vertices to allocate
|
246
|
+
|
247
|
+
- ``verts`` -- (optional) list of vertices to add
|
248
|
+
|
249
|
+
- ``arcs`` -- (optional) list of arcs to add
|
250
|
+
|
251
|
+
The first ``nverts`` are created as vertices of the graph, and the next
|
252
|
+
``extra_vertices`` can be freely added without reallocation. See top level
|
253
|
+
documentation for more details. The input ``verts`` and ``arcs`` are mainly
|
254
|
+
for use in pickling.
|
255
|
+
"""
|
256
|
+
|
257
|
+
def __cinit__(self, int nverts, int expected_degree=16, int extra_vertices=10,
|
258
|
+
verts=None, arcs=None, directed=True):
|
259
|
+
"""
|
260
|
+
Allocation and initialization happen in one place.
|
261
|
+
|
262
|
+
Memory usage is roughly
|
263
|
+
|
264
|
+
O( (nverts + extra_vertices)*expected_degree + num_arcs ).
|
265
|
+
|
266
|
+
EXAMPLES::
|
267
|
+
|
268
|
+
sage: from sage.graphs.base.sparse_graph import SparseGraph
|
269
|
+
sage: S = SparseGraph(nverts = 10, expected_degree = 3, extra_vertices = 10)
|
270
|
+
|
271
|
+
TESTS::
|
272
|
+
|
273
|
+
sage: Graph(-1)
|
274
|
+
Traceback (most recent call last):
|
275
|
+
...
|
276
|
+
ValueError: The number of vertices cannot be strictly negative!
|
277
|
+
"""
|
278
|
+
cdef int i = 1
|
279
|
+
if nverts < 0:
|
280
|
+
raise ValueError("The number of vertices cannot be strictly negative!")
|
281
|
+
if nverts == 0 and extra_vertices == 0:
|
282
|
+
raise RuntimeError('Sparse graphs must allocate space for vertices!')
|
283
|
+
self.num_verts = nverts
|
284
|
+
nverts += extra_vertices
|
285
|
+
self.num_arcs = 0
|
286
|
+
while i < expected_degree:
|
287
|
+
i = i << 1
|
288
|
+
self.hash_length = i
|
289
|
+
self.hash_mask = i - 1
|
290
|
+
|
291
|
+
# Allocating memory (initialized to zero)
|
292
|
+
self.vertices = <SparseGraphBTNode **>check_calloc(
|
293
|
+
nverts * self.hash_length, sizeof(SparseGraphBTNode *))
|
294
|
+
if directed:
|
295
|
+
# In a directed graph we keep also track of the incoming edges.
|
296
|
+
# So each edge has two copies.
|
297
|
+
self.vertices_rev = <SparseGraphBTNode **>check_calloc(
|
298
|
+
nverts * self.hash_length, sizeof(SparseGraphBTNode *))
|
299
|
+
else:
|
300
|
+
self.vertices_rev = self.vertices
|
301
|
+
self._directed = directed
|
302
|
+
|
303
|
+
self.in_degrees = <int *>check_calloc(nverts, sizeof(int))
|
304
|
+
self.out_degrees = <int *>check_calloc(nverts, sizeof(int))
|
305
|
+
|
306
|
+
bitset_init(self.active_vertices, self.num_verts + extra_vertices)
|
307
|
+
bitset_set_first_n(self.active_vertices, self.num_verts)
|
308
|
+
|
309
|
+
if verts is not None:
|
310
|
+
self.add_vertices(verts)
|
311
|
+
|
312
|
+
if arcs is not None:
|
313
|
+
for u, v, l in arcs:
|
314
|
+
self.add_arc_label(u, v, l)
|
315
|
+
|
316
|
+
def __dealloc__(self):
|
317
|
+
"""
|
318
|
+
New and dealloc are both tested at class level.
|
319
|
+
"""
|
320
|
+
cdef SparseGraphBTNode **temp
|
321
|
+
cdef SparseGraphLLNode *label_temp
|
322
|
+
cdef size_t i
|
323
|
+
|
324
|
+
# Freeing the list of arcs attached to each vertex (going out)
|
325
|
+
for i in range(self.active_vertices.size * self.hash_length):
|
326
|
+
temp = &(self.vertices[i])
|
327
|
+
|
328
|
+
# While temp[0]=self.vertices[i] is not NULL, find a leaf in the
|
329
|
+
# tree rooted at temp[0] and free it. Then go back to temp[0] and do
|
330
|
+
# it again. When self.vertices[i] is NULL, go for self.vertices[i+1]
|
331
|
+
while temp[0]:
|
332
|
+
if temp[0].left:
|
333
|
+
temp = &(temp[0].left)
|
334
|
+
elif temp[0].right:
|
335
|
+
temp = &(temp[0].right)
|
336
|
+
else:
|
337
|
+
label_temp = temp[0].labels
|
338
|
+
while label_temp:
|
339
|
+
temp[0].labels = label_temp.next
|
340
|
+
sig_free(label_temp)
|
341
|
+
label_temp = temp[0].labels
|
342
|
+
sig_free(temp[0])
|
343
|
+
temp[0] = NULL
|
344
|
+
temp = &(self.vertices[i])
|
345
|
+
|
346
|
+
if self.is_directed():
|
347
|
+
|
348
|
+
# Freeing the list of arcs attached to each vertex (going in)
|
349
|
+
for i in range(self.active_vertices.size * self.hash_length):
|
350
|
+
temp = &(self.vertices_rev[i])
|
351
|
+
|
352
|
+
# While temp[0]=self.vertices_rev[i] is not NULL, find a leaf in the
|
353
|
+
# tree rooted at temp[0] and free it. Then go back to temp[0] and do
|
354
|
+
# it again. When self.vertices_rev[i] is NULL, go for self.vertices_rev[i+1]
|
355
|
+
while temp[0]:
|
356
|
+
if temp[0].left:
|
357
|
+
temp = &(temp[0].left)
|
358
|
+
elif temp[0].right:
|
359
|
+
temp = &(temp[0].right)
|
360
|
+
else:
|
361
|
+
label_temp = temp[0].labels
|
362
|
+
while label_temp:
|
363
|
+
temp[0].labels = label_temp.next
|
364
|
+
sig_free(label_temp)
|
365
|
+
label_temp = temp[0].labels
|
366
|
+
sig_free(temp[0])
|
367
|
+
temp[0] = NULL
|
368
|
+
temp = &(self.vertices_rev[i])
|
369
|
+
sig_free(self.vertices_rev)
|
370
|
+
|
371
|
+
sig_free(self.vertices)
|
372
|
+
sig_free(self.in_degrees)
|
373
|
+
sig_free(self.out_degrees)
|
374
|
+
bitset_free(self.active_vertices)
|
375
|
+
|
376
|
+
cpdef realloc(self, int total):
|
377
|
+
"""
|
378
|
+
Reallocate the number of vertices to use, without actually adding any.
|
379
|
+
|
380
|
+
INPUT:
|
381
|
+
|
382
|
+
- ``total`` -- integer; the total size to make the array
|
383
|
+
|
384
|
+
Returns -1 and fails if reallocation would destroy any active vertices.
|
385
|
+
|
386
|
+
EXAMPLES::
|
387
|
+
|
388
|
+
sage: from sage.graphs.base.sparse_graph import SparseGraph
|
389
|
+
sage: S = SparseGraph(nverts=4, extra_vertices=4)
|
390
|
+
sage: S.current_allocation()
|
391
|
+
8
|
392
|
+
sage: S.add_vertex(6)
|
393
|
+
6
|
394
|
+
sage: S.current_allocation()
|
395
|
+
8
|
396
|
+
sage: S.add_vertex(10)
|
397
|
+
10
|
398
|
+
sage: S.current_allocation()
|
399
|
+
16
|
400
|
+
sage: S.add_vertex(40)
|
401
|
+
Traceback (most recent call last):
|
402
|
+
...
|
403
|
+
RuntimeError: requested vertex is past twice the allocated range: use realloc
|
404
|
+
sage: S.realloc(50)
|
405
|
+
sage: S.add_vertex(40)
|
406
|
+
40
|
407
|
+
sage: S.current_allocation()
|
408
|
+
50
|
409
|
+
sage: S.realloc(30)
|
410
|
+
-1
|
411
|
+
sage: S.current_allocation()
|
412
|
+
50
|
413
|
+
sage: S.del_vertex(40)
|
414
|
+
sage: S.realloc(30)
|
415
|
+
sage: S.current_allocation()
|
416
|
+
30
|
417
|
+
"""
|
418
|
+
if not total:
|
419
|
+
raise RuntimeError('Sparse graphs must allocate space for vertices!')
|
420
|
+
cdef bitset_t bits
|
421
|
+
cdef size_t s_total = <size_t>total
|
422
|
+
if s_total < self.active_vertices.size:
|
423
|
+
bitset_init(bits, self.active_vertices.size)
|
424
|
+
bitset_set_first_n(bits, s_total)
|
425
|
+
if not bitset_issubset(self.active_vertices, bits):
|
426
|
+
bitset_free(bits)
|
427
|
+
return -1
|
428
|
+
bitset_free(bits)
|
429
|
+
|
430
|
+
self.vertices = <SparseGraphBTNode **>check_reallocarray(
|
431
|
+
self.vertices, s_total * self.hash_length, sizeof(SparseGraphBTNode *))
|
432
|
+
if self.is_directed():
|
433
|
+
self.vertices_rev = <SparseGraphBTNode **>check_reallocarray(
|
434
|
+
self.vertices_rev, s_total * self.hash_length, sizeof(SparseGraphBTNode *))
|
435
|
+
else:
|
436
|
+
self.vertices_rev = self.vertices
|
437
|
+
|
438
|
+
self.in_degrees = <int *>check_reallocarray(self.in_degrees, s_total, sizeof(int))
|
439
|
+
self.out_degrees = <int *>check_reallocarray(self.out_degrees, s_total, sizeof(int))
|
440
|
+
|
441
|
+
cdef int new_vertices = total - self.active_vertices.size
|
442
|
+
|
443
|
+
# Initializing the entries corresponding to new vertices if any
|
444
|
+
if new_vertices > 0:
|
445
|
+
|
446
|
+
# self.vertices
|
447
|
+
memset(self.vertices + self.active_vertices.size * self.hash_length, 0,
|
448
|
+
new_vertices * self.hash_length * sizeof(SparseGraphBTNode *))
|
449
|
+
if self.is_directed():
|
450
|
+
memset(self.vertices_rev + self.active_vertices.size * self.hash_length, 0,
|
451
|
+
new_vertices * self.hash_length * sizeof(SparseGraphBTNode *))
|
452
|
+
|
453
|
+
# self.in_degrees
|
454
|
+
memset(self.in_degrees + self.active_vertices.size, 0,
|
455
|
+
new_vertices * sizeof(int))
|
456
|
+
|
457
|
+
# self.out_degrees
|
458
|
+
memset(self.out_degrees + self.active_vertices.size, 0,
|
459
|
+
new_vertices * sizeof(int))
|
460
|
+
|
461
|
+
# self.active_vertices
|
462
|
+
bitset_realloc(self.active_vertices, s_total)
|
463
|
+
|
464
|
+
cpdef inline bint is_directed(self) noexcept:
|
465
|
+
r"""
|
466
|
+
Return whether the graph is directed.
|
467
|
+
|
468
|
+
EXAMPLES::
|
469
|
+
|
470
|
+
sage: from sage.graphs.base.sparse_graph import SparseGraph
|
471
|
+
sage: G = SparseGraph(5)
|
472
|
+
sage: G.is_directed()
|
473
|
+
True
|
474
|
+
sage: G = SparseGraph(5, directed=False)
|
475
|
+
sage: G.is_directed()
|
476
|
+
False
|
477
|
+
"""
|
478
|
+
return self._directed
|
479
|
+
|
480
|
+
###################################
|
481
|
+
# Unlabeled arc functions
|
482
|
+
###################################
|
483
|
+
|
484
|
+
cdef inline int _del_arc_unsafe(self, int u, int v, SparseGraphBTNode **parent) except -1:
|
485
|
+
"""
|
486
|
+
.. WARNING::
|
487
|
+
|
488
|
+
This method is for internal use only. Use :meth:`del_arc_unsafe` instead.
|
489
|
+
|
490
|
+
Deletes *all* arcs from u to v, returns the number of arcs deleted.
|
491
|
+
"""
|
492
|
+
cdef int i = (u * self.hash_length) + (v & self.hash_mask)
|
493
|
+
parent = &parent[i]
|
494
|
+
cdef int compared, left_len, right_len
|
495
|
+
cdef SparseGraphBTNode *temp
|
496
|
+
cdef SparseGraphBTNode **left_child
|
497
|
+
cdef SparseGraphBTNode **right_child
|
498
|
+
cdef SparseGraphLLNode *labels
|
499
|
+
cdef int n_arcs = 0
|
500
|
+
|
501
|
+
# Assigning to parent the SparseGraphBTNode corresponding to arc (u,v)
|
502
|
+
while parent[0]:
|
503
|
+
compared = compare(parent[0].vertex, v)
|
504
|
+
if compared > 0:
|
505
|
+
parent = &(parent[0].left)
|
506
|
+
elif compared < 0:
|
507
|
+
parent = &(parent[0].right)
|
508
|
+
else: # if parent[0].vertex == v:
|
509
|
+
break
|
510
|
+
|
511
|
+
# If not found, there is no arc to delete !
|
512
|
+
if not parent[0]:
|
513
|
+
return n_arcs
|
514
|
+
|
515
|
+
# now parent[0] points to the BT node corresponding to (u,v)
|
516
|
+
labels = parent[0].labels
|
517
|
+
n_arcs += parent[0].number
|
518
|
+
|
519
|
+
# Freeing the labels
|
520
|
+
while labels:
|
521
|
+
n_arcs += labels.number
|
522
|
+
parent[0].labels = parent[0].labels.next
|
523
|
+
sig_free(labels)
|
524
|
+
labels = parent[0].labels
|
525
|
+
|
526
|
+
# Now, if the SparseGraphBTNode element is to be removed, it has to be
|
527
|
+
# replaced in the binary tree by one of its children.
|
528
|
+
|
529
|
+
# If there is no left child
|
530
|
+
if not parent[0].left:
|
531
|
+
temp = parent[0]
|
532
|
+
parent[0] = parent[0].right
|
533
|
+
sig_free(temp)
|
534
|
+
return n_arcs
|
535
|
+
|
536
|
+
# If there is no right child
|
537
|
+
elif not parent[0].right:
|
538
|
+
temp = parent[0]
|
539
|
+
parent[0] = parent[0].left
|
540
|
+
sig_free(temp)
|
541
|
+
return n_arcs
|
542
|
+
|
543
|
+
# Both children
|
544
|
+
else:
|
545
|
+
left_len = 0
|
546
|
+
right_len = 0
|
547
|
+
left_child = &(parent[0].left)
|
548
|
+
right_child = &(parent[0].right)
|
549
|
+
|
550
|
+
# left_len is equal to the maximum length of a path LR...R. The
|
551
|
+
# last element of this path is the value of left_child
|
552
|
+
|
553
|
+
while left_child[0].right:
|
554
|
+
left_len += 1
|
555
|
+
left_child = &(left_child[0].right)
|
556
|
+
# right_len is equal to the maximum length of a path RL...L. The
|
557
|
+
# last element of this path is the value of right_child
|
558
|
+
|
559
|
+
while right_child[0].left:
|
560
|
+
right_len += 1
|
561
|
+
right_child = &(right_child[0].left)
|
562
|
+
|
563
|
+
# According to the respective lengths, replace parent by the left or
|
564
|
+
# right child and place the other child at its expected place.
|
565
|
+
if left_len > right_len:
|
566
|
+
left_child[0].right = parent[0].right
|
567
|
+
temp = parent[0]
|
568
|
+
parent[0] = left_child[0]
|
569
|
+
left_child[0] = left_child[0].left
|
570
|
+
parent[0].left = temp.left
|
571
|
+
sig_free(temp)
|
572
|
+
return n_arcs
|
573
|
+
else:
|
574
|
+
right_child[0].left = parent[0].left
|
575
|
+
temp = parent[0]
|
576
|
+
parent[0] = right_child[0]
|
577
|
+
right_child[0] = right_child[0].right
|
578
|
+
parent[0].right = temp.right
|
579
|
+
sig_free(temp)
|
580
|
+
return n_arcs
|
581
|
+
|
582
|
+
cdef int del_arc_unsafe(self, int u, int v) except -1:
|
583
|
+
"""
|
584
|
+
Delete *all* arcs from u to v.
|
585
|
+
|
586
|
+
INPUT:
|
587
|
+
|
588
|
+
- ``u``, ``v`` -- nonnegative integers
|
589
|
+
|
590
|
+
OUTPUT:
|
591
|
+
|
592
|
+
- 0 -- no error
|
593
|
+
- 1 -- no arc to delete
|
594
|
+
"""
|
595
|
+
cdef int n_arcs = self._del_arc_unsafe(u, v, self.vertices)
|
596
|
+
if u != v or self.is_directed():
|
597
|
+
# We remove the reverse copy only if u != v or graph is directed.
|
598
|
+
self._del_arc_unsafe(v, u, self.vertices_rev)
|
599
|
+
if self.vertices == self.vertices_rev:
|
600
|
+
# In case of an undirected graph, we have added two copies each.
|
601
|
+
self.in_degrees[u] -= n_arcs
|
602
|
+
self.out_degrees[v] -= n_arcs
|
603
|
+
self.num_arcs -= n_arcs
|
604
|
+
|
605
|
+
self.in_degrees[v] -= n_arcs
|
606
|
+
self.out_degrees[u] -= n_arcs
|
607
|
+
self.num_arcs -= n_arcs
|
608
|
+
if n_arcs:
|
609
|
+
return 1
|
610
|
+
|
611
|
+
###################################
|
612
|
+
# Neighbor functions
|
613
|
+
###################################
|
614
|
+
|
615
|
+
cdef inline int _neighbors_BTNode_unsafe (self, int u, bint out, SparseGraphBTNode **res, int size) except -2:
|
616
|
+
r"""
|
617
|
+
.. WARNING::
|
618
|
+
|
619
|
+
This method is for internal use only.
|
620
|
+
"""
|
621
|
+
cdef SparseGraphBTNode** vertices = self.vertices if out else self.vertices_rev
|
622
|
+
cdef int i
|
623
|
+
cdef int n = 0
|
624
|
+
cdef int nr = 0
|
625
|
+
cdef SparseGraphBTNode *c
|
626
|
+
|
627
|
+
for i in range(u * self.hash_length, (u+1) * self.hash_length):
|
628
|
+
if not vertices[i]:
|
629
|
+
continue
|
630
|
+
else:
|
631
|
+
res[n] = vertices[i]
|
632
|
+
nr = 1
|
633
|
+
while nr > 0 and n < size:
|
634
|
+
c = res[n]
|
635
|
+
n += 1
|
636
|
+
nr -= 1
|
637
|
+
if c.left:
|
638
|
+
res[n+nr] = c.left
|
639
|
+
nr += 1
|
640
|
+
if c.right:
|
641
|
+
res[n+nr] = c.right
|
642
|
+
nr += 1
|
643
|
+
return -1 if nr > 0 else n
|
644
|
+
|
645
|
+
cdef inline int next_out_neighbor_unsafe(self, int u, int v, int* l) except -2:
|
646
|
+
"""
|
647
|
+
Return the next out-neighbor of ``u`` that is greater than ``v``.
|
648
|
+
|
649
|
+
If ``v`` is ``-1`` return the first neighbor of ``u``.
|
650
|
+
|
651
|
+
Return ``-1`` in case there does not exist such an out-neighbor.
|
652
|
+
|
653
|
+
Set ``l`` to be the label of the first arc.
|
654
|
+
|
655
|
+
.. WARNING::
|
656
|
+
|
657
|
+
Repeated calls to this function until -1 is returned DOES NOT yield
|
658
|
+
a linear time algorithm in the number of neighbors of v.
|
659
|
+
To list the neighbors of a vertex in linear time, one should use
|
660
|
+
out_neighbors_unsafe.
|
661
|
+
"""
|
662
|
+
cdef SparseGraphBTNode* next_bt = self.next_out_neighbor_BTNode_unsafe(u, v)
|
663
|
+
if next_bt:
|
664
|
+
if next_bt.number:
|
665
|
+
l[0] = 0
|
666
|
+
else:
|
667
|
+
l[0] = next_bt.labels.label
|
668
|
+
return next_bt.vertex
|
669
|
+
else:
|
670
|
+
return -1
|
671
|
+
|
672
|
+
cdef inline SparseGraphBTNode* next_neighbor_BTNode_unsafe(self, SparseGraphBTNode** vertices, int u, int v) noexcept:
|
673
|
+
"""
|
674
|
+
Return the next neighbor of ``u`` that is greater than ``v``.
|
675
|
+
|
676
|
+
If ``v`` is ``-1`` return the first neighbor of ``u``.
|
677
|
+
|
678
|
+
Return ``NULL`` in case there does not exist such a neighbor.
|
679
|
+
|
680
|
+
If ``vertices`` is ``self.vertices`` the out-neighbor is given.
|
681
|
+
If ``vertices`` is ``self.vertices_rev`` the in-neighbor is given.
|
682
|
+
|
683
|
+
.. WARNING::
|
684
|
+
|
685
|
+
Repeated calls to this function until NULL is returned DOES NOT
|
686
|
+
yield a linear time algorithm in the number of neighbors of u.
|
687
|
+
To list the neighbors of a vertex in linear time, one should use
|
688
|
+
_neighbors_BTNode_unsafe.
|
689
|
+
"""
|
690
|
+
cdef int i
|
691
|
+
cdef int start_i = (u * self.hash_length) + (v & self.hash_mask)
|
692
|
+
cdef SparseGraphBTNode* temp
|
693
|
+
cdef SparseGraphBTNode* last_larger
|
694
|
+
|
695
|
+
i = start_i
|
696
|
+
if v != -1 and vertices[i]:
|
697
|
+
last_larger = NULL
|
698
|
+
temp = vertices[i]
|
699
|
+
while temp:
|
700
|
+
if compare(temp.vertex, v) > 0:
|
701
|
+
# We have found a candidate.
|
702
|
+
# We fall back to it, if we do not find anything smaller.
|
703
|
+
last_larger = temp
|
704
|
+
temp = temp.left
|
705
|
+
else: # note compare < 0
|
706
|
+
temp = temp.right
|
707
|
+
if last_larger:
|
708
|
+
return last_larger
|
709
|
+
elif v == -1:
|
710
|
+
start_i = (u*self.hash_length) - 1
|
711
|
+
|
712
|
+
# Return the next vertex.
|
713
|
+
for i in range(start_i+1, (u+1) * self.hash_length):
|
714
|
+
if not vertices[i]:
|
715
|
+
continue
|
716
|
+
temp = vertices[i]
|
717
|
+
while temp.left:
|
718
|
+
temp = temp.left
|
719
|
+
return temp
|
720
|
+
return NULL
|
721
|
+
|
722
|
+
cpdef int out_degree(self, int u) noexcept:
|
723
|
+
"""
|
724
|
+
Return the out-degree of ``v``
|
725
|
+
|
726
|
+
INPUT:
|
727
|
+
|
728
|
+
- ``u`` -- integer
|
729
|
+
|
730
|
+
EXAMPLES::
|
731
|
+
|
732
|
+
sage: from sage.graphs.base.sparse_graph import SparseGraph
|
733
|
+
sage: G = SparseGraph(5)
|
734
|
+
sage: G.add_arc(0,1)
|
735
|
+
sage: G.add_arc(1,2)
|
736
|
+
sage: G.add_arc(1,3)
|
737
|
+
sage: G.out_degree(0)
|
738
|
+
1
|
739
|
+
sage: G.out_degree(1)
|
740
|
+
2
|
741
|
+
"""
|
742
|
+
return self.out_degrees[u]
|
743
|
+
|
744
|
+
cdef inline int next_in_neighbor_unsafe(self, int v, int u, int* l) except -2:
|
745
|
+
"""
|
746
|
+
Return the next in-neighbor of ``v`` that is greater than ``u``.
|
747
|
+
|
748
|
+
If ``u`` is ``-1`` return the first neighbor of ``v``.
|
749
|
+
|
750
|
+
Return ``-1`` in case there does not exist such an in-neighbor.
|
751
|
+
|
752
|
+
Set ``l`` to be the label of the first arc.
|
753
|
+
|
754
|
+
.. WARNING::
|
755
|
+
|
756
|
+
Repeated calls to this function until -1 is returned DOES NOT yield
|
757
|
+
a linear time algorithm in the number of neighbors of v.
|
758
|
+
To list the neighbors of a vertex in linear time, one should use
|
759
|
+
in_neighbors_unsafe.
|
760
|
+
"""
|
761
|
+
cdef SparseGraphBTNode* next_bt = self.next_in_neighbor_BTNode_unsafe(v, u)
|
762
|
+
if next_bt:
|
763
|
+
if next_bt.number:
|
764
|
+
l[0] = 0
|
765
|
+
else:
|
766
|
+
l[0] = next_bt.labels.label
|
767
|
+
return next_bt.vertex
|
768
|
+
else:
|
769
|
+
return -1
|
770
|
+
|
771
|
+
cdef inline int _neighbors_unsafe(self, int u, bint out, int *neighbors, int size) except -2:
|
772
|
+
r"""
|
773
|
+
.. WARNING::
|
774
|
+
|
775
|
+
This method is for internal use only.
|
776
|
+
"""
|
777
|
+
cdef int r
|
778
|
+
cdef SparseGraphBTNode **nodes = <SparseGraphBTNode **>check_allocarray(size, sizeof(SparseGraphBTNode *))
|
779
|
+
|
780
|
+
r = self._neighbors_BTNode_unsafe(u, out, nodes, size)
|
781
|
+
for i in range(r if r >= 0 else size):
|
782
|
+
neighbors[i] = nodes[i].vertex
|
783
|
+
sig_free(nodes)
|
784
|
+
return r
|
785
|
+
|
786
|
+
cdef int out_neighbors_unsafe(self, int u, int *neighbors, int size) except -2:
|
787
|
+
return self._neighbors_unsafe(u, 1, neighbors, size)
|
788
|
+
|
789
|
+
cdef int in_neighbors_unsafe(self, int u, int *neighbors, int size) except -2:
|
790
|
+
return self._neighbors_unsafe(u, 0, neighbors, size)
|
791
|
+
|
792
|
+
cpdef int in_degree(self, int v) noexcept:
|
793
|
+
"""
|
794
|
+
Return the in-degree of ``v``
|
795
|
+
|
796
|
+
INPUT:
|
797
|
+
|
798
|
+
- ``v`` -- integer
|
799
|
+
|
800
|
+
EXAMPLES::
|
801
|
+
|
802
|
+
sage: from sage.graphs.base.sparse_graph import SparseGraph
|
803
|
+
sage: G = SparseGraph(5)
|
804
|
+
sage: G.add_arc(0,1)
|
805
|
+
sage: G.add_arc(1,2)
|
806
|
+
sage: G.add_arc(1,3)
|
807
|
+
sage: G.in_degree(0)
|
808
|
+
0
|
809
|
+
sage: G.in_degree(1)
|
810
|
+
1
|
811
|
+
"""
|
812
|
+
return self.in_degrees[v]
|
813
|
+
|
814
|
+
###################################
|
815
|
+
# Labeled arc functions
|
816
|
+
###################################
|
817
|
+
|
818
|
+
cdef inline int _add_arc_label_unsafe(self, int u, int v, int l, SparseGraphBTNode **ins_pt) except -1:
|
819
|
+
r"""
|
820
|
+
.. WARNING::
|
821
|
+
|
822
|
+
This method is for internal use only. Use :meth:`add_arc_label_unsafe` instead.
|
823
|
+
|
824
|
+
Add arc (u, v) with label l to only the ingoing or outgoing arcs
|
825
|
+
"""
|
826
|
+
cdef int i = (u * self.hash_length) + (v & self.hash_mask)
|
827
|
+
ins_pt = &ins_pt[i]
|
828
|
+
cdef int compared
|
829
|
+
cdef SparseGraphLLNode *label_ptr
|
830
|
+
while ins_pt[0]:
|
831
|
+
compared = compare(ins_pt[0].vertex, v)
|
832
|
+
if compared > 0:
|
833
|
+
ins_pt = &(ins_pt[0].left)
|
834
|
+
elif compared < 0:
|
835
|
+
ins_pt = &(ins_pt[0].right)
|
836
|
+
else:
|
837
|
+
break
|
838
|
+
if not ins_pt[0]:
|
839
|
+
ins_pt[0] = <SparseGraphBTNode *>check_malloc(sizeof(SparseGraphBTNode))
|
840
|
+
ins_pt[0].number = 0
|
841
|
+
ins_pt[0].vertex = v
|
842
|
+
ins_pt[0].left = NULL
|
843
|
+
ins_pt[0].right = NULL
|
844
|
+
ins_pt[0].labels = NULL
|
845
|
+
if l:
|
846
|
+
label_ptr = ins_pt[0].labels
|
847
|
+
while label_ptr and label_ptr.label != l:
|
848
|
+
label_ptr = label_ptr.next
|
849
|
+
if not label_ptr:
|
850
|
+
label_ptr = <SparseGraphLLNode *>check_malloc(sizeof(SparseGraphLLNode))
|
851
|
+
label_ptr.label = l
|
852
|
+
label_ptr.number = 1
|
853
|
+
label_ptr.next = ins_pt[0].labels
|
854
|
+
ins_pt[0].labels = label_ptr
|
855
|
+
else:
|
856
|
+
label_ptr.number += 1
|
857
|
+
else:
|
858
|
+
ins_pt[0].number += 1
|
859
|
+
|
860
|
+
cdef int add_arc_label_unsafe(self, int u, int v, int l) except -1:
|
861
|
+
"""
|
862
|
+
Add arc (u, v) to the graph with label l.
|
863
|
+
|
864
|
+
INPUT:
|
865
|
+
|
866
|
+
- ``u``, ``v`` -- nonnegative integers
|
867
|
+
|
868
|
+
- ``l`` -- positive integer label, or zero for no label
|
869
|
+
|
870
|
+
OUTPUT: ``0`` -- no error
|
871
|
+
"""
|
872
|
+
self._add_arc_label_unsafe(u, v, l, self.vertices)
|
873
|
+
if u != v or self.is_directed():
|
874
|
+
# We add the reverse copy only if u != v or graph is directed.
|
875
|
+
self._add_arc_label_unsafe(v, u, l, self.vertices_rev)
|
876
|
+
if self.vertices == self.vertices_rev:
|
877
|
+
# In case of an undirected graph, we have added two arcs.
|
878
|
+
self.in_degrees[u] += 1
|
879
|
+
self.out_degrees[v] += 1
|
880
|
+
self.num_arcs += 1
|
881
|
+
|
882
|
+
self.in_degrees[v] += 1
|
883
|
+
self.out_degrees[u] += 1
|
884
|
+
self.num_arcs += 1
|
885
|
+
|
886
|
+
def add_arc_label(self, int u, int v, int l=0):
|
887
|
+
"""
|
888
|
+
Add arc ``(u, v)`` to the graph with label ``l``.
|
889
|
+
|
890
|
+
INPUT:
|
891
|
+
|
892
|
+
- ``u``, ``v`` -- nonnegative integers, must be in ``self``
|
893
|
+
|
894
|
+
- ``l`` -- positive integer label, or zero for no label
|
895
|
+
|
896
|
+
EXAMPLES::
|
897
|
+
|
898
|
+
sage: from sage.graphs.base.sparse_graph import SparseGraph
|
899
|
+
sage: G = SparseGraph(5)
|
900
|
+
sage: G.add_arc_label(0,1)
|
901
|
+
sage: G.add_arc_label(4,7)
|
902
|
+
Traceback (most recent call last):
|
903
|
+
...
|
904
|
+
LookupError: vertex (7) is not a vertex of the graph
|
905
|
+
sage: G.has_arc(1,0)
|
906
|
+
False
|
907
|
+
sage: G.has_arc(0,1)
|
908
|
+
True
|
909
|
+
sage: G.add_arc_label(1,2,2)
|
910
|
+
sage: G.arc_label(1,2)
|
911
|
+
2
|
912
|
+
"""
|
913
|
+
self.check_vertex(u)
|
914
|
+
self.check_vertex(v)
|
915
|
+
if l < 0:
|
916
|
+
raise ValueError("Label ({0}) must be a nonnegative integer.".format(l))
|
917
|
+
self.add_arc_label_unsafe(u, v, l)
|
918
|
+
|
919
|
+
cdef int arc_label_unsafe(self, int u, int v) except -1:
|
920
|
+
"""
|
921
|
+
Retrieves the first label found associated with (u, v) (a positive
|
922
|
+
integer).
|
923
|
+
|
924
|
+
INPUT:
|
925
|
+
|
926
|
+
- ``u``, ``v`` -- integers from `0`, ..., `n-1`, where `n` is the
|
927
|
+
number of vertices
|
928
|
+
|
929
|
+
OUTPUT: one of
|
930
|
+
|
931
|
+
- positive integer -- indicates that there is a label on ``(u, v)``
|
932
|
+
|
933
|
+
- ``0`` -- either the arc ``(u, v)`` is unlabeled, or there is no arc at all.
|
934
|
+
"""
|
935
|
+
cdef int i = (u * self.hash_length) + (v & self.hash_mask)
|
936
|
+
cdef int compared
|
937
|
+
cdef SparseGraphBTNode *temp = self.vertices[i]
|
938
|
+
while temp:
|
939
|
+
compared = compare(temp.vertex, v)
|
940
|
+
if compared > 0:
|
941
|
+
temp = temp.left
|
942
|
+
elif compared < 0:
|
943
|
+
temp = temp.right
|
944
|
+
else:
|
945
|
+
break
|
946
|
+
if not temp or not temp.labels:
|
947
|
+
return 0
|
948
|
+
return temp.labels.label
|
949
|
+
|
950
|
+
cdef int all_arcs_unsafe(self, int u, int v, int *arc_labels, int size) except -1:
|
951
|
+
"""
|
952
|
+
Give the labels of all arcs (u, v).
|
953
|
+
|
954
|
+
INPUT:
|
955
|
+
|
956
|
+
- ``u``, ``v`` -- integers from `0`, ..., `n-1`, where `n` is the
|
957
|
+
number of vertices
|
958
|
+
- ``arc_labels`` -- must be a pointer to an (allocated) integer array
|
959
|
+
- ``size`` -- the length of the array
|
960
|
+
|
961
|
+
OUTPUT: integer; the number of arcs ``(u, v)``.
|
962
|
+
``-1`` -- indicates that the array has been filled with labels, but
|
963
|
+
there were more.
|
964
|
+
"""
|
965
|
+
cdef int i = (u * self.hash_length) + (v & self.hash_mask), j
|
966
|
+
cdef int compared, num_arcs
|
967
|
+
cdef SparseGraphBTNode *temp = self.vertices[i]
|
968
|
+
cdef SparseGraphLLNode *label
|
969
|
+
while temp:
|
970
|
+
compared = compare(temp.vertex, v)
|
971
|
+
if compared > 0:
|
972
|
+
temp = temp.left
|
973
|
+
elif compared < 0:
|
974
|
+
temp = temp.right
|
975
|
+
else: # temp.vertex == v:
|
976
|
+
break
|
977
|
+
if not temp:
|
978
|
+
return 0
|
979
|
+
j = 0
|
980
|
+
num_arcs = temp.number
|
981
|
+
while j < num_arcs and j < size:
|
982
|
+
arc_labels[j] = 0
|
983
|
+
j += 1
|
984
|
+
label = temp.labels
|
985
|
+
while label:
|
986
|
+
num_arcs += label.number
|
987
|
+
while j < num_arcs and j < size:
|
988
|
+
arc_labels[j] = label.label
|
989
|
+
j += 1
|
990
|
+
label = label.next
|
991
|
+
if j == size and label:
|
992
|
+
return -1
|
993
|
+
return num_arcs
|
994
|
+
|
995
|
+
cdef SparseGraphLLNode* arc_labels_unsafe(self, int u, int v) noexcept:
|
996
|
+
"""
|
997
|
+
Return the first label of arcs (u, v) or ``NULL`` if there are none.
|
998
|
+
|
999
|
+
INPUT:
|
1000
|
+
|
1001
|
+
- ``u``, ``v`` -- integers from `0`, ..., `n-1`, where `n` is the
|
1002
|
+
number of vertices
|
1003
|
+
|
1004
|
+
OUTPUT:
|
1005
|
+
|
1006
|
+
- a pointer to the first label or ``NULL`` if there are none
|
1007
|
+
"""
|
1008
|
+
cdef int i = (u * self.hash_length) + (v & self.hash_mask)
|
1009
|
+
cdef int compared
|
1010
|
+
cdef SparseGraphBTNode *temp = self.vertices[i]
|
1011
|
+
while temp:
|
1012
|
+
compared = compare(temp.vertex, v)
|
1013
|
+
if compared > 0:
|
1014
|
+
temp = temp.left
|
1015
|
+
elif compared < 0:
|
1016
|
+
temp = temp.right
|
1017
|
+
else: # temp.vertex == v:
|
1018
|
+
break
|
1019
|
+
if not temp:
|
1020
|
+
return NULL
|
1021
|
+
return temp.labels
|
1022
|
+
|
1023
|
+
cdef inline int _del_arc_label_unsafe(self, int u, int v, int l, SparseGraphBTNode **parent) noexcept:
|
1024
|
+
"""
|
1025
|
+
.. WARNING::
|
1026
|
+
|
1027
|
+
This method is for internal use only. Use :meth:`del_arc_label_unsafe` instead.
|
1028
|
+
|
1029
|
+
Delete an arc (u, v) with label l.
|
1030
|
+
|
1031
|
+
OUTPUT:
|
1032
|
+
|
1033
|
+
- 0 -- no error
|
1034
|
+
- 1 -- no arc with label l
|
1035
|
+
"""
|
1036
|
+
cdef int i = (u * self.hash_length) + (v & self.hash_mask)
|
1037
|
+
cdef SparseGraphBTNode **old_parent = parent
|
1038
|
+
parent = &parent[i]
|
1039
|
+
cdef int compared
|
1040
|
+
cdef SparseGraphLLNode **labels
|
1041
|
+
cdef SparseGraphLLNode *label
|
1042
|
+
while parent[0]:
|
1043
|
+
compared = compare(parent[0].vertex, v)
|
1044
|
+
if compared > 0:
|
1045
|
+
parent = &(parent[0].left)
|
1046
|
+
elif compared < 0:
|
1047
|
+
parent = &(parent[0].right)
|
1048
|
+
else: # if parent[0].vertex == v:
|
1049
|
+
break
|
1050
|
+
if not parent[0]:
|
1051
|
+
return 1 # indicate an error
|
1052
|
+
if l == 0:
|
1053
|
+
if parent[0].number > 1:
|
1054
|
+
parent[0].number -= 1
|
1055
|
+
elif parent[0].number == 1:
|
1056
|
+
if not parent[0].labels:
|
1057
|
+
self._del_arc_unsafe(u, v, old_parent)
|
1058
|
+
return 0
|
1059
|
+
else:
|
1060
|
+
parent[0].number -= 1
|
1061
|
+
else:
|
1062
|
+
return 1 # indicate an error
|
1063
|
+
else:
|
1064
|
+
labels = &(parent[0].labels)
|
1065
|
+
while labels[0] and labels[0].label != l:
|
1066
|
+
labels = &(labels[0].next)
|
1067
|
+
if not labels[0]:
|
1068
|
+
return 1
|
1069
|
+
label = labels[0]
|
1070
|
+
if label.number > 1:
|
1071
|
+
label.number -= 1
|
1072
|
+
else:
|
1073
|
+
labels[0] = labels[0].next
|
1074
|
+
sig_free(label)
|
1075
|
+
if labels == &(parent[0].labels) and not labels[0] and parent[0].number == 0:
|
1076
|
+
# here we need to delete an "empty" binary tree node
|
1077
|
+
self._del_arc_unsafe(u, v, old_parent)
|
1078
|
+
|
1079
|
+
cdef int del_arc_label_unsafe(self, int u, int v, int l) except -1:
|
1080
|
+
"""
|
1081
|
+
Delete an arc (u, v) with label l.
|
1082
|
+
|
1083
|
+
INPUT:
|
1084
|
+
|
1085
|
+
- ``u``, ``v`` -- integers from `0`, ..., `n-1`, where `n` is the
|
1086
|
+
number of vertices
|
1087
|
+
|
1088
|
+
- ``l`` -- positive integer label, or zero for no label
|
1089
|
+
|
1090
|
+
OUTPUT: one of
|
1091
|
+
|
1092
|
+
- ``0`` -- no error
|
1093
|
+
|
1094
|
+
- ``1`` -- no arc with label ``l``
|
1095
|
+
"""
|
1096
|
+
if self._del_arc_label_unsafe(u, v, l, self.vertices):
|
1097
|
+
return 1 # indicate an error
|
1098
|
+
|
1099
|
+
if u != v or self.is_directed():
|
1100
|
+
# We remove the reverse copy only if u != v or graph is directed.
|
1101
|
+
self._del_arc_label_unsafe(v, u, l, self.vertices_rev)
|
1102
|
+
if self.vertices == self.vertices_rev:
|
1103
|
+
# In case of an undirected graph, we have removed two arcs.
|
1104
|
+
self.in_degrees[u] -= 1
|
1105
|
+
self.out_degrees[v] -= 1
|
1106
|
+
self.num_arcs -= 1
|
1107
|
+
|
1108
|
+
self.in_degrees[v] -= 1
|
1109
|
+
self.out_degrees[u] -= 1
|
1110
|
+
self.num_arcs -= 1
|
1111
|
+
|
1112
|
+
cdef int has_arc_label_unsafe(self, int u, int v, int l) except -1:
|
1113
|
+
"""
|
1114
|
+
Indicates whether there is an arc (u, v) with label l.
|
1115
|
+
|
1116
|
+
INPUT:
|
1117
|
+
|
1118
|
+
- ``u``, ``v`` -- integers from `0`, ..., `n-1`, where `n` is the
|
1119
|
+
number of vertices
|
1120
|
+
|
1121
|
+
- ``l`` -- positive integer label, or zero for no label, or ``-1`` for any label
|
1122
|
+
|
1123
|
+
OUTPUT: one of
|
1124
|
+
|
1125
|
+
- ``0`` -- false
|
1126
|
+
|
1127
|
+
- ``1`` -- true
|
1128
|
+
"""
|
1129
|
+
cdef int i = (u * self.hash_length) + (v & self.hash_mask)
|
1130
|
+
cdef int compared
|
1131
|
+
cdef SparseGraphBTNode *temp = self.vertices[i]
|
1132
|
+
cdef SparseGraphLLNode *label
|
1133
|
+
while temp:
|
1134
|
+
compared = compare(temp.vertex, v)
|
1135
|
+
if compared > 0:
|
1136
|
+
temp = temp.left
|
1137
|
+
elif compared < 0:
|
1138
|
+
temp = temp.right
|
1139
|
+
else: # if temp.vertex == v:
|
1140
|
+
break
|
1141
|
+
if not temp:
|
1142
|
+
return 0
|
1143
|
+
if l == -1:
|
1144
|
+
return 1
|
1145
|
+
if l == 0 and temp.number > 0:
|
1146
|
+
return 1
|
1147
|
+
label = temp.labels
|
1148
|
+
while label:
|
1149
|
+
if label.label == l:
|
1150
|
+
return 1
|
1151
|
+
label = label.next
|
1152
|
+
return 0
|
1153
|
+
|
1154
|
+
|
1155
|
+
##############################
|
1156
|
+
# Further tests. Unit tests for methods, functions, classes defined with cdef.
|
1157
|
+
##############################
|
1158
|
+
|
1159
|
+
def _test_adjacency_sequence_out():
|
1160
|
+
"""
|
1161
|
+
Randomly test the method ``SparseGraph.adjacency_sequence_out()``. No output
|
1162
|
+
indicates that no errors were found.
|
1163
|
+
|
1164
|
+
TESTS::
|
1165
|
+
|
1166
|
+
sage: from sage.graphs.base.sparse_graph import _test_adjacency_sequence_out
|
1167
|
+
sage: _test_adjacency_sequence_out() # long time
|
1168
|
+
"""
|
1169
|
+
from sage.graphs.digraph import DiGraph
|
1170
|
+
from sage.graphs.graph_generators import GraphGenerators
|
1171
|
+
from sage.misc.prandom import randint, random
|
1172
|
+
low = 0
|
1173
|
+
high = 1000
|
1174
|
+
n = 0
|
1175
|
+
while not n:
|
1176
|
+
randg = DiGraph(GraphGenerators().RandomGNP(randint(low, high), random()))
|
1177
|
+
n = randg.order()
|
1178
|
+
# set all labels to 0
|
1179
|
+
E = [(u, v, 0) for u, v in randg.edges(sort=True, labels=False)]
|
1180
|
+
cdef SparseGraph g = SparseGraph(n,
|
1181
|
+
verts=randg.vertices(sort=False),
|
1182
|
+
arcs=E)
|
1183
|
+
assert g.num_verts == randg.order(), (
|
1184
|
+
"Graph order mismatch: %s vs. %s" % (g.num_verts, randg.order()))
|
1185
|
+
assert g.num_arcs == randg.size(), (
|
1186
|
+
"Graph size mismatch: %s vs. %s" % (g.num_arcs, randg.size()))
|
1187
|
+
M = randg.adjacency_matrix()
|
1188
|
+
cdef int *V = <int *>check_allocarray(n, sizeof(int))
|
1189
|
+
cdef int i = 0
|
1190
|
+
for v in randg.vertex_iterator():
|
1191
|
+
V[i] = v
|
1192
|
+
i += 1
|
1193
|
+
cdef int *seq = <int *>check_allocarray(n, sizeof(int))
|
1194
|
+
for i in range(randint(50, 101)):
|
1195
|
+
u = randint(low, n - 1)
|
1196
|
+
g.adjacency_sequence_out(n, V, u, seq)
|
1197
|
+
A = [seq[k] for k in range(n)]
|
1198
|
+
try:
|
1199
|
+
assert A == list(M[u])
|
1200
|
+
except AssertionError:
|
1201
|
+
sig_free(V)
|
1202
|
+
sig_free(seq)
|
1203
|
+
raise AssertionError("Graph adjacency mismatch")
|
1204
|
+
sig_free(seq)
|
1205
|
+
sig_free(V)
|
1206
|
+
|
1207
|
+
|
1208
|
+
###########################################
|
1209
|
+
# Sparse Graph Backend
|
1210
|
+
###########################################
|
1211
|
+
|
1212
|
+
cdef class SparseGraphBackend(CGraphBackend):
|
1213
|
+
"""
|
1214
|
+
Backend for Sage graphs using SparseGraphs.
|
1215
|
+
|
1216
|
+
::
|
1217
|
+
|
1218
|
+
sage: from sage.graphs.base.sparse_graph import SparseGraphBackend
|
1219
|
+
|
1220
|
+
This class is only intended for use by the Sage Graph and DiGraph class.
|
1221
|
+
If you are interested in using a SparseGraph, you probably want to do
|
1222
|
+
something like the following example, which creates a Sage Graph instance
|
1223
|
+
which wraps a SparseGraph object::
|
1224
|
+
|
1225
|
+
sage: G = Graph(30, sparse=True)
|
1226
|
+
sage: G.add_edges([(0,1), (0,3), (4,5), (9, 23)])
|
1227
|
+
sage: G.edges(sort=True, labels=False)
|
1228
|
+
[(0, 1), (0, 3), (4, 5), (9, 23)]
|
1229
|
+
|
1230
|
+
Note that Sage graphs using the backend are more flexible than SparseGraphs
|
1231
|
+
themselves. This is because SparseGraphs (by design) do not deal with Python
|
1232
|
+
objects::
|
1233
|
+
|
1234
|
+
sage: G.add_vertex((0,1,2))
|
1235
|
+
sage: sorted(list(G),
|
1236
|
+
....: key=lambda x: (isinstance(x, tuple), x))
|
1237
|
+
[0,
|
1238
|
+
...
|
1239
|
+
29,
|
1240
|
+
(0, 1, 2)]
|
1241
|
+
sage: from sage.graphs.base.sparse_graph import SparseGraph
|
1242
|
+
sage: SG = SparseGraph(30)
|
1243
|
+
sage: SG.add_vertex((0,1,2))
|
1244
|
+
Traceback (most recent call last):
|
1245
|
+
...
|
1246
|
+
TypeError: an integer is required
|
1247
|
+
"""
|
1248
|
+
|
1249
|
+
def __init__(self, int n, directed=True):
|
1250
|
+
"""
|
1251
|
+
Initialize a sparse graph with n vertices.
|
1252
|
+
|
1253
|
+
EXAMPLES::
|
1254
|
+
|
1255
|
+
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
|
1256
|
+
sage: D.add_edge(0,1,None,False)
|
1257
|
+
sage: list(D.iterator_edges(range(9), True))
|
1258
|
+
[(0, 1, None)]
|
1259
|
+
"""
|
1260
|
+
self._cg = SparseGraph(n, directed=directed)
|
1261
|
+
self._directed = directed
|
1262
|
+
self.vertex_labels = {}
|
1263
|
+
self.vertex_ints = {}
|
1264
|
+
self.edge_labels = {}
|
1265
|
+
self.edge_labels_max = 1
|
1266
|
+
self.edge_labels_available_ids = []
|
1267
|
+
|
1268
|
+
cdef inline int new_edge_label(self, object l) except -1:
|
1269
|
+
"""
|
1270
|
+
Return a new unique int representing the arbitrary label l.
|
1271
|
+
"""
|
1272
|
+
if l is None:
|
1273
|
+
return 0
|
1274
|
+
|
1275
|
+
cdef int l_int
|
1276
|
+
if self.edge_labels_available_ids:
|
1277
|
+
l_int = self.edge_labels_available_ids.pop(-1)
|
1278
|
+
else:
|
1279
|
+
l_int = self.edge_labels_max
|
1280
|
+
self.edge_labels_max += 1
|
1281
|
+
|
1282
|
+
self.edge_labels[l_int] = l
|
1283
|
+
return l_int
|
1284
|
+
|
1285
|
+
cdef inline int free_edge_label(self, int l_int) except -1:
|
1286
|
+
"""
|
1287
|
+
Free the label corresponding to ``l_int``.
|
1288
|
+
|
1289
|
+
Usually called after deleting an edge.
|
1290
|
+
"""
|
1291
|
+
if l_int:
|
1292
|
+
self.edge_labels.pop(l_int)
|
1293
|
+
self.edge_labels_available_ids.append(l_int)
|
1294
|
+
|
1295
|
+
def get_edge_label(self, object u, object v):
|
1296
|
+
"""
|
1297
|
+
Return the edge label for ``(u, v)``.
|
1298
|
+
|
1299
|
+
INPUT:
|
1300
|
+
|
1301
|
+
- ``u``, ``v`` -- the vertices of the edge
|
1302
|
+
|
1303
|
+
EXAMPLES::
|
1304
|
+
|
1305
|
+
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
|
1306
|
+
sage: D.add_edges([(0,1,1), (2,3,2), (4,5,3), (5,6,2)], False)
|
1307
|
+
sage: list(D.iterator_edges(range(9), True))
|
1308
|
+
[(0, 1, 1), (2, 3, 2), (4, 5, 3), (5, 6, 2)]
|
1309
|
+
sage: D.get_edge_label(3,2)
|
1310
|
+
2
|
1311
|
+
"""
|
1312
|
+
cdef int l_int
|
1313
|
+
if not self.has_vertex(u):
|
1314
|
+
raise LookupError("({0}) is not a vertex of the graph.".format(repr(u)))
|
1315
|
+
if not self.has_vertex(v):
|
1316
|
+
raise LookupError("({0}) is not a vertex of the graph.".format(repr(v)))
|
1317
|
+
cdef int u_int = self.get_vertex(u)
|
1318
|
+
cdef int v_int = self.get_vertex(v)
|
1319
|
+
if not self._cg.has_arc_unsafe(u_int, v_int):
|
1320
|
+
raise LookupError("({0}, {1}) is not an edge of the graph.".format(repr(u), repr(v)))
|
1321
|
+
if self.multiple_edges(None):
|
1322
|
+
return [self.edge_labels[l_int] if l_int != 0 else None
|
1323
|
+
for l_int in self._cg.all_arcs(u_int, v_int)]
|
1324
|
+
l_int = self._cg.arc_label(u_int, v_int)
|
1325
|
+
return self.edge_labels[l_int] if l_int else None
|
1326
|
+
|
1327
|
+
def has_edge(self, object u, object v, object l):
|
1328
|
+
"""
|
1329
|
+
Return whether this graph has edge ``(u,v)`` with label ``l``. If ``l``
|
1330
|
+
is ``None``, return whether this graph has an edge ``(u,v)`` with any
|
1331
|
+
label.
|
1332
|
+
|
1333
|
+
INPUT:
|
1334
|
+
|
1335
|
+
- ``u``, ``v`` -- the vertices of the edge
|
1336
|
+
|
1337
|
+
- ``l`` -- the edge label, or ``None``
|
1338
|
+
|
1339
|
+
EXAMPLES::
|
1340
|
+
|
1341
|
+
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
|
1342
|
+
sage: D.add_edges([(0,1), (2,3), (4,5), (5,6)], False)
|
1343
|
+
sage: D.has_edge(0,1,None)
|
1344
|
+
True
|
1345
|
+
"""
|
1346
|
+
cdef int u_int = self.get_vertex_checked(u)
|
1347
|
+
cdef int v_int = self.get_vertex_checked(v)
|
1348
|
+
if u_int == -1 or v_int == -1:
|
1349
|
+
return False
|
1350
|
+
return self._has_labeled_edge_unsafe(u_int, v_int, l)
|
1351
|
+
|
1352
|
+
cdef inline bint _has_labeled_edge_unsafe(self, int u_int, int v_int, object l) except -1:
|
1353
|
+
"""
|
1354
|
+
Return whether ``self`` has an arc specified by indices of the vertices
|
1355
|
+
and an arc label.
|
1356
|
+
"""
|
1357
|
+
cdef SparseGraph cg = self.cg()
|
1358
|
+
if l is None:
|
1359
|
+
return 1 == cg.has_arc_unsafe(u_int, v_int)
|
1360
|
+
cdef SparseGraphLLNode* label = cg.arc_labels_unsafe(u_int, v_int)
|
1361
|
+
while label:
|
1362
|
+
if label.label and self.edge_labels[label.label] == l:
|
1363
|
+
return True
|
1364
|
+
label = label.next
|
1365
|
+
return False
|
1366
|
+
|
1367
|
+
def multiple_edges(self, new):
|
1368
|
+
"""
|
1369
|
+
Get/set whether or not ``self`` allows multiple edges.
|
1370
|
+
|
1371
|
+
INPUT:
|
1372
|
+
|
1373
|
+
- ``new`` -- boolean (to set) or ``None`` (to get)
|
1374
|
+
|
1375
|
+
EXAMPLES::
|
1376
|
+
|
1377
|
+
sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
|
1378
|
+
sage: G.multiple_edges(True)
|
1379
|
+
sage: G.multiple_edges(None)
|
1380
|
+
True
|
1381
|
+
sage: G.multiple_edges(False)
|
1382
|
+
sage: G.multiple_edges(None)
|
1383
|
+
False
|
1384
|
+
sage: G.add_edge(0,1,0,True)
|
1385
|
+
sage: G.add_edge(0,1,0,True)
|
1386
|
+
sage: list(G.iterator_out_edges(range(9), True))
|
1387
|
+
[(0, 1, 0)]
|
1388
|
+
"""
|
1389
|
+
if new is None:
|
1390
|
+
return self._multiple_edges
|
1391
|
+
self._multiple_edges = bool(new)
|
1392
|
+
|
1393
|
+
def set_edge_label(self, object u, object v, object l, bint directed):
|
1394
|
+
"""
|
1395
|
+
Label the edge ``(u,v)`` by ``l``.
|
1396
|
+
|
1397
|
+
INPUT:
|
1398
|
+
|
1399
|
+
- ``u``, ``v`` -- the vertices of the edge
|
1400
|
+
|
1401
|
+
- ``l`` -- the edge label
|
1402
|
+
|
1403
|
+
- ``directed`` -- if ``False``, also set ``(v,u)`` with label ``l``
|
1404
|
+
|
1405
|
+
EXAMPLES::
|
1406
|
+
|
1407
|
+
sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
|
1408
|
+
sage: G.add_edge(1,2,None,True)
|
1409
|
+
sage: G.set_edge_label(1,2,'a',True)
|
1410
|
+
sage: list(G.iterator_out_edges(range(9), True))
|
1411
|
+
[(1, 2, 'a')]
|
1412
|
+
|
1413
|
+
Note that it fails silently if there is no edge there::
|
1414
|
+
|
1415
|
+
sage: G.set_edge_label(2,1,'b',True)
|
1416
|
+
sage: list(G.iterator_out_edges(range(9), True))
|
1417
|
+
[(1, 2, 'a')]
|
1418
|
+
"""
|
1419
|
+
if not self.has_edge(u, v, None):
|
1420
|
+
return
|
1421
|
+
if self.multiple_edges(None):
|
1422
|
+
if len(self.get_edge_label(u, v)) > 1:
|
1423
|
+
raise RuntimeError("Cannot set edge label, since there are multiple edges from %s to %s." % (u, v))
|
1424
|
+
# now we know there is exactly one edge from u to v
|
1425
|
+
cdef int l_int, ll_int
|
1426
|
+
if l is None:
|
1427
|
+
l_int = 0
|
1428
|
+
else:
|
1429
|
+
l_int = self.new_edge_label(l)
|
1430
|
+
cdef int u_int = self.get_vertex(u)
|
1431
|
+
cdef int v_int = self.get_vertex(v)
|
1432
|
+
if not (<SparseGraph>self._cg).has_arc_unsafe(u_int, v_int):
|
1433
|
+
return
|
1434
|
+
ll_int = (<SparseGraph>self._cg).arc_label_unsafe(u_int, v_int)
|
1435
|
+
if ll_int:
|
1436
|
+
self.edge_labels.pop(ll_int)
|
1437
|
+
self.edge_labels_available_ids.append(ll_int)
|
1438
|
+
self._cg.del_arc_label(u_int, v_int, ll_int)
|
1439
|
+
self._cg.add_arc_label(u_int, v_int, l_int)
|
1440
|
+
if not directed and self._directed and v_int != u_int:
|
1441
|
+
self._cg.del_arc_label(v_int, u_int, ll_int)
|
1442
|
+
self._cg.add_arc_label(v_int, u_int, l_int)
|
1443
|
+
|
1444
|
+
def _iterator_edges(self, object vertices, const bint labels, const int modus=0):
|
1445
|
+
"""
|
1446
|
+
Iterate over the edges incident to a sequence of vertices.
|
1447
|
+
|
1448
|
+
INPUT:
|
1449
|
+
|
1450
|
+
- ``vertices`` -- a list of vertex labels
|
1451
|
+
|
1452
|
+
- ``labels`` -- boolean, whether to return labels as well
|
1453
|
+
|
1454
|
+
- ``modus`` -- integer representing the modus of the iterator:
|
1455
|
+
- ``0`` -- outgoing edges
|
1456
|
+
- ``1`` -- ingoing edges
|
1457
|
+
- ``2`` -- unsorted edges of an undirected graph
|
1458
|
+
- ``3`` -- sorted edges of an undirected graph
|
1459
|
+
|
1460
|
+
EXAMPLES::
|
1461
|
+
|
1462
|
+
sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9)
|
1463
|
+
sage: G.add_edge(1, 2, None, False)
|
1464
|
+
sage: list(G._iterator_edges(range(9), False, 3))
|
1465
|
+
[(1, 2)]
|
1466
|
+
sage: list(G._iterator_edges(range(9), True, 3))
|
1467
|
+
[(1, 2, None)]
|
1468
|
+
|
1469
|
+
::
|
1470
|
+
|
1471
|
+
sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9)
|
1472
|
+
sage: G.add_edge(1, 2, None, True)
|
1473
|
+
sage: list(G.iterator_in_edges([1], False))
|
1474
|
+
[]
|
1475
|
+
sage: list(G.iterator_in_edges([2], False))
|
1476
|
+
[(1, 2)]
|
1477
|
+
sage: list(G.iterator_in_edges([2], True))
|
1478
|
+
[(1, 2, None)]
|
1479
|
+
|
1480
|
+
::
|
1481
|
+
|
1482
|
+
sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9)
|
1483
|
+
sage: G.add_edge(1, 2, None, True)
|
1484
|
+
sage: list(G.iterator_out_edges([2], False))
|
1485
|
+
[]
|
1486
|
+
sage: list(G.iterator_out_edges([1], False))
|
1487
|
+
[(1, 2)]
|
1488
|
+
sage: list(G.iterator_out_edges([1], True))
|
1489
|
+
[(1, 2, None)]
|
1490
|
+
"""
|
1491
|
+
cdef object u, v, l, v_copy
|
1492
|
+
cdef int u_int, v_int, l_int, foo
|
1493
|
+
cdef CGraph cg = self.cg()
|
1494
|
+
cdef list b_vertices_2, all_arc_labels
|
1495
|
+
cdef FrozenBitset b_vertices
|
1496
|
+
cdef bint out = modus == 0
|
1497
|
+
|
1498
|
+
cdef int vertices_case
|
1499
|
+
cdef object it
|
1500
|
+
|
1501
|
+
cdef int r
|
1502
|
+
cdef int maxdegree = 0
|
1503
|
+
cdef int *degrees = NULL
|
1504
|
+
if out:
|
1505
|
+
degrees = cg.out_degrees
|
1506
|
+
else:
|
1507
|
+
degrees = cg.in_degrees
|
1508
|
+
for v_int in range(cg.active_vertices.size):
|
1509
|
+
if bitset_in(cg.active_vertices, v_int):
|
1510
|
+
maxdegree = max(degrees[v_int], maxdegree)
|
1511
|
+
cdef MemoryAllocator mem = MemoryAllocator()
|
1512
|
+
cdef SparseGraphBTNode **neighbors = <SparseGraphBTNode **>mem.allocarray(maxdegree, sizeof(SparseGraphBTNode *))
|
1513
|
+
|
1514
|
+
if not isinstance(vertices, list):
|
1515
|
+
# ALL edges
|
1516
|
+
it = self.iterator_verts(None)
|
1517
|
+
vertices_case = 0
|
1518
|
+
|
1519
|
+
elif not vertices:
|
1520
|
+
return
|
1521
|
+
|
1522
|
+
elif len(vertices) == 1:
|
1523
|
+
# One vertex
|
1524
|
+
vertices_case = 1
|
1525
|
+
v_int = -1
|
1526
|
+
|
1527
|
+
else:
|
1528
|
+
# Several vertices (nonempty list)
|
1529
|
+
vertices_case = 2
|
1530
|
+
b_vertices_2 = [self.get_vertex_checked(v) for v in vertices]
|
1531
|
+
try:
|
1532
|
+
b_vertices = FrozenBitset(foo for foo in b_vertices_2 if foo >= 0)
|
1533
|
+
except ValueError:
|
1534
|
+
# Avoiding "Bitset must not be empty"
|
1535
|
+
# in case none of the vertices is active.
|
1536
|
+
return
|
1537
|
+
it = iter(b_vertices)
|
1538
|
+
|
1539
|
+
while True:
|
1540
|
+
# Think of this as a loop through ``vertices``.
|
1541
|
+
# We pick the next vertex according to three cases.
|
1542
|
+
|
1543
|
+
if vertices_case == 0:
|
1544
|
+
# ALL edges
|
1545
|
+
try:
|
1546
|
+
v = next(it)
|
1547
|
+
v_int = self.get_vertex(v)
|
1548
|
+
except StopIteration:
|
1549
|
+
return
|
1550
|
+
|
1551
|
+
elif vertices_case == 1:
|
1552
|
+
# One vertex
|
1553
|
+
if v_int != -1:
|
1554
|
+
# Only visit one vertex once.
|
1555
|
+
return
|
1556
|
+
v = vertices[0]
|
1557
|
+
v_int = self.get_vertex_checked(v)
|
1558
|
+
if v_int == -1:
|
1559
|
+
return
|
1560
|
+
|
1561
|
+
else:
|
1562
|
+
# Several vertices (nonempty list)
|
1563
|
+
try:
|
1564
|
+
v_int = -1
|
1565
|
+
while v_int == -1:
|
1566
|
+
v_int = next(it)
|
1567
|
+
v = self.vertex_label(v_int)
|
1568
|
+
except StopIteration:
|
1569
|
+
return
|
1570
|
+
|
1571
|
+
# WARNING
|
1572
|
+
# If you modify this, you must keep in mind the documentation in the
|
1573
|
+
# corresponding method in ``generic_graph.py`` in the method ``edge_iterator``.
|
1574
|
+
# E.g. code assumes that you can use an iterator to relabel or delete arcs.
|
1575
|
+
|
1576
|
+
r = self._cg._neighbors_BTNode_unsafe(v_int, out, neighbors, maxdegree)
|
1577
|
+
for i in range(r):
|
1578
|
+
u_int = neighbors[i].vertex
|
1579
|
+
if neighbors[i].number:
|
1580
|
+
l_int = 0
|
1581
|
+
else:
|
1582
|
+
l_int = neighbors[i].labels.label
|
1583
|
+
if (modus < 2 or # Do not delete duplicates.
|
1584
|
+
vertices_case == 1 or # Only one vertex, so no duplicates.
|
1585
|
+
u_int >= v_int or # We visit if u_int >= v_int ...
|
1586
|
+
(vertices_case == 2 and
|
1587
|
+
u_int < b_vertices.capacity() and
|
1588
|
+
not bitset_in(b_vertices._bitset, u_int))): # ... or if u_int is not in ``vertices``.
|
1589
|
+
u = self.vertex_label(u_int)
|
1590
|
+
if labels:
|
1591
|
+
l = self.edge_labels[l_int] if l_int else None
|
1592
|
+
|
1593
|
+
# Yield the arc/arcs.
|
1594
|
+
v_copy = v
|
1595
|
+
if _reorganize_edge(v, u, modus):
|
1596
|
+
u, v = v, u
|
1597
|
+
|
1598
|
+
if not self._multiple_edges:
|
1599
|
+
if labels:
|
1600
|
+
yield (v, u, l)
|
1601
|
+
else:
|
1602
|
+
yield (v, u)
|
1603
|
+
else:
|
1604
|
+
if out:
|
1605
|
+
all_arc_labels = cg.all_arcs(v_int, u_int)
|
1606
|
+
else:
|
1607
|
+
all_arc_labels = cg.all_arcs(u_int, v_int)
|
1608
|
+
|
1609
|
+
for l_int in all_arc_labels:
|
1610
|
+
if labels:
|
1611
|
+
l = self.edge_labels[l_int] if l_int else None
|
1612
|
+
yield (v, u, l)
|
1613
|
+
else:
|
1614
|
+
yield (v, u)
|
1615
|
+
v = v_copy
|
1616
|
+
|
1617
|
+
##############################
|
1618
|
+
# Functions to simplify edge iterator.
|
1619
|
+
##############################
|
1620
|
+
|
1621
|
+
cdef inline bint _reorganize_edge(object v, object u, const int modus) noexcept:
|
1622
|
+
"""
|
1623
|
+
Return ``True`` if ``v`` and ``u`` should be exchanged according to the modus.
|
1624
|
+
|
1625
|
+
INPUT:
|
1626
|
+
|
1627
|
+
- ``v`` -- vertex
|
1628
|
+
|
1629
|
+
- ``u`` -- vertex
|
1630
|
+
|
1631
|
+
- ``modus`` -- integer representing the modus of the iterator:
|
1632
|
+
- ``0`` -- outgoing edges
|
1633
|
+
- ``1`` -- ingoing edges
|
1634
|
+
- ``2`` -- unsorted edges of an undirected graph
|
1635
|
+
- ``3`` -- sorted edges of an undirected graph
|
1636
|
+
|
1637
|
+
OUTPUT: Boolean according the modus:
|
1638
|
+
|
1639
|
+
- ``modus == 0`` -- ``False``
|
1640
|
+
- ``modus == 1`` -- ``True``
|
1641
|
+
- ``modus == 2`` -- ``True
|
1642
|
+
- ``modus == 3`` -- ``False if v <= u else True``
|
1643
|
+
"""
|
1644
|
+
if modus == 0:
|
1645
|
+
return False
|
1646
|
+
elif modus == 3:
|
1647
|
+
try:
|
1648
|
+
if v <= u:
|
1649
|
+
return False
|
1650
|
+
except TypeError:
|
1651
|
+
pass
|
1652
|
+
|
1653
|
+
return True
|