19 #include <boost/multiprecision/cpp_int.hpp>
20 #include <boost/multiprecision/miller_rabin.hpp>
21 #include <boost/program_options.hpp>
35 namespace factorization {
41 if (num == 0)
return "0";
42 std::string binary =
"";
44 binary = (num % 2 == 0 ?
"0" :
"1") + binary;
58 for (
int i =
var.
size() - 1; i >= 1; --i) {
59 result = (result << 1) + sol.
get(
var[i]);
62 result = (result << 1) + 1;
64 result = (result << 1) + sol.
get(
var[0]);
81 return boost::multiprecision::miller_rabin_test(
93 (1 << (size - 1)) | 1;
114 std::optional<int64_t>
bound = std::nullopt;
159 if (
bound.has_value()) {
160 return std::to_string(
bound.value());
173 const std::string &solver)
override {
174 std::lock_guard<std::mutex> lock(
mtx);
176 if (tts.has_value()) {
177 std::cerr << std::left << std::setw(4) <<
get_solver() <<
" "
178 << std::fixed << std::setprecision(3) << tts.value()
212 std::shared_ptr<SolHolder> sol_holder_ptr)
216 if (event ==
"init") {
219 }
else if (event ==
"new") {
223 if (hint.has_value())
set_hint(hint.value());
243 std::shared_ptr<SolHolder> sol_holder_ptr)
250 if (where == GRB_CB_MIPSOL) {
254 if (where == GRB_CB_MIP) {
259 if (hint.has_value()) {
266 if (where == GRB_CB_MIPNODE) {
271 if (hint.has_value()) {
286 namespace po = boost::program_options;
295 int main(
int argc,
char *argv[]) {
297 po::options_description desc(
298 "Factorization/Multiplication z = x * y using QUBO solvers");
299 desc.add_options()(
"help,h",
"produce help message")
300 (
"multiplication,m",
"solve multiplication problem (default: factorization)")
301 (
"x,x", po::value<uint32_t>(),
"set value of x")
302 (
"y,y", po::value<uint32_t>(),
"set value of y")
303 (
"random,r", po::value<uint32_t>(),
"set bit size of random prime numbers for x and y (default: 32)")
304 (
"time,t", po::value<uint32_t>(),
"set time limit in seconds")
305 (
"fix,f",
"fix the LSBs of x, y, and z")
306 (
"seed,s", po::value<uint32_t>(),
"set random seed")
307 (
"abs2,a",
"use ABS2 GPU QUBO solver")
308 (
"gurobi,g",
"use Gurobi optimizer")
309 (
"easy,e",
"use QUBO++ Easy solver");
312 po::variables_map vm;
314 po::store(po::parse_command_line(argc, argv, desc), vm);
315 }
catch (
const std::exception &e) {
316 std::cout <<
"Wrong arguments. Please use -h/--help option to see the "
322 if (vm.count(
"help")) {
323 std::cout << desc << std::endl;
328 if (vm.count(
"seed")) {
332 bool fix_lsb = vm.count(
"fix");
333 bool use_abs2 = vm.count(
"abs2");
334 bool use_grb = vm.count(
"gurobi");
335 bool use_easy = vm.count(
"easy");
336 if (!use_abs2 && !use_grb && !use_easy) {
344 if (vm.count(
"time")) {
345 time_limit = vm[
"time"].as<uint32_t>();
351 bool factorization_mode =
true;
352 if (vm.count(
"multiplication")) factorization_mode =
false;
355 uint64_t X = 0, Y = 0;
356 if (vm.count(
"x") && vm.count(
"y")) {
357 X = vm[
"x"].as<uint32_t>();
358 Y = vm[
"y"].as<uint32_t>();
360 std::cerr <<
"x must be a prime number." << std::endl;
364 std::cerr <<
"y must be a prime number." << std::endl;
369 if (vm.count(
"random")) size = vm[
"random"].as<uint32_t>();
379 uint32_t Xsize = 32 - __builtin_clz(X);
380 uint32_t Ysize = 32 - __builtin_clz(Y);
381 uint32_t Zsize = Xsize + Ysize;
394 for (uint32_t i = 0; i < Xsize; ++i) {
395 x_var_map.push_back({var_x[i], (X >> i) & 1});
397 for (uint32_t i = 0; i < Ysize; ++i) {
398 y_var_map.push_back({var_y[i], (Y >> i) & 1});
401 for (uint32_t i = 0; i < Zsize; ++i) {
402 z_var_map.push_back({var_z[i], (Z >> i) & 1});
405 opt_sol.insert(opt_sol.end(), x_var_map.begin(), x_var_map.end());
406 opt_sol.insert(opt_sol.end(), y_var_map.begin(), y_var_map.end());
407 opt_sol.insert(opt_sol.end(), z_var_map.begin(), z_var_map.end());
414 if (factorization_mode) {
422 expr.
replace({{var_x[0], 1}, {var_y[0], 1}, {var_z[0], 1}});
431 std::shared_ptr<SolHolder> sol_holder_ptr;
432 if (factorization_mode) {
434 std::make_shared<SolHolder>(quad_model, fix_lsb, var_x, var_y);
436 sol_holder_ptr = std::make_shared<SolHolder>(quad_model, fix_lsb, var_z);
438 std::cout <<
"QUBO : Variables = " << quad_model.var_count()
439 <<
" Linear terms = " << quad_model.term_count(1)
440 <<
" Quad terms = " << quad_model.term_count(2) << std::endl;
445 std::thread easy_thread;
446 std::thread abs2_thread;
447 std::thread grb_thread;
449 std::shared_ptr<qbpp::easy_solver::EasySolver> easy_solver_ptr;
452 easy_solver_ptr = std::make_shared<qbpp::easy_solver::EasySolver>(
453 quad_model, sol_holder_ptr);
454 easy_solver_ptr->set_time_limit(time_limit);
455 easy_solver_ptr->set_target_energy(0);
456 easy_thread = std::thread([&easy_solver_ptr, &sol_holder_ptr]() {
457 auto sol = easy_solver_ptr->search();
458 sol_holder_ptr->set_if_better(sol,
"EASY");
462 std::shared_ptr<qbpp_abs2::Solver> abs2_solver_ptr;
463 std::shared_ptr<qbpp_abs2::QuadModel> abs2_quad_model_ptr;
464 std::shared_ptr<qbpp_abs2::Param> abs2_param_ptr;
465 std::shared_ptr<ABS2Callback> abs2_callback_ptr;
469 abs2_solver_ptr = std::make_shared<qbpp_abs2::Solver>();
472 abs2_quad_model_ptr = std::make_shared<qbpp_abs2::QuadModel>(quad_model);
475 std::make_shared<ABS2Callback>(*abs2_quad_model_ptr, sol_holder_ptr);
478 abs2_param_ptr = std::make_shared<qbpp_abs2::Param>();
480 abs2_param_ptr->set_time_limit(time_limit);
482 abs2_param_ptr->set_target_energy(0);
484 abs2_param_ptr->set(*abs2_callback_ptr);
485 abs2_thread = std::thread([&abs2_solver_ptr, &abs2_quad_model_ptr,
486 &abs2_param_ptr, &sol_holder_ptr]() {
487 auto sol = (*abs2_solver_ptr)(*abs2_quad_model_ptr, *abs2_param_ptr);
488 sol_holder_ptr->set_if_better(sol,
"ABS2");
492 std::shared_ptr<qbpp_grb::QuadModel> grb_quad_model_ptr;
493 std::shared_ptr<GRB_Callback> grb_callback_ptr;
496 grb_quad_model_ptr = std::make_shared<qbpp_grb::QuadModel>(quad_model);
498 grb_quad_model_ptr->set_time_limit(time_limit);
501 std::make_shared<GRB_Callback>(*grb_quad_model_ptr, sol_holder_ptr);
503 grb_callback_ptr->set_target_energy(0);
505 grb_quad_model_ptr->set(*grb_callback_ptr);
506 grb_thread = std::thread([&grb_quad_model_ptr, &sol_holder_ptr]() {
507 auto sol = grb_quad_model_ptr->optimize();
508 sol_holder_ptr->set_if_better(sol,
"GRB");
512 if (use_easy) easy_thread.join();
513 if (use_abs2) abs2_thread.join();
514 if (use_grb) grb_thread.join();
void set(const std::string &operation)
Set the operation to the ABS2 Callback.
Callback()
Constructor for creating a callback object.
Expr & simplify_as_binary()
Expr & replace(const MapList &map_list)
vindex_t var_count() const
virtual std::optional< double > set_if_better(const qbpp::Sol &new_sol, const std::string &solver="")
std::string get_solver() const
energy_t get_energy() const
var_val_t get(vindex_t index) const
Class to define ABS2 callback function for factorization.
ABS2Callback(const qbpp_abs2::QuadModel &quad_model, std::shared_ptr< SolHolder > sol_holder_ptr)
Construct a new ABS2Callback object for factorization.
const std::shared_ptr< SolHolder > sol_holder_ptr_
The solution holder.
void callback(const std::string &event) override
The default callback function for ABS2 QUBO solver.
Class to define Gurobi callback function for factorization.
void callback() override
callback function for Gurobi optimizer.
std::shared_ptr< SolHolder > sol_holder_ptr_
The solution holder for Gurobi.
GRB_Callback(qbpp_grb::QuadModel &quad_model, std::shared_ptr< SolHolder > sol_holder_ptr)
Target energy to stop the Gurobi optimizer. std::optional<qbpp::energy_t> target_energy = std::nullop...
Solution holder to store the best solution of factorization.
std::string get_bound_str() const
Gets the bound value of the best solution as a string.
const qbpp::Vector< qbpp::Var > & var_x
The vector of Var.
std::optional< double > set_if_better(const qbpp::Sol &new_sol, const std::string &solver) override
Sets new_sol as the best solution if it is better than the current best solution.
SolHolder(const qbpp::QuadModel &quad_model, bool fix_lsb, const qbpp::Vector< qbpp::Var > &var_x, const qbpp::Vector< qbpp::Var > &var_y)
Constructor with a quad_model.
std::mutex mtx
Mutex for thread safety in print function.
const bool factorization_mode
True if factorization, false if multiplication.
const qbpp::Vector< qbpp::Var > & var_z
The vector of Var.
std::optional< int64_t > bound
The bound of the best solution found by Gurobi.
const qbpp::Vector< qbpp::Var > & var_y
The vector of Var.
std::optional< int64_t > get_bound() const
Gets the bound value of the best solution.
void set_bound(int64_t bound)
Sets the bound value of the best solution.
SolHolder(const SolHolder &sol_holder)=default
SolHolder(const qbpp::QuadModel &quad_model, bool fix_lsb, const qbpp::Vector< qbpp::Var > &var_z)
Constructor with a quad_model.
const bool fix_lsb
True if the MSBs and LSBs of x, y, and z are fixed.
static void set_seed(uint32_t seed=1)
A class for defining the ABS2 callback function.
const QuadModel quad_model
QuadModel object created by QUBO++ library.
A class for storing both the qbpp::QuadModel and abs2::Model.
Class to manage a callback function called by Gurobi Optimizer.
void abort_if_target_energy(qbpp::energy_t energy)
Abort the optimization process if the target energy is achieved.
const QuadModel quad_model
QUBO model.
double getDoubleInfoPublic(int what)
Calls GetDoubleInfo() of GRBCallback.
Sol get_sol()
Get the solution obtained by Gurobi Optimizer.
Callback(const QuadModel &quad_model)
Constructor: a new Callback object.
Class to store a QUBO model using Gurobi Optimizer through QUBO++ library.
GRBVar get_grb_var(int index) const
Get the Gurobi variable from the index.
Class to store a solution of a QUBO model using Gurobi Optimizer.
int main(int argc, char *argv[])
Solves the factorization problem using ABS2 QUBO Solver and Gurobi optimizer from QUBO++ library.
Sol get_sol() const
Get the solution from the ABS2 solver.
void set_hint(const Sol &hint)
Provide a hint solution to the ABS2 solver.
Namespace for factorization using QUBO++ library.
Expr multiplier(const qbpp::Vector< T > &x, const qbpp::Vector< U > &y, const qbpp::Vector< Var > &z, MapList &opt_sol)
Function to generate QUBO expression for multiplier.
uint32_t rand_prime(int size)
Generates a random prime number of the specified size.
bool is_prime(uint32_t num)
uint64_t as_uint64(const qbpp::Sol &sol, const qbpp::Vector< qbpp::Var > &var, bool fix_lsb)
Converts a vector of Var in a solution to a 64-bit unsigned integer.
std::string toBinaryString(uint64_t num)
Converts a number to a binary string.
Namespace to use ABS2 QUBO solver from QUBO++ library.
Namespace to use Gurobi optimizer from QUBO++ library.
Generates a QUBO Expression for the Graph Coloring Problem using QUBO++ library.
Var var(const std::string &var_str)
boost::multiprecision::uint128_t uint128_t
std::list< std::pair< std::variant< Var, VarInt >, Expr > > MapList
QUBO++, a C++ library for generating expressions for binary and spin variables.
QUBO++ interface to call ABS2 GPU QUBO solver.
Easy QUBO Solver for solving QUBO problems.
QUBO++ interface to call Gurobi Optimizer.
A miscellaneous library used for sample programs of the QUBO++ library.
Generates QUBO expression for binary multipliers using QUBO++ library.