Ticket #7184: trac_7184-reviewer.patch

File trac_7184-reviewer.patch, 7.5 KB (added by ncohen, 11 years ago)
  • sage/graphs/graph.py

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1255872109 -7200
    # Node ID 2a46f1db3fc58c127b95367564f9444319f354dd
    # Parent  9c002164e33a27cee061ed47c149172ae2b756fa
    implements spanning_tree_count and fixes some errors in kirchhoff_matrix
    
    diff -r 9c002164e33a -r 2a46f1db3fc5 sage/graphs/graph.py
    a b  
    6363-  Stephen Hartke (2009-08-22): Fixed bug in blocks_and_cut_vertices()
    6464   where the list of cut_vertices is not treated as a set.
    6565
     66-  Anders Jonsson (2009-10-10): Counting of spanning trees and out-trees added.
     67
    6668
    6769Graph Format
    6870------------
     
    11141116        M = matrix(self.num_verts(), D, sparse=sparse)
    11151117        return M
    11161118
    1117     def kirchhoff_matrix(self, weighted=None, **kwds):
     1119    def kirchhoff_matrix(self, weighted=None, indegree=True, **kwds):
    11181120        """
    11191121        Returns the Kirchhoff matrix (a.k.a. the Laplacian) of the graph.
    11201122       
    1121         The Kirchhoff matrix is defined to be D - M, where D is the
     1123        The Kirchhoff matrix is defined to be `D - M`, where `D` is the
    11221124        diagonal degree matrix (each diagonal entry is the degree of the
    1123         corresponding vertex), and M is the adjacency matrix.
    1124        
    1125         If weighted == True, the weighted adjacency matrix is used for M,
    1126         and the diagonal entries are the row-sums of M.
     1125        corresponding vertex), and `M` is the adjacency matrix.
     1126
     1127        ( In the special case of DiGraphs, `D` is defined as the diagonal
     1128        in-degree matrix or diagonal out-degree matrix according to the
     1129        value of ``indegree``)
     1130       
     1131        INPUT:
     1132
     1133        - ``weighted`` -- Binary variable :
     1134            - If ``weighted == True``, the weighted adjacency matrix is used for `M`,
     1135              and the diagonal matrix `D` takes into account the weight of edges
     1136              (replace in the definition "degree" by "sum of the incident edges" ).
     1137            - Else, each edge is assumed to have weight 1.
     1138           
     1139            Default is to take weights into consideration if and only if the graph is
     1140            weighted.
     1141
     1142        - ``indegree`` -- Binary variable  :
     1143            - If ``indegree=True``, each diagonal entry of `D` is equal to the
     1144              in-degree of the corresponding vertex.
     1145            - Else, each diagonal entry of `D` is equal to the
     1146              out-degree of the corresponding vertex.
     1147             
     1148              By default, ``indegree`` is set to ``True``
     1149
     1150            ( This variable only matters when the graph is a digraph )
    11271151
    11281152        Note that any additional keywords will be passed on to either
    1129         the adjacency_matrix or weighted_adjacency_matrix method.
     1153        the ``adjacency_matrix`` or ``weighted_adjacency_matrix`` method.
    11301154
    11311155        AUTHORS:
    11321156             
     
    11681192            [-1 -1  3 -1]
    11691193            [-1  0 -1  2]
    11701194
    1171         A weighted directed graph with loops::
     1195        A weighted directed graph with loops, changing the variable ``indegree`` ::
    11721196
    11731197            sage: G = DiGraph({1:{1:2,2:3}, 2:{1:4}}, weighted=True,sparse=True)
    11741198            sage: G.laplacian_matrix()
     1199            [ 4 -3]
     1200            [-4  3]
     1201
     1202::
     1203
     1204            sage: G = DiGraph({1:{1:2,2:3}, 2:{1:4}}, weighted=True,sparse=True)
     1205            sage: G.laplacian_matrix(indegree=False)
    11751206            [ 3 -3]
    11761207            [-4  4]
    11771208        """
     
    11881219           
    11891220        A = -M
    11901221
     1222
    11911223        if M.is_sparse():
    11921224            row_sums = {}
    1193             for (i,j), entry in M.dict().iteritems():
    1194                 row_sums[i] = row_sums.get(i, 0) + entry
    1195         else:
    1196             ones = matrix(M.base_ring(), M.nrows(), 1, [1]*M.nrows())
    1197             S = M*ones
    1198             row_sums = dict((i, S[i,0]) for i in range(M.nrows()))
    1199                
    1200         for i in range(M.nrows()):
    1201             A[i,i] += row_sums.get(i, 0)
     1225            if indegree:
     1226                for (i,j), entry in M.dict().iteritems():
     1227                    row_sums[j] = row_sums.get(j, 0) + entry
     1228            else:
     1229                for (i,j), entry in M.dict().iteritems():
     1230                    row_sums[i] = row_sums.get(i, 0) + entry
     1231
     1232
     1233            for i in range(M.nrows()):
     1234                A[i,i] += row_sums.get(i, 0)
     1235
     1236        else:
     1237            if indegree:
     1238                ones = matrix(M.base_ring(), 1,  M.nrows(), [1]*M.nrows())
     1239                S = ones*M
     1240                for i in range(M.nrows()):
     1241                    A[i,i] += S[0,i]
     1242            else:
     1243                ones = matrix(M.base_ring(),  M.nrows(), 1, [1]*M.nrows())
     1244                S = M*ones
     1245                for i in range(M.nrows()):
     1246                    A[i,i] += S[i,0]
    12021247        return A
    12031248
    12041249    laplacian_matrix = kirchhoff_matrix
     
    21052150
    21062151    num_edges = size
    21072152
     2153    def spanning_trees_count(self, root_vertex=None):
     2154        """
     2155        Returns the number of spanning trees in a graph. In the case of a
     2156        digraph, couts the number of spanning out-trees rooted in
     2157        ``root_vertex``.
     2158        Default is to set first vertex as root.
     2159       
     2160        This computation uses Kirchhoff's Matrix Tree Theorem [1] to calculate
     2161        the number of spanning trees. For complete graphs on `n` vertices the
     2162        result can also be reached using Cayley's formula: the number of
     2163        spanning trees are `n^(n-2)`.
     2164       
     2165        For digraphs, the augmented Kirchhoff Matrix as defined in [2] is
     2166        used for calculations. Here the result is the number of out-trees
     2167        rooted at a specific vertex.
     2168         
     2169        INPUT:
     2170 
     2171        - ``root_vertex`` -- integer (default: the first vertex) This is the vertex
     2172        that will be used as root for all spanning out-trees if the graph
     2173        is a directed graph.
     2174        This argument is ignored if the graph is not a digraph.
     2175         
     2176        REFERENCES:
     2177         
     2178        - [1] http://mathworld.wolfram.com/MatrixTreeTheorem.html
     2179         
     2180        - [2] Lih-Hsing Hsu, Cheng-Kuan Lin, "Graph Theory and Interconnection
     2181        Networks"
     2182         
     2183        AUTHORS:
     2184         
     2185        - Anders Jonsson (2009-10-10)
     2186         
     2187        EXAMPLES::
     2188         
     2189            sage: G = graphs.PetersenGraph()
     2190            sage: G.spanning_trees_count()
     2191            2000
     2192         
     2193        ::
     2194         
     2195            sage: n = 11
     2196            sage: G = graphs.CompleteGraph(n)
     2197            sage: ST = G.spanning_trees_count()
     2198            sage: ST == n^(n-2)
     2199            True
     2200         
     2201        ::
     2202         
     2203            sage: M=matrix(3,3,[0,1,0,0,0,1,1,1,0])
     2204            sage: D=DiGraph(M)
     2205            sage: D.spanning_trees_count()
     2206            1
     2207            sage: D.spanning_trees_count(0)
     2208            1
     2209            sage: D.spanning_trees_count(2)
     2210            2
     2211         
     2212        """
     2213        if self.is_directed() == False:
     2214            M=self.kirchhoff_matrix()
     2215            M.subdivide(1,1)
     2216            M2 = M.subdivision(1,1)
     2217            return abs(M2.determinant())
     2218        else:
     2219            if root_vertex == None:
     2220                root_vertex=self.vertex_iterator().next()
     2221            if root_vertex not in self.vertices():
     2222                raise ValueError, ("Vertex (%s) not in the graph."%root_vertex)
     2223 
     2224            M=self.kirchhoff_matrix()
     2225
     2226            index=self.vertices().index(root_vertex)
     2227            M[index,index]+=1
     2228            return abs(M.determinant())   
     2229
    21082230    ### Planarity
    21092231
    21102232    def is_planar(self, on_embedding=None, kuratowski=False, set_embedding=False, set_pos=False):