14#ifndef LIMBO_ALGORITHMS_COLORING_LP
15#define LIMBO_ALGORITHMS_COLORING_LP
27#include <boost/cstdint.hpp>
28#include <boost/graph/graph_concepts.hpp>
29#include <boost/property_map/property_map.hpp>
30#include <boost/dynamic_bitset.hpp>
33#include "gurobi_c++.h"
35#ifdef DEBUG_NONINTEGERS
36extern std::vector<unsigned int> vLP1NonInteger;
37extern std::vector<unsigned int> vLP1HalfInteger;
38extern std::vector<unsigned int> vLP2NonInteger;
39extern std::vector<unsigned int> vLP2HalfInteger;
40extern std::vector<unsigned int> vLPEndNonInteger;
41extern std::vector<unsigned int> vLPEndHalfInteger;
42extern std::vector<unsigned int> vLPNumIter;
66template <
typename GraphType>
72 typedef typename base_type::graph_type graph_type;
73 typedef typename base_type::graph_vertex_type graph_vertex_type;
74 typedef typename base_type::graph_edge_type graph_edge_type;
75 typedef typename base_type::vertex_iterator_type vertex_iterator_type;
76 typedef typename base_type::edge_iterator_type edge_iterator_type;
77 typedef typename base_type::edge_weight_type edge_weight_type;
111 void set(
double c,
char s)
214 bool is_integer(
double value)
const {
return value == floor(value);}
228template <
typename GraphType>
238template <
typename GraphType>
249 uint32_t numVertices = boost::num_vertices(this->
m_graph);
259 vVertexStack.reserve(numVertices);
260 vNodeVisited[v] =
true;
261 vNodeDistColor[v] = 0;
262 vVertexStack.push_back(v);
263 while (!vVertexStack.empty())
269 graph_vertex_type cv = vVertexStack.back();
271 typename boost::graph_traits<graph_type>::adjacency_iterator ui, uie;
272 for(boost::tie(ui, uie) = adjacent_vertices(cv, this->
m_graph); ui != uie; ++ui)
274 graph_vertex_type u = *ui;
276 if(vNodeDistColor[u] == -1)
278 vNodeDistColor[u] = 1 - vNodeDistColor[cv];
279 vNodeVisited[u] =
true;
281 vVertexStack.push_back(u);
291 for (boost::tie(ui, uie) = adjacent_vertices(cv, this->
m_graph); ui != uie; ++ui)
293 graph_vertex_type u = *ui;
294 if (vNodeVisited[u] && (vNodeDistColor[u] == vNodeDistColor[cv]))
300 int32_t cnt = vVertexStack.size();
301 for(int32_t k = cnt - 1; k >= 0; --k)
303 cycle.push_back(vVertexStack[k]);
305 vInCycle[vVertexStack[k]] =
true;
306 if(vVertexStack[k] == u)
break;
310 if (!cycle.empty() && vInCycle[v] && !(this->has_precolored() &&
check_precolored_num(cycle)+2 > cycle.size()))
313 vOddCyle.back().swap(cycle);
316 for (int32_t k = 0; k != cnt; ++k)
324 vVertexStack.pop_back();
325 vNodeVisited[cv] =
false;
331template <
typename GraphType>
334 graph_vertex_type u = 0;
335 uint32_t maxDegree = 0;
336 vertex_iterator_type vi, vie;
337 for (boost::tie(vi, vie) = boost::vertices(this->
m_graph); vi != vie; ++vi)
339 uint32_t d = boost::degree(*vi, this->
m_graph);
349template <
typename GraphType>
352 uint32_t numVertices = boost::num_vertices(this->
m_graph);
354 uint32_t numColorBits = numVertices<<1;
357 vColorBits.reserve(numColorBits);
361 for (uint32_t i = 0; i != numColorBits; ++i)
363 sprintf(buf,
"v%u", i);
365 uint32_t vertexIdx = i>>1;
368 vColorBits.push_back(optModel.addVar(0.0, 1.0, 0.0, GRB_CONTINUOUS, buf));
371 int8_t colorBit = (i&1)? (
color&1) : (
color>>1);
372#ifdef DEBUG_LPCOLORING
375 vColorBits.push_back(optModel.addVar(colorBit, colorBit, colorBit, GRB_CONTINUOUS, buf));
389 optModel.setObjective(obj, GRB_MINIMIZE);
392 edge_iterator_type ei, eie;
393 for(boost::tie(ei, eie) = boost::edges(this->
m_graph); ei != eie; ++ei)
395 graph_edge_type e = *ei;
396 graph_vertex_type s = boost::source(e, this->
m_graph);
397 graph_vertex_type t = boost::target(e, this->
m_graph);
404 uint32_t bitIdxS = s<<1;
405 uint32_t bitIdxT = t<<1;
408 limboAssertMsg(w > 0,
"no stitch edge allowed, positive edge weight expected: %u", w);
412 vColorBits[bitIdxS] + vColorBits[bitIdxS+1]
413 + vColorBits[bitIdxT] + vColorBits[bitIdxT+1] >= 1
418 1 - vColorBits[bitIdxS] + vColorBits[bitIdxS+1]
419 + 1 - vColorBits[bitIdxT] + vColorBits[bitIdxT+1] >= 1
424 vColorBits[bitIdxS] + 1 - vColorBits[bitIdxS+1]
425 + vColorBits[bitIdxT] + 1 - vColorBits[bitIdxT+1] >= 1
430 1 - vColorBits[bitIdxS] + 1 - vColorBits[bitIdxS+1]
431 + 1 - vColorBits[bitIdxT] + 1 - vColorBits[bitIdxT+1] >= 1
435 if (this->
color_num() == base_type::THREE)
437 for(uint32_t k = 0; k < numColorBits; k += 2)
441 vColorBits[k] + vColorBits[k+1] <= 1,
450template <
typename GraphType>
457 uint32_t bitIdxAnchor = anchorVertex<<1;
458 vColorBits[bitIdxAnchor].set(GRB_DoubleAttr_UB, 0.0);
459 vColorBits[bitIdxAnchor].set(GRB_DoubleAttr_LB, 0.0);
460 vColorBits[bitIdxAnchor+1].set(GRB_DoubleAttr_UB, 0.0);
461 vColorBits[bitIdxAnchor+1].set(GRB_DoubleAttr_LB, 0.0);
465template <
typename GraphType>
468 for(uint32_t k = 0, ke = vColorBits.size(); k < ke; k += 2)
470 double value1 = vColorBits[k].get(GRB_DoubleAttr_X);
471 double value2 = vColorBits[k+1].get(GRB_DoubleAttr_X);
475 obj += vColorBits[k+1]-vColorBits[k];
476 else if (value1 < value2)
477 obj += vColorBits[k]-vColorBits[k+1];
483template <
typename GraphType>
486 edge_iterator_type ei, eie;
487 for(boost::tie(ei, eie) = boost::edges(this->
m_graph); ei != eie; ++ei)
489 graph_edge_type e = *ei;
490 graph_vertex_type s = boost::source(e, this->
m_graph);
491 graph_vertex_type t = boost::target(e, this->
m_graph);
493 for (uint32_t i = 0; i != 2; ++i)
495 uint32_t bitIdxS = (s<<1)+i;
496 uint32_t bitIdxT = (t<<1)+i;
498 double value1 = vColorBits[bitIdxS].get(GRB_DoubleAttr_X);
499 double value2 = vColorBits[bitIdxT].get(GRB_DoubleAttr_X);
502 obj += vColorBits[bitIdxT]-vColorBits[bitIdxS];
503 else if (value1 < value2)
504 obj += vColorBits[bitIdxS]-vColorBits[bitIdxT];
510template <
typename GraphType>
515 for(uint32_t k = 0, ke = vColorBits.size(); k < ke; k += 2)
518 if (vColorBits[k].get(GRB_DoubleAttr_X) != 0.5 && vColorBits[k+1].get(GRB_DoubleAttr_X) != 0.5)
521 graph_vertex_type v = k>>1;
527 int32_t cycleLength = oddCycle.size();
528 GRBLinExpr constraint1 = 0;
529 GRBLinExpr constraint2 = 0;
533 graph_vertex_type u = *it2;
534 constraint1 += vColorBits[u<<1];
535 constraint2 += vColorBits[(u<<1)+1];
539 optModel.addConstr(constraint1 >= 1, buf);
541 optModel.addConstr(constraint1 <= cycleLength-1, buf);
543 optModel.addConstr(constraint2 >= 1, buf);
545 optModel.addConstr(constraint2 <= cycleLength-1, buf);
551template <
typename GraphType>
557#ifdef DEBUG_LPCOLORING
562 int32_t optStatus = optModel.get(GRB_IntAttr_Status);
563 if (optStatus == GRB_INFEASIBLE)
569 optModel.computeIIS();
573 limboAssertMsg(optStatus != GRB_INFEASIBLE,
"model is infeasible");
578template <
typename GraphType>
581#ifdef DEBUG_LPCOLORING
591 env.set(GRB_IntParam_OutputFlag, 0);
594 env.set(GRB_IntParam_Threads, this->
m_threads);
596 env.set(GRB_IntParam_Method, -1);
598 GRBModel optModel = GRBModel(env);
602#ifndef DEBUG_NOANCHOR
608#ifdef DEBUG_LPCOLORING
616#ifdef DEBUG_NONINTEGERS
631 optModel.setObjective(obj);
639#ifdef DEBUG_LPCOLORING
646#ifdef DEBUG_NONINTEGERS
655#ifdef DEBUG_NONINTEGERS
668#ifdef DEBUG_LPCOLORING
674template <
typename GraphType>
677 for (uint32_t i = 0, ie = this->
m_vColor.size(); i != ie; ++i)
679 GRBVar
const& var1 = vColorBits[i<<1];
680 GRBVar
const& var2 = vColorBits[(i<<1)+1];
681 int8_t b1 = round(var1.get(GRB_DoubleAttr_X));
682 int8_t b2 = round(var2.get(GRB_DoubleAttr_X));
690template <
typename GraphType>
699 bool modifyFlag =
false;
700 for (uint32_t i = 0, ie = vColorBits.size(); i < ie; i += 2)
702 GRBVar
const& var1 = vColorBits[i];
703 GRBVar
const& var2 = vColorBits[i+1];
704 double value1 = var1.get(GRB_DoubleAttr_X);
705 double value2 = var2.get(GRB_DoubleAttr_X);
707 if (!(value1 == 0.5 && value2 == 0.5))
710 GRBColumn column[2] = {
711 optModel.getCol(var1),
712 optModel.getCol(var2)
719 bool mValidColorBits[2][2] = {{
true,
true}, {
true,
true}};
720 if (this->
color_num() == base_type::THREE)
721 mValidColorBits[1][1] =
false;
723 uint32_t invalidCount = 0;
724 bool failFlag =
false;
726 for (uint32_t j = 0; j != 2 && !failFlag; ++j)
727 for (uint32_t k = 0, ke = column[j].size(); k != ke; ++k)
729 GRBConstr constr = column[j].getConstr(k);
733 char sense = constr.get(GRB_CharAttr_Sense);
734 curConstrInfo[0].
set(optModel.getCoeff(constr, var1), sense);
735 curConstrInfo[1].
set(optModel.getCoeff(constr, var2), sense);
738 if (!curConstrInfo[0].same_direction(prevConstrInfo[0]) || !curConstrInfo[1].same_direction(prevConstrInfo[1]))
745 for (int32_t b1 = 0; b1 != 2; ++b1)
746 for (int32_t b2 = 0; b2 != 2; ++b2)
748 if (mValidColorBits[b1][b2])
750 double delta = curConstrInfo[0].
coeff*(b1-value1) + curConstrInfo[1].coeff*(b2-value2);
751 if ((sense ==
'>' && delta < 0.0) || (sense ==
'<' && delta > 0.0))
753 mValidColorBits[b1][b2] =
false;
760 if (invalidCount == 4)
766 prevConstrInfo[0] = curConstrInfo[0];
767 prevConstrInfo[1] = curConstrInfo[1];
773 for (int32_t b1 = 0; b1 != 2; ++b1)
774 for (int32_t b2 = 0; b2 != 2; ++b2)
775 if (mValidColorBits[b1][b2])
777 vColorBits[i].set(GRB_DoubleAttr_UB, b1);
778 vColorBits[i].set(GRB_DoubleAttr_LB, b1);
779 vColorBits[i+1].set(GRB_DoubleAttr_UB, b2);
780 vColorBits[i+1].set(GRB_DoubleAttr_LB, b2);
787 if (!modifyFlag)
break;
797template <
typename GraphType>
805 edge_iterator_type ei, eie;
809 for (boost::tie(ei, eie) = boost::edges(this->
m_graph); ei != eie; ++ei)
818template <
typename GraphType>
821 graph_vertex_type v[2] = {
822 boost::source(e, this->
m_graph),
823 boost::target(e, this->
m_graph)
830 int8_t bestColor[2] = {0, 0};
831 edge_weight_type bestCost = std::numeric_limits<edge_weight_type>::max();
833 for (c[0] = 0; c[0] != this->
color_num(); c[0] += 1)
834 for (c[1] = 0; c[1] != this->
color_num(); c[1] += 1)
836 edge_weight_type curCost = 0;
837 typename boost::graph_traits<graph_type>::adjacency_iterator ui, uie;
838 for (int32_t i = 0; i != 2; ++i)
842 graph_vertex_type cv = v[i], ov = v[!i];
843 for (boost::tie(ui, uie) = boost::adjacent_vertices(cv, this->
m_graph); ui != uie; ++ui)
845 graph_vertex_type u = *ui;
846 if (u != ov && c[i] == this->
m_vColor[u])
848 std::pair<graph_edge_type, bool> eU2cv = boost::edge(cv, u, this->
m_graph);
849#ifdef DEBUG_LPCOLORING
853 curCost += std::max((edge_weight_type)1, boost::get(boost::edge_weight, this->
m_graph, eU2cv.first));
858 curCost += std::max((edge_weight_type)1, boost::get(boost::edge_weight, this->
m_graph, e));
859 if (curCost < bestCost)
866 bool retFlag =
false;
867 if (this->
m_vColor[v[0]] != bestColor[0] || this->
m_vColor[v[1]] != bestColor[1])
869 this->
m_vColor[v[0]] = bestColor[0];
870 this->
m_vColor[v[1]] = bestColor[1];
880template <
typename GraphType>
886#ifdef DEBUG_LPCOLORING
892template <
typename GraphType>
897 for (vector<GRBVar>::const_iterator it = vVariables.begin(), ite = vVariables.end(); it != ite; ++it)
899 double value = it->get(GRB_DoubleAttr_X);
900 if (value != 0.0 && value != 1.0)
910template <
typename GraphType>
913 uint32_t precoloredNum = 0;
917 return precoloredNum;
920template <
typename GraphType>
923 const char* prefix =
"";
924 for (uint32_t i = 0, ie = vColorBits.size(); i < ie; i += 2)
926 printf(
"%sv%u=(%g,%g)", prefix, i>>1, vColorBits[i].get(GRB_DoubleAttr_X), vColorBits[i+1].get(GRB_DoubleAttr_X));
#define limboAssertMsg(condition, args...)
custom assertion with message
#define limboAssert(condition)
custom assertion without message
base class for all graph coloring algorithms
Check string is integer, floating point, number... Convert string to upper/lower cases.
Coloring(graph_type const &g)
virtual int8_t color(graph_vertex_type v) const
graph_type const & m_graph
initial graph
virtual edge_weight_type edge_weight(graph_edge_type const &e) const
int32_t m_threads
control number of threads for ILP solver
virtual bool has_precolored() const
std::vector< int8_t > m_vColor
coloring solutions
virtual edge_weight_type calc_cost(std::vector< int8_t > const &vColor) const
virtual void color_num(ColorNumType cn)
void set_optimize_model(vector< GRBVar > &vColorBits, vector< GRBVar > &vEdgeBits, GRBLinExpr &obj, GRBModel &optModel)
uint32_t lp_iters() const
uint32_t m_lp_iters
record lp iterations
bool refine_color(graph_edge_type const &e)
uint32_t m_constrs_num
record number of constraints
uint32_t check_precolored_num(vector< LPColoring< GraphType >::graph_vertex_type > const &vVertex) const
void adjust_variable_pair_in_objective(vector< GRBVar > const &vColorBits, GRBLinExpr &obj) const
tune objective for each color bit pair of vertex
void rounding_with_binding_analysis(GRBModel &optModel, vector< GRBVar > &vColorBits, vector< GRBVar > &vEdgeBits)
void print_solution(vector< GRBVar > const &vColorBits) const
void add_odd_cycle_constraints(vector< GRBVar > const &vColorBits, GRBModel &optModel)
odd cycle trick from Prof. Baldick
void solve_model(GRBModel &optModel)
solve model
void set_anchor(vector< GRBVar > &vColorBits) const
void non_integer_num(vector< GRBVar > const &vColorBits, vector< GRBVar > const &vEdgeBits, NonIntegerInfo &info) const
bool is_integer(double value) const
void get_odd_cycles(graph_vertex_type const &v, vector< vector< graph_vertex_type > > &vOddCyle)
void adjust_conflict_edge_vertices_in_objective(vector< GRBVar > const &vColorBits, GRBLinExpr &obj) const
tune objective for each color bit pair along conflict edges
void non_integer_num(vector< GRBVar > const &vVariables, uint32_t &nonIntegerNum, uint32_t &halfIntegerNum) const
LPColoring(graph_type const &g)
constructor
uint32_t post_refinement()
greedy final coloring refinement
graph_vertex_type max_degree_vertex() const
boost::dynamic_bitset m_vVertexHandledByOddCycle
members
void apply_solution(vector< GRBVar > const &vColorBits)
void initialize()
create the NoStitchGraph (this->m_graph) from the (m_conflict_graph)
namespace for Limbo.Algorithms.Coloring
namespace for Limbo.algorithms
void write_graph(std::ofstream &out, GraphType const &g, VertexLabelType const &vl, EdgeLabelType const &el)
write graph to graphviz format and convert to pdf. Although Boost.Graph has write_graphviz component,...
std::iterator_traits< Iterator >::value_type max(Iterator first, Iterator last)
get max of an array
bool is_integer(string const &s)
check whether string represents an integer
hasher class for graph_edge_type
information for a variable of a constraint
bool same_direction(ConstrVariableInfo const &rhs) const
ConstrVariableInfo()
constructor
void set(double c, char s)
records the information of non-integer values
uint32_t vertex_non_integer_num
number of vertices with non-integer solutions
uint32_t vertex_half_integer_num
number of vertices with half-integer solutions
NonIntegerInfo()
constructor
uint32_t edge_non_integer_num
number of edges with non-integer solutions
uint32_t edge_half_integer_num
number of edges with half-integer solutions