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.
Files changed (140) hide show
  1. {passagemath_graphs-10.5.10.dist-info → passagemath_graphs-10.5.43.dist-info}/METADATA +126 -30
  2. passagemath_graphs-10.5.43.dist-info/RECORD +256 -0
  3. {passagemath_graphs-10.5.10.dist-info → passagemath_graphs-10.5.43.dist-info}/WHEEL +2 -1
  4. passagemath_graphs.dylibs/libgmp.10.dylib +0 -0
  5. sage/all__sagemath_graphs.py +5 -0
  6. sage/combinat/abstract_tree.py +1 -1
  7. sage/combinat/binary_tree.py +1 -1
  8. sage/combinat/cluster_algebra_quiver/all.py +1 -1
  9. sage/combinat/cluster_algebra_quiver/cluster_seed.py +28 -24
  10. sage/combinat/cluster_algebra_quiver/interact.py +4 -0
  11. sage/combinat/designs/MOLS_handbook_data.py +5 -5
  12. sage/combinat/designs/bibd.py +10 -9
  13. sage/combinat/designs/covering_array.py +3 -3
  14. sage/combinat/designs/covering_design.py +2 -1
  15. sage/combinat/designs/database.py +11 -10
  16. sage/combinat/designs/designs_pyx.cpython-39-darwin.so +0 -0
  17. sage/combinat/designs/designs_pyx.pyx +13 -45
  18. sage/combinat/designs/difference_family.py +6 -6
  19. sage/combinat/designs/difference_matrices.py +1 -1
  20. sage/combinat/designs/evenly_distributed_sets.cpython-39-darwin.so +0 -0
  21. sage/combinat/designs/evenly_distributed_sets.pyx +15 -22
  22. sage/combinat/designs/ext_rep.py +9 -14
  23. sage/combinat/designs/gen_quadrangles_with_spread.cpython-39-darwin.so +0 -0
  24. sage/combinat/designs/gen_quadrangles_with_spread.pyx +1 -1
  25. sage/combinat/designs/group_divisible_designs.py +1 -1
  26. sage/combinat/designs/incidence_structures.py +8 -8
  27. sage/combinat/designs/latin_squares.py +1 -1
  28. sage/combinat/designs/orthogonal_arrays_build_recursive.py +8 -7
  29. sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-39-darwin.so +0 -0
  30. sage/combinat/designs/resolvable_bibd.py +1 -1
  31. sage/combinat/designs/steiner_quadruple_systems.py +1 -1
  32. sage/combinat/designs/subhypergraph_search.cpython-39-darwin.so +0 -0
  33. sage/combinat/designs/subhypergraph_search.pyx +9 -9
  34. sage/combinat/finite_state_machine_generators.py +2 -2
  35. sage/combinat/graph_path.py +3 -3
  36. sage/combinat/interval_posets.py +10 -10
  37. sage/combinat/ordered_tree.py +1 -1
  38. sage/combinat/posets/cartesian_product.py +1 -1
  39. sage/combinat/posets/d_complete.py +1 -1
  40. sage/combinat/posets/forest.py +1 -1
  41. sage/combinat/posets/hasse_cython.cpython-39-darwin.so +0 -0
  42. sage/combinat/posets/hasse_diagram.py +8 -6
  43. sage/combinat/posets/incidence_algebras.py +8 -8
  44. sage/combinat/posets/lattices.py +28 -4
  45. sage/combinat/posets/linear_extension_iterator.cpython-39-darwin.so +0 -0
  46. sage/combinat/posets/linear_extension_iterator.pyx +2 -0
  47. sage/combinat/posets/linear_extensions.py +7 -16
  48. sage/combinat/posets/moebius_algebra.py +1 -1
  49. sage/combinat/posets/poset_examples.py +1 -1
  50. sage/combinat/posets/posets.py +54 -56
  51. sage/combinat/rooted_tree.py +3 -3
  52. sage/combinat/tamari_lattices.py +1 -1
  53. sage/ext_data/kenzo/CP2.txt +45 -0
  54. sage/ext_data/kenzo/CP3.txt +349 -0
  55. sage/ext_data/kenzo/CP4.txt +4774 -0
  56. sage/ext_data/kenzo/README.txt +49 -0
  57. sage/ext_data/kenzo/S4.txt +20 -0
  58. sage/graphs/asteroidal_triples.cpython-39-darwin.so +0 -0
  59. sage/graphs/base/boost_graph.cpython-39-darwin.so +0 -0
  60. sage/graphs/base/boost_graph.pxd +1 -1
  61. sage/graphs/base/boost_graph.pyx +1 -1
  62. sage/graphs/base/c_graph.cpython-39-darwin.so +0 -0
  63. sage/graphs/base/c_graph.pxd +4 -4
  64. sage/graphs/base/c_graph.pyx +270 -184
  65. sage/graphs/base/dense_graph.cpython-39-darwin.so +0 -0
  66. sage/graphs/base/graph_backends.cpython-39-darwin.so +0 -0
  67. sage/graphs/base/sparse_graph.cpython-39-darwin.so +0 -0
  68. sage/graphs/base/static_dense_graph.cpython-39-darwin.so +0 -0
  69. sage/graphs/base/static_sparse_backend.cpython-39-darwin.so +0 -0
  70. sage/graphs/base/static_sparse_backend.pyx +93 -6
  71. sage/graphs/base/static_sparse_graph.cpython-39-darwin.so +0 -0
  72. sage/graphs/base/static_sparse_graph.pyx +1 -1
  73. sage/graphs/bipartite_graph.py +0 -1
  74. sage/graphs/centrality.cpython-39-darwin.so +0 -0
  75. sage/graphs/centrality.pyx +0 -0
  76. sage/graphs/comparability.cpython-39-darwin.so +0 -0
  77. sage/graphs/comparability.pyx +172 -138
  78. sage/graphs/connectivity.cpython-39-darwin.so +0 -0
  79. sage/graphs/connectivity.pyx +194 -18
  80. sage/graphs/convexity_properties.cpython-39-darwin.so +0 -0
  81. sage/graphs/digraph_generators.py +118 -74
  82. sage/graphs/distances_all_pairs.cpython-39-darwin.so +0 -0
  83. sage/graphs/distances_all_pairs.pyx +145 -27
  84. sage/graphs/edge_connectivity.cpython-39-darwin.so +0 -0
  85. sage/graphs/generators/basic.py +471 -130
  86. sage/graphs/generators/distance_regular.cpython-39-darwin.so +0 -0
  87. sage/graphs/generators/distance_regular.pyx +12 -12
  88. sage/graphs/generators/families.py +2 -2
  89. sage/graphs/generators/random.py +8 -13
  90. sage/graphs/generators/smallgraphs.py +12 -11
  91. sage/graphs/generic_graph.py +687 -265
  92. sage/graphs/generic_graph_pyx.cpython-39-darwin.so +0 -0
  93. sage/graphs/genus.cpython-39-darwin.so +0 -0
  94. sage/graphs/graph.py +12 -46
  95. sage/graphs/graph_coloring.cpython-39-darwin.so +0 -0
  96. sage/graphs/graph_database.py +1 -1
  97. sage/graphs/graph_decompositions/bandwidth.cpython-39-darwin.so +0 -0
  98. sage/graphs/graph_decompositions/clique_separators.cpython-39-darwin.so +0 -0
  99. sage/graphs/graph_decompositions/cutwidth.cpython-39-darwin.so +0 -0
  100. sage/graphs/graph_decompositions/fast_digraph.cpython-39-darwin.so +0 -0
  101. sage/graphs/graph_decompositions/graph_products.cpython-39-darwin.so +0 -0
  102. sage/graphs/graph_decompositions/modular_decomposition.cpython-39-darwin.so +0 -0
  103. sage/graphs/graph_decompositions/slice_decomposition.cpython-39-darwin.so +0 -0
  104. sage/graphs/graph_decompositions/tree_decomposition.cpython-39-darwin.so +0 -0
  105. sage/graphs/graph_decompositions/vertex_separation.cpython-39-darwin.so +0 -0
  106. sage/graphs/graph_generators.py +110 -55
  107. sage/graphs/graph_generators_pyx.cpython-39-darwin.so +0 -0
  108. sage/graphs/graph_latex.py +1 -1
  109. sage/graphs/graph_list.py +2 -3
  110. sage/graphs/graph_plot.py +225 -30
  111. sage/graphs/hyperbolicity.cpython-39-darwin.so +0 -0
  112. sage/graphs/independent_sets.cpython-39-darwin.so +0 -0
  113. sage/graphs/isgci.py +3 -8
  114. sage/graphs/isoperimetric_inequalities.cpython-39-darwin.so +0 -0
  115. sage/graphs/line_graph.cpython-39-darwin.so +0 -0
  116. sage/graphs/matching.py +14 -25
  117. sage/graphs/matching_covered_graph.py +871 -60
  118. sage/graphs/orientations.py +190 -134
  119. sage/graphs/path_enumeration.cpython-39-darwin.so +0 -0
  120. sage/graphs/path_enumeration.pyx +25 -25
  121. sage/graphs/spanning_tree.cpython-39-darwin.so +0 -0
  122. sage/graphs/strongly_regular_db.cpython-39-darwin.so +0 -0
  123. sage/graphs/strongly_regular_db.pyx +54 -52
  124. sage/graphs/traversals.cpython-39-darwin.so +0 -0
  125. sage/graphs/traversals.pyx +114 -46
  126. sage/graphs/trees.cpython-39-darwin.so +0 -0
  127. sage/graphs/views.cpython-39-darwin.so +0 -0
  128. sage/graphs/weakly_chordal.cpython-39-darwin.so +0 -0
  129. sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-39-darwin.so +0 -0
  130. sage/knots/free_knotinfo_monoid.py +2 -3
  131. sage/knots/knot.py +1 -1
  132. sage/knots/knotinfo.py +4 -4
  133. sage/knots/link.py +58 -57
  134. sage/sandpiles/sandpile.py +2 -3
  135. sage/topology/cell_complex.py +1 -1
  136. sage/topology/cubical_complex.py +7 -7
  137. sage/topology/delta_complex.py +4 -4
  138. sage/topology/simplicial_complex.py +7 -22
  139. passagemath_graphs-10.5.10.dist-info/RECORD +0 -251
  140. {passagemath_graphs-10.5.10.dist-info → passagemath_graphs-10.5.43.dist-info}/top_level.txt +0 -0
