openjij
Framework for the Ising model and QUBO.
Loading...
Searching...
No Matches
min_polynomial.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4#include <utility>
5#include <cmath>
6#include <algorithm>
7
8namespace openjij {
9namespace utility {
10
11const double ZERO_TOL = 1e-13;
12
13template <typename RandomNumberEngine>
14std::pair<std::int64_t, double>
16 const double a,
17 const double b,
18 const std::int64_t l,
19 const std::int64_t u,
20 const std::int64_t x,
21 RandomNumberEngine &random_number_engine
22) {
23 if ((std::abs(a) < ZERO_TOL) && (std::abs(b) < ZERO_TOL)) {
24 return {x + std::uniform_int_distribution<std::int64_t>(l, u)(random_number_engine), 0.0};
25 }
26
27 if (a > 0) {
28 const auto clamped_center = std::clamp(-b / (2.0 * a), static_cast<double>(l), static_cast<double>(u));
29 const auto dx = static_cast<std::int64_t>(std::round(clamped_center));
30 const double energy_diff = a * dx * dx + b * dx;
31 return {x + dx, energy_diff};
32 } else {
33 const double el = a * l * l + b * l;
34 const double eu = a * u * u + b * u;
35 if (el <= eu) {
36 return {x + l, el};
37 } else {
38 return {x + u, eu};
39 }
40 }
41}
42
43template <typename RandomNumberEngine>
44std::pair<std::int64_t, double>
46 const double a,
47 const double b,
48 const double c,
49 const std::int64_t l,
50 const std::int64_t u,
51 const std::int64_t x,
52 RandomNumberEngine &random_number_engine
53) {
54
55 if (std::abs(a) >= ZERO_TOL) {
56 const double val_l = a * l * l * l + b * l * l + c * l;
57 const double val_u = a * u * u * u + b * u * u + c * u;
58
59 std::int64_t best_dx;
60 double min_val;
61
62 if (val_l <= val_u) {
63 best_dx = l;
64 min_val = val_l;
65 } else {
66 best_dx = u;
67 min_val = val_u;
68 }
69
70 const double delta = b * b - 3 * a * c;
71 if (delta >= 0) {
72 const double sqrt_delta = std::sqrt(delta);
73 const double r1 = (-b + sqrt_delta) / (3 * a);
74 const double r2 = (-b - sqrt_delta) / (3 * a);
75
76 const double local_min_root = (a > 0) ? std::max(r1, r2) : std::min(r1, r2);
77
78 if (l < local_min_root && local_min_root < u) {
79 const auto cand1 = static_cast<std::int64_t>(std::floor(local_min_root));
80 const double val1 = a * cand1 * cand1 * cand1 + b * cand1 * cand1 + c * cand1;
81 if (val1 < min_val) {
82 min_val = val1;
83 best_dx = cand1;
84 }
85
86 const auto cand2 = static_cast<std::int64_t>(std::ceil(local_min_root));
87 if (cand2 <= u) {
88 const double val2 = a * cand2 * cand2 * cand2 + b * cand2 * cand2 + c * cand2;
89 if (val2 < min_val) {
90 min_val = val2;
91 best_dx = cand2;
92 }
93 }
94 }
95 }
96 return {x + best_dx, min_val};
97 } else {
98 return FindMinimumIntegerQuadratic(b, c, l, u, x, random_number_engine);
99 }
100}
101
102template <typename RandomNumberEngine>
103std::pair<std::int64_t, double>
105 const double a,
106 const double b,
107 const double c,
108 const double d,
109 const std::int64_t l,
110 const std::int64_t u,
111 const std::int64_t x,
112 RandomNumberEngine &random_number_engine
113) {
114
115 if (std::abs(a) >= ZERO_TOL) {
116 const auto f = [&](double dx) {
117 return a * dx * dx * dx * dx + b * dx * dx * dx + c * dx * dx + d * dx;
118 };
119
120 const double val_l = f(static_cast<double>(l));
121 const double val_u = f(static_cast<double>(u));
122 const double m_pi = 3.14159265358979323846;
123
124 std::int64_t best_dx;
125 double min_val;
126
127 if (val_l <= val_u) {
128 best_dx = l;
129 min_val = val_l;
130 } else {
131 best_dx = u;
132 min_val = val_u;
133 }
134
135 const double A = 4.0 * a;
136 const double B = 3.0 * b;
137 const double C = 2.0 * c;
138 const double D = d;
139 const double p = (3.0 * A * C - B * B) / (3.0 * A * A);
140 const double q = (2.0 * B * B * B - 9.0 * A * B * C + 27.0 * A * A * D) / (27.0 * A * A * A);
141
142 const double delta = std::pow(q / 2.0, 2) + std::pow(p / 3.0, 3);
143
144 const auto check_and_update =
145 [&](double r, std::int64_t current_best_dx, double current_min_val)
146 -> std::pair<std::int64_t, double> {
147 const double f_double_prime = 12.0 * a * r * r + 6.0 * b * r + 2.0 * c;
148 if (f_double_prime > 0 && l < r && r < u) {
149 const double floor_r = std::floor(r);
150 const double v1 = f(floor_r);
151 if (v1 < current_min_val) {
152 current_min_val = v1;
153 current_best_dx = static_cast<std::int64_t>(floor_r);
154 }
155
156 const double ceil_r = std::ceil(r);
157 if (static_cast<std::int64_t>(ceil_r) <= u) {
158 const double v2 = f(ceil_r);
159 if (v2 < current_min_val) {
160 current_min_val = v2;
161 current_best_dx = static_cast<std::int64_t>(ceil_r);
162 }
163 }
164 }
165 return {current_best_dx, current_min_val};
166 };
167
168 if (delta >= 0) {
169 const double sqrt_delta = std::sqrt(delta);
170 const double u_cbrt = std::cbrt(-q / 2.0 + sqrt_delta);
171 const double v_cbrt = std::cbrt(-q / 2.0 - sqrt_delta);
172 const double r1 = u_cbrt + v_cbrt - B / (3.0 * A);
173 const auto result = check_and_update(r1, best_dx, min_val);
174 best_dx = result.first;
175 min_val = result.second;
176 } else {
177 const double r_term = std::sqrt(-std::pow(p, 3) / 27.0);
178 const double theta = std::acos(-q / (2.0 * r_term));
179
180 const double common_term = 2.0 * std::cbrt(r_term);
181 const double shift = B / (3.0 * A);
182
183 const double r1 = common_term * std::cos(theta / 3.0) - shift;
184 auto result1 = check_and_update(r1, best_dx, min_val);
185 best_dx = result1.first;
186 min_val = result1.second;
187
188 const double r2 = common_term * std::cos((theta + 2.0 * m_pi) / 3.0) - shift;
189 auto result2 = check_and_update(r2, best_dx, min_val);
190 best_dx = result2.first;
191 min_val = result2.second;
192
193 const double r3 = common_term * std::cos((theta + 4.0 * m_pi) / 3.0) - shift;
194 auto result3 = check_and_update(r3, best_dx, min_val);
195 best_dx = result3.first;
196 min_val = result3.second;
197 }
198 return {x + best_dx, min_val};
199 } else {
200 return FindMinimumIntegerCubic(b, c, d, l, u, x, random_number_engine);
201 }
202}
203
204}
205}
const double ZERO_TOL
Definition min_polynomial.hpp:11
std::pair< std::int64_t, double > FindMinimumIntegerQuartic(const double a, const double b, const double c, const double d, const std::int64_t l, const std::int64_t u, const std::int64_t x, RandomNumberEngine &random_number_engine)
Definition min_polynomial.hpp:104
std::pair< std::int64_t, double > FindMinimumIntegerQuadratic(const double a, const double b, const std::int64_t l, const std::int64_t u, const std::int64_t x, RandomNumberEngine &random_number_engine)
Definition min_polynomial.hpp:15
std::pair< std::int64_t, double > FindMinimumIntegerCubic(const double a, const double b, const double c, const std::int64_t l, const std::int64_t u, const std::int64_t x, RandomNumberEngine &random_number_engine)
Definition min_polynomial.hpp:45
Definition algorithm.hpp:24