Ticket #7599: trac_7599.patch

File trac_7599.patch, 7.0 KB (added by ncohen, 10 years ago)
  • sage/graphs/graph.py

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1249573009 25200
    # Node ID 213bea8f242d95b70482e463a944c02d6901558f
    # Parent  559b1c01842f0c0dffa96edbd7f797c4eeae5a3a
    Graph.vertex_cut and edge_cut
    
    diff -r 559b1c01842f -r 213bea8f242d sage/graphs/graph.py
    a b  
    32533253
    32543254            v = pv
    32553255        return B, C
     3256               
     3257    def edge_cut(self,s,t,value_only=True,use_edge_labels=False):
     3258        r"""
     3259        Returns a minimum edge cut between vertices `s` and `t`
     3260        ( cf. http://en.wikipedia.org/wiki/Cut_%28graph_theory%29 )
     3261        represented by a list of edges.
     3262   
     3263       
     3264        INPUT:
     3265
     3266        - ``s`` -- Source vertex
     3267
     3268        - ``t`` -- Sink vertex
     3269   
     3270        - ``value_only`` (boolean)
     3271
     3272            - When set to ``True``, only the value of a maximal
     3273              flow is returned.
     3274
     3275            - When set to ``False``, a list of edges in the minimum cut is
     3276              also returned.
     3277
     3278        - ``use_edge_labels`` (boolean)
     3279            - When set to ``True``, computes a weighted minimum cut
     3280              where each edge has a weight defined by its label. ( if
     3281              an edge has no label, `1` is assumed )
     3282
     3283            - when set to ``False`` (default), each edge has weight `1`.
     3284   
     3285        EXAMPLE:
     3286       
     3287        A basic application in a ``PappusGraph``::
     3288       
     3289           sage: g=graphs.PappusGraph()
     3290           sage: g.edge_cut(1,2,value_only=True) # optional - requires Glpk or COIN-OR/CBC
     3291           3.0
     3292
     3293        If the graph is a path with weighted edges, the edge cut between the two ends
     3294        is the edge of minimum weight ::
     3295
     3296           sage: g = graphs.PathGraph(15)
     3297           sage: for (u,v) in g.edge_iterator(labels=None):
     3298           ...      g.set_edge_label(u,v,random())
     3299           sage: minimum = min([l for u,v,l in g.edge_iterator()])
     3300           sage: minimum == g.edge_cut(0,14,use_edge_labels=True)                                # optional - requires Glpk or COIN-OR/CBC
     3301           True
     3302           sage: [value,[[u,v]]] = g.edge_cut(0,14,use_edge_labels=True, value_only=False)       # optional - requires Glpk or COIN-OR/CBC
     3303           sage: g.edge_label(u,v) == minimum                                                    # optional - requires Glpk or COIN-OR/CBC
     3304           True
     3305        """
     3306        from sage.numerical.mip import MixedIntegerLinearProgram
     3307        g=self
     3308        p=MixedIntegerLinearProgram(maximization=False)
     3309        b=p.new_variable(dim=2)
     3310        v=p.new_variable()
     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        # Some vertices belong to part 1, others to part 0
     3318        p.add_constraint(v[s],min=0,max=0)
     3319        p.add_constraint(v[t],min=1,max=1)       
     3320
     3321        if g.is_directed():
     3322            # we minimize the number of edges
     3323            p.set_objective(sum([weight(w)*b[x][y] for (x,y,w) in g.edges()]))
     3324           
     3325            # Adjacent vertices can belong to different parts only if the
     3326            # edge that connects them is part of the cut
     3327            [p.add_constraint(v[x]+b[x][y]-v[y],min=0,max=0) for (x,y) in g.edges(labels=None)]
     3328           
     3329           
     3330        else:
     3331            # we minimize the number of edges
     3332            p.set_objective(sum([weight(w)*b[min(x,y)][max(x,y)] for (x,y,w) in g.edges()]))
     3333
     3334            # Adjacent vertices can belong to different parts only if the
     3335            # edge that connects them is part of the cut
     3336            for (x,y) in g.edges(labels=None):
     3337                p.add_constraint(v[x]+b[min(x,y)][max(x,y)]-v[y],min=0)
     3338                p.add_constraint(v[y]+b[min(x,y)][max(x,y)]-v[x],min=0)
     3339
     3340        p.set_binary(v)
     3341        p.set_binary(b)
     3342
     3343        if value_only:
     3344            return p.solve(objective_only=True)
     3345        else:
     3346            obj=p.solve()
     3347            b=p.get_values(b)
     3348            if g.is_directed():
     3349                return [obj,[(x,y) for (x,y) in g.edges(labels=None) if b[x][y]==1]]
     3350            else:
     3351                return [obj,[(x,y) for (x,y) in g.edges(labels=None) if b[min(x,y)][max(x,y)]==1]]
     3352       
     3353    def vertex_cut(self,s,t,value_only=True):
     3354        r"""
     3355        Returns a minimum vertex cut between non-adjacent vertices `s` and `t`
     3356        ( cf. http://en.wikipedia.org/wiki/Cut_%28graph_theory%29 )
     3357        represented by a list of vertices.
     3358   
     3359       
     3360        INPUT:
     3361   
     3362        - ``value_only`` : When set to ``True``, only the cardinal of the
     3363          minimum cut is returned
     3364   
     3365        EXAMPLE:
     3366
     3367        A basic application in a ``PappusGraph``::
     3368       
     3369           sage: g=graphs.PappusGraph()
     3370           sage: g.vertex_cut(1,16,value_only=True) # optional - requires Glpk or COIN-OR/CBC
     3371           3.0
     3372
     3373        Or in a bipartite complete graph `K_{2,8}` between the first 2
     3374        vertices, in which case the minimum cut is the other set of 8
     3375        vertices ::
     3376
     3377           sage: g = graphs.CompleteBipartiteGraph(2,8)
     3378           sage: [value, vertices] = g.vertex_cut(0,1, value_only=False) # optional - requires Glpk or COIN-OR/CBC
     3379           sage: print value                                             # optional - requires Glpk or COIN-OR/CBC
     3380           8.0
     3381           sage: vertices == range(2,10)                                 # optional - requires Glpk or COIN-OR/CBC
     3382           True
     3383        """
     3384        from sage.numerical.mip import MixedIntegerLinearProgram
     3385        g=self
     3386        if g.has_edge(s,t):
     3387            raise ValueError, "There can be no vertex cut between adjacent vertices !"
     3388
     3389        p=MixedIntegerLinearProgram(maximization=False)
     3390        b=p.new_variable()
     3391        v=p.new_variable()
     3392
     3393        # Some vertices belong to part 1, some others to part 0
     3394        p.add_constraint(v[s],min=0,max=0)
     3395        p.add_constraint(v[t],min=1,max=1)
     3396
     3397        # b indicates whether the vertices belong to the cut
     3398        p.add_constraint(b[s],min=0,max=0)
     3399        p.add_constraint(b[t],min=0,max=0)
     3400
     3401        if g.is_directed():
     3402            p.set_objective(sum([b[x] for x in g.vertices()]))
     3403            # adjacent vertices belong to the same part except if one of them
     3404            # belongs to the cut
     3405            [p.add_constraint(v[x]+b[y]-v[y],min=0) for (x,y) in g.edges(labels=None)]
     3406
     3407        else:
     3408            p.set_objective(sum([b[x] for x in g.vertices()]))
     3409            # adjacent vertices belong to the same part except if one of them
     3410            # belongs to the cut
     3411            for (x,y) in g.edges(labels=None):
     3412                p.add_constraint(v[x]+b[y]-v[y],min=0)
     3413                p.add_constraint(v[y]+b[x]-v[x],min=0)
     3414
     3415        p.set_binary(b)
     3416        p.set_binary(v)
     3417
     3418        if value_only:
     3419            return p.solve(objective_only=True)
     3420        else:
     3421            obj=p.solve()
     3422            b=p.get_values(b)
     3423            return [obj,[v for v in g if b[v]==1]]
    32563424
    32573425    ### Vertex handlers
    32583426