1 | #include <ogdf/graphalg/MaxFlowEdmondsKarp.h> |
2 | #include <ogdf/basic/graph_generators.h> |
3 | #include <ogdf/graphalg/MinSTCutMaxFlow.h> |
4 | #include <ogdf/graphalg/MinSTCutDijkstra.h> |
5 | #include <ogdf/graphalg/MinSTCutBFS.h> |
6 | |
7 | #include <graphs.h> |
8 | |
9 | using std::string; |
10 | |
11 | template<typename T> |
12 | void describeMSTCutFromMaxFlowSuite(const string &name) { |
13 | describe("MinSTCutMaxFlow<" + name + ">" , [] { |
14 | it("can handle an isolated node" , [](){ |
15 | Graph graph; |
16 | node v = graph.newNode(); |
17 | EdgeArray<T> weights(graph, 4); |
18 | |
19 | EdgeArray<T> flow; |
20 | MaxFlowEdmondsKarp<T> maxFlowEdmondsKarp(graph); |
21 | maxFlowEdmondsKarp.computeFlow(weights, v, v, flow); |
22 | MinSTCutMaxFlow<T> minSTCut; |
23 | minSTCut.call(graph, weights, flow, v, v); |
24 | }); |
25 | |
26 | it("works on a simple example" , [](){ |
27 | Graph graph; |
28 | node s = graph.newNode(); |
29 | node t = graph.newNode(); |
30 | node v1 = graph.newNode(); |
31 | node v2 = graph.newNode(); |
32 | |
33 | graph.newEdge(s, v1); |
34 | graph.newEdge(v2, t); |
35 | |
36 | EdgeArray<T> weights(graph, 4); |
37 | weights[graph.newEdge(s, v2)] = 1; |
38 | weights[graph.newEdge(v1, t)] = 2; |
39 | |
40 | EdgeArray<T> flow; |
41 | MaxFlowEdmondsKarp<T> mfek(graph); |
42 | mfek.computeFlow(weights, s, t, flow); |
43 | MinSTCutMaxFlow<T> minSTCut; |
44 | minSTCut.call(graph, weights, flow, s, t); |
45 | |
46 | AssertThat(minSTCut.isInFrontCut(s), Equals(true)); |
47 | AssertThat(minSTCut.isInFrontCut(v1), Equals(true)); |
48 | AssertThat(minSTCut.isInBackCut(t), Equals(true)); |
49 | AssertThat(minSTCut.isInBackCut(v2), Equals(true)); |
50 | }); |
51 | |
52 | it("works on a more complex example" , [](){ |
53 | Graph graph; |
54 | emptyGraph(graph, 8); |
55 | List<node> nodes; |
56 | graph.allNodes(nodes); |
57 | EdgeArray<T> weights(graph); |
58 | weights[graph.newEdge(*nodes.get(0), *nodes.get(1))] = 16; |
59 | weights[graph.newEdge(*nodes.get(0), *nodes.get(2))] = 13; |
60 | weights[graph.newEdge(*nodes.get(1), *nodes.get(2))] = 10; |
61 | weights[graph.newEdge(*nodes.get(1), *nodes.get(3))] = 12; |
62 | weights[graph.newEdge(*nodes.get(2), *nodes.get(1))] = 4; |
63 | weights[graph.newEdge(*nodes.get(2), *nodes.get(4))] = 14; |
64 | weights[graph.newEdge(*nodes.get(3), *nodes.get(2))] = 9; |
65 | weights[graph.newEdge(*nodes.get(3), *nodes.get(5))] = 20; |
66 | weights[graph.newEdge(*nodes.get(4), *nodes.get(3))] = 7; |
67 | weights[graph.newEdge(*nodes.get(4), *nodes.get(5))] = 4; |
68 | |
69 | weights[graph.newEdge(*nodes.get(5), *nodes.get(6))] = 100; |
70 | weights[graph.newEdge(*nodes.get(7), *nodes.get(5))] = 100; |
71 | |
72 | EdgeArray<T> flow; |
73 | MaxFlowEdmondsKarp<T> mfek(graph); |
74 | mfek.computeFlow(weights, *nodes.get(0), *nodes.get(5), flow); |
75 | MinSTCutMaxFlow<T> minSTCut; |
76 | minSTCut.call(graph, weights, flow, *nodes.get(0), *nodes.get(5)); |
77 | |
78 | AssertThat(minSTCut.isInFrontCut(*nodes.get(0)), Equals(true)); |
79 | AssertThat(minSTCut.isInFrontCut(*nodes.get(1)), Equals(true)); |
80 | AssertThat(minSTCut.isInFrontCut(*nodes.get(2)), Equals(true)); |
81 | AssertThat(minSTCut.isInFrontCut(*nodes.get(4)), Equals(true)); |
82 | |
83 | AssertThat(minSTCut.isInBackCut(*nodes.get(3)), Equals(true)); |
84 | AssertThat(minSTCut.isInBackCut(*nodes.get(5)), Equals(true)); |
85 | |
86 | AssertThat(minSTCut.isInFrontCut(*nodes.get(6)), Equals(false)); |
87 | AssertThat(minSTCut.isInBackCut(*nodes.get(6)), Equals(false)); |
88 | AssertThat(minSTCut.isOfType(*nodes.get(6), MinSTCutMaxFlow<T>::cutType::NO_CUT), Equals(true)); |
89 | AssertThat(minSTCut.isInBackCut(*nodes.get(7)), Equals(true)); |
90 | AssertThat(minSTCut.isInFrontCut(*nodes.get(7)), Equals(false)); |
91 | }); |
92 | |
93 | describe("detection of complementary back cuts" , [] { |
94 | MinSTCutMaxFlow<T> minSTCut; |
95 | forEachGraphItWorks({GraphProperty::connected}, [&] (const Graph& graph, const std::string& graphName, const std::set<GraphProperty>& props) { |
96 | EdgeArray<T> caps(graph); |
97 | |
98 | for(edge e : graph.edges) { |
99 | caps[e] = randomNumber(1, 10); |
100 | } |
101 | |
102 | for(node v : graph.nodes) if(v != graph.firstNode()) { |
103 | List<edge> cutEdges; |
104 | minSTCut.call(graph, caps, graph.firstNode(), v, cutEdges, nullptr); |
105 | |
106 | bool isComplement = true; |
107 | |
108 | for(node w : graph.nodes) { |
109 | isComplement &= minSTCut.isInFrontCut(w) != minSTCut.isInBackCut(w); |
110 | } |
111 | |
112 | AssertThat(minSTCut.frontCutIsComplementOfBackCut(), Equals(isComplement)); |
113 | } |
114 | }); |
115 | }); |
116 | }); |
117 | } |
118 | |
119 | template<typename T> |
120 | void describeMSTCutSuite(MinSTCutModule<T> &minst, const string &name, const string &type, bool canHandleNonPlanar) { |
121 | describe("MinSTCut" + name + "<" + type + ">" , [&] { |
122 | it("works on a planar unweighted example" , [&]() { |
123 | Graph graph; |
124 | node s = graph.newNode(); |
125 | node t = graph.newNode(); |
126 | node v1 = graph.newNode(); |
127 | node v2 = graph.newNode(); |
128 | node v3 = graph.newNode(); |
129 | node v4 = graph.newNode(); |
130 | node v5 = graph.newNode(); |
131 | |
132 | edge e1 = graph.newEdge(s, v1); |
133 | edge e2 = graph.newEdge(s, v2); |
134 | edge e_st = graph.newEdge(s, t); |
135 | graph.newEdge(v2, v4); |
136 | graph.newEdge(v2, v5); |
137 | graph.newEdge(v1, v3); |
138 | graph.newEdge(v1, v4); |
139 | graph.newEdge(v5, t); |
140 | graph.newEdge(v4, t); |
141 | graph.newEdge(v3, t); |
142 | |
143 | List<edge> edgeList; |
144 | minst.call(graph, s, t, edgeList, e_st); |
145 | |
146 | AssertThat(edgeList.size(), Equals(2)); |
147 | AssertThat(edgeList.popFrontRet(), Equals(e2)); |
148 | AssertThat(edgeList.popFrontRet(), Equals(e1)); |
149 | }); |
150 | |
151 | it("works on a planar weighted example" , [&]() { |
152 | Graph graph; |
153 | node s = graph.newNode(); |
154 | node t = graph.newNode(); |
155 | node v1 = graph.newNode(); |
156 | node v2 = graph.newNode(); |
157 | node v3 = graph.newNode(); |
158 | |
159 | graph.newEdge(s, v1); |
160 | graph.newEdge(s, v2); |
161 | graph.newEdge(s, v3); |
162 | edge e_st = graph.newEdge(s, t); |
163 | |
164 | EdgeArray<T> weights(graph, 4); |
165 | edge e1, e2, e3; |
166 | weights[e1 = graph.newEdge(v3, t)] = 2; |
167 | weights[e2 = graph.newEdge(v2, t)] = 2; |
168 | weights[e3 = graph.newEdge(v1, t)] = 2; |
169 | |
170 | List<edge> edgeList; |
171 | minst.call(graph, weights, s, t, edgeList, e_st); |
172 | |
173 | AssertThat(edgeList.size(), Equals(3)); |
174 | AssertThat(edgeList.popFrontRet(), Equals(e1)); |
175 | AssertThat(edgeList.popFrontRet(), Equals(e2)); |
176 | AssertThat(edgeList.popFrontRet(), Equals(e3)); |
177 | }); |
178 | if(canHandleNonPlanar) { |
179 | it("works on a non-planar weighted example" , [&]() { |
180 | Graph graph; |
181 | completeGraph(graph, 5); |
182 | |
183 | EdgeArray<T> weight(graph, 5); |
184 | |
185 | node s = graph.chooseNode(); |
186 | node t = graph.newNode(); |
187 | edge e = graph.newEdge(s,t); |
188 | weight[e] = 1; |
189 | List<edge> edgeList; |
190 | minst.call(graph, weight, s, t, edgeList); |
191 | |
192 | AssertThat(((MinSTCutMaxFlow<T>&) minst).isInFrontCut(s), IsTrue()); |
193 | AssertThat(((MinSTCutMaxFlow<T>&) minst).isInBackCut(t), IsTrue()); |
194 | |
195 | AssertThat(edgeList.size(), Equals(1)); |
196 | AssertThat(edgeList.front(), Equals(e)); |
197 | }); |
198 | it("works on a non-planar unweighted example" , [&]() { |
199 | Graph graph; |
200 | completeGraph(graph, 5); |
201 | |
202 | List<node> nodes; |
203 | graph.allNodes(nodes); |
204 | node s = *nodes.get(0); |
205 | node t = *nodes.get(1); |
206 | List<edge> edgeList; |
207 | minst.call(graph, s, t, edgeList); |
208 | |
209 | AssertThat(edgeList.size(), Equals(4)); |
210 | }); |
211 | } |
212 | |
213 | }); |
214 | } |
215 | |
216 | go_bandit([](){ |
217 | describe("MinSTCut from a flow" , []() { |
218 | describeMSTCutFromMaxFlowSuite<int>("int" ); |
219 | describeMSTCutFromMaxFlowSuite<double>("double" ); |
220 | }); |
221 | describe("MinSTCut from a graph" , []() { |
222 | MinSTCutMaxFlow<int> mFint(true, new MaxFlowGoldbergTarjan<int>()); |
223 | describeMSTCutSuite<int>(mFint, "MaxFlow(GoldbergTarjan)" , "int" , true); |
224 | MinSTCutMaxFlow<double> mFdouble; |
225 | describeMSTCutSuite<double>(mFdouble, "MaxFlow(EdmondsKarp)" , "double" , true); |
226 | MinSTCutDijkstra<int> mDint; |
227 | describeMSTCutSuite<int>(mDint, "Dijkstra" , "int" , false); |
228 | MinSTCutDijkstra<double> mDdouble; |
229 | describeMSTCutSuite<double>(mDdouble, "Dijkstra" , "double" , false); |
230 | MinSTCutBFS<int> mBint; |
231 | describeMSTCutSuite<int>(mBint, "BFS" , "int" , false); |
232 | MinSTCutBFS<double> mBdouble; |
233 | describeMSTCutSuite<double>(mBdouble, "BFS" , "double" , false); |
234 | }); |
235 | }); |
236 | |