@@ -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
- from sage.arith.long cimport pyobject_to_long
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
- # Lists of vertices who are left to be explored. They are represented
3750
- # as pairs of pair and pair: ((distance, side), (predecessor, name)).
3751
- # 1 indicates x's side, -1 indicates y's, the distance being
3752
- # defined relatively.
3753
- cdef priority_queue[pair[pair[double, int], pair[int, int]]] pq
3754
- pq.push(((0, 1), (x_int, x_int)))
3755
- pq.push(((0, -1), (y_int, y_int)))
3756
- cdef list neighbors
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 pq.empty():
3771
- (distance, side), (pred, v) = pq.top()
3772
- # priority_queue by default is max heap
3773
- # negative value of distance is stored in priority_queue to get
3774
- # minimum distance
3775
- distance = -distance
3776
- pq.pop()
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, pred_other = pred_x, pred_y
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, pred_other = pred_y, pred_x
3786
-
3787
- if v not in dist_current:
3788
- if not distance_flag:
3789
- pred_current[v] = pred
3790
- dist_current[v] = distance
3791
-
3792
- if v in dist_other:
3793
- f_tmp = distance + dist_other[v]
3794
- if meeting_vertex == -1 or f_tmp < shortest_path_length:
3795
- meeting_vertex = v
3796
- shortest_path_length = f_tmp
3797
- if side == 1:
3798
- nbr = self.cg().out_neighbors(v)
3799
- else:
3800
- nbr = self.cg().in_neighbors(v)
3801
-
3802
- if not exclude_e and not exclude_v:
3803
- neighbors = []
3804
- for n in nbr:
3805
- if include_v and n not in include_vertices_int:
3806
- continue
3807
- neighbors.append(n)
3808
- else:
3809
- neighbors = []
3810
- for w in nbr:
3811
- if exclude_v and w in exclude_vertices_int:
3812
- continue
3813
- if (exclude_e and
3814
- ((side == 1 and (v, w) in exclude_edges_int) or
3815
- (side == -1 and (w, v) in exclude_edges_int))):
3816
- continue
3817
- if include_v and w not in include_vertices_int:
3818
- continue
3819
- neighbors.append(w)
3820
- for w in neighbors:
3821
- # If the neighbor is new, adds its non-found neighbors to
3822
- # the queue.
3823
- if w not in dist_current:
3824
- v_obj = self.vertex_label(v)
3825
- w_obj = self.vertex_label(w)
3826
- if side == -1:
3827
- v_obj, w_obj = w_obj, v_obj
3828
- if self._multiple_edges:
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
- shortest_path.append(x)
3859
- shortest_path.reverse()
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
- if meeting_vertex == y_int:
3862
- return shortest_path
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
- w = pred_y[meeting_vertex]
3865
- while w != y_int:
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
- ....: G.set_edge_label(u, v, 1)
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
- ....: G.set_edge_label(u, v, 1)
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
- # Lists of vertices who are left to be explored. They are represented
3967
- # as pairs of pair and pair: ((distance, side), (predecessor, name)).
3968
- # 1 indicates x's side, -1 indicates y's, the distance being
3969
- # defined relatively.
3970
- cdef priority_queue[pair[pair[double, int], pair[int, int]]] pq
3971
- pq.push(((0, 1), (x_int, x_int)))
3972
- pq.push(((0, -1), (y_int, y_int)))
3973
- cdef list neighbors
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 shortest_path = []
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 pq.empty():
3988
- (distance, side), (pred, v) = pq.top()
3989
- # priority_queue by default is max heap
3990
- # negative value of distance is stored in priority_queue to get
3991
- # minimum distance
3992
- distance = -distance
3993
- pq.pop()
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, pred_other = pred_x, pred_y
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, pred_other = pred_y, pred_x
4003
-
4004
- if v not in dist_current:
4005
- if not distance_flag:
4006
- pred_current[v] = pred
4007
- dist_current[v] = distance
4008
-
4009
- if v in dist_other:
4010
- f_tmp = distance + dist_other[v]
4011
- if meeting_vertex == -1 or f_tmp < shortest_path_length:
4012
- meeting_vertex = v
4013
- shortest_path_length = f_tmp
4014
-
4015
- if side == 1:
4016
- neighbors = self.cg().out_neighbors(v)
4017
- else:
4018
- neighbors = self.cg().in_neighbors(v)
4019
- for w in neighbors:
4020
- # If the neighbor is new, adds its non-found neighbors to
4021
- # the queue.
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
- # priority_queue is by default max_heap
4034
- # negative value of distance + edge_label is stored in
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
- while w != x_int:
4054
- shortest_path.append(self.vertex_label(w))
4055
- w = pred_x[w]
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
- if meeting_vertex == y_int:
4061
- return shortest_path
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
- w = pred_y[meeting_vertex]
4064
- while w != y_int:
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 = Graph(graphs.PetersenGraph())
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, report_distance=False, edges=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 size_t n = 0
4394
- for _ in self.depth_first_search(v, ignore_direction=True):
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