Limbo 3.5.4
Loading...
Searching...
No Matches
MISColoring.h
Go to the documentation of this file.
1
6#ifndef LIMBO_ALGORITHMS_COLORING_MISCOLORING
7#define LIMBO_ALGORITHMS_COLORING_MISCOLORING
8
9#include <iostream>
10#include <vector>
11#include <queue>
12#include <set>
13#include <limits>
14#include <cassert>
15#include <cmath>
16#include <stdlib.h>
17#include <cstdio>
18#include <sstream>
19#include <algorithm>
20#include <boost/cstdint.hpp>
21#include <boost/unordered_map.hpp>
22#include <boost/graph/graph_concepts.hpp>
23#include <boost/graph/subgraph.hpp>
24#include <boost/property_map/property_map.hpp>
25//#include <boost/graph/bipartite.hpp>
26//#include <boost/graph/kruskal_min_spanning_tree.hpp>
27//#include <boost/graph/prim_minimum_spanning_tree.hpp>
28//#include <boost/graph/dijkstra_shortest_paths.hpp>
29#include <limbo/string/String.h>
31#if GUROBI == 1
34#endif
35
37namespace limbo
38{
40namespace algorithms
41{
43namespace coloring
44{
45
53template <typename GraphType>
54class MISColoring : public Coloring<GraphType>
55{
56 public:
58 typedef Coloring<GraphType> base_type;
59 using typename base_type::graph_type;
60 using typename base_type::graph_vertex_type;
61 using typename base_type::graph_edge_type;
62 using typename base_type::vertex_iterator_type;
63 using typename base_type::edge_iterator_type;
64 using typename base_type::edge_weight_type;
65 using typename base_type::ColorNumType;
66 typedef typename base_type::EdgeHashType edge_hash_type;
67#if GUROBI == 1
70#endif
72
75 MISColoring(graph_type const& g)
76 : base_type(g)
77 {}
78
79 virtual ~MISColoring() {}
80
84 virtual void precolor(graph_vertex_type /*v*/, int8_t /*c*/) {limboAssert("precoloring is not supported");}
85
90 void write_graph_sol(string const& filename, std::vector<int8_t> const& vVertexExcludeMark, std::vector<graph_vertex_type> const& vMISVertex) const
91 {
92 std::ofstream out((filename+".gv").c_str());
93 out << "graph D { \n"
94 << " randir = LR\n"
95 << " size=\"4, 3\"\n"
96 << " ratio=\"fill\"\n"
97 << " edge[style=\"bold\",fontsize=200]\n"
98 << " node[shape=\"circle\",fontsize=200]\n";
99
100 //output nodes
101 uint32_t vertex_num = boost::num_vertices(this->m_graph);
102 for(uint32_t k = 0; k < vertex_num; ++k)
103 {
104 out << " " << k << "[shape=\"circle\"";
105 //output coloring label
106 if (vVertexExcludeMark[k]) // excluded
107 out << ",label=\"" << k << "\",style=filled,fillcolor=\"grey\"";
108 else if (std::find(vMISVertex.begin(), vMISVertex.end(), k) != vMISVertex.end())
109 out << ",label=\"" << k << "\",style=filled,fillcolor=\"red\"";
110 else
111 out << ",label=\"" << k << "\"";
112 out << "]\n";
113 }//end for
114
115 //output edges
116 edge_iterator_type ei, eie;
117 for (boost::tie(ei, eie) = boost::edges(this->m_graph); ei != eie; ++ei)
118 {
119 edge_weight_type w = boost::get(boost::edge_weight, this->m_graph, *ei);
120 graph_vertex_type s = boost::source(*ei, this->m_graph);
121 graph_vertex_type t = boost::target(*ei, this->m_graph);
122 if (w >= 0) // conflict edge
123 {
124 if (vVertexExcludeMark[s] || vVertexExcludeMark[t]) // skipped
125 out << " " << s << "--" << t << "[color=\"grey\",style=\"solid\",penwidth=3]\n";
126 else
127 out << " " << s << "--" << t << "[color=\"black\",style=\"solid\",penwidth=3]\n";
128 }
129 else // stitch edge
130 out << " " << s << "--" << t << "[color=\"blue\",style=\"dotted\",penwidth=3]\n";
131 }
132 out << "}";
133 out.close();
134 la::graphviz2pdf(filename);
135 }
136
137 protected:
140 virtual double coloring()
141 {
142 std::vector<int8_t> vVertexExcludeMark (boost::num_vertices(this->m_graph), 0);
143 std::vector<graph_vertex_type> vMISVertex;
144
145 for (int8_t c = 0; c < this->color_num(); ++c)
146 {
147 vMISVertex.clear();
148 // compute maximum independent set to the residual graph
149#if GUROBI == 1
150 // find maximum independent set with maximum number of vertices
151 computeMWISILP(vVertexExcludeMark, vMISVertex);
152#else
153 // only find maximum independent set
154 computeMIS(vVertexExcludeMark, vMISVertex);
155#endif
156 // apply color
157 for (typename std::vector<graph_vertex_type>::const_iterator vi = vMISVertex.begin(); vi != vMISVertex.end(); ++vi)
158 {
159 this->m_vColor[*vi] = c;
160 vVertexExcludeMark[*vi] = true;
161 }
162 }
163
164 // greedy coloring for the rest
165 vertex_iterator_type vi, vie;
166 for (boost::tie(vi, vie) = boost::vertices(this->m_graph); vi != vie; ++vi)
167 {
168 graph_vertex_type v = *vi;
169 if (!vVertexExcludeMark[v]) // skip excluded vertices
170 {
171 int8_t bestColor = 0;
172 edge_weight_type bestCost = std::numeric_limits<edge_weight_type>::max();
173 for (int8_t c = 0; c < this->color_num(); ++c)
174 {
175 edge_weight_type curCost = 0;
176 typename boost::graph_traits<graph_type>::adjacency_iterator ui, uie;
177 for (boost::tie(ui, uie) = boost::adjacent_vertices(v, this->m_graph); ui != uie; ++ui)
178 {
179 graph_vertex_type u = *ui;
180 if (this->m_vColor[u] >= 0 && this->m_vColor[u] < this->color_num())
181 {
182 if (c == this->m_vColor[u])
183 {
184 std::pair<graph_edge_type, bool> eU2v = boost::edge(v, u, this->m_graph);
185#ifdef DEBUG_MISCOLORING
186 assert(eU2v.second);
187#endif
188 // edge weight is important since we may deal with merged graphs
189 // this is just for generality purpose
190 curCost += std::max((edge_weight_type)1, boost::get(boost::edge_weight, this->m_graph, eU2v.first));
191 }
192 }
193 }
194 if (curCost < bestCost)
195 {
196 bestCost = curCost;
197 bestColor = c;
198 }
199 }
200 this->m_vColor[v] = bestColor;
201 }
202 }
203
204#ifdef DEBUG_MISCOLORING
205 this->write_graph("final_output");
206#endif
207 return this->calc_cost(this->m_vColor);
208 }
209
210#if GUROBI == 1
217 double computeMWISILP(std::vector<int8_t> const& vVertexExcludeMark, std::vector<graph_vertex_type>& vMISVertex)
218 {
219 uint32_t vertex_num = boost::num_vertices(this->m_graph);
220 uint32_t edge_num = boost::num_edges(this->m_graph);
221 uint32_t exclude_vertex_num = std::count(vVertexExcludeMark.begin(), vVertexExcludeMark.end(), 1);
222
224 model_type opt_model;
226 gurobiParams.setOutputFlag(0);
227 gurobiParams.setNumThreads(this->m_threads);
228 //set up the ILP variables
229 // this is a map of length vertex_num
230 std::vector<model_type::variable_type> vVertex2Var (vertex_num);
231 boost::unordered_map<graph_edge_type, model_type::variable_type, edge_hash_type> hEdge2Var; // edge index
232
233 // vertex variables
234 opt_model.reserveVariables(vertex_num-exclude_vertex_num+edge_num);
235 vertex_iterator_type vi, vie;
236 for (boost::tie(vi, vie) = boost::vertices(this->m_graph); vi != vie; ++vi)
237 {
238 graph_vertex_type v = *vi;
239 if (!vVertexExcludeMark[v]) // skip excluded vertices
240 {
241 std::ostringstream oss;
242 oss << "v" << v;
243 vVertex2Var[v] = opt_model.addVariable(0, 1, limbo::solvers::INTEGER, oss.str());
244 }
245 }
246 // edge variables
247 edge_iterator_type ei, eie;
248 for (boost::tie(ei, eie) = boost::edges(this->m_graph); ei != eie; ++ei)
249 {
250 graph_vertex_type s = boost::source(*ei, this->m_graph);
251 graph_vertex_type t = boost::target(*ei, this->m_graph);
252
253 if (!vVertexExcludeMark[s] && !vVertexExcludeMark[t]) // skip any edge connected to excluded vertices
254 {
255 std::ostringstream oss;
256 oss << "e" << s << "_" << t;
257 hEdge2Var.insert(std::make_pair(*ei, opt_model.addVariable(0, 1, limbo::solvers::INTEGER, oss.str())));
258 }
259 }
260
261 // set up the objective
262 // maximize the edge weight selected, which is equivalent to minimize the edge weight in the residual graph
263 // max. sum e
264 model_type::expression_type obj;
265 for (typename boost::unordered_map<graph_edge_type, model_type::variable_type, edge_hash_type>::const_iterator it = hEdge2Var.begin(); it != hEdge2Var.end(); ++it)
266 obj += it->second;
267 opt_model.setObjective(obj);
268 opt_model.setOptimizeType(limbo::solvers::MAX);
269
270 // conflict constraints
271 char buf[100];
272 uint32_t constr_num = 0;
273 for (boost::tie(ei, eie) = boost::edges(this->m_graph); ei != eie; ++ei)
274 {
275 graph_vertex_type s = boost::source(*ei, this->m_graph);
276 graph_vertex_type t = boost::target(*ei, this->m_graph);
277
278 if (!vVertexExcludeMark[s] && !vVertexExcludeMark[t]) // skip any edge connected to excluded vertices
279 {
280 sprintf(buf, "R%u", constr_num++);
281 opt_model.addConstraint(
282 vVertex2Var[s] + vVertex2Var[t] <= 1
283 , buf);
284 }
285 }
286 // edge selected constraints
287 // the edge variable will be 1 if any of its vertices is selected
288 // e <= vs + vt
289 // if vs = vt = 0, e = 0
290 // else e can be any value between 0 and 1
291 // consider that we are maximizing e in the objective
292 for (typename boost::unordered_map<graph_edge_type, model_type::variable_type, edge_hash_type>::const_iterator it = hEdge2Var.begin(); it != hEdge2Var.end(); ++it)
293 {
294 graph_edge_type const& e = it->first;
295 graph_vertex_type s = boost::source(e, this->m_graph);
296 graph_vertex_type t = boost::target(e, this->m_graph);
297
298 sprintf(buf, "E%u", constr_num++);
299 opt_model.addConstraint(
300 it->second - vVertex2Var[s] - vVertex2Var[t] <= 0
301 , buf);
302 }
303
304 //optimize model
305 solver_type solver (&opt_model);
306 int32_t opt_status = solver(&gurobiParams);
307#ifdef DEBUG_MISCOLORING
308 opt_model.print("graph.lp");
309 opt_model.printSolution("graph.sol");
310#endif
311 if(opt_status == limbo::solvers::INFEASIBLE)
312 {
313 cout << "ERROR: The model is infeasible... EXIT" << endl;
314 exit(1);
315 }
316
317 // collect maximum independent set vertices
318 for (boost::tie(vi, vie) = boost::vertices(this->m_graph); vi != vie; ++vi)
319 {
320 graph_vertex_type v = *vi;
321 if (!vVertexExcludeMark[v]) // skip excluded vertices
322 {
323 int8_t value = opt_model.variableSolution(vVertex2Var[v]);
324 if (value)
325 vMISVertex.push_back(v);
326 }
327 }
328
329#ifdef DEBUG_MISCOLORING
330 this->write_graph_sol("graph_sol", vVertexExcludeMark, vMISVertex); // dump solution figure
331#endif
332
333 // return objective value
334 return opt_model.evaluateObjective();
335 }
336#endif
337
342 double computeMIS(std::vector<int8_t> const& vVertexExcludeMark, std::vector<graph_vertex_type>& vMISVertex)
343 {
344 uint32_t vertex_num = boost::num_vertices(this->m_graph);
345
346 // this is a map of length vertex_num
347 std::set<graph_vertex_type> sVertex;
348
349 for (uint32_t i = 0; i < vertex_num; ++i)
350 {
351 if (!vVertexExcludeMark[i]) // skip excluded vertices
352 sVertex.insert(i);
353 }
354
355 // while sVertex is not empty
356 // choose v \in V
357 // add v to vMISVertex
358 // remove neighbors of v from V
359 while (!sVertex.empty())
360 {
361 graph_vertex_type v = *sVertex.begin();
362 vMISVertex.push_back(v);
363
364 sVertex.erase(v);
365 typename boost::graph_traits<graph_type>::adjacency_iterator ui, uie;
366 for (boost::tie(ui, uie) = boost::adjacent_vertices(v, this->m_graph); ui != uie; ++ui)
367 {
368 graph_vertex_type u = *ui;
369 sVertex.erase(u);
370 }
371 }
372
373#ifdef DEBUG_MISCOLORING
374 this->write_graph_sol("graph_sol", vVertexExcludeMark, vMISVertex); // dump solution figure
375#endif
376
377 // return size of independent set
378 return vMISVertex.size();
379 }
380};
381
382} // namespace coloring
383} // namespace algorithms
384} // namespace limbo
385
386#endif
#define limboAssert(condition)
custom assertion without message
Definition AssertMsg.h:36
base class for all graph coloring algorithms
Gurobi API wrapper using its C API.
Basic utilities such as variables and linear expressions in solvers.
Check string is integer, floating point, number... Convert string to upper/lower cases.
graph_type const & m_graph
initial graph
Definition Coloring.h:239
int32_t m_threads
control number of threads for ILP solver
Definition Coloring.h:244
virtual ColorNumType color_num() const
Definition Coloring.h:173
std::vector< int8_t > m_vColor
coloring solutions
Definition Coloring.h:240
virtual edge_weight_type calc_cost(std::vector< int8_t > const &vColor) const
Definition Coloring.h:397
virtual void write_graph(std::string const &filename) const
virtual void precolor(graph_vertex_type, int8_t)
Definition MISColoring.h:84
double computeMIS(std::vector< int8_t > const &vVertexExcludeMark, std::vector< graph_vertex_type > &vMISVertex)
compute maximum independent set, weight is not supported yet
void write_graph_sol(string const &filename, std::vector< int8_t > const &vVertexExcludeMark, std::vector< graph_vertex_type > const &vMISVertex) const
Definition MISColoring.h:90
Gurobi API with limbo::solvers::LinearModel.
Definition GurobiApi.h:97
Base class for custom Gurobi parameters.
Definition GurobiApi.h:34
void setNumThreads(int v)
set number of threads
Definition GurobiApi.h:65
void setOutputFlag(int v)
set output flag
Definition GurobiApi.h:62
model to describe an optimization problem
Definition Solvers.h:1161
namespace for Limbo.Algorithms.Coloring
namespace for Limbo.algorithms
@ MAX
maximize objective
Definition Solvers.h:32
@ INFEASIBLE
the model is infeasible
Definition Solvers.h:37
@ INTEGER
integer number
Definition Solvers.h:34
namespace for Limbo