test_unitaries.cpp
Go to the documentation of this file.
1 
16 #include "catch.hpp"
17 #include "QuEST.h"
18 #include "utilities.hpp"
19 
24 #define PREPARE_TEST(quregVec, quregMatr, refVec, refMatr) \
25  Qureg quregVec = createQureg(NUM_QUBITS, QUEST_ENV); \
26  Qureg quregMatr = createDensityQureg(NUM_QUBITS, QUEST_ENV); \
27  initDebugState(quregVec); \
28  initDebugState(quregMatr); \
29  QVector refVec = toQVector(quregVec); \
30  QMatrix refMatr = toQMatrix(quregMatr);
31 
33 #define CLEANUP_TEST(quregVec, quregMatr) \
34  destroyQureg(quregVec, QUEST_ENV); \
35  destroyQureg(quregMatr, QUEST_ENV);
36 
37 /* allows concise use of Contains in catch's REQUIRE_THROWS_WITH */
38 using Catch::Matchers::Contains;
39 
40 
41 
46 TEST_CASE( "compactUnitary", "[unitaries]" ) {
47 
48  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
49 
50  qcomp a = getRandomReal(-1,1) * expI(getRandomReal(0,2*M_PI));
51  qcomp b = sqrt(1-abs(a)*abs(a)) * expI(getRandomReal(0,2*M_PI));
52  Complex alpha = toComplex( a );
53  Complex beta = toComplex( b );
54  QMatrix op = toQMatrix(alpha, beta);
55 
56  SECTION( "correctness" ) {
57 
58  int target = GENERATE( range(0,NUM_QUBITS) );
59 
60  SECTION( "state-vector" ) {
61 
62  compactUnitary(quregVec, target, alpha, beta);
63  applyReferenceOp(refVec, target, op);
64  REQUIRE( areEqual(quregVec, refVec) );
65  }
66  SECTION( "density-matrix" ) {
67 
68  compactUnitary(quregMatr, target, alpha, beta);
69  applyReferenceOp(refMatr, target, op);
70  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
71  }
72  }
73  SECTION( "input validation" ) {
74 
75  SECTION( "qubit indices" ) {
76 
77  int target = GENERATE( -1, NUM_QUBITS );
78  REQUIRE_THROWS_WITH( compactUnitary(quregVec, target, alpha, beta), Contains("Invalid target") );
79  }
80  SECTION( "unitarity" ) {
81 
82  // unitary when |alpha|^2 + |beta|^2 = 1
83  alpha = {.real=1, .imag=2};
84  beta = {.real=3, .imag=4};
85  REQUIRE_THROWS_WITH( compactUnitary(quregVec, 0, alpha, beta), Contains("unitary") );
86  }
87  }
88  CLEANUP_TEST( quregVec, quregMatr );
89 }
90 
91 
92 
97 TEST_CASE( "controlledCompactUnitary", "[unitaries]" ) {
98 
99  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
100 
101  qcomp a = getRandomReal(-1,1) * expI(getRandomReal(0,2*M_PI));
102  qcomp b = sqrt(1-abs(a)*abs(a)) * expI(getRandomReal(0,2*M_PI));
103  Complex alpha = toComplex( a );
104  Complex beta = toComplex( b );
105  QMatrix op = toQMatrix(alpha, beta);
106 
107  SECTION( "correctness" ) {
108 
109  int target = GENERATE( range(0,NUM_QUBITS) );
110  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
111 
112  SECTION( "state-vector" ) {
113 
114  controlledCompactUnitary(quregVec, control, target, alpha, beta);
115  applyReferenceOp(refVec, control, target, op);
116  REQUIRE( areEqual(quregVec, refVec) );
117  }
118  SECTION( "density-matrix" ) {
119 
120  controlledCompactUnitary(quregMatr, control, target, alpha, beta);
121  applyReferenceOp(refMatr, control, target, op);
122  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
123  }
124  }
125  SECTION( "input validation" ) {
126 
127  SECTION( "control and target collision" ) {
128 
129  int qb = 0;
130  REQUIRE_THROWS_WITH( controlledCompactUnitary(quregVec, qb, qb, alpha, beta), Contains("Control") && Contains("target") );
131  }
132  SECTION( "qubit indices" ) {
133 
134  int qb = GENERATE( -1, NUM_QUBITS );
135  REQUIRE_THROWS_WITH( controlledCompactUnitary(quregVec, qb, 0, alpha, beta), Contains("Invalid control") );
136  REQUIRE_THROWS_WITH( controlledCompactUnitary(quregVec, 0, qb, alpha, beta), Contains("Invalid target") );
137  }
138  SECTION( "unitarity" ) {
139 
140  // unitary when |a|^2 + |b^2 = 1
141  alpha = {.real=1, .imag=2};
142  beta = {.real=3, .imag=4};
143  REQUIRE_THROWS_WITH( controlledCompactUnitary(quregVec, 0, 1, alpha, beta), Contains("unitary") );
144  }
145  }
146  CLEANUP_TEST( quregVec, quregMatr );
147 }
148 
149 
150 
155 TEST_CASE( "controlledMultiQubitUnitary", "[unitaries]" ) {
156 
157  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
158 
159  // figure out max-num targs (inclusive) allowed by hardware backend
160  int maxNumTargs = calcLog2(quregVec.numAmpsPerChunk);
161  if (maxNumTargs >= NUM_QUBITS)
162  maxNumTargs = NUM_QUBITS - 1; // make space for control qubit
163 
164  SECTION( "correctness" ) {
165 
166  // generate all possible qubit arrangements
167  int ctrl = GENERATE( range(0,NUM_QUBITS) );
168  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
169  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs, ctrl) );
170 
171  // for each qubit arrangement, use a new random unitary
172  QMatrix op = getRandomUnitary(numTargs);
173  ComplexMatrixN matr = createComplexMatrixN(numTargs);
174  toComplexMatrixN(op, matr);
175 
176  SECTION( "state-vector" ) {
177 
178  controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr);
179  applyReferenceOp(refVec, ctrl, targs, numTargs, op);
180  REQUIRE( areEqual(quregVec, refVec) );
181  }
182  SECTION( "density-matrix" ) {
183 
184  controlledMultiQubitUnitary(quregMatr, ctrl, targs, numTargs, matr);
185  applyReferenceOp(refMatr, ctrl, targs, numTargs, op);
186  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
187  }
188  destroyComplexMatrixN(matr);
189  }
190  SECTION( "input validation" ) {
191 
192  SECTION( "number of targets" ) {
193 
194  // there cannot be more targets than qubits in register
195  // (numTargs=NUM_QUBITS is caught elsewhere, because that implies ctrl is invalid)
196  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
197  int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
198  ComplexMatrixN matr = createComplexMatrixN(NUM_QUBITS+1); // prevent seg-fault
199  REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, 0, targs, numTargs, matr), Contains("Invalid number of target"));
200  destroyComplexMatrixN(matr);
201  }
202  SECTION( "repetition in targets" ) {
203 
204  int ctrl = 0;
205  int numTargs = 3;
206  int targs[] = {1,2,2};
207  ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
208 
209  REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr), Contains("target") && Contains("unique"));
210  destroyComplexMatrixN(matr);
211  }
212  SECTION( "control and target collision" ) {
213 
214  int numTargs = 3;
215  int targs[] = {0,1,2};
216  int ctrl = targs[GENERATE_COPY( range(0,numTargs) )];
217  ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
218 
219  REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr), Contains("Control") && Contains("target"));
220  destroyComplexMatrixN(matr);
221  }
222  SECTION( "qubit indices" ) {
223 
224  int ctrl = 0;
225  int numTargs = 3;
226  int targs[] = {1,2,3};
227  ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
228 
229  int inv = GENERATE( -1, NUM_QUBITS );
230  ctrl = inv;
231  REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr), Contains("Invalid control") );
232 
233  ctrl = 0; // restore valid ctrl
234  targs[GENERATE_COPY( range(0,numTargs) )] = inv; // make invalid target
235  REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr), Contains("Invalid target") );
236 
237  destroyComplexMatrixN(matr);
238  }
239  SECTION( "unitarity" ) {
240 
241  int ctrl = 0;
242  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
243  ComplexMatrixN matr = createComplexMatrixN(numTargs); // initially zero, hence not-unitary
244 
245  int targs[numTargs];
246  for (int i=0; i<numTargs; i++)
247  targs[i] = i+1;
248 
249  REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, numTargs, matr), Contains("unitary") );
250  destroyComplexMatrixN(matr);
251  }
252  SECTION( "unitary creation" ) {
253 
254  int numTargs = 3;
255  int targs[] = {1,2,3};
256 
257  /* compilers don't auto-initialise to NULL; the below circumstance
258  * only really occurs when 'malloc' returns NULL in createComplexMatrixN,
259  * which actually triggers its own validation. Hence this test is useless
260  * currently.
261  */
262  ComplexMatrixN matr;
263  matr.real = NULL;
264  matr.imag = NULL;
265  REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, 0, targs, numTargs, matr), Contains("created") );
266  }
267  SECTION( "unitary dimensions" ) {
268 
269  int ctrl = 0;
270  int targs[2] = {1,2};
272 
273  REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, ctrl, targs, 2, matr), Contains("matrix size"));
274  destroyComplexMatrixN(matr);
275  }
276  SECTION( "unitary fits in node" ) {
277 
278  // pretend we have a very limited distributed memory (judged by matr size)
279  quregVec.numAmpsPerChunk = 1;
280  int qb[] = {1,2};
281  ComplexMatrixN matr = createComplexMatrixN(2); // prevents seg-fault if validation doesn't trigger
282  REQUIRE_THROWS_WITH( controlledMultiQubitUnitary(quregVec, 0, qb, 2, matr), Contains("targets too many qubits"));
283  destroyComplexMatrixN(matr);
284  }
285  }
286  CLEANUP_TEST( quregVec, quregMatr );
287 }
288 
289 
290 
295 TEST_CASE( "controlledNot", "[unitaries]" ) {
296 
297  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
298  QMatrix op{{0,1},{1,0}};
299 
300  SECTION( "correctness" ) {
301 
302  int target = GENERATE( range(0,NUM_QUBITS) );
303  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
304 
305  SECTION( "state-vector" ) {
306 
307  controlledNot(quregVec, control, target);
308  applyReferenceOp(refVec, control, target, op);
309  REQUIRE( areEqual(quregVec, refVec) );
310  }
311  SECTION( "density-matrix" ) {
312 
313  controlledNot(quregMatr, control, target);
314  applyReferenceOp(refMatr, control, target, op);
315  REQUIRE( areEqual(quregMatr, refMatr) );
316  }
317  }
318  SECTION( "input validation" ) {
319 
320  SECTION( "control and target collision" ) {
321 
322  int qb = GENERATE( range(0,NUM_QUBITS) );
323  REQUIRE_THROWS_WITH( controlledNot(quregVec, qb, qb), Contains("Control") && Contains("target") );
324  }
325  SECTION( "qubit indices" ) {
326 
327  int qb = GENERATE( -1, NUM_QUBITS );
328  REQUIRE_THROWS_WITH( controlledNot(quregVec, qb, 0), Contains("Invalid control") );
329  REQUIRE_THROWS_WITH( controlledNot(quregVec, 0, qb), Contains("Invalid target") );
330  }
331  }
332  CLEANUP_TEST( quregVec, quregMatr );
333 }
334 
335 
336 
341 TEST_CASE( "controlledPauliY", "[unitaries]" ) {
342 
343  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
344  QMatrix op{{0,-1i},{1i,0}};
345 
346  SECTION( "correctness" ) {
347 
348  int target = GENERATE( range(0,NUM_QUBITS) );
349  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
350 
351  SECTION( "state-vector" ) {
352 
353  controlledPauliY(quregVec, control, target);
354  applyReferenceOp(refVec, control, target, op);
355  REQUIRE( areEqual(quregVec, refVec) );
356  }
357  SECTION( "density-matrix" ) {
358 
359  controlledPauliY(quregMatr, control, target);
360  applyReferenceOp(refMatr, control, target, op);
361  REQUIRE( areEqual(quregMatr, refMatr) );
362  }
363  }
364  SECTION( "input validation" ) {
365 
366  SECTION( "control and target collision" ) {
367 
368  int qb = GENERATE( range(0,NUM_QUBITS) );
369  REQUIRE_THROWS_WITH( controlledPauliY(quregVec, qb, qb), Contains("Control") && Contains("target") );
370  }
371  SECTION( "qubit indices" ) {
372 
373  int qb = GENERATE( -1, NUM_QUBITS );
374  REQUIRE_THROWS_WITH( controlledPauliY(quregVec, qb, 0), Contains("Invalid control") );
375  REQUIRE_THROWS_WITH( controlledPauliY(quregVec, 0, qb), Contains("Invalid target") );
376  }
377  }
378  CLEANUP_TEST( quregVec, quregMatr );
379 }
380 
381 
382 
387 TEST_CASE( "controlledPhaseFlip", "[unitaries]" ) {
388 
389  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
390  QMatrix op{{1,0},{0,-1}};
391 
392  SECTION( "correctness" ) {
393 
394  int target = GENERATE( range(0,NUM_QUBITS) );
395  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
396 
397  SECTION( "state-vector" ) {
398 
399  controlledPhaseFlip(quregVec, control, target);
400  applyReferenceOp(refVec, control, target, op);
401  REQUIRE( areEqual(quregVec, refVec) );
402  }
403  SECTION( "density-matrix" ) {
404 
405  controlledPhaseFlip(quregMatr, control, target);
406  applyReferenceOp(refMatr, control, target, op);
407  REQUIRE( areEqual(quregMatr, refMatr) );
408  }
409  }
410  SECTION( "input validation" ) {
411 
412  SECTION( "control and target collision" ) {
413 
414  int qb = GENERATE( range(0,NUM_QUBITS) );
415  REQUIRE_THROWS_WITH( controlledPhaseFlip(quregVec, qb, qb), Contains("Control") && Contains("target") );
416  }
417  SECTION( "qubit indices" ) {
418 
419  int qb = GENERATE( -1, NUM_QUBITS );
420  REQUIRE_THROWS_WITH( controlledPhaseFlip(quregVec, qb, 0), Contains("Invalid control") );
421  REQUIRE_THROWS_WITH( controlledPhaseFlip(quregVec, 0, qb), Contains("Invalid target") );
422  }
423  }
424  CLEANUP_TEST( quregVec, quregMatr );
425 }
426 
427 
428 
433 TEST_CASE( "controlledPhaseShift", "[unitaries]" ) {
434 
435  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
436  qreal param = getRandomReal(-2*M_PI, 2*M_PI);
437  QMatrix op{{1,0},{0,expI(param)}};
438 
439  SECTION( "correctness" ) {
440 
441  int target = GENERATE( range(0,NUM_QUBITS) );
442  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
443 
444  SECTION( "state-vector" ) {
445 
446  controlledPhaseShift(quregVec, control, target, param);
447  applyReferenceOp(refVec, control, target, op);
448  REQUIRE( areEqual(quregVec, refVec) );
449  }
450  SECTION( "density-matrix" ) {
451 
452  controlledPhaseShift(quregMatr, control, target, param);
453  applyReferenceOp(refMatr, control, target, op);
454  REQUIRE( areEqual(quregMatr, refMatr) );
455  }
456  }
457  SECTION( "input validation" ) {
458 
459  SECTION( "control and target collision" ) {
460 
461  int qb = GENERATE( range(0,NUM_QUBITS) );
462  REQUIRE_THROWS_WITH( controlledPhaseShift(quregVec, qb, qb, param), Contains("Control") && Contains("target") );
463  }
464  SECTION( "qubit indices" ) {
465 
466  int qb = GENERATE( -1, NUM_QUBITS );
467  REQUIRE_THROWS_WITH( controlledPhaseShift(quregVec, qb, 0, param), Contains("Invalid control") );
468  REQUIRE_THROWS_WITH( controlledPhaseShift(quregVec, 0, qb, param), Contains("Invalid target") );
469  }
470  }
471  CLEANUP_TEST( quregVec, quregMatr );
472 }
473 
474 
475 
480 TEST_CASE( "controlledRotateAroundAxis", "[unitaries]" ) {
481 
482  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
483 
484  // each test will use a random parameter and axis vector
485  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
486  Vector vec = {.x=getRandomReal(-1,1), .y=getRandomReal(-1,1), .z=getRandomReal(-1,1)};
487 
488  // Rn(a) = cos(a/2)I - i sin(a/2) n . paulivector
489  // (pg 24 of vcpc.univie.ac.at/~ian/hotlist/qc/talks/bloch-sphere-rotations.pdf)
490  qreal c = cos(param/2);
491  qreal s = sin(param/2);
492  qreal m = sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z);
493  QMatrix op{{c - 1i*vec.z*s/m, -(vec.y + 1i*vec.x)*s/m},
494  {(vec.y - 1i*vec.x)*s/m, c + 1i*vec.z*s/m}};
495 
496  SECTION( "correctness" ) {
497 
498  int target = GENERATE( range(0,NUM_QUBITS) );
499  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
500 
501  SECTION( "state-vector" ) {
502 
503  controlledRotateAroundAxis(quregVec, control, target, param, vec);
504  applyReferenceOp(refVec, control, target, op);
505  REQUIRE( areEqual(quregVec, refVec) );
506  }
507  SECTION( "density-matrix" ) {
508 
509  controlledRotateAroundAxis(quregMatr, control, target, param, vec);
510  applyReferenceOp(refMatr, control, target, op);
511  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
512  }
513  }
514  SECTION( "input validation" ) {
515 
516  SECTION( "control and target collision" ) {
517 
518  int qb = GENERATE( range(0,NUM_QUBITS) );
519  REQUIRE_THROWS_WITH( controlledRotateAroundAxis(quregVec, qb, qb, param, vec), Contains("Control") && Contains("target") );
520  }
521  SECTION( "qubit indices" ) {
522 
523  int qb = GENERATE( -1, NUM_QUBITS );
524  REQUIRE_THROWS_WITH( controlledRotateAroundAxis(quregVec, qb, 0, param, vec), Contains("Invalid control") );
525  REQUIRE_THROWS_WITH( controlledRotateAroundAxis(quregVec, 0, qb, param, vec), Contains("Invalid target") );
526  }
527  SECTION( "zero rotation axis" ) {
528 
529  vec = {.x=0, .y=0, .z=0};
530  REQUIRE_THROWS_WITH( controlledRotateAroundAxis(quregVec, 0, 1, param, vec), Contains("Invalid axis") && Contains("zero") );
531  }
532  }
533  CLEANUP_TEST( quregVec, quregMatr );
534 }
535 
536 
537 
542 TEST_CASE( "controlledRotateX", "[unitaries]" ) {
543 
544  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
545  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
546  QMatrix op{{cos(param/2), -1i*sin(param/2)}, {-1i*sin(param/2), cos(param/2)}};
547 
548  SECTION( "correctness" ) {
549 
550  int target = GENERATE( range(0,NUM_QUBITS) );
551  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
552 
553  SECTION( "state-vector" ) {
554 
555  controlledRotateX(quregVec, control, target, param);
556  applyReferenceOp(refVec, control, target, op);
557  REQUIRE( areEqual(quregVec, refVec) );
558  }
559  SECTION( "density-matrix" ) {
560 
561  controlledRotateX(quregMatr, control, target, param);
562  applyReferenceOp(refMatr, control, target, op);
563  REQUIRE( areEqual(quregMatr, refMatr) );
564  }
565  }
566  SECTION( "input validation" ) {
567 
568  SECTION( "control and target collision" ) {
569 
570  int qb = GENERATE( range(0,NUM_QUBITS) );
571  REQUIRE_THROWS_WITH( controlledRotateX(quregVec, qb, qb, param), Contains("Control") && Contains("target") );
572  }
573  SECTION( "qubit indices" ) {
574 
575  int qb = GENERATE( -1, NUM_QUBITS );
576  REQUIRE_THROWS_WITH( controlledRotateX(quregVec, qb, 0, param), Contains("Invalid control") );
577  REQUIRE_THROWS_WITH( controlledRotateX(quregVec, 0, qb, param), Contains("Invalid target") );
578  }
579  }
580  CLEANUP_TEST( quregVec, quregMatr );
581 }
582 
583 
584 
589 TEST_CASE( "controlledRotateY", "[unitaries]" ) {
590 
591  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
592  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
593  QMatrix op{{cos(param/2), -sin(param/2)},{sin(param/2), cos(param/2)}};
594 
595  SECTION( "correctness" ) {
596 
597  int target = GENERATE( range(0,NUM_QUBITS) );
598  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
599 
600  SECTION( "state-vector" ) {
601 
602  controlledRotateY(quregVec, control, target, param);
603  applyReferenceOp(refVec, control, target, op);
604  REQUIRE( areEqual(quregVec, refVec) );
605  }
606  SECTION( "density-matrix" ) {
607 
608  controlledRotateY(quregMatr, control, target, param);
609  applyReferenceOp(refMatr, control, target, op);
610  REQUIRE( areEqual(quregMatr, refMatr, 2*REAL_EPS) );
611  }
612  }
613  SECTION( "input validation" ) {
614 
615  SECTION( "control and target collision" ) {
616 
617  int qb = GENERATE( range(0,NUM_QUBITS) );
618  REQUIRE_THROWS_WITH( controlledRotateY(quregVec, qb, qb, param), Contains("Control") && Contains("target") );
619  }
620  SECTION( "qubit indices" ) {
621 
622  int qb = GENERATE( -1, NUM_QUBITS );
623  REQUIRE_THROWS_WITH( controlledRotateY(quregVec, qb, 0, param), Contains("Invalid control") );
624  REQUIRE_THROWS_WITH( controlledRotateY(quregVec, 0, qb, param), Contains("Invalid target") );
625  }
626  }
627  CLEANUP_TEST( quregVec, quregMatr );
628 }
629 
630 
631 
636 TEST_CASE( "controlledRotateZ", "[unitaries]" ) {
637 
638  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
639  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
640  QMatrix op{{expI(-param/2.),0},{0,expI(param/2.)}};
641 
642  SECTION( "correctness" ) {
643 
644  int target = GENERATE( range(0,NUM_QUBITS) );
645  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
646 
647  SECTION( "state-vector" ) {
648 
649  controlledRotateZ(quregVec, control, target, param);
650  applyReferenceOp(refVec, control, target, op);
651  REQUIRE( areEqual(quregVec, refVec) );
652  }
653  SECTION( "density-matrix" ) {
654 
655  controlledRotateZ(quregMatr, control, target, param);
656  applyReferenceOp(refMatr, control, target, op);
657  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
658  }
659  }
660  SECTION( "input validation" ) {
661 
662  SECTION( "control and target collision" ) {
663 
664  int qb = GENERATE( range(0,NUM_QUBITS) );
665  REQUIRE_THROWS_WITH( controlledRotateZ(quregVec, qb, qb, param), Contains("Control") && Contains("target") );
666  }
667  SECTION( "qubit indices" ) {
668 
669  int qb = GENERATE( -1, NUM_QUBITS );
670  REQUIRE_THROWS_WITH( controlledRotateZ(quregVec, qb, 0, param), Contains("Invalid control") );
671  REQUIRE_THROWS_WITH( controlledRotateZ(quregVec, 0, qb, param), Contains("Invalid target") );
672  }
673  }
674  CLEANUP_TEST( quregVec, quregMatr );
675 }
676 
677 
678 
683 TEST_CASE( "controlledTwoQubitUnitary", "[unitaries]" ) {
684 
685  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
686 
687  // in distributed mode, each node must be able to fit all amps modified by unitary
688  REQUIRE( quregVec.numAmpsPerChunk >= 4 );
689 
690  // every test will use a unique random matrix
691  QMatrix op = getRandomUnitary(2);
692  ComplexMatrix4 matr = toComplexMatrix4(op);
693 
694  SECTION( "correctness" ) {
695 
696  int targ1 = GENERATE( range(0,NUM_QUBITS) );
697  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
698  int control = GENERATE_COPY( filter([=](int c){ return c!=targ1 && c!=targ2; }, range(0,NUM_QUBITS)) );
699 
700  SECTION( "state-vector" ) {
701 
702  controlledTwoQubitUnitary(quregVec, control, targ1, targ2, matr);
703  applyReferenceOp(refVec, control, targ1, targ2, op);
704  REQUIRE( areEqual(quregVec, refVec) );
705  }
706  SECTION( "density-matrix" ) {
707 
708  controlledTwoQubitUnitary(quregMatr, control, targ1, targ2, matr);
709  applyReferenceOp(refMatr, control, targ1, targ2, op);
710  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
711  }
712  }
713  SECTION( "input validation" ) {
714 
715  SECTION( "repetition of targets" ) {
716  int targ = 0;
717  int ctrl = 1;
718  REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, ctrl, targ, targ, matr), Contains("target") && Contains("unique") );
719  }
720  SECTION( "control and target collision" ) {
721 
722  int targ1 = 1;
723  int targ2 = 2;
724  int ctrl = GENERATE( 1,2 ); // catch2 bug; can't do GENERATE_COPY( targ1, targ2 )
725  REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, ctrl, targ1, targ2, matr), Contains("Control") && Contains("target") );
726  }
727  SECTION( "qubit indices" ) {
728 
729  // valid config
730  int ctrl = 0;
731  int targ1 = 1;
732  int targ2 = 2;
733 
734  int qb = GENERATE( -1, NUM_QUBITS );
735  REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, qb, targ1, targ2, matr), Contains("Invalid control") );
736  REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, ctrl, qb, targ2, matr), Contains("Invalid target") );
737  REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, ctrl, targ1, qb, matr), Contains("Invalid target") );
738  }
739  SECTION( "unitarity" ) {
740 
741  matr.real[0][0] = 0; // break matr unitarity
742  REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, 0, 1, 2, matr), Contains("unitary") );
743  }
744  SECTION( "unitary fits in node" ) {
745 
746  // pretend we have a very limited distributed memory
747  quregVec.numAmpsPerChunk = 1;
748  REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, 0, 1, 2, matr), Contains("targets too many qubits"));
749  }
750  }
751  CLEANUP_TEST( quregVec, quregMatr );
752 }
753 
754 
755 
760 TEST_CASE( "controlledUnitary", "[unitaries]" ) {
761 
762  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
763  QMatrix op = getRandomUnitary(1);
764  ComplexMatrix2 matr = toComplexMatrix2(op);
765 
766  SECTION( "correctness" ) {
767 
768  int target = GENERATE( range(0,NUM_QUBITS) );
769  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
770 
771  SECTION( "state-vector" ) {
772 
773  controlledUnitary(quregVec, control, target, matr);
774  applyReferenceOp(refVec, control, target, op);
775  REQUIRE( areEqual(quregVec, refVec) );
776  }
777  SECTION( "density-matrix" ) {
778 
779  controlledUnitary(quregMatr, control, target, matr);
780  applyReferenceOp(refMatr, control, target, op);
781  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
782  }
783  }
784  SECTION( "input validation" ) {
785 
786  SECTION( "control and target collision" ) {
787 
788  int qb = GENERATE( range(0,NUM_QUBITS) );
789  REQUIRE_THROWS_WITH( controlledUnitary(quregVec, qb, qb, matr), Contains("Control") && Contains("target") );
790  }
791  SECTION( "qubit indices" ) {
792 
793  int qb = GENERATE( -1, NUM_QUBITS );
794  REQUIRE_THROWS_WITH( controlledUnitary(quregVec, qb, 0, matr), Contains("Invalid control") );
795  REQUIRE_THROWS_WITH( controlledUnitary(quregVec, 0, qb, matr), Contains("Invalid target") );
796  }
797  SECTION( "unitarity" ) {
798 
799  matr.real[0][0] = 0; // break unitarity
800  REQUIRE_THROWS_WITH( controlledUnitary(quregVec, 0, 1, matr), Contains("unitary") );
801  }
802  }
803  CLEANUP_TEST( quregVec, quregMatr );
804 }
805 
806 
807 
812 TEST_CASE( "hadamard", "[unitaries]" ) {
813 
814  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
815  qreal a = 1/sqrt(2);
816  QMatrix op{{a,a},{a,-a}};
817 
818  SECTION( "correctness" ) {
819 
820  int target = GENERATE( range(0,NUM_QUBITS) );
821 
822  SECTION( "state-vector ") {
823 
824  hadamard(quregVec, target);
825  applyReferenceOp(refVec, target, op);
826  REQUIRE( areEqual(quregVec, refVec) );
827  }
828  SECTION( "density-matrix" ) {
829 
830  hadamard(quregMatr, target);
831  applyReferenceOp(refMatr, target, op);
832  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
833  }
834  }
835  SECTION( "input validation" ) {
836 
837  SECTION( "qubit indices" ) {
838 
839  int target = GENERATE( -1, NUM_QUBITS );
840  REQUIRE_THROWS_WITH( hadamard(quregVec, target), Contains("Invalid target") );
841  }
842  }
843  CLEANUP_TEST( quregVec, quregMatr );
844 }
845 
846 
847 
852 TEST_CASE( "multiControlledMultiQubitUnitary", "[unitaries]" ) {
853 
854  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
855 
856  // figure out max-num targs (inclusive) allowed by hardware backend
857  int maxNumTargs = calcLog2(quregVec.numAmpsPerChunk);
858  if (maxNumTargs >= NUM_QUBITS)
859  maxNumTargs = NUM_QUBITS - 1; // leave room for min-number of control qubits
860 
861  SECTION( "correctness" ) {
862 
863  // try all possible numbers of targets and controls
864  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
865  int maxNumCtrls = NUM_QUBITS - numTargs;
866  int numCtrls = GENERATE_COPY( range(1,maxNumCtrls+1) );
867 
868  // generate all possible valid qubit arrangements
869  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
870  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, targs, numTargs) );
871 
872  // for each qubit arrangement, use a new random unitary
873  QMatrix op = getRandomUnitary(numTargs);
874  ComplexMatrixN matr = createComplexMatrixN(numTargs);
875  toComplexMatrixN(op, matr);
876 
877  SECTION( "state-vector" ) {
878 
879  multiControlledMultiQubitUnitary(quregVec, ctrls, numCtrls, targs, numTargs, matr);
880  applyReferenceOp(refVec, ctrls, numCtrls, targs, numTargs, op);
881  REQUIRE( areEqual(quregVec, refVec) );
882  }
883  SECTION( "density-matrix" ) {
884 
885  multiControlledMultiQubitUnitary(quregMatr, ctrls, numCtrls, targs, numTargs, matr);
886  applyReferenceOp(refMatr, ctrls, numCtrls, targs, numTargs, op);
887  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
888  }
889  destroyComplexMatrixN(matr);
890  }
891  SECTION( "input validation" ) {
892 
893  SECTION( "number of targets" ) {
894 
895  // there cannot be more targets than qubits in register
896  // (numTargs=NUM_QUBITS is caught elsewhere, because that implies ctrls are invalid)
897  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
898  int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
899  int ctrls[] = {0};
900  ComplexMatrixN matr = createComplexMatrixN(NUM_QUBITS+1); // prevent seg-fault
901  toComplexMatrixN(getRandomUnitary(NUM_QUBITS+1), matr); // ensure unitary
902 
903  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, numTargs, matr), Contains("Invalid number of target"));
904  destroyComplexMatrixN(matr);
905  }
906  SECTION( "repetition in targets" ) {
907 
908  int ctrls[] = {0};
909  int numTargs = 3;
910  int targs[] = {1,2,2};
911  ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
912  toComplexMatrixN(getRandomUnitary(numTargs), matr); // ensure unitary
913 
914  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, numTargs, matr), Contains("target") && Contains("unique"));
915  destroyComplexMatrixN(matr);
916  }
917  SECTION( "number of controls" ) {
918 
919  int numCtrls = GENERATE( -1, 0, NUM_QUBITS, NUM_QUBITS+1 );
920  int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
921  int targs[1] = {0};
923  toComplexMatrixN(getRandomUnitary(1), matr); // ensure unitary
924 
925  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, numCtrls, targs, 1, matr), Contains("Invalid number of control"));
926  destroyComplexMatrixN(matr);
927  }
928  SECTION( "repetition in controls" ) {
929 
930  int ctrls[] = {0,1,1};
931  int targs[] = {3};
933  toComplexMatrixN(getRandomUnitary(1), matr); // ensure unitary
934 
935  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 3, targs, 1, matr), Contains("control") && Contains("unique"));
936  destroyComplexMatrixN(matr);
937  }
938  SECTION( "control and target collision" ) {
939 
940  int ctrls[] = {0,1,2};
941  int targs[] = {3,1,4};
943  toComplexMatrixN(getRandomUnitary(3), matr); // ensure unitary
944 
945  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 3, targs, 3, matr), Contains("Control") && Contains("target") && Contains("disjoint"));
946  destroyComplexMatrixN(matr);
947  }
948  SECTION( "qubit indices" ) {
949 
950  // valid inds
951  int numQb = 2;
952  int qb1[2] = {0,1};
953  int qb2[2] = {2,3};
954  ComplexMatrixN matr = createComplexMatrixN(numQb);
955  toComplexMatrixN(getRandomUnitary(numQb), matr); // ensure unitary
956 
957  // make qb1 invalid
958  int inv = GENERATE( -1, NUM_QUBITS );
959  qb1[GENERATE_COPY(range(0,numQb))] = inv;
960 
961  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, qb1, numQb, qb2, numQb, matr), Contains("Invalid control") );
962  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, qb2, numQb, qb1, numQb, matr), Contains("Invalid target") );
963  destroyComplexMatrixN(matr);
964  }
965  SECTION( "unitarity" ) {
966 
967  int ctrls[1] = {0};
968  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
969  int targs[numTargs];
970  for (int i=0; i<numTargs; i++)
971  targs[i] = i+1;
972 
973  ComplexMatrixN matr = createComplexMatrixN(numTargs); // initially zero, hence not-unitary
974  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, numTargs, matr), Contains("unitary") );
975  destroyComplexMatrixN(matr);
976  }
977  SECTION( "unitary creation" ) {
978 
979  int ctrls[1] = {0};
980  int targs[3] = {1,2,3};
981 
982  /* compilers don't auto-initialise to NULL; the below circumstance
983  * only really occurs when 'malloc' returns NULL in createComplexMatrixN,
984  * which actually triggers its own validation. Hence this test is useless
985  * currently.
986  */
987  ComplexMatrixN matr;
988  matr.real = NULL;
989  matr.imag = NULL;
990  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, 3, matr), Contains("created") );
991  }
992  SECTION( "unitary dimensions" ) {
993 
994  int ctrls[1] = {0};
995  int targs[2] = {1,2};
996  ComplexMatrixN matr = createComplexMatrixN(3); // intentionally wrong size
997  toComplexMatrixN(getRandomUnitary(3), matr); // ensure unitary
998 
999  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, 2, matr), Contains("matrix size"));
1000  destroyComplexMatrixN(matr);
1001  }
1002  SECTION( "unitary fits in node" ) {
1003 
1004  // pretend we have a very limited distributed memory (judged by matr size)
1005  quregVec.numAmpsPerChunk = 1;
1006  int ctrls[1] = {0};
1007  int targs[2] = {1,2};
1009  toComplexMatrixN(getRandomUnitary(2), matr); // ensure unitary
1010 
1011  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, 2, matr), Contains("targets too many qubits"));
1012  destroyComplexMatrixN(matr);
1013  }
1014  }
1015  CLEANUP_TEST( quregVec, quregMatr );
1016 }
1017 
1018 
1019 
1024 TEST_CASE( "multiControlledPhaseFlip", "[unitaries]" ) {
1025 
1026  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1027 
1028  // acts on the final control qubit
1029  QMatrix op{{1,0},{0,-1}};
1030 
1031  SECTION( "correctness" ) {
1032 
1033  // generate ALL valid qubit arrangements
1034  int numCtrls = GENERATE( range(1,NUM_QUBITS) ); // numCtrls=NUM_QUBITS stopped by overzealous validation
1035  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls) );
1036 
1037  SECTION( "state-vector" ) {
1038 
1039  multiControlledPhaseFlip(quregVec, ctrls, numCtrls);
1040  applyReferenceOp(refVec, ctrls, numCtrls-1, ctrls[numCtrls-1], op);
1041  REQUIRE( areEqual(quregVec, refVec) );
1042  }
1043  SECTION( "density-matrix" ) {
1044 
1045  multiControlledPhaseFlip(quregMatr, ctrls, numCtrls);
1046  applyReferenceOp(refMatr, ctrls, numCtrls-1, ctrls[numCtrls-1], op);
1047  REQUIRE( areEqual(quregMatr, refMatr) );
1048  }
1049  }
1050  SECTION( "input validation" ) {
1051 
1052  SECTION( "number of controls" ) {
1053 
1054  int numCtrls = GENERATE( -1, 0, NUM_QUBITS+1 );
1055  int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1056  REQUIRE_THROWS_WITH( multiControlledPhaseFlip(quregVec, ctrls, numCtrls), Contains("Invalid number of qubits"));
1057  }
1058  SECTION( "repetition of controls" ) {
1059 
1060  int numCtrls = 3;
1061  int ctrls[] = {0,1,1};
1062  REQUIRE_THROWS_WITH( multiControlledPhaseFlip(quregVec, ctrls, numCtrls), Contains("qubits must be unique"));
1063  }
1064  SECTION( "qubit indices" ) {
1065 
1066  int numCtrls = 3;
1067  int ctrls[] = { 1, 2, GENERATE( -1, NUM_QUBITS ) };
1068  REQUIRE_THROWS_WITH( multiControlledPhaseFlip(quregVec, ctrls, numCtrls), Contains("Invalid qubit") );
1069  }
1070  }
1071  CLEANUP_TEST( quregVec, quregMatr );
1072 }
1073 
1074 
1075 
1080 TEST_CASE( "multiControlledPhaseShift", "[unitaries]" ) {
1081 
1082  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1083  qreal param = getRandomReal(-2*M_PI, 2*M_PI);
1084  QMatrix op{{1,0},{0,expI(param)}};
1085 
1086  SECTION( "correctness" ) {
1087 
1088  // generate ALL valid qubit arrangements
1089  int numCtrls = GENERATE( range(1,NUM_QUBITS) ); // numCtrls=NUM_QUBITS stopped by overzealous validation
1090  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls) );
1091 
1092  SECTION( "state-vector" ) {
1093 
1094  multiControlledPhaseShift(quregVec, ctrls, numCtrls, param);
1095  applyReferenceOp(refVec, ctrls, numCtrls-1, ctrls[numCtrls-1], op);
1096  REQUIRE( areEqual(quregVec, refVec) );
1097  }
1098  SECTION( "density-matrix" ) {
1099 
1100  multiControlledPhaseShift(quregMatr, ctrls, numCtrls, param);
1101  applyReferenceOp(refMatr, ctrls, numCtrls-1, ctrls[numCtrls-1], op);
1102  REQUIRE( areEqual(quregMatr, refMatr) );
1103  }
1104  }
1105  SECTION( "input validation" ) {
1106 
1107  SECTION( "number of controls" ) {
1108 
1109  int numCtrls = GENERATE( -1, 0, NUM_QUBITS+1 );
1110  int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1111  REQUIRE_THROWS_WITH( multiControlledPhaseShift(quregVec, ctrls, numCtrls, param), Contains("Invalid number of qubits"));
1112  }
1113  SECTION( "repetition of controls" ) {
1114 
1115  int numCtrls = 3;
1116  int ctrls[] = {0,1,1};
1117  REQUIRE_THROWS_WITH( multiControlledPhaseShift(quregVec, ctrls, numCtrls, param), Contains("qubits must be unique"));
1118  }
1119  SECTION( "qubit indices" ) {
1120 
1121  int numCtrls = 3;
1122  int ctrls[] = { 1, 2, GENERATE( -1, NUM_QUBITS ) };
1123  REQUIRE_THROWS_WITH( multiControlledPhaseShift(quregVec, ctrls, numCtrls, param), Contains("Invalid qubit") );
1124  }
1125  }
1126  CLEANUP_TEST( quregVec, quregMatr );
1127 }
1128 
1129 
1130 
1135 TEST_CASE( "multiControlledTwoQubitUnitary", "[unitaries]" ) {
1136 
1137  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1138 
1139  // in distributed mode, each node must be able to fit all amps modified by unitary
1140  REQUIRE( quregVec.numAmpsPerChunk >= 4 );
1141 
1142  // every test will use a unique random matrix
1143  QMatrix op = getRandomUnitary(2);
1144  ComplexMatrix4 matr = toComplexMatrix4(op);
1145 
1146  SECTION( "correctness" ) {
1147 
1148  // generate ALL valid qubit arrangements
1149  int targ1 = GENERATE( range(0,NUM_QUBITS) );
1150  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
1151  int targs[] = {targ1, targ2};
1152  int numCtrls = GENERATE( range(1,NUM_QUBITS-1) ); // leave room for 2 targets (upper bound is exclusive)
1153  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, targs, 2) );
1154 
1155  SECTION( "state-vector" ) {
1156 
1157  multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr);
1158  applyReferenceOp(refVec, ctrls, numCtrls, targ1, targ2, op);
1159  REQUIRE( areEqual(quregVec, refVec) );
1160  }
1161  SECTION( "density-matrix" ) {
1162 
1163  multiControlledTwoQubitUnitary(quregMatr, ctrls, numCtrls, targ1, targ2, matr);
1164  applyReferenceOp(refMatr, ctrls, numCtrls, targ1, targ2, op);
1165  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1166  }
1167  }
1168  SECTION( "input validation" ) {
1169 
1170  SECTION( "number of controls" ) {
1171 
1172  // numCtrls=(NUM_QUBITS-1) is ok since requires ctrl qubit inds are invalid
1173  int numCtrls = GENERATE( -1, 0, NUM_QUBITS, NUM_QUBITS+1 );
1174  int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1175  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, 0, 1, matr), Contains("Invalid number of control"));
1176  }
1177  SECTION( "repetition of controls" ) {
1178 
1179  int numCtrls = 3;
1180  int ctrls[] = {0,1,1};
1181  int targ1 = 2;
1182  int targ2 = 3;
1183  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr), Contains("control") && Contains("unique"));;
1184  }
1185  SECTION( "repetition of targets" ) {
1186 
1187  int numCtrls = 3;
1188  int ctrls[] = {0,1,2};
1189  int targ1 = 3;
1190  int targ2 = targ1;
1191  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr), Contains("target") && Contains("unique"));
1192  }
1193  SECTION( "control and target collision" ) {
1194 
1195  int numCtrls = 3;
1196  int ctrls[] = {0,1,2};
1197  int targ1 = 3;
1198  int targ2 = ctrls[GENERATE_COPY( range(0,numCtrls) )];
1199  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr), Contains("Control") && Contains("target") );
1200  }
1201  SECTION( "qubit indices" ) {
1202 
1203  // valid indices
1204  int targ1 = 0;
1205  int targ2 = 1;
1206  int numCtrls = 3;
1207  int ctrls[] = { 2, 3, 4 };
1208 
1209  int inv = GENERATE( -1, NUM_QUBITS );
1210  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, inv, targ2, matr), Contains("Invalid target") );
1211  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, inv, matr), Contains("Invalid target") );
1212 
1213  ctrls[numCtrls-1] = inv; // make ctrls invalid
1214  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr), Contains("Invalid control") );
1215  }
1216  SECTION( "unitarity " ) {
1217 
1218  int ctrls[1] = {0};
1219  matr.real[0][0] = 0; // break unitarity
1220  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, 1, 1, 2, matr), Contains("unitary") );
1221  }
1222  SECTION( "unitary fits in node" ) {
1223 
1224  // pretend we have a very limited distributed memory
1225  quregVec.numAmpsPerChunk = 1;
1226  int ctrls[1] = {0};
1227  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, 1, 1, 2, matr), Contains("targets too many qubits"));
1228  }
1229  }
1230  CLEANUP_TEST( quregVec, quregMatr );
1231 }
1232 
1233 
1234 
1239 TEST_CASE( "multiControlledUnitary", "[unitaries]" ) {
1240 
1241  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1242 
1243  // every test will use a unique random matrix
1244  QMatrix op = getRandomUnitary(1);
1245  ComplexMatrix2 matr = toComplexMatrix2(op);
1246 
1247  SECTION( "correctness" ) {
1248 
1249  int target = GENERATE( range(0,NUM_QUBITS) );
1250  int numCtrls = GENERATE( range(1,NUM_QUBITS) ); // leave space for one target (exclusive upper bound)
1251  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, target) );
1252 
1253  SECTION( "state-vector" ) {
1254 
1255  multiControlledUnitary(quregVec, ctrls, numCtrls, target, matr);
1256  applyReferenceOp(refVec, ctrls, numCtrls, target, op);
1257  REQUIRE( areEqual(quregVec, refVec) );
1258  }
1259  SECTION( "density-matrix" ) {
1260 
1261  multiControlledUnitary(quregMatr, ctrls, numCtrls, target, matr);
1262  applyReferenceOp(refMatr, ctrls, numCtrls, target, op);
1263  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1264  }
1265  }
1266  SECTION( "input validation" ) {
1267 
1268  SECTION( "number of controls" ) {
1269 
1270  int numCtrls = GENERATE( -1, 0, NUM_QUBITS, NUM_QUBITS+1 );
1271  int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1272  REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, numCtrls, 0, matr), Contains("Invalid number of control"));
1273  }
1274  SECTION( "repetition of controls" ) {
1275 
1276  int ctrls[] = {0,1,1};
1277  REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 3, 2, matr), Contains("control") && Contains("unique"));
1278  }
1279  SECTION( "control and target collision" ) {
1280 
1281  int ctrls[] = {0,1,2};
1282  int targ = ctrls[GENERATE( range(0,3) )];
1283  REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 3, targ, matr), Contains("Control") && Contains("target") );
1284  }
1285  SECTION( "qubit indices" ) {
1286 
1287  int ctrls[] = { 1, 2, GENERATE( -1, NUM_QUBITS ) };
1288  REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 3, 0, matr), Contains("Invalid control") );
1289 
1290  ctrls[2] = 3; // make ctrls valid
1291  int targ = GENERATE( -1, NUM_QUBITS );
1292  REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 3, targ, matr), Contains("Invalid target") );
1293  }
1294  SECTION( "unitarity" ) {
1295 
1296  matr.real[0][0] = 0; // break matr unitarity
1297  int ctrls[] = {0};
1298  REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 1, 1, matr), Contains("unitary") );
1299  }
1300  }
1301  CLEANUP_TEST( quregVec, quregMatr );
1302 }
1303 
1304 
1305 
1310 TEST_CASE( "multiQubitUnitary", "[unitaries]" ) {
1311 
1312  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1313 
1314  // figure out max-num (inclusive) targs allowed by hardware backend
1315  int maxNumTargs = calcLog2(quregVec.numAmpsPerChunk);
1316 
1317  SECTION( "correctness" ) {
1318 
1319  // generate all possible qubit arrangements
1320  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) ); // inclusive upper bound
1321  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1322 
1323  // for each qubit arrangement, use a new random unitary
1324  QMatrix op = getRandomUnitary(numTargs);
1325  ComplexMatrixN matr = createComplexMatrixN(numTargs);
1326  toComplexMatrixN(op, matr);
1327 
1328  SECTION( "state-vector" ) {
1329 
1330  multiQubitUnitary(quregVec, targs, numTargs, matr);
1331  applyReferenceOp(refVec, targs, numTargs, op);
1332  REQUIRE( areEqual(quregVec, refVec) );
1333  }
1334  SECTION( "density-matrix" ) {
1335 
1336  multiQubitUnitary(quregMatr, targs, numTargs, matr);
1337  applyReferenceOp(refMatr, targs, numTargs, op);
1338  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1339  }
1340  destroyComplexMatrixN(matr);
1341  }
1342  SECTION( "input validation" ) {
1343 
1344  SECTION( "number of targets" ) {
1345 
1346  // there cannot be more targets than qubits in register
1347  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
1348  int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
1349  ComplexMatrixN matr = createComplexMatrixN(NUM_QUBITS+1); // prevent seg-fault
1350 
1351  REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), Contains("Invalid number of target"));
1352  destroyComplexMatrixN(matr);
1353  }
1354  SECTION( "repetition in targets" ) {
1355 
1356  int numTargs = 3;
1357  int targs[] = {1,2,2};
1358  ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
1359 
1360  REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), Contains("target") && Contains("unique"));
1361  destroyComplexMatrixN(matr);
1362  }
1363  SECTION( "qubit indices" ) {
1364 
1365  int numTargs = 3;
1366  int targs[] = {1,2,3};
1367  ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
1368 
1369  int inv = GENERATE( -1, NUM_QUBITS );
1370  targs[GENERATE_COPY( range(0,numTargs) )] = inv; // make invalid target
1371  REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), Contains("Invalid target") );
1372 
1373  destroyComplexMatrixN(matr);
1374  }
1375  SECTION( "unitarity" ) {
1376 
1377  int numTargs = GENERATE_COPY( range(1,maxNumTargs) );
1378  int targs[numTargs];
1379  for (int i=0; i<numTargs; i++)
1380  targs[i] = i+1;
1381 
1382  ComplexMatrixN matr = createComplexMatrixN(numTargs); // initially zero, hence not-unitary
1383 
1384  REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), Contains("unitary") );
1385  destroyComplexMatrixN(matr);
1386  }
1387  SECTION( "unitary creation" ) {
1388 
1389  int numTargs = 3;
1390  int targs[] = {1,2,3};
1391 
1392  /* compilers don't auto-initialise to NULL; the below circumstance
1393  * only really occurs when 'malloc' returns NULL in createComplexMatrixN,
1394  * which actually triggers its own validation. Hence this test is useless
1395  * currently.
1396  */
1397  ComplexMatrixN matr;
1398  matr.real = NULL;
1399  matr.imag = NULL;
1400  REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), Contains("created") );
1401  }
1402  SECTION( "unitary dimensions" ) {
1403 
1404  int targs[2] = {1,2};
1405  ComplexMatrixN matr = createComplexMatrixN(3); // intentionally wrong size
1406 
1407  REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, 2, matr), Contains("matrix size"));
1408  destroyComplexMatrixN(matr);
1409  }
1410  SECTION( "unitary fits in node" ) {
1411 
1412  // pretend we have a very limited distributed memory (judged by matr size)
1413  quregVec.numAmpsPerChunk = 1;
1414  int qb[] = {1,2};
1415  ComplexMatrixN matr = createComplexMatrixN(2); // prevents seg-fault if validation doesn't trigger
1416  REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, qb, 2, matr), Contains("targets too many qubits"));
1417  destroyComplexMatrixN(matr);
1418  }
1419  }
1420  CLEANUP_TEST( quregVec, quregMatr );
1421 }
1422 
1423 
1424 
1429 TEST_CASE( "multiRotatePauli", "[unitaries]" ) {
1430 
1431  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1432  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
1433 
1434  SECTION( "correctness" ) {
1435 
1436  int numTargs = GENERATE( range(1,NUM_QUBITS+1) );
1437  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1438 
1439  /* it's too expensive to try ALL Pauli sequences, via
1440  * pauliOpType* paulis = GENERATE_COPY( pauliseqs(numTargs) );.
1441  * Furthermore, take(10, pauliseqs(numTargs)) will try the same pauli codes.
1442  * Hence, we instead opt to repeatedlyrandomly generate pauliseqs
1443  */
1444  GENERATE( range(0,10) ); // gen 10 random pauli-codes for every targs
1445  pauliOpType paulis[numTargs];
1446  for (int i=0; i<numTargs; i++)
1447  paulis[i] = (pauliOpType) getRandomInt(0,4);
1448 
1449  // exclude identities from reference matrix exp (they apply unwanted global phase)
1450  int refTargs[numTargs];
1451  int numRefTargs = 0;
1452 
1453  QMatrix xMatr{{0,1},{1,0}};
1454  QMatrix yMatr{{0,-1i},{1i,0}};
1455  QMatrix zMatr{{1,0},{0,-1}};
1456 
1457  // build correct reference matrix by pauli-matrix exponentiation...
1458  QMatrix pauliProd{{1}};
1459  for (int i=0; i<numTargs; i++) {
1460  QMatrix fac;
1461  if (paulis[i] == PAULI_I) continue; // exclude I-targets from ref list
1462  if (paulis[i] == PAULI_X) fac = xMatr;
1463  if (paulis[i] == PAULI_Y) fac = yMatr;
1464  if (paulis[i] == PAULI_Z) fac = zMatr;
1465  pauliProd = getKroneckerProduct(fac, pauliProd);
1466 
1467  // include this target in ref list
1468  refTargs[numRefTargs++] = targs[i];
1469  }
1470 
1471  // produces exp(-i param/2 pauliProd), unless pauliProd = I
1472  QMatrix op;
1473  if (numRefTargs > 0)
1474  op = getExponentialOfPauliMatrix(param, pauliProd);
1475 
1476  SECTION( "state-vector" ) {
1477 
1478  multiRotatePauli(quregVec, targs, paulis, numTargs, param);
1479  if (numRefTargs > 0)
1480  applyReferenceOp(refVec, refTargs, numRefTargs, op);
1481  REQUIRE( areEqual(quregVec, refVec) );
1482  }
1483  SECTION( "density-matrix" ) {
1484 
1485  multiRotatePauli(quregMatr, targs, paulis, numTargs, param);
1486  if (numRefTargs > 0)
1487  applyReferenceOp(refMatr, refTargs, numRefTargs, op);
1488  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1489  }
1490  }
1491  SECTION( "input validation" ) {
1492 
1493  SECTION( "number of targets" ) {
1494 
1495  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
1496  int targs[NUM_QUBITS+1]; // prevent seg-fault if validation isn't triggered
1497  pauliOpType paulis[NUM_QUBITS+1] = {PAULI_I};
1498  REQUIRE_THROWS_WITH( multiRotatePauli(quregVec, targs, paulis, numTargs, param), Contains("Invalid number of target"));
1499 
1500  }
1501  SECTION( "repetition of targets" ) {
1502 
1503  int numTargs = 3;
1504  int targs[3] = {0, 1, 1};
1505  pauliOpType paulis[3] = {PAULI_I};
1506  REQUIRE_THROWS_WITH( multiRotatePauli(quregVec, targs, paulis, numTargs, param), Contains("target") && Contains("unique"));
1507  }
1508  SECTION( "qubit indices" ) {
1509 
1510  int numTargs = 3;
1511  int targs[3] = {0, 1, 2};
1512  targs[GENERATE_COPY(range(0,numTargs))] = GENERATE( -1, NUM_QUBITS );
1513  pauliOpType paulis[3] = {PAULI_I};
1514  REQUIRE_THROWS_WITH( multiRotatePauli(quregVec, targs, paulis, numTargs, param), Contains("Invalid target"));
1515  }
1516  SECTION( "pauli codes" ) {
1517  int numTargs = 3;
1518  int targs[3] = {0, 1, 2};
1519  pauliOpType paulis[3] = {PAULI_I, PAULI_I, PAULI_I};
1520  paulis[GENERATE_COPY(range(0,numTargs))] = (pauliOpType) GENERATE( -1, 4 );
1521  REQUIRE_THROWS_WITH( multiRotatePauli(quregVec, targs, paulis, numTargs, param), Contains("Invalid Pauli code"));
1522  }
1523  }
1524  CLEANUP_TEST( quregVec, quregMatr );
1525 }
1526 
1527 
1528 
1533 TEST_CASE( "multiRotateZ", "[unitaries]" ) {
1534 
1535  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1536  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
1537 
1538  SECTION( "correctness" ) {
1539 
1540  int numTargs = GENERATE( range(1,NUM_QUBITS+1) );
1541  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1542 
1543  // build correct reference matrix by diagonal-matrix exponentiation...
1544  QMatrix zMatr{{1,0},{0,-1}};
1545  QMatrix zProd = zMatr;
1546  for (int t=0; t<numTargs-1; t++)
1547  zProd = getKroneckerProduct(zMatr, zProd); // Z . Z ... Z
1548 
1549  // (-i param/2) Z . I . Z ...
1550  QMatrix expArg = (-1i * param / 2.) *
1551  getFullOperatorMatrix(NULL, 0, targs, numTargs, zProd, NUM_QUBITS);
1552 
1553  // exp( -i param/2 Z . I . Z ...)
1555 
1556  // all qubits to specify full operator matrix on reference structures
1557  int allQubits[NUM_QUBITS];
1558  for (int i=0; i<NUM_QUBITS; i++)
1559  allQubits[i] = i;
1560 
1561  SECTION( "state-vector" ) {
1562 
1563  multiRotateZ(quregVec, targs, numTargs, param);
1564  applyReferenceOp(refVec, allQubits, NUM_QUBITS, op);
1565  REQUIRE( areEqual(quregVec, refVec) );
1566 
1567  }
1568  SECTION( "density-matrix" ) {
1569 
1570  multiRotateZ(quregMatr, targs, numTargs, param);
1571  applyReferenceOp(refMatr, allQubits, NUM_QUBITS, op);
1572  REQUIRE( areEqual(quregMatr, refMatr, 2*REAL_EPS) );
1573  }
1574  }
1575  SECTION( "input validation" ) {
1576 
1577  SECTION( "number of targets" ) {
1578 
1579  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
1580  int targs[NUM_QUBITS+1]; // prevent seg-fault if validation isn't triggered
1581  REQUIRE_THROWS_WITH( multiRotateZ(quregVec, targs, numTargs, param), Contains("Invalid number of target"));
1582 
1583  }
1584  SECTION( "repetition of targets" ) {
1585 
1586  int numTargs = 3;
1587  int targs[3] = {0, 1, 1};
1588  REQUIRE_THROWS_WITH( multiRotateZ(quregVec, targs, numTargs, param), Contains("target") && Contains("unique"));
1589  }
1590  SECTION( "qubit indices" ) {
1591 
1592  int numTargs = 3;
1593  int targs[3] = {0, 1, 2};
1594  targs[GENERATE_COPY(range(0,numTargs))] = GENERATE( -1, NUM_QUBITS );
1595  REQUIRE_THROWS_WITH( multiRotateZ(quregVec, targs, numTargs, param), Contains("Invalid target"));
1596  }
1597  }
1598  CLEANUP_TEST( quregVec, quregMatr );
1599 }
1600 
1601 
1602 
1607 TEST_CASE( "multiStateControlledUnitary", "[unitaries]" ) {
1608 
1609  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1610 
1611  // every test will use a unique random matrix
1612  QMatrix op = getRandomUnitary(1);
1613  ComplexMatrix2 matr = toComplexMatrix2(op);
1614 
1615  // the zero-conditioned control qubits can be effected by notting before/after ctrls
1616  QMatrix notOp{{0,1},{1,0}};
1617 
1618  SECTION( "correctness" ) {
1619 
1620  int target = GENERATE( range(0,NUM_QUBITS) );
1621  int numCtrls = GENERATE( range(1,NUM_QUBITS) ); // leave space for one target (exclusive upper bound)
1622  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, target) );
1623  int* ctrlState = GENERATE_COPY( bitsets(numCtrls) );
1624 
1625  SECTION( "state-vector" ) {
1626 
1627  multiStateControlledUnitary(quregVec, ctrls, ctrlState, numCtrls, target, matr);
1628 
1629  // simulate controlled-state by notting before & after controls
1630  for (int i=0; i<numCtrls; i++)
1631  if (ctrlState[i] == 0)
1632  applyReferenceOp(refVec, ctrls[i], notOp);
1633  applyReferenceOp(refVec, ctrls, numCtrls, target, op);
1634  for (int i=0; i<numCtrls; i++)
1635  if (ctrlState[i] == 0)
1636  applyReferenceOp(refVec, ctrls[i], notOp);
1637 
1638  REQUIRE( areEqual(quregVec, refVec) );
1639  }
1640  SECTION( "density-matrix" ) {
1641 
1642  multiStateControlledUnitary(quregMatr, ctrls, ctrlState, numCtrls, target, matr);
1643 
1644  // simulate controlled-state by notting before & after controls
1645  for (int i=0; i<numCtrls; i++)
1646  if (ctrlState[i] == 0)
1647  applyReferenceOp(refMatr, ctrls[i], notOp);
1648  applyReferenceOp(refMatr, ctrls, numCtrls, target, op);
1649  for (int i=0; i<numCtrls; i++)
1650  if (ctrlState[i] == 0)
1651  applyReferenceOp(refMatr, ctrls[i], notOp);
1652 
1653  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1654  }
1655  }
1656  SECTION( "input validation" ) {
1657 
1658  SECTION( "number of controls" ) {
1659 
1660  int numCtrls = GENERATE( -1, 0, NUM_QUBITS, NUM_QUBITS+1 );
1661  int ctrls[NUM_QUBITS+1];
1662  int ctrlState[NUM_QUBITS+1] = {0};
1663  REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, numCtrls, 0, matr), Contains("Invalid number of control"));
1664  }
1665  SECTION( "repetition of controls" ) {
1666 
1667  int ctrls[] = {0,1,1};
1668  int ctrlState[] = {0, 1, 0};
1669  REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, 2, matr), Contains("control") && Contains("unique"));
1670  }
1671  SECTION( "control and target collision" ) {
1672 
1673  int ctrls[] = {0,1,2};
1674  int ctrlState[] = {0, 1, 0};
1675  int targ = ctrls[GENERATE( range(0,3) )];
1676  REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, targ, matr), Contains("Control") && Contains("target") );
1677  }
1678  SECTION( "qubit indices" ) {
1679 
1680  int ctrls[] = { 1, 2, GENERATE( -1, NUM_QUBITS ) };
1681  int ctrlState[] = {0, 1, 0};
1682  REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, 0, matr), Contains("Invalid control") );
1683 
1684  ctrls[2] = 3; // make ctrls valid
1685  int targ = GENERATE( -1, NUM_QUBITS );
1686  REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, targ, matr), Contains("Invalid target") );
1687  }
1688  SECTION( "unitarity" ) {
1689 
1690  matr.real[0][0] = 0; // break matr unitarity
1691  int ctrls[] = {0};
1692  int ctrlState[1] = {0};
1693  REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 1, 1, matr), Contains("unitary") );
1694  }
1695  SECTION( "control state bits" ) {
1696 
1697  // valid qubits
1698  int ctrls[] = {0, 1, 2};
1699  int ctrlState[] = {0, 0, 0};
1700  int targ = 3;
1701 
1702  // make invalid
1703  ctrlState[2] = GENERATE(-1, 2);
1704  REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, targ, matr), Contains("state") );
1705  }
1706  }
1707  CLEANUP_TEST( quregVec, quregMatr );
1708 }
1709 
1710 
1711 
1716 TEST_CASE( "pauliX", "[unitaries]" ) {
1717 
1718  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1719  QMatrix op{{0,1},{1,0}};
1720 
1721  SECTION( "correctness" ) {
1722 
1723  int target = GENERATE( range(0,NUM_QUBITS) );
1724 
1725  SECTION( "state-vector" ) {
1726 
1727  pauliX(quregVec, target);
1728  applyReferenceOp(refVec, target, op);
1729  REQUIRE( areEqual(quregVec, refVec) );
1730  }
1731  SECTION( "density-matrix correctness" ) {
1732 
1733  pauliX(quregMatr, target);
1734  applyReferenceOp(refMatr, target, op);
1735  REQUIRE( areEqual(quregMatr, refMatr) );
1736  }
1737  }
1738  SECTION( "input validation" ) {
1739 
1740  SECTION( "qubit indices" ) {
1741 
1742  int target = GENERATE( -1, NUM_QUBITS );
1743  REQUIRE_THROWS_WITH( pauliX(quregVec, target), Contains("Invalid target") );
1744  }
1745  }
1746  CLEANUP_TEST( quregVec, quregMatr );
1747 }
1748 
1749 
1750 
1755 TEST_CASE( "pauliY", "[unitaries]" ) {
1756 
1757  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1758  QMatrix op{{0,-1i},{1i,0}};
1759 
1760  SECTION( "correctness" ) {
1761 
1762  int target = GENERATE( range(0,NUM_QUBITS) );
1763 
1764  SECTION( "state-vector" ) {
1765 
1766  pauliY(quregVec, target);
1767  applyReferenceOp(refVec, target, op);
1768  REQUIRE( areEqual(quregVec, refVec) );
1769  }
1770  SECTION( "density-matrix correctness" ) {
1771 
1772  pauliY(quregMatr, target);
1773  applyReferenceOp(refMatr, target, op);
1774  REQUIRE( areEqual(quregMatr, refMatr) );
1775  }
1776  }
1777  SECTION( "input validation" ) {
1778 
1779  SECTION( "qubit indices" ) {
1780 
1781  int target = GENERATE( -1, NUM_QUBITS );
1782  REQUIRE_THROWS_WITH( pauliY(quregVec, target), Contains("Invalid target") );
1783  }
1784  }
1785  CLEANUP_TEST( quregVec, quregMatr );
1786 }
1787 
1788 
1789 
1794 TEST_CASE( "pauliZ", "[unitaries]" ) {
1795 
1796  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1797  QMatrix op{{1,0},{0,-1}};
1798 
1799  SECTION( "correctness" ) {
1800 
1801  int target = GENERATE( range(0,NUM_QUBITS) );
1802 
1803  SECTION( "state-vector" ) {
1804 
1805  pauliZ(quregVec, target);
1806  applyReferenceOp(refVec, target, op);
1807  REQUIRE( areEqual(quregVec, refVec) );
1808  }
1809  SECTION( "density-matrix correctness" ) {
1810 
1811  pauliZ(quregMatr, target);
1812  applyReferenceOp(refMatr, target, op);
1813  REQUIRE( areEqual(quregMatr, refMatr) );
1814  }
1815  }
1816  SECTION( "input validation" ) {
1817 
1818  SECTION( "qubit indices" ) {
1819 
1820  int target = GENERATE( -1, NUM_QUBITS );
1821  REQUIRE_THROWS_WITH( pauliZ(quregVec, target), Contains("Invalid target") );
1822  }
1823  }
1824  CLEANUP_TEST( quregVec, quregMatr );
1825 }
1826 
1827 
1828 
1833 TEST_CASE( "phaseShift", "[unitaries]" ) {
1834 
1835  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1836  qreal param = getRandomReal(-2*M_PI, 2*M_PI);
1837  QMatrix op{{1,0},{0,expI(param)}};
1838 
1839  SECTION( "correctness" ) {
1840 
1841  int target = GENERATE( range(0,NUM_QUBITS) );
1842 
1843  SECTION( "state-vector ") {
1844 
1845  phaseShift(quregVec, target, param);
1846  applyReferenceOp(refVec, target, op);
1847  REQUIRE( areEqual(quregVec, refVec) );
1848  }
1849  SECTION( "density-matrix" ) {
1850 
1851  phaseShift(quregMatr, target, param);
1852  applyReferenceOp(refMatr, target, op);
1853  REQUIRE( areEqual(quregMatr, refMatr) );
1854  }
1855  }
1856  SECTION( "input validation" ) {
1857 
1858  SECTION( "qubit indices" ) {
1859 
1860  int target = GENERATE( -1, NUM_QUBITS );
1861  REQUIRE_THROWS_WITH( phaseShift(quregVec, target, param), Contains("Invalid target") );
1862  }
1863  }
1864  CLEANUP_TEST( quregVec, quregMatr );
1865 }
1866 
1867 
1868 
1873 TEST_CASE( "rotateAroundAxis", "[unitaries]" ) {
1874 
1875  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1876 
1877  // each test will use a random parameter and axis vector
1878  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
1879  Vector vec = {.x=getRandomReal(-1,1), .y=getRandomReal(-1,1), .z=getRandomReal(-1,1)};
1880 
1881  // Rn(a) = cos(a/2)I - i sin(a/2) n . paulivector
1882  // (pg 24 of vcpc.univie.ac.at/~ian/hotlist/qc/talks/bloch-sphere-rotations.pdf)
1883  qreal c = cos(param/2);
1884  qreal s = sin(param/2);
1885  qreal m = sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z);
1886  QMatrix op{{c - 1i*vec.z*s/m, -(vec.y + 1i*vec.x)*s/m},
1887  {(vec.y - 1i*vec.x)*s/m, c + 1i*vec.z*s/m}};
1888 
1889  SECTION( "correctness" ) {
1890 
1891  int target = GENERATE( range(0,NUM_QUBITS) );
1892 
1893  SECTION( "state-vector ") {
1894 
1895  rotateAroundAxis(quregVec, target, param, vec);
1896  applyReferenceOp(refVec, target, op);
1897  REQUIRE( areEqual(quregVec, refVec) );
1898  }
1899  SECTION( "density-matrix" ) {
1900 
1901  rotateAroundAxis(quregMatr, target, param, vec);
1902  applyReferenceOp(refMatr, target, op);
1903  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1904  }
1905  }
1906  SECTION( "input validation" ) {
1907 
1908  SECTION( "qubit indices" ) {
1909 
1910  int target = GENERATE( -1, NUM_QUBITS );
1911  REQUIRE_THROWS_WITH( rotateAroundAxis(quregVec, target, param, vec), Contains("Invalid target") );
1912  }
1913  SECTION( "zero rotation axis" ) {
1914 
1915  int target = 0;
1916  vec = {.x=0, .y=0, .z=0};
1917  REQUIRE_THROWS_WITH( rotateAroundAxis(quregVec, target, param, vec), Contains("Invalid axis") && Contains("zero") );
1918  }
1919  }
1920  CLEANUP_TEST( quregVec, quregMatr );
1921 }
1922 
1923 
1924 
1929 TEST_CASE( "rotateX", "[unitaries]" ) {
1930 
1931  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1932  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
1933  QMatrix op{{cos(param/2), -1i*sin(param/2)}, {-1i*sin(param/2), cos(param/2)}};
1934 
1935  SECTION( "correctness" ) {
1936 
1937  int target = GENERATE( range(0,NUM_QUBITS) );
1938 
1939  SECTION( "state-vector ") {
1940 
1941  rotateX(quregVec, target, param);
1942  applyReferenceOp(refVec, target, op);
1943  REQUIRE( areEqual(quregVec, refVec) );
1944  }
1945  SECTION( "density-matrix" ) {
1946 
1947  rotateX(quregMatr, target, param);
1948  applyReferenceOp(refMatr, target, op);
1949  REQUIRE( areEqual(quregMatr, refMatr) );
1950  }
1951  }
1952  SECTION( "input validation" ) {
1953 
1954  SECTION( "qubit indices" ) {
1955 
1956  int target = GENERATE( -1, NUM_QUBITS );
1957  REQUIRE_THROWS_WITH( rotateX(quregVec, target, param), Contains("Invalid target") );
1958  }
1959  }
1960  CLEANUP_TEST( quregVec, quregMatr );
1961 }
1962 
1963 
1964 
1969 TEST_CASE( "rotateY", "[unitaries]" ) {
1970 
1971  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1972  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
1973  QMatrix op{{cos(param/2), -sin(param/2)},{sin(param/2), cos(param/2)}};
1974 
1975  SECTION( "correctness" ) {
1976 
1977  int target = GENERATE( range(0,NUM_QUBITS) );
1978 
1979  SECTION( "state-vector ") {
1980 
1981  rotateY(quregVec, target, param);
1982  applyReferenceOp(refVec, target, op);
1983  REQUIRE( areEqual(quregVec, refVec) );
1984  }
1985  SECTION( "density-matrix" ) {
1986 
1987  rotateY(quregMatr, target, param);
1988  applyReferenceOp(refMatr, target, op);
1989  REQUIRE( areEqual(quregMatr, refMatr, 2*REAL_EPS) );
1990  }
1991  }
1992  SECTION( "input validation" ) {
1993 
1994  SECTION( "qubit indices" ) {
1995 
1996  int target = GENERATE( -1, NUM_QUBITS );
1997  REQUIRE_THROWS_WITH( rotateY(quregVec, target, param), Contains("Invalid target") );
1998  }
1999  }
2000  CLEANUP_TEST( quregVec, quregMatr );
2001 }
2002 
2003 
2004 
2009 TEST_CASE( "rotateZ", "[unitaries]" ) {
2010 
2011  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2012  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
2013  QMatrix op{{expI(-param/2.),0},{0,expI(param/2.)}};
2014 
2015  SECTION( "correctness" ) {
2016 
2017  int target = GENERATE( range(0,NUM_QUBITS) );
2018 
2019  SECTION( "state-vector ") {
2020 
2021  rotateZ(quregVec, target, param);
2022  applyReferenceOp(refVec, target, op);
2023  REQUIRE( areEqual(quregVec, refVec) );
2024  }
2025  SECTION( "density-matrix" ) {
2026 
2027  rotateZ(quregMatr, target, param);
2028  applyReferenceOp(refMatr, target, op);
2029  REQUIRE( areEqual(quregMatr, refMatr) );
2030  }
2031  }
2032  SECTION( "input validation" ) {
2033 
2034  SECTION( "qubit indices" ) {
2035 
2036  int target = GENERATE( -1, NUM_QUBITS );
2037  REQUIRE_THROWS_WITH( rotateZ(quregVec, target, param), Contains("Invalid target") );
2038  }
2039  }
2040  CLEANUP_TEST( quregVec, quregMatr );
2041 }
2042 
2043 
2044 
2049 TEST_CASE( "sGate", "[unitaries]" ) {
2050 
2051  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2052  QMatrix op{{1,0},{0,1i}};
2053 
2054  SECTION( "correctness" ) {
2055 
2056  int target = GENERATE( range(0,NUM_QUBITS) );
2057 
2058  SECTION( "state-vector ") {
2059 
2060  sGate(quregVec, target);
2061  applyReferenceOp(refVec, target, op);
2062  REQUIRE( areEqual(quregVec, refVec) );
2063  }
2064  SECTION( "density-matrix" ) {
2065 
2066  sGate(quregMatr, target);
2067  applyReferenceOp(refMatr, target, op);
2068  REQUIRE( areEqual(quregMatr, refMatr) );
2069  }
2070  }
2071  SECTION( "input validation" ) {
2072 
2073  SECTION( "qubit indices" ) {
2074 
2075  int target = GENERATE( -1, NUM_QUBITS );
2076  REQUIRE_THROWS_WITH( sGate(quregVec, target), Contains("Invalid target") );
2077  }
2078  }
2079  CLEANUP_TEST( quregVec, quregMatr );
2080 }
2081 
2082 
2083 
2088 TEST_CASE( "sqrtSwapGate", "[unitaries]" ) {
2089 
2090  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2091  qcomp a = (1. + 1i)/2.;
2092  qcomp b = (1. - 1i)/2.;
2093  QMatrix op{{1,0,0,0},{0,a,b,0},{0,b,a,0},{0,0,0,1}};
2094 
2095  SECTION( "correctness" ) {
2096 
2097  int targ1 = GENERATE( range(0,NUM_QUBITS) );
2098  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
2099  int targs[] = {targ1, targ2};
2100 
2101  SECTION( "state-vector" ) {
2102 
2103  sqrtSwapGate(quregVec, targ1, targ2);
2104  applyReferenceOp(refVec, targs, 2, op);
2105  REQUIRE( areEqual(quregVec, refVec) );
2106  }
2107  SECTION( "density-matrix" ) {
2108 
2109  sqrtSwapGate(quregMatr, targ1, targ2);
2110  applyReferenceOp(refMatr, targs, 2, op);
2111  REQUIRE( areEqual(quregMatr, refMatr) );
2112  }
2113  }
2114  SECTION( "input validation" ) {
2115 
2116  SECTION( "qubit indices" ) {
2117 
2118  int targ1 = GENERATE( -1, NUM_QUBITS );
2119  int targ2 = 0;
2120  REQUIRE_THROWS_WITH( sqrtSwapGate(quregVec, targ1, targ2), Contains("Invalid target") );
2121  REQUIRE_THROWS_WITH( sqrtSwapGate(quregVec, targ2, targ1), Contains("Invalid target") );
2122  }
2123  SECTION( "repetition of targets" ) {
2124 
2125  int qb = 0;
2126  REQUIRE_THROWS_WITH( sqrtSwapGate(quregVec, qb, qb), Contains("target") && Contains("unique") );
2127  }
2128  }
2129  CLEANUP_TEST( quregVec, quregMatr );
2130 }
2131 
2132 
2133 
2138 TEST_CASE( "swapGate", "[unitaries]" ) {
2139 
2140  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2141  QMatrix op{{1,0,0,0},{0,0,1,0},{0,1,0,0},{0,0,0,1}};
2142 
2143  SECTION( "correctness" ) {
2144 
2145  int targ1 = GENERATE( range(0,NUM_QUBITS) );
2146  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
2147  int targs[] = {targ1, targ2};
2148 
2149  SECTION( "state-vector" ) {
2150 
2151  swapGate(quregVec, targ1, targ2);
2152  applyReferenceOp(refVec, targs, 2, op);
2153  REQUIRE( areEqual(quregVec, refVec) );
2154  }
2155  SECTION( "density-matrix" ) {
2156 
2157  swapGate(quregMatr, targ1, targ2);
2158  applyReferenceOp(refMatr, targs, 2, op);
2159  REQUIRE( areEqual(quregMatr, refMatr) );
2160  }
2161  }
2162  SECTION( "input validation" ) {
2163 
2164  SECTION( "qubit indices" ) {
2165 
2166  int targ1 = GENERATE( -1, NUM_QUBITS );
2167  int targ2 = 0;
2168  REQUIRE_THROWS_WITH( swapGate(quregVec, targ1, targ2), Contains("Invalid target") );
2169  REQUIRE_THROWS_WITH( swapGate(quregVec, targ2, targ1), Contains("Invalid target") );
2170  }
2171  SECTION( "repetition of targets" ) {
2172 
2173  int qb = 0;
2174  REQUIRE_THROWS_WITH( swapGate(quregVec, qb, qb), Contains("target") && Contains("unique") );
2175  }
2176  }
2177  CLEANUP_TEST( quregVec, quregMatr );
2178 }
2179 
2180 
2181 
2186 TEST_CASE( "tGate", "[unitaries]" ) {
2187 
2188  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2189  QMatrix op{{1,0},{0,expI(M_PI/4.)}};
2190 
2191  SECTION( "correctness" ) {
2192 
2193  int target = GENERATE( range(0,NUM_QUBITS) );
2194 
2195  SECTION( "state-vector ") {
2196 
2197  tGate(quregVec, target);
2198  applyReferenceOp(refVec, target, op);
2199  REQUIRE( areEqual(quregVec, refVec) );
2200  }
2201  SECTION( "density-matrix" ) {
2202 
2203  tGate(quregMatr, target);
2204  applyReferenceOp(refMatr, target, op);
2205  REQUIRE( areEqual(quregMatr, refMatr) );
2206  }
2207  }
2208  SECTION( "input validation" ) {
2209 
2210  SECTION( "qubit indices" ) {
2211 
2212  int target = GENERATE( -1, NUM_QUBITS );
2213  REQUIRE_THROWS_WITH( tGate(quregVec, target), Contains("Invalid target") );
2214  }
2215  }
2216  CLEANUP_TEST( quregVec, quregMatr );
2217 }
2218 
2219 
2220 
2225 TEST_CASE( "twoQubitUnitary", "[unitaries]" ) {
2226 
2227  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2228 
2229  // in distributed mode, each node must be able to fit all amps modified by unitary
2230  REQUIRE( quregVec.numAmpsPerChunk >= 4 );
2231 
2232  // every test will use a unique random matrix
2233  QMatrix op = getRandomUnitary(2);
2234  ComplexMatrix4 matr = toComplexMatrix4(op);
2235 
2236  SECTION( "correctness" ) {
2237 
2238  int targ1 = GENERATE( range(0,NUM_QUBITS) );
2239  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
2240  int targs[] = {targ1, targ2};
2241 
2242  SECTION( "state-vector" ) {
2243 
2244  twoQubitUnitary(quregVec, targ1, targ2, matr);
2245  applyReferenceOp(refVec, targs, 2, op);
2246  REQUIRE( areEqual(quregVec, refVec) );
2247  }
2248  SECTION( "density-matrix" ) {
2249 
2250  twoQubitUnitary(quregMatr, targ1, targ2, matr);
2251  applyReferenceOp(refMatr, targs, 2, op);
2252  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
2253  }
2254  }
2255  SECTION( "input validation" ) {
2256 
2257  SECTION( "qubit indices" ) {
2258 
2259  int targ1 = GENERATE( -1, NUM_QUBITS );
2260  int targ2 = 0;
2261  REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, targ1, targ2, matr), Contains("Invalid target") );
2262  REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, targ2, targ1, matr), Contains("Invalid target") );
2263  }
2264  SECTION( "repetition of targets" ) {
2265 
2266  int qb = 0;
2267  REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, qb, qb, matr), Contains("target") && Contains("unique") );
2268  }
2269  SECTION( "unitarity" ) {
2270 
2271  matr.real[0][0] = 0; // break matr unitarity
2272  REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, 0, 1, matr), Contains("unitary") );
2273  }
2274  SECTION( "unitary fits in node" ) {
2275 
2276  // pretend we have a very limited distributed memory
2277  quregVec.numAmpsPerChunk = 1;
2278  REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, 0, 1, matr), Contains("targets too many qubits"));
2279  }
2280  }
2281  CLEANUP_TEST( quregVec, quregMatr );
2282 }
2283 
2284 
2285 
2290 TEST_CASE( "unitary", "[unitaries]" ) {
2291 
2292  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2293 
2294  // every test will use a unique random matrix
2295  QMatrix op = getRandomUnitary(1);
2296  ComplexMatrix2 matr = toComplexMatrix2(op);
2297 
2298  SECTION( "correctness" ) {
2299 
2300  int target = GENERATE( range(0,NUM_QUBITS) );
2301 
2302  SECTION( "state-vector" ) {
2303 
2304  unitary(quregVec, target, matr);
2305  applyReferenceOp(refVec, target, op);
2306  REQUIRE( areEqual(quregVec, refVec) );
2307  }
2308  SECTION( "density-matrix" ) {
2309 
2310  unitary(quregMatr, target, matr);
2311  applyReferenceOp(refMatr, target, op);
2312  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
2313  }
2314  }
2315  SECTION( "input validation" ) {
2316 
2317  SECTION( "qubit indices" ) {
2318 
2319  int target = GENERATE( -1, NUM_QUBITS );
2320  REQUIRE_THROWS_WITH( unitary(quregVec, target, matr), Contains("Invalid target") );
2321  }
2322  SECTION( "unitarity" ) {
2323 
2324  matr.real[0][0] = 0; // break matr unitarity
2325  REQUIRE_THROWS_WITH( unitary(quregVec, 0, matr), Contains("unitary") );
2326  }
2327  }
2328  CLEANUP_TEST( quregVec, quregMatr );
2329 }
void controlledRotateZ(Qureg qureg, int controlQubit, int targetQubit, qreal angle)
Applies a controlled rotation by a given angle around the Z-axis of the Bloch-sphere.
Definition: QuEST.c:245
Represents a 3-vector of real numbers.
Definition: QuEST.h:148
pauliOpType
Codes for specifying Pauli operators.
Definition: QuEST.h:96
QMatrix getFullOperatorMatrix(int *ctrls, int numCtrls, int *targs, int numTargs, QMatrix op, int numQubits)
Takes a 2^numTargs-by-2^numTargs matrix op and a returns a 2^numQubits-by-2^numQubits matrix where op...
Definition: utilities.cpp:293
void twoQubitUnitary(Qureg qureg, int targetQubit1, int targetQubit2, ComplexMatrix4 u)
Apply a general two-qubit unitary (including a global phase factor).
Definition: QuEST.c:257
void controlledRotateX(Qureg qureg, int controlQubit, int targetQubit, qreal angle)
Applies a controlled rotation by a given angle around the X-axis of the Bloch-sphere.
Definition: QuEST.c:221
qreal real[4][4]
Definition: QuEST.h:127
#define CLEANUP_TEST(quregVec, quregMatr)
Destroys the data structures made by PREPARE_TEST.
@ PAULI_Z
Definition: QuEST.h:96
void rotateAroundAxis(Qureg qureg, int rotQubit, qreal angle, Vector axis)
Rotate a single qubit by a given angle around a given Vector on the Bloch-sphere.
Definition: QuEST.c:575
void destroyComplexMatrixN(ComplexMatrixN m)
Destroy a ComplexMatrixN instance created with createComplexMatrixN()
Definition: QuEST.c:1120
@ PAULI_I
Definition: QuEST.h:96
int getRandomInt(int min, int max)
Returns a random integer between min (inclusive) and max (exclusive), from the uniform distribution.
Definition: utilities.cpp:481
TEST_CASE("compactUnitary", "[unitaries]")
ComplexMatrixN createComplexMatrixN(int numQubits)
Create (dynamically) a square complex matrix which can be passed to the multi-qubit general unitary f...
Definition: QuEST.c:1099
void controlledRotateAroundAxis(Qureg qureg, int controlQubit, int targetQubit, qreal angle, Vector axis)
Applies a controlled rotation by a given angle around a given vector on the Bloch-sphere.
Definition: QuEST.c:588
qreal z
Definition: QuEST.h:150
void multiControlledTwoQubitUnitary(Qureg qureg, int *controlQubits, int numControlQubits, int targetQubit1, int targetQubit2, ComplexMatrix4 u)
Apply a general multi-controlled two-qubit unitary (including a global phase factor).
Definition: QuEST.c:283
#define NUM_QUBITS
The default number of qubits in the registers created for unit testing (both statevectors and density...
Definition: utilities.hpp:36
QMatrix getRandomUnitary(int numQb)
Returns a uniformly random (under Haar) 2^numQb-by-2^numQb unitary matrix.
Definition: utilities.cpp:485
qreal getRandomReal(qreal min, qreal max)
Returns a random real between min (inclusive) and max (exclusive), from the uniform distribution.
Definition: utilities.cpp:410
void unitary(Qureg qureg, int targetQubit, ComplexMatrix2 u)
Apply a general single-qubit unitary (including a global phase factor).
Definition: QuEST.c:349
void sGate(Qureg qureg, int targetQubit)
Apply the single-qubit S gate.
Definition: QuEST.c:466
Represents a 4x4 matrix of complex numbers.
Definition: QuEST.h:125
void rotateY(Qureg qureg, int targetQubit, qreal angle)
Rotate a single qubit by a given angle around the Y-axis of the Bloch-sphere.
Definition: QuEST.c:199
void multiControlledPhaseShift(Qureg qureg, int *controlQubits, int numControlQubits, qreal angle)
Introduce a phase factor on state of the passed qubits.
Definition: QuEST.c:511
Represents a general 2^N by 2^N matrix of complex numbers.
Definition: QuEST.h:136
#define qreal
void multiRotatePauli(Qureg qureg, int *targetQubits, enum pauliOpType *targetPaulis, int numTargets, qreal angle)
Apply a multi-qubit multi-Pauli rotation on a selected number of qubits.
Definition: QuEST.c:642
QMatrix toQMatrix(ComplexMatrix2 src)
Returns a copy of the given 2-by-2 matrix.
Definition: utilities.cpp:869
unsigned int calcLog2(long unsigned int num)
returns log2 of numbers which must be gauranteed to be 2^n
void multiControlledPhaseFlip(Qureg qureg, int *controlQubits, int numControlQubits)
Apply the multiple-qubit controlled phase flip gate, also known as the multiple-qubit controlled paul...
Definition: QuEST.c:561
void multiQubitUnitary(Qureg qureg, int *targs, int numTargs, ComplexMatrixN u)
Apply a general multi-qubit unitary (including a global phase factor) with any number of target qubit...
Definition: QuEST.c:297
#define PREPARE_TEST(quregVec, quregMatr, refVec, refMatr)
Prepares the needed data structures for unit testing unitaries.
@ PAULI_X
Definition: QuEST.h:96
void controlledPauliY(Qureg qureg, int controlQubit, int targetQubit)
Apply the controlled pauliY (single control, single target) gate, also known as the c-Y and c-sigma-Y...
Definition: QuEST.c:537
QMatrix getExponentialOfPauliMatrix(qreal angle, QMatrix a)
Returns the matrix exponential of a kronecker product of pauli matrices (or of any involutory matrice...
Definition: utilities.cpp:205
void multiControlledMultiQubitUnitary(Qureg qureg, int *ctrls, int numCtrls, int *targs, int numTargs, ComplexMatrixN u)
Apply a general multi-controlled multi-qubit unitary (including a global phase factor).
Definition: QuEST.c:331
void toComplexMatrixN(QMatrix qm, ComplexMatrixN cm)
Initialises cm with the values of qm.
Definition: utilities.cpp:858
void rotateX(Qureg qureg, int targetQubit, qreal angle)
Rotate a single qubit by a given angle around the X-axis of the Bloch-sphere.
Definition: QuEST.c:188
qreal y
Definition: QuEST.h:150
qcomp expI(qreal phase)
Returns the unit-norm complex number exp(i*phase).
Definition: utilities.cpp:406
qreal x
Definition: QuEST.h:150
void pauliZ(Qureg qureg, int targetQubit)
Apply the single-qubit Pauli-Z (also known as the Z, sigma-Z or phase-flip) gate.
Definition: QuEST.c:455
void swapGate(Qureg qureg, int qb1, int qb2)
Performs a SWAP gate between qubit1 and qubit2.
Definition: QuEST.c:601
#define qcomp
ComplexMatrix4 toComplexMatrix4(QMatrix qm)
Returns a ComplexMatrix4 copy of QMatix qm.
Definition: utilities.cpp:852
#define toComplex(scalar)
void controlledPhaseFlip(Qureg qureg, int idQubit1, int idQubit2)
Apply the (two-qubit) controlled phase flip gate, also known as the controlled pauliZ gate.
Definition: QuEST.c:549
@ PAULI_Y
Definition: QuEST.h:96
void controlledMultiQubitUnitary(Qureg qureg, int ctrl, int *targs, int numTargs, ComplexMatrixN u)
Apply a general controlled multi-qubit unitary (including a global phase factor).
Definition: QuEST.c:314
qreal ** real
Definition: QuEST.h:139
void compactUnitary(Qureg qureg, int targetQubit, Complex alpha, Complex beta)
Apply a single-qubit unitary parameterised by two given complex scalars.
Definition: QuEST.c:405
void pauliY(Qureg qureg, int targetQubit)
Apply the single-qubit Pauli-Y (also known as the Y or sigma-Y) gate.
Definition: QuEST.c:444
void controlledPhaseShift(Qureg qureg, int idQubit1, int idQubit2, qreal angle)
Introduce a phase factor on state of qubits idQubit1 and idQubit2.
Definition: QuEST.c:499
void controlledUnitary(Qureg qureg, int controlQubit, int targetQubit, ComplexMatrix2 u)
Apply a general controlled unitary (single control, single target), which can include a global phase ...
Definition: QuEST.c:361
qreal ** imag
Definition: QuEST.h:140
void phaseShift(Qureg qureg, int targetQubit, qreal angle)
Shift the phase between and of a single qubit by a given angle.
Definition: QuEST.c:488
void controlledNot(Qureg qureg, int controlQubit, int targetQubit)
Apply the controlled not (single control, single target) gate, also known as the c-X,...
Definition: QuEST.c:525
qreal real[2][2]
Definition: QuEST.h:116
void pauliX(Qureg qureg, int targetQubit)
Apply the single-qubit Pauli-X (also known as the X, sigma-X, NOT or bit-flip) gate.
Definition: QuEST.c:433
std::vector< std::vector< qcomp > > QMatrix
A complex square matrix.
Definition: utilities.hpp:49
void controlledTwoQubitUnitary(Qureg qureg, int controlQubit, int targetQubit1, int targetQubit2, ComplexMatrix4 u)
Apply a general controlled two-qubit unitary (including a global phase factor).
Definition: QuEST.c:270
ComplexMatrix2 toComplexMatrix2(QMatrix qm)
Returns a ComplexMatrix2 copy of QMatix qm.
Definition: utilities.cpp:846
Catch::Generators::GeneratorWrapper< int * > sublists(int *list, int len, int sublen)
Returns a Catch2 generator of every length-sublen sublist of length-len list, in increasing lexograph...
Definition: utilities.cpp:1199
qreal real
Definition: QuEST.h:105
void tGate(Qureg qureg, int targetQubit)
Apply the single-qubit T gate.
Definition: QuEST.c:477
void multiRotateZ(Qureg qureg, int *qubits, int numQubits, qreal angle)
Apply a multi-qubit Z rotation on a selected number of qubits.
Definition: QuEST.c:626
QMatrix getKroneckerProduct(QMatrix a, QMatrix b)
Returns the kronecker product of a and b, where a and b are square but possibly differently-sized com...
Definition: utilities.cpp:169
QMatrix getExponentialOfDiagonalMatrix(QMatrix a)
Returns the matrix exponential of a diagonal, square, complex matrix.
Definition: utilities.cpp:187
void hadamard(Qureg qureg, int targetQubit)
Apply the single-qubit Hadamard gate.
Definition: QuEST.c:177
Represents one complex number.
Definition: QuEST.h:103
void rotateZ(Qureg qureg, int targetQubit, qreal angle)
Rotate a single qubit by a given angle around the Z-axis of the Bloch-sphere (also known as a phase s...
Definition: QuEST.c:210
void multiControlledUnitary(Qureg qureg, int *controlQubits, int numControlQubits, int targetQubit, ComplexMatrix2 u)
Apply a general multiple-control single-target unitary, which can include a global phase factor.
Definition: QuEST.c:374
bool areEqual(QVector a, QVector b)
Returns true if the absolute value of the difference between every amplitude in vectors a and b is le...
Definition: utilities.cpp:387
void applyReferenceOp(QVector &state, int *ctrls, int numCtrls, int *targs, int numTargs, QMatrix op)
Modifies the state-vector state to be the result of applying the multi-target operator matrix op,...
Definition: utilities.cpp:573
Catch::Generators::GeneratorWrapper< int * > bitsets(int numBits)
Returns a Catch2 generator of every numBits-length bit-set, in increasing lexographic order,...
Definition: utilities.cpp:1268
void controlledCompactUnitary(Qureg qureg, int controlQubit, int targetQubit, Complex alpha, Complex beta)
Apply a controlled unitary (single control, single target) parameterised by two given complex scalars...
Definition: QuEST.c:418
void multiStateControlledUnitary(Qureg qureg, int *controlQubits, int *controlState, int numControlQubits, int targetQubit, ComplexMatrix2 u)
Apply a general multiple-control, conditioned on a specific bit sequence, single-target unitary,...
Definition: QuEST.c:389
void sqrtSwapGate(Qureg qureg, int qb1, int qb2)
Performs a sqrt SWAP gate between qubit1 and qubit2.
Definition: QuEST.c:613
Represents a 2x2 matrix of complex numbers.
Definition: QuEST.h:114
void controlledRotateY(Qureg qureg, int controlQubit, int targetQubit, qreal angle)
Applies a controlled rotation by a given angle around the Y-axis of the Bloch-sphere.
Definition: QuEST.c:233