Merge lp:~698id/igraph/st-mincut into lp:igraph

Proposed by Peter Scott
Status: Merged
Merged at revision: 2997
Proposed branch: lp:~698id/igraph/st-mincut
Merge into: lp:igraph
Diff against target: 175 lines (+136/-0)
3 files modified
interfaces/python/igraph/__init__.py (+17/-0)
interfaces/python/igraph/test/flow.py (+18/-0)
interfaces/python/src/graphobject.c (+101/-0)
To merge this branch: bzr merge lp:~698id/igraph/st-mincut
Reviewer Review Type Date Requested Status
Tamás Nepusz Approve
Review via email: mp+128343@code.launchpad.net

Description of the change

Adds Python bindings for the igraph_st_mincut() C function, letting you get a minimum s-t cut. The code is very straightforward, and mostly similar to the other min cut functions, and there are tests.

To post a comment you must log in.
Revision history for this message
Tamás Nepusz (ntamas) wrote :

Thanks a lot, I'll take a look at it soon (probably today).

Revision history for this message
Tamás Nepusz (ntamas) wrote :

I took a look at it and it is all right -- one thing I will change before merging is to add "source" and "target" keyword arguments to Graph.mincut as well to make it similar to mincut_value (which calculates the value of an s-t mincut if source and target are given and calculates the global mincut otherwise). Since this is an API change in Graph.mincut, I will make this change in the 0.7 branch only and merge your changes intact into the 0.6 branch. Thanks a lot once again!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'interfaces/python/igraph/__init__.py'
2--- interfaces/python/igraph/__init__.py 2012-09-04 22:58:16 +0000
3+++ interfaces/python/igraph/__init__.py 2012-10-06 04:05:29 +0000
4@@ -651,6 +651,23 @@
5 """
6 return Cut(self, *GraphBase.mincut(self, capacity))
7
8+ def st_mincut(self, source, target, capacity=None):
9+ """st_mincut(source, target, capacity=None)
10+
11+ Calculates the minimum cut between the source and target vertices in a
12+ graph.
13+
14+ @param source: the source vertex ID
15+ @param target: the target vertex ID
16+ @param capacity: the capacity of the edges. It must be a list or a valid
17+ attribute name or C{None}. In the latter case, every edge will have the
18+ same capacity.
19+ @return: the value of the minimum cut, the IDs of vertices in the
20+ first and second partition, and the IDs of edges in the cut,
21+ packed in a 4-tuple
22+ """
23+ return Cut(self, *GraphBase.st_mincut(self, source, target, capacity))
24+
25 def modularity(self, membership, weights=None):
26 """modularity(membership, weights=None)
27
28
29=== modified file 'interfaces/python/igraph/test/flow.py'
30--- interfaces/python/igraph/test/flow.py 2010-11-26 13:33:18 +0000
31+++ interfaces/python/igraph/test/flow.py 2012-10-06 04:05:29 +0000
32@@ -89,6 +89,24 @@
33 self.failUnless(mc.value == 4)
34 self.assertRaises(KeyError, g.mincut, "unknown")
35
36+ def testStMinCut(self):
37+ g = self.constructSimpleGraph()
38+ mc = g.st_mincut(0, 3, "capacity")
39+ self.failUnless(isinstance(mc, Cut))
40+ self.failUnless(mc.cut == [3, 4])
41+ self.failUnless(mc.value == 4)
42+ self.failUnless(set(mc.partition[0]).union(mc.partition[1]) == \
43+ set(range(g.vcount())))
44+ mc = g.st_mincut(0, 3)
45+ self.failUnless(isinstance(mc, Cut))
46+ self.failUnless(mc.cut == [3, 4])
47+ self.failUnless(mc.value == 2)
48+ mc = g.st_mincut(2, 0, "capacity")
49+ self.failUnless(isinstance(mc, Cut))
50+ self.failUnless(mc.cut == [0, 1])
51+ self.failUnless(mc.value == 6)
52+
53+
54 def testAllSTCuts1(self):
55 # Simple graph with four vertices
56 g = self.constructSimpleGraph(directed=True)
57
58=== modified file 'interfaces/python/src/graphobject.c'
59--- interfaces/python/src/graphobject.c 2012-09-25 22:24:23 +0000
60+++ interfaces/python/src/graphobject.c 2012-10-06 04:05:29 +0000
61@@ -9755,6 +9755,89 @@
62 return result;
63 }
64
65+/** \ingroup python_interface_graph
66+ * \brief Calculates a minimum s-t cut in a graph
67+ */
68+PyObject *igraphmodule_Graph_st_mincut(igraphmodule_GraphObject * self,
69+ PyObject * args, PyObject * kwds)
70+{
71+ static char *kwlist[] = { "source", "target", "capacity", NULL };
72+ igraph_integer_t source, target;
73+ PyObject *cut_o, *part_o, *part2_o, *result;
74+ PyObject *source_o, *target_o, *capacity_o = Py_None;
75+ igraph_vector_t capacity_vector;
76+ igraph_real_t value;
77+ igraph_vector_t partition, partition2, cut;
78+
79+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOO", kwlist,
80+ &source_o, &target_o, &capacity_o))
81+ return NULL;
82+
83+ if (igraphmodule_PyObject_to_vid(source_o, &source, &self->g))
84+ return NULL;
85+ if (igraphmodule_PyObject_to_vid(target_o, &target, &self->g))
86+ return NULL;
87+
88+ if (igraphmodule_PyObject_to_attribute_values(capacity_o,
89+ &capacity_vector,
90+ self, ATTRHASH_IDX_EDGE, 1.0))
91+ return igraphmodule_handle_igraph_error();
92+
93+ if (igraph_vector_init(&partition, 0)) {
94+ igraph_vector_destroy(&capacity_vector);
95+ return igraphmodule_handle_igraph_error();
96+ }
97+ if (igraph_vector_init(&partition2, 0)) {
98+ igraph_vector_destroy(&partition);
99+ igraph_vector_destroy(&capacity_vector);
100+ return igraphmodule_handle_igraph_error();
101+ }
102+ if (igraph_vector_init(&cut, 0)) {
103+ igraph_vector_destroy(&partition);
104+ igraph_vector_destroy(&partition2);
105+ igraph_vector_destroy(&capacity_vector);
106+ return igraphmodule_handle_igraph_error();
107+ }
108+
109+ if (igraph_st_mincut(&self->g, &value, &cut, &partition, &partition2,
110+ source, target, &capacity_vector)) {
111+ igraph_vector_destroy(&cut);
112+ igraph_vector_destroy(&partition);
113+ igraph_vector_destroy(&partition2);
114+ igraph_vector_destroy(&capacity_vector);
115+ return igraphmodule_handle_igraph_error();
116+ }
117+
118+ igraph_vector_destroy(&capacity_vector);
119+
120+ cut_o=igraphmodule_vector_t_to_PyList(&cut, IGRAPHMODULE_TYPE_INT);
121+ igraph_vector_destroy(&cut);
122+ if (!cut_o) {
123+ igraph_vector_destroy(&partition);
124+ igraph_vector_destroy(&partition2);
125+ return NULL;
126+ }
127+
128+ part_o=igraphmodule_vector_t_to_PyList(&partition, IGRAPHMODULE_TYPE_INT);
129+ igraph_vector_destroy(&partition);
130+ if (!part_o) {
131+ Py_DECREF(cut_o);
132+ igraph_vector_destroy(&partition2);
133+ return NULL;
134+ }
135+
136+ part2_o=igraphmodule_vector_t_to_PyList(&partition2, IGRAPHMODULE_TYPE_INT);
137+ igraph_vector_destroy(&partition2);
138+ if (!part2_o) {
139+ Py_DECREF(part_o);
140+ Py_DECREF(cut_o);
141+ return NULL;
142+ }
143+
144+ result = Py_BuildValue("dNNN", (double)value, cut_o, part_o, part2_o);
145+ return result;
146+}
147+
148 /**********************************************************************
149 * Vertex separators *
150 **********************************************************************/
151@@ -14220,6 +14303,24 @@
152 " the ACM 44(4):585-591, 1997.\n"
153 },
154
155+ {"st_mincut", (PyCFunction) igraphmodule_Graph_st_mincut,
156+ METH_VARARGS | METH_KEYWORDS,
157+ "st_mincut(source, target, capacity=None)\n\n"
158+ "Calculates the minimum cut between the source and target vertices in a\n"
159+ "graph.\n\n"
160+ "@param source: the source vertex ID\n"
161+ "@param target: the target vertex ID\n"
162+ "@param capacity: the capacity of the edges. It must be a list or a valid\n"
163+ " attribute name or C{None}. In the latter case, every edge will have the\n"
164+ " same capacity.\n"
165+ "@return: the value of the minimum cut, the IDs of vertices in the\n"
166+ " first and second partition, and the IDs of edges in the cut,\n"
167+ " packed in a 4-tuple\n\n"
168+ "@attention: this function has a more convenient interface in class\n"
169+ " L{Graph} which wraps the result in a list of L{Cut} objects. It is\n"
170+ " advised to use that.\n"
171+ },
172+
173 /*********************/
174 /* VERTEX SEPARATORS */
175 /*********************/

Subscribers

People subscribed via source and target branches