QNLP  v1.0
test_hamming.cpp
Go to the documentation of this file.
1 //#define CATCH_CONFIG_RUNNER
2 
3 #include "hamming.hpp"
4 #include "Simulator.hpp"
5 #include "IntelSimulator.cpp"
6 #include "catch2/catch.hpp"
7 
8 #include <bitset>
9 
10 #define IS_SET(byte,bit) (((byte) & (1UL << (bit))) >> (bit))
11 
12 using namespace QNLP;
13 using namespace Catch::Matchers;
14 
15 typedef ComplexDP Type;
16 
18 
27 std::size_t calc_hammingDist(std::size_t pattern1, std::size_t pattern2, std::size_t len_bin_pattern){
28  std::size_t num_diffs = 0;
29 
30  for(int i = 0; i < len_bin_pattern; i++){
31  num_diffs += (IS_SET(pattern1,i) == IS_SET(pattern2,i));
32  }
33  return num_diffs;
34 }
35 
44 std::map<std::size_t, double> expected_amplitude(std::vector<std::size_t>& target_vec, std::size_t test, std::size_t len_bin_pattern){
45  const std::size_t num_bin_pattern = target_vec.size();
46  double norm_factor = 0.0;
47 
48  // Calculate Hamming Distance for each training pattern to test pattern
49  std::map<std::size_t, double> exp_amp;
50  for(std::size_t i = 0; i < num_bin_pattern; i++){
51  exp_amp.insert(pair<std::size_t, double>(target_vec[i],(double) calc_hammingDist(target_vec[i],test, len_bin_pattern)));
52  }
53 
54  for(auto& [k,v] : exp_amp){
55  v = sin(v * 0.5* M_PI / (double) len_bin_pattern);
56  norm_factor += v*v;
57  }
58 
59  norm_factor = sqrt(norm_factor);
60 
61  for(auto& [k,v] : exp_amp){
62  v /= norm_factor;
63  }
64 
65  return exp_amp;
66 }
67 
72 TEST_CASE("Test Hamming distance with Roatation about y axis routine","[hammingroty]"){
73  const std::size_t max_qubits = 6;
74  double mach_eps = 7./3. - 4./3. -1.;
75 
76  std::size_t num_qubits;
77  std::size_t len_reg_auxiliary;
78  std::size_t num_bin_pattern;
79  std::size_t val;
80 
81  std::size_t test_pattern = 2;
82 
83  for(std::size_t len_reg_memory = 2; len_reg_memory < max_qubits; len_reg_memory++){
84  DYNAMIC_SECTION("Testing " << len_reg_memory << " memory qubits"){
85 
86  for(std::size_t test_pattern = 2; test_pattern < pow(2,len_reg_memory); test_pattern++){
87  DYNAMIC_SECTION("Testing test pattern (integer format) = " << test_pattern ){
88 
89  // Experiment set-up
90  num_qubits = 2*len_reg_memory + 2;
93 
95  sim.initRegister();
96  auto &r = sim.getQubitRegister();
97 
98  // Set up registers to store indices
99  std::vector<std::size_t> reg_memory(len_reg_memory);
100  for(std::size_t i = 0; i < len_reg_memory; i++){
101  reg_memory[i] = i;
102  }
103  std::vector<std::size_t> reg_auxiliary(len_reg_auxiliary);
104  for(std::size_t i = 0; i < len_reg_auxiliary; i++){
105  reg_auxiliary[i] = i + len_reg_memory;
106  }
107 
108  // Init data to encode
109  std::vector<std::size_t> vec_to_encode(num_bin_pattern);
110  for(std::size_t i = 0; i < num_bin_pattern; i++){
111  vec_to_encode[i] = i;
112  }
113 
114  // Encode
115  sim.encodeBinToSuperpos_unique(reg_memory, reg_auxiliary, vec_to_encode, len_reg_memory);
116 
117  // Compute Hamming distance
118  sim.applyHammingDistanceRotY(test_pattern, reg_memory, reg_auxiliary, len_reg_memory);
119 
120  // Post-selection
121  sim.collapseToBasisZ(reg_auxiliary[len_reg_auxiliary-2], 1);
122 
123  // Generate expected amplitudes from classical computation
124  std::map<std::size_t, double> exp_amp = expected_amplitude(vec_to_encode, test_pattern, len_reg_memory);
125 
126  for(int i = 0; i < num_bin_pattern; i++){
127  REQUIRE(r[i].real() + 10*mach_eps == Approx(0.).margin(1e-12));
128  REQUIRE(r[i].imag() + 10*mach_eps == Approx(0.).margin(1e-12) );
129 
130  }
131  for(int i = num_bin_pattern; i < pow(2,2*len_reg_memory); i++){
132  REQUIRE(r[i].real() + 10*mach_eps == Approx(0.).margin(1e-12));
133  REQUIRE(r[i].imag() + 10*mach_eps == Approx(0.).margin(1e-12) );
134  }
135  // Check relevant state's amplitudes are set correctly.
136  for(int i = pow(2,2*len_reg_memory); i < pow(2,2*len_reg_memory) + num_bin_pattern; i++){
137 
138  CAPTURE( i, r[i].real() + 10*mach_eps == Approx(exp_amp[vec_to_encode[i - pow(2,2*len_reg_memory)]]).margin(1e-12));
139  REQUIRE(r[i].real() + 10*mach_eps == Approx(exp_amp[vec_to_encode[i - pow(2,2*len_reg_memory)]]).margin(1e-12));
140  REQUIRE(r[i].imag() + 10*mach_eps == Approx(0.).margin(1e-12) );
141 
142  }
143  for(int i = pow(2,2*len_reg_memory) + num_bin_pattern; i < pow(2,num_qubits); i++){
144  REQUIRE(r[i].real() + 10*mach_eps == Approx(0.).margin(1e-12));
145  REQUIRE(r[i].imag() + 10*mach_eps == Approx(0.).margin(1e-12) );
146 
147  }
148 
149  val = sim.applyMeasurementToRegister(reg_memory);
150 
151  CHECK_THAT(vec_to_encode, VectorContains(val));
152 
153  }
154  }
155  }
156  }
157 }
std::size_t calc_hammingDist(std::size_t pattern1, std::size_t pattern2, std::size_t len_bin_pattern)
Calulates the Hamming distance between two binary strings stored as integers.
#define IS_SET(byte, bit)
Functions to compute the Hamming distance between a test pattern and the states in memory using y rot...
Class definition for IntelSimulator. The purpose of this class is to map the functionality of the und...
Class definition for implementing the Hamming distance routine along with controlled Y rotations to e...
Definition: hamming.hpp:26
ComplexDP Type
TEST_CASE("Test Hamming distance with Roatation about y axis routine","[hammingroty]")
Test the Hamming distance routine which uses Y rotations to encode the Hamming distance into each sta...
std::map< std::size_t, double > expected_amplitude(std::vector< std::size_t > &target_vec, std::size_t test, std::size_t len_bin_pattern)
Classically calculates the Hamming distance between each binary string in a vector and a test binary ...