# HG changeset patch
# User Nathann Cohen
# Date 1270388381 -7200
# Node ID 4d0b42b9beb43aa8c0d5f332949bf04d50625f93
# Parent db7143738e1dbcb0c5415884ebaeee4500da1520
trac #7289 : Multiway cut for Graphs
diff -r db7143738e1d -r 4d0b42b9beb4 sage/graphs/generic_graph.py
--- a/sage/graphs/generic_graph.py Fri Mar 19 20:27:13 2010 -0700
+++ b/sage/graphs/generic_graph.py Sun Apr 04 15:39:41 2010 +0200
@@ -3197,6 +3197,148 @@
b=p.get_values(b)
return [obj,[v for v in g if b[v]==1]]
+ def multiway_cut(self, vertices, value_only = False, use_edge_labels = False, **kwds):
+ r"""
+ Returns a minimum edge multiway cut corresponding to the
+ given set of vertices
+ ( cf. http://www.d.kth.se/~viggo/wwwcompendium/node92.html )
+ represented by a list of edges.
+
+ A multiway cut for a vertex set `S` in a graph or a digraph
+ `G` if a set `C` of edges such that any two vertices `u,v`
+ in `S` are disconnected when removing from `G` the edges from
+ `C`.
+
+ Such a cut is said to be minimum when its cardinality
+ (or weight) is minimum.
+
+ INPUT:
+
+ - ``vertices`` (iterable)-- the set of vertices
+
+ - ``value_only`` (boolean)
+
+ - When set to ``True``, only the value of a minimum
+ multiway cut is returned.
+
+ - When set to ``False`` (default), the list of edges
+ is returned
+
+ - ``use_edge_labels`` (boolean)
+ - When set to ``True``, computes a weighted minimum cut
+ where each edge has a weight defined by its label. ( if
+ an edge has no label, `1` is assumed )
+
+ - when set to ``False`` (default), each edge has weight `1`.
+
+ - ``**kwds`` -- arguments to be passed down to the ``solve``
+ function of ``MixedIntegerLinearProgram``. See the documentation
+ of ``MixedIntegerLinearProgram.solve`` for more information.
+
+ EXAMPLES:
+
+ Of course, a multiway cut between two vertices correspond
+ to a minimum edge cut ::
+
+ sage: g = graphs.PetersenGraph()
+ sage: g.edge_cut(0,3) == g.multiway_cut([0,3], value_only = True) # optional - requires GLPK, CBC or CPLEX
+ True
+
+ As Petersen's graph is `3`-regular, a minimum multiway cut
+ between three vertices contains at most `2\times 3` edges
+ (which could correspond to the neighborhood of 2
+ vertices)::
+
+ sage: g.multiway_cut([0,3,9], value_only = True) == 2*3 # optional - requires GLPK, CBC or CPLEX
+ True
+
+ In this case, though, the vertices are an independent set.
+ If we pick instead vertices `0,9,` and `7`, we can save `4`
+ edges in the multiway cut ::
+
+ sage: g.multiway_cut([0,7,9], value_only = True) == 2*3 - 1 # optional - requires GLPK, CBC or CPLEX
+ True
+
+ This example, though, does not work in the directed case anymore,
+ as it is not possible in Petersen's graph to mutualise edges ::
+
+ sage: g = DiGraph(g)
+ sage: g.multiway_cut([0,7,9], value_only = True) == 3*3 # optional - requires GLPK, CBC or CPLEX
+ True
+
+ Of course, a multiway cut between the whole vertex set
+ contains all the edges of the graph::
+
+ sage: C = g.multiway_cut(g.vertices()) # optional - requires GLPK, CBC or CPLEX
+ sage: set(C) == set(g.edges()) # optional - requires GLPK, CBC or CPLEX
+ True
+ """
+ from sage.numerical.mip import MixedIntegerLinearProgram
+ from itertools import combinations, chain
+
+ p = MixedIntegerLinearProgram(maximization = False)
+
+ # height[c][v] represents the height of vertex v for commodity c
+ height = p.new_variable(dim = 2)
+
+ # cut[e] represents whether e is in the cut
+ cut = p.new_variable()
+
+ # Reorder
+ R = lambda x,y : (x,y) if x .5, self.edge_iterator())
+
+ else:
+ return filter(lambda (u,v,l) : cut[R(u,v)] > .5, self.edge_iterator())
+
def vertex_cover(self,algorithm="Cliquer",value_only=False,log=0):
r"""
Returns a minimum vertex cover of the graph