QUBO++ Library with QUBO Solver APIs
Author: Koji Nakano, License: Non-commercial research and evaluation purposes without any guarantees.
qbpp_tsp.hpp
Go to the documentation of this file.
1 
7 #include <iostream>
8 #include <limits>
9 #include <memory>
10 #include <random>
11 #include <sstream>
12 #include <string>
13 #include <utility>
14 #include <vector>
15 
16 #include "qbpp.hpp"
17 #include "qbpp_misc.hpp"
18 
19 namespace qbpp {
20 
22 namespace tsp {
23 
24 constexpr uint32_t uint32_limit = std::numeric_limits<uint32_t>::max();
25 
30 class TSPMap {
33  const uint32_t grid_size;
35  std::vector<std::pair<int32_t, int32_t>> nodes;
36 
37  public:
41  TSPMap(uint32_t grid_size = 100) : grid_size(grid_size) {};
42 
45  void gen_random_map(uint32_t n);
46 
50  void add_node(uint32_t x, uint32_t y) { nodes.push_back({x, y}); }
51 
57  uint32_t dist(const std::pair<int32_t, int32_t> &p1,
58  const std::pair<int32_t, int32_t> &p2) const {
59  return static_cast<uint32_t>(std::round(
60  std::sqrt((p1.first - p2.first) * (p1.first - p2.first) +
61  (p1.second - p2.second) * (p1.second - p2.second))));
62  }
63 
68  uint32_t dist(uint32_t i, uint32_t j) const {
69  return dist(nodes[i], nodes[j]);
70  }
71 
77  uint32_t min_dist(uint32_t x, uint32_t y) const {
78  uint32_t min_dist = grid_size * 2;
79  for (const auto &[px, py] : nodes) {
80  if (dist({x, y}, {px, py}) < min_dist) min_dist = dist({x, y}, {px, py});
81  }
82  return min_dist;
83  }
84 
87  uint32_t node_count() const { return static_cast<uint32_t>(nodes.size()); }
88 
91  uint32_t get_grid_size() const { return grid_size; }
92 
96  std::pair<int32_t, int32_t> &operator[](uint32_t index) {
97  return nodes[index];
98  }
99 };
100 
105  const bool fix_first;
108 
113  std::tuple<qbpp::Model, bool, qbpp::Vector<qbpp::Vector<qbpp::Var>>>
114  helper_func(const TSPMap &map, bool fix_first);
115 
118  tuple)
119  : qbpp::QuadModel(std::get<0>(tuple)),
120  fix_first(std::get<1>(tuple)),
121  x(std::get<2>(tuple)) {}
122 
123  public:
128  TSPQuadModel(const TSPMap &map, bool fix_first = false)
130 
133  uint32_t node_count() const { return static_cast<uint32_t>(x.size()); }
134 
136  qbpp::Var get_var(uint32_t i, uint32_t j) const { return x[i][j]; }
137 
139  bool get_fix_first() const { return fix_first; }
140 };
141 
143 class TSPSol {
147  const Sol sol;
149  const std::vector<uint32_t> tour;
150 
155  static std::vector<uint32_t> gen_tour(const TSPQuadModel &tsp_quad_model,
156  const Sol &sol);
157 
158  public:
165  sol(sol),
167 
171  uint32_t operator[](uint32_t index) const { return tour[index]; }
172 
174  uint32_t node_count() const { return tsp_quad_model.node_count(); }
175 
177  void print() const {
178  std::cout << sol.get_energy() << " :";
179  for (const auto &i : tour)
180  if (i != uint32_limit)
181  std::cout << " " << i;
182  else
183  std::cout << " -";
184  std::cout << std::endl;
185  }
186 
187  void print_matrix() const {
188  for (uint32_t i = 0; i < tsp_quad_model.node_count(); i++) {
189  for (uint32_t j = 0; j < tsp_quad_model.node_count(); j++) {
190  if (i == 0 && j == 0)
191  std::cout << "1";
192  else if (i == 0 || j == 0)
193  std::cout << "0";
194  else {
195  std::cout << sol.get(tsp_quad_model.get_var(i, j));
196  }
197  }
198  std::cout << std::endl;
199  }
200  }
201 };
202 
209  std::vector<std::tuple<int, int, std::string>> nodes;
211  std::vector<std::tuple<int, int>> edges;
212 
213  public:
215  DrawSimpleGraph() = default;
216 
221  void add_node(int x, int y, const std::string &label = "") {
222  nodes.push_back(std::make_tuple(x, y, label));
223  }
227  void add_node(std::pair<int, int> node, const std::string &label = "") {
228  add_node(node.first, node.second, label);
229  }
230 
235  void add_edge(unsigned int node1, unsigned int node2) {
236  edges.push_back(std::make_pair(node1, node2));
237  }
239  uint32_t node_count() const { return static_cast<uint32_t>(nodes.size()); }
240 
242  uint32_t edge_count() const { return static_cast<uint32_t>(edges.size()); }
243 
248  void draw(std::string filename) {
249  std::ostringstream dot_stream;
250  dot_stream << "graph G {\n"
251  << "node [shape=circle, fixedsize=true, width=3, fontsize=100, "
252  "penwidth=5];\n"
253  << "edge [penwidth=5];\n";
254  int index = 0;
255  for (auto [x, y, s] : nodes) {
256  dot_stream << index << " [label = \"" << index << "\", pos = \"" << x
257  << "," << y << "!\"";
258  if (s != "") dot_stream << " " << s;
259  dot_stream << "];\n";
260  ++index;
261  }
262  for (auto [node1, node2] : edges) {
263  dot_stream << node1 << " -- " << node2 << "\n";
264  }
265  dot_stream << "}\n";
266  std::string command = "neato -T" +
267  filename.substr(filename.rfind('.') + 1) + " -o " +
268  filename;
269 
270  std::unique_ptr<FILE, qbpp::misc::PcloseDeleter> pipe(
271  popen(command.c_str(), "w"));
272 
273  if (!pipe) {
274  throw std::runtime_error(THROW_MESSAGE("popen() failed!"));
275  }
276  fprintf(pipe.get(), "%s", dot_stream.str().c_str());
277  }
278 };
279 
280 //==============================
281 // TSPMap member functions
282 //==============================
283 
284 inline void TSPMap::gen_random_map(uint32_t n) {
285  nodes.reserve(n);
286  uint32_t x, y;
287  for (uint32_t i = 0; i < n; i++) {
288  uint32_t counter = 0;
289  uint32_t max_dist = 1;
290  // Terminate if dist>=max_dist is satisfied 10 times.
291  while (counter < 10) {
294  uint32_t dist = min_dist(x, y);
295  if (dist >= max_dist) {
296  max_dist = dist;
297  counter++;
298  }
299  }
300  add_node(x, y);
301  }
302 }
303 
304 //===============================
305 // TSPQuadModel member functions
306 //===============================
307 
308 inline std::tuple<qbpp::Model, bool, qbpp::Vector<qbpp::Vector<qbpp::Var>>>
309 TSPQuadModel::helper_func(const TSPMap &tsp_map, bool fix_first) {
310  auto node_count = tsp_map.node_count();
311  auto x = qbpp::var("x", node_count, node_count);
312  std::cout << "Generating QUBO expression for permutation." << std::endl;
313  auto permutation_expr = qbpp::sum(
315  std::cout << "Generating QUBO expressions for tour distances." << std::endl;
316 
318  tbb::parallel_for(decltype(node_count)(0), node_count, [&](int i) {
319  uint32_t next_i = (i + 1) % node_count;
320  auto &expr = exprs[i];
321 
322  for (uint32_t j = 0; j < node_count; j++) {
323  for (uint32_t k = 0; k < node_count; k++) {
324  if (j == k) continue;
325  expr += tsp_map.dist(j, k) * x[i][j] * x[next_i][k];
326  }
327  }
328  });
329 
330  auto tsp_expr = qbpp::sum(exprs) + permutation_expr * tsp_map.get_grid_size();
331 
332  if (fix_first) {
333  std::cout << "Fixing the first visiting node." << std::endl;
334  qbpp::MapList fix0 = {{x[0][0], 1}};
335  for (uint32_t i = 1; i < node_count; i++) {
336  fix0.push_back({x[0][i], 0});
337  fix0.push_back({x[i][0], 0});
338  }
339  tsp_expr.replace(fix0);
340  }
341 
342  std::cout << "Simplifying the QUBO expression." << std::endl;
343 
344  tsp_expr.simplify_as_binary();
345 
346  return {tsp_expr, fix_first, x};
347 }
348 
349 //=========================
350 // TSPSol member functions
351 //=========================
352 
353 inline std::vector<uint32_t> TSPSol::gen_tour(
354  const TSPQuadModel &tsp_quad_model, const Sol &sol) {
355  std::vector<uint32_t> tour;
356  for (uint32_t i = 0; i < tsp_quad_model.node_count(); i++) {
357  if (tsp_quad_model.get_fix_first() && i == 0) {
358  tour.push_back(0);
359  continue;
360  }
361  uint32_t count = 0;
362  uint32_t node;
363  for (uint32_t j = (tsp_quad_model.get_fix_first() ? 1 : 0);
364  j < tsp_quad_model.node_count(); j++) {
365  if (sol.get(tsp_quad_model.get_var(i, j)) == 1) {
366  node = j;
367  count++;
368  }
369  }
370  if (count != 1) node = uint32_limit;
371  tour.push_back(node);
372  }
373  return tour;
374 }
375 
376 } // namespace tsp
377 } // namespace qbpp
energy_t get_energy() const
Definition: qbpp.hpp:1545
var_val_t get(vindex_t index) const
Definition: qbpp.hpp:1500
void push_back(const T &t)
Definition: qbpp.hpp:375
size_t size() const
Definition: qbpp.hpp:385
static uint64_t gen()
Definition: qbpp_misc.hpp:45
Class to draw a simple undirected graph.
Definition: qbpp_tsp.hpp:206
void add_node(std::pair< int, int > node, const std::string &label="")
Add a node to the graph.
Definition: qbpp_tsp.hpp:227
DrawSimpleGraph()=default
Default constructor to create an empty graph.
void add_edge(unsigned int node1, unsigned int node2)
Add an edge to the graph.
Definition: qbpp_tsp.hpp:235
std::vector< std::tuple< int, int > > edges
List of edges (node1, node2)
Definition: qbpp_tsp.hpp:211
uint32_t node_count() const
Get the number of nodes in the graph.
Definition: qbpp_tsp.hpp:239
std::vector< std::tuple< int, int, std::string > > nodes
List of nodes with coordinate (x, y)
Definition: qbpp_tsp.hpp:209
void draw(std::string filename)
Draw the graph in a file.
Definition: qbpp_tsp.hpp:248
void add_node(int x, int y, const std::string &label="")
Add a node to the graph.
Definition: qbpp_tsp.hpp:221
uint32_t edge_count() const
Get the number of edges in the graph.
Definition: qbpp_tsp.hpp:242
Class to generates a random map for the TSP with n nodes.
Definition: qbpp_tsp.hpp:30
TSPMap(uint32_t grid_size=100)
Constructor: Creates an empty map.
Definition: qbpp_tsp.hpp:41
uint32_t min_dist(uint32_t x, uint32_t y) const
Compute the minimum distance between a new node and all other nodes.
Definition: qbpp_tsp.hpp:77
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.
Definition: qbpp_tsp.hpp:57
uint32_t dist(uint32_t i, uint32_t j) const
Compute the Euclidean distance between two nodes.
Definition: qbpp_tsp.hpp:68
void add_node(uint32_t x, uint32_t y)
Add a node to the map.
Definition: qbpp_tsp.hpp:50
uint32_t node_count() const
Gets the number of nodes in the map.
Definition: qbpp_tsp.hpp:87
void gen_random_map(uint32_t n)
Generate a random map with n nodes.
Definition: qbpp_tsp.hpp:284
std::vector< std::pair< int32_t, int32_t > > nodes
List of nodes with coordinate (x, y)
Definition: qbpp_tsp.hpp:35
std::pair< int32_t, int32_t > & operator[](uint32_t index)
Get the position of the node at index i.
Definition: qbpp_tsp.hpp:96
const uint32_t grid_size
Size of the grid. grid_size x grid_size coordinates are used for the map.
Definition: qbpp_tsp.hpp:33
uint32_t get_grid_size() const
Gets the size of the grid.
Definition: qbpp_tsp.hpp:91
Class to store the QUBO expression for the Traveling Salesman Problem (TSP).
Definition: qbpp_tsp.hpp:103
TSPQuadModel(const TSPMap &map, bool fix_first=false)
Generate a QUBO expression for the Traveling Salesman Problem (TSP) from a map.
Definition: qbpp_tsp.hpp:128
bool get_fix_first() const
Returns true if the first node is fixed to node 0.
Definition: qbpp_tsp.hpp:139
uint32_t node_count() const
Returns the number of nodes in the TSP.
Definition: qbpp_tsp.hpp:133
const qbpp::Vector< qbpp::Vector< qbpp::Var > > x
Variables for the TSP.
Definition: qbpp_tsp.hpp:107
qbpp::Var get_var(uint32_t i, uint32_t j) const
Get the variable at (i, j).
Definition: qbpp_tsp.hpp:136
TSPQuadModel(std::tuple< qbpp::QuadModel, bool, qbpp::Vector< qbpp::Vector< qbpp::Var >>> tuple)
Definition: qbpp_tsp.hpp:116
const bool fix_first
true if the first node is fixed to node 0.
Definition: qbpp_tsp.hpp:105
std::tuple< qbpp::Model, bool, qbpp::Vector< qbpp::Vector< qbpp::Var > > > helper_func(const TSPMap &map, bool fix_first)
Generate a QUBO expression for the Traveling Salesman Problem (TSP).
Definition: qbpp_tsp.hpp:309
Class to store a Tour of the TSP.
Definition: qbpp_tsp.hpp:143
TSPSol(const TSPQuadModel &tsp_quad_model, const qbpp::Sol &sol)
Generates a solution of the Traveling Salesman Problem (TSP) from a QUBO model and its solution.
Definition: qbpp_tsp.hpp:163
uint32_t node_count() const
Get the number of nodes in the tour.
Definition: qbpp_tsp.hpp:174
const Sol sol
Solution of the QUBO model.
Definition: qbpp_tsp.hpp:147
const TSPQuadModel tsp_quad_model
QUBO expression for the Traveling Salesman Problem (TSP).
Definition: qbpp_tsp.hpp:145
static std::vector< uint32_t > gen_tour(const TSPQuadModel &tsp_quad_model, const Sol &sol)
helper function to generate a tour from the solution.
Definition: qbpp_tsp.hpp:353
uint32_t operator[](uint32_t index) const
Get the node at index in the tour.
Definition: qbpp_tsp.hpp:171
void print() const
Print the tour.
Definition: qbpp_tsp.hpp:177
void print_matrix() const
Definition: qbpp_tsp.hpp:187
const std::vector< uint32_t > tour
A vector of nodes representing the tour.
Definition: qbpp_tsp.hpp:149
constexpr uint32_t uint32_limit
Definition: qbpp_tsp.hpp:24
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
Vector< Vector< Expr > > transpose(const Vector< Vector< T >> &vec)
Definition: qbpp.hpp:3618
Expr sum(const Vector< T > &items)
Definition: qbpp.hpp:3209
Expr expr()
Definition: qbpp.hpp:2318
std::list< std::pair< std::variant< Var, VarInt >, Expr > > MapList
Definition: qbpp.hpp:134
QUBO++, a C++ library for generating expressions for binary and spin variables.
#define THROW_MESSAGE(...)
Definition: qbpp.hpp:86
A miscellaneous library used for sample programs of the QUBO++ library.