cimod
C++ library for a binary (and polynomial) quadratic model.
main.hpp
Go to the documentation of this file.
1 // Copyright 2022 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 
35 namespace py = pybind11;
36 
37 using namespace py::literals;
38 using namespace cimod;
39 
40 template<typename IndexType, typename FloatType, typename DataType>
41 inline 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 
50  pyclass_BQM
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 
152 template<typename IndexType, typename FloatType>
153 inline 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  }
185  py_polynomial[ tuple ] = poly_value_list[ i ];
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",
219  py::overload_cast<PolynomialKeyList<IndexType>&, const PolynomialValueList<FloatType>&, const Vartype>(
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
BINARY
Definition: vartype.py:22
SPIN
Definition: vartype.py:21
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