cimod
C++ library for a binary (and polynomial) quadratic model.
binary_polynomial_model.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 
117 #pragma once
118 
119 #include <algorithm>
120 #include <bitset>
121 #include <cstdint>
122 #include <iostream>
123 #include <set>
124 #include <string>
125 #include <tuple>
126 #include <typeinfo>
127 #include <unordered_map>
128 #include <unordered_set>
129 #include <utility>
130 #include <vector>
131 
132 #include <nlohmann/json.hpp>
133 
134 #include "cimod/hash.hpp"
135 #include "cimod/utilities.hpp"
136 #include "cimod/vartypes.hpp"
137 
138 
139 namespace cimod {
140 
144  template<typename IndexType, typename FloatType>
145  using Polynomial = std::unordered_map<std::vector<IndexType>, FloatType, vector_hash>;
146 
150  template<typename IndexType>
151  using PolynomialKeyList = std::vector<std::vector<IndexType>>;
152 
156  template<typename FloatType>
157  using PolynomialValueList = std::vector<FloatType>;
158 
161  template<typename IndexType>
162  using Sample = std::unordered_map<IndexType, int32_t>;
163 
167  template<typename IndexType, typename FloatType>
169 
170  public:
175  if ( vartype_ == Vartype::NONE ) {
176  throw std::runtime_error( "Unknown vartype detected" );
177  }
178  AddInteractionsFrom( poly_map );
180  }
181 
188  const PolynomialValueList<FloatType> &value_list,
189  const Vartype vartype ) :
190  vartype_( vartype ) {
191  if ( vartype_ == Vartype::NONE ) {
192  throw std::runtime_error( "Unknown vartype detected" );
193  }
194  AddInteractionsFrom( key_list, value_list );
196  }
197 
203  const PolynomialKeyList<IndexType> &key_list,
204  const PolynomialValueList<FloatType> &value_list,
205  const Vartype vartype ) :
206  vartype_( vartype ) {
207  if ( vartype_ == Vartype::NONE ) {
208  throw std::runtime_error( "Unknown vartype detected" );
209  }
210  AddInteractionsFrom( key_list, value_list );
212  }
213 
221  const std::vector<IndexType> &variables,
222  const PolynomialKeyList<std::size_t> &poly_key_distance_list,
223  const PolynomialValueList<FloatType> &poly_value_list,
224  const Vartype vartype ) :
225  vartype_( vartype ) {
226  if ( vartype_ == Vartype::NONE ) {
227  throw std::runtime_error( "Unknown vartype detected" );
228  }
229 
230  if ( poly_key_distance_list.size() != poly_value_list.size() ) {
231  throw std::runtime_error( "The sizes of key_list and value_list must match each other" );
232  }
233 
234  variables_ = std::unordered_set<IndexType>( variables.begin(), variables.end() );
235 
236  if ( variables_.size() != variables.size() ) {
237  throw std::runtime_error( "Unknown error. It seems that the input variables contain the same variables" );
238  }
239 
240  std::size_t num_interactions = poly_key_distance_list.size();
241  poly_key_list_.resize( num_interactions );
242  poly_value_list_.resize( num_interactions );
243 
244 #pragma omp parallel for
245  for ( int64_t i = 0; i < ( int64_t )num_interactions; ++i ) {
246  std::vector<IndexType> temp;
247  for ( const auto &it : poly_key_distance_list[ i ] ) {
248  temp.push_back( variables[ it ] );
249  }
250  std::sort( temp.begin(), temp.end() );
251  poly_key_list_[ i ] = temp;
252  poly_value_list_[ i ] = poly_value_list[ i ];
253  }
254 
255  for ( std::size_t i = 0; i < num_interactions; ++i ) {
256  poly_key_inv_[ poly_key_list_[ i ] ] = i;
257  for ( const auto &it : poly_key_list_[ i ] ) {
258  each_variable_num_[ it ]++;
259  }
260  }
261 
263  }
264 
269  for ( std::size_t i = 0; i < poly_key_list_.size(); ++i ) {
270  poly_map[ poly_key_list_[ i ] ] = poly_value_list_[ i ];
271  }
272  return poly_map;
273  }
274 
280  FloatType GetPolynomial( std::vector<IndexType> &key ) const {
281  FormatPolynomialKey( &key, vartype_ );
282  if ( poly_key_inv_.count( key ) != 0 ) {
283  return poly_value_list_[ poly_key_inv_.at( key ) ];
284  } else {
285  return 0;
286  }
287  }
288 
294  FloatType GetPolynomial( const std::vector<IndexType> &key ) const {
295  std::vector<IndexType> copied_key = key;
296  return GetPolynomial( copied_key );
297  }
298 
302  const std::unordered_map<IndexType, int64_t> &GetVariablesToIntegers() {
305  }
306  return variables_to_integers_;
307  }
308 
312  std::unordered_map<IndexType, int64_t> GetVariablesToIntegers() const {
315  } else {
316  return variables_to_integers_;
317  }
318  }
319 
324  int64_t GetVariablesToIntegers( const IndexType &index ) {
327  }
328  if ( variables_to_integers_.count( index ) == 0 ) {
329  return -1;
330  } else {
331  return variables_to_integers_.at( index );
332  }
333  }
334 
339  int64_t GetVariablesToIntegers( const IndexType &index ) const {
340  if ( variables_.count( index ) == 0 ) {
341  return -1;
342  } else {
343  std::vector<IndexType> sorted_variables = GetSortedVariables();
344  return std::distance(
345  sorted_variables.begin(), std::lower_bound( sorted_variables.begin(), sorted_variables.end(), index ) );
346  }
347  }
348 
352  return poly_key_list_;
353  }
354 
358  return poly_value_list_;
359  }
360 
363  const std::unordered_map<std::vector<IndexType>, std::size_t, vector_hash> &GetKeysInv() const {
364  return poly_key_inv_;
365  }
366 
369  const std::unordered_set<IndexType> &GetVariables() const {
370  return variables_;
371  }
372 
376  const std::vector<IndexType> &GetSortedVariables() {
379  }
380  return sorted_variables_;
381  }
382 
386  std::vector<IndexType> GetSortedVariables() const {
388  return GenerateSortedVariables();
389  } else {
390  return sorted_variables_;
391  }
392  }
393 
396  std::size_t GetDegree() const {
397  std::size_t degree = 0;
398  for ( const auto &it : poly_key_list_ ) {
399  if ( degree < it.size() ) {
400  degree = it.size();
401  }
402  }
403  return degree;
404  }
405 
408  FloatType GetOffset() const {
409  return GetPolynomial( std::vector<IndexType>{} );
410  }
411 
414  Vartype GetVartype() const {
415  return vartype_;
416  }
417 
420  std::size_t GetNumInteractions() const {
421  return poly_key_list_.size();
422  }
423 
426  std::size_t GetNumVariables() const {
427  return variables_.size();
428  }
429 
434  return BinaryPolynomialModel( {}, vartype );
435  }
436 
438  void Clear() {
439  each_variable_num_.clear();
440  variables_to_integers_.clear();
443  std::unordered_set<IndexType>().swap( variables_ );
444  poly_key_inv_.clear();
446  }
447 
450  void RemoveInteraction( std::vector<IndexType> &key ) {
451  FormatPolynomialKey( &key, vartype_ );
452  if ( poly_key_inv_.count( key ) == 0 ) {
453  return;
454  }
455 
456  for ( const auto &index : key ) {
457  if ( each_variable_num_[ index ] >= 2 ) {
458  each_variable_num_[ index ]--;
459  } else if ( each_variable_num_[ index ] == 1 ) {
460  each_variable_num_.erase( index );
461  variables_.erase( index );
463  }
464  }
465 
466  std::size_t inv = poly_key_inv_[ key ];
467 
468  std::swap( poly_key_inv_[ key ], poly_key_inv_[ poly_key_list_.back() ] );
469  poly_key_inv_.erase( key );
470 
471  std::swap( poly_key_list_[ inv ], poly_key_list_.back() );
472  poly_key_list_.pop_back();
473 
474  std::swap( poly_value_list_[ inv ], poly_value_list_.back() );
475  poly_value_list_.pop_back();
476  }
477 
480  void RemoveInteraction( const std::vector<IndexType> &key ) {
481  std::vector<IndexType> copied_key = key;
482  RemoveInteraction( copied_key );
483  }
484 
488  for ( auto &&key : key_list ) {
489  RemoveInteraction( key );
490  }
491  }
492 
496  for ( const auto &key : key_list ) {
497  RemoveInteraction( key );
498  }
499  }
500 
502  void RemoveOffset() {
503  RemoveInteraction( std::vector<IndexType>{} );
504  }
505 
508  void RemoveVariable( const IndexType &index ) {
509  for ( auto &&key : poly_key_list_ ) {
510  if ( std::binary_search( key.begin(), key.end(), index ) ) {
511  RemoveInteraction( key );
512  }
513  }
514  }
515 
518  void RemoveVariablesFrom( const std::vector<IndexType> &key ) {
519  for ( const auto &index : key ) {
520  RemoveVariable( index );
521  }
522  }
523 
528  void AddInteraction( std::vector<IndexType> &key, const FloatType &value, const Vartype vartype = Vartype::NONE ) {
529  if ( std::abs( value ) <= 0.0 ) {
530  return;
531  }
532 
533  if ( vartype_ == vartype || vartype == Vartype::NONE ) {
534  FormatPolynomialKey( &key, vartype_ );
535  SetKeyAndValue( key, value );
536  } else {
537  const std::size_t original_key_size = key.size();
538  const std::size_t changed_key_list_size = IntegerPower( 2, original_key_size );
539 
541  FormatPolynomialKey( &key, vartype );
542  for ( std::size_t i = 0; i < changed_key_list_size; ++i ) {
543  const auto changed_key = GenerateChangedKey( key, i );
544  int sign = ( ( original_key_size - changed_key.size() ) % 2 == 0 ) ? 1.0 : -1.0;
545  SetKeyAndValue( changed_key, value * IntegerPower( 2, changed_key.size() ) * sign );
546  }
547  } else if ( vartype_ == Vartype::BINARY && vartype == Vartype::SPIN ) {
548  FormatPolynomialKey( &key, vartype );
549  FloatType changed_value = value * ( 1.0 / changed_key_list_size );
550  for ( std::size_t i = 0; i < changed_key_list_size; ++i ) {
551  SetKeyAndValue( GenerateChangedKey( key, i ), changed_value );
552  }
553  } else {
554  throw std::runtime_error( "Unknown vartype error" );
555  }
556  }
557  }
558 
563  void AddInteraction( const std::vector<IndexType> &key, const FloatType &value, const Vartype vartype = Vartype::NONE ) {
564  std::vector<IndexType> copied_key = key;
565  AddInteraction( copied_key, value, vartype );
566  }
567 
572  for ( const auto &it : poly_map ) {
573  AddInteraction( it.first, it.second, vartype );
574  }
575  }
576 
583  const PolynomialValueList<FloatType> &value_list,
584  const Vartype vartype = Vartype::NONE ) {
585  if ( key_list.size() != value_list.size() ) {
586  throw std::runtime_error( "The sizes of key_list and value_list must match each other" );
587  }
588  for ( std::size_t i = 0; i < key_list.size(); ++i ) {
589  AddInteraction( key_list[ i ], value_list[ i ], vartype );
590  }
591  }
592 
598  const PolynomialKeyList<IndexType> &key_list,
599  const PolynomialValueList<FloatType> &value_list,
600  const Vartype vartype = Vartype::NONE ) {
601  if ( key_list.size() != value_list.size() ) {
602  throw std::runtime_error( "The sizes of key_list and value_list must match each other" );
603  }
604  for ( std::size_t i = 0; i < key_list.size(); ++i ) {
605  std::vector<IndexType> copied_key = key_list[ i ];
606  AddInteraction( copied_key, value_list[ i ], vartype );
607  }
608  }
609 
612  void AddOffset( FloatType offset ) {
613  AddInteraction( std::vector<IndexType>{}, offset );
614  }
615 
621  FloatType Energy( const Sample<IndexType> &sample, bool omp_flag = true ) const {
622  if ( sample.size() != GetNumVariables() ) {
623  throw std::runtime_error( "The size of sample must be equal to num_variables" );
624  }
625 
626  if ( GetNumInteractions() == 0 ) {
627  return 0.0;
628  }
629 
630  std::size_t num_interactions = GetNumInteractions();
631  FloatType val = 0.0;
632 
633  if ( omp_flag ) {
634 #pragma omp parallel for reduction( + : val )
635  for ( int64_t i = 0; i < ( int64_t )num_interactions; ++i ) {
636  int32_t spin_multiple = 1;
637  for ( const auto &index : poly_key_list_[ i ] ) {
638  spin_multiple *= sample.at( index );
639  if ( spin_multiple == 0.0 ) {
640  break;
641  }
642  }
643  val += spin_multiple * poly_value_list_[ i ];
644  }
645  } else {
646  for ( std::size_t i = 0; i < num_interactions; ++i ) {
647  int32_t spin_multiple = 1;
648  for ( const auto &index : poly_key_list_[ i ] ) {
649  spin_multiple *= sample.at( index );
650  if ( spin_multiple == 0.0 ) {
651  break;
652  }
653  }
654  val += spin_multiple * poly_value_list_[ i ];
655  }
656  }
657  return val;
658  }
659 
665  FloatType Energy( const std::vector<int32_t> &sample_vec, bool omp_flag = true ) {
666  if ( sample_vec.size() != GetNumVariables() ) {
667  throw std::runtime_error( "The size of sample must be equal to num_variables" );
668  }
669 
670  if ( GetNumInteractions() == 0 ) {
671  return 0.0;
672  }
673 
676  }
677 
678  std::size_t num_interactions = GetNumInteractions();
679  FloatType val = 0.0;
680 
681  if ( omp_flag ) {
682 #pragma omp parallel for reduction( + : val )
683  for ( int64_t i = 0; i < ( int64_t )num_interactions; ++i ) {
684  int32_t spin_multiple = 1;
685  for ( const auto &index : poly_key_list_[ i ] ) {
686  spin_multiple *= sample_vec[ variables_to_integers_.at( index ) ];
687  if ( spin_multiple == 0.0 ) {
688  break;
689  }
690  }
691  val += spin_multiple * poly_value_list_[ i ];
692  }
693  } else {
694  for ( std::size_t i = 0; i < num_interactions; ++i ) {
695  int32_t spin_multiple = 1;
696  for ( const auto &index : poly_key_list_[ i ] ) {
697  spin_multiple *= sample_vec[ variables_to_integers_.at( index ) ];
698  if ( spin_multiple == 0.0 ) {
699  break;
700  }
701  }
702  val += spin_multiple * poly_value_list_[ i ];
703  }
704  }
705  return val;
706  }
707 
711  PolynomialValueList<FloatType> Energies( const std::vector<Sample<IndexType>> &samples ) const {
712  PolynomialValueList<FloatType> val_list( samples.size() );
713 #pragma omp parallel for
714  for ( int64_t i = 0; i < ( int64_t )samples.size(); ++i ) {
715  val_list[ i ] = Energy( samples[ i ], false );
716  }
717  return val_list;
718  }
719 
723  PolynomialValueList<FloatType> Energies( const std::vector<std::vector<int32_t>> &samples_vec ) {
724  PolynomialValueList<FloatType> val_list( samples_vec.size() );
725 #pragma omp parallel for
726  for ( int64_t i = 0; i < ( int64_t )samples_vec.size(); ++i ) {
727  val_list[ i ] = Energy( samples_vec[ i ], false );
728  }
729  return val_list;
730  }
731 
736  void Scale(
737  const FloatType scalar,
738  const PolynomialKeyList<IndexType> &ignored_interactions = {},
739  const bool ignored_offset = false ) {
740 
741  std::size_t num_interactions = GetNumInteractions();
742 
743  for ( std::size_t i = 0; i < num_interactions; ++i ) {
744  poly_value_list_[ i ] *= scalar;
745  }
746 
747  FloatType scalar_inv = 1.0 / scalar;
748  for ( const auto &key : ignored_interactions ) {
749  if ( poly_key_inv_.count( key ) != 0 ) {
750  poly_value_list_[ poly_key_inv_[ key ] ] *= scalar_inv;
751  }
752  }
753 
754  if ( ignored_offset == true && poly_key_inv_.count( std::vector<IndexType>{} ) != 0
755  && std::count( ignored_interactions.begin(), ignored_interactions.end(), std::vector<IndexType>{} ) == 0 ) {
756  poly_value_list_[ poly_key_inv_[ std::vector<IndexType>{} ] ] *= scalar_inv;
757  }
758  }
759 
765  void normalize(
766  const std::pair<FloatType, FloatType> &range = { 1.0, 1.0 },
767  const PolynomialKeyList<IndexType> &ignored_interactions = {},
768  const bool ignored_offset = false ) {
769 
770  if ( GetNumInteractions() == 0 ) {
771  return;
772  }
773 
774  FloatType max_poly_value = poly_value_list_[ 0 ];
775  FloatType min_poly_value = poly_value_list_[ 0 ];
776 
777  for ( const auto &poly_value : poly_value_list_ ) {
778  if ( max_poly_value < poly_value ) {
779  max_poly_value = poly_value;
780  }
781  if ( min_poly_value > poly_value ) {
782  min_poly_value = poly_value;
783  }
784  }
785 
786  FloatType inv_scale = std::max( min_poly_value / range.first, max_poly_value / range.second );
787 
788  if ( inv_scale != 0.0 ) {
789  Scale( 1.0 / inv_scale, ignored_interactions, ignored_offset );
790  }
791  }
792 
797  BinaryPolynomialModel ChangeVartype( const Vartype vartype, const bool inplace ) {
798 
799  if ( vartype == Vartype::SPIN ) {
800  if ( inplace ) {
801  *this = ToSpin();
802  return *this;
803  } else {
804  return ToSpin();
805  }
806  } else if ( vartype == Vartype::BINARY ) {
807  if ( inplace ) {
808  *this = ToBinary();
809  return *this;
810  } else {
811  return ToBinary();
812  }
813  } else {
814  throw std::runtime_error( "Unknown vartype error" );
815  }
816  }
817 
819  void ChangeVartype( const Vartype vartype ) {
820  if ( vartype == Vartype::SPIN ) {
821  *this = ToSpin();
822  } else if ( vartype == Vartype::BINARY ) {
823  *this = ToBinary();
824  } else {
825  throw std::runtime_error( "Unknown vartype error" );
826  }
827  }
828 
832  bool HasVariable( const IndexType &index ) {
833  if ( variables_.count( index ) != 0 ) {
834  return true;
835  } else {
836  return false;
837  }
838  }
839 
843  if ( vartype_ == Vartype::BINARY ) {
844  return GetPolynomial();
845  }
847  std::size_t num_interactions = GetNumInteractions();
848  for ( std::size_t i = 0; i < num_interactions; ++i ) {
849  const std::vector<IndexType> &original_key = poly_key_list_[ i ];
850  const FloatType original_value = poly_value_list_[ i ];
851  const std::size_t original_key_size = original_key.size();
852  const std::size_t changed_key_list_size = IntegerPower( 2, original_key_size );
853 
854  for ( std::size_t j = 0; j < changed_key_list_size; ++j ) {
855  const auto changed_key = GenerateChangedKey( original_key, j );
856  int sign = ( ( original_key_size - changed_key.size() ) % 2 == 0 ) ? 1.0 : -1.0;
857  FloatType changed_value = original_value * IntegerPower( 2, changed_key.size() ) * sign;
858  poly_map[ changed_key ] += changed_value;
859  if ( poly_map[ changed_key ] == 0.0 ) {
860  poly_map.erase( changed_key );
861  }
862  }
863  }
864  return poly_map;
865  }
866 
870  if ( vartype_ == Vartype::SPIN ) {
871  return GetPolynomial();
872  }
874  const std::size_t num_interactions = GetNumInteractions();
875  for ( std::size_t i = 0; i < num_interactions; ++i ) {
876  const std::vector<IndexType> &original_key = poly_key_list_[ i ];
877  const FloatType original_value = poly_value_list_[ i ];
878  const std::size_t original_key_size = original_key.size();
879  const std::size_t changed_key_list_size = IntegerPower( 2, original_key_size );
880  const FloatType changed_value = original_value * ( 1.0 / changed_key_list_size );
881 
882  for ( std::size_t j = 0; j < changed_key_list_size; ++j ) {
883  const auto changed_key = GenerateChangedKey( original_key, j );
884  poly_map[ changed_key ] += changed_value;
885  if ( poly_map[ changed_key ] == 0.0 ) {
886  poly_map.erase( changed_key );
887  }
888  }
889  }
890  return poly_map;
891  }
892 
895  nlohmann::json ToSerializable() const {
896  nlohmann::json output;
897  if ( vartype_ == Vartype::BINARY ) {
898  output[ "vartype" ] = "BINARY";
899  } else if ( vartype_ == Vartype::SPIN ) {
900  output[ "vartype" ] = "SPIN";
901  } else {
902  throw std::runtime_error( "Variable type must be SPIN or BINARY." );
903  }
904 
905  std::size_t num_interactions = GetNumInteractions();
906  PolynomialKeyList<std::size_t> poly_key_distance_list( num_interactions );
907  std::vector<IndexType> sorted_variables = GetSortedVariables();
908 
909 #pragma omp parallel for
910  for ( int64_t i = 0; i < ( int64_t )num_interactions; ++i ) {
911  std::vector<std::size_t> temp;
912  for ( const auto &it : poly_key_list_[ i ] ) {
913  auto it_index = std::lower_bound( sorted_variables.begin(), sorted_variables.end(), it );
914  std::size_t index_distance = std::distance( sorted_variables.begin(), it_index );
915  temp.push_back( index_distance );
916  }
917  poly_key_distance_list[ i ] = temp;
918  }
919 
920  output[ "variables" ] = sorted_variables;
921  output[ "poly_key_distance_list" ] = poly_key_distance_list;
922  output[ "poly_value_list" ] = poly_value_list_;
923  output[ "type" ] = "BinaryPolynomialModel";
924 
925  return output;
926  }
927 
933  template<typename IndexType_serial = IndexType, typename FloatType_serial = FloatType>
935  if ( input.at( "type" ) != "BinaryPolynomialModel" ) {
936  throw std::runtime_error( "Type must be \"BinaryPolynomialModel\".\n" );
937  }
939  if ( input.at( "vartype" ) == "SPIN" ) {
941  } else if ( input.at( "vartype" ) == "BINARY" ) {
943  } else {
944  throw std::runtime_error( "Variable type must be SPIN or BINARY." );
945  }
947  input[ "variables" ], input[ "poly_key_distance_list" ], input[ "poly_value_list" ], vartype );
948  }
949 
955  }
956 
961  static BinaryPolynomialModel
963  return BinaryPolynomialModel<IndexType, FloatType>( key_list, value_list, Vartype::BINARY );
964  }
965 
970  static BinaryPolynomialModel
972  return BinaryPolynomialModel<IndexType, FloatType>( key_list, value_list, Vartype::BINARY );
973  }
974 
980  }
981 
986  static BinaryPolynomialModel
988  return BinaryPolynomialModel<IndexType, FloatType>( key_list, value_list, Vartype::SPIN );
989  }
990 
995  static BinaryPolynomialModel
997  return BinaryPolynomialModel<IndexType, FloatType>( key_list, value_list, Vartype::SPIN );
998  }
999 
1000  protected:
1002  std::unordered_set<IndexType> variables_;
1003 
1005  std::unordered_map<IndexType, std::size_t> each_variable_num_;
1006 
1008  std::unordered_map<IndexType, int64_t> variables_to_integers_;
1009 
1011  std::vector<IndexType> sorted_variables_;
1012 
1015 
1019 
1023 
1025  std::unordered_map<std::vector<IndexType>, std::size_t, vector_hash> poly_key_inv_;
1026 
1029 
1034  void SetKeyAndValue( const std::vector<IndexType> &key, const FloatType &value ) {
1035  // key is assumed to be sorted
1036  if ( poly_key_inv_.count( key ) == 0 ) {
1037  poly_key_inv_[ key ] = poly_value_list_.size();
1038  poly_key_list_.push_back( key );
1039  poly_value_list_.push_back( value );
1040  } else {
1041  if ( poly_value_list_[ poly_key_inv_[ key ] ] + value == 0.0 ) {
1042  RemoveInteraction( key );
1043  return;
1044  }
1045  poly_value_list_[ poly_key_inv_[ key ] ] += value;
1046  }
1047  for ( const auto &index : key ) {
1048  each_variable_num_[ index ]++;
1049  variables_.emplace( index );
1051  }
1052  }
1053 
1058  std::size_t IntegerPower( std::size_t base, std::size_t exponent ) const {
1059  std::size_t val = 1;
1060  for ( std::size_t i = 0; i < exponent; ++i ) {
1061  val *= base;
1062  }
1063  return val;
1064  }
1065 
1070  std::vector<IndexType>
1071  GenerateChangedKey( const std::vector<IndexType> &original_key, const std::size_t num_of_key ) const {
1072  if ( original_key.size() >= UINT16_MAX ) {
1073  throw std::runtime_error( "Too large degree of the interaction" );
1074  }
1075  const std::size_t original_key_size = original_key.size();
1076  std::bitset<UINT16_MAX> bs( num_of_key );
1077  std::vector<IndexType> changed_key;
1078  for ( std::size_t i = 0; i < original_key_size; ++i ) {
1079  if ( bs[ i ] ) {
1080  changed_key.push_back( original_key[ i ] );
1081  }
1082  }
1083  return changed_key;
1084  }
1085 
1089  if ( vartype_ == Vartype::SPIN ) {
1090  return *this;
1091  }
1093  }
1094 
1098  if ( vartype_ == Vartype::BINARY ) {
1099  return *this;
1100  }
1102  }
1103 
1107  variables_to_integers_.clear();
1108  for ( std::size_t i = 0; i < sorted_variables_.size(); ++i ) {
1110  }
1112  }
1113 
1116  std::unordered_map<IndexType, int64_t> GenerateVariablesToIntegers() const {
1117  std::vector<IndexType> sorted_variables = GenerateSortedVariables();
1118  std::unordered_map<IndexType, int64_t> variables_to_integers;
1119  for ( std::size_t i = 0; i < sorted_variables.size(); ++i ) {
1120  variables_to_integers[ sorted_variables[ i ] ] = i;
1121  }
1122  return variables_to_integers;
1123  }
1124 
1127  std::vector<IndexType> GenerateSortedVariables() const {
1128  std::vector<IndexType> sorted_variables( variables_.begin(), variables_.end() );
1129  std::sort( sorted_variables.begin(), sorted_variables.end() );
1130  return sorted_variables;
1131  }
1132  };
1133 
1134 } // namespace cimod
Class for BinaryPolynomialModel.
Definition: binary_polynomial_model.hpp:168
void AddInteractionsFrom(const PolynomialKeyList< IndexType > &key_list, const PolynomialValueList< FloatType > &value_list, const Vartype vartype=Vartype::NONE)
Add interactions to the BinaryPolynomialModel.
Definition: binary_polynomial_model.hpp:597
void RemoveOffset()
Set the offset of the BinaryPolynomialModel to zero.
Definition: binary_polynomial_model.hpp:502
void ChangeVartype(const Vartype vartype)
Change the vartype of the BinaryPolynomialModel.
Definition: binary_polynomial_model.hpp:819
std::unordered_map< IndexType, int64_t > GetVariablesToIntegers() const
Get variables_to_integers object.
Definition: binary_polynomial_model.hpp:312
FloatType Energy(const std::vector< int32_t > &sample_vec, bool omp_flag=true)
Determine the energy of the specified sample_vec (as std::vector) of the BinaryPolynomialModel.
Definition: binary_polynomial_model.hpp:665
std::unordered_map< std::vector< IndexType >, std::size_t, vector_hash > poly_key_inv_
The inverse key list, which indicates the index of the poly_key_list_ and poly_value_list_.
Definition: binary_polynomial_model.hpp:1025
Vartype vartype_
The model's type. SPIN or BINARY.
Definition: binary_polynomial_model.hpp:1028
int64_t GetVariablesToIntegers(const IndexType &index)
Get the specific integer number corresponding to the input variable (index).
Definition: binary_polynomial_model.hpp:324
bool relabel_flag_for_variables_to_integers_
If true variable_to_index must be relabeled.
Definition: binary_polynomial_model.hpp:1014
void Clear()
Clear the BinaryPolynomialModel.
Definition: binary_polynomial_model.hpp:438
std::unordered_set< IndexType > variables_
Variable list as std::unordered_set.
Definition: binary_polynomial_model.hpp:1002
std::size_t GetDegree() const
Return the maximum degree of interaction.
Definition: binary_polynomial_model.hpp:396
std::size_t IntegerPower(std::size_t base, std::size_t exponent) const
Caluculate the base to the power of exponent (std::pow(base, exponent) is too slow).
Definition: binary_polynomial_model.hpp:1058
BinaryPolynomialModel(const std::vector< IndexType > &variables, const PolynomialKeyList< std::size_t > &poly_key_distance_list, const PolynomialValueList< FloatType > &poly_value_list, const Vartype vartype)
BinaryPolynomialModel constructor.
Definition: binary_polynomial_model.hpp:220
std::vector< IndexType > GenerateSortedVariables() const
Generate sorted variables.
Definition: binary_polynomial_model.hpp:1127
void RemoveVariablesFrom(const std::vector< IndexType > &key)
Remove the specified variables from the BinaryPolynomialModel.
Definition: binary_polynomial_model.hpp:518
static BinaryPolynomialModel FromHubo(PolynomialKeyList< IndexType > &key_list, const PolynomialValueList< FloatType > &value_list)
Create a BinaryPolynomialModel from a Hubo model.
Definition: binary_polynomial_model.hpp:971
void RemoveInteractionsFrom(const PolynomialKeyList< IndexType > &key_list)
Remove the specified interactions from the BinaryPolynomialModel.
Definition: binary_polynomial_model.hpp:495
std::unordered_map< IndexType, int64_t > variables_to_integers_
The correspondence from variables to the integer numbers.
Definition: binary_polynomial_model.hpp:1008
BinaryPolynomialModel(PolynomialKeyList< IndexType > &key_list, const PolynomialValueList< FloatType > &value_list, const Vartype vartype)
BinaryPolynomialModel constructor.
Definition: binary_polynomial_model.hpp:186
void AddInteractionsFrom(PolynomialKeyList< IndexType > &key_list, const PolynomialValueList< FloatType > &value_list, const Vartype vartype=Vartype::NONE)
Add interactions to the BinaryPolynomialModel.
Definition: binary_polynomial_model.hpp:581
std::unordered_map< IndexType, std::size_t > each_variable_num_
The list of the number of the variables appeared in the polynomial interactions as std::unordered_map...
Definition: binary_polynomial_model.hpp:1005
void AddInteraction(std::vector< IndexType > &key, const FloatType &value, const Vartype vartype=Vartype::NONE)
Add an interaction to the BinaryPolynomialModel.
Definition: binary_polynomial_model.hpp:528
PolynomialValueList< FloatType > Energies(const std::vector< std::vector< int32_t >> &samples_vec)
Determine the energies of the given samples_vec.
Definition: binary_polynomial_model.hpp:723
static BinaryPolynomialModel< IndexType_serial, FloatType_serial > FromSerializable(const nlohmann::json &input)
Create a BinaryPolynomialModel instance from a serializable object.
Definition: binary_polynomial_model.hpp:934
BinaryPolynomialModel(const PolynomialKeyList< IndexType > &key_list, const PolynomialValueList< FloatType > &value_list, const Vartype vartype)
BinaryPolynomialModel constructor.
Definition: binary_polynomial_model.hpp:202
void RemoveInteraction(const std::vector< IndexType > &key)
Remove the specified interaction from the BinaryPolynomialModel.
Definition: binary_polynomial_model.hpp:480
std::unordered_map< IndexType, int64_t > GenerateVariablesToIntegers() const
Generate variables_to_integers.
Definition: binary_polynomial_model.hpp:1116
int64_t GetVariablesToIntegers(const IndexType &index) const
Get the specific integer number corresponding to the input variable (index).
Definition: binary_polynomial_model.hpp:339
static BinaryPolynomialModel FromHubo(const Polynomial< IndexType, FloatType > &poly_map)
Create a BinaryPolynomialModel from a Hubo model.
Definition: binary_polynomial_model.hpp:953
FloatType GetOffset() const
Return the offset.
Definition: binary_polynomial_model.hpp:408
bool HasVariable(const IndexType &index)
Check if the specified index is in the BinaryPolynomialModel.
Definition: binary_polynomial_model.hpp:832
FloatType GetPolynomial(std::vector< IndexType > &key) const
Get the specific value of the interaction according to the key representing the indices of the polyno...
Definition: binary_polynomial_model.hpp:280
PolynomialValueList< FloatType > Energies(const std::vector< Sample< IndexType >> &samples) const
Determine the energies of the given samples.
Definition: binary_polynomial_model.hpp:711
const std::unordered_set< IndexType > & GetVariables() const
Return the variables as std::unordered_set.
Definition: binary_polynomial_model.hpp:369
void Scale(const FloatType scalar, const PolynomialKeyList< IndexType > &ignored_interactions={}, const bool ignored_offset=false)
Multiply by the specified scalar all the values of the interactions of the BinaryPolynomialModel.
Definition: binary_polynomial_model.hpp:736
std::size_t GetNumVariables() const
Return the number of variables.
Definition: binary_polynomial_model.hpp:426
void SetKeyAndValue(const std::vector< IndexType > &key, const FloatType &value)
Set key and value.
Definition: binary_polynomial_model.hpp:1034
static BinaryPolynomialModel FromHubo(const PolynomialKeyList< IndexType > &key_list, const PolynomialValueList< FloatType > &value_list)
Create a BinaryPolynomialModel from a Hubo model.
Definition: binary_polynomial_model.hpp:962
BinaryPolynomialModel Empty(const Vartype vartype) const
Create an empty BinaryPolynomialModel.
Definition: binary_polynomial_model.hpp:433
void UpdateVariablesToIntegers()
Update sorted_variables_ and variables_to_integers_.
Definition: binary_polynomial_model.hpp:1105
std::vector< IndexType > sorted_variables_
Sorted variables is represents the correspondence from integer numbers.to the variables.
Definition: binary_polynomial_model.hpp:1011
Vartype GetVartype() const
Return the vartype.
Definition: binary_polynomial_model.hpp:414
const std::unordered_map< IndexType, int64_t > & GetVariablesToIntegers()
Get variables_to_integers object.
Definition: binary_polynomial_model.hpp:302
void AddInteraction(const std::vector< IndexType > &key, const FloatType &value, const Vartype vartype=Vartype::NONE)
Add an interaction to the BinaryPolynomialModel.
Definition: binary_polynomial_model.hpp:563
BinaryPolynomialModel ToBinary() const
Generate BinaryPolynomialModel with the vartype being BINARY.
Definition: binary_polynomial_model.hpp:1097
const std::unordered_map< std::vector< IndexType >, std::size_t, vector_hash > & GetKeysInv() const
Get The inverse key list, which indicates the index of the poly_key_list_ and poly_value_list_.
Definition: binary_polynomial_model.hpp:363
PolynomialValueList< FloatType > poly_value_list_
The list of the values of the polynomial interactions (namely, the list of values of the polynomial i...
Definition: binary_polynomial_model.hpp:1022
nlohmann::json ToSerializable() const
Convert the BinaryPolynomialModel to a serializable object.
Definition: binary_polynomial_model.hpp:895
BinaryPolynomialModel ChangeVartype(const Vartype vartype, const bool inplace)
Create a BinaryPolynomialModel with the specified vartype.
Definition: binary_polynomial_model.hpp:797
static BinaryPolynomialModel FromHising(const Polynomial< IndexType, FloatType > &poly_map)
Create a BinaryPolynomialModel from a higher ordere Ising model.
Definition: binary_polynomial_model.hpp:978
std::vector< IndexType > GenerateChangedKey(const std::vector< IndexType > &original_key, const std::size_t num_of_key) const
Generate the num_of_key-th the key when the vartype is changed.
Definition: binary_polynomial_model.hpp:1071
PolynomialKeyList< IndexType > poly_key_list_
The list of the indices of the polynomial interactions (namely, the list of keys of the polynomial in...
Definition: binary_polynomial_model.hpp:1018
const PolynomialValueList< FloatType > & GetValueList() const
Get the PolynomialValueList object.
Definition: binary_polynomial_model.hpp:357
BinaryPolynomialModel ToSpin() const
Generate BinaryPolynomialModel with the vartype being SPIN.
Definition: binary_polynomial_model.hpp:1088
void normalize(const std::pair< FloatType, FloatType > &range={ 1.0, 1.0 }, const PolynomialKeyList< IndexType > &ignored_interactions={}, const bool ignored_offset=false)
Normalizes the values of the interactions of the BinaryPolynomialModel such that they fall in the pro...
Definition: binary_polynomial_model.hpp:765
const std::vector< IndexType > & GetSortedVariables()
Return the sorted variables as std::vector.
Definition: binary_polynomial_model.hpp:376
static BinaryPolynomialModel FromHising(PolynomialKeyList< IndexType > &key_list, const PolynomialValueList< FloatType > &value_list)
Create a BinaryPolynomialModel from a higher ordere Ising model.
Definition: binary_polynomial_model.hpp:996
Polynomial< IndexType, FloatType > ToHising() const
Generate the polynomial interactions corresponding to the vartype being SPIN from the BinaryPolynomia...
Definition: binary_polynomial_model.hpp:869
FloatType Energy(const Sample< IndexType > &sample, bool omp_flag=true) const
Determine the energy of the specified sample of the BinaryPolynomialModel.
Definition: binary_polynomial_model.hpp:621
std::size_t GetNumInteractions() const
Return the number of the interactions.
Definition: binary_polynomial_model.hpp:420
void AddOffset(FloatType offset)
Add specified value to the offset of the BinaryPolynomialModel.
Definition: binary_polynomial_model.hpp:612
std::vector< IndexType > GetSortedVariables() const
Return the sorted variables as std::vector.
Definition: binary_polynomial_model.hpp:386
void RemoveVariable(const IndexType &index)
Remove a variable from the BinaryPolynomialModel.
Definition: binary_polynomial_model.hpp:508
const PolynomialKeyList< IndexType > & GetKeyList() const
Get the PolynomialKeyList object.
Definition: binary_polynomial_model.hpp:351
Polynomial< IndexType, FloatType > ToHubo() const
Generate the polynomial interactions corresponding to the vartype being BINARY from the BinaryPolynom...
Definition: binary_polynomial_model.hpp:842
static BinaryPolynomialModel FromHising(const PolynomialKeyList< IndexType > &key_list, const PolynomialValueList< FloatType > &value_list)
Create a BinaryPolynomialModel from a higher ordere Ising model.
Definition: binary_polynomial_model.hpp:987
Polynomial< IndexType, FloatType > GetPolynomial() const
Get the Polynomial object.
Definition: binary_polynomial_model.hpp:267
BinaryPolynomialModel(const Polynomial< IndexType, FloatType > &poly_map, const Vartype vartype)
BinaryPolynomialModel constructor.
Definition: binary_polynomial_model.hpp:174
void RemoveInteraction(std::vector< IndexType > &key)
Remove the specified interaction from the BinaryPolynomialModel.
Definition: binary_polynomial_model.hpp:450
FloatType GetPolynomial(const std::vector< IndexType > &key) const
Get the specific value of the interaction according to the key representing the indices of the polyno...
Definition: binary_polynomial_model.hpp:294
void RemoveInteractionsFrom(PolynomialKeyList< IndexType > &key_list)
Remove the specified interactions from the BinaryPolynomialModel.
Definition: binary_polynomial_model.hpp:487
void AddInteractionsFrom(const Polynomial< IndexType, FloatType > &poly_map, const Vartype vartype=Vartype::NONE)
Add interactions to the BinaryPolynomialModel.
Definition: binary_polynomial_model.hpp:571
vartype
Definition: legacy/binary_quadratic_model.py:182
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< std::vector< IndexType >, FloatType, vector_hash > Polynomial
Type alias for the polynomial interactions as std::unordered_map.
Definition: binary_polynomial_model.hpp:145
void FormatPolynomialKey(std::vector< IndexType > *key, const Vartype &vartype)
Format the input key: for example, {2,1,1}-->{1,2} for BINARY variable and {2,1,1}-->{2} for SPIN var...
Definition: utilities.hpp:50
Vartype
Enum class for representing problem type.
Definition: vartypes.hpp:24
Definition: hash.hpp:73