@@ -13,13 +13,10 @@ the following methods:
1313 :meth:`ConvexityProperties. hull` | Return the convex hull of a set of vertices
1414 :meth:`ConvexityProperties. hull_number` | Compute the hull number of a graph and a corresponding generating set
1515 :meth:`geodetic_closure`| Return the geodetic closure of a set of vertices
16+ :meth:`is_geodetic` | Check whether the input ( di) graph is geodetic
1617
17- These methods can be used through the :class:`ConvexityProperties` object
18- returned by :meth:`Graph. convexity_properties`.
19-
20- AUTHORS:
21-
22- - Nathann Cohen
18+ Some of these methods can be used through the :class:`ConvexityProperties`
19+ object returned by :meth:`Graph. convexity_properties`.
2320
2421Methods
2522-------
@@ -674,3 +671,156 @@ def geodetic_closure(G, S):
674671 free_short_digraph(sd)
675672
676673 return ret
674+
675+
676+ def is_geodetic (G ):
677+ r """
678+ Check whether the input ( di) graph is geodetic.
679+
680+ A graph `G` is * geodetic* if there exists only one shortest path between
681+ every pair of its vertices. This can be checked in time `O( nm) ` in
682+ unweighted ( di) graphs with `n` nodes and `m` edges. Examples of geodetic
683+ graphs are trees, cliques and odd cycles. See the
684+ :wikipedia:`Geodetic_graph` for more details.
685+
686+ ( Di) graphs with multiple edges are not considered geodetic.
687+
688+ INPUT:
689+
690+ - ``G`` -- a graph or a digraph
691+
692+ EXAMPLES:
693+
694+ Trees, cliques and odd cycles are geodetic::
695+
696+ sage: T = graphs. RandomTree( 20)
697+ sage: T. is_geodetic( )
698+ True
699+ sage: all( graphs. CompleteGraph( n) . is_geodetic( ) for n in range( 8))
700+ True
701+ sage: all( graphs. CycleGraph( n) . is_geodetic( ) for n in range( 3, 16, 2))
702+ True
703+
704+ Even cycles of order at least 4 are not geodetic::
705+
706+ sage: all( graphs. CycleGraph( n) . is_geodetic( ) for n in range( 4, 17, 2))
707+ False
708+
709+ The Petersen graph is geodetic::
710+
711+ sage: P = graphs. PetersenGraph( )
712+ sage: P. is_geodetic( )
713+ True
714+
715+ Grid graphs are not geodetic::
716+
717+ sage: G = graphs. Grid2dGraph( 2, 3)
718+ sage: G. is_geodetic( )
719+ False
720+
721+ This method is also valid for digraphs::
722+
723+ sage: G = DiGraph( graphs. PetersenGraph( ))
724+ sage: G. is_geodetic( )
725+ True
726+ sage: G = digraphs. Path( 5)
727+ sage: G. add_path( [0, 'a', 'b', 'c', 4 ])
728+ sage: G. is_geodetic( )
729+ False
730+
731+ TESTS::
732+
733+ sage: all( g. is_geodetic( ) for g in graphs( 3))
734+ True
735+ sage: all(( 2* g) . is_geodetic( ) for g in graphs( 3))
736+ True
737+ sage: G = graphs. CycleGraph( 5)
738+ sage: G. allow_loops( True)
739+ sage: G. add_edges( [(u, u) for u in G ])
740+ sage: G. is_geodetic( )
741+ True
742+ sage: G. allow_multiple_edges( True)
743+ sage: G. is_geodetic( )
744+ True
745+ sage: G. add_edge( G. random_edge( ))
746+ sage: G. is_geodetic( )
747+ False
748+ """
749+ if G.has_multiple_edges():
750+ return False
751+
752+ if G.order() < 4 :
753+ return True
754+
755+ # Copy the graph as a short digraph
756+ cdef int n = G.order()
757+ cdef short_digraph sd
758+ init_short_digraph(sd, G, edge_labelled = False , vertex_list = list (G))
759+
760+ # Allocate some data structures
761+ cdef MemoryAllocator mem = MemoryAllocator()
762+ cdef uint32_t * distances = < uint32_t * > mem.malloc(n * sizeof(uint32_t))
763+ cdef uint32_t * waiting_list = < uint32_t * > mem.malloc(n * sizeof(uint32_t))
764+ if not distances or not waiting_list:
765+ free_short_digraph(sd)
766+ raise MemoryError ()
767+ cdef bitset_t seen
768+ bitset_init(seen, n)
769+
770+ # We now explore geodesics between vertices in S, and we avoid visiting
771+ # twice the geodesics between u and v
772+
773+ cdef uint32_t source, u, v
774+ cdef uint32_t waiting_beginning
775+ cdef uint32_t waiting_end
776+ cdef uint32_t * p_tmp
777+ cdef uint32_t * end
778+ cdef uint32_t ** p_vertices = sd.neighbors
779+
780+ for source in range (n):
781+
782+ # Compute distances from source using BFS
783+ bitset_clear(seen)
784+ bitset_add(seen, source)
785+ distances[source] = 0
786+ waiting_beginning = 0
787+ waiting_end = 0
788+ waiting_list[waiting_beginning] = source
789+
790+ # For as long as there are vertices left to explore
791+ while waiting_beginning <= waiting_end:
792+
793+ # We pick the first one
794+ v = waiting_list[waiting_beginning]
795+ p_tmp = p_vertices[v]
796+ end = p_vertices[v + 1 ]
797+
798+ # and we iterate over all the outneighbors u of v
799+ while p_tmp < end:
800+ u = p_tmp[0 ]
801+
802+ # If we notice one of these neighbors is not seen yet, we set
803+ # its parameters and add it to the queue to be explored later.
804+ # Otherwise, we check whether we have detected a second shortest
805+ # path between source and v.
806+ if not bitset_in(seen, u):
807+ distances[u] = distances[v] + 1
808+ bitset_add(seen, u)
809+ waiting_end += 1
810+ waiting_list[waiting_end] = u
811+ elif distances[u] == distances[v] + 1 :
812+ # G is not geodetic
813+ bitset_free(seen)
814+ free_short_digraph(sd)
815+ return False
816+
817+ p_tmp += 1
818+
819+ # We go to the next vertex in the queue
820+ waiting_beginning += 1
821+
822+ bitset_free(seen)
823+ free_short_digraph(sd)
824+
825+ # The graph is geodetic
826+ return True
0 commit comments