QNLP  v1.0
test_diffusion.cpp
Go to the documentation of this file.
1 #include "diffusion.hpp"
2 #include "oracle.hpp"
3 #include "Simulator.hpp"
4 #include "IntelSimulator.cpp"
5 #include "catch2/catch.hpp"
6 
7 #include <bitset>
8 
9 using namespace QNLP;
10 
11 typedef ComplexDP Type;
12 
17 TEST_CASE("4 qubit diffusion using module","[diffusion]"){
18  std::size_t num_qubits = 4;
20  auto& reg = sim.getQubitRegister();
21  double previous_prob = 0.;
22 
23  SECTION("2^4 bit patterns (16)"){
24  // Testing patterns 000 001 010 011, etc.
25  std::vector<std::size_t> bit_patterns;
26  for(std::size_t s = 0; s < (std::size_t)(0b1 << num_qubits); s++){
27  bit_patterns.push_back(s);
28  }
29 
30  //Declare which indices are control lines
31  std::vector<std::size_t> ctrl_indices;
32  for(std::size_t i = 0; i < num_qubits-1; ++i){
33  ctrl_indices.push_back(i);
34  }
35 
36  //Create oracle object with num_ctrl_gates and indices
37  Oracle<decltype(sim)> oracle;
38 
39  Diffusion<decltype(sim)> diffusion;
40 
41  // Loop over given bit-patterns and show effect on resulting state
42  for(auto &i : bit_patterns){
43  DYNAMIC_SECTION("bitStringNCU with pattern " << i){
44  sim.initRegister();
45  //Create initial superposition
46  for(std::size_t j = 0; j < num_qubits; ++j){
47  sim.applyGateH(j);
48  }
49 
50  // sqrt(N) iterations optimal
51  for(int iteration = 1 ; iteration < (M_PI/4)*sqrt( (0b1<<num_qubits) / 1); iteration++){
52  // Mark state: convert matching state pattern to |11...1>
53  // apply nCZ, and undo conversion; negates the matched pattern phase
54  oracle.bitStringNCU(sim, i, ctrl_indices, num_qubits-1, sim.getGateZ(), "Z");
55 
56  CAPTURE( reg[i], i );
57  //REQUIRE( reg[i].real() < 0.);
58  //reg.Print("PRE-DIFF iteration=" + std::to_string(iteration));
59 
60  diffusion.applyOpDiffusion( sim, ctrl_indices, num_qubits-1);
61  CAPTURE( reg[i], i );
62  if(i>0){
63  REQUIRE( abs(reg[i])*abs(reg[i]) > abs(reg[0])*abs(reg[0]) );
64  }
65  else {
66  REQUIRE( abs(reg[i])*abs(reg[i]) > abs(reg[1])*abs(reg[1]) );
67  }
68  REQUIRE( abs(reg[i])*abs(reg[i]) > previous_prob );
69  previous_prob = abs(reg[i])*abs(reg[i]);
70  }
71  }
72  }
73  }
74 }
75 
80 TEST_CASE("8 qubit diffusion using module","[diffusion]"){
81  std::size_t num_qubits = 8;
83  auto& reg = sim.getQubitRegister();
84  double previous_prob = 0.;
85 
86  SECTION("2^8 bit patterns (256)"){
87  // Testing patterns 000 001 010 011, etc.
88  std::vector<std::size_t> bit_patterns;
89  for(std::size_t s = 0; s < (std::size_t)(0b1 << num_qubits); s++){
90  bit_patterns.push_back(s);
91  }
92 
93  //Declare which indices are control lines
94  std::vector<std::size_t> ctrl_indices;
95  for(std::size_t i = 0; i < num_qubits-1; ++i){
96  ctrl_indices.push_back(i);
97  }
98 
99  //Create oracle object with num_ctrl_gates and indices
100  Oracle<decltype(sim)> oracle;
101 
102  Diffusion<decltype(sim)> diffusion;
103 
104  // Loop over given bit-patterns and show effect on resulting state
105  for(auto &i : bit_patterns){
106  DYNAMIC_SECTION("bitStringNCU with pattern " << i){
107  sim.initRegister();
108  //Create initial superposition
109  for(std::size_t j = 0; j < num_qubits; ++j){
110  sim.applyGateH(j);
111  }
112 
113  // O sqrt(N) iterations optimal
114  // R = (M_PI/4)*sqrt( (0b1<<num_qubits) / 1);
115  for(int iteration = 1 ; iteration < (M_PI/4)*sqrt( (0b1<<num_qubits) / 1); iteration++){
116  // Mark state: convert matching state pattern to |11...1>
117  // apply nCZ, and undo conversion; negates the matched pattern phase
118  oracle.bitStringNCU(sim, i, ctrl_indices, num_qubits-1, sim.getGateZ(), "Z");
119 
120  CAPTURE( reg[i], i );
121  //REQUIRE( reg[i].real() < 0.);
122  //reg.Print("PRE-DIFF iteration=" + std::to_string(iteration));
123 
124  diffusion.applyOpDiffusion( sim, ctrl_indices, num_qubits-1);
125  CAPTURE( reg[i], i );
126  if(i>0){
127  REQUIRE( abs(reg[i])*abs(reg[i]) > abs(reg[0])*abs(reg[0]) );
128  }
129  else {
130  REQUIRE( abs(reg[i])*abs(reg[i]) > abs(reg[1])*abs(reg[1]) );
131  }
132  REQUIRE( abs(reg[i])*abs(reg[i]) > previous_prob );
133  previous_prob = abs(reg[i])*abs(reg[i]);
134  }
135  }
136  }
137  }
138 }
139 
144 TEST_CASE("4 qubit diffusion using Simulator method","[diffusion]"){
145  std::size_t num_qubits = 4;
147  auto& reg = sim.getQubitRegister();
148  double previous_prob = 0.;
149 
150  SECTION("2^4 bit patterns (16)"){
151  // Testing patterns 000 001 010 011, etc.
152  std::vector<std::size_t> bit_patterns;
153  for(std::size_t s = 0; s < (std::size_t)(0b1 << num_qubits); s++){
154  bit_patterns.push_back(s);
155  }
156 
157  //Declare which indices are control lines
158  std::vector<std::size_t> ctrl_indices;
159  for(std::size_t i = 0; i < num_qubits-1; ++i){
160  ctrl_indices.push_back(i);
161  }
162 
163  // Loop over given bit-patterns and show effect on resulting state
164  for(auto &i : bit_patterns){
165  DYNAMIC_SECTION("bitStringNCU with pattern " << i){
166  sim.initRegister();
167  //Create initial superposition
168  for(std::size_t j = 0; j < num_qubits; ++j){
169  sim.applyGateH(j);
170  }
171 
172  // sqrt(N) iterations optimal
173  for(int iteration = 1 ; iteration < (M_PI/4)*sqrt( (0b1<<num_qubits) / 1); iteration++){
174  // Mark state: convert matching state pattern to |11...1>
175  // apply nCZ, and undo conversion; negates the matched pattern phase
176  sim.applyOracleU(i, ctrl_indices, num_qubits-1, sim.getGateZ(), "Z");
177 
178  CAPTURE( reg[i], i );
179  sim.applyDiffusion(ctrl_indices, num_qubits-1);
180 
181  CAPTURE( reg[i], i );
182  if(i>0){
183  REQUIRE( abs(reg[i])*abs(reg[i]) > abs(reg[0])*abs(reg[0]) );
184  }
185  else {
186  REQUIRE( abs(reg[i])*abs(reg[i]) > abs(reg[1])*abs(reg[1]) );
187  }
188  REQUIRE( abs(reg[i])*abs(reg[i]) > previous_prob );
189  previous_prob = abs(reg[i])*abs(reg[i]);
190  }
191  }
192  }
193  }
194 }
195 
200 TEST_CASE("8 qubit diffusion using Simulator method","[diffusion]"){
201  std::size_t num_qubits = 8;
203  auto& reg = sim.getQubitRegister();
204  double previous_prob = 0.;
205 
206  SECTION("2^8 bit patterns (256)"){
207  // Testing patterns 000 001 010 011, etc.
208  std::vector<std::size_t> bit_patterns;
209  for(std::size_t s = 0; s < (std::size_t)(0b1 << num_qubits); s++){
210  bit_patterns.push_back(s);
211  }
212 
213  //Declare which indices are control lines
214  std::vector<std::size_t> ctrl_indices;
215  for(std::size_t i = 0; i < num_qubits-1; ++i){
216  ctrl_indices.push_back(i);
217  }
218 
219  // Loop over given bit-patterns and show effect on resulting state
220  for(auto &i : bit_patterns){
221  DYNAMIC_SECTION("bitStringNCU with pattern " << i){
222  sim.initRegister();
223  //Create initial superposition
224  for(std::size_t j = 0; j < num_qubits; ++j){
225  sim.applyGateH(j);
226  }
227 
228  // O sqrt(N) iterations optimal
229  // R = (M_PI/4)*sqrt( (0b1<<num_qubits) / 1);
230  for(int iteration = 1 ; iteration < (M_PI/4)*sqrt( (0b1<<num_qubits) / 1); iteration++){
231  // Mark state: convert matching state pattern to |11...1>
232  // apply nCZ, and undo conversion; negates the matched pattern phase
233  sim.applyOracleU(i, ctrl_indices, num_qubits-1, sim.getGateZ(), "Z");
234 
235  CAPTURE( reg[i], i );
236 
237  sim.applyDiffusion(ctrl_indices, num_qubits-1);
238  CAPTURE( reg[i], i );
239  if(i>0){
240 
241  REQUIRE( abs(reg[i])*abs(reg[i]) > abs(reg[0])*abs(reg[0]) );
242  }
243  else {
244  REQUIRE( abs(reg[i])*abs(reg[i]) > abs(reg[1])*abs(reg[1]) );
245  }
246  REQUIRE( abs(reg[i])*abs(reg[i]) > previous_prob );
247  previous_prob = abs(reg[i])*abs(reg[i]);
248  }
249  }
250  }
251  }
252 }
TEST_CASE("4 qubit diffusion using module","[diffusion]")
Test diffusion for 4 qubits.
ComplexDP Type
Class definition for IntelSimulator. The purpose of this class is to map the functionality of the und...
Class definition for defining and applying an Oracle.
Definition: oracle.hpp:26
Class definition for applying Grover diffusion to a marked register.
Definition: diffusion.hpp:27
Functions for applying black-box like functions to select appropriate qubits matching given patterns.
static void bitStringNCU(SimulatorType &s, std::size_t bitstring, const std::vector< std::size_t > &ctrl_indices, const std::size_t target, const Mat2x2Type &U, std::string gateLabel)
Takes bitstring as the binary pattern and indices as the qubits to operate upon. Applies the appropri...
Definition: oracle.hpp:54
Defines class with operator which applies the Grover diffusion to a marked register....
void applyOpDiffusion(SimulatorType &sim, const std::vector< std::size_t > &ctrlIndices, const std::size_t target)
Application of the Grover diffusion operator to already marked register. Follows the Q = -A S_0 A str...
Definition: diffusion.hpp:49