passagemath-graphs 10.5.10__cp39-cp39-macosx_14_0_arm64.whl → 10.5.43__cp39-cp39-macosx_14_0_arm64.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.5.10.dist-info → passagemath_graphs-10.5.43.dist-info}/METADATA +126 -30
- passagemath_graphs-10.5.43.dist-info/RECORD +256 -0
- {passagemath_graphs-10.5.10.dist-info → passagemath_graphs-10.5.43.dist-info}/WHEEL +2 -1
- passagemath_graphs.dylibs/libgmp.10.dylib +0 -0
- sage/all__sagemath_graphs.py +5 -0
- sage/combinat/abstract_tree.py +1 -1
- sage/combinat/binary_tree.py +1 -1
- sage/combinat/cluster_algebra_quiver/all.py +1 -1
- sage/combinat/cluster_algebra_quiver/cluster_seed.py +28 -24
- sage/combinat/cluster_algebra_quiver/interact.py +4 -0
- sage/combinat/designs/MOLS_handbook_data.py +5 -5
- sage/combinat/designs/bibd.py +10 -9
- sage/combinat/designs/covering_array.py +3 -3
- sage/combinat/designs/covering_design.py +2 -1
- sage/combinat/designs/database.py +11 -10
- sage/combinat/designs/designs_pyx.cpython-39-darwin.so +0 -0
- sage/combinat/designs/designs_pyx.pyx +13 -45
- sage/combinat/designs/difference_family.py +6 -6
- sage/combinat/designs/difference_matrices.py +1 -1
- sage/combinat/designs/evenly_distributed_sets.cpython-39-darwin.so +0 -0
- sage/combinat/designs/evenly_distributed_sets.pyx +15 -22
- sage/combinat/designs/ext_rep.py +9 -14
- sage/combinat/designs/gen_quadrangles_with_spread.cpython-39-darwin.so +0 -0
- sage/combinat/designs/gen_quadrangles_with_spread.pyx +1 -1
- sage/combinat/designs/group_divisible_designs.py +1 -1
- sage/combinat/designs/incidence_structures.py +8 -8
- sage/combinat/designs/latin_squares.py +1 -1
- sage/combinat/designs/orthogonal_arrays_build_recursive.py +8 -7
- sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-39-darwin.so +0 -0
- sage/combinat/designs/resolvable_bibd.py +1 -1
- sage/combinat/designs/steiner_quadruple_systems.py +1 -1
- sage/combinat/designs/subhypergraph_search.cpython-39-darwin.so +0 -0
- sage/combinat/designs/subhypergraph_search.pyx +9 -9
- sage/combinat/finite_state_machine_generators.py +2 -2
- sage/combinat/graph_path.py +3 -3
- sage/combinat/interval_posets.py +10 -10
- sage/combinat/ordered_tree.py +1 -1
- sage/combinat/posets/cartesian_product.py +1 -1
- sage/combinat/posets/d_complete.py +1 -1
- sage/combinat/posets/forest.py +1 -1
- sage/combinat/posets/hasse_cython.cpython-39-darwin.so +0 -0
- sage/combinat/posets/hasse_diagram.py +8 -6
- sage/combinat/posets/incidence_algebras.py +8 -8
- sage/combinat/posets/lattices.py +28 -4
- sage/combinat/posets/linear_extension_iterator.cpython-39-darwin.so +0 -0
- sage/combinat/posets/linear_extension_iterator.pyx +2 -0
- sage/combinat/posets/linear_extensions.py +7 -16
- sage/combinat/posets/moebius_algebra.py +1 -1
- sage/combinat/posets/poset_examples.py +1 -1
- sage/combinat/posets/posets.py +54 -56
- sage/combinat/rooted_tree.py +3 -3
- sage/combinat/tamari_lattices.py +1 -1
- 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/asteroidal_triples.cpython-39-darwin.so +0 -0
- sage/graphs/base/boost_graph.cpython-39-darwin.so +0 -0
- sage/graphs/base/boost_graph.pxd +1 -1
- sage/graphs/base/boost_graph.pyx +1 -1
- sage/graphs/base/c_graph.cpython-39-darwin.so +0 -0
- sage/graphs/base/c_graph.pxd +4 -4
- sage/graphs/base/c_graph.pyx +270 -184
- sage/graphs/base/dense_graph.cpython-39-darwin.so +0 -0
- sage/graphs/base/graph_backends.cpython-39-darwin.so +0 -0
- sage/graphs/base/sparse_graph.cpython-39-darwin.so +0 -0
- sage/graphs/base/static_dense_graph.cpython-39-darwin.so +0 -0
- sage/graphs/base/static_sparse_backend.cpython-39-darwin.so +0 -0
- sage/graphs/base/static_sparse_backend.pyx +93 -6
- sage/graphs/base/static_sparse_graph.cpython-39-darwin.so +0 -0
- sage/graphs/base/static_sparse_graph.pyx +1 -1
- sage/graphs/bipartite_graph.py +0 -1
- sage/graphs/centrality.cpython-39-darwin.so +0 -0
- sage/graphs/centrality.pyx +0 -0
- sage/graphs/comparability.cpython-39-darwin.so +0 -0
- sage/graphs/comparability.pyx +172 -138
- sage/graphs/connectivity.cpython-39-darwin.so +0 -0
- sage/graphs/connectivity.pyx +194 -18
- sage/graphs/convexity_properties.cpython-39-darwin.so +0 -0
- sage/graphs/digraph_generators.py +118 -74
- sage/graphs/distances_all_pairs.cpython-39-darwin.so +0 -0
- sage/graphs/distances_all_pairs.pyx +145 -27
- sage/graphs/edge_connectivity.cpython-39-darwin.so +0 -0
- sage/graphs/generators/basic.py +471 -130
- sage/graphs/generators/distance_regular.cpython-39-darwin.so +0 -0
- sage/graphs/generators/distance_regular.pyx +12 -12
- sage/graphs/generators/families.py +2 -2
- sage/graphs/generators/random.py +8 -13
- sage/graphs/generators/smallgraphs.py +12 -11
- sage/graphs/generic_graph.py +687 -265
- sage/graphs/generic_graph_pyx.cpython-39-darwin.so +0 -0
- sage/graphs/genus.cpython-39-darwin.so +0 -0
- sage/graphs/graph.py +12 -46
- sage/graphs/graph_coloring.cpython-39-darwin.so +0 -0
- sage/graphs/graph_database.py +1 -1
- sage/graphs/graph_decompositions/bandwidth.cpython-39-darwin.so +0 -0
- sage/graphs/graph_decompositions/clique_separators.cpython-39-darwin.so +0 -0
- sage/graphs/graph_decompositions/cutwidth.cpython-39-darwin.so +0 -0
- sage/graphs/graph_decompositions/fast_digraph.cpython-39-darwin.so +0 -0
- sage/graphs/graph_decompositions/graph_products.cpython-39-darwin.so +0 -0
- sage/graphs/graph_decompositions/modular_decomposition.cpython-39-darwin.so +0 -0
- sage/graphs/graph_decompositions/slice_decomposition.cpython-39-darwin.so +0 -0
- sage/graphs/graph_decompositions/tree_decomposition.cpython-39-darwin.so +0 -0
- sage/graphs/graph_decompositions/vertex_separation.cpython-39-darwin.so +0 -0
- sage/graphs/graph_generators.py +110 -55
- sage/graphs/graph_generators_pyx.cpython-39-darwin.so +0 -0
- sage/graphs/graph_latex.py +1 -1
- sage/graphs/graph_list.py +2 -3
- sage/graphs/graph_plot.py +225 -30
- sage/graphs/hyperbolicity.cpython-39-darwin.so +0 -0
- sage/graphs/independent_sets.cpython-39-darwin.so +0 -0
- sage/graphs/isgci.py +3 -8
- sage/graphs/isoperimetric_inequalities.cpython-39-darwin.so +0 -0
- sage/graphs/line_graph.cpython-39-darwin.so +0 -0
- sage/graphs/matching.py +14 -25
- sage/graphs/matching_covered_graph.py +871 -60
- sage/graphs/orientations.py +190 -134
- sage/graphs/path_enumeration.cpython-39-darwin.so +0 -0
- sage/graphs/path_enumeration.pyx +25 -25
- sage/graphs/spanning_tree.cpython-39-darwin.so +0 -0
- sage/graphs/strongly_regular_db.cpython-39-darwin.so +0 -0
- sage/graphs/strongly_regular_db.pyx +54 -52
- sage/graphs/traversals.cpython-39-darwin.so +0 -0
- sage/graphs/traversals.pyx +114 -46
- sage/graphs/trees.cpython-39-darwin.so +0 -0
- sage/graphs/views.cpython-39-darwin.so +0 -0
- sage/graphs/weakly_chordal.cpython-39-darwin.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-39-darwin.so +0 -0
- sage/knots/free_knotinfo_monoid.py +2 -3
- sage/knots/knot.py +1 -1
- sage/knots/knotinfo.py +4 -4
- sage/knots/link.py +58 -57
- sage/sandpiles/sandpile.py +2 -3
- sage/topology/cell_complex.py +1 -1
- sage/topology/cubical_complex.py +7 -7
- sage/topology/delta_complex.py +4 -4
- sage/topology/simplicial_complex.py +7 -22
- passagemath_graphs-10.5.10.dist-info/RECORD +0 -251
- {passagemath_graphs-10.5.10.dist-info → passagemath_graphs-10.5.43.dist-info}/top_level.txt +0 -0
sage/graphs/base/c_graph.pyx
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# sage_setup: distribution = sagemath-graphs
|
2
2
|
# distutils: language = c++
|
3
|
+
# distutils: extra_compile_args = -std=c++11
|
3
4
|
r"""
|
4
5
|
Fast compiled graphs
|
5
6
|
|
@@ -44,15 +45,18 @@ method :meth:`realloc <sage.graphs.base.c_graph.CGraph.realloc>`.
|
|
44
45
|
# https://www.gnu.org/licenses/
|
45
46
|
# ****************************************************************************
|
46
47
|
|
48
|
+
from cysignals.memory cimport check_allocarray, sig_free
|
49
|
+
from libcpp.pair cimport pair
|
50
|
+
from libcpp.queue cimport queue
|
51
|
+
from libcpp.stack cimport stack
|
52
|
+
|
53
|
+
from sage.arith.long cimport pyobject_to_long
|
54
|
+
from sage.data_structures.bitset cimport FrozenBitset
|
47
55
|
from sage.data_structures.bitset_base cimport *
|
56
|
+
from sage.data_structures.pairing_heap cimport PairingHeap
|
48
57
|
from sage.rings.integer cimport smallInteger
|
49
|
-
|
50
|
-
from libcpp.queue cimport priority_queue, queue
|
51
|
-
from libcpp.stack cimport stack
|
52
|
-
from libcpp.pair cimport pair
|
58
|
+
|
53
59
|
from sage.rings.integer_ring import ZZ
|
54
|
-
from cysignals.memory cimport check_allocarray, sig_free
|
55
|
-
from sage.data_structures.bitset cimport FrozenBitset
|
56
60
|
|
57
61
|
|
58
62
|
cdef extern from "Python.h":
|
@@ -3738,7 +3742,6 @@ cdef class CGraphBackend(GenericGraphBackend):
|
|
3738
3742
|
cdef dict pred_x = {}
|
3739
3743
|
cdef dict pred_y = {}
|
3740
3744
|
cdef dict pred_current
|
3741
|
-
cdef dict pred_other
|
3742
3745
|
|
3743
3746
|
# Stores the distances from x and y
|
3744
3747
|
cdef dict dist_x = {}
|
@@ -3746,95 +3749,90 @@ cdef class CGraphBackend(GenericGraphBackend):
|
|
3746
3749
|
cdef dict dist_current
|
3747
3750
|
cdef dict dist_other
|
3748
3751
|
|
3749
|
-
#
|
3750
|
-
#
|
3751
|
-
#
|
3752
|
-
|
3753
|
-
cdef
|
3754
|
-
|
3755
|
-
|
3756
|
-
|
3757
|
-
|
3758
|
-
cdef list shortest_path = []
|
3752
|
+
# We use 2 min-heap data structures (pairing heaps), one for the
|
3753
|
+
# exploration from x and the other for the reverse exploration to y.
|
3754
|
+
# Each heap associates to a vertex a pair (distance, pred).
|
3755
|
+
cdef PairingHeap[int, pair[double, int]] px = PairingHeap[int, pair[double, int]]()
|
3756
|
+
cdef PairingHeap[int, pair[double, int]] py = PairingHeap[int, pair[double, int]]()
|
3757
|
+
cdef PairingHeap[int, pair[double, int]] * ptmp
|
3758
|
+
px.push(x_int, (0, x_int))
|
3759
|
+
py.push(y_int, (0, y_int))
|
3759
3760
|
|
3760
3761
|
# Meeting_vertex is a vertex discovered through x and through y
|
3761
3762
|
# which defines the shortest path found
|
3762
3763
|
# (of length shortest_path_length).
|
3763
3764
|
cdef int meeting_vertex = -1
|
3765
|
+
cdef double shortest_path_length
|
3766
|
+
cdef double f_tmp
|
3764
3767
|
|
3765
3768
|
if reduced_weight is not None:
|
3766
3769
|
def weight_function(e):
|
3767
3770
|
return reduced_weight[(e[0], e[1])]
|
3768
3771
|
|
3769
3772
|
# As long as the current side (x or y) is not totally explored ...
|
3770
|
-
while not
|
3771
|
-
|
3772
|
-
|
3773
|
-
|
3774
|
-
|
3775
|
-
|
3776
|
-
|
3773
|
+
while not (px.empty() and py.empty()):
|
3774
|
+
if (px.empty() or
|
3775
|
+
(not py.empty() and px.top_value().first > py.top_value().first)):
|
3776
|
+
side = -1
|
3777
|
+
ptmp = &py
|
3778
|
+
else: # px is not empty
|
3779
|
+
side = 1
|
3780
|
+
ptmp = &px
|
3781
|
+
v, (distance, pred) = ptmp.top()
|
3777
3782
|
if meeting_vertex != -1 and distance > shortest_path_length:
|
3778
3783
|
break
|
3784
|
+
ptmp.pop()
|
3779
3785
|
|
3780
3786
|
if side == 1:
|
3781
3787
|
dist_current, dist_other = dist_x, dist_y
|
3782
|
-
pred_current
|
3788
|
+
pred_current = pred_x
|
3789
|
+
nbr_iter = self.cg().out_neighbors(v)
|
3783
3790
|
else:
|
3784
3791
|
dist_current, dist_other = dist_y, dist_x
|
3785
|
-
pred_current
|
3786
|
-
|
3787
|
-
|
3788
|
-
|
3789
|
-
|
3790
|
-
|
3791
|
-
|
3792
|
-
|
3793
|
-
|
3794
|
-
|
3795
|
-
|
3796
|
-
|
3797
|
-
|
3798
|
-
|
3799
|
-
|
3800
|
-
|
3801
|
-
|
3802
|
-
|
3803
|
-
|
3804
|
-
|
3805
|
-
|
3806
|
-
|
3807
|
-
|
3808
|
-
|
3809
|
-
|
3810
|
-
|
3811
|
-
|
3812
|
-
|
3813
|
-
|
3814
|
-
|
3815
|
-
|
3816
|
-
|
3817
|
-
|
3818
|
-
|
3819
|
-
|
3820
|
-
|
3821
|
-
|
3822
|
-
|
3823
|
-
|
3824
|
-
|
3825
|
-
|
3826
|
-
|
3827
|
-
|
3828
|
-
|
3829
|
-
edge_label = min(weight_function((v_obj, w_obj, l)) for l in self.get_edge_label(v_obj, w_obj))
|
3830
|
-
else:
|
3831
|
-
edge_label = weight_function((v_obj, w_obj, self.get_edge_label(v_obj, w_obj)))
|
3832
|
-
if edge_label < 0:
|
3833
|
-
raise ValueError("the graph contains an edge with negative weight")
|
3834
|
-
# priority_queue is by default max_heap
|
3835
|
-
# negative value of distance + edge_label is stored in
|
3836
|
-
# priority_queue to get minimum distance
|
3837
|
-
pq.push(((-(distance + edge_label), side), (v, w)))
|
3792
|
+
pred_current = pred_y
|
3793
|
+
nbr_iter = self.cg().in_neighbors(v)
|
3794
|
+
|
3795
|
+
dist_current[v] = distance
|
3796
|
+
if not distance_flag:
|
3797
|
+
pred_current[v] = pred
|
3798
|
+
|
3799
|
+
if v in dist_other:
|
3800
|
+
f_tmp = distance + dist_other[v]
|
3801
|
+
if meeting_vertex == -1 or f_tmp < shortest_path_length:
|
3802
|
+
meeting_vertex = v
|
3803
|
+
shortest_path_length = f_tmp
|
3804
|
+
|
3805
|
+
if not exclude_e and not exclude_v:
|
3806
|
+
neighbors = (w for w in nbr_iter
|
3807
|
+
if not include_v or w in include_vertices_int)
|
3808
|
+
else:
|
3809
|
+
neighbors = (w for w in nbr_iter
|
3810
|
+
if ((not exclude_v or w not in exclude_vertices_int) and
|
3811
|
+
(not exclude_e or
|
3812
|
+
((side == 1 and (v, w) not in exclude_edges_int) or
|
3813
|
+
(side == -1 and (w, v) not in exclude_edges_int))) and
|
3814
|
+
(not include_v or w in include_vertices_int)))
|
3815
|
+
|
3816
|
+
for w in neighbors:
|
3817
|
+
# If w has not yet been extracted from the heap, we check if we
|
3818
|
+
# can improve its path
|
3819
|
+
if w not in dist_current:
|
3820
|
+
v_obj = self.vertex_label(v)
|
3821
|
+
w_obj = self.vertex_label(w)
|
3822
|
+
if side == -1:
|
3823
|
+
v_obj, w_obj = w_obj, v_obj
|
3824
|
+
if self._multiple_edges:
|
3825
|
+
edge_label = min(weight_function((v_obj, w_obj, l)) for l in self.get_edge_label(v_obj, w_obj))
|
3826
|
+
else:
|
3827
|
+
edge_label = weight_function((v_obj, w_obj, self.get_edge_label(v_obj, w_obj)))
|
3828
|
+
if edge_label < 0:
|
3829
|
+
raise ValueError("the graph contains an edge with negative weight")
|
3830
|
+
f_tmp = distance + edge_label
|
3831
|
+
if ptmp.contains(w):
|
3832
|
+
if ptmp.value(w).first > f_tmp:
|
3833
|
+
ptmp.decrease(w, (f_tmp, v))
|
3834
|
+
else:
|
3835
|
+
ptmp.push(w, (f_tmp, v))
|
3838
3836
|
|
3839
3837
|
# No meeting point has been found
|
3840
3838
|
if meeting_vertex == -1:
|
@@ -3842,33 +3840,34 @@ cdef class CGraphBackend(GenericGraphBackend):
|
|
3842
3840
|
from sage.rings.infinity import Infinity
|
3843
3841
|
return Infinity
|
3844
3842
|
return []
|
3845
|
-
else:
|
3846
|
-
# build the shortest path and returns it.
|
3847
|
-
if distance_flag:
|
3848
|
-
if shortest_path_length in ZZ:
|
3849
|
-
return int(shortest_path_length)
|
3850
|
-
else:
|
3851
|
-
return shortest_path_length
|
3852
|
-
w = meeting_vertex
|
3853
|
-
|
3854
|
-
while w != x_int:
|
3855
|
-
shortest_path.append(self.vertex_label(w))
|
3856
|
-
w = pred_x[w]
|
3857
3843
|
|
3858
|
-
|
3859
|
-
|
3844
|
+
if distance_flag:
|
3845
|
+
if shortest_path_length in ZZ:
|
3846
|
+
return int(shortest_path_length)
|
3847
|
+
return shortest_path_length
|
3860
3848
|
|
3861
|
-
|
3862
|
-
|
3849
|
+
# build the shortest path and return it.
|
3850
|
+
cdef list shortest_path = []
|
3851
|
+
w = meeting_vertex
|
3852
|
+
while w != x_int:
|
3853
|
+
shortest_path.append(self.vertex_label(w))
|
3854
|
+
w = pred_x[w]
|
3863
3855
|
|
3864
|
-
|
3865
|
-
|
3866
|
-
shortest_path.append(self.vertex_label(w))
|
3867
|
-
w = pred_y[w]
|
3868
|
-
shortest_path.append(y)
|
3856
|
+
shortest_path.append(x)
|
3857
|
+
shortest_path.reverse()
|
3869
3858
|
|
3859
|
+
if meeting_vertex == y_int:
|
3870
3860
|
return shortest_path
|
3871
3861
|
|
3862
|
+
w = pred_y[meeting_vertex]
|
3863
|
+
while w != y_int:
|
3864
|
+
shortest_path.append(self.vertex_label(w))
|
3865
|
+
w = pred_y[w]
|
3866
|
+
|
3867
|
+
shortest_path.append(y)
|
3868
|
+
|
3869
|
+
return shortest_path
|
3870
|
+
|
3872
3871
|
def bidirectional_dijkstra(self, x, y, weight_function=None,
|
3873
3872
|
distance_flag=False):
|
3874
3873
|
r"""
|
@@ -3900,7 +3899,7 @@ cdef class CGraphBackend(GenericGraphBackend):
|
|
3900
3899
|
|
3901
3900
|
sage: G = Graph(graphs.PetersenGraph())
|
3902
3901
|
sage: for (u, v) in G.edges(sort=True, labels=None):
|
3903
|
-
....:
|
3902
|
+
....: G.set_edge_label(u, v, 1)
|
3904
3903
|
sage: G.shortest_path(0, 1, by_weight=True)
|
3905
3904
|
[0, 1]
|
3906
3905
|
sage: G.shortest_path_length(0, 1, by_weight=True)
|
@@ -3929,7 +3928,7 @@ cdef class CGraphBackend(GenericGraphBackend):
|
|
3929
3928
|
|
3930
3929
|
sage: G = DiGraph({0: [1, 2], 1: [4], 2: [3, 4], 4: [5], 5: [6]}, multiedges=True)
|
3931
3930
|
sage: for u, v in list(G.edges(labels=None, sort=False)):
|
3932
|
-
....:
|
3931
|
+
....: G.set_edge_label(u, v, 1)
|
3933
3932
|
sage: G.distance(0, 5, by_weight=true)
|
3934
3933
|
3
|
3935
3934
|
"""
|
@@ -3955,7 +3954,6 @@ cdef class CGraphBackend(GenericGraphBackend):
|
|
3955
3954
|
cdef dict pred_x = {}
|
3956
3955
|
cdef dict pred_y = {}
|
3957
3956
|
cdef dict pred_current
|
3958
|
-
cdef dict pred_other
|
3959
3957
|
|
3960
3958
|
# Stores the distances from x and y
|
3961
3959
|
cdef dict dist_x = {}
|
@@ -3963,77 +3961,81 @@ cdef class CGraphBackend(GenericGraphBackend):
|
|
3963
3961
|
cdef dict dist_current
|
3964
3962
|
cdef dict dist_other
|
3965
3963
|
|
3966
|
-
#
|
3967
|
-
#
|
3968
|
-
#
|
3969
|
-
|
3970
|
-
cdef
|
3971
|
-
|
3972
|
-
|
3973
|
-
|
3964
|
+
# We use 2 min-heap data structures (pairing heaps), one for the
|
3965
|
+
# exploration from x and the other for the reverse exploration to y.
|
3966
|
+
# Each heap associates to a vertex a pair (distance, pred).
|
3967
|
+
cdef PairingHeap[int, pair[double, int]] px = PairingHeap[int, pair[double, int]]()
|
3968
|
+
cdef PairingHeap[int, pair[double, int]] py = PairingHeap[int, pair[double, int]]()
|
3969
|
+
cdef PairingHeap[int, pair[double, int]] * ptmp
|
3970
|
+
px.push(x_int, (0, x_int))
|
3971
|
+
py.push(y_int, (0, y_int))
|
3974
3972
|
|
3975
|
-
cdef list
|
3973
|
+
cdef list neighbors
|
3976
3974
|
|
3977
3975
|
# Meeting_vertex is a vertex discovered through x and through y
|
3978
3976
|
# which defines the shortest path found
|
3979
3977
|
# (of length shortest_path_length).
|
3980
3978
|
cdef int meeting_vertex = -1
|
3979
|
+
cdef double shortest_path_length
|
3980
|
+
cdef double f_tmp
|
3981
3981
|
|
3982
3982
|
if weight_function is None:
|
3983
3983
|
def weight_function(e):
|
3984
3984
|
return 1 if e[2] is None else e[2]
|
3985
3985
|
|
3986
3986
|
# As long as the current side (x or y) is not totally explored ...
|
3987
|
-
while not
|
3988
|
-
|
3989
|
-
|
3990
|
-
|
3991
|
-
|
3992
|
-
|
3993
|
-
|
3987
|
+
while not (px.empty() and py.empty()):
|
3988
|
+
if (px.empty() or
|
3989
|
+
(not py.empty() and px.top_value().first > py.top_value().first)):
|
3990
|
+
side = -1
|
3991
|
+
ptmp = &py
|
3992
|
+
else: # px is not empty
|
3993
|
+
side = 1
|
3994
|
+
ptmp = &px
|
3995
|
+
v, (distance, pred) = ptmp.top()
|
3994
3996
|
if meeting_vertex != -1 and distance > shortest_path_length:
|
3995
3997
|
break
|
3998
|
+
ptmp.pop()
|
3996
3999
|
|
3997
4000
|
if side == 1:
|
3998
4001
|
dist_current, dist_other = dist_x, dist_y
|
3999
|
-
pred_current
|
4002
|
+
pred_current = pred_x
|
4003
|
+
neighbors = self.cg().out_neighbors(v)
|
4000
4004
|
else:
|
4001
4005
|
dist_current, dist_other = dist_y, dist_x
|
4002
|
-
pred_current
|
4003
|
-
|
4004
|
-
|
4005
|
-
|
4006
|
-
|
4007
|
-
|
4008
|
-
|
4009
|
-
|
4010
|
-
|
4011
|
-
|
4012
|
-
|
4013
|
-
|
4014
|
-
|
4015
|
-
|
4016
|
-
|
4017
|
-
|
4018
|
-
|
4019
|
-
|
4020
|
-
|
4021
|
-
|
4022
|
-
|
4023
|
-
|
4024
|
-
|
4025
|
-
|
4026
|
-
|
4027
|
-
|
4028
|
-
|
4029
|
-
|
4030
|
-
|
4031
|
-
if
|
4032
|
-
|
4033
|
-
|
4034
|
-
|
4035
|
-
# priority_queue to get minimum distance
|
4036
|
-
pq.push(((-(distance + edge_label), side), (v, w)))
|
4006
|
+
pred_current = pred_y
|
4007
|
+
neighbors = self.cg().in_neighbors(v)
|
4008
|
+
|
4009
|
+
dist_current[v] = distance
|
4010
|
+
if not distance_flag:
|
4011
|
+
pred_current[v] = pred
|
4012
|
+
|
4013
|
+
if v in dist_other:
|
4014
|
+
f_tmp = distance + dist_other[v]
|
4015
|
+
if meeting_vertex == -1 or f_tmp < shortest_path_length:
|
4016
|
+
meeting_vertex = v
|
4017
|
+
shortest_path_length = f_tmp
|
4018
|
+
|
4019
|
+
for w in neighbors:
|
4020
|
+
# If w has not yet been extracted from the heap, we check if we
|
4021
|
+
# can improve its path
|
4022
|
+
if w not in dist_current:
|
4023
|
+
v_obj = self.vertex_label(v)
|
4024
|
+
w_obj = self.vertex_label(w)
|
4025
|
+
if side == -1:
|
4026
|
+
v_obj, w_obj = w_obj, v_obj
|
4027
|
+
if self._multiple_edges:
|
4028
|
+
edge_label = min(weight_function((v_obj, w_obj, l)) for l in self.get_edge_label(v_obj, w_obj))
|
4029
|
+
else:
|
4030
|
+
edge_label = weight_function((v_obj, w_obj, self.get_edge_label(v_obj, w_obj)))
|
4031
|
+
if edge_label < 0:
|
4032
|
+
raise ValueError("the graph contains an edge with negative weight")
|
4033
|
+
f_tmp = distance + edge_label
|
4034
|
+
if ptmp.contains(w):
|
4035
|
+
if ptmp.value(w).first > f_tmp:
|
4036
|
+
ptmp.decrease(w, (f_tmp, v))
|
4037
|
+
else:
|
4038
|
+
ptmp.push(w, (f_tmp, v))
|
4037
4039
|
|
4038
4040
|
# No meeting point has been found
|
4039
4041
|
if meeting_vertex == -1:
|
@@ -4041,33 +4043,34 @@ cdef class CGraphBackend(GenericGraphBackend):
|
|
4041
4043
|
from sage.rings.infinity import Infinity
|
4042
4044
|
return Infinity
|
4043
4045
|
return []
|
4044
|
-
else:
|
4045
|
-
# build the shortest path and returns it.
|
4046
|
-
if distance_flag:
|
4047
|
-
if shortest_path_length in ZZ:
|
4048
|
-
return int(shortest_path_length)
|
4049
|
-
else:
|
4050
|
-
return shortest_path_length
|
4051
|
-
w = meeting_vertex
|
4052
4046
|
|
4053
|
-
|
4054
|
-
|
4055
|
-
|
4056
|
-
|
4057
|
-
shortest_path.append(x)
|
4058
|
-
shortest_path.reverse()
|
4047
|
+
if distance_flag:
|
4048
|
+
if shortest_path_length in ZZ:
|
4049
|
+
return int(shortest_path_length)
|
4050
|
+
return shortest_path_length
|
4059
4051
|
|
4060
|
-
|
4061
|
-
|
4052
|
+
# build the shortest path and return it.
|
4053
|
+
cdef list shortest_path = []
|
4054
|
+
w = meeting_vertex
|
4055
|
+
while w != x_int:
|
4056
|
+
shortest_path.append(self.vertex_label(w))
|
4057
|
+
w = pred_x[w]
|
4062
4058
|
|
4063
|
-
|
4064
|
-
|
4065
|
-
shortest_path.append(self.vertex_label(w))
|
4066
|
-
w = pred_y[w]
|
4067
|
-
shortest_path.append(y)
|
4059
|
+
shortest_path.append(x)
|
4060
|
+
shortest_path.reverse()
|
4068
4061
|
|
4062
|
+
if meeting_vertex == y_int:
|
4069
4063
|
return shortest_path
|
4070
4064
|
|
4065
|
+
w = pred_y[meeting_vertex]
|
4066
|
+
while w != y_int:
|
4067
|
+
shortest_path.append(self.vertex_label(w))
|
4068
|
+
w = pred_y[w]
|
4069
|
+
|
4070
|
+
shortest_path.append(y)
|
4071
|
+
|
4072
|
+
return shortest_path
|
4073
|
+
|
4071
4074
|
def shortest_path_all_vertices(self, v, cutoff=None,
|
4072
4075
|
distance_flag=False):
|
4073
4076
|
r"""
|
@@ -4177,7 +4180,8 @@ cdef class CGraphBackend(GenericGraphBackend):
|
|
4177
4180
|
# Searching
|
4178
4181
|
###################################
|
4179
4182
|
|
4180
|
-
def depth_first_search(self, v, reverse=False, ignore_direction=False
|
4183
|
+
def depth_first_search(self, v, reverse=False, ignore_direction=False,
|
4184
|
+
forbidden_vertices=None):
|
4181
4185
|
r"""
|
4182
4186
|
Return a depth-first search from vertex ``v``.
|
4183
4187
|
|
@@ -4193,6 +4197,9 @@ cdef class CGraphBackend(GenericGraphBackend):
|
|
4193
4197
|
relevant to digraphs. If this is a digraph, ignore all orientations
|
4194
4198
|
and consider the graph as undirected.
|
4195
4199
|
|
4200
|
+
- ``forbidden_vertices`` -- list (default: ``None``); set of vertices to
|
4201
|
+
avoid during the search. The start vertex ``v`` cannot be in this set.
|
4202
|
+
|
4196
4203
|
ALGORITHM:
|
4197
4204
|
|
4198
4205
|
Below is a general template for depth-first search.
|
@@ -4235,7 +4242,7 @@ cdef class CGraphBackend(GenericGraphBackend):
|
|
4235
4242
|
|
4236
4243
|
Traversing the Petersen graph using depth-first search::
|
4237
4244
|
|
4238
|
-
sage: G =
|
4245
|
+
sage: G = graphs.PetersenGraph()
|
4239
4246
|
sage: list(G.depth_first_search(0))
|
4240
4247
|
[0, 5, 8, 6, 9, 7, 2, 3, 4, 1]
|
4241
4248
|
|
@@ -4252,14 +4259,33 @@ cdef class CGraphBackend(GenericGraphBackend):
|
|
4252
4259
|
....: "Stuttgart": ["Nurnberg"], "Erfurt": ["Wurzburg"]})
|
4253
4260
|
sage: list(G.depth_first_search("Stuttgart"))
|
4254
4261
|
['Stuttgart', 'Nurnberg', ...]
|
4262
|
+
|
4263
|
+
Avoiding some cities:
|
4264
|
+
|
4265
|
+
sage: list(G.depth_first_search("Stuttgart",
|
4266
|
+
....: forbidden_vertices=["Frankfurt", "Munchen"]))
|
4267
|
+
['Stuttgart', 'Nurnberg', 'Wurzburg', 'Erfurt']
|
4268
|
+
|
4269
|
+
TESTS:
|
4270
|
+
|
4271
|
+
The start vertex cannot be forbidden::
|
4272
|
+
|
4273
|
+
sage: G = graphs.PetersenGraph()
|
4274
|
+
sage: list(G.depth_first_search(0, forbidden_vertices=[0, 1]))
|
4275
|
+
Traceback (most recent call last):
|
4276
|
+
...
|
4277
|
+
ValueError: the start vertex is in the set of forbidden vertices
|
4255
4278
|
"""
|
4256
4279
|
return Search_iterator(self,
|
4257
4280
|
v,
|
4258
4281
|
direction=-1,
|
4259
4282
|
reverse=reverse,
|
4260
|
-
ignore_direction=ignore_direction
|
4283
|
+
ignore_direction=ignore_direction,
|
4284
|
+
forbidden_vertices=forbidden_vertices)
|
4261
4285
|
|
4262
|
-
def breadth_first_search(self, v, reverse=False, ignore_direction=False,
|
4286
|
+
def breadth_first_search(self, v, reverse=False, ignore_direction=False,
|
4287
|
+
report_distance=False, edges=False,
|
4288
|
+
forbidden_vertices=None):
|
4263
4289
|
r"""
|
4264
4290
|
Return a breadth-first search from vertex ``v``.
|
4265
4291
|
|
@@ -4287,6 +4313,9 @@ cdef class CGraphBackend(GenericGraphBackend):
|
|
4287
4313
|
Note that parameters ``edges`` and ``report_distance`` cannot be
|
4288
4314
|
``True`` simultaneously.
|
4289
4315
|
|
4316
|
+
- ``forbidden_vertices`` -- list (default: ``None``); set of vertices to
|
4317
|
+
avoid during the search. The start vertex ``v`` cannot be in this set.
|
4318
|
+
|
4290
4319
|
ALGORITHM:
|
4291
4320
|
|
4292
4321
|
Below is a general template for breadth-first search.
|
@@ -4338,6 +4367,22 @@ cdef class CGraphBackend(GenericGraphBackend):
|
|
4338
4367
|
sage: G = graphs.EuropeMap(continental=True)
|
4339
4368
|
sage: list(G.breadth_first_search("Portugal"))
|
4340
4369
|
['Portugal', 'Spain', ..., 'Greece']
|
4370
|
+
|
4371
|
+
Avoiding some countries:
|
4372
|
+
|
4373
|
+
sage: list(G.breadth_first_search("Portugal",
|
4374
|
+
....: forbidden_vertices=["Germany","Italy"]))
|
4375
|
+
['Portugal', 'Spain', ..., 'Sweden']
|
4376
|
+
|
4377
|
+
TESTS:
|
4378
|
+
|
4379
|
+
The start vertex cannot be forbidden::
|
4380
|
+
|
4381
|
+
sage: G = graphs.PetersenGraph()
|
4382
|
+
sage: list(G.breadth_first_search(0, forbidden_vertices=[0]))
|
4383
|
+
Traceback (most recent call last):
|
4384
|
+
...
|
4385
|
+
ValueError: the start vertex is in the set of forbidden vertices
|
4341
4386
|
"""
|
4342
4387
|
return Search_iterator(self,
|
4343
4388
|
v,
|
@@ -4345,16 +4390,22 @@ cdef class CGraphBackend(GenericGraphBackend):
|
|
4345
4390
|
reverse=reverse,
|
4346
4391
|
ignore_direction=ignore_direction,
|
4347
4392
|
report_distance=report_distance,
|
4348
|
-
edges=edges
|
4393
|
+
edges=edges,
|
4394
|
+
forbidden_vertices=forbidden_vertices)
|
4349
4395
|
|
4350
4396
|
###################################
|
4351
4397
|
# Connectedness
|
4352
4398
|
###################################
|
4353
4399
|
|
4354
|
-
def is_connected(self):
|
4400
|
+
def is_connected(self, forbidden_vertices=None):
|
4355
4401
|
r"""
|
4356
4402
|
Check whether the graph is connected.
|
4357
4403
|
|
4404
|
+
INPUT:
|
4405
|
+
|
4406
|
+
- ``forbidden_vertices`` -- list (default: ``None``); set of vertices to
|
4407
|
+
avoid during the search
|
4408
|
+
|
4358
4409
|
EXAMPLES:
|
4359
4410
|
|
4360
4411
|
Petersen's graph is connected::
|
@@ -4372,6 +4423,16 @@ cdef class CGraphBackend(GenericGraphBackend):
|
|
4372
4423
|
sage: Graph(graphs.CubeGraph(3)).is_connected()
|
4373
4424
|
True
|
4374
4425
|
|
4426
|
+
A graph with forbidden vertices::
|
4427
|
+
|
4428
|
+
sage: G = graphs.PathGraph(5)
|
4429
|
+
sage: G._backend.is_connected()
|
4430
|
+
True
|
4431
|
+
sage: G._backend.is_connected(forbidden_vertices=[1])
|
4432
|
+
False
|
4433
|
+
sage: G._backend.is_connected(forbidden_vertices=[0, 1])
|
4434
|
+
True
|
4435
|
+
|
4375
4436
|
TESTS::
|
4376
4437
|
|
4377
4438
|
sage: P = posets.PentagonPoset() # needs sage.modules
|
@@ -4390,8 +4451,18 @@ cdef class CGraphBackend(GenericGraphBackend):
|
|
4390
4451
|
if v_int == -1:
|
4391
4452
|
return True
|
4392
4453
|
v = self.vertex_label(v_int)
|
4393
|
-
cdef
|
4394
|
-
|
4454
|
+
cdef set forbidden = set(forbidden_vertices) if forbidden_vertices else set()
|
4455
|
+
while v in forbidden:
|
4456
|
+
v_int = bitset_next(cg.active_vertices, v_int + 1)
|
4457
|
+
if v_int == -1:
|
4458
|
+
# The empty graph is connected. So the graph with only forbidden
|
4459
|
+
# vertices also is
|
4460
|
+
return True
|
4461
|
+
v = self.vertex_label(v_int)
|
4462
|
+
|
4463
|
+
cdef size_t n = len(forbidden)
|
4464
|
+
for _ in self.depth_first_search(v, ignore_direction=True,
|
4465
|
+
forbidden_vertices=forbidden):
|
4395
4466
|
n += 1
|
4396
4467
|
return n == cg.num_verts
|
4397
4468
|
|
@@ -4721,7 +4792,8 @@ cdef class Search_iterator:
|
|
4721
4792
|
cdef in_neighbors
|
4722
4793
|
|
4723
4794
|
def __init__(self, graph, v, direction=0, reverse=False,
|
4724
|
-
ignore_direction=False, report_distance=False, edges=False
|
4795
|
+
ignore_direction=False, report_distance=False, edges=False,
|
4796
|
+
forbidden_vertices=None):
|
4725
4797
|
r"""
|
4726
4798
|
Initialize an iterator for traversing a (di)graph.
|
4727
4799
|
|
@@ -4763,11 +4835,16 @@ cdef class Search_iterator:
|
|
4763
4835
|
Note that parameters ``edges`` and ``report_distance`` cannot be
|
4764
4836
|
``True`` simultaneously.
|
4765
4837
|
|
4838
|
+
- ``forbidden_vertices`` -- list (default: ``None``); set of vertices to
|
4839
|
+
avoid during the search. The start vertex ``v`` cannot be in this set.
|
4840
|
+
|
4766
4841
|
EXAMPLES::
|
4767
4842
|
|
4768
4843
|
sage: g = graphs.PetersenGraph()
|
4769
4844
|
sage: list(g.breadth_first_search(0))
|
4770
4845
|
[0, 1, 4, 5, 2, 6, 3, 9, 7, 8]
|
4846
|
+
sage: list(g.breadth_first_search(0, forbidden_vertices=[1, 2]))
|
4847
|
+
[0, 4, 5, 3, 9, 7, 8, 6]
|
4771
4848
|
|
4772
4849
|
TESTS:
|
4773
4850
|
|
@@ -4806,10 +4883,19 @@ cdef class Search_iterator:
|
|
4806
4883
|
bitset_set_first_n(self.seen, 0)
|
4807
4884
|
|
4808
4885
|
cdef int v_id = self.graph.get_vertex(v)
|
4886
|
+
cdef int u_id
|
4809
4887
|
|
4810
4888
|
if v_id == -1:
|
4811
4889
|
raise LookupError("vertex ({0}) is not a vertex of the graph".format(repr(v)))
|
4812
4890
|
|
4891
|
+
if forbidden_vertices is not None:
|
4892
|
+
for u in forbidden_vertices:
|
4893
|
+
u_id = self.graph.get_vertex(u)
|
4894
|
+
if u_id != -1:
|
4895
|
+
if u_id == v_id:
|
4896
|
+
raise ValueError(f"the start vertex is in the set of forbidden vertices")
|
4897
|
+
bitset_add(self.seen, u_id)
|
4898
|
+
|
4813
4899
|
if direction == 0:
|
4814
4900
|
self.fifo.push(v_id)
|
4815
4901
|
self.first_with_new_distance = -1
|