Ticket #7966: trac_7966.patch

File trac_7966.patch, 9.2 KB (added by ncohen, 9 years ago)
  • sage/graphs/base/c_graph.pyx

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1263742513 -3600
    # Node ID 92d49144b85e53672012c358da97dcad49418858
    # Parent  886b9d327712e66bd2fe99a5f68f18c01b327645
    trac 7966 : Speeding up distance computations in Graphs
    
    diff -r 886b9d327712 -r 92d49144b85e sage/graphs/base/c_graph.pyx
    a b  
    13881388            shortest_path.append(y)
    13891389
    13901390            return shortest_path
     1391
     1392    def shortest_path_all_vertices(self, v, cutoff = None):
     1393        r"""
     1394        Returns for each vertex `u` a shortest  `v-u` path.
     1395
     1396        INPUT:
     1397
     1398        - ``v`` -- a vertex
     1399        - ``cutoff`` -- maximal distance. Longer paths will not be returned
     1400
     1401        OUTPUT:
     1402
     1403        A list which associates to each vertex `u` the shortest path between
     1404        `u` and `v` if there is one.
     1405
     1406        NOTE:
     1407
     1408        - The weight of edges is not taken into account.
     1409
     1410        ALGORITHM:
     1411
     1412        This is just a breadth-first search.
     1413
     1414        EXAMPLES:
     1415
     1416        On the Petersen Graph::
     1417
     1418            sage: g = graphs.PetersenGraph()
     1419            sage: paths = g._backend.shortest_path_all_vertices(0)
     1420            sage: all([ len(paths[v]) == 0 or len(paths[v])-1 == g.distance(0,v) for v in g])
     1421            True
     1422
     1423        On a disconnected graph ::
     1424
     1425            sage: g = 2*graphs.RandomGNP(20,.3)
     1426            sage: paths = g._backend.shortest_path_all_vertices(0)
     1427            sage: all([ (not paths.has_key(v) and g.distance(0,v) == +Infinity) or len(paths[v])-1 == g.distance(0,v) for v in g])
     1428            True
     1429        """
     1430        cdef list current_layer
     1431        cdef list next_layer
     1432        cdef bitset_t seen
     1433        cdef int v_int
     1434        cdef int u_int
     1435        cdef dict distances_int
     1436        cdef dict distance
     1437        cdef int d
     1438
     1439        distances = {}
     1440        d = 0
     1441   
     1442        v_int = get_vertex(v, self.vertex_ints, self.vertex_labels, self._cg)
     1443
     1444        bitset_init(seen,(<CGraph>self._cg).active_vertices.size)
     1445        bitset_set_first_n(seen,0)
     1446        bitset_add(seen,v_int)
     1447   
     1448       
     1449        current_layer = [(u_int, v_int) for u_int in self._cg.out_neighbors(v_int)]
     1450        next_layer = []
     1451        distances[v] = [v]
     1452
     1453        while current_layer:
     1454            if cutoff is not None and d >= cutoff:
     1455                break
     1456
     1457            while current_layer:
     1458                v_int, u_int = current_layer.pop()
     1459   
     1460                if bitset_not_in(seen,v_int):
     1461                    bitset_add(seen,v_int)
     1462                    distances[vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)] = distances[vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg)] + [vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)]
     1463                    next_layer.extend([(u_int,v_int) for u_int in self._cg.out_neighbors(v_int)])
     1464
     1465            current_layer = next_layer
     1466            next_layer = []
     1467            d += 1
     1468
     1469        # If the graph is not connected, vertices which have not been
     1470        # seen should be associated to the empty path
     1471
     1472        #for 0 <= v_int < (<CGraph>self._cg).active_vertices.size:
     1473        #    if bitset_in((<CGraph>self._cg).active_vertices, v_int) and not bitset_in(seen, v_int):
     1474        #        distances[vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)] = []
     1475                   
     1476        bitset_free(seen)
     1477        return distances   
     1478
    13911479           
    13921480    def depth_first_search(self, v, reverse=False, ignore_direction=False):
    13931481        r"""
  • sage/graphs/generic_graph.py

    diff -r 886b9d327712 -r 92d49144b85e sage/graphs/generic_graph.py
    a b  
    67636763        """
    67646764        return self.shortest_path_length(u, v)
    67656765
     6766    def distance_all_pairs(self):
     6767        r"""
     6768        Returns the distances between all pairs of vertices.
     6769
     6770        OUTPUT:
     6771
     6772        A doubly indexed dictionary
     6773
     6774        EXAMPLE:
     6775
     6776        The Petersen Graph::
     6777       
     6778            sage: g = graphs.PetersenGraph()
     6779            sage: print g.distance_all_pairs()
     6780            {0: {0: 0, 1: 1, 2: 2, 3: 2, 4: 1, 5: 1, 6: 2, 7: 2, 8: 2, 9: 2}, 1: {0: 1, 1: 0, 2: 1, 3: 2, 4: 2, 5: 2, 6: 1, 7: 2, 8: 2, 9: 2}, 2: {0: 2, 1: 1, 2: 0, 3: 1, 4: 2, 5: 2, 6: 2, 7: 1, 8: 2, 9: 2}, 3: {0: 2, 1: 2, 2: 1, 3: 0, 4: 1, 5: 2, 6: 2, 7: 2, 8: 1, 9: 2}, 4: {0: 1, 1: 2, 2: 2, 3: 1, 4: 0, 5: 2, 6: 2, 7: 2, 8: 2, 9: 1}, 5: {0: 1, 1: 2, 2: 2, 3: 2, 4: 2, 5: 0, 6: 2, 7: 1, 8: 1, 9: 2}, 6: {0: 2, 1: 1, 2: 2, 3: 2, 4: 2, 5: 2, 6: 0, 7: 2, 8: 1, 9: 1}, 7: {0: 2, 1: 2, 2: 1, 3: 2, 4: 2, 5: 1, 6: 2, 7: 0, 8: 2, 9: 1}, 8: {0: 2, 1: 2, 2: 2, 3: 1, 4: 2, 5: 1, 6: 1, 7: 2, 8: 0, 9: 2}, 9: {0: 2, 1: 2, 2: 2, 3: 2, 4: 1, 5: 2, 6: 1, 7: 1, 8: 2, 9: 0}}
     6781
     6782        Testing on Random Graphs::
     6783
     6784            sage: g = graphs.RandomGNP(20,.3)
     6785            sage: distances = g.distance_all_pairs()
     6786            sage: all([g.distance(0,v) == distances[0][v] for v in g])
     6787            True
     6788        """
     6789
     6790        from sage.rings.infinity import Infinity
     6791        distances = dict([(v, self.shortest_path_lengths(v)) for v in self])
     6792       
     6793        # setting the necessary +Infinity
     6794        cc = self.connected_components()
     6795        for cc1 in cc:
     6796            for cc2 in cc:
     6797                if cc1 != cc2:
     6798                    for u in cc1:
     6799                        for v in cc2:
     6800                            distances[u][v] = Infinity
     6801
     6802        return distances
     6803
    67666804    def eccentricity(self, v=None, dist_dict=None, with_labels=False):
    67676805        """
    67686806        Return the eccentricity of vertex (or vertices) v.
     
    70807118        else:
    70817119            dstring = "distances " + str(sorted(distances))
    70827120        D.name("Distance graph for %s in " % dstring + self.name())
     7121
    70837122        # Create the appropriate edges
    7084         # Using shortest_path_all_pairs() here is much slower, see Trac 7533
     7123        d = self.distance_all_pairs()
    70857124        for u in self.vertex_iterator():
    70867125            for v in self.vertex_iterator():
    7087                 if self.distance(u,v) in distances:
     7126                if d[u][v] in distances:
    70887127                    D.add_edge(u,v)
    70897128        return D
    70907129
     
    74777516       
    74787517            sage: D = graphs.DodecahedralGraph()
    74797518            sage: D.shortest_paths(0)
    7480             {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 19, 3], 4: [0, 19, 3, 4], 5: [0, 19, 3, 4, 5], 6: [0, 1, 2, 6], 7: [0, 1, 8, 7], 8: [0, 1, 8], 9: [0, 10, 9], 10: [0, 10], 11: [0, 10, 11], 12: [0, 10, 11, 12], 13: [0, 10, 9, 13], 14: [0, 1, 8, 7, 14], 15: [0, 10, 11, 12, 16, 15], 16: [0, 10, 11, 12, 16], 17: [0, 19, 18, 17], 18: [0, 19, 18], 19: [0, 19]}
     7519            {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 19, 3], 4: [0, 19, 3, 4], 5: [0, 1, 2, 6, 5], 6: [0, 1, 2, 6], 7: [0, 1, 8, 7], 8: [0, 1, 8], 9: [0, 10, 9], 10: [0, 10], 11: [0, 10, 11], 12: [0, 10, 11, 12], 13: [0, 10, 9, 13], 14: [0, 1, 8, 7, 14], 15: [0, 19, 18, 17, 16, 15], 16: [0, 19, 18, 17, 16], 17: [0, 19, 18, 17], 18: [0, 19, 18], 19: [0, 19]}
     7520
     7521        All these paths are obviously induced graphs::
     7522       
     7523            sage: all([D.subgraph(p).is_isomorphic(graphs.PathGraph(len(p)) )for p in D.shortest_paths(0).values()])
     7524            True
     7525
     7526        ::
     7527
    74817528            sage: D.shortest_paths(0, cutoff=2)
    74827529            {0: [0], 1: [0, 1], 2: [0, 1, 2], 3: [0, 19, 3], 8: [0, 1, 8], 9: [0, 10, 9], 10: [0, 10], 11: [0, 10, 11], 18: [0, 19, 18], 19: [0, 19]}
    74837530            sage: G = Graph( { 0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2} }, sparse=True)
     
    74897536        if by_weight:
    74907537            return networkx.single_source_dijkstra_path(self.networkx_graph(copy=False), u)
    74917538        else:
    7492             return networkx.single_source_shortest_path(self.networkx_graph(copy=False), u, cutoff)
     7539            try:
     7540                return self._backend.shortest_path_all_vertices(u, cutoff)
     7541            except AttributeError:
     7542                return networkx.single_source_shortest_path(self.networkx_graph(copy=False), u, cutoff)
    74937543   
    74947544    def shortest_path_lengths(self, u, by_weight=False, weight_sums=None):
    74957545        """
     
    76817731     
    76827732        """
    76837733
    7684         distances=self.shortest_path_all_pairs(default_weight=ZZ(1))[0]
    7685         return sum([sum(v.itervalues()) for v in distances.itervalues()])/2
     7734        return sum([sum(v.itervalues()) for v in self.distance_all_pairs().itervalues()])/2
    76867735
    76877736    def average_distance(self):
    76887737        r"""
     
    77127761
    77137762        """
    77147763
    7715         return self.wiener_index()/((self.order()*(self.order()-1))/2)
     7764        return Integer(self.wiener_index())/Integer((self.order()*(self.order()-1))/2)
    77167765
    77177766    def szeged_index(self):
    77187767        r"""
     
    77477796          Applied Mathematics Letters, 9 (5), pp. 45-49.
    77487797
    77497798        """
    7750         distances=self.shortest_path_all_pairs()[0]
     7799        distances=self.distance_all_pairs()
    77517800        s=0
    77527801        for (u,v) in self.edges(labels=None):
    77537802            du=distances[u]
     
    77617810            s+=(n1*n2)
    77627811        return s
    77637812               
    7764            
    7765        
    7766 
    77677813    ### Searches
    77687814   
    77697815    def breadth_first_search(self, start, ignore_direction=False, distance=None, neighbors=None):