@@ -44,7 +44,7 @@ namespace simulator
4444 complex matrix[2 ][2 ]; // 2x2 matrix that stores various types of gates
4545 };
4646
47- static inline const constexpr qgate_2x2 pre_defined_qgates[7 ] = {
47+ static constexpr qgate_2x2 pre_defined_qgates[7 ] = {
4848 {IDENTITY, {{1 , 0 }, {0 , 1 }}},
4949 {PAULI_X, {{0 , 1 }, {1 , 0 }}},
5050 {PAULI_Y, {{0 , {0 , -1 }}, {{0 , 1 }, 0 }}},
@@ -55,13 +55,13 @@ namespace simulator
5555 };
5656
5757 static void apply_predefined_gate (complex (&__s)[1 << n_qubits], const gate_type &__g_type, const std::size_t &qubit_target);
58- static qgate_2x2 &get_theta_gate (qgate_2x2 &__g, const enum gate_type &__g_type, const double &__theta);
58+ static qgate_2x2 &get_theta_gate (qgate_2x2 &__g, const gate_type &__g_type, const double &__theta);
5959 static void apply_theta_gate (complex (&__s)[1 << n_qubits], const gate_type &__g_type, const double &__theta, const std::size_t &qubit_target);
6060 static void apply_2qubit_gate (complex (&__s)[1 << n_qubits], const gate_type &__g_type, const std::size_t &q_control, const std::size_t &q_target);
6161
6262 private:
6363 // a vector-space (hilbert-space) defined over complex numbers C
64- // 1 << n_qubit translates to 2^N, where N is the the number of qubit the hilbert-space(quantum-system) supports
64+ // 1 << n_qubit translates to 2^N, where N is the number of qubit the hilbert-space(quantum-system) supports
6565 // memory consumption on x86_64 architecture for N-qubit system is: f(N) = 16 * 2^abs(N) bytes, that is exponential growth
6666 // Initially, the hilbert-space is defined as 1 + 0i, 0 + 0i, 0 + 0i, 0 + 0i, 0 + 0i, ..., 0 + 0i
6767 complex M_qubits[1 << n_qubits] = {};
@@ -85,16 +85,17 @@ namespace simulator
8585 const complex (&get_qubits () const )[1 << n_qubits];
8686 const constexpr std::size_t get_size () const ;
8787 const constexpr std::size_t memory_consumption () const ;
88+ const constexpr std::size_t no_of_qubits () const ;
8889 std::size_t measure ();
8990 ~qubit () = default ;
9091 };
9192
9293 template <std::size_t n_qubits>
9394 void qubit<n_qubits>::apply_predefined_gate(complex (&__s)[1 << n_qubits], const gate_type &__g_type, const std::size_t &qubit_target)
9495 {
95- std::size_t stride = 1 << qubit_target; // Distance between paired indices
96+ const std::size_t stride = 1 << qubit_target; // Distance between paired indices
9697
97- for (std::size_t i = 0 ; i < ( 1 << n_qubits) ; i += 2 * stride)
98+ for (std::size_t i = 0 ; i < 1 << n_qubits; i += 2 * stride)
9899 {
99100 for (std::size_t j = 0 ; j < stride; ++j)
100101 {
@@ -105,40 +106,40 @@ namespace simulator
105106 complex a = __s[idx0];
106107 complex b = __s[idx1];
107108
108- __s[idx0] = pre_defined_qgates[( std::size_t ) __g_type].matrix [0 ][0 ] * a + pre_defined_qgates[( std::size_t ) __g_type].matrix [0 ][1 ] * b;
109- __s[idx1] = pre_defined_qgates[( std::size_t ) __g_type].matrix [1 ][0 ] * a + pre_defined_qgates[( std::size_t ) __g_type].matrix [1 ][1 ] * b;
109+ __s[idx0] = pre_defined_qgates[static_cast < std::size_t >( __g_type) ].matrix [0 ][0 ] * a + pre_defined_qgates[static_cast < std::size_t >( __g_type) ].matrix [0 ][1 ] * b;
110+ __s[idx1] = pre_defined_qgates[static_cast < std::size_t >( __g_type) ].matrix [1 ][0 ] * a + pre_defined_qgates[static_cast < std::size_t >( __g_type) ].matrix [1 ][1 ] * b;
110111 }
111112 }
112113 }
113114
114115 template <std::size_t n_qubits>
115- qubit<n_qubits>::qgate_2x2 &qubit<n_qubits>::get_theta_gate(qubit<n_qubits>:: qgate_2x2 &__g, const enum gate_type &__g_type, const double &__theta)
116+ qubit<n_qubits>::qgate_2x2 &qubit<n_qubits>::get_theta_gate(qgate_2x2 &__g, const gate_type &__g_type, const double &__theta)
116117 {
117118 __g.type = __g_type;
118119 switch (__g_type)
119120 {
120- case qubit<n_qubits>:: gate_type::PHASE_GENERAL_SHIFT:
121+ case gate_type::PHASE_GENERAL_SHIFT:
121122 __g.matrix [0 ][0 ] = 1.0 ;
122123 __g.matrix [0 ][1 ] = 0.0 ;
123124 __g.matrix [1 ][0 ] = 0.0 ;
124125 __g.matrix [1 ][1 ] = std::polar (1.0 , __theta);
125126 break ;
126127
127- case qubit<n_qubits>:: gate_type::ROTATION_X:
128+ case gate_type::ROTATION_X:
128129 __g.matrix [0 ][0 ] = std::__complex_cos<double >(__theta / 2.0 );
129130 __g.matrix [0 ][1 ] = (complex ){0.0 , -1.0 } * std::__complex_sin<double >(__theta / 2.0 );
130131 __g.matrix [1 ][0 ] = (complex ){0.0 , -1.0 } * std::__complex_sin<double >(__theta / 2.0 );
131132 __g.matrix [1 ][1 ] = std::__complex_cos<double >(__theta / 2.0 );
132133 break ;
133134
134- case qubit<n_qubits>:: gate_type::ROTATION_Y:
135+ case gate_type::ROTATION_Y:
135136 __g.matrix [0 ][0 ] = std::__complex_cos<double >(__theta / 2.0 );
136137 __g.matrix [0 ][1 ] = -std::__complex_sin<double >(__theta / 2.0 );
137138 __g.matrix [1 ][0 ] = std::__complex_sin<double >(__theta / 2.0 );
138139 __g.matrix [1 ][1 ] = std::__complex_cos<double >(__theta / 2.0 );
139140 break ;
140141
141- case qubit<n_qubits>:: gate_type::ROTATION_Z:
142+ case gate_type::ROTATION_Z:
142143 __g.matrix [0 ][0 ] = std::polar (1.0 , -__theta / 2.0 );
143144 __g.matrix [0 ][1 ] = 0.0 ;
144145 __g.matrix [1 ][0 ] = 0.0 ;
@@ -148,19 +149,18 @@ namespace simulator
148149 default :
149150 std::fprintf (stderr, " error: invalid gate selected '%u'\n " , (unsigned )__g_type);
150151 std::exit (EXIT_FAILURE);
151- break ;
152152 }
153153 return __g;
154154 }
155155
156156 template <std::size_t n_qubits>
157157 void qubit<n_qubits>::apply_theta_gate(complex (&__s)[1 << n_qubits], const gate_type &__g_type, const double &__theta, const std::size_t &qubit_target)
158158 {
159- std::size_t stride = 1 << qubit_target; // Distance between paired indices
160- qubit<n_qubits>:: qgate_2x2 __g;
161- __g = qubit<n_qubits> ::get_theta_gate (__g, __g_type, __theta);
159+ const std::size_t stride = 1 << qubit_target; // Distance between paired indices
160+ qgate_2x2 __g;
161+ __g = qubit::get_theta_gate (__g, __g_type, __theta);
162162
163- for (std::size_t i = 0 ; i < ( 1 << n_qubits) ; i += 2 * stride)
163+ for (std::size_t i = 0 ; i < 1 << n_qubits; i += 2 * stride)
164164 {
165165 for (std::size_t j = 0 ; j < stride; ++j)
166166 {
@@ -186,7 +186,7 @@ namespace simulator
186186 std::exit (EXIT_FAILURE);
187187 }
188188
189- if (__g_type == qubit<n_qubits>:: gate_type::CONTROLLED_NOT)
189+ if (__g_type == gate_type::CONTROLLED_NOT)
190190 {
191191 for (std::size_t i = 0 ; i < (1 << n_qubits); i++)
192192 {
@@ -201,7 +201,7 @@ namespace simulator
201201 }
202202 }
203203 }
204- else if (__g_type == qubit<n_qubits>:: gate_type::CONTROLLED_Z)
204+ else if (__g_type == gate_type::CONTROLLED_Z)
205205 {
206206 for (std::size_t i = 0 ; i < (1 << n_qubits); i++)
207207 {
@@ -211,13 +211,13 @@ namespace simulator
211211 }
212212 }
213213 }
214- else if (__g_type == qubit<n_qubits>:: gate_type::SWAP_GATE)
214+ else if (__g_type == gate_type::SWAP_GATE)
215215 {
216216 for (std::size_t i = 0 ; i < (1 << n_qubits); ++i)
217217 {
218218 // Extract the bits at positions q_control and q_target.
219- std::size_t bit_q1 = (i >> q_control) & 1 ;
220- std::size_t bit_q2 = (i >> q_target) & 1 ;
219+ const std::size_t bit_q1 = (i >> q_control) & 1 ;
220+ const std::size_t bit_q2 = (i >> q_target) & 1 ;
221221
222222 // Only need to swap if the bits differ.
223223 if (bit_q1 != bit_q2)
@@ -243,98 +243,98 @@ namespace simulator
243243 template <std::size_t n_qubits>
244244 qubit<n_qubits> &qubit<n_qubits>::apply_identity(const std::size_t &q_target)
245245 {
246- qubit<n_qubits> ::apply_predefined_gate (this ->M_qubits , qubit<n_qubits>:: gate_type::IDENTITY, q_target);
246+ qubit::apply_predefined_gate (this ->M_qubits , gate_type::IDENTITY, q_target);
247247 return *this ;
248248 }
249249
250250 template <std::size_t n_qubits>
251251 qubit<n_qubits> &qubit<n_qubits>::apply_pauli_x(const std::size_t &q_target)
252252 {
253- qubit<n_qubits> ::apply_predefined_gate (this ->M_qubits , qubit<n_qubits>:: gate_type::PAULI_X, q_target);
253+ qubit::apply_predefined_gate (this ->M_qubits , gate_type::PAULI_X, q_target);
254254 return *this ;
255255 }
256256
257257 template <std::size_t n_qubits>
258258 qubit<n_qubits> &qubit<n_qubits>::apply_pauli_y(const std::size_t &q_target)
259259 {
260- qubit<n_qubits> ::apply_predefined_gate (this ->M_qubits , qubit<n_qubits>:: gate_type::PAULI_Y, q_target);
260+ qubit::apply_predefined_gate (this ->M_qubits , gate_type::PAULI_Y, q_target);
261261 return *this ;
262262 }
263263
264264 template <std::size_t n_qubits>
265265 qubit<n_qubits> &qubit<n_qubits>::apply_pauli_z(const std::size_t &q_target)
266266 {
267- qubit<n_qubits> ::apply_predefined_gate (this ->M_qubits , qubit<n_qubits>:: gate_type::PAULI_Z, q_target);
267+ qubit::apply_predefined_gate (this ->M_qubits , gate_type::PAULI_Z, q_target);
268268 return *this ;
269269 }
270270
271271 template <std::size_t n_qubits>
272272 qubit<n_qubits> &qubit<n_qubits>::apply_hadamard(const std::size_t &q_target)
273273 {
274- qubit<n_qubits> ::apply_predefined_gate (this ->M_qubits , qubit<n_qubits>:: gate_type::HADAMARD, q_target);
274+ qubit::apply_predefined_gate (this ->M_qubits , gate_type::HADAMARD, q_target);
275275 return *this ;
276276 }
277277
278278 template <std::size_t n_qubits>
279279 qubit<n_qubits> &qubit<n_qubits>::apply_phase_pi_2_shift(const std::size_t &q_target)
280280 {
281- qubit<n_qubits> ::apply_predefined_gate (this ->M_qubits , qubit<n_qubits>:: gate_type::PHASE_PI_2_SHIFT, q_target);
281+ qubit::apply_predefined_gate (this ->M_qubits , gate_type::PHASE_PI_2_SHIFT, q_target);
282282 return *this ;
283283 }
284284
285285 template <std::size_t n_qubits>
286286 qubit<n_qubits> &qubit<n_qubits>::apply_phase_pi_4_shift(const std::size_t &q_target)
287287 {
288- qubit<n_qubits> ::apply_predefined_gate (this ->M_qubits , qubit<n_qubits>:: gate_type::PHASE_PI_4_SHIFT, q_target);
288+ qubit::apply_predefined_gate (this ->M_qubits , gate_type::PHASE_PI_4_SHIFT, q_target);
289289 return *this ;
290290 }
291291
292292 template <std::size_t n_qubits>
293293 qubit<n_qubits> &qubit<n_qubits>::apply_phase_general_shift(const double &_theta, const std::size_t &q_target)
294294 {
295- qubit<n_qubits> ::apply_theta_gate (this ->M_qubits , qubit<n_qubits>:: gate_type::PHASE_GENERAL_SHIFT, _theta, q_target);
295+ qubit::apply_theta_gate (this ->M_qubits , gate_type::PHASE_GENERAL_SHIFT, _theta, q_target);
296296 return *this ;
297297 }
298298
299299 template <std::size_t n_qubits>
300300 qubit<n_qubits> &qubit<n_qubits>::apply_rotation_x(const double &_theta, const std::size_t &q_target)
301301 {
302- qubit<n_qubits> ::apply_theta_gate (this ->M_qubits , qubit<n_qubits>:: gate_type::ROTATION_X, _theta, q_target);
302+ qubit::apply_theta_gate (this ->M_qubits , gate_type::ROTATION_X, _theta, q_target);
303303 return *this ;
304304 }
305305
306306 template <std::size_t n_qubits>
307307 qubit<n_qubits> &qubit<n_qubits>::apply_rotation_y(const double &_theta, const std::size_t &q_target)
308308 {
309- qubit<n_qubits> ::apply_theta_gate (this ->M_qubits , qubit<n_qubits>:: gate_type::ROTATION_Y, _theta, q_target);
309+ qubit::apply_theta_gate (this ->M_qubits , gate_type::ROTATION_Y, _theta, q_target);
310310 return *this ;
311311 }
312312
313313 template <std::size_t n_qubits>
314314 qubit<n_qubits> &qubit<n_qubits>::apply_rotation_z(const double &_theta, const std::size_t &q_target)
315315 {
316- qubit<n_qubits> ::apply_theta_gate (this ->M_qubits , qubit<n_qubits>:: gate_type::ROTATION_Z, _theta, q_target);
316+ qubit::apply_theta_gate (this ->M_qubits , gate_type::ROTATION_Z, _theta, q_target);
317317 return *this ;
318318 }
319319
320320 template <std::size_t n_qubits>
321321 qubit<n_qubits> &qubit<n_qubits>::apply_cnot(const std::size_t &q_control, const std::size_t &q_target)
322322 {
323- qubit<n_qubits> ::apply_2qubit_gate (this ->M_qubits , qubit<n_qubits>:: gate_type::CONTROLLED_NOT, q_control, q_target);
323+ qubit::apply_2qubit_gate (this ->M_qubits , gate_type::CONTROLLED_NOT, q_control, q_target);
324324 return *this ;
325325 }
326326
327327 template <std::size_t n_qubits>
328328 qubit<n_qubits> &qubit<n_qubits>::apply_cz(const std::size_t &q_control, const std::size_t &q_target)
329329 {
330- qubit<n_qubits> ::apply_2qubit_gate (this ->M_qubits , qubit<n_qubits>:: gate_type::CONTROLLED_Z, q_control, q_target);
330+ qubit::apply_2qubit_gate (this ->M_qubits , gate_type::CONTROLLED_Z, q_control, q_target);
331331 return *this ;
332332 }
333333
334334 template <std::size_t n_qubits>
335335 qubit<n_qubits> &qubit<n_qubits>::apply_swap(const std::size_t &q_control, const std::size_t &q_target)
336336 {
337- qubit<n_qubits> ::apply_2qubit_gate (this ->M_qubits , qubit<n_qubits>:: gate_type::SWAP_GATE, q_control, q_target);
337+ qubit::apply_2qubit_gate (this ->M_qubits , gate_type::SWAP_GATE, q_control, q_target);
338338 return *this ;
339339 }
340340
@@ -353,7 +353,13 @@ namespace simulator
353353 template <std::size_t n_qubits>
354354 const constexpr std::size_t qubit<n_qubits>::memory_consumption() const
355355 {
356- return sizeof (qubit<n_qubits>::complex ) * (1 << n_qubits);
356+ return sizeof (complex ) * (1 << n_qubits);
357+ }
358+
359+ template <std::size_t n_qubits>
360+ const constexpr std::size_t qubit<n_qubits>::no_of_qubits() const
361+ {
362+ return n_qubits;
357363 }
358364
359365 template <std::size_t n_qubits>
@@ -367,7 +373,7 @@ namespace simulator
367373
368374 std::random_device rd;
369375 std::mt19937 gen (rd ());
370- std::uniform_real_distribution< double > dist (0.0 , tot_prob);
376+ std::uniform_real_distribution dist (0.0 , tot_prob);
371377 double r = dist (gen);
372378
373379 double accum = 0.0 ;
0 commit comments