Ticket #8166: trac_8166-rebase.patch

File trac_8166-rebase.patch, 10.2 KB (added by mvngu, 11 years ago)
  • sage/graphs/generic_graph.py

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1274451908 25200
    # Node ID 35c219593994239c7763d329c2f510487bb0da01
    # Parent  e7d605054deba9189c3f43a297947ad3fcf06318
    #8166: maximum matching using NetworkX and linear programming
    
    diff --git a/sage/graphs/generic_graph.py b/sage/graphs/generic_graph.py
    a b  
    434434
    435435           Please use this method only if you need to copy but change the
    436436           underlying implementation.  Otherwise simply do ``copy(g)``
    437            instead of idoing ``g.copy()``.
     437           instead of doing ``g.copy()``.
    438438
    439439        EXAMPLES::
    440440       
     
    19411941    def spanning_trees_count(self, root_vertex=None):
    19421942        """
    19431943        Returns the number of spanning trees in a graph. In the case of a
    1944         digraph, couts the number of spanning out-trees rooted in
     1944        digraph, counts the number of spanning out-trees rooted in
    19451945        ``root_vertex``.
    19461946        Default is to set first vertex as root.
    19471947
     
    20602060       
    20612061        .. [AMOZ06] Asahiro, Y. and Miyano, E. and Ono, H. and Zenmyo, K.
    20622062          Graph orientation algorithms to minimize the maximum outdegree
    2063           Proceedings of the 12th Computing: The Australasian Theroy Symposium
     2063          Proceedings of the 12th Computing: The Australasian Theory Symposium
    20642064          Volume 51, page 20
    20652065          Australian Computer Society, Inc. 2006
    20662066        """
     
    36313631           
    36323632        - ``use_edge_labels`` -- boolean (default: ``True``)
    36333633
    3634           - When set to ``True``, computes a maximun flow
     3634          - When set to ``True``, computes a maximum flow
    36353635            where each edge has a capacity defined by its label. (If
    36363636            an edge has no label, `1` is assumed.)
    36373637
     
    36463646        - ``solver`` -- Specify a Linear Program solver to be used.
    36473647          If set to ``None``, the default one is used.
    36483648          function of ``MixedIntegerLinearProgram``. See the documentation  of ``MixedIntegerLinearProgram.solve``
    3649           for more informations.
     3649          for more information.
    36503650
    36513651        - ``verbose`` (integer) -- sets the level of verbosity. Set to 0
    36523652          by default (quiet).
     
    36753675            sage: g.add_edges([('s',i) for i in range(4)])
    36763676            sage: g.add_edges([(i,4+j) for i in range(4) for j in range(4)])
    36773677            sage: g.add_edges([(4+i,'t') for i in range(4)])
    3678             sage: [cardinal, flow_graph] = g.flow('s','t',integer=True,value_only=False) # optional - requries GLPK or CBC
    3679             sage: flow_graph.delete_vertices(['s','t'])                                  # optional - requries GLPK or CBC
    3680             sage: len(flow_graph.edges(labels=None))                                     # optional - requries GLPK or CBC   
     3678            sage: [cardinal, flow_graph] = g.flow('s','t',integer=True,value_only=False) # optional - requires GLPK or CBC
     3679            sage: flow_graph.delete_vertices(['s','t'])                                  # optional - requires GLPK or CBC
     3680            sage: len(flow_graph.edges(labels=None))                                     # optional - requires GLPK or CBC   
    36813681            4
    36823682       
    36833683        """
     
    38623862
    38633863        return paths
    38643864
    3865 
    3866     def matching(self, value_only=False, use_edge_labels=True, solver=None, verbose=0):
     3865    def matching(self, value_only=False, algorithm="Edmonds", use_edge_labels=True, solver=None, verbose=0):
    38673866        r"""
    38683867        Returns a maximum weighted matching of the graph
    38693868        represented by the list of its edges. For more information, see the
     
    38823881            \mbox{Maximize : }&\sum_{e\in G.edges()} w_e b_e\\
    38833882            \mbox{Such that : }&\forall v \in G, \sum_{(u,v)\in G.edges()} b_{(u,v)}\leq 1\\
    38843883            &\forall x\in G, b_x\mbox{ is a binary variable}
    3885    
    3886         INPUT:
    3887    
     3884
     3885        INPUT:
     3886
    38883887        - ``value_only`` -- boolean (default: ``False``). When set to
    38893888          ``True``, only the cardinal (or the weight) of the matching is
    38903889          returned.
    38913890
     3891        - ``algorithm`` -- string (default: ``"Edmonds"``)
     3892
     3893          - ``"Edmonds"`` selects Edmonds' algorithm as implemented in NetworkX
     3894
     3895          - ``"LP"`` uses a Linear Program formulation of the matching problem
     3896
    38923897        - ``use_edge_labels`` -- boolean (default: ``True``)
    38933898
    38943899          - When set to ``True``, computes a weighted matching
     
    38973902
    38983903          - When set to ``False``, each edge has weight `1`.
    38993904
    3900 
    39013905        - ``solver`` -- (default: ``None``) Specify a Linear Program (LP)
    39023906          solver to be used. If set to ``None``, the default one is used. For
    39033907          more information on LP solvers and which default solver is used, see
     
    39083912
    39093913        - ``verbose`` -- integer (default: ``0``). Sets the level of
    39103914          verbosity. Set to 0 by default, which means quiet.
    3911    
    3912         EXAMPLE::
    3913        
    3914            sage: g=graphs.PappusGraph()
    3915            sage: g.matching(value_only=True) # optional - requires Glpk or COIN-OR/CBC
     3915          Only useful when ``algorithm == "LP"``.
     3916
     3917        ALGORITHM:
     3918
     3919        The problem is solved using Edmond's algorithm implemented in
     3920        NetworkX, or using Linear Programming depending on the value of
     3921        ``algorithm``.
     3922
     3923        EXAMPLES:
     3924
     3925        Maximum matching in a Pappus Graph::
     3926
     3927           sage: g = graphs.PappusGraph()
     3928           sage: g.matching(value_only=True)
    39163929           9.0
    3917         """
    3918 
    3919         from sage.numerical.mip import MixedIntegerLinearProgram
    3920         g=self
    3921 
    3922         # returns the weight of an edge considering it may not be
    3923         # weighted ...
    3924 
     3930
     3931        Same test with the Linear Program formulation::
     3932
     3933           sage: g = graphs.PappusGraph()
     3934           sage: g.matching(algorithm="LP", value_only=True)
     3935           9.0
     3936
     3937        TESTS:
     3938
     3939        If ``algorithm`` is set to anything different from ``"Edmonds"`` or
     3940        ``"LP"``, an exception is raised::
     3941
     3942           sage: g = graphs.PappusGraph()
     3943           sage: g.matching(algorithm="somethingdifferent")
     3944           Traceback (most recent call last):
     3945           ...
     3946           ValueError: Algorithm must be set to either "Edmonds" or "LP".
     3947        """
    39253948        from sage.rings.real_mpfr import RR
    3926         weight=lambda x: x if x in RR else 1
    3927 
    3928         p=MixedIntegerLinearProgram(maximization=True)
    3929 
    3930         b=p.new_variable(dim=2)
    3931         p.set_objective(sum([weight(w)*b[min(u,v)][max(u,v)] for (u,v,w) in g.edges()]))
    3932 
    3933 
    3934         # for any vertex v, there is at most one edge incident to v in the maximum matching
    3935         for v in g.vertices():
    3936             p.add_constraint(sum([b[min(u,v)][max(u,v)] for u in g.neighbors(v)]),max=1)
    3937 
    3938         p.set_binary(b)
    3939    
    3940         if value_only:
    3941             return p.solve(objective_only=True, solver=solver, log=verbose)
    3942         else:
    3943             p.solve(solver=solver, log=verbose)
    3944             b=p.get_values(b)
    3945             return [(u,v,w) for (u,v,w) in g.edges() if b[min(u,v)][max(u,v)] == 1]
     3949        weight = lambda x: x if x in RR else 1
     3950
     3951        if algorithm == "Edmonds":
     3952            import networkx
     3953            if use_edge_labels:
     3954                g = networkx.Graph()
     3955                for u, v, l in self.edges():
     3956                    g.add_edge(u, v, attr_dict={"weight": weight(l)})
     3957            else:
     3958                g = self.networkx_graph(copy=False)
     3959            d = networkx.max_weight_matching(g)
     3960            if value_only:
     3961                return sum([weight(self.edge_label(u, v))
     3962                            for u, v in d.iteritems()]) * 0.5
     3963            else:
     3964                return [(u, v, self.edge_label(u, v))
     3965                        for u, v in d.iteritems() if u < v]
     3966
     3967        elif algorithm == "LP":
     3968            from sage.numerical.mip import MixedIntegerLinearProgram
     3969            g = self
     3970            # returns the weight of an edge considering it may not be
     3971            # weighted ...
     3972            p = MixedIntegerLinearProgram(maximization=True)
     3973            b = p.new_variable(dim=2)
     3974            p.set_objective(
     3975                sum([weight(w) * b[min(u, v)][max(u, v)]
     3976                     for u, v, w in g.edges()]))
     3977            # for any vertex v, there is at most one edge incident to v in
     3978            # the maximum matching
     3979            for v in g.vertex_iterator():
     3980                p.add_constraint(
     3981                    sum([b[min(u, v)][max(u, v)]
     3982                         for u in g.neighbors(v)]), max=1)
     3983            p.set_binary(b)
     3984            if value_only:
     3985                return p.solve(objective_only=True, solver=solver, log=verbose)
     3986            else:
     3987                p.solve(solver=solver, log=verbose)
     3988                b = p.get_values(b)
     3989                return [(u, v, w) for u, v, w in g.edges()
     3990                        if b[min(u, v)][max(u, v)] == 1]
     3991
     3992        else:
     3993            raise ValueError(
     3994                'Algorithm must be set to either "Edmonds" or "LP".')
    39463995
    39473996    def dominating_set(self, independent=False, value_only=False, solver=None, verbose=0):
    39483997        r"""
     
    1008810137
    1008910138    def _keys_for_vertices(self):
    1009010139        """
    10091         Returns a function mapping each vertex to a unique and hopefuly readable string
     10140        Returns a function mapping each vertex to a unique and hopefully readable string
    1009210141        """
    1009310142        from sage.graphs.dot2tex_utils import key, key_with_hash
    1009410143        if len(set(key(v) for v in self)) < len(self.vertices()):
     
    1011410163        INPUT:
    1011510164
    1011610165        - ``labels`` - "string" or "latex" (default: "string"). If labels is
    10117           string latex command are not interepreted. This option stands for both
     10166          string latex command are not interpreted. This option stands for both
    1011810167          vertex labels and edge labels.
    1011910168
    1012010169        - ``vertex_labels`` - boolean (default: True) whether to add the labels
  • sage/graphs/graph.py

    diff --git a/sage/graphs/graph.py b/sage/graphs/graph.py
    a b  
    31663166   
    31673167        return classes_b
    31683168
    3169     def max_weight_matching(self):
    3170         import networkx
    3171         return networkx.max_weight_matching(self.networkx_graph(copy=False))
    3172 
    3173 
    31743169def compare_edges(x, y):
    31753170    """
    31763171    Compare edge x to edge y, return -1 if x y, 1 if x y, else 0.