Ticket #13784: trac_13784.patch

File trac_13784.patch, 44.8 KB (added by ncohen, 8 years ago)
  • sage/graphs/generic_graph.py

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1354362247 -3600
    # Node ID 76c0c1b4aee6a503ca4569e9b3de9b7cc468cb3f
    # Parent  654bc12b640b8bc0fa5da75f62f4ecfda1a351ac
    Move methods from GenericGraph to Graph
    
    diff --git a/sage/graphs/generic_graph.py b/sage/graphs/generic_graph.py
    a b  
    297297    :meth:`~GenericGraph.genus` | Returns the minimal genus of the graph.
    298298    :meth:`~GenericGraph.trace_faces` | A helper function for finding the genus of a graph.
    299299
    300 **Graph stuff that should not be in this file:**
    301 
    302 .. csv-table::
    303     :class: contentstable
    304     :widths: 30, 70
    305     :delim: |
    306 
    307     :meth:`~GenericGraph.minimum_outdegree_orientation` | Returns an orientation of ``self`` with the smallest possible maximum outdegree
    308     :meth:`~GenericGraph.matching` | Returns a maximum weighted matching of the graph
    309     :meth:`~GenericGraph.maximum_average_degree` | Returns the Maximum Average Degree (MAD) of the current graph.
    310     :meth:`~GenericGraph.cores` | Returns the core number for each vertex in an ordered list.
    311 
    312 
    313300Methods
    314301-------
    315302"""
     
    28482835        import networkx
    28492836        return networkx.cycle_basis(self.networkx_graph(copy=False))
    28502837
    2851     def minimum_outdegree_orientation(self, use_edge_labels=False, solver=None, verbose=0):
    2852         r"""
    2853         Returns an orientation of ``self`` with the smallest possible maximum
    2854         outdegree.
    2855 
    2856         Given a Graph `G`, is is polynomial to compute an orientation
    2857         `D` of the edges of `G` such that the maximum out-degree in
    2858         `D` is minimized. This problem, though, is NP-complete in the
    2859         weighted case [AMOZ06]_.
    2860 
    2861         INPUT:
    2862 
    2863         - ``use_edge_labels`` -- boolean (default: ``False``)
    2864 
    2865           - When set to ``True``, uses edge labels as weights to
    2866             compute the orientation and assumes a weight of `1`
    2867             when there is no value available for a given edge.
    2868 
    2869           - When set to ``False`` (default), gives a weight of 1
    2870             to all the edges.
    2871 
    2872         - ``solver`` -- (default: ``None``) Specify a Linear Program (LP)
    2873           solver to be used. If set to ``None``, the default one is used. For
    2874           more information on LP solvers and which default solver is used, see
    2875           the method
    2876           :meth:`solve <sage.numerical.mip.MixedIntegerLinearProgram.solve>`
    2877           of the class
    2878           :class:`MixedIntegerLinearProgram <sage.numerical.mip.MixedIntegerLinearProgram>`.
    2879 
    2880         - ``verbose`` -- integer (default: ``0``). Sets the level of
    2881           verbosity. Set to 0 by default, which means quiet.
    2882 
    2883         EXAMPLE:
    2884 
    2885         Given a complete bipartite graph `K_{n,m}`, the maximum out-degree
    2886         of an optimal orientation is `\left\lceil \frac {nm} {n+m}\right\rceil`::
    2887 
    2888             sage: g = graphs.CompleteBipartiteGraph(3,4)
    2889             sage: o = g.minimum_outdegree_orientation()
    2890             sage: max(o.out_degree()) == ceil((4*3)/(3+4))
    2891             True
    2892 
    2893         REFERENCES:
    2894        
    2895         .. [AMOZ06] Asahiro, Y. and Miyano, E. and Ono, H. and Zenmyo, K.
    2896           Graph orientation algorithms to minimize the maximum outdegree
    2897           Proceedings of the 12th Computing: The Australasian Theory Symposium
    2898           Volume 51, page 20
    2899           Australian Computer Society, Inc. 2006
    2900         """
    2901 
    2902         if self.is_directed():
    2903             raise ValueError("Cannot compute an orientation of a DiGraph. "+\
    2904                                  "Please convert it to a Graph if you really mean it.")
    2905 
    2906         if use_edge_labels:
    2907             from sage.rings.real_mpfr import RR
    2908             weight = lambda u,v : self.edge_label(u,v) if self.edge_label(u,v) in RR else 1
    2909         else:
    2910             weight = lambda u,v : 1
    2911 
    2912         from sage.numerical.mip import MixedIntegerLinearProgram
    2913        
    2914         p = MixedIntegerLinearProgram(maximization=False, solver=solver)
    2915 
    2916         # The orientation of an edge is boolean
    2917         # and indicates whether the edge uv
    2918         # with u<v goes from u to v ( equal to 0 )
    2919         # or from v to u ( equal to 1)
    2920         orientation = p.new_variable(dim=2)
    2921        
    2922         degree = p.new_variable()
    2923 
    2924         # Whether an edge adjacent to a vertex u counts
    2925         # positively or negatively
    2926         outgoing = lambda u,v,variable : (1-variable) if u>v else variable
    2927        
    2928         for u in self:
    2929             p.add_constraint(p.sum([weight(u,v)*outgoing(u,v,orientation[min(u,v)][max(u,v)]) for v in self.neighbors(u)])-degree['max'],max=0)
    2930 
    2931         p.set_objective(degree['max'])
    2932 
    2933         p.set_binary(orientation)
    2934 
    2935         p.solve(log=verbose)
    2936 
    2937         orientation = p.get_values(orientation)
    2938 
    2939         # All the edges from self are doubled in O
    2940         # ( one in each direction )
    2941         from sage.graphs.digraph import DiGraph
    2942         O = DiGraph(self)
    2943 
    2944         # Builds the list of edges that should be removed
    2945         edges=[]
    2946 
    2947         for u,v in self.edge_iterator(labels=None):
    2948             # assumes u<v
    2949             if u>v:
    2950                 u,v=v,u
    2951 
    2952             if orientation[min(u,v)][max(u,v)] == 1:
    2953                 edges.append((max(u,v),min(u,v)))
    2954             else:
    2955                 edges.append((min(u,v),max(u,v)))
    2956 
    2957         O.delete_edges(edges)
    2958 
    2959         return O
    2960 
    29612838    ### Planarity
    29622839
    29632840    def is_planar(self, on_embedding=None, kuratowski=False, set_embedding=False, set_pos=False):
     
    69376814
    69386815        return paths
    69396816
    6940     def matching(self, value_only=False, algorithm="Edmonds", use_edge_labels=True, solver=None, verbose=0):
    6941         r"""
    6942         Returns a maximum weighted matching of the graph
    6943         represented by the list of its edges. For more information, see the
    6944         `Wikipedia article on matchings
    6945         <http://en.wikipedia.org/wiki/Matching_%28graph_theory%29>`_.
    6946 
    6947         Given a graph `G` such that each edge `e` has a weight `w_e`,
    6948         a maximum matching is a subset `S` of the edges of `G` of
    6949         maximum weight such that no two edges of `S` are incident
    6950         with each other.
    6951 
    6952         As an optimization problem, it can be expressed as:
    6953 
    6954         .. math::
    6955 
    6956             \mbox{Maximize : }&\sum_{e\in G.edges()} w_e b_e\\
    6957             \mbox{Such that : }&\forall v \in G, \sum_{(u,v)\in G.edges()} b_{(u,v)}\leq 1\\
    6958             &\forall x\in G, b_x\mbox{ is a binary variable}
    6959 
    6960         INPUT:
    6961 
    6962         - ``value_only`` -- boolean (default: ``False``). When set to
    6963           ``True``, only the cardinal (or the weight) of the matching is
    6964           returned.
    6965 
    6966         - ``algorithm`` -- string (default: ``"Edmonds"``)
    6967 
    6968           - ``"Edmonds"`` selects Edmonds' algorithm as implemented in NetworkX
    6969 
    6970           - ``"LP"`` uses a Linear Program formulation of the matching problem
    6971 
    6972         - ``use_edge_labels`` -- boolean (default: ``False``)
    6973 
    6974           - When set to ``True``, computes a weighted matching where each edge
    6975             is weighted by its label. (If an edge has no label, `1` is assumed.)
    6976 
    6977           - When set to ``False``, each edge has weight `1`.
    6978 
    6979         - ``solver`` -- (default: ``None``) Specify a Linear Program (LP)
    6980           solver to be used. If set to ``None``, the default one is used. For
    6981           more information on LP solvers and which default solver is used, see
    6982           the method
    6983           :meth:`solve <sage.numerical.mip.MixedIntegerLinearProgram.solve>`
    6984           of the class
    6985           :class:`MixedIntegerLinearProgram <sage.numerical.mip.MixedIntegerLinearProgram>`.
    6986 
    6987         - ``verbose`` -- integer (default: ``0``). Sets the level of
    6988           verbosity. Set to 0 by default, which means quiet.
    6989           Only useful when ``algorithm == "LP"``.
    6990 
    6991         ALGORITHM:
    6992 
    6993         The problem is solved using Edmond's algorithm implemented in
    6994         NetworkX, or using Linear Programming depending on the value of
    6995         ``algorithm``.
    6996 
    6997         EXAMPLES:
    6998 
    6999         Maximum matching in a Pappus Graph::
    7000 
    7001            sage: g = graphs.PappusGraph()
    7002            sage: g.matching(value_only=True)
    7003            9.0
    7004 
    7005         Same test with the Linear Program formulation::
    7006 
    7007            sage: g = graphs.PappusGraph()
    7008            sage: g.matching(algorithm="LP", value_only=True)
    7009            9.0
    7010 
    7011         TESTS:
    7012 
    7013         If ``algorithm`` is set to anything different from ``"Edmonds"`` or
    7014         ``"LP"``, an exception is raised::
    7015 
    7016            sage: g = graphs.PappusGraph()
    7017            sage: g.matching(algorithm="somethingdifferent")
    7018            Traceback (most recent call last):
    7019            ...
    7020            ValueError: algorithm must be set to either "Edmonds" or "LP"
    7021         """
    7022         from sage.rings.real_mpfr import RR
    7023         weight = lambda x: x if x in RR else 1
    7024 
    7025         if algorithm == "Edmonds":
    7026             import networkx
    7027             if use_edge_labels:
    7028                 g = networkx.Graph()
    7029                 for u, v, l in self.edges():
    7030                     g.add_edge(u, v, attr_dict={"weight": weight(l)})
    7031             else:
    7032                 g = self.networkx_graph(copy=False)
    7033             d = networkx.max_weight_matching(g)
    7034             if value_only:
    7035                 if use_edge_labels:
    7036                     return sum([weight(self.edge_label(u, v))
    7037                                 for u, v in d.iteritems()]) * 0.5
    7038                 else:
    7039                     return Integer(len(d)/2)
    7040             else:
    7041                 return [(u, v, self.edge_label(u, v))
    7042                         for u, v in d.iteritems() if u < v]
    7043 
    7044         elif algorithm == "LP":
    7045             from sage.numerical.mip import MixedIntegerLinearProgram
    7046             g = self
    7047             # returns the weight of an edge considering it may not be
    7048             # weighted ...
    7049             p = MixedIntegerLinearProgram(maximization=True, solver=solver)
    7050             b = p.new_variable(dim=2)
    7051             p.set_objective(
    7052                 p.sum([weight(w) * b[min(u, v)][max(u, v)]
    7053                      for u, v, w in g.edges()]))
    7054             # for any vertex v, there is at most one edge incident to v in
    7055             # the maximum matching
    7056             for v in g.vertex_iterator():
    7057                 p.add_constraint(
    7058                     p.sum([b[min(u, v)][max(u, v)]
    7059                          for u in g.neighbors(v)]), max=1)
    7060             p.set_binary(b)
    7061             if value_only:
    7062                 if use_edge_labels:
    7063                     return p.solve(objective_only=True, log=verbose)
    7064                 else:
    7065                     return Integer(round(p.solve(objective_only=True, log=verbose)))
    7066             else:
    7067                 p.solve(log=verbose)
    7068                 b = p.get_values(b)
    7069                 return [(u, v, w) for u, v, w in g.edges()
    7070                         if b[min(u, v)][max(u, v)] == 1]
    7071 
    7072         else:
    7073             raise ValueError('algorithm must be set to either "Edmonds" or "LP"')
    7074 
    70756817    def dominating_set(self, independent=False, value_only=False, solver=None, verbose=0):
    70766818        r"""
    70776819        Returns a minimum dominating set of the graph
     
    94069148
    94079149        return 2*Integer(self.size())/Integer(self.order())
    94089150
    9409     def maximum_average_degree(self, value_only=True, solver = None, verbose = 0):
    9410         r"""
    9411         Returns the Maximum Average Degree (MAD) of the current graph.
    9412 
    9413         The Maximum Average Degree (MAD) of a graph is defined as
    9414         the average degree of its densest subgraph. More formally,
    9415         ``Mad(G) = \max_{H\subseteq G} Ad(H)``, where `Ad(G)` denotes
    9416         the average degree of `G`.
    9417 
    9418         This can be computed in polynomial time.
    9419 
    9420         INPUT:
    9421 
    9422         - ``value_only`` (boolean) -- ``True`` by default
    9423 
    9424             - If ``value_only=True``, only the numerical
    9425               value of the `MAD` is returned.
    9426 
    9427             - Else, the subgraph of `G` realizing the `MAD`
    9428               is returned.
    9429 
    9430         - ``solver`` -- (default: ``None``) Specify a Linear Program (LP)
    9431           solver to be used. If set to ``None``, the default one is used. For
    9432           more information on LP solvers and which default solver is used, see
    9433           the method
    9434           :meth:`solve <sage.numerical.mip.MixedIntegerLinearProgram.solve>`
    9435           of the class
    9436           :class:`MixedIntegerLinearProgram <sage.numerical.mip.MixedIntegerLinearProgram>`.
    9437 
    9438         - ``verbose`` -- integer (default: ``0``). Sets the level of
    9439           verbosity. Set to 0 by default, which means quiet.
    9440 
    9441         EXAMPLES:
    9442 
    9443         In any graph, the `Mad` is always larger than the average
    9444         degree::
    9445 
    9446             sage: g = graphs.RandomGNP(20,.3)
    9447             sage: mad_g = g.maximum_average_degree()
    9448             sage: g.average_degree() <= mad_g
    9449             True
    9450 
    9451         Unlike the average degree, the `Mad` of the disjoint
    9452         union of two graphs is the maximum of the `Mad` of each
    9453         graphs::
    9454 
    9455             sage: h = graphs.RandomGNP(20,.3)
    9456             sage: mad_h = h.maximum_average_degree()
    9457             sage: (g+h).maximum_average_degree() == max(mad_g, mad_h)
    9458             True
    9459 
    9460         The subgraph of a regular graph realizing the maximum
    9461         average degree is always the whole graph ::
    9462 
    9463             sage: g = graphs.CompleteGraph(5)
    9464             sage: mad_g = g.maximum_average_degree(value_only=False)
    9465             sage: g.is_isomorphic(mad_g)
    9466             True
    9467 
    9468         This also works for complete bipartite graphs ::
    9469 
    9470             sage: g = graphs.CompleteBipartiteGraph(3,4)
    9471             sage: mad_g = g.maximum_average_degree(value_only=False)
    9472             sage: g.is_isomorphic(mad_g)
    9473             True
    9474         """
    9475 
    9476         g = self
    9477         from sage.numerical.mip import MixedIntegerLinearProgram
    9478 
    9479         p = MixedIntegerLinearProgram(maximization=True, solver = solver)
    9480 
    9481         d = p.new_variable()
    9482         one = p.new_variable()
    9483 
    9484         # Reorders u and v so that uv and vu are not considered
    9485         # to be different edges
    9486         reorder = lambda u,v : (min(u,v),max(u,v))
    9487 
    9488         for u,v in g.edge_iterator(labels=False):
    9489             p.add_constraint( one[ reorder(u,v) ] - 2*d[u] , max = 0 )
    9490             p.add_constraint( one[ reorder(u,v) ] - 2*d[v] , max = 0 )
    9491 
    9492         p.add_constraint( p.sum([d[v] for v in g]), max = 1)
    9493 
    9494         p.set_objective( p.sum([ one[reorder(u,v)] for u,v in g.edge_iterator(labels=False)]) )
    9495 
    9496         obj = p.solve(log = verbose)
    9497 
    9498         # Paying attention to numerical error :
    9499         # The zero values could be something like 0.000000000001
    9500         # so I can not write l > 0
    9501         # And the non-zero, though they should be equal to
    9502         # 1/(order of the optimal subgraph) may be a bit lower
    9503 
    9504         # setting the minimum to 1/(10 * size of the whole graph )
    9505         # should be safe :-)
    9506         m = 1/(10 *Integer(g.order()))
    9507         g_mad = g.subgraph([v for v,l in p.get_values(d).iteritems() if l>m ])
    9508        
    9509         if value_only:
    9510             return g_mad.average_degree()
    9511         else:
    9512             return g_mad
    9513 
    95149151    def degree_histogram(self):
    95159152        """
    95169153        Returns a list, whose ith entry is the frequency of degree i.
     
    1127510912        """
    1127610913        import networkx
    1127710914        return networkx.transitivity(self.networkx_graph(copy=False))
    11278    
    11279     ### Cores
    11280    
    11281     def cores(self, k = None, with_labels=False):
    11282         """
    11283         Returns the core number for each vertex in an ordered list.
    11284        
    11285 
    11286         **DEFINITIONS**
    11287 
    11288         * *K-cores* in graph theory were introduced by Seidman in 1983 and by
    11289           Bollobas in 1984 as a method of (destructively) simplifying graph
    11290           topology to aid in analysis and visualization. They have been more
    11291           recently defined as the following by Batagelj et al:
    11292 
    11293           *Given a graph `G` with vertices set `V` and edges set `E`, the
    11294           `k`-core of `G` is the graph obtained from `G` by recursively removing
    11295           the vertices with degree less than `k`, for as long as there are any.*
    11296 
    11297           This operation can be useful to filter or to study some properties of
    11298           the graphs. For instance, when you compute the 2-core of graph G, you
    11299           are cutting all the vertices which are in a tree part of graph.  (A
    11300           tree is a graph with no loops). [WPkcore]_
    11301        
    11302           [PSW1996]_ defines a `k`-core of `G` as the largest subgraph (it is
    11303           unique) of `G` with minimum degree at least `k`.
    11304 
    11305         * Core number of a vertex
    11306 
    11307           The core number of a vertex `v` is the largest integer `k` such that
    11308           `v` belongs to the `k`-core of `G`.
    11309 
    11310         * Degeneracy
    11311 
    11312           The *degeneracy* of a graph `G`, usually denoted `\delta^*(G)`, is the
    11313           smallest integer `k` such that the graph `G` can be reduced to the
    11314           empty graph by iteratively removing vertices of degree `\leq
    11315           k`. Equivalently, `\delta^*(G)=k` if `k` is the smallest integer such
    11316           that the `k`-core of `G` is empty.
    11317 
    11318         **IMPLEMENTATION**
    11319 
    11320         This implementation is based on the NetworkX implementation of
    11321         the algorithm described in [BZ]_.
    11322 
    11323         **INPUT**
    11324        
    11325         - ``k`` (integer)
    11326 
    11327             * If ``k = None`` (default), returns the core number for each vertex.
    11328 
    11329             * If ``k`` is an integer, returns a pair ``(ordering, core)``, where
    11330               ``core`` is the list of vertices in the `k`-core of ``self``, and
    11331               ``ordering`` is an elimination order for the other vertices such
    11332               that each vertex is of degree strictly less than `k` when it is to
    11333               be eliminated from the graph.
    11334        
    11335         - ``with_labels`` (boolean)
    11336 
    11337            * When set to ``False``, and ``k = None``, the method returns a list
    11338              whose `i` th element is the core number of the `i` th vertex. When
    11339              set to ``True``, the method returns a dictionary whose keys are
    11340              vertices, and whose values are the corresponding core numbers.
    11341 
    11342              By default, ``with_labels = False``.
    11343        
    11344         REFERENCE:
    11345 
    11346         .. [WPkcore] K-core. Wikipedia. (2007). [Online] Available:
    11347           http://en.wikipedia.org/wiki/K-core
    11348 
    11349         .. [PSW1996] Boris Pittel, Joel Spencer and Nicholas Wormald. Sudden
    11350           Emergence of a Giant k-Core in a Random
    11351           Graph. (1996). J. Combinatorial Theory. Ser B 67. pages
    11352           111-151. [Online] Available:
    11353           http://cs.nyu.edu/cs/faculty/spencer/papers/k-core.pdf
    11354 
    11355         .. [BZ] Vladimir Batagelj and Matjaz Zaversnik. An `O(m)`
    11356           Algorithm for Cores Decomposition of
    11357           Networks. arXiv:cs/0310049v1. [Online] Available:
    11358           http://arxiv.org/abs/cs/0310049
    11359        
    11360         EXAMPLES::
    11361        
    11362             sage: (graphs.FruchtGraph()).cores()
    11363             [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
    11364             sage: (graphs.FruchtGraph()).cores(with_labels=True)
    11365             {0: 3, 1: 3, 2: 3, 3: 3, 4: 3, 5: 3, 6: 3, 7: 3, 8: 3, 9: 3, 10: 3, 11: 3}
    11366             sage: a=random_matrix(ZZ,20,x=2,sparse=True, density=.1)
    11367             sage: b=DiGraph(20)
    11368             sage: b.add_edges(a.nonzero_positions())
    11369             sage: cores=b.cores(with_labels=True); cores
    11370             {0: 3, 1: 3, 2: 3, 3: 3, 4: 2, 5: 2, 6: 3, 7: 1, 8: 3, 9: 3, 10: 3, 11: 3, 12: 3, 13: 3, 14: 2, 15: 3, 16: 3, 17: 3, 18: 3, 19: 3}
    11371             sage: [v for v,c in cores.items() if c>=2] # the vertices in the 2-core
    11372             [0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
    11373 
    11374         Checking the 2-core of a random lobster is indeed the empty set::
    11375 
    11376             sage: g = graphs.RandomLobster(20,.5,.5)
    11377             sage: ordering, core = g.cores(2)
    11378             sage: len(core) == 0
    11379             True
    11380         """
    11381         # compute the degrees of each vertex
    11382         degrees=self.degree(labels=True)
    11383        
    11384         # sort vertices by degree.  Store in a list and keep track of
    11385         # where a specific degree starts (effectively, the list is
    11386         # sorted by bins).
    11387         verts= sorted( degrees.keys(), key=lambda x: degrees[x])
    11388         bin_boundaries=[0]
    11389         curr_degree=0
    11390         for i,v in enumerate(verts):
    11391             if degrees[v]>curr_degree:
    11392                 bin_boundaries.extend([i]*(degrees[v]-curr_degree))
    11393                 curr_degree=degrees[v]
    11394         vert_pos = dict((v,pos) for pos,v in enumerate(verts))
    11395         # Set up initial guesses for core and lists of neighbors.
    11396         core= degrees
    11397         nbrs=dict((v,set(self.neighbors(v))) for v in self)
    11398         # form vertex core building up from smallest
    11399         for v in verts:
    11400            
    11401             # If all the vertices have a degree larger than k, we can
    11402             # return our answer if k != None
    11403             if k is not None and core[v] >= k:
    11404                 return verts[:vert_pos[v]], verts[vert_pos[v]:]
    11405 
    11406             for u in nbrs[v]:
    11407                 if core[u] > core[v]:
    11408                     nbrs[u].remove(v)
    11409 
    11410                     # cleverly move u to the end of the next smallest
    11411                     # bin (i.e., subtract one from the degree of u).
    11412                     # We do this by swapping u with the first vertex
    11413                     # in the bin that contains u, then incrementing
    11414                     # the bin boundary for the bin that contains u.
    11415                     pos=vert_pos[u]
    11416                     bin_start=bin_boundaries[core[u]]
    11417                     vert_pos[u]=bin_start
    11418                     vert_pos[verts[bin_start]]=pos
    11419                     verts[bin_start],verts[pos]=verts[pos],verts[bin_start]
    11420                     bin_boundaries[core[u]]+=1
    11421                     core[u] -= 1
    11422 
    11423         if k is not None:
    11424             return verts, []
    11425 
    11426         if with_labels:
    11427             return core
    11428         else:
    11429             return core.values()
    1143010915
    1143110916    ### Distance
    1143210917
  • sage/graphs/graph.py

    diff --git a/sage/graphs/graph.py b/sage/graphs/graph.py
    a b  
    6262    :delim: |
    6363
    6464    :meth:`~Graph.gomory_hu_tree` | Returns a Gomory-Hu tree of self.
     65    :meth:`~Graph.minimum_outdegree_orientation` | Returns an orientation of ``self`` with the smallest possible maximum outdegree
    6566    :meth:`~Graph.bounded_outdegree_orientation` | Computes an orientation of ``self`` such that every vertex `v` has out-degree less than `b(v)`
    6667    :meth:`~Graph.strong_orientation` | Returns a strongly connected orientation of the current graph.
    6768    :meth:`~Graph.degree_constrained_subgraph` | Returns a degree-constrained subgraph.
    6869
    69 
    7070**Clique-related methods:**
    7171
    7272.. csv-table::
     
    115115    :widths: 30, 70
    116116    :delim: |
    117117
     118    :meth:`~Graph.cores` | Returns the core number for each vertex in an ordered list.
     119    :meth:`~Graph.matching` | Returns a maximum weighted matching of the graph
    118120    :meth:`~Graph.fractional_chromatic_index` | Computes the fractional chromatic index of ``self``
    119121    :meth:`~Graph.modular_decomposition` | Returns the modular decomposition of the current graph.
     122    :meth:`~Graph.maximum_average_degree` | Returns the Maximum Average Degree (MAD) of the current graph.
    120123    :meth:`~Graph.two_factor_petersen` | Returns a decomposition of the graph into 2-factors.
    121124
    122125
     
    24462449                else:
    24472450                    d.add_edge(e)
    24482451            tmp = (e[0],e[1])
    2449            
     2452
    24502453        return d
    24512454
     2455    def minimum_outdegree_orientation(self, use_edge_labels=False, solver=None, verbose=0):
     2456        r"""
     2457        Returns an orientation of ``self`` with the smallest possible maximum
     2458        outdegree.
     2459
     2460        Given a Graph `G`, is is polynomial to compute an orientation
     2461        `D` of the edges of `G` such that the maximum out-degree in
     2462        `D` is minimized. This problem, though, is NP-complete in the
     2463        weighted case [AMOZ06]_.
     2464
     2465        INPUT:
     2466
     2467        - ``use_edge_labels`` -- boolean (default: ``False``)
     2468
     2469          - When set to ``True``, uses edge labels as weights to
     2470            compute the orientation and assumes a weight of `1`
     2471            when there is no value available for a given edge.
     2472
     2473          - When set to ``False`` (default), gives a weight of 1
     2474            to all the edges.
     2475
     2476        - ``solver`` -- (default: ``None``) Specify a Linear Program (LP)
     2477          solver to be used. If set to ``None``, the default one is used. For
     2478          more information on LP solvers and which default solver is used, see
     2479          the method
     2480          :meth:`solve <sage.numerical.mip.MixedIntegerLinearProgram.solve>`
     2481          of the class
     2482          :class:`MixedIntegerLinearProgram <sage.numerical.mip.MixedIntegerLinearProgram>`.
     2483
     2484        - ``verbose`` -- integer (default: ``0``). Sets the level of
     2485          verbosity. Set to 0 by default, which means quiet.
     2486
     2487        EXAMPLE:
     2488
     2489        Given a complete bipartite graph `K_{n,m}`, the maximum out-degree
     2490        of an optimal orientation is `\left\lceil \frac {nm} {n+m}\right\rceil`::
     2491
     2492            sage: g = graphs.CompleteBipartiteGraph(3,4)
     2493            sage: o = g.minimum_outdegree_orientation()
     2494            sage: max(o.out_degree()) == ceil((4*3)/(3+4))
     2495            True
     2496
     2497        REFERENCES:
     2498
     2499        .. [AMOZ06] Asahiro, Y. and Miyano, E. and Ono, H. and Zenmyo, K.
     2500          Graph orientation algorithms to minimize the maximum outdegree
     2501          Proceedings of the 12th Computing: The Australasian Theory Symposium
     2502          Volume 51, page 20
     2503          Australian Computer Society, Inc. 2006
     2504        """
     2505
     2506        if self.is_directed():
     2507            raise ValueError("Cannot compute an orientation of a DiGraph. "+\
     2508                                 "Please convert it to a Graph if you really mean it.")
     2509
     2510        if use_edge_labels:
     2511            from sage.rings.real_mpfr import RR
     2512            weight = lambda u,v : self.edge_label(u,v) if self.edge_label(u,v) in RR else 1
     2513        else:
     2514            weight = lambda u,v : 1
     2515
     2516        from sage.numerical.mip import MixedIntegerLinearProgram
     2517
     2518        p = MixedIntegerLinearProgram(maximization=False, solver=solver)
     2519
     2520        # The orientation of an edge is boolean
     2521        # and indicates whether the edge uv
     2522        # with u<v goes from u to v ( equal to 0 )
     2523        # or from v to u ( equal to 1)
     2524        orientation = p.new_variable(dim=2)
     2525
     2526        degree = p.new_variable()
     2527
     2528        # Whether an edge adjacent to a vertex u counts
     2529        # positively or negatively
     2530        outgoing = lambda u,v,variable : (1-variable) if u>v else variable
     2531
     2532        for u in self:
     2533            p.add_constraint(p.sum([weight(u,v)*outgoing(u,v,orientation[min(u,v)][max(u,v)]) for v in self.neighbors(u)])-degree['max'],max=0)
     2534
     2535        p.set_objective(degree['max'])
     2536
     2537        p.set_binary(orientation)
     2538
     2539        p.solve(log=verbose)
     2540
     2541        orientation = p.get_values(orientation)
     2542
     2543        # All the edges from self are doubled in O
     2544        # ( one in each direction )
     2545        from sage.graphs.digraph import DiGraph
     2546        O = DiGraph(self)
     2547
     2548        # Builds the list of edges that should be removed
     2549        edges=[]
     2550
     2551        for u,v in self.edge_iterator(labels=None):
     2552            # assumes u<v
     2553            if u>v:
     2554                u,v=v,u
     2555
     2556            if orientation[min(u,v)][max(u,v)] == 1:
     2557                edges.append((max(u,v),min(u,v)))
     2558            else:
     2559                edges.append((min(u,v),max(u,v)))
     2560
     2561        O.delete_edges(edges)
     2562
     2563        return O
     2564
    24522565    def bounded_outdegree_orientation(self, bound):
    24532566        r"""
    24542567        Computes an orientation of ``self`` such that every vertex `v`
     
    27902903        else:
    27912904            raise ValueError("The 'algorithm' keyword must be set to either 'DLX' or 'MILP'.")
    27922905
     2906    def matching(self, value_only=False, algorithm="Edmonds", use_edge_labels=True, solver=None, verbose=0):
     2907        r"""
     2908        Returns a maximum weighted matching of the graph
     2909        represented by the list of its edges. For more information, see the
     2910        `Wikipedia article on matchings
     2911        <http://en.wikipedia.org/wiki/Matching_%28graph_theory%29>`_.
     2912
     2913        Given a graph `G` such that each edge `e` has a weight `w_e`,
     2914        a maximum matching is a subset `S` of the edges of `G` of
     2915        maximum weight such that no two edges of `S` are incident
     2916        with each other.
     2917
     2918        As an optimization problem, it can be expressed as:
     2919
     2920        .. math::
     2921
     2922            \mbox{Maximize : }&\sum_{e\in G.edges()} w_e b_e\\
     2923            \mbox{Such that : }&\forall v \in G, \sum_{(u,v)\in G.edges()} b_{(u,v)}\leq 1\\
     2924            &\forall x\in G, b_x\mbox{ is a binary variable}
     2925
     2926        INPUT:
     2927
     2928        - ``value_only`` -- boolean (default: ``False``). When set to
     2929          ``True``, only the cardinal (or the weight) of the matching is
     2930          returned.
     2931
     2932        - ``algorithm`` -- string (default: ``"Edmonds"``)
     2933
     2934          - ``"Edmonds"`` selects Edmonds' algorithm as implemented in NetworkX
     2935
     2936          - ``"LP"`` uses a Linear Program formulation of the matching problem
     2937
     2938        - ``use_edge_labels`` -- boolean (default: ``False``)
     2939
     2940          - When set to ``True``, computes a weighted matching where each edge
     2941            is weighted by its label. (If an edge has no label, `1` is assumed.)
     2942
     2943          - When set to ``False``, each edge has weight `1`.
     2944
     2945        - ``solver`` -- (default: ``None``) Specify a Linear Program (LP)
     2946          solver to be used. If set to ``None``, the default one is used. For
     2947          more information on LP solvers and which default solver is used, see
     2948          the method
     2949          :meth:`solve <sage.numerical.mip.MixedIntegerLinearProgram.solve>`
     2950          of the class
     2951          :class:`MixedIntegerLinearProgram <sage.numerical.mip.MixedIntegerLinearProgram>`.
     2952
     2953        - ``verbose`` -- integer (default: ``0``). Sets the level of
     2954          verbosity. Set to 0 by default, which means quiet.
     2955          Only useful when ``algorithm == "LP"``.
     2956
     2957        ALGORITHM:
     2958
     2959        The problem is solved using Edmond's algorithm implemented in
     2960        NetworkX, or using Linear Programming depending on the value of
     2961        ``algorithm``.
     2962
     2963        EXAMPLES:
     2964
     2965        Maximum matching in a Pappus Graph::
     2966
     2967           sage: g = graphs.PappusGraph()
     2968           sage: g.matching(value_only=True)
     2969           9.0
     2970
     2971        Same test with the Linear Program formulation::
     2972
     2973           sage: g = graphs.PappusGraph()
     2974           sage: g.matching(algorithm="LP", value_only=True)
     2975           9.0
     2976
     2977        TESTS:
     2978
     2979        If ``algorithm`` is set to anything different from ``"Edmonds"`` or
     2980        ``"LP"``, an exception is raised::
     2981
     2982           sage: g = graphs.PappusGraph()
     2983           sage: g.matching(algorithm="somethingdifferent")
     2984           Traceback (most recent call last):
     2985           ...
     2986           ValueError: algorithm must be set to either "Edmonds" or "LP"
     2987        """
     2988        from sage.rings.real_mpfr import RR
     2989        weight = lambda x: x if x in RR else 1
     2990
     2991        if algorithm == "Edmonds":
     2992            import networkx
     2993            if use_edge_labels:
     2994                g = networkx.Graph()
     2995                for u, v, l in self.edges():
     2996                    g.add_edge(u, v, attr_dict={"weight": weight(l)})
     2997            else:
     2998                g = self.networkx_graph(copy=False)
     2999            d = networkx.max_weight_matching(g)
     3000            if value_only:
     3001                if use_edge_labels:
     3002                    return sum([weight(self.edge_label(u, v))
     3003                                for u, v in d.iteritems()]) * 0.5
     3004                else:
     3005                    return Integer(len(d)/2)
     3006            else:
     3007                return [(u, v, self.edge_label(u, v))
     3008                        for u, v in d.iteritems() if u < v]
     3009
     3010        elif algorithm == "LP":
     3011            from sage.numerical.mip import MixedIntegerLinearProgram
     3012            g = self
     3013            # returns the weight of an edge considering it may not be
     3014            # weighted ...
     3015            p = MixedIntegerLinearProgram(maximization=True, solver=solver)
     3016            b = p.new_variable(dim=2)
     3017            p.set_objective(
     3018                p.sum([weight(w) * b[min(u, v)][max(u, v)]
     3019                     for u, v, w in g.edges()]))
     3020            # for any vertex v, there is at most one edge incident to v in
     3021            # the maximum matching
     3022            for v in g.vertex_iterator():
     3023                p.add_constraint(
     3024                    p.sum([b[min(u, v)][max(u, v)]
     3025                         for u in g.neighbors(v)]), max=1)
     3026            p.set_binary(b)
     3027            if value_only:
     3028                if use_edge_labels:
     3029                    return p.solve(objective_only=True, log=verbose)
     3030                else:
     3031                    return Integer(round(p.solve(objective_only=True, log=verbose)))
     3032            else:
     3033                p.solve(log=verbose)
     3034                b = p.get_values(b)
     3035                return [(u, v, w) for u, v, w in g.edges()
     3036                        if b[min(u, v)][max(u, v)] == 1]
     3037
     3038        else:
     3039            raise ValueError('algorithm must be set to either "Edmonds" or "LP"')
     3040
    27933041    def fractional_chromatic_index(self, verbose_constraints = 0, verbose = 0):
    27943042        r"""
    27953043        Computes the fractional chromatic index of ``self``
     
    28143062        The fractional chromatic index is computed through Linear Programming
    28153063        through its dual. The LP solved by sage is actually:
    28163064
    2817         .. MATH:: 
    2818  
     3065        .. MATH::
     3066
    28193067            \mbox{Maximize : }&\sum_{e\in E(G)} r_{e}\\
    2820             \mbox{Such that : }&\\ 
    2821             &\forall M\text{ matching }\subseteq G, \sum_{e\in M}r_{v}\leq 1\\ 
    2822    
     3068            \mbox{Such that : }&\\
     3069            &\forall M\text{ matching }\subseteq G, \sum_{e\in M}r_{v}\leq 1\\
     3070
    28233071        INPUT:
    28243072
    28253073        - ``verbose_constraints`` -- whether to display which constraints are
    28263074          being generated.
    2827    
     3075
    28283076        - ``verbose`` -- level of verbosity required from the LP solver
    2829    
     3077
    28303078        .. NOTE::
    28313079
    28323080            This implementation can be improved by computing matchings through a
     
    28383086
    28393087
    28403088        EXAMPLE:
    2841    
     3089
    28423090        The fractional chromatic index of a `C_5` is `5/2`::
    2843    
     3091
    28443092            sage: g = graphs.CycleGraph(5)
    28453093            sage: g.fractional_chromatic_index()
    28463094            2.5
    28473095        """
    28483096
    28493097        from sage.numerical.mip import MixedIntegerLinearProgram
    2850        
     3098
    28513099        g = self.copy()
    28523100        p = MixedIntegerLinearProgram(constraint_generation = True)
    28533101
    28543102        # One variable per edge
    28553103        r = p.new_variable(dim = 2)
    28563104        R = lambda x,y : r[x][y] if x<y else r[y][x]
    2857        
     3105
    28583106        # We want to maximize the sum of weights on the edges
    28593107        p.set_objective( p.sum( R(u,v) for u,v in g.edges(labels = False)))
    28603108
     
    28933141        # Accomplished !
    28943142        return obj
    28953143
     3144    def maximum_average_degree(self, value_only=True, solver = None, verbose = 0):
     3145        r"""
     3146        Returns the Maximum Average Degree (MAD) of the current graph.
     3147
     3148        The Maximum Average Degree (MAD) of a graph is defined as
     3149        the average degree of its densest subgraph. More formally,
     3150        ``Mad(G) = \max_{H\subseteq G} Ad(H)``, where `Ad(G)` denotes
     3151        the average degree of `G`.
     3152
     3153        This can be computed in polynomial time.
     3154
     3155        INPUT:
     3156
     3157        - ``value_only`` (boolean) -- ``True`` by default
     3158
     3159            - If ``value_only=True``, only the numerical
     3160              value of the `MAD` is returned.
     3161
     3162            - Else, the subgraph of `G` realizing the `MAD`
     3163              is returned.
     3164
     3165        - ``solver`` -- (default: ``None``) Specify a Linear Program (LP)
     3166          solver to be used. If set to ``None``, the default one is used. For
     3167          more information on LP solvers and which default solver is used, see
     3168          the method
     3169          :meth:`solve <sage.numerical.mip.MixedIntegerLinearProgram.solve>`
     3170          of the class
     3171          :class:`MixedIntegerLinearProgram <sage.numerical.mip.MixedIntegerLinearProgram>`.
     3172
     3173        - ``verbose`` -- integer (default: ``0``). Sets the level of
     3174          verbosity. Set to 0 by default, which means quiet.
     3175
     3176        EXAMPLES:
     3177
     3178        In any graph, the `Mad` is always larger than the average
     3179        degree::
     3180
     3181            sage: g = graphs.RandomGNP(20,.3)
     3182            sage: mad_g = g.maximum_average_degree()
     3183            sage: g.average_degree() <= mad_g
     3184            True
     3185
     3186        Unlike the average degree, the `Mad` of the disjoint
     3187        union of two graphs is the maximum of the `Mad` of each
     3188        graphs::
     3189
     3190            sage: h = graphs.RandomGNP(20,.3)
     3191            sage: mad_h = h.maximum_average_degree()
     3192            sage: (g+h).maximum_average_degree() == max(mad_g, mad_h)
     3193            True
     3194
     3195        The subgraph of a regular graph realizing the maximum
     3196        average degree is always the whole graph ::
     3197
     3198            sage: g = graphs.CompleteGraph(5)
     3199            sage: mad_g = g.maximum_average_degree(value_only=False)
     3200            sage: g.is_isomorphic(mad_g)
     3201            True
     3202
     3203        This also works for complete bipartite graphs ::
     3204
     3205            sage: g = graphs.CompleteBipartiteGraph(3,4)
     3206            sage: mad_g = g.maximum_average_degree(value_only=False)
     3207            sage: g.is_isomorphic(mad_g)
     3208            True
     3209        """
     3210
     3211        g = self
     3212        from sage.numerical.mip import MixedIntegerLinearProgram
     3213
     3214        p = MixedIntegerLinearProgram(maximization=True, solver = solver)
     3215
     3216        d = p.new_variable()
     3217        one = p.new_variable()
     3218
     3219        # Reorders u and v so that uv and vu are not considered
     3220        # to be different edges
     3221        reorder = lambda u,v : (min(u,v),max(u,v))
     3222
     3223        for u,v in g.edge_iterator(labels=False):
     3224            p.add_constraint( one[ reorder(u,v) ] - 2*d[u] , max = 0 )
     3225            p.add_constraint( one[ reorder(u,v) ] - 2*d[v] , max = 0 )
     3226
     3227        p.add_constraint( p.sum([d[v] for v in g]), max = 1)
     3228
     3229        p.set_objective( p.sum([ one[reorder(u,v)] for u,v in g.edge_iterator(labels=False)]) )
     3230
     3231        obj = p.solve(log = verbose)
     3232
     3233        # Paying attention to numerical error :
     3234        # The zero values could be something like 0.000000000001
     3235        # so I can not write l > 0
     3236        # And the non-zero, though they should be equal to
     3237        # 1/(order of the optimal subgraph) may be a bit lower
     3238
     3239        # setting the minimum to 1/(10 * size of the whole graph )
     3240        # should be safe :-)
     3241        m = 1/(10 *Integer(g.order()))
     3242        g_mad = g.subgraph([v for v,l in p.get_values(d).iteritems() if l>m ])
     3243
     3244        if value_only:
     3245            return g_mad.average_degree()
     3246        else:
     3247            return g_mad
     3248
    28963249    def independent_set_of_representatives(self, family, solver=None, verbose=0):
    28973250        r"""
    28983251        Returns an independent set of representatives.
     
    44604813
    44614814    ### Miscellaneous
    44624815
     4816    def cores(self, k = None, with_labels=False):
     4817        """
     4818        Returns the core number for each vertex in an ordered list.
     4819
     4820
     4821        **DEFINITIONS**
     4822
     4823        * *K-cores* in graph theory were introduced by Seidman in 1983 and by
     4824          Bollobas in 1984 as a method of (destructively) simplifying graph
     4825          topology to aid in analysis and visualization. They have been more
     4826          recently defined as the following by Batagelj et al:
     4827
     4828          *Given a graph `G` with vertices set `V` and edges set `E`, the
     4829          `k`-core of `G` is the graph obtained from `G` by recursively removing
     4830          the vertices with degree less than `k`, for as long as there are any.*
     4831
     4832          This operation can be useful to filter or to study some properties of
     4833          the graphs. For instance, when you compute the 2-core of graph G, you
     4834          are cutting all the vertices which are in a tree part of graph.  (A
     4835          tree is a graph with no loops). [WPkcore]_
     4836
     4837          [PSW1996]_ defines a `k`-core of `G` as the largest subgraph (it is
     4838          unique) of `G` with minimum degree at least `k`.
     4839
     4840        * Core number of a vertex
     4841
     4842          The core number of a vertex `v` is the largest integer `k` such that
     4843          `v` belongs to the `k`-core of `G`.
     4844
     4845        * Degeneracy
     4846
     4847          The *degeneracy* of a graph `G`, usually denoted `\delta^*(G)`, is the
     4848          smallest integer `k` such that the graph `G` can be reduced to the
     4849          empty graph by iteratively removing vertices of degree `\leq
     4850          k`. Equivalently, `\delta^*(G)=k` if `k` is the smallest integer such
     4851          that the `k`-core of `G` is empty.
     4852
     4853        **IMPLEMENTATION**
     4854
     4855        This implementation is based on the NetworkX implementation of
     4856        the algorithm described in [BZ]_.
     4857
     4858        **INPUT**
     4859
     4860        - ``k`` (integer)
     4861
     4862            * If ``k = None`` (default), returns the core number for each vertex.
     4863
     4864            * If ``k`` is an integer, returns a pair ``(ordering, core)``, where
     4865              ``core`` is the list of vertices in the `k`-core of ``self``, and
     4866              ``ordering`` is an elimination order for the other vertices such
     4867              that each vertex is of degree strictly less than `k` when it is to
     4868              be eliminated from the graph.
     4869
     4870        - ``with_labels`` (boolean)
     4871
     4872           * When set to ``False``, and ``k = None``, the method returns a list
     4873             whose `i` th element is the core number of the `i` th vertex. When
     4874             set to ``True``, the method returns a dictionary whose keys are
     4875             vertices, and whose values are the corresponding core numbers.
     4876
     4877             By default, ``with_labels = False``.
     4878
     4879        REFERENCE:
     4880
     4881        .. [WPkcore] K-core. Wikipedia. (2007). [Online] Available:
     4882          http://en.wikipedia.org/wiki/K-core
     4883
     4884        .. [PSW1996] Boris Pittel, Joel Spencer and Nicholas Wormald. Sudden
     4885          Emergence of a Giant k-Core in a Random
     4886          Graph. (1996). J. Combinatorial Theory. Ser B 67. pages
     4887          111-151. [Online] Available:
     4888          http://cs.nyu.edu/cs/faculty/spencer/papers/k-core.pdf
     4889
     4890        .. [BZ] Vladimir Batagelj and Matjaz Zaversnik. An `O(m)`
     4891          Algorithm for Cores Decomposition of
     4892          Networks. arXiv:cs/0310049v1. [Online] Available:
     4893          http://arxiv.org/abs/cs/0310049
     4894
     4895        EXAMPLES::
     4896
     4897            sage: (graphs.FruchtGraph()).cores()
     4898            [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
     4899            sage: (graphs.FruchtGraph()).cores(with_labels=True)
     4900            {0: 3, 1: 3, 2: 3, 3: 3, 4: 3, 5: 3, 6: 3, 7: 3, 8: 3, 9: 3, 10: 3, 11: 3}
     4901            sage: a=random_matrix(ZZ,20,x=2,sparse=True, density=.1)
     4902            sage: b=DiGraph(20)
     4903            sage: b.add_edges(a.nonzero_positions())
     4904            sage: cores=b.cores(with_labels=True); cores
     4905            {0: 3, 1: 3, 2: 3, 3: 3, 4: 2, 5: 2, 6: 3, 7: 1, 8: 3, 9: 3, 10: 3, 11: 3, 12: 3, 13: 3, 14: 2, 15: 3, 16: 3, 17: 3, 18: 3, 19: 3}
     4906            sage: [v for v,c in cores.items() if c>=2] # the vertices in the 2-core
     4907            [0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
     4908
     4909        Checking the 2-core of a random lobster is indeed the empty set::
     4910
     4911            sage: g = graphs.RandomLobster(20,.5,.5)
     4912            sage: ordering, core = g.cores(2)
     4913            sage: len(core) == 0
     4914            True
     4915        """
     4916        # compute the degrees of each vertex
     4917        degrees=self.degree(labels=True)
     4918
     4919        # sort vertices by degree.  Store in a list and keep track of
     4920        # where a specific degree starts (effectively, the list is
     4921        # sorted by bins).
     4922        verts= sorted( degrees.keys(), key=lambda x: degrees[x])
     4923        bin_boundaries=[0]
     4924        curr_degree=0
     4925        for i,v in enumerate(verts):
     4926            if degrees[v]>curr_degree:
     4927                bin_boundaries.extend([i]*(degrees[v]-curr_degree))
     4928                curr_degree=degrees[v]
     4929        vert_pos = dict((v,pos) for pos,v in enumerate(verts))
     4930        # Set up initial guesses for core and lists of neighbors.
     4931        core= degrees
     4932        nbrs=dict((v,set(self.neighbors(v))) for v in self)
     4933        # form vertex core building up from smallest
     4934        for v in verts:
     4935
     4936            # If all the vertices have a degree larger than k, we can
     4937            # return our answer if k != None
     4938            if k is not None and core[v] >= k:
     4939                return verts[:vert_pos[v]], verts[vert_pos[v]:]
     4940
     4941            for u in nbrs[v]:
     4942                if core[u] > core[v]:
     4943                    nbrs[u].remove(v)
     4944
     4945                    # cleverly move u to the end of the next smallest
     4946                    # bin (i.e., subtract one from the degree of u).
     4947                    # We do this by swapping u with the first vertex
     4948                    # in the bin that contains u, then incrementing
     4949                    # the bin boundary for the bin that contains u.
     4950                    pos=vert_pos[u]
     4951                    bin_start=bin_boundaries[core[u]]
     4952                    vert_pos[u]=bin_start
     4953                    vert_pos[verts[bin_start]]=pos
     4954                    verts[bin_start],verts[pos]=verts[pos],verts[bin_start]
     4955                    bin_boundaries[core[u]]+=1
     4956                    core[u] -= 1
     4957
     4958        if k is not None:
     4959            return verts, []
     4960
     4961        if with_labels:
     4962            return core
     4963        else:
     4964            return core.values()
     4965
    44634966    def modular_decomposition(self):
    44644967        r"""
    44654968        Returns the modular decomposition of the current graph.