andres::graph
ilp.hxx
1 #pragma once
2 #ifndef ANDRES_GRAPH_MULTICUT_ILP_HXX
3 #define ANDRES_GRAPH_MULTICUT_ILP_HXX
4 
5 #include <cassert>
6 #include <cstddef>
7 #include <stdexcept>
8 #include <vector>
9 #include <deque>
10 #include <array>
11 #include <algorithm>
12 
13 #include "andres/partition.hxx"
14 #include "andres/graph/complete-graph.hxx"
15 #include "andres/graph/paths.hxx"
16 #include "andres/graph/components.hxx"
17 #include "andres/graph/shortest-paths.hxx"
18 
19 namespace andres {
20 namespace graph {
21 namespace multicut {
22 
31 template<typename ILP, typename GRAPH, typename ECA, typename ELA, typename VIS>
32 inline void
34  const GRAPH& graph,
35  const ECA& edgeCosts,
36  const ELA& inputLabels,
37  ELA& outputLabels,
38  VIS& visitor,
39  size_t numberOfIterations = std::numeric_limits<size_t>::max()
40 ) {
41  struct SubgraphWithCut {
42  SubgraphWithCut(const ILP& ilp)
43  : ilp_(ilp)
44  {}
45  bool vertex(const size_t v) const
46  { return true; }
47  bool edge(const size_t e) const
48  { return ilp_.label(e) == 0; }
49  const ILP& ilp_;
50  };
51 
52  ComponentsBySearch<GRAPH> components;
53  ILP ilp;
54  std::deque<size_t> path;
55  std::vector<ptrdiff_t> buffer;
56  std::vector<double> variables(graph.numberOfEdges());
57  std::vector<double> coefficients(graph.numberOfEdges());
58 
59  auto addCycleInequalities = [&] ()
60  {
61  components.build(graph, SubgraphWithCut(ilp));
62 
63  // search for violated non-chordal cycles and add corresp. inequalities
64  size_t counter = 0;
65 
66  #pragma omp parallel for firstprivate(path, buffer, variables, coefficients), schedule(guided)
67  for (size_t edge = 0; edge < graph.numberOfEdges(); ++edge)
68  if (ilp.label(edge) == 1)
69  {
70  auto v0 = graph.vertexOfEdge(edge, 0);
71  auto v1 = graph.vertexOfEdge(edge, 1);
72 
73  if (components.areConnected(v0, v1))
74  {
75  // search for shortest path
76  spsp(graph, SubgraphWithCut(ilp), v0, v1, path, buffer);
77 
78  // skip chordal paths
79  if (findChord(graph, path.begin(), path.end(), true).first)
80  continue;
81 
82  // add inequality
83  auto sz = path.size();
84 
85  for (size_t j = 0; j < sz - 1; ++j)
86  {
87  variables[j] = static_cast<double>(graph.findEdge(path[j], path[j + 1]).second);
88  coefficients[j] = 1.0;
89  }
90 
91  variables[sz-1] = static_cast<double>(edge);
92  coefficients[sz-1] = -1.0;
93 
94  #pragma omp critical
95  ilp.addConstraint(variables.begin(), variables.begin() + sz, coefficients.begin(), 0, std::numeric_limits<double>::infinity());
96 
97  #pragma omp atomic
98  ++counter;
99  }
100  }
101 
102  return counter;
103  };
104 
105  auto repairSolution = [&] ()
106  {
107  for (size_t edge = 0; edge < graph.numberOfEdges(); ++edge)
108  {
109  auto v0 = graph.vertexOfEdge(edge, 0);
110  auto v1 = graph.vertexOfEdge(edge, 1);
111 
112  outputLabels[edge] = components.areConnected(v0, v1) ? 0 : 1;
113  }
114 
115  ilp.setStart(outputLabels.begin());
116  };
117 
118  ilp.initModel(graph.numberOfEdges(), edgeCosts.data());
119  ilp.setStart(inputLabels.begin());
120 
121  for (size_t i = 0; numberOfIterations == 0 || i < numberOfIterations; ++i)
122  {
123  if (i != 0)
124  {
125  repairSolution();
126 
127  if (!visitor(outputLabels))
128  break;
129  }
130 
131  ilp.optimize();
132 
133  if (addCycleInequalities() == 0)
134  break;
135  }
136 
137  repairSolution();
138 }
139 
140 template<typename ILP, typename GRAPH, typename ECA, typename ELA>
141 inline void
143  const GRAPH& graph,
144  const ECA& edgeCosts,
145  const ELA& inputLabels,
146  ELA& outputLabels,
147  size_t numberOfIterations = std::numeric_limits<size_t>::max()
148 ) {
149  struct Visitor {
150  bool operator()(ELA const& edge_labels) const {
151  return true;
152  }
153  } visitor;
154 
155  ilp<ILP>(graph, edgeCosts, inputLabels, outputLabels, visitor, numberOfIterations);
156 }
157 
163 template<typename ILP, typename GRAPH_VISITOR, typename ECA, typename ELA, typename VIS>
164 inline void
166  const CompleteGraph<GRAPH_VISITOR>& graph,
167  const ECA& edgeCosts,
168  const ELA& inputLabels,
169  ELA& outputLabels,
170  VIS& visitor,
171  size_t numberOfIterations = std::numeric_limits<size_t>::max()
172 ) {
173  struct SubgraphWithCut {
174  SubgraphWithCut(const ILP& ilp)
175  : ilp_(ilp)
176  {}
177  bool vertex(const size_t v) const
178  { return true; }
179  bool edge(const size_t e) const
180  { return ilp_.label(e) == 0; }
181  const ILP& ilp_;
182  };
183 
185  ILP ilp;
186  std::array<double, 3> variables;
187  std::array<double, 3> coefficients;
188 
189  auto addCycleInequalities = [&] ()
190  {
191  components.build(graph, SubgraphWithCut(ilp));
192 
193  size_t counter = 0;
194 
195  #pragma omp parallel for firstprivate(variables, coefficients), schedule(guided)
196  for(size_t edge = 0; edge < graph.numberOfEdges(); ++edge)
197  if (ilp.label(edge) == 1)
198  {
199  variables[2] = edge;
200 
201  auto v0 = graph.vertexOfEdge(edge, 0);
202  auto v1 = graph.vertexOfEdge(edge, 1);
203 
204  for (size_t i = 0; i < graph.numberOfVertices(); ++i)
205  {
206  if (i == v0 || i == v1)
207  continue;
208 
209  variables[0] = graph.findEdge(v0, i).second;
210  variables[1] = graph.findEdge(v1, i).second;
211 
212  if (ilp.label(variables[0]) == 0 && ilp.label(variables[1]) == 0)
213  {
214  coefficients[0] = 1.0;
215  coefficients[1] = 1.0;
216  coefficients[2] = -1.0;
217 
218  #pragma omp critical
219  ilp.addConstraint(variables.begin(), variables.end(), coefficients.begin(), 0, std::numeric_limits<double>::infinity());
220 
221  #pragma omp atomic
222  ++counter;
223  }
224  }
225  }
226 
227  return counter;
228  };
229 
230  auto repairSolution = [&] ()
231  {
232  for(size_t edge = 0; edge < graph.numberOfEdges(); ++edge)
233  {
234  auto v0 = graph.vertexOfEdge(edge, 0);
235  auto v1 = graph.vertexOfEdge(edge, 1);
236 
237  outputLabels[edge] = components.areConnected(v0, v1) ? 0 : 1;
238  }
239 
240  ilp.setStart(outputLabels.begin());
241  };
242 
243  ilp.initModel(graph.numberOfEdges(), edgeCosts.data());
244  ilp.setStart(inputLabels.begin());
245 
246  for (size_t i = 0; numberOfIterations == 0 || i < numberOfIterations; ++i)
247  {
248  if (i != 0)
249  {
250  repairSolution();
251 
252  if (!visitor(outputLabels))
253  break;
254  }
255 
256  ilp.optimize();
257 
258  if (addCycleInequalities() == 0)
259  break;
260  }
261 
262  repairSolution();
263 }
264 
265 template<typename ILP, typename GRAPH_VISITOR, typename ECA, typename ELA>
266 inline void
268  const CompleteGraph<GRAPH_VISITOR>& graph,
269  const ECA& edgeCosts,
270  const ELA& inputLabels,
271  ELA& outputLabels,
272  size_t numberOfIterations = std::numeric_limits<size_t>::max()
273 ) {
274  struct Visitor
275  {
276  bool operator()(ELA const& edge_labels) const
277  {
278  return true;
279  }
280  } visitor;
281 
282  ilp<ILP>(graph, edgeCosts, inputLabels, outputLabels, visitor, numberOfIterations);
283 }
284 
285 } // namespace multicut
286 } // namespace graph
287 } // namespace andres
288 
289 #endif // #ifndef ANDRES_GRAPH_MULTICUT_ILP_HXX