Ticket #7601: trac_7601.patch

File trac_7601.patch, 6.3 KB (added by ncohen, 11 years ago)
  • sage/graphs/graph.py

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1249573009 25200
    # Node ID 0146a338195f2ca694531f082f3e4b14a887098e
    # Parent  965feac7d92d5fbe7ecbd5d7ff218991f4243bed
    Graph.edge_connectivity
    
    diff -r 965feac7d92d -r 0146a338195f sage/graphs/graph.py
    a b  
    32543254            v = pv
    32553255        return B, C
    32563256
     3257    def edge_connectivity(self,value_only=True,use_edge_labels=True, vertices=False):
     3258        r"""
     3259        Returns the edge connectivity of the graph
     3260        ( cf. http://en.wikipedia.org/wiki/Connectivity_(graph_theory) )
     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 minimum edge cut
     3268              are returned.
     3269
     3270        - ``use_edge_labels`` (boolean)
     3271           
     3272            - When set to ``True``, computes a weighted minimum 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. Implies
     3282              ``value_only=False``.
     3283           
     3284            The default value of this parameter is ``False``.
     3285   
     3286        EXAMPLE:
     3287
     3288        A basic application on the PappusGraph()
     3289       
     3290           sage: g = graphs.PappusGraph()
     3291           sage: g.edge_connectivity() # optional - requires Glpk or COIN-OR/CBC
     3292           3.0
     3293
     3294        The edge connectivity of a complete graph ( and of a random graph )
     3295        is its minimum degree, and one of the two parts of the bipartition
     3296        is reduced to only one vertex. The cutedges isomorphic to a
     3297        Star graph ::
     3298
     3299           sage: g = graphs.CompleteGraph(5)
     3300           sage: [ value, edges, [ setA, setB ]] = g.edge_connectivity(vertices=True) # optional - requires Glpk or COIN-OR/CBC
     3301           sage: print value                                                          # optional - requires Glpk or COIN-OR/CBC
     3302           4.0
     3303           sage: len(setA) == 1 or len(setB) == 1                                     # optional - requires Glpk or COIN-OR/CBC
     3304           True
     3305           sage: cut = Graph()
     3306           sage: cut.add_edges(edges)                                                 # optional - requires Glpk or COIN-OR/CBC
     3307           sage: cut.is_isomorphic(graphs.StarGraph(4))                               # optional - requires Glpk or COIN-OR/CBC
     3308           True
     3309
     3310        Even if obviously in any graph we know that the edge connectivity
     3311        is less than the minimum degree of the graph::
     3312
     3313           sage: g = graphs.RandomGNP(10,.3)
     3314           sage: min(g.degree()) >= g.edge_connectivity()                             # optional - requires Glpk or COIN-OR/CBC
     3315           True
     3316
     3317        If we build a tree then assign to its edges a random value, the
     3318        minimum cut will be the edge with minimum value::
     3319
     3320           sage: g = graphs.RandomGNP(15,.5)
     3321           sage: tree = Graph()
     3322           sage: tree.add_edges(g.min_spanning_tree())
     3323           sage: for u,v in tree.edge_iterator(labels=None):
     3324           ...        tree.set_edge_label(u,v,random())
     3325           sage: minimum = min([l for u,v,l in tree.edge_iterator()])                 # optional - requires Glpk or COIN-OR/CBC
     3326           sage: [value, [(u,v,l)]] = tree.edge_connectivity(value_only=False)        # optional - requires Glpk or COIN-OR/CBC
     3327           sage: l == minimum                                                         # optional - requires Glpk or COIN-OR/CBC
     3328           True
     3329        """
     3330        g=self
     3331
     3332        if vertices:
     3333            value_only=False
     3334       
     3335        if use_edge_labels:
     3336            weight=lambda x: 1 if x==None else x
     3337        else:
     3338            weight=lambda x: 1
     3339
     3340        if g.is_directed():
     3341            reorder_edge = lambda x,y : (x,y)
     3342        else:
     3343            reorder_edge = lambda x,y : (x,y) if x<= y else (y,x)   
     3344
     3345        from sage.numerical.mip import MixedIntegerLinearProgram
     3346
     3347        p = MixedIntegerLinearProgram(maximization=False)
     3348
     3349        in_set = p.new_variable(dim=2)
     3350        in_cut = p.new_variable(dim=1)
     3351
     3352
     3353        # A vertex has to be in some set
     3354        for v in g:
     3355            p.add_constraint(in_set[0][v]+in_set[1][v],max=1,min=1)
     3356
     3357        # There is no empty set
     3358        p.add_constraint(sum([in_set[1][v] for v in g]),min=1)
     3359        p.add_constraint(sum([in_set[0][v] for v in g]),min=1)
     3360
     3361        if g.is_directed():
     3362            # There is no edge from set 0 to set 1 which
     3363            # is not in the cut
     3364            for (u,v) in g.edge_iterator(labels=None):
     3365                p.add_constraint(in_set[0][u] + in_set[1][v] - in_cut[(u,v)], max = 1)
     3366        else:
     3367
     3368            # Two adjacent vertices are in different sets if and only if
     3369            # the edge between them is in the cut
     3370   
     3371            for (u,v) in g.edge_iterator(labels=None):
     3372                p.add_constraint(in_set[0][u]+in_set[1][v]-in_cut[reorder_edge(u,v)],max=1)
     3373                p.add_constraint(in_set[1][u]+in_set[0][v]-in_cut[reorder_edge(u,v)],max=1)
     3374
     3375   
     3376        p.set_binary(in_set)
     3377        p.set_binary(in_cut)
     3378
     3379        p.set_objective(sum([weight(l ) * in_cut[reorder_edge(u,v)] for (u,v,l ) in g.edge_iterator()]))
     3380
     3381        if value_only:
     3382            return p.solve(objective_only=True)
     3383        else:
     3384            val = [p.solve()]
     3385
     3386            in_cut = p.get_values(in_cut)
     3387            in_set = p.get_values(in_set)
     3388
     3389            edges = []
     3390            for (u,v,l) in g.edge_iterator():
     3391                if in_cut[reorder_edge(u,v)] == 1:
     3392                    edges.append((u,v,l))
     3393                   
     3394            val.append(edges)
     3395           
     3396            if vertices:
     3397                a = []
     3398                b = []
     3399                for v in g:
     3400                    if in_set[0][v] == 1:
     3401                        a.append(v)
     3402                    else:
     3403                        b.append(v)
     3404                val.append([a,b])
     3405
     3406            return val
     3407
    32573408    ### Vertex handlers
    32583409
    32593410    def add_vertex(self, name=None):