Ticket #7291: trac_7291.patch

File trac_7291.patch, 5.4 KB (added by ncohen, 12 years ago)
  • sage/graphs/graph.py

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1249573009 25200
    # Node ID bc0f21e213312d161071d20d2b9828d9b8d82f74
    # Parent  1c446a66c1c631bb8984f3a91d9cbda74f657b67
    Max cut in Graph
    
    diff -r 1c446a66c1c6 -r bc0f21e21331 sage/graphs/graph.py
    a b  
    32543254            v = pv
    32553255        return B, C
    32563256
     3257    def max_cut(self,value_only=True,use_edge_labels=True, vertices=False):
     3258        r"""
     3259        Returns a maximum edge cut of the graph
     3260        ( cf. http://en.wikipedia.org/wiki/Cut_%28graph_theory%29 )
     3261       
     3262        INPUT:
     3263   
     3264
     3265        - ``value_only`` (boolean) --
     3266            - When set to ``True`` ( default ), only the value is returned.
     3267            - When set to ``False``, both the value and a maximum edge cut
     3268              are returned.
     3269
     3270        - ``use_edge_labels`` (boolean) --
     3271           
     3272            - When set to ``True``, computes a maximum weighted cut
     3273              where each edge has a weight defined by its label. ( if
     3274              an edge has no label, `1` is assumed )
     3275
     3276            - when set to ``False``, each edge has weight `1`.
     3277
     3278        - ``vertices`` (boolean)
     3279
     3280            - When set to ``True``, also returns the two sets of
     3281              vertices that are disconnected by the cut. This implies
     3282              ``value_only=False``.
     3283           
     3284            The default value of this parameter is ``False``.
     3285   
     3286        EXAMPLE:
     3287       
     3288        Quite obviously, the max cut of a bipartite graph
     3289        is the number of edges, and the two sets of vertices
     3290        are the the two sides ::
     3291
     3292            sage: g = graphs.CompleteBipartiteGraph(5,6)
     3293            sage: [ value, edges, [ setA, setB ]] = g.max_cut(vertices=True)                  # optional - requires Glpk or COIN-OR/CBC
     3294            sage: value == 5*6                                                                # optional - requires Glpk or COIN-OR/CBC
     3295            True
     3296            sage: bsetA, bsetB  = g.bipartite_sets()
     3297            sage: (bsetA == setA and bsetB == setB ) or ((bsetA == setB and bsetB == setA ))  # optional - requires Glpk or COIN-OR/CBC
     3298            True
     3299
     3300        The max cut of a Petersen graph::
     3301       
     3302           sage: g=graphs.PetersenGraph()
     3303           sage: g.max_cut()                                                                  # optional - requires Glpk or COIN-OR/CBC
     3304           12.0
     3305
     3306        """
     3307        g=self
     3308
     3309        if vertices:
     3310            value_only=False
     3311       
     3312        if use_edge_labels:
     3313            weight=lambda x: 1 if x==None else x
     3314        else:
     3315            weight=lambda x: 1
     3316
     3317        if g.is_directed():
     3318            reorder_edge = lambda x,y : (x,y)
     3319        else:
     3320            reorder_edge = lambda x,y : (x,y) if x<= y else (y,x)   
     3321
     3322        from sage.numerical.mip import MixedIntegerLinearProgram
     3323
     3324        p = MixedIntegerLinearProgram(maximization=True)
     3325
     3326        in_set = p.new_variable(dim=2)
     3327        in_cut = p.new_variable(dim=1)
     3328
     3329
     3330        # A vertex has to be in some set
     3331        for v in g:
     3332            p.add_constraint(in_set[0][v]+in_set[1][v],max=1,min=1)
     3333
     3334        # There is no empty set
     3335        p.add_constraint(sum([in_set[1][v] for v in g]),min=1)
     3336        p.add_constraint(sum([in_set[0][v] for v in g]),min=1)
     3337
     3338        if g.is_directed():
     3339            # There is no edge from set 0 to set 1 which
     3340            # is not in the cut
     3341            # Besides, an edge can only be in the cut if its vertices
     3342            # belong to different sets
     3343            for (u,v) in g.edge_iterator(labels=None):
     3344                p.add_constraint(in_set[0][u] + in_set[1][v] - in_cut[(u,v)], max = 1)
     3345                p.add_constraint(in_set[0][u] + in_set[0][v] + in_cut[(u,v)], max = 2)
     3346                p.add_constraint(in_set[1][u] + in_set[1][v] + in_cut[(u,v)], max = 2)
     3347        else:
     3348
     3349            # Two adjacent vertices are in different sets if and only if
     3350            # the edge between them is in the cut
     3351   
     3352            for (u,v) in g.edge_iterator(labels=None):
     3353                p.add_constraint(in_set[0][u]+in_set[1][v]-in_cut[reorder_edge(u,v)],max=1)
     3354                p.add_constraint(in_set[1][u]+in_set[0][v]-in_cut[reorder_edge(u,v)],max=1)
     3355                p.add_constraint(in_set[0][u] + in_set[0][v] + in_cut[reorder_edge(u,v)], max = 2)
     3356                p.add_constraint(in_set[1][u] + in_set[1][v] + in_cut[reorder_edge(u,v)], max = 2)
     3357
     3358   
     3359        p.set_binary(in_set)
     3360        p.set_binary(in_cut)
     3361
     3362        p.set_objective(sum([weight(l ) * in_cut[reorder_edge(u,v)] for (u,v,l ) in g.edge_iterator()]))
     3363
     3364        if value_only:
     3365            return p.solve(objective_only=True)
     3366        else:
     3367            val = [p.solve()]
     3368
     3369            in_cut = p.get_values(in_cut)
     3370            in_set = p.get_values(in_set)
     3371
     3372            edges = []
     3373            for (u,v,l) in g.edge_iterator():
     3374                if in_cut[reorder_edge(u,v)] == 1:
     3375                    edges.append((u,v,l))
     3376                   
     3377            val.append(edges)
     3378           
     3379            if vertices:
     3380                a = []
     3381                b = []
     3382                for v in g:
     3383                    if in_set[0][v] == 1:
     3384                        a.append(v)
     3385                    else:
     3386                        b.append(v)
     3387                val.append([a,b])
     3388
     3389            return val
     3390
    32573391    ### Vertex handlers
    32583392
    32593393    def add_vertex(self, name=None):