openjij
Framework for the Ising model and QUBO.
Loading...
Searching...
No Matches
sparse.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 <algorithm>
18#include <cassert>
19#include <cstddef>
20#include <type_traits>
21#include <unordered_map>
22#include <utility>
23
27
28namespace openjij {
29namespace graph {
30
40template <typename FloatType> class Sparse : public Graph {
41 static_assert(std::is_floating_point<FloatType>::value,
42 "FloatType must be floating-point type.");
43
44public:
49 std::unordered_map<std::pair<Index, Index>, FloatType, utility::PairHash>;
50
55
56private:
62
66 std::size_t _num_edges;
67
71 std::vector<Nodes> _list_adj_nodes;
72
81 inline bool set_adj_node(Index from, Index to) {
84
85 // get adjacent nodes of node "from"
87 // check if the node "to" exists in the nodes
88 if (std::find(nodes.begin(), nodes.end(), to) == nodes.end()) {
89 // nodes size must be smaller than num_edges
90
91#ifndef NDEBUG
92 assert(nodes.size() < _num_edges);
93#else
94 // return false
95 if (nodes.size() >= _num_edges)
96 return false;
97#endif
98 // add node
99 nodes.push_back(to);
100 // add node from "to" to "from"
102 }
103 return true;
104 }
105
106public:
113 Sparse(std::size_t num_spins, std::size_t num_edges)
114 : Graph(num_spins), _num_edges(std::min(num_spins, num_edges)),
115 _list_adj_nodes(num_spins) {}
116
122 explicit Sparse(std::size_t num_spins) : Sparse(num_spins, num_spins) {}
123
130 Sparse(const json &j, std::size_t num_edges)
131 : Sparse(static_cast<std::size_t>(j["num_variables"]), num_edges) {
132
133 // define SparseMatrix and iterator
134 using SparseMatrix = Eigen::SparseMatrix<FloatType, Eigen::RowMajor>;
135 using SpIter = typename SparseMatrix::InnerIterator;
136
137 // define bqm with ising variables
139 // interactions
140 // for(auto&& elem : bqm.get_quadratic()){
141 // const auto& key = elem.first;
142 // const auto& val = elem.second;
143 // J(key.first, key.second) += val;
144 //}
145 // local field
146 // for(auto&& elem : bqm.get_linear()){
147 // const auto& key = elem.first;
148 // const auto& val = elem.second;
149 // h(key) += val;
150 //}
151
152 // insert elements
153 SparseMatrix quadmat = bqm.interaction_matrix();
154 size_t num_variables = quadmat.rows() - 1;
155 for (int k = 0; k < quadmat.outerSize(); k++) {
156 for (SpIter it(quadmat, k); it; ++it) {
157 size_t r = it.row();
158 size_t c = it.col();
159 FloatType val = it.value();
160
161 if (r == num_variables && c == num_variables)
162 continue;
163
164 if (c == num_variables) {
165 // local field
166 h(r) += val;
167 } else {
168 // quadratic
169 J(r, c) += val;
170 }
171 }
172 }
173 }
174
180 Sparse(const json &j) : Sparse(j, j["num_variables"]) {}
181
186 Sparse(const Sparse<FloatType> &) = default;
187
193
201 const Nodes &adj_nodes(Index ind) const { return _list_adj_nodes[ind]; }
202
208 std::size_t get_num_edges() const { return _num_edges; }
209
219 return this->energy(spins);
220 }
221
222 FloatType calc_energy(const Eigen::Matrix<FloatType, Eigen::Dynamic, 1,
223 Eigen::ColMajor> &spins) const {
224 return this->energy(spins);
225 }
226
234 FloatType energy(const Spins &spins) const {
235 if (!(spins.size() == this->get_num_spins())) {
236 std::out_of_range("Out of range in energy in Sparse graph.");
237 }
238
239 FloatType ret = 0;
240 for (std::size_t ind = 0; ind < this->get_num_spins(); ind++) {
241 for (auto &adj_ind : _list_adj_nodes[ind]) {
242 if (ind != adj_ind)
243 ret += (1. / 2) * this->J(ind, adj_ind) * spins[ind] * spins[adj_ind];
244 else
245 ret += this->h(ind) * spins[ind];
246 }
247 }
248
249 return ret;
250 }
251
252 FloatType energy(const Eigen::Matrix<FloatType, Eigen::Dynamic, 1,
253 Eigen::ColMajor> &spins) const {
255 for (size_t i = 0; i < temp_spins.size(); i++) {
256 temp_spins[i] = spins(i);
257 }
258 return energy(temp_spins);
259 }
260
270 assert(i < get_num_spins());
272
273 // i <= j
274 // add node if it does not exist
275 set_adj_node(i, j);
276 return _J[std::make_pair(std::min(i, j), std::max(i, j))];
277 }
278
287 const FloatType &J(Index i, Index j) const {
288 assert(i < get_num_spins());
290 return _J.at(std::make_pair(std::min(i, j), std::max(i, j)));
291 }
292
301 assert(i < get_num_spins());
302 set_adj_node(i, i);
303 return _J[std::make_pair(i, i)];
304 }
305
313 const FloatType &h(Index i) const {
314 assert(i < get_num_spins());
315 return _J.at(std::make_pair(i, i));
316 }
317};
318} // namespace graph
319} // namespace openjij
Abstract graph class.
Definition graph.hpp:37
std::size_t get_num_spins() const noexcept
get number of spins
Definition graph.hpp:89
Sparse graph: two-body intereactions with O(1) connectivity The Hamiltonian is like.
Definition sparse.hpp:40
Sparse(const json &j)
Sparse constructor (from nlohmann::json)
Definition sparse.hpp:180
FloatType calc_energy(const Spins &spins) const
calculate total energy
Definition sparse.hpp:218
FloatType & h(Index i)
access h_{i} (local field)
Definition sparse.hpp:300
const FloatType & J(Index i, Index j) const
access J_{ij}
Definition sparse.hpp:287
std::size_t get_num_edges() const
get number of edges
Definition sparse.hpp:208
Sparse(const json &j, std::size_t num_edges)
Sparse constructor (from nlohmann::json)
Definition sparse.hpp:130
std::unordered_map< std::pair< Index, Index >, FloatType, utility::PairHash > Interactions
interaction type
Definition sparse.hpp:49
Interactions _J
interactions (the number of intereactions is num_spins*(num_spins+1)/2)
Definition sparse.hpp:61
Sparse(const Sparse< FloatType > &)=default
Sparse copy constructor.
Sparse(std::size_t num_spins)
Sparse delegate constructor.
Definition sparse.hpp:122
bool set_adj_node(Index from, Index to)
add adjacent node from "from" Index to "to" Index
Definition sparse.hpp:81
FloatType value_type
float type
Definition sparse.hpp:54
FloatType & J(Index i, Index j)
access J_{ij}
Definition sparse.hpp:269
FloatType calc_energy(const Eigen::Matrix< FloatType, Eigen::Dynamic, 1, Eigen::ColMajor > &spins) const
Definition sparse.hpp:222
Sparse(Sparse< FloatType > &&)=default
Sparse move constructor.
const Nodes & adj_nodes(Index ind) const
list of adjacent nodes
Definition sparse.hpp:201
FloatType energy(const Eigen::Matrix< FloatType, Eigen::Dynamic, 1, Eigen::ColMajor > &spins) const
Definition sparse.hpp:252
std::size_t _num_edges
the uppder limit of the number of edges per site
Definition sparse.hpp:66
const FloatType & h(Index i) const
access h_{i} (local field)
Definition sparse.hpp:313
Sparse(std::size_t num_spins, std::size_t num_edges)
Sparse constructor.
Definition sparse.hpp:113
std::vector< Nodes > _list_adj_nodes
the list of the indices of adjacent nodes
Definition sparse.hpp:71
FloatType energy(const Spins &spins) const
calculate total energy
Definition sparse.hpp:234
auto json_parse(const json &obj, bool relabel=true)
parse json object from bqm.to_serializable
Definition parse.hpp:50
std::vector< Index > Nodes
Definition graph.hpp:32
std::vector< Spin > Spins
Definition graph.hpp:27
nlohmann::json json
Definition parse.hpp:33
std::size_t Index
Definition graph.hpp:30
Definition algorithm.hpp:24
double FloatType
Note:
Definition compile_config.hpp:37
hash class for std::pair
Definition pairhash.hpp:30