cimod
C++ library for a binary (and polynomial) quadratic model.
Loading...
Searching...
No Matches
main.hpp
Go to the documentation of this file.
1// Copyright 2020-2025 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
16#pragma once
17
18
19#include <pybind11/pybind11.h>
20#include <pybind11/stl.h>
21#include <pybind11/functional.h>
22#include <pybind11/eigen.h>
23
24#include <pybind11_json/pybind11_json.hpp>
25
26#include <nlohmann/json.hpp>
27
28#include <sstream>
29
34
35namespace py = pybind11;
36
37using namespace py::literals;
38using namespace cimod;
39
40template<typename IndexType, typename FloatType, typename DataType>
41inline void declare_BQM( py::module& m, const std::string& name ) {
42
44
45 using DenseMatrix = Eigen::Matrix<FloatType, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
46 using SparseMatrix = Eigen::SparseMatrix<FloatType, Eigen::RowMajor>;
47
48 auto pyclass_BQM = py::class_<BQM>( m, name.c_str() );
49
51 .def(
53 "linear"_a,
54 "quadratic"_a,
55 "offset"_a,
56 "vartype"_a )
57 .def(
59 "linear"_a,
60 "quadratic"_a,
61 "vartype"_a )
62 .def(
63 py::init<Eigen::Ref<const DenseMatrix>, std::vector<IndexType>, FloatType, Vartype, bool>(),
64 "mat"_a,
65 "labels_vec"_a,
66 "offset"_a,
67 "vartype"_a,
68 "fix_format"_a = true )
69 .def(
70 py::init<Eigen::Ref<const DenseMatrix>, std::vector<IndexType>, Vartype, bool>(),
71 "mat"_a,
72 "labels_vec"_a,
73 "vartype"_a,
74 "fix_format"_a = true )
75 .def(
76 py::init<const SparseMatrix&, std::vector<IndexType>, FloatType, Vartype>(),
77 "mat"_a,
78 "labels_vec"_a,
79 "offset"_a,
80 "vartype"_a)
81 .def(
82 py::init<const SparseMatrix&, std::vector<IndexType>, Vartype>(),
83 "mat"_a,
84 "labels_vec"_a,
85 "vartype"_a)
86 .def( py::init<const BQM&>(), "bqm"_a )
87 .def( "length", &BQM::length )
88 .def( "get_num_variables", &BQM::get_num_variables )
89 .def( "get_linear", py::overload_cast<IndexType>( &BQM::get_linear, py::const_ ) )
90 .def( "get_linear", py::overload_cast<>( &BQM::get_linear, py::const_ ) )
91 .def( "get_quadratic", py::overload_cast<IndexType, IndexType>( &BQM::get_quadratic, py::const_ ) )
92 .def( "get_quadratic", py::overload_cast<>( &BQM::get_quadratic, py::const_ ) )
93 .def( "get_offset", &BQM::get_offset )
94 .def( "get_vartype", &BQM::get_vartype )
95 .def( "get_variables", &BQM::get_variables )
96 //.def("print", &BQM::print)
97 .def( "empty", &BQM::empty, "vartype"_a )
98 .def( "add_variable", &BQM::add_variable, "v"_a, "bias"_a )
99 .def( "add_variables_from", &BQM::add_variables_from, "linear"_a )
100 .def( "add_interaction", &BQM::add_interaction, "u"_a, "v"_a, "bias"_a )
101 .def( "add_interactions_from", &BQM::add_interactions_from, "quadratic"_a )
102 .def( "remove_variable", &BQM::remove_variable, "v"_a )
103 .def( "remove_variables_from", &BQM::remove_variables_from, "variables"_a )
104 .def( "remove_interaction", &BQM::remove_interaction, "u"_a, "v"_a )
105 .def( "remove_interactions_from", &BQM::remove_interactions_from, "interactions"_a )
106 .def( "add_offset", &BQM::add_offset, "offset"_a )
107 .def( "remove_offset", &BQM::remove_offset )
108 .def(
109 "scale",
110 &BQM::scale,
111 "scalar"_a,
112 "ignored_variables"_a = std::vector<IndexType>(),
113 "ignored_interactions"_a = std::vector<std::pair<IndexType, IndexType>>(),
114 "ignored_offset"_a = false )
115 .def(
116 "normalize",
117 &BQM::normalize,
118 "bias_range"_a = std::pair<FloatType, FloatType>( 1.0, 1.0 ),
119 "use_quadratic_range"_a = false,
120 "quadratic_range"_a = std::pair<FloatType, FloatType>( 1.0, 1.0 ),
121 "ignored_variables"_a = std::vector<IndexType>(),
122 "ignored_interactions"_a = std::vector<std::pair<IndexType, IndexType>>(),
123 "ignored_offset"_a = false )
124 .def( "fix_variable", &BQM::fix_variable, "v"_a, "value"_a )
125 .def( "fix_variables", &BQM::fix_variables, "fixed"_a )
126 .def( "flip_variable", &BQM::flip_variable, "v"_a )
127 //.def("contract_variables", &BQM::contract_variables, "u"_a, "v"_a)
128 .def( "change_vartype", py::overload_cast<const Vartype&>( &BQM::change_vartype ), "vartype"_a )
129 .def( "change_vartype", py::overload_cast<const Vartype&, bool>( &BQM::change_vartype ), "vartype"_a, "inplace"_a )
130 .def( "energy", &BQM::energy, "sample"_a )
131 .def( "energies", &BQM::energies, "samples_like"_a )
132 .def( "to_qubo", &BQM::to_qubo )
133 .def( "to_ising", &BQM::to_ising )
134 .def_static( "from_qubo", &BQM::from_qubo, "Q"_a, "offset"_a = 0.0 )
135 .def_static( "from_ising", &BQM::from_ising, "h"_a, "J"_a, "offset"_a = 0.0 )
136 .def( "interaction_matrix", py::overload_cast<>( &BQM::interaction_matrix, py::const_ ) )
137 //.def("to_serialiable", &BQM::to_serializable)
138 //.def_static("from_serialiable", &BQM::from_serializable, "input"_a);
139 .def( "to_serializable", []( const BQM& self ) { return static_cast<py::object>( self.to_serializable() ); } )
140 .def_static(
141 "from_serializable",
142 []( const py::object& input ) { return BQM::from_serializable( static_cast<nlohmann::json>( input ) ); },
143 "input"_a );
144
145 // interaction_matrix for Dict (legacy BQM) class
146 if constexpr ( std::is_same_v<DataType, cimod::Dict> )
147 pyclass_BQM.def( "_generate_indices", &BQM::_generate_indices )
148 .def(
149 "interaction_matrix", py::overload_cast<const std::vector<IndexType>&>( &BQM::interaction_matrix, py::const_ ) );
150}
151
152template<typename IndexType, typename FloatType>
153inline void declare_BPM( py::module& m, const std::string& name ) {
154
156
157 py::class_<BPM>( m, name.c_str() )
158 .def( py::init<Polynomial<IndexType, FloatType>&, const Vartype>(), "polynomial"_a, "vartype"_a )
159 .def(
161 "keys"_a,
162 "values"_a,
163 "vartype"_a )
164 .def(
165 py::init<
166 const std::vector<IndexType>&,
169 const Vartype>(),
170 "variables"_a,
171 "keys_distance"_a,
172 "values"_a,
173 "vartype"_a )
174 .def(
175 "get_polynomial",
176 []( const BPM& self ) {
177 py::dict py_polynomial;
178 const auto& poly_key_list = self.GetKeyList();
179 const auto& poly_value_list = self.GetValueList();
180 for ( std::size_t i = 0; i < poly_key_list.size(); ++i ) {
181 py::tuple tuple;
182 for ( const auto& index : poly_key_list[ i ] ) {
183 tuple = tuple + py::make_tuple( index );
184 }
186 }
187 return py_polynomial;
188 } )
189 .def( "get_polynomial", py::overload_cast<std::vector<IndexType>&>( &BPM::GetPolynomial, py::const_ ), "key"_a )
190 .def( "get_variables_to_integers", py::overload_cast<>( &BPM::GetVariablesToIntegers ) )
191 .def( "get_variables_to_integers", py::overload_cast<const IndexType&>( &BPM::GetVariablesToIntegers ), "v"_a )
192 .def( "get_key_list", &BPM::GetKeyList )
193 .def( "get_value_list", &BPM::GetValueList )
194 .def( "get_variables", py::overload_cast<>( &BPM::GetSortedVariables ) )
195 .def( "indices", py::overload_cast<>( &BPM::GetSortedVariables ) ) // This will be depricated
196 .def( "get_degree", &BPM::GetDegree )
197 .def( "get_offset", &BPM::GetOffset )
198 .def( "get_vartype", &BPM::GetVartype )
199 .def( "get_num_interactions", &BPM::GetNumInteractions )
200 .def( "get_num_variables", &BPM::GetNumVariables )
201 .def( "empty", &BPM::Empty, "vartype"_a )
202 .def( "clear", &BPM::Clear )
203 .def( "remove_interaction", py::overload_cast<std::vector<IndexType>&>( &BPM::RemoveInteraction ), "key"_a )
204 .def(
205 "remove_interactions_from",
206 py::overload_cast<PolynomialKeyList<IndexType>&>( &BPM::RemoveInteractionsFrom ),
207 "keys"_a )
208 .def( "remove_offset", &BPM::RemoveOffset )
209 .def( "remove_variable", &BPM::RemoveVariable, "v"_a )
210 .def( "remove_variables_from", &BPM::RemoveVariablesFrom, "variables"_a )
211 .def(
212 "add_interaction",
213 py::overload_cast<std::vector<IndexType>&, const FloatType&, const Vartype>( &BPM::AddInteraction ),
214 "key"_a,
215 "value"_a,
216 "vartype"_a = Vartype::NONE )
217 .def(
218 "add_interactions_from",
220 &BPM::AddInteractionsFrom ),
221 "keys"_a,
222 "values"_a,
223 "vartype"_a = Vartype::NONE )
224 .def(
225 "add_interactions_from",
226 py::overload_cast<const Polynomial<IndexType, FloatType>&, const Vartype>( &BPM::AddInteractionsFrom ),
227 "polynomial"_a,
228 "vartype"_a = Vartype::NONE )
229 .def( "add_offset", &BPM::AddOffset, "offset"_a )
230 .def(
231 "energy",
232 py::overload_cast<const Sample<IndexType>&, bool>( &BPM::Energy, py::const_ ),
233 "sample"_a,
234 "omp_flag"_a = true )
235 .def( "energy", py::overload_cast<const std::vector<int32_t>&, bool>( &BPM::Energy ), "sample"_a, "omp_flag"_a = true )
236 .def( "energies", py::overload_cast<const std::vector<Sample<IndexType>>&>( &BPM::Energies, py::const_ ), "samples"_a )
237 .def( "energies", py::overload_cast<const std::vector<std::vector<int32_t>>&>( &BPM::Energies ), "samples"_a )
238 .def(
239 "scale",
240 &BPM::Scale,
241 "scalar"_a,
242 "ignored_interactions"_a = PolynomialKeyList<IndexType>{},
243 "ignored_offset"_a = false )
244 .def(
245 "normalize",
246 &BPM::normalize,
247 "range"_a = std::pair<FloatType, FloatType>{ 1.0, 1.0 },
248 "ignored_interactions"_a = PolynomialKeyList<IndexType>{},
249 "ignored_offset"_a = false )
250 .def( "change_vartype", py::overload_cast<const Vartype, const bool>( &BPM::ChangeVartype ), "vartype"_a, "inplace"_a )
251 .def( "change_vartype", py::overload_cast<const Vartype>( &BPM::ChangeVartype ), "vartype"_a )
252 .def( "has_variable", &BPM::HasVariable, "v"_a )
253 .def(
254 "to_hubo",
255 []( const BPM& self ) {
256 py::dict py_polynomial;
257 for ( const auto& it : self.ToHubo() ) {
258 py::tuple tuple;
259 for ( const auto& index : it.first ) {
260 tuple = tuple + py::make_tuple( index );
261 }
262 py_polynomial[ tuple ] = it.second;
263 }
264 return py_polynomial;
265 } )
266 .def(
267 "to_hising",
268 []( const BPM& self ) {
269 py::dict py_polynomial;
270 for ( const auto& it : self.ToHising() ) {
271 py::tuple tuple;
272 for ( const auto& index : it.first ) {
273 tuple = tuple + py::make_tuple( index );
274 }
275 py_polynomial[ tuple ] = it.second;
276 }
277 return py_polynomial;
278 } )
279 .def( "to_serializable", []( const BPM& self ) { return static_cast<py::object>( self.ToSerializable() ); } )
280 .def_static(
281 "from_serializable",
282 []( const py::object& input ) { return BPM::FromSerializable( static_cast<nlohmann::json>( input ) ); },
283 "input"_a )
284 .def_static(
285 "from_hubo", py::overload_cast<const Polynomial<IndexType, FloatType>&>( &BPM::FromHubo ), "polynomial"_a )
286 .def_static(
287 "from_hubo",
288 py::overload_cast<PolynomialKeyList<IndexType>&, const PolynomialValueList<FloatType>&>( &BPM::FromHubo ),
289 "keys"_a,
290 "value"_a )
291 .def_static(
292 "from_hising", py::overload_cast<const Polynomial<IndexType, FloatType>&>( &BPM::FromHising ), "polynomial"_a )
293 .def_static(
294 "from_hising",
295 py::overload_cast<PolynomialKeyList<IndexType>&, const PolynomialValueList<FloatType>&>( &BPM::FromHising ),
296 "keys"_a,
297 "value"_a )
298 .def( "__repr__", []( const BPM& self ) {
299 const auto& poly_key_list = self.GetKeyList();
300 const auto& poly_value_list = self.GetValueList();
301 std::ostringstream out;
302 out << "cxxcimod.BinaryPolynomialModel({";
303 for ( std::size_t i = 0; i < poly_key_list.size(); ++i ) {
304 py::tuple tuple;
305 for ( const auto& it : poly_key_list[ i ] ) {
306 tuple = tuple + py::make_tuple( it );
307 }
308 out << tuple.attr( "__repr__" )();
309 if ( i == poly_key_list.size() - 1 ) {
310 out << ": " << poly_value_list[ i ];
311 } else {
312 out << ": " << poly_value_list[ i ] << ", ";
313 }
314 }
315 out << "}, ";
316 if ( self.GetVartype() == Vartype::SPIN ) {
317 out << "Vartype.SPIN"
318 << ")";
319 } else if ( self.GetVartype() == Vartype::BINARY ) {
320 out << "Vartype.BINARY"
321 << ")";
322 } else {
323 out << "Vartype.NONE"
324 << ")";
325 }
326 return out.str();
327 } );
328}
Class for BinaryPolynomialModel.
Definition binary_polynomial_model.hpp:168
Class for dense binary quadratic model.
Definition binary_quadratic_model.hpp:148
void declare_BQM(py::module &m, const std::string &name)
Definition main.hpp:41
void declare_BPM(py::module &m, const std::string &name)
Definition main.hpp:153
Definition binary_polynomial_model.hpp:139
std::vector< std::vector< IndexType > > PolynomialKeyList
Type alias for the indices of the polynomial interactions (namely, the list of keys of the polynomial...
Definition binary_polynomial_model.hpp:151
std::unordered_map< IndexType, int32_t > Sample
Type alias for sample, which represents the spin or binary configurations.
Definition binary_polynomial_model.hpp:162
std::vector< FloatType > PolynomialValueList
Type alias for the values of the polynomial interactions (namely, the list of values of the polynomia...
Definition binary_polynomial_model.hpp:157
std::unordered_map< IndexType, FloatType > Linear
Type alias for linear bias.
Definition binary_quadratic_model.hpp:111
std::unordered_map< std::pair< IndexType, IndexType >, FloatType, pair_hash > Quadratic
Type alias for quadratic bias.
Definition binary_quadratic_model.hpp:119
std::unordered_map< std::vector< IndexType >, FloatType, vector_hash > Polynomial
Type alias for the polynomial interactions as std::unordered_map.
Definition binary_polynomial_model.hpp:145
Vartype
Enum class for representing problem type.
Definition vartypes.hpp:24