| 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 | |