QUBO++ Library with QUBO Solver APIs
Author: Koji Nakano, License: Non-commercial research and evaluation purposes without any guarantees.
qbpp_graph_color.hpp
Go to the documentation of this file.
1 
6 #include <boost/polygon/voronoi.hpp>
7 #include <iostream>
8 #include <limits>
9 #include <memory>
10 #include <queue>
11 #include <random>
12 #include <sstream>
13 #include <string>
14 #include <utility>
15 #include <vector>
16 
17 #include "qbpp.hpp"
18 #include "qbpp_misc.hpp"
19 
20 namespace qbpp {
21 
23 namespace graph_color {
24 
25 class GraphColorMap;
27 
34  const uint32_t grid_size_;
35 
38  std::vector<std::pair<int32_t, int32_t>> nodes_;
39 
44  std::vector<std::pair<uint32_t, uint32_t>> edges_;
45 
48  // @note -1 means that the color is not determined.
50 
53  std::vector<uint32_t> color_hist_;
54 
58  uint32_t failure_ = 0;
59 
63  void add_node(uint32_t x, uint32_t y) { nodes_.push_back({x, y}); }
64 
70  uint32_t dist(const std::pair<int32_t, int32_t> &p1,
71  const std::pair<int32_t, int32_t> &p2) const {
72  return static_cast<uint32_t>(std::round(
73  std::sqrt((p1.first - p2.first) * (p1.first - p2.first) +
74  (p1.second - p2.second) * (p1.second - p2.second))));
75  }
76 
81  uint32_t dist(size_t i, size_t j) const { return dist(nodes_[i], nodes_[j]); }
82 
88  uint32_t min_dist(uint32_t x, uint32_t y) const {
89  uint32_t min_dist = grid_size_ * 2;
90  for (const auto &[px, py] : nodes_) {
91  if (dist({x, y}, {px, py}) < min_dist) min_dist = dist({x, y}, {px, py});
92  }
93  return min_dist;
94  }
95 
99  std::pair<int32_t, int32_t> &operator[](uint32_t index) {
100  return nodes_[index];
101  }
102 
103  public:
107  GraphColorMap(uint32_t grid_size = 100) : grid_size_(grid_size) {};
108 
112  void gen_random_map(uint32_t n, bool is_circle = false);
113 
116  void gen_proximity_edges(uint32_t proximity);
117 
119  void gen_delaunay_edges();
120 
126  void set_color_histogram(const GraphColorQuadModel &model,
127  const qbpp::Sol &sol);
128 
131  uint32_t node_count() const { return static_cast<uint32_t>(nodes_.size()); }
132 
135  uint32_t get_grid_size() const { return grid_size_; }
136 
137  const std::vector<std::pair<uint32_t, uint32_t>> get_edges() const {
138  return edges_;
139  }
140 
145  void draw(const std::string &filename);
146 
149  void print() {
150  for (size_t i = 0; i < color_hist_.size(); i++) {
151  std::cout << "Color " << i << " : " << color_hist_[i] << std::endl;
152  }
153  std::cout << "Failure : " << failure_ << std::endl;
154  }
155 };
156 
164 
167  std::pair<qbpp::Model, qbpp::Vector<qbpp::Vector<qbpp::Var>>> helper_func(
168  const GraphColorMap &map, uint32_t color_count);
169 
176  : qbpp::QuadModel(pair.first), x_(pair.second) {}
177 
178  public:
182  GraphColorQuadModel(const GraphColorMap &map, uint32_t color_count)
183  : GraphColorQuadModel(helper_func(map, color_count)) {}
184 
187  uint32_t node_count() const { return static_cast<uint32_t>(x_.size()); }
188 
191  const qbpp::Vector<qbpp::Vector<qbpp::Var>> &get_x() const { return x_; }
192 };
193 
194 //==============================
195 // GraphColorMap member functions
196 //==============================
197 
198 inline void GraphColorMap::gen_random_map(uint32_t n, bool is_circle) {
199  nodes_.reserve(n);
200  uint32_t x, y;
201  for (uint32_t i = 0; i < n; i++) {
202  uint32_t counter = 0;
203  uint32_t max_dist = 1;
204  // Terminate if dist>=max_dist is satisfied 10 times.
205  while (counter < 10) {
206  if (is_circle) {
207  do {
210  } while ((x - grid_size_ / 2) * (x - grid_size_ / 2) +
211  (y - grid_size_ / 2) * (y - grid_size_ / 2) >
212  grid_size_ * grid_size_ / 4);
213  } else {
216  }
217  uint32_t dist = min_dist(x, y);
218  if (dist >= max_dist) {
219  max_dist = dist;
220  counter++;
221  }
222  }
223  add_node(x, y);
224  }
225 }
226 
227 inline void GraphColorMap::gen_proximity_edges(uint32_t proximity) {
228  for (size_t i = 0; i < nodes_.size(); i++) {
229  for (size_t j = i + 1; j < nodes_.size(); j++) {
230  if (dist(i, j) < proximity) {
231  edges_.push_back({i, j});
232  }
233  }
234  }
235 }
236 
238  typedef boost::polygon::point_data<int> Point;
239  std::vector<Point> points;
240  for (const auto &[x, y] : nodes_) {
241  points.push_back(Point(x, y));
242  }
243  boost::polygon::voronoi_diagram<double> vd;
244  boost::polygon::construct_voronoi(points.begin(), points.end(), &vd);
245  for (const auto &cell : vd.cells()) {
246  size_t source_index = cell.source_index();
247  const auto *edge = cell.incident_edge();
248  do {
249  size_t twin_source_index = edge->twin()->cell()->source_index();
250  if (source_index < twin_source_index)
251  edges_.push_back({static_cast<uint32_t>(source_index),
252  static_cast<uint32_t>(twin_source_index)});
253  edge = edge->next();
254  } while (edge != cell.incident_edge());
255  }
256 }
257 
259  const qbpp::Sol &sol) {
260  color_ = qbpp::onehot_to_int(sol.get(model.get_x()));
261  for (auto c : color_) {
262  if (c < 0) {
263  ++failure_;
264  } else {
265  if (c >= static_cast<decltype(c)>(color_hist_.size())) {
266  color_hist_.resize(static_cast<size_t>(c) + 1, 0);
267  }
268  color_hist_[static_cast<size_t>(c)]++;
269  }
270  }
271 }
272 
273 inline void GraphColorMap::draw(const std::string &filename) {
274  const std::vector<std::string> color_palette = {
275  "#FFFFFF", // 白 エラーを意味.
276  "#FF0000", // 赤
277  "#00FF00", // 緑
278  "#FFFF00", // 黄色
279  "#00FFFF", // シアン
280  "#FF00FF", // マゼンタ
281  "#FFA500", // オレンジ
282  "#800080", // 紫
283  "#A52A2A", // 茶色
284  "#87CEEB", // ライトブルー
285  "#FFD700", // ゴールド
286  "#808080", // グレー
287  "#FF1493", // ディープピンク
288  "#00CED1", // ダークターコイズ
289  "#ADFF2F", // イエローグリーン
290  "#ADD8E6", // ライトスカイブルー
291  "#008000", // ダークグリーン
292  "#F0E68C", // カーキ
293  "#7FFF00", // チャートリューズ
294  "#40E0D0", // ターコイズ
295  "#DDA0DD", // プラム
296  "#FF4500", // オレンジレッド
297  "#DA70D6", // オーキッド
298  "#F08080", // ライトコーラル
299  "#87CEFA", // スカイブルー(もう一つの明るい青)
300  "#FF6347", // トマト
301  "#FFE4B5", // モカ
302  "#BA55D3", // ミディアムオーキッド
303  "#3CB371", // ミディアムシーグリーン
304  "#4682B4", // スチールブルー
305  "#B0E0E6", // パウダーブルー
306  "#7B68EE" // ミディアムスレートブルー
307  };
308 
309  std::ostringstream dot_stream;
310  dot_stream << "graph G {\n"
311  << "node [shape=circle, fixedsize=true, width=3, fontsize=100, "
312  "penwidth=8];\n"
313  << "edge [penwidth=8];\n";
314 
315  for (size_t i = 0; i < nodes_.size(); ++i) {
316  dot_stream << i << " [label=\"" << i << "\", pos=\"" << nodes_[i].first
317  << "," << nodes_[i].second << "!\"" << ", fillcolor=\"";
318  if (static_cast<size_t>(color_[i] + 1) < color_palette.size()) {
319  dot_stream << color_palette[static_cast<size_t>(color_[i]) + 1];
320  } else {
321  dot_stream << color_palette[0];
322  }
323  dot_stream << "\", style=filled];\n";
324  }
325 
326  for (const auto &[node1, node2] : edges_) {
327  if (color_[node1] == color_[node2] || color_[node1] < 0 ||
328  color_[node2] < 0) {
329  dot_stream << node1 << " -- " << node2
330  << " [style=dashed,penwidth=16,color=\"red\"];\n";
331  } else {
332  dot_stream << node1 << " -- " << node2 << ";\n";
333  }
334  }
335 
336  dot_stream << "}\n";
337 
338  std::string command =
339  "neato -T" + filename.substr(filename.rfind('.') + 1) + " -o " + filename;
340 
341  std::unique_ptr<FILE, qbpp::misc::PcloseDeleter> pipe(
342  popen(command.c_str(), "w"));
343 
344  if (!pipe) {
345  throw std::runtime_error("popen() failed!");
346  }
347 
348  std::string dot_content = dot_stream.str();
349  fwrite(dot_content.c_str(), sizeof(char), dot_content.size(), pipe.get());
350 }
351 
352 //======================================
353 // GraphColorQuadModel member functions
354 //======================================
355 
356 inline std::pair<qbpp::Model, qbpp::Vector<qbpp::Vector<qbpp::Var>>>
358  uint32_t color_count) {
359  auto x = qbpp::var("x", graph_map.node_count(), color_count);
360 
361  auto f = qbpp::sum(qbpp::vector_sum(x) == 1);
362 
363  for (auto [i, j] : graph_map.get_edges()) {
364  f += qbpp::sum(x[i] * x[j]);
365  }
366  return {simplify_as_binary(f), x};
367 }
368 
369 } // namespace graph_color
370 } // namespace qbpp
var_val_t get(vindex_t index) const
Definition: qbpp.hpp:1500
size_t size() const
Definition: qbpp.hpp:385
Class to store a graph with node coloring and related information.
uint32_t get_grid_size() const
Gets the size of the grid.
uint32_t min_dist(uint32_t x, uint32_t y) const
Compute the minimum distance between a new node and all other nodes.
void gen_proximity_edges(uint32_t proximity)
Create an edges between nodes that are close to each other.
qbpp::Vector< int32_t > color_
List of colors of the nodes.
void gen_delaunay_edges()
Create edges between nodes using the Delaunay triangulation.
void draw(const std::string &filename)
Draw the graph in a file.
std::vector< std::pair< uint32_t, uint32_t > > edges_
List of edges with the distance between the nodes.
const uint32_t grid_size_
Size of the grid. grid_size x grid_size coordinates are used for the map.
const std::vector< std::pair< uint32_t, uint32_t > > get_edges() const
uint32_t dist(size_t i, size_t j) const
Compute the Euclidean distance between two nodes.
uint32_t dist(const std::pair< int32_t, int32_t > &p1, const std::pair< int32_t, int32_t > &p2) const
Compute the Euclidean distance between two nodes.
GraphColorMap(uint32_t grid_size=100)
Constructor to Create an empty map.
std::vector< uint32_t > color_hist_
Histogram of the colors.
uint32_t failure_
Number of failure nodes.
void gen_random_map(uint32_t n, bool is_circle=false)
Generate a random map with n nodes.
void print()
Displays the histogram of the colors.
std::vector< std::pair< int32_t, int32_t > > nodes_
List of nodes with coordinate (x, y)
void set_color_histogram(const GraphColorQuadModel &model, const qbpp::Sol &sol)
Set the color histogram of the nodes.
std::pair< int32_t, int32_t > & operator[](uint32_t index)
Get the position of the node at index i.
void add_node(uint32_t x, uint32_t y)
Add a node to the map.
uint32_t node_count() const
Gets the number of nodes in the map.
Class to store the QUBO expression with variables for the Graph Coloring Problem.
std::pair< qbpp::Model, qbpp::Vector< qbpp::Vector< qbpp::Var > > > helper_func(const GraphColorMap &map, uint32_t color_count)
Helper function to generate the QUBO expression for the GraphColorMap object and the number of colors...
uint32_t node_count() const
Returns the number of nodes in the TSP.
GraphColorQuadModel(const GraphColorMap &map, uint32_t color_count)
Generate a QUBO expression for the Graph Coloring Problem.
const qbpp::Vector< qbpp::Vector< qbpp::Var > > & get_x() const
Returns the reference of the variables for the Graph Coloring Problem.
const qbpp::Vector< qbpp::Vector< qbpp::Var > > x_
Variables for the Graph Coloring Problem.
GraphColorQuadModel(std::pair< qbpp::QuadModel, qbpp::Vector< qbpp::Vector< qbpp::Var >>> pair)
Delegated constructor for the GraphColorQuadModel.
static uint64_t gen()
Definition: qbpp_misc.hpp:45
Generates a QUBO Expression for the Graph Coloring Problem using QUBO++ library.
Definition: qbpp.hpp:53
Expr vector_sum(const T &items[[maybe_unused]])
Definition: qbpp.hpp:3282
Var var(const std::string &var_str)
Definition: qbpp.hpp:2172
Expr sum(const Vector< T > &items)
Definition: qbpp.hpp:3209
Expr simplify_as_binary(const Expr &expr)
Definition: qbpp.hpp:2759
int32_t onehot_to_int(const Vector< var_val_t > &vec)
Definition: qbpp.hpp:3627
QUBO++, a C++ library for generating expressions for binary and spin variables.
A miscellaneous library used for sample programs of the QUBO++ library.