openjij
Framework for the Ising model and QUBO.
Loading...
Searching...
No Matches
integer_quadratic_sa_system.hpp
Go to the documentation of this file.
1// Copyright 2023 Jij Inc.
2
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6
7// http://www.apache.org/licenses/LICENSE-2.0
8
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#pragma once
16
17#include "../utility/variable.hpp"
18#include "./sa_system.hpp"
19#include <cstdint>
20#include <random>
21#include <vector>
22
23namespace openjij {
24namespace system {
25
26template <typename RandType>
27class IntegerSASystem<graph::IntegerQuadraticModel, RandType> {
28
29public:
31 const typename RandType::result_type seed)
32 : model(model), seed(seed), random_number_engine(seed) {
33
34 const std::int64_t num_variables = model.GetNumVariables();
35
36 // Initialize the state with random values
37 this->state_.reserve(num_variables);
38 const auto &bounds = this->model.GetBounds();
39 for (std::int64_t i = 0; i < num_variables; ++i) {
40 auto x = utility::IntegerVariable(bounds[i].first, bounds[i].second);
41 x.SetRandomValue(this->random_number_engine);
42 this->state_.push_back(x);
43 }
44 this->energy_ = this->CalculateEnergy(this->state_);
45
46 // Precompute the coefficients for energy difference when updating a state
47 const auto &squared = this->model.GetSquared();
48 this->quad_coeff_ = squared;
49 this->linear_coeff_.resize(num_variables, 0.0);
50
51 const auto &linear = this->model.GetLinear();
52 const auto &quadratic = this->model.GetQuadratic();
53
54 for (std::int64_t row = 0; row < num_variables; ++row) {
55 double dE = linear[row] + 2.0 * squared[row] * this->state_[row].value;
56 for (const auto &[col, value] : quadratic[row]) {
57 dE += value * this->state_[col].value;
58 }
59 this->linear_coeff_[row] = dE;
60 }
61 }
62
63 double
64 CalculateEnergy(const std::vector<utility::IntegerVariable> &state) const {
65 double energy = this->model.GetConstant();
66 const auto &linear = this->model.GetLinear();
67 const auto &squared = this->model.GetSquared();
68 const auto &quadratic = this->model.GetQuadratic();
69 const std::int64_t num_variables = this->model.GetNumVariables();
70
71 for (std::int64_t i = 0; i < num_variables; ++i) {
72 auto x = state[i].value;
73 energy += linear[i] * x + squared[i] * x * x;
74 for (const auto &[j, value] : quadratic[i]) {
75 auto y = state[j].value;
76 energy += 0.5 * value * x * y;
77 }
78 }
79 return energy;
80 }
81
82 std::int64_t GenerateCandidateValue(std::int64_t index) {
83 return this->state_[index].GenerateCandidateValue(
84 this->random_number_engine);
85 }
86
87 double GetEnergyDifference(std::int64_t index, std::int64_t new_value) const {
88 std::int64_t d = new_value - this->state_[index].value;
89 return this->quad_coeff_[index] * d * d + this->linear_coeff_[index] * d;
90 }
91
92 void SetValue(std::int64_t index, std::int64_t new_value) {
93 if (this->state_[index].value == new_value) {
94 return;
95 }
96
97 this->energy_ += this->GetEnergyDifference(index, new_value);
98 std::int64_t dx = new_value - this->state_[index].value;
99 this->linear_coeff_[index] += 2.0 * this->model.GetSquared()[index] * dx;
100
101 const auto &quadratic = this->model.GetQuadratic();
102 for (const auto &[i, q] : quadratic[index]) {
103 this->linear_coeff_[i] += q * dx;
104 }
105
106 this->state_[index].SetValue(new_value);
107 }
108
109 std::pair<int, double> GetMinEnergyDifference(std::int64_t index) {
110 const double a = this->quad_coeff_[index];
111 const double b = this->linear_coeff_[index];
112 const auto &x = this->state_[index];
113 const std::int64_t dxl = x.lower_bound - x.value;
114 const std::int64_t dxu = x.upper_bound - x.value;
115
116 if (a > 0) {
117 const double center = -b / (2 * a);
118 if (dxu <= center) {
119 return std::make_pair(x.upper_bound,
120 this->GetEnergyDifference(index, x.upper_bound));
121 } else if (dxl < center && center < dxu) {
122 const std::int64_t dx_left =
123 static_cast<std::int64_t>(std::floor(center));
124 const std::int64_t dx_right =
125 static_cast<std::int64_t>(std::ceil(center));
126 if (center - dx_left <= dx_right - center) {
127 return std::make_pair(
128 x.value + dx_left,
129 this->GetEnergyDifference(index, x.value + dx_left));
130 } else {
131 return std::make_pair(
132 x.value + dx_right,
133 this->GetEnergyDifference(index, x.value + dx_right));
134 }
135 } else if (dxl >= center) {
136 return std::make_pair(x.lower_bound,
137 this->GetEnergyDifference(index, x.lower_bound));
138 } else {
139 throw std::runtime_error("Invalid state");
140 }
141 } else if (a == 0) {
142 if (b > 0) {
143 return std::make_pair(x.lower_bound,
144 this->GetEnergyDifference(index, x.lower_bound));
145 } else if (b < 0) {
146 return std::make_pair(x.upper_bound,
147 this->GetEnergyDifference(index, x.upper_bound));
148 } else {
149 const std::int64_t random_value =
150 x.GenerateRandomValue(this->random_number_engine);
151 return std::make_pair(random_value, 0.0);
152 }
153 } else {
154 const double dE_lower = this->GetEnergyDifference(index, x.lower_bound);
155 const double dE_upper = this->GetEnergyDifference(index, x.upper_bound);
156 if (dE_lower <= dE_upper) {
157 return std::make_pair(x.lower_bound, dE_lower);
158 } else {
159 return std::make_pair(x.upper_bound, dE_upper);
160 }
161 }
162 }
163
164 const std::vector<utility::IntegerVariable> &GetState() const {
165 return this->state_;
166 }
167
168 const std::vector<double> &GetLinearCoeff() const {
169 return this->linear_coeff_;
170 }
171
172 const std::vector<double> &GetQuadCoeff() const { return this->quad_coeff_; }
173
174 double GetEnergy() const { return this->energy_; }
175
176 bool IsLinearCoeff(std::int64_t index) const {
177 return this->model.GetOnlyBilinearIndexSet().count(index) > 0;
178 }
179
180 bool CanOptMove(std::int64_t index) const { return true; }
181
182 double GetLinearCoeff(std::int64_t index) const {
183 return this->linear_coeff_[index];
184 }
185
186public:
188 const std::int64_t seed;
190
191private:
192 std::vector<utility::IntegerVariable> state_;
193 double energy_;
194 std::vector<double> quad_coeff_;
195 std::vector<double> linear_coeff_;
196};
197
198} // namespace system
199} // namespace openjij
Definition integer_quadratic_model.hpp:20
const std::vector< double > & GetLinear() const
Definition integer_quadratic_model.hpp:152
std::int64_t GetNumVariables() const
Definition integer_quadratic_model.hpp:147
const std::vector< double > & GetSquared() const
Definition integer_quadratic_model.hpp:153
const std::vector< std::vector< std::pair< std::int64_t, double > > > & GetQuadratic() const
Definition integer_quadratic_model.hpp:149
const std::vector< std::pair< std::int64_t, std::int64_t > > & GetBounds() const
Definition integer_quadratic_model.hpp:155
std::vector< utility::IntegerVariable > state_
Definition integer_quadratic_sa_system.hpp:192
double GetEnergyDifference(std::int64_t index, std::int64_t new_value) const
Definition integer_quadratic_sa_system.hpp:87
std::int64_t GenerateCandidateValue(std::int64_t index)
Definition integer_quadratic_sa_system.hpp:82
const std::vector< utility::IntegerVariable > & GetState() const
Definition integer_quadratic_sa_system.hpp:164
const std::vector< double > & GetLinearCoeff() const
Definition integer_quadratic_sa_system.hpp:168
double energy_
Definition integer_quadratic_sa_system.hpp:193
double GetEnergy() const
Definition integer_quadratic_sa_system.hpp:174
double CalculateEnergy(const std::vector< utility::IntegerVariable > &state) const
Definition integer_quadratic_sa_system.hpp:64
bool CanOptMove(std::int64_t index) const
Definition integer_quadratic_sa_system.hpp:180
void SetValue(std::int64_t index, std::int64_t new_value)
Definition integer_quadratic_sa_system.hpp:92
std::vector< double > linear_coeff_
Definition integer_quadratic_sa_system.hpp:195
bool IsLinearCoeff(std::int64_t index) const
Definition integer_quadratic_sa_system.hpp:176
const graph::IntegerQuadraticModel model
Definition integer_quadratic_sa_system.hpp:187
IntegerSASystem(const graph::IntegerQuadraticModel &model, const typename RandType::result_type seed)
Definition integer_quadratic_sa_system.hpp:30
double GetLinearCoeff(std::int64_t index) const
Definition integer_quadratic_sa_system.hpp:182
const std::vector< double > & GetQuadCoeff() const
Definition integer_quadratic_sa_system.hpp:172
std::pair< int, double > GetMinEnergyDifference(std::int64_t index)
Definition integer_quadratic_sa_system.hpp:109
const std::int64_t seed
Definition integer_quadratic_sa_system.hpp:188
std::vector< double > quad_coeff_
Definition integer_quadratic_sa_system.hpp:194
RandType random_number_engine
Definition integer_quadratic_sa_system.hpp:189
Definition sa_system.hpp:24
Definition algorithm.hpp:24
Definition variable.hpp:20