Commits (3)
......@@ -1757,6 +1757,11 @@ REFERENCES:
algorithms," in "Algebra, geometry, and software
systems" (2003), 177-206.
.. [DHV2018] Feodor Dragan, Michel Habib, Laurent Viennot.
Revisiting Radius, Diameter, and all Eccentricity Computation in
Graphs through Certificates.
.. [DI1989] Dan Gusfield and Robert W. Irving. *The stable marriage
problem: structure and algorithms*. Vol. 54. Cambridge:
MIT press, 1989.
......@@ -1659,3 +1659,175 @@ def floyd_warshall(gg, paths=True, distances=False):
return d_prec
if distances:
return d_dist
# radius #
cdef uint32_t radius_certificate(short_digraph g):
Compute the radius of the input Graph using the algorithm.
The ``radius-certificate`` algorithm
calculates the exact value of the radius of a unweighted undirected graph
[DHV2018]_. THis algorithm maintains lower bounds on eccentricities of all
nodes and performs one-to-all distance queries from nodes with minimal lower
bound. It then performs one-to-all distance queries from antipodes of the
previous query source, which it uses to update the lower bound.
It iterates until an exact solution is obtained. It can be very fast in
practice. See the code's documentation and [DHV2018]_ for more details.
- ``g`` -- a short_digraph
cdef uint32_t i, LB
cdef uint32_t n = g.n
# L is the lower certificate
L = []
# K is the antipode inverse list.
# for all i, vertex L[i] is the antipode of vertex K[i]
K = []
# allocate some arrays for BFS
cdef MemoryAllocator mem = MemoryAllocator()
cdef bitset_t seen
bitset_init(seen, n)
cdef uint32_t * distances = <uint32_t *>mem.malloc(4 * n * sizeof(uint32_t))
if not distances:
raise MemoryError()
cdef uint32_t * waiting_list = distances + n
# e_L[i] lowerbound on eccentricity of vertex i
cdef uint32_t* e_L = distances + 2 * n
memset(e_L, 0, n*sizeof(uint32_t))
# e[i] is the exact eccentricity of vertex i, for i in set K
cdef uint32_t* e = distances + 3 * n
memset(e, 0, n*sizeof(uint32_t))
# if graph is unconnected, radius is infinity
LB = simple_BFS(g, 0, distances, NULL, waiting_list, seen)
return LB
while True:
# select vertex u with a minimal eccentricity lower bound
min_e_L = UINT32_MAX
u = 0
for i in range(n):
min_e_L = e_L[i]
u = i
# find the exact eccentricity of vertex u
e[u] = simple_BFS(g, u, distances, NULL, waiting_list, seen)
# if the exact eccentricity of u equals the minimal lower bound of
# eccentricities, terminate and return eccentricity of u as radius since
# the radius can't be any lower than the minimal lower bound.
return e[u]
# if the eccentricity lower bounds are not tight, we try to improve
# them
max_Duv = 0
a = 0
# select any vertex a, such that dist(u,a) = eccentricity(u)
# thus a is the antipode of u
for i in range(n):
max_Duv = distances[i]
a = i
# calculate the distances from a,
x = simple_BFS(g, a, distances, NULL, waiting_list, seen)
# add u to the antipode_inverse list
# add a to the lower certificate
# update the lower bounds using distance from a
for i in range(n):
e_L[i]= max(e_L[i], distances[i])
# find -minimal eccentricity lowerbound of all vertices
min_e_L = min([e_L[p] for p in range(n)])
# find minimum of exact eccentricities of vertices in set K
min_e_K = min([e[h] for h in K])
# if minimum eccentricity lower bound is greater than minimum of exact
# eccentricities of K, then return minimum exact eccentricity
# from K as the radius
if(min_e_K <= min_e_L) :
return min_e_K
def radius(G, algorithm="radius-certificate"):
Return the radius of `G`.
This algorithm returns Infinity if the (di)graph is not connected.
- ``algorithm`` -- (default: ``'radius-certificate'``) specifies the
algorithm to use among:
- ``'radius-certificate'`` -- The radius algorithm,
proposed in [DHV2018]_, computes the exact value of the radius of an
unweighted undirected graph.
It can be very fast in practice.
sage: from sage.graphs.distances_all_pairs import radius
sage: G = Graph(4)
sage: while not G.is_connected():
....: G = graphs.RandomGNP(1000,0.008)
sage: radius(G, algorithm='radius-certificate')
sage: G = Graph({0: [], 1: [], 2: [1]})
sage: radius(G, algorithm='radius-certificate')
cdef int n = G.order()
if not n:
return 0
if algorithm not in ['radius-certificate']:
raise ValueError("unknown algorithm for computing the radius")
if G.is_directed():
raise ValueError("algorithm '" + algorithm + "' does not work" +
" on directed graphs")
# Copying the whole graph to obtain the list of neighbors quicker than by
# calling out_neighbors. This data structure is well documented in the
# module sage.graphs.base.static_sparse_graph
cdef list int_to_vertex = list(G)
cdef short_digraph sd
init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex)
cdef int LB =0
LB =radius_certificate(sd)
if LB < 0 or LB > n:
from sage.rings.infinity import Infinity
return +Infinity
return int(LB)
......@@ -14742,8 +14742,14 @@ class GenericGraph(GenericGraph_pyx):
- ``by_weight`` -- boolean (default: ``False``); if ``True``, edge
weights are taken into account; if False, all edges have weight 1
- ``algorithm`` -- string (default: ``None``); see method
:meth:`eccentricity` for the list of available algorithms
- ``algorithm`` -- string (default: ``None``); in addition to the list
of algorithms in method :meth:`eccentricity`, the following algorithms
are available:
- ``'radius-certificate'``: this algorithm is implemented in
It works only if ``by_weight==False`` and graph is undirected.
See the function documentation for more information.
- ``weight_function`` -- function (default: ``None``); a function that
takes as input an edge ``(u, v, l)`` and outputs its weight. If not
......@@ -14783,6 +14789,19 @@ class GenericGraph(GenericGraph_pyx):
if not self.order():
raise ValueError("radius is not defined for the empty graph")
if weight_function is not None:
by_weight = True
if algorithm in ['radius-certificate']:
if by_weight:
raise ValueError("algorithm '" + algorithm + "' does not work" +
" on weighted graphs")
if self.is_directed():
raise ValueError("algorithm '" + algorithm + "' does not work" +
" on directed graphs")
from sage.graphs.distances_all_pairs import radius
return radius(self, algorithm=algorithm)
return min(self.eccentricity(v=list(self), by_weight=by_weight,