Unit tests

Unit tests of the QuEST API, using Catch2 in C++14. More...

Functions

 TEST_CASE ("applyDiagonalOp", "[operators]")
 
 TEST_CASE ("applyFullQFT", "[operators]")
 
 TEST_CASE ("applyMatrix2", "[operators]")
 
 TEST_CASE ("applyMatrix4", "[operators]")
 
 TEST_CASE ("applyMatrixN", "[operators]")
 
 TEST_CASE ("applyMultiControlledMatrixN", "[operators]")
 
 TEST_CASE ("applyMultiVarPhaseFunc", "[operators]")
 
 TEST_CASE ("applyMultiVarPhaseFuncOverrides", "[operators]")
 
 TEST_CASE ("applyNamedPhaseFunc", "[operators]")
 
 TEST_CASE ("applyNamedPhaseFuncOverrides", "[operators]")
 
 TEST_CASE ("applyParamNamedPhaseFunc", "[operators]")
 
 TEST_CASE ("applyParamNamedPhaseFuncOverrides", "[operators]")
 
 TEST_CASE ("applyPauliHamil", "[operators]")
 
 TEST_CASE ("applyPauliSum", "[operators]")
 
 TEST_CASE ("applyPhaseFunc", "[operators]")
 
 TEST_CASE ("applyPhaseFuncOverrides", "[operators]")
 
 TEST_CASE ("applyProjector", "[operators]")
 
 TEST_CASE ("applyQFT", "[operators]")
 
 TEST_CASE ("applyTrotterCircuit", "[operators]")
 
 TEST_CASE ("calcDensityInnerProduct", "[calculations]")
 
 TEST_CASE ("calcExpecDiagonalOp", "[calculations]")
 
 TEST_CASE ("calcExpecPauliHamil", "[calculations]")
 
 TEST_CASE ("calcExpecPauliProd", "[calculations]")
 
 TEST_CASE ("calcExpecPauliSum", "[calculations]")
 
 TEST_CASE ("calcFidelity", "[calculations]")
 
 TEST_CASE ("calcHilbertSchmidtDistance", "[calculations]")
 
 TEST_CASE ("calcInnerProduct", "[calculations]")
 
 TEST_CASE ("calcProbOfAllOutcomes", "[calculations]")
 
 TEST_CASE ("calcProbOfOutcome", "[calculations]")
 
 TEST_CASE ("calcPurity", "[calculations]")
 
 TEST_CASE ("calcTotalProb", "[calculations]")
 
 TEST_CASE ("cloneQureg", "[state_initialisations]")
 
 TEST_CASE ("collapseToOutcome", "[gates]")
 
 TEST_CASE ("compactUnitary", "[unitaries]")
 
 TEST_CASE ("controlledCompactUnitary", "[unitaries]")
 
 TEST_CASE ("controlledMultiQubitUnitary", "[unitaries]")
 
 TEST_CASE ("controlledNot", "[unitaries]")
 
 TEST_CASE ("controlledPauliY", "[unitaries]")
 
 TEST_CASE ("controlledPhaseFlip", "[unitaries]")
 
 TEST_CASE ("controlledPhaseShift", "[unitaries]")
 
 TEST_CASE ("controlledRotateAroundAxis", "[unitaries]")
 
 TEST_CASE ("controlledRotateX", "[unitaries]")
 
 TEST_CASE ("controlledRotateY", "[unitaries]")
 
 TEST_CASE ("controlledRotateZ", "[unitaries]")
 
 TEST_CASE ("controlledTwoQubitUnitary", "[unitaries]")
 
 TEST_CASE ("controlledUnitary", "[unitaries]")
 
 TEST_CASE ("createCloneQureg", "[data_structures]")
 
 TEST_CASE ("createComplexMatrixN", "[data_structures]")
 
 TEST_CASE ("createDensityQureg", "[data_structures]")
 
 TEST_CASE ("createDiagonalOp", "[data_structures]")
 
 TEST_CASE ("createDiagonalOpFromPauliHamilFile", "[data_structures]")
 
 TEST_CASE ("createPauliHamil", "[data_structures]")
 
 TEST_CASE ("createPauliHamilFromFile", "[data_structures]")
 
 TEST_CASE ("createQuESTEnv", "[data_structures]")
 
 TEST_CASE ("createQureg", "[data_structures]")
 
 TEST_CASE ("destroyComplexMatrixN", "[data_structures]")
 
 TEST_CASE ("destroyDiagonalOp", "[data_structures]")
 
 TEST_CASE ("destroyPauliHamil", "[data_structures]")
 
 TEST_CASE ("destroyQuESTEnv", "[data_structures]")
 
 TEST_CASE ("destroyQureg", "[data_structures]")
 
 TEST_CASE ("fromComplex", "[data_structures]")
 
 TEST_CASE ("getAmp", "[calculations]")
 
 TEST_CASE ("getDensityAmp", "[calculations]")
 
 TEST_CASE ("getImagAmp", "[calculations]")
 
 TEST_CASE ("getNumAmps", "[calculations]")
 
 TEST_CASE ("getNumQubits", "[calculations]")
 
 TEST_CASE ("getProbAmp", "[calculations]")
 
 TEST_CASE ("getRealAmp", "[calculations]")
 
 TEST_CASE ("getStaticComplexMatrixN", "[data_structures]")
 
 TEST_CASE ("hadamard", "[unitaries]")
 
 TEST_CASE ("initBlankState", "[state_initialisations]")
 
 TEST_CASE ("initClassicalState", "[state_initialisations]")
 
 TEST_CASE ("initComplexMatrixN", "[data_structures]")
 
 TEST_CASE ("initDiagonalOp", "[data_structures]")
 
 TEST_CASE ("initDiagonalOpFromPauliHamil", "[data_structures]")
 
 TEST_CASE ("initPauliHamil", "[data_structures]")
 
 TEST_CASE ("initPlusState", "[state_initialisations]")
 
 TEST_CASE ("initPureState", "[state_initialisations]")
 
 TEST_CASE ("initStateFromAmps", "[state_initialisations]")
 
 TEST_CASE ("initZeroState", "[state_initialisations]")
 
 TEST_CASE ("measure", "[gates]")
 
 TEST_CASE ("measureWithStats", "[gates]")
 
 TEST_CASE ("mixDamping", "[decoherence]")
 
 TEST_CASE ("mixDensityMatrix", "[decoherence]")
 
 TEST_CASE ("mixDephasing", "[decoherence]")
 
 TEST_CASE ("mixDepolarising", "[decoherence]")
 
 TEST_CASE ("mixKrausMap", "[decoherence]")
 
 TEST_CASE ("mixMultiQubitKrausMap", "[decoherence]")
 
 TEST_CASE ("mixPauli", "[decoherence]")
 
 TEST_CASE ("mixTwoQubitDephasing", "[decoherence]")
 
 TEST_CASE ("mixTwoQubitDepolarising", "[decoherence]")
 
 TEST_CASE ("mixTwoQubitKrausMap", "[decoherence]")
 
 TEST_CASE ("multiControlledMultiQubitNot", "[unitaries]")
 
 TEST_CASE ("multiControlledMultiQubitUnitary", "[unitaries]")
 
 TEST_CASE ("multiControlledMultiRotatePauli", "[unitaries]")
 
 TEST_CASE ("multiControlledMultiRotateZ", "[unitaries]")
 
 TEST_CASE ("multiControlledPhaseFlip", "[unitaries]")
 
 TEST_CASE ("multiControlledPhaseShift", "[unitaries]")
 
 TEST_CASE ("multiControlledTwoQubitUnitary", "[unitaries]")
 
 TEST_CASE ("multiControlledUnitary", "[unitaries]")
 
 TEST_CASE ("multiQubitNot", "[unitaries]")
 
 TEST_CASE ("multiQubitUnitary", "[unitaries]")
 
 TEST_CASE ("multiRotatePauli", "[unitaries]")
 
 TEST_CASE ("multiRotateZ", "[unitaries]")
 
 TEST_CASE ("multiStateControlledUnitary", "[unitaries]")
 
 TEST_CASE ("pauliX", "[unitaries]")
 
 TEST_CASE ("pauliY", "[unitaries]")
 
 TEST_CASE ("pauliZ", "[unitaries]")
 
 TEST_CASE ("phaseShift", "[unitaries]")
 
 TEST_CASE ("rotateAroundAxis", "[unitaries]")
 
 TEST_CASE ("rotateX", "[unitaries]")
 
 TEST_CASE ("rotateY", "[unitaries]")
 
 TEST_CASE ("rotateZ", "[unitaries]")
 
 TEST_CASE ("setAmps", "[state_initialisations]")
 
 TEST_CASE ("setDiagonalOpElems", "[data_structures]")
 
 TEST_CASE ("setWeightedQureg", "[state_initialisations]")
 
 TEST_CASE ("sGate", "[unitaries]")
 
 TEST_CASE ("sqrtSwapGate", "[unitaries]")
 
 TEST_CASE ("swapGate", "[unitaries]")
 
 TEST_CASE ("syncDiagonalOp", "[data_structures]")
 
 TEST_CASE ("tGate", "[unitaries]")
 
 TEST_CASE ("toComplex", "[data_structures]")
 
 TEST_CASE ("twoQubitUnitary", "[unitaries]")
 
 TEST_CASE ("unitary", "[unitaries]")
 

Detailed Description

Unit tests of the QuEST API, using Catch2 in C++14.

Function Documentation

◆ TEST_CASE() [1/124]

TEST_CASE ( "applyDiagonalOp"  ,
""  [operators] 
)
See also
applyDiagonalOp
Author
Tyson Jones

Definition at line 32 of file test_operators.cpp.

32  {
33 
34  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
35 
36  SECTION( "correctness" ) {
37 
38  // try 10 random operators
39  GENERATE( range(0,10) );
40 
41  // make a totally random (non-Hermitian) diagonal oeprator
43  for (long long int i=0; i<op.numElemsPerChunk; i++) {
44  op.real[i] = getRandomReal(-5, 5);
45  op.imag[i] = getRandomReal(-5, 5);
46  }
47  syncDiagonalOp(op);
48 
49  SECTION( "state-vector" ) {
50 
51  QVector ref = toQMatrix(op) * refVec;
52  applyDiagonalOp(quregVec, op);
53  REQUIRE( areEqual(quregVec, ref) );
54  }
55  SECTION( "density-matrix" ) {
56 
57  QMatrix ref = toQMatrix(op) * refMatr;
58  applyDiagonalOp(quregMatr, op);
59  REQUIRE( areEqual(quregMatr, ref, 100*REAL_EPS) );
60  }
61 
63  }
64  SECTION( "input validation" ) {
65 
66  SECTION( "mismatching size" ) {
67 
69 
70  REQUIRE_THROWS_WITH( applyDiagonalOp(quregVec, op), Contains("equal number of qubits"));
71  REQUIRE_THROWS_WITH( applyDiagonalOp(quregMatr, op), Contains("equal number of qubits"));
72 
74  }
75  }
76  CLEANUP_TEST( quregVec, quregMatr );
77 }

References applyDiagonalOp(), areEqual(), CLEANUP_TEST, createDiagonalOp(), destroyDiagonalOp(), getRandomReal(), DiagonalOp::imag, NUM_QUBITS, DiagonalOp::numElemsPerChunk, PREPARE_TEST, QUEST_ENV, DiagonalOp::real, syncDiagonalOp(), and toQMatrix().

◆ TEST_CASE() [2/124]

TEST_CASE ( "applyFullQFT"  ,
""  [operators] 
)
See also
applyFullQFT
Author
Tyson Jones

Definition at line 83 of file test_operators.cpp.

83  {
84 
85  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
86 
87  SECTION( "correctness" ) {
88 
89  // try 10 times for each kind of input
90  GENERATE( range(0,10) );
91 
92  SECTION( "state-vector" ) {
93 
94  SECTION( "normalised" ) {
95 
97  toQureg(quregVec, refVec);
98  refVec = getDFT(refVec);
99 
100  applyFullQFT(quregVec);
101  REQUIRE( areEqual(quregVec, refVec) );
102  }
103  SECTION( "unnormalised" ) {
104 
105  refVec = getRandomQVector(1 << NUM_QUBITS);
106  toQureg(quregVec, refVec);
107  refVec = getDFT(refVec);
108 
109  applyFullQFT(quregVec);
110  REQUIRE( areEqual(quregVec, refVec) );
111  }
112  }
113  SECTION( "density-matrix" ) {
114 
115  SECTION( "pure" ) {
116 
117  /* a pure density matrix should be mapped to a pure state
118  * corresponding to the state-vector DFT
119  */
120 
122  refMatr = getPureDensityMatrix(refVec);
123 
124  toQureg(quregMatr, refMatr);
125  applyFullQFT(quregMatr);
126 
127  refVec = getDFT(refVec);
128  refMatr = getPureDensityMatrix(refVec);
129 
130  REQUIRE( areEqual(quregMatr, refMatr) );
131  }
132  SECTION( "mixed" ) {
133 
134  /* a mixed density matrix, conceptualised as a mixture of orthogonal
135  * state-vectors, should be mapped to an equally weighted mixture
136  * of DFTs of each state-vector (because QFT is unitary and hence
137  * maintains state orthogonality)
138  */
139 
140  int numStates = (1 << NUM_QUBITS)/4; // quarter as many states as possible
141  std::vector<QVector> states = getRandomOrthonormalVectors(NUM_QUBITS, numStates);
142  std::vector<qreal> probs = getRandomProbabilities(numStates);
143 
144  // set qureg to random mixture
145  refMatr = getMixedDensityMatrix(probs, states);
146  toQureg(quregMatr, refMatr);
147 
148  // apply QFT to mixture
149  applyFullQFT(quregMatr);
150 
151  // compute dft of mixture, via dft of each state
152  refMatr = getZeroMatrix(1 << NUM_QUBITS);
153  for (int i=0; i<numStates; i++)
154  refMatr += probs[i] * getPureDensityMatrix(getDFT(states[i]));
155 
156  REQUIRE( areEqual(quregMatr, refMatr) );
157  }
158  SECTION( "unnormalised" ) {
159 
160  /* repeat method above, except that we use unnormalised vectors,
161  * and mix them with arbitrary complex numbers instead of probabilities,
162  * yielding an unnormalised density matrix
163  */
164 
165  int numVecs = (1 << NUM_QUBITS)/4; // quarter as many states as possible
166  std::vector<QVector> vecs;
167  std::vector<qcomp> coeffs;
168  for (int i=0; i<numVecs; i++) {
169  vecs.push_back(getRandomQVector(1 << NUM_QUBITS));
170  coeffs.push_back(getRandomComplex());
171  }
172 
173  // produce unnormalised matrix
174  refMatr = getZeroMatrix(1 << NUM_QUBITS);
175  for (int i=0; i<numVecs; i++)
176  refMatr += coeffs[i] * getPureDensityMatrix(vecs[i]);
177 
178  toQureg(quregMatr, refMatr);
179  applyFullQFT(quregMatr);
180 
181  // compute target matrix via dft of each unnormalised vector
182  refMatr = getZeroMatrix(1 << NUM_QUBITS);
183  for (int i=0; i<numVecs; i++)
184  refMatr += coeffs[i] * getPureDensityMatrix(getDFT(vecs[i]));
185 
186  REQUIRE( areEqual(quregMatr, refMatr) );
187  }
188  }
189  }
190  SECTION( "input validation" ) {
191 
192  SUCCEED( );
193  }
194  CLEANUP_TEST( quregVec, quregMatr );
195 }

References applyFullQFT(), areEqual(), CLEANUP_TEST, getDFT(), getMixedDensityMatrix(), getPureDensityMatrix(), getRandomComplex(), getRandomOrthonormalVectors(), getRandomProbabilities(), getRandomQVector(), getRandomStateVector(), getZeroMatrix(), NUM_QUBITS, PREPARE_TEST, and toQureg().

◆ TEST_CASE() [3/124]

TEST_CASE ( "applyMatrix2"  ,
""  [operators] 
)
See also
applyMatrix2
Author
Tyson Jones

Definition at line 203 of file test_operators.cpp.

203  {
204 
205  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
206 
207  // every test will use a unique random matrix
208  QMatrix op = getRandomQMatrix(2); // 2-by-2
209  ComplexMatrix2 matr = toComplexMatrix2(op);
210 
211  SECTION( "correctness" ) {
212 
213  int target = GENERATE( range(0,NUM_QUBITS) );
214 
215  // reference boilerplate
216  int* ctrls = NULL;
217  int numCtrls = 0;
218  int targs[] = {target};
219  int numTargs = 1;
220 
221  SECTION( "state-vector" ) {
222 
223  applyMatrix2(quregVec, target, matr);
224  applyReferenceMatrix(refVec, ctrls, numCtrls, targs, numTargs, op);
225 
226  REQUIRE( areEqual(quregVec, refVec) );
227  }
228  SECTION( "density-matrix" ) {
229 
230  applyMatrix2(quregMatr, target, matr);
231  applyReferenceMatrix(refMatr, ctrls, numCtrls, targs, numTargs, op);
232 
233  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
234  }
235  }
236  SECTION( "input validation" ) {
237 
238  SECTION( "qubit indices" ) {
239 
240  int target = GENERATE( -1, NUM_QUBITS );
241  REQUIRE_THROWS_WITH( applyMatrix2(quregVec, target, matr), Contains("Invalid target") );
242  }
243  }
244  CLEANUP_TEST( quregVec, quregMatr );
245 }

References applyMatrix2(), applyReferenceMatrix(), areEqual(), CLEANUP_TEST, getRandomQMatrix(), NUM_QUBITS, PREPARE_TEST, and toComplexMatrix2().

◆ TEST_CASE() [4/124]

TEST_CASE ( "applyMatrix4"  ,
""  [operators] 
)
See also
applyMatrix4
Author
Tyson Jones

Definition at line 253 of file test_operators.cpp.

253  {
254 
255  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
256 
257  // in distributed mode, each node must be able to fit all amps modified by matrix
258  REQUIRE( quregVec.numAmpsPerChunk >= 4 );
259 
260  // every test will use a unique random matrix
261  QMatrix op = getRandomQMatrix(4); // 4-by-4
262  ComplexMatrix4 matr = toComplexMatrix4(op);
263 
264  SECTION( "correctness" ) {
265 
266  int targ1 = GENERATE( range(0,NUM_QUBITS) );
267  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
268 
269  // reference boilerplate
270  int* ctrls = NULL;
271  int numCtrls = 0;
272  int targs[] = {targ1, targ2};
273  int numTargs = 2;
274 
275  SECTION( "state-vector" ) {
276 
277  applyMatrix4(quregVec, targ1, targ2, matr);
278  applyReferenceMatrix(refVec, ctrls, numCtrls, targs, numTargs, op);
279  REQUIRE( areEqual(quregVec, refVec) );
280  }
281  SECTION( "density-matrix" ) {
282 
283  applyMatrix4(quregMatr, targ1, targ2, matr);
284  applyReferenceMatrix(refMatr, ctrls, numCtrls, targs, numTargs, op);
285  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
286  }
287  }
288  SECTION( "input validation" ) {
289 
290  SECTION( "qubit indices" ) {
291 
292  int targ1 = GENERATE( -1, NUM_QUBITS );
293  int targ2 = 0;
294  REQUIRE_THROWS_WITH( applyMatrix4(quregVec, targ1, targ2, matr), Contains("Invalid target") );
295  REQUIRE_THROWS_WITH( applyMatrix4(quregVec, targ2, targ1, matr), Contains("Invalid target") );
296  }
297  SECTION( "repetition of targets" ) {
298 
299  int qb = 0;
300  REQUIRE_THROWS_WITH( applyMatrix4(quregVec, qb, qb, matr), Contains("target") && Contains("unique") );
301  }
302  SECTION( "matrix fits in node" ) {
303 
304  // pretend we have a very limited distributed memory
305  quregVec.numAmpsPerChunk = 1;
306  REQUIRE_THROWS_WITH( applyMatrix4(quregVec, 0, 1, matr), Contains("targets too many qubits"));
307  }
308  }
309  CLEANUP_TEST( quregVec, quregMatr );
310 }

References applyMatrix4(), applyReferenceMatrix(), areEqual(), CLEANUP_TEST, getRandomQMatrix(), NUM_QUBITS, PREPARE_TEST, and toComplexMatrix4().

◆ TEST_CASE() [5/124]

TEST_CASE ( "applyMatrixN"  ,
""  [operators] 
)
See also
applyMatrixN
Author
Tyson Jones

Definition at line 318 of file test_operators.cpp.

318  {
319 
320  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
321 
322  // figure out max-num (inclusive) targs allowed by hardware backend
323  int maxNumTargs = calcLog2(quregVec.numAmpsPerChunk);
324 
325  SECTION( "correctness" ) {
326 
327  // generate all possible qubit arrangements
328  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) ); // inclusive upper bound
329  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
330 
331  // for each qubit arrangement, use a new random matrix
332  QMatrix op = getRandomQMatrix(1 << numTargs);
333  ComplexMatrixN matr = createComplexMatrixN(numTargs);
334  toComplexMatrixN(op, matr);
335 
336  // reference boilerplate
337  int* ctrls = NULL;
338  int numCtrls = 0;
339 
340  SECTION( "state-vector" ) {
341 
342  applyMatrixN(quregVec, targs, numTargs, matr);
343  applyReferenceMatrix(refVec, ctrls, numCtrls, targs, numTargs, op);
344  REQUIRE( areEqual(quregVec, refVec) );
345  }
346  SECTION( "density-matrix" ) {
347 
348  applyMatrixN(quregMatr, targs, numTargs, matr);
349  applyReferenceMatrix(refMatr, ctrls, numCtrls, targs, numTargs, op);
350  REQUIRE( areEqual(quregMatr, refMatr, 100*REAL_EPS) );
351  }
352  destroyComplexMatrixN(matr);
353  }
354  SECTION( "input validation" ) {
355 
356  SECTION( "number of targets" ) {
357 
358  // there cannot be more targets than qubits in register
359  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
360  int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
361  ComplexMatrixN matr = createComplexMatrixN(NUM_QUBITS+1); // prevent seg-fault
362 
363  REQUIRE_THROWS_WITH( applyMatrixN(quregVec, targs, numTargs, matr), Contains("Invalid number of target"));
364  destroyComplexMatrixN(matr);
365  }
366  SECTION( "repetition in targets" ) {
367 
368  int numTargs = 3;
369  int targs[] = {1,2,2};
370  ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
371 
372  REQUIRE_THROWS_WITH( applyMatrixN(quregVec, targs, numTargs, matr), Contains("target") && Contains("unique"));
373  destroyComplexMatrixN(matr);
374  }
375  SECTION( "qubit indices" ) {
376 
377  int numTargs = 3;
378  int targs[] = {1,2,3};
379  ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
380 
381  int inv = GENERATE( -1, NUM_QUBITS );
382  targs[GENERATE_COPY( range(0,numTargs) )] = inv; // make invalid target
383  REQUIRE_THROWS_WITH( applyMatrixN(quregVec, targs, numTargs, matr), Contains("Invalid target") );
384 
385  destroyComplexMatrixN(matr);
386  }
387  SECTION( "matrix creation" ) {
388 
389  int numTargs = 3;
390  int targs[] = {1,2,3};
391 
392  /* compilers don't auto-initialise to NULL; the below circumstance
393  * only really occurs when 'malloc' returns NULL in createComplexMatrixN,
394  * which actually triggers its own validation. Hence this test is useless
395  * currently.
396  */
397  ComplexMatrixN matr;
398  matr.real = NULL;
399  matr.imag = NULL;
400  REQUIRE_THROWS_WITH( applyMatrixN(quregVec, targs, numTargs, matr), Contains("created") );
401  }
402  SECTION( "matrix dimensions" ) {
403 
404  int targs[2] = {1,2};
405  ComplexMatrixN matr = createComplexMatrixN(3); // intentionally wrong size
406 
407  REQUIRE_THROWS_WITH( applyMatrixN(quregVec, targs, 2, matr), Contains("matrix size"));
408  destroyComplexMatrixN(matr);
409  }
410  SECTION( "matrix fits in node" ) {
411 
412  // pretend we have a very limited distributed memory (judged by matr size)
413  quregVec.numAmpsPerChunk = 1;
414  int qb[] = {1,2};
415  ComplexMatrixN matr = createComplexMatrixN(2); // prevents seg-fault if validation doesn't trigger
416  REQUIRE_THROWS_WITH( applyMatrixN(quregVec, qb, 2, matr), Contains("targets too many qubits"));
417  destroyComplexMatrixN(matr);
418  }
419  }
420  CLEANUP_TEST( quregVec, quregMatr );
421 }

References applyMatrixN(), applyReferenceMatrix(), areEqual(), calcLog2(), CLEANUP_TEST, createComplexMatrixN(), destroyComplexMatrixN(), getRandomQMatrix(), ComplexMatrixN::imag, NUM_QUBITS, PREPARE_TEST, ComplexMatrixN::real, sublists(), and toComplexMatrixN().

◆ TEST_CASE() [6/124]

TEST_CASE ( "applyMultiControlledMatrixN"  ,
""  [operators] 
)
See also
applyMultiControlledMatrixN
Author
Tyson Jones

Definition at line 429 of file test_operators.cpp.

429  {
430 
431  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
432 
433  // figure out max-num targs (inclusive) allowed by hardware backend
434  int maxNumTargs = calcLog2(quregVec.numAmpsPerChunk);
435  if (maxNumTargs >= NUM_QUBITS)
436  maxNumTargs = NUM_QUBITS - 1; // leave room for min-number of control qubits
437 
438  SECTION( "correctness" ) {
439 
440  // try all possible numbers of targets and controls
441  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
442  int maxNumCtrls = NUM_QUBITS - numTargs;
443  int numCtrls = GENERATE_COPY( range(1,maxNumCtrls+1) );
444 
445  // generate all possible valid qubit arrangements
446  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
447  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, targs, numTargs) );
448 
449  // for each qubit arrangement, use a new random unitary
450  QMatrix op = getRandomQMatrix(1 << numTargs);
451  ComplexMatrixN matr = createComplexMatrixN(numTargs);
452  toComplexMatrixN(op, matr);
453 
454  SECTION( "state-vector" ) {
455 
456  applyMultiControlledMatrixN(quregVec, ctrls, numCtrls, targs, numTargs, matr);
457  applyReferenceMatrix(refVec, ctrls, numCtrls, targs, numTargs, op);
458  REQUIRE( areEqual(quregVec, refVec) );
459  }
460  SECTION( "density-matrix" ) {
461 
462  applyMultiControlledMatrixN(quregMatr, ctrls, numCtrls, targs, numTargs, matr);
463  applyReferenceMatrix(refMatr, ctrls, numCtrls, targs, numTargs, op);
464  REQUIRE( areEqual(quregMatr, refMatr, 100*REAL_EPS) );
465  }
466  destroyComplexMatrixN(matr);
467  }
468  SECTION( "input validation" ) {
469 
470  SECTION( "number of targets" ) {
471 
472  // there cannot be more targets than qubits in register
473  // (numTargs=NUM_QUBITS is caught elsewhere, because that implies ctrls are invalid)
474  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
475  int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
476  int ctrls[] = {0};
477  ComplexMatrixN matr = createComplexMatrixN(NUM_QUBITS+1); // prevent seg-fault
478  toComplexMatrixN(getRandomQMatrix( 1 << (NUM_QUBITS+1)), matr);
479 
480  REQUIRE_THROWS_WITH( applyMultiControlledMatrixN(quregVec, ctrls, 1, targs, numTargs, matr), Contains("Invalid number of target"));
481  destroyComplexMatrixN(matr);
482  }
483  SECTION( "repetition in targets" ) {
484 
485  int ctrls[] = {0};
486  int numTargs = 3;
487  int targs[] = {1,2,2};
488  ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
489  toComplexMatrixN(getRandomQMatrix(1 << numTargs), matr);
490 
491  REQUIRE_THROWS_WITH( applyMultiControlledMatrixN(quregVec, ctrls, 1, targs, numTargs, matr), Contains("target") && Contains("unique"));
492  destroyComplexMatrixN(matr);
493  }
494  SECTION( "number of controls" ) {
495 
496  int numCtrls = GENERATE( -1, 0, NUM_QUBITS, NUM_QUBITS+1 );
497  int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
498  int targs[1] = {0};
500  toComplexMatrixN(getRandomQMatrix(1 << 1), matr);
501 
502  REQUIRE_THROWS_WITH( applyMultiControlledMatrixN(quregVec, ctrls, numCtrls, targs, 1, matr), Contains("Invalid number of control"));
503  destroyComplexMatrixN(matr);
504  }
505  SECTION( "repetition in controls" ) {
506 
507  int ctrls[] = {0,1,1};
508  int targs[] = {3};
510  toComplexMatrixN(getRandomQMatrix(1 << 1), matr);
511 
512  REQUIRE_THROWS_WITH( applyMultiControlledMatrixN(quregVec, ctrls, 3, targs, 1, matr), Contains("control") && Contains("unique"));
513  destroyComplexMatrixN(matr);
514  }
515  SECTION( "control and target collision" ) {
516 
517  int ctrls[] = {0,1,2};
518  int targs[] = {3,1,4};
520  toComplexMatrixN(getRandomQMatrix(1 << 3), matr);
521 
522  REQUIRE_THROWS_WITH( applyMultiControlledMatrixN(quregVec, ctrls, 3, targs, 3, matr), Contains("Control") && Contains("target") && Contains("disjoint"));
523  destroyComplexMatrixN(matr);
524  }
525  SECTION( "qubit indices" ) {
526 
527  // valid inds
528  int numQb = 2;
529  int qb1[2] = {0,1};
530  int qb2[2] = {2,3};
531  ComplexMatrixN matr = createComplexMatrixN(numQb);
532  toComplexMatrixN(getRandomQMatrix(1 << numQb), matr);
533 
534  // make qb1 invalid
535  int inv = GENERATE( -1, NUM_QUBITS );
536  qb1[GENERATE_COPY(range(0,numQb))] = inv;
537 
538  REQUIRE_THROWS_WITH( applyMultiControlledMatrixN(quregVec, qb1, numQb, qb2, numQb, matr), Contains("Invalid control") );
539  REQUIRE_THROWS_WITH( applyMultiControlledMatrixN(quregVec, qb2, numQb, qb1, numQb, matr), Contains("Invalid target") );
540  destroyComplexMatrixN(matr);
541  }
542  SECTION( "matrix creation" ) {
543 
544  int ctrls[1] = {0};
545  int targs[3] = {1,2,3};
546 
547  /* compilers don't auto-initialise to NULL; the below circumstance
548  * only really occurs when 'malloc' returns NULL in createComplexMatrixN,
549  * which actually triggers its own validation. Hence this test is useless
550  * currently.
551  */
552  ComplexMatrixN matr;
553  matr.real = NULL;
554  matr.imag = NULL;
555  REQUIRE_THROWS_WITH( applyMultiControlledMatrixN(quregVec, ctrls, 1, targs, 3, matr), Contains("created") );
556  }
557  SECTION( "matrix dimensions" ) {
558 
559  int ctrls[1] = {0};
560  int targs[2] = {1,2};
561  ComplexMatrixN matr = createComplexMatrixN(3); // intentionally wrong size
562  toComplexMatrixN(getRandomQMatrix(1 << 3), matr);
563 
564  REQUIRE_THROWS_WITH( applyMultiControlledMatrixN(quregVec, ctrls, 1, targs, 2, matr), Contains("matrix size"));
565  destroyComplexMatrixN(matr);
566  }
567  SECTION( "matrix fits in node" ) {
568 
569  // pretend we have a very limited distributed memory (judged by matr size)
570  quregVec.numAmpsPerChunk = 1;
571  int ctrls[1] = {0};
572  int targs[2] = {1,2};
574  toComplexMatrixN(getRandomQMatrix(1 << 2), matr);
575 
576  REQUIRE_THROWS_WITH( applyMultiControlledMatrixN(quregVec, ctrls, 1, targs, 2, matr), Contains("targets too many qubits"));
577  destroyComplexMatrixN(matr);
578  }
579  }
580  CLEANUP_TEST( quregVec, quregMatr );
581 }

References applyMultiControlledMatrixN(), applyReferenceMatrix(), areEqual(), calcLog2(), CLEANUP_TEST, createComplexMatrixN(), destroyComplexMatrixN(), getRandomQMatrix(), ComplexMatrixN::imag, NUM_QUBITS, PREPARE_TEST, ComplexMatrixN::real, sublists(), and toComplexMatrixN().

◆ TEST_CASE() [7/124]

TEST_CASE ( "applyMultiVarPhaseFunc"  ,
""  [operators] 
)
See also
applyMultiVarPhaseFunc
Author
Tyson Jones

Definition at line 589 of file test_operators.cpp.

589  {
590 
591  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
592 
593  SECTION( "correctness" ) {
594 
595  // try every kind of binary encodings
596  enum bitEncoding encoding = GENERATE( UNSIGNED,TWOS_COMPLEMENT );
597 
598  // try every possible number of registers
599  // (between #qubits containing 1, and 1 containing #qubits)
600  int numRegs;
601  int maxNumRegs = 0;
602  if (encoding == UNSIGNED)
603  maxNumRegs = NUM_QUBITS;
604  if (encoding == TWOS_COMPLEMENT)
605  maxNumRegs = NUM_QUBITS/2; // floors
606  numRegs = GENERATE_COPY( range(1, maxNumRegs+1) );
607 
608  // try every possible total number of involed qubits
609  int totalNumQubits;
610  int minTotalQubits = 0;
611  if (encoding == UNSIGNED)
612  // each register must contain at least 1 qubit
613  minTotalQubits = numRegs;
614  if (encoding == TWOS_COMPLEMENT)
615  // each register must contain at least 2 qubits
616  minTotalQubits = 2*numRegs;
617  totalNumQubits = GENERATE_COPY( range(minTotalQubits,NUM_QUBITS+1) );
618 
619  // try every qubits subset and ordering
620  int* regs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), totalNumQubits) );
621 
622  // assign each sub-reg its minimum length
623  int unallocQubits = totalNumQubits;
624  int numQubitsPerReg[numRegs];
625  for (int i=0; i<numRegs; i++)
626  if (encoding == UNSIGNED) {
627  numQubitsPerReg[i] = 1;
628  unallocQubits -= 1;
629  }
630  else if (encoding == TWOS_COMPLEMENT) {
631  numQubitsPerReg[i] = 2;
632  unallocQubits -= 2;
633  }
634  // and randomly allocate the remaining qubits between the registers
635  while (unallocQubits > 0) {
636  numQubitsPerReg[getRandomInt(0,numRegs)] += 1;
637  unallocQubits--;
638  }
639 
640 
641  // each register gets a random number of terms in the full phase function
642  int numTermsPerReg[numRegs];
643  int numTermsTotal = 0;
644  for (int r=0; r<numRegs; r++) {
645  int numTerms = getRandomInt(1,5);
646  numTermsPerReg[r] = numTerms;
647  numTermsTotal += numTerms;
648  }
649 
650  // populate the multi-var phase function with random but POSITIVE-power terms,
651  // which must further be integers in two's complement
652  int flatInd = 0;
653  qreal coeffs[numTermsTotal];
654  qreal expons[numTermsTotal];
655  for (int r=0; r<numRegs; r++) {
656  for (int t=0; t<numTermsPerReg[r]; t++) {
657  coeffs[flatInd] = getRandomReal(-10,10);
658  if (encoding == TWOS_COMPLEMENT)
659  expons[flatInd] = getRandomInt(0, 3+1);
660  else if (encoding == UNSIGNED)
661  expons[flatInd] = getRandomReal(0, 3);
662 
663  flatInd++;
664  }
665  }
666 
667  /* To perform this calculation more distinctly from the QuEST
668  * core method, we can exploit that
669  * exp(i (f1[x1] + f2[x2]))|x2>|x1> = exp(i f2[x2])|x2> (x) exp(i f1[x1])|x1>
670  * and so compute a separate diagonal matrix for each sub-register with
671  * phases determined only by its own variable, and Kronecker multiply
672  * them together. The target qubits of the Kronecker product is then
673  * just the full register, stored in *regs.
674  */
675  QMatrix allRegMatr{{1}};
676  int startInd = 0;
677 
678  for (int r=0; r<numRegs; r++) {
679 
680  QMatrix singleRegMatr = getZeroMatrix( 1 << numQubitsPerReg[r] );
681 
682  for (size_t i=0; i<singleRegMatr.size(); i++) {
683 
684  long long int ind = 0;
685  if (encoding == UNSIGNED)
686  ind = i;
687  if (encoding == TWOS_COMPLEMENT)
688  ind = getTwosComplement(i, numQubitsPerReg[r]);
689 
690  qreal phase = 0;
691  for (int t=0; t<numTermsPerReg[r]; t++)
692  phase += coeffs[t+startInd] * pow(ind, expons[t+startInd]);
693 
694  singleRegMatr[i][i] = expI(phase);
695  }
696  allRegMatr = getKroneckerProduct(singleRegMatr, allRegMatr);
697  startInd += numTermsPerReg[r];
698  }
699 
700  SECTION( "state-vector" ) {
701 
702  applyMultiVarPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, encoding, coeffs, expons, numTermsPerReg);
703  applyReferenceOp(refVec, regs, totalNumQubits, allRegMatr);
704  REQUIRE( areEqual(quregVec, refVec, 1E4*REAL_EPS) );
705  }
706  SECTION( "density-matrix" ) {
707 
708  applyMultiVarPhaseFunc(quregMatr, regs, numQubitsPerReg, numRegs, encoding, coeffs, expons, numTermsPerReg);
709  applyReferenceOp(refMatr, regs, totalNumQubits, allRegMatr);
710  REQUIRE( areEqual(quregMatr, refMatr, 1E6*REAL_EPS) );
711  }
712  }
713  SECTION( "input validation" ) {
714 
715  int numRegs = 2;
716  int numQubitsPerReg[] = {2,3};
717  int qubits[] = {0,1,2,3,4};
718 
719  SECTION( "number of registers" ) {
720 
721  numRegs = GENERATE_COPY( -1, 0, 1+MAX_NUM_REGS_APPLY_ARBITRARY_PHASE );
722  REQUIRE_THROWS_WITH( applyMultiVarPhaseFunc(quregVec, qubits, numQubitsPerReg, numRegs, UNSIGNED, NULL, NULL, NULL), Contains("Invalid number of qubit subregisters") );
723  }
724  SECTION( "number of qubits" ) {
725 
726  numQubitsPerReg[GENERATE_COPY(range(0,numRegs))] = GENERATE( -1, 0, 1+NUM_QUBITS );
727  REQUIRE_THROWS_WITH( applyMultiVarPhaseFunc(quregVec, qubits, numQubitsPerReg, numRegs, UNSIGNED, NULL, NULL, NULL), Contains("Invalid number of qubits") );
728  }
729  SECTION( "repetition of qubits" ) {
730 
731  qubits[GENERATE(2,3,4)] = qubits[1];
732  REQUIRE_THROWS_WITH( applyMultiVarPhaseFunc(quregVec, qubits, numQubitsPerReg, numRegs, UNSIGNED, NULL, NULL, NULL), Contains("The qubits must be unique") );
733  }
734  SECTION( "qubit indices" ) {
735 
736  qubits[GENERATE(range(0,NUM_QUBITS))] = GENERATE( -1, NUM_QUBITS );
737  REQUIRE_THROWS_WITH( applyMultiVarPhaseFunc(quregVec, qubits, numQubitsPerReg, numRegs, UNSIGNED, NULL, NULL, NULL), Contains("Invalid qubit index") );
738  }
739  SECTION( "number of terms" ) {
740 
741  int numTermsPerReg[] = {3, 3};
742 
743  numTermsPerReg[GENERATE_COPY(range(0,numRegs))] = GENERATE( -1, 0 );
744  REQUIRE_THROWS_WITH( applyMultiVarPhaseFunc(quregVec, qubits, numQubitsPerReg, numRegs, UNSIGNED, NULL, NULL, numTermsPerReg), Contains("Invalid number of terms in the phase function") );
745  }
746  SECTION( "bit encoding name" ) {
747 
748  enum bitEncoding enc = (enum bitEncoding) GENERATE( -1, 2 );
749  REQUIRE_THROWS_WITH( applyMultiVarPhaseFunc(quregVec, qubits, numQubitsPerReg, numRegs, enc, NULL, NULL, NULL), Contains("Invalid bit encoding") );
750  }
751  SECTION( "two's complement register" ) {
752 
753  numQubitsPerReg[GENERATE_COPY(range(0,numRegs))] = 1;
754  REQUIRE_THROWS_WITH( applyMultiVarPhaseFunc(quregVec, qubits, numQubitsPerReg, numRegs, TWOS_COMPLEMENT, NULL, NULL, NULL), Contains("A sub-register contained too few qubits to employ TWOS_COMPLEMENT encoding") );
755  }
756  SECTION( "fractional exponent" ) {
757 
758  int numTermsPerReg[] = {3, 3};
759  qreal coeffs[] = {0,0,0, 0,0,0};
760  qreal expos[] = {1,2,3, 1,2,3};
761 
762  expos[GENERATE(range(0,6))] = GENERATE( 0.5, 1.999, 5.0001 );
763  REQUIRE_THROWS_WITH( applyMultiVarPhaseFunc(quregVec, qubits, numQubitsPerReg, numRegs, TWOS_COMPLEMENT, coeffs, expos, numTermsPerReg), Contains("The phase function contained a fractional exponent, which is illegal in TWOS_COMPLEMENT") );
764 
765  // ensure fractional exponents are valid in unsigned mode however
766  REQUIRE_NOTHROW( applyMultiVarPhaseFunc(quregVec, qubits, numQubitsPerReg, numRegs, UNSIGNED, coeffs, expos, numTermsPerReg) );
767 
768  }
769  SECTION( "negative exponent" ) {
770 
771  int numTermsPerReg[] = {3, 3};
772  qreal coeffs[] = {0,0,0, 0,0,0};
773  qreal expos[] = {1,2,3, 1,2,3};
774 
775  expos[GENERATE(range(0,6))] = GENERATE( -1, -2, -2.5 );
776  enum bitEncoding enc = GENERATE( UNSIGNED, TWOS_COMPLEMENT );
777 
778  REQUIRE_THROWS_WITH( applyMultiVarPhaseFunc(quregVec, qubits, numQubitsPerReg, numRegs, enc, coeffs, expos, numTermsPerReg), Contains("The phase function contained an illegal negative exponent") );
779  }
780  }
781  CLEANUP_TEST( quregVec, quregMatr );
782 }

References applyMultiVarPhaseFunc(), applyReferenceOp(), areEqual(), CLEANUP_TEST, expI(), getKroneckerProduct(), getRandomInt(), getRandomReal(), getTwosComplement(), getZeroMatrix(), MAX_NUM_REGS_APPLY_ARBITRARY_PHASE, NUM_QUBITS, PREPARE_TEST, qreal, sublists(), TWOS_COMPLEMENT, and UNSIGNED.

◆ TEST_CASE() [8/124]

TEST_CASE ( "applyMultiVarPhaseFuncOverrides"  ,
""  [operators] 
)
See also
applyMultiVarPhaseFuncOverrides
Author
Tyson Jones

Definition at line 790 of file test_operators.cpp.

790  {
791 
792  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
793 
794  SECTION( "correctness" ) {
795 
796  // try every kind of binary encodings
797  enum bitEncoding encoding = GENERATE( UNSIGNED,TWOS_COMPLEMENT );
798 
799  // try every possible number of registers
800  // (between #qubits containing 1, and 1 containing #qubits)
801  int numRegs;
802  int maxNumRegs = 0;
803  if (encoding == UNSIGNED)
804  maxNumRegs = NUM_QUBITS;
805  if (encoding == TWOS_COMPLEMENT)
806  maxNumRegs = NUM_QUBITS/2; // floors
807  numRegs = GENERATE_COPY( range(1, maxNumRegs+1) );
808 
809  // try every possible total number of involed qubits
810  int totalNumQubits;
811  int minTotalQubits = 0;
812  if (encoding == UNSIGNED)
813  // each register must contain at least 1 qubit
814  minTotalQubits = numRegs;
815  if (encoding == TWOS_COMPLEMENT)
816  // each register must contain at least 2 qubits
817  minTotalQubits = 2*numRegs;
818  totalNumQubits = GENERATE_COPY( range(minTotalQubits,NUM_QUBITS+1) );
819 
820  // try every qubits subset and ordering
821  int* regs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), totalNumQubits) );
822 
823  // assign each sub-reg its minimum length
824  int unallocQubits = totalNumQubits;
825  int numQubitsPerReg[numRegs];
826  for (int i=0; i<numRegs; i++)
827  if (encoding == UNSIGNED) {
828  numQubitsPerReg[i] = 1;
829  unallocQubits -= 1;
830  }
831  else if (encoding == TWOS_COMPLEMENT) {
832  numQubitsPerReg[i] = 2;
833  unallocQubits -= 2;
834  }
835  // and randomly allocate the remaining qubits between the registers
836  while (unallocQubits > 0) {
837  numQubitsPerReg[getRandomInt(0,numRegs)] += 1;
838  unallocQubits--;
839  }
840 
841 
842  // each register gets a random number of terms in the full phase function
843  int numTermsPerReg[numRegs];
844  int numTermsTotal = 0;
845  for (int r=0; r<numRegs; r++) {
846  int numTerms = getRandomInt(1,5);
847  numTermsPerReg[r] = numTerms;
848  numTermsTotal += numTerms;
849  }
850 
851  // populate the multi-var phase function with random but POSITIVE-power terms,
852  // which must further be integers in two's complement
853  int flatInd = 0;
854  qreal coeffs[numTermsTotal];
855  qreal expons[numTermsTotal];
856  for (int r=0; r<numRegs; r++) {
857  for (int t=0; t<numTermsPerReg[r]; t++) {
858  coeffs[flatInd] = getRandomReal(-10,10);
859  if (encoding == TWOS_COMPLEMENT)
860  expons[flatInd] = getRandomInt(0, 3+1);
861  else if (encoding == UNSIGNED)
862  expons[flatInd] = getRandomReal(0, 3);
863 
864  flatInd++;
865  }
866  }
867 
868 
869  // choose a random number of overrides (even overriding every amplitude)
870  int numOverrides = getRandomInt(0, (1<<totalNumQubits) + 1);
871 
872  // randomise each override index (uniqueness isn't checked)
873  long long int overrideInds[numOverrides*numRegs];
874  flatInd = 0;
875  for (int v=0; v<numOverrides; v++) {
876  for (int r=0; r<numRegs; r++) {
877  if (encoding == UNSIGNED)
878  overrideInds[flatInd] = getRandomInt(0, 1<<numQubitsPerReg[r]);
879  else if (encoding == TWOS_COMPLEMENT)
880  overrideInds[flatInd] = getRandomInt(-(1<<(numQubitsPerReg[r]-1)), (1<<(numQubitsPerReg[r]-1))-1);
881  flatInd++;
882  }
883  }
884 
885  // override to a random phase
886  qreal overridePhases[numOverrides];
887  for (int v=0; v<numOverrides; v++)
888  overridePhases[v] = getRandomReal(-4, 4); // periodic in [-pi, pi]
889 
890  /* To perform this calculation more distinctly from the QuEST
891  * core method, we can exploit that
892  * exp(i (f1[x1] + f2[x2]))|x2>|x1> = exp(i f2[x2])|x2> (x) exp(i f1[x1])|x1>
893  * and so compute a separate diagonal matrix for each sub-register with
894  * phases determined only by its own variable, and Kronecker multiply
895  * them together. The target qubits of the Kronecker product is then
896  * just the full register, stored in *regs. We do this, then iterate
897  * the list of overrides directly to overwrite the ultimate diagonal
898  * entries
899  */
900  QMatrix allRegMatr{{1}};
901  int startInd = 0;
902  for (int r=0; r<numRegs; r++) {
903 
904  QMatrix singleRegMatr = getZeroMatrix( 1 << numQubitsPerReg[r] );
905 
906  for (size_t i=0; i<singleRegMatr.size(); i++) {
907 
908  long long int ind = 0;
909  if (encoding == UNSIGNED)
910  ind = i;
911  if (encoding == TWOS_COMPLEMENT)
912  ind = getTwosComplement(i, numQubitsPerReg[r]);
913 
914  qreal phase = 0;
915  for (int t=0; t<numTermsPerReg[r]; t++)
916  phase += coeffs[t+startInd] * pow(ind, expons[t+startInd]);
917 
918  singleRegMatr[i][i] = expI(phase);
919  }
920  allRegMatr = getKroneckerProduct(singleRegMatr, allRegMatr);
921  startInd += numTermsPerReg[r];
922  }
923  setDiagMatrixOverrides(allRegMatr, numQubitsPerReg, numRegs, encoding, overrideInds, overridePhases, numOverrides);
924 
925  SECTION( "state-vector" ) {
926 
927  applyMultiVarPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, encoding, coeffs, expons, numTermsPerReg, overrideInds, overridePhases, numOverrides);
928  applyReferenceOp(refVec, regs, totalNumQubits, allRegMatr);
929  REQUIRE( areEqual(quregVec, refVec, 1E4*REAL_EPS) );
930  }
931  SECTION( "density-matrix" ) {
932 
933  applyMultiVarPhaseFuncOverrides(quregMatr, regs, numQubitsPerReg, numRegs, encoding, coeffs, expons, numTermsPerReg, overrideInds, overridePhases, numOverrides);
934  applyReferenceOp(refMatr, regs, totalNumQubits, allRegMatr);
935  REQUIRE( areEqual(quregMatr, refMatr, 1E6*REAL_EPS) );
936  }
937  }
938  SECTION( "input validation" ) {
939 
940  int numRegs = 2;
941  int numQubitsPerReg[] = {2,3};
942  int qubits[] = {0,1,2,3,4};
943 
944  SECTION( "number of registers" ) {
945 
946  numRegs = GENERATE_COPY( -1, 0, 1+MAX_NUM_REGS_APPLY_ARBITRARY_PHASE );
947  REQUIRE_THROWS_WITH( applyMultiVarPhaseFuncOverrides(quregVec, qubits, numQubitsPerReg, numRegs, UNSIGNED, NULL, NULL, NULL, NULL, NULL, 0), Contains("Invalid number of qubit subregisters") );
948  }
949  SECTION( "number of qubits" ) {
950 
951  numQubitsPerReg[GENERATE_COPY(range(0,numRegs))] = GENERATE( -1, 0, 1+NUM_QUBITS );
952  REQUIRE_THROWS_WITH( applyMultiVarPhaseFuncOverrides(quregVec, qubits, numQubitsPerReg, numRegs, UNSIGNED, NULL, NULL, NULL, NULL, NULL, 0), Contains("Invalid number of qubits") );
953  }
954  SECTION( "repetition of qubits" ) {
955 
956  qubits[GENERATE(2,3,4)] = qubits[1];
957  REQUIRE_THROWS_WITH( applyMultiVarPhaseFuncOverrides(quregVec, qubits, numQubitsPerReg, numRegs, UNSIGNED, NULL, NULL, NULL, NULL, NULL, 0), Contains("The qubits must be unique") );
958  }
959  SECTION( "qubit indices" ) {
960 
961  qubits[GENERATE(range(0,NUM_QUBITS))] = GENERATE( -1, NUM_QUBITS );
962  REQUIRE_THROWS_WITH( applyMultiVarPhaseFuncOverrides(quregVec, qubits, numQubitsPerReg, numRegs, UNSIGNED, NULL, NULL, NULL, NULL, NULL, 0), Contains("Invalid qubit index") );
963  }
964  SECTION( "number of terms" ) {
965 
966  int numTermsPerReg[] = {3, 3};
967 
968  numTermsPerReg[GENERATE_COPY(range(0,numRegs))] = GENERATE( -1, 0 );
969  REQUIRE_THROWS_WITH( applyMultiVarPhaseFuncOverrides(quregVec, qubits, numQubitsPerReg, numRegs, UNSIGNED, NULL, NULL, numTermsPerReg, NULL, NULL, 0), Contains("Invalid number of terms in the phase function") );
970  }
971  SECTION( "bit encoding name" ) {
972 
973  enum bitEncoding enc = (enum bitEncoding) GENERATE( -1, 2 );
974  REQUIRE_THROWS_WITH( applyMultiVarPhaseFuncOverrides(quregVec, qubits, numQubitsPerReg, numRegs, enc, NULL, NULL, NULL, NULL, NULL, 0), Contains("Invalid bit encoding") );
975  }
976  SECTION( "two's complement register" ) {
977 
978  numQubitsPerReg[GENERATE_COPY(range(0,numRegs))] = 1;
979  REQUIRE_THROWS_WITH( applyMultiVarPhaseFuncOverrides(quregVec, qubits, numQubitsPerReg, numRegs, TWOS_COMPLEMENT, NULL, NULL, NULL, NULL, NULL, 0), Contains("A sub-register contained too few qubits to employ TWOS_COMPLEMENT encoding") );
980  }
981  SECTION( "fractional exponent" ) {
982 
983  int numTermsPerReg[] = {3, 3};
984  qreal coeffs[] = {0,0,0, 0,0,0};
985  qreal expos[] = {1,2,3, 1,2,3};
986 
987  expos[GENERATE(range(0,6))] = GENERATE( 0.5, 1.999, 5.0001 );
988  REQUIRE_THROWS_WITH( applyMultiVarPhaseFuncOverrides(quregVec, qubits, numQubitsPerReg, numRegs, TWOS_COMPLEMENT, coeffs, expos, numTermsPerReg, NULL, NULL, 0), Contains("The phase function contained a fractional exponent, which is illegal in TWOS_COMPLEMENT") );
989 
990  // ensure fractional exponents are valid in unsigned mode however
991  REQUIRE_NOTHROW( applyMultiVarPhaseFuncOverrides(quregVec, qubits, numQubitsPerReg, numRegs, UNSIGNED, coeffs, expos, numTermsPerReg, NULL, NULL, 0) );
992  }
993  SECTION( "negative exponent" ) {
994 
995  int numTermsPerReg[] = {3, 3};
996  qreal coeffs[] = {0,0,0, 0,0,0};
997  qreal expos[] = {1,2,3, 1,2,3};
998 
999  expos[GENERATE(range(0,6))] = GENERATE( -1, -2, -2.5 );
1000  enum bitEncoding enc = GENERATE( UNSIGNED, TWOS_COMPLEMENT );
1001 
1002  REQUIRE_THROWS_WITH( applyMultiVarPhaseFuncOverrides(quregVec, qubits, numQubitsPerReg, numRegs, enc, coeffs, expos, numTermsPerReg, NULL, NULL, 0), Contains("The phase function contained an illegal negative exponent") );
1003  }
1004  SECTION( "number of overrides" ) {
1005 
1006  int numTermsPerReg[] = {3, 3};
1007  qreal coeffs[] = {0,0,0, 0,0,0};
1008  qreal expos[] = {1,2,3, 1,2,3};
1009 
1010  int numOverrides = -1;
1011  REQUIRE_THROWS_WITH( applyMultiVarPhaseFuncOverrides(quregVec, qubits, numQubitsPerReg, numRegs, UNSIGNED, coeffs, expos, numTermsPerReg, NULL, NULL, numOverrides), Contains("Invalid number of phase function overrides specified") );
1012  }
1013  SECTION( "override indices" ) {
1014 
1015  int numTermsPerReg[] = {3, 3};
1016  qreal coeffs[] = {0,0,0, 0,0,0};
1017  qreal expos[] = {1,2,3, 1,2,3};
1018 
1019  // numQubitsPerReg = {2, 3}
1020  int numOverrides = 3;
1021  long long int overrideInds[] = {0,0, 0,0, 0,0}; // repetition not checked
1022  qreal overridePhases[] = {.1, .1, .1};
1023 
1024  // first element of overrideInds coordinate is a 2 qubit register
1025  enum bitEncoding enc = UNSIGNED;
1026  int badInd = GENERATE(0, 2, 4);
1027  overrideInds[badInd] = GENERATE( -1, (1<<2) );
1028  REQUIRE_THROWS_WITH( applyMultiVarPhaseFuncOverrides(quregVec, qubits, numQubitsPerReg, numRegs, enc, coeffs, expos, numTermsPerReg, overrideInds, overridePhases, numOverrides), Contains("Invalid phase function override index, in the UNSIGNED encoding") );
1029  overrideInds[badInd] = 0;
1030 
1031  // second element of overrideInds coordinate is a 3 qubit register
1032  badInd += 1;
1033  overrideInds[badInd] = GENERATE( -1, (1<<3) );
1034  REQUIRE_THROWS_WITH( applyMultiVarPhaseFuncOverrides(quregVec, qubits, numQubitsPerReg, numRegs, enc, coeffs, expos, numTermsPerReg, overrideInds, overridePhases, numOverrides), Contains("Invalid phase function override index, in the UNSIGNED encoding") );
1035  overrideInds[badInd] = 0;
1036  badInd -= 1;
1037 
1038  enc = TWOS_COMPLEMENT;
1039  int minInd = -(1<<(numQubitsPerReg[0]-1));
1040  int maxInd = (1<<(numQubitsPerReg[0]-1)) - 1;
1041  overrideInds[badInd] = GENERATE_COPY( minInd-1, maxInd+1 );
1042  REQUIRE_THROWS_WITH( applyMultiVarPhaseFuncOverrides(quregVec, qubits, numQubitsPerReg, numRegs, enc, coeffs, expos, numTermsPerReg, overrideInds, overridePhases, numOverrides), Contains("Invalid phase function override index, in the TWOS_COMPLEMENT encoding") );
1043  overrideInds[badInd] = 0;
1044 
1045  badInd++;
1046  minInd = -(1<<(numQubitsPerReg[1]-1));
1047  maxInd = (1<<(numQubitsPerReg[1]-1)) -1;
1048  overrideInds[badInd] = GENERATE_COPY( minInd-1, maxInd+1 );
1049  REQUIRE_THROWS_WITH( applyMultiVarPhaseFuncOverrides(quregVec, qubits, numQubitsPerReg, numRegs, enc, coeffs, expos, numTermsPerReg, overrideInds, overridePhases, numOverrides), Contains("Invalid phase function override index, in the TWOS_COMPLEMENT encoding") );
1050  }
1051  }
1052  CLEANUP_TEST( quregVec, quregMatr );
1053 }

References applyMultiVarPhaseFuncOverrides(), applyReferenceOp(), areEqual(), CLEANUP_TEST, expI(), getKroneckerProduct(), getRandomInt(), getRandomReal(), getTwosComplement(), getZeroMatrix(), MAX_NUM_REGS_APPLY_ARBITRARY_PHASE, NUM_QUBITS, PREPARE_TEST, qreal, setDiagMatrixOverrides(), sublists(), TWOS_COMPLEMENT, and UNSIGNED.

◆ TEST_CASE() [9/124]

TEST_CASE ( "applyNamedPhaseFunc"  ,
""  [operators] 
)
See also
applyNamedPhaseFunc
Author
Tyson Jones

Definition at line 1061 of file test_operators.cpp.

1061  {
1062 
1063  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1064 
1065  SECTION( "correctness" ) {
1066 
1067  // try every kind of binary encoding
1068  enum bitEncoding encoding = GENERATE( UNSIGNED,TWOS_COMPLEMENT );
1069 
1070  // try every possible number of registers
1071  // (between #qubits containing 1, and 1 containing #qubits)
1072  int numRegs;
1073  int maxNumRegs = 0;
1074  if (encoding == UNSIGNED)
1075  maxNumRegs = NUM_QUBITS;
1076  if (encoding == TWOS_COMPLEMENT)
1077  maxNumRegs = NUM_QUBITS/2; // floors
1078  numRegs = GENERATE_COPY( range(1, maxNumRegs+1) );
1079 
1080  // try every possible total number of involved qubits
1081  int totalNumQubits;
1082  int minTotalQubits = 0;
1083  if (encoding == UNSIGNED)
1084  // each register must contain at least 1 qubit
1085  minTotalQubits = numRegs;
1086  if (encoding == TWOS_COMPLEMENT)
1087  // each register must contain at least 2 qubits
1088  minTotalQubits = 2*numRegs;
1089  totalNumQubits = GENERATE_COPY( range(minTotalQubits,NUM_QUBITS+1) );
1090 
1091  // try every qubits subset and ordering
1092  int* regs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), totalNumQubits) );
1093 
1094  // assign each sub-reg its minimum length
1095  int unallocQubits = totalNumQubits;
1096  int numQubitsPerReg[numRegs];
1097  for (int i=0; i<numRegs; i++)
1098  if (encoding == UNSIGNED) {
1099  numQubitsPerReg[i] = 1;
1100  unallocQubits -= 1;
1101  }
1102  else if (encoding == TWOS_COMPLEMENT) {
1103  numQubitsPerReg[i] = 2;
1104  unallocQubits -= 2;
1105  }
1106  // and randomly allocate the remaining qubits between the registers
1107  while (unallocQubits > 0) {
1108  numQubitsPerReg[getRandomInt(0,numRegs)] += 1;
1109  unallocQubits--;
1110  }
1111 
1112  // for reference, determine the values corresponding to each register for all basis states
1113  qreal regVals[1<<totalNumQubits][numRegs];
1114  for (long long int i=0; i<(1<<totalNumQubits); i++) {
1115 
1116  long long int bits = i;
1117  for (int r=0; r<numRegs; r++) {
1118  regVals[i][r] = bits % (1 << numQubitsPerReg[r]);
1119  bits = bits >> numQubitsPerReg[r];
1120 
1121  if (encoding == TWOS_COMPLEMENT)
1122  regVals[i][r] = getTwosComplement(regVals[i][r], numQubitsPerReg[r]);
1123  }
1124  }
1125 
1126  /* the reference diagonal matrix which assumes the qubits are
1127  * contiguous and strictly increasing between the registers, and hence
1128  * only depends on the number of qubits in each register.
1129  */
1130  QMatrix diagMatr = getZeroMatrix(1 << totalNumQubits);
1131 
1132  SECTION( "NORM" ) {
1133 
1134  for (size_t i=0; i<diagMatr.size(); i++) {
1135  qreal phase = 0;
1136  for (int r=0; r<numRegs; r++)
1137  phase += pow(regVals[i][r], 2);
1138  phase = sqrt(phase);
1139  diagMatr[i][i] = expI(phase);
1140  }
1141 
1142  SECTION( "state-vector" ) {
1143 
1144  applyNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, encoding, NORM);
1145  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
1146  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
1147  }
1148  SECTION( "density-matrix" ) {
1149 
1150  applyNamedPhaseFunc(quregMatr, regs, numQubitsPerReg, numRegs, encoding, NORM);
1151  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
1152  REQUIRE( areEqual(quregMatr, refMatr, 142*REAL_EPS) );
1153  }
1154  }
1155  SECTION( "PRODUCT" ) {
1156 
1157  for (size_t i=0; i<diagMatr.size(); i++) {
1158  qreal phase = 1;
1159  for (int r=0; r<numRegs; r++)
1160  phase *= regVals[i][r];
1161  diagMatr[i][i] = expI(phase);
1162  }
1163 
1164  SECTION( "state-vector" ) {
1165 
1166  applyNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, encoding, PRODUCT);
1167  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
1168  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
1169  }
1170  SECTION( "density-matrix" ) {
1171 
1172  applyNamedPhaseFunc(quregMatr, regs, numQubitsPerReg, numRegs, encoding, PRODUCT);
1173  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
1174  REQUIRE( areEqual(quregMatr, refMatr, 142*REAL_EPS) );
1175  }
1176  }
1177  SECTION( "DISTANCE" ) {
1178 
1179  // test only if there are an even number of registers
1180  if (numRegs%2 == 0) {
1181 
1182  for (size_t i=0; i<diagMatr.size(); i++) {
1183  qreal phase = 0;
1184  for (int r=0; r<numRegs; r+=2)
1185  phase += pow(regVals[i][r+1]-regVals[i][r], 2);
1186  phase = sqrt(phase);
1187  diagMatr[i][i] = expI(phase);
1188  }
1189  }
1190 
1191  SECTION( "state-vector" ) {
1192 
1193  if (numRegs%2 == 0) {
1194  applyNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, encoding, DISTANCE);
1195  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
1196  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
1197  }
1198  }
1199  SECTION( "density-matrix" ) {
1200 
1201  if (numRegs%2 == 0) {
1202  applyNamedPhaseFunc(quregMatr, regs, numQubitsPerReg, numRegs, encoding, DISTANCE);
1203  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
1204  REQUIRE( areEqual(quregMatr, refMatr, 142*REAL_EPS) );
1205  }
1206  }
1207  }
1208  }
1209  SECTION( "input validation" ) {
1210 
1211  int numRegs = 2;
1212  int numQubitsPerReg[] = {2,3};
1213  int regs[] = {0,1,2,3,4};
1214 
1215  SECTION( "number of registers" ) {
1216 
1217  numRegs = GENERATE_COPY( -1, 0, 1+MAX_NUM_REGS_APPLY_ARBITRARY_PHASE );
1218  REQUIRE_THROWS_WITH( applyNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, NORM), Contains("Invalid number of qubit subregisters") );
1219  }
1220  SECTION( "number of qubits" ) {
1221 
1222  numQubitsPerReg[GENERATE_COPY(range(0,numRegs))] = GENERATE( -1, 0, 1+NUM_QUBITS );
1223  REQUIRE_THROWS_WITH( applyNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, NORM), Contains("Invalid number of qubits") );
1224  }
1225  SECTION( "repetition of qubits" ) {
1226 
1227  regs[GENERATE(2,3,4)] = regs[1];
1228  REQUIRE_THROWS_WITH( applyNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, NORM), Contains("The qubits must be unique") );
1229  }
1230  SECTION( "qubit indices" ) {
1231 
1232  regs[GENERATE(range(0,NUM_QUBITS))] = GENERATE( -1, NUM_QUBITS );
1233  REQUIRE_THROWS_WITH( applyNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, NORM), Contains("Invalid qubit index") );
1234  }
1235  SECTION( "bit encoding name" ) {
1236 
1237  enum bitEncoding enc = (enum bitEncoding) GENERATE( -1, 2 );
1238  REQUIRE_THROWS_WITH( applyNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, enc, NORM), Contains("Invalid bit encoding") );
1239  }
1240  SECTION( "two's complement register" ) {
1241 
1242  numQubitsPerReg[GENERATE_COPY(range(0,numRegs))] = 1;
1243  REQUIRE_THROWS_WITH( applyNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, TWOS_COMPLEMENT, NORM), Contains("A sub-register contained too few qubits to employ TWOS_COMPLEMENT encoding") );
1244  }
1245  SECTION( "phase function name" ) {
1246 
1247  enum phaseFunc func = (enum phaseFunc) GENERATE( -1, 14 );
1248  REQUIRE_THROWS_WITH( applyNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, func), Contains("Invalid named phase function") );
1249  }
1250  SECTION( "phase function parameters" ) {
1251 
1253  REQUIRE_THROWS_WITH( applyNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, func), Contains("Invalid number of parameters") );
1254  }
1255  SECTION( "distance pair registers" ) {
1256 
1257  int numQb[] = {1,1,1,1,1};
1258  int qb[] = {0,1,2,3,4};
1259 
1260  numRegs = GENERATE( 1, 3, 5 );
1261  REQUIRE_THROWS_WITH( applyNamedPhaseFunc(quregVec, qb, numQb, numRegs, UNSIGNED, DISTANCE), Contains("Phase functions DISTANCE") && Contains("even number of sub-registers") );
1262  }
1263  }
1264  CLEANUP_TEST( quregVec, quregMatr );
1265 }

References applyNamedPhaseFunc(), applyReferenceOp(), areEqual(), CLEANUP_TEST, DISTANCE, expI(), getRandomInt(), getTwosComplement(), getZeroMatrix(), INVERSE_DISTANCE, INVERSE_NORM, INVERSE_PRODUCT, MAX_NUM_REGS_APPLY_ARBITRARY_PHASE, NORM, NUM_QUBITS, PREPARE_TEST, PRODUCT, qreal, SCALED_DISTANCE, SCALED_INVERSE_DISTANCE, SCALED_INVERSE_NORM, SCALED_INVERSE_PRODUCT, SCALED_INVERSE_SHIFTED_DISTANCE, SCALED_INVERSE_SHIFTED_NORM, SCALED_NORM, SCALED_PRODUCT, sublists(), TWOS_COMPLEMENT, and UNSIGNED.

◆ TEST_CASE() [10/124]

TEST_CASE ( "applyNamedPhaseFuncOverrides"  ,
""  [operators] 
)
See also
applyNamedPhaseFuncOverrides
Author
Tyson Jones

Definition at line 1273 of file test_operators.cpp.

1273  {
1274 
1275  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1276 
1277  SECTION( "correctness" ) {
1278 
1279  // try every kind of binary encoding
1280  enum bitEncoding encoding = GENERATE( UNSIGNED,TWOS_COMPLEMENT );
1281 
1282  // try every possible number of registers
1283  // (between #qubits containing 1, and 1 containing #qubits)
1284  int numRegs;
1285  int maxNumRegs = 0;
1286  if (encoding == UNSIGNED)
1287  maxNumRegs = NUM_QUBITS;
1288  if (encoding == TWOS_COMPLEMENT)
1289  maxNumRegs = NUM_QUBITS/2; // floors
1290  numRegs = GENERATE_COPY( range(1, maxNumRegs+1) );
1291 
1292  // try every possible total number of involved qubits
1293  int totalNumQubits;
1294  int minTotalQubits = 0;
1295  if (encoding == UNSIGNED)
1296  // each register must contain at least 1 qubit
1297  minTotalQubits = numRegs;
1298  if (encoding == TWOS_COMPLEMENT)
1299  // each register must contain at least 2 qubits
1300  minTotalQubits = 2*numRegs;
1301  totalNumQubits = GENERATE_COPY( range(minTotalQubits,NUM_QUBITS+1) );
1302 
1303  // try every qubits subset and ordering
1304  int* regs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), totalNumQubits) );
1305 
1306  // assign each sub-reg its minimum length
1307  int unallocQubits = totalNumQubits;
1308  int numQubitsPerReg[numRegs];
1309  for (int i=0; i<numRegs; i++)
1310  if (encoding == UNSIGNED) {
1311  numQubitsPerReg[i] = 1;
1312  unallocQubits -= 1;
1313  }
1314  else if (encoding == TWOS_COMPLEMENT) {
1315  numQubitsPerReg[i] = 2;
1316  unallocQubits -= 2;
1317  }
1318  // and randomly allocate the remaining qubits between the registers
1319  while (unallocQubits > 0) {
1320  numQubitsPerReg[getRandomInt(0,numRegs)] += 1;
1321  unallocQubits--;
1322  }
1323 
1324 
1325  // choose a random number of overrides (even overriding every amplitude)
1326  int numOverrides = getRandomInt(0, (1<<totalNumQubits) + 1);
1327 
1328  // randomise each override index (uniqueness isn't checked)
1329  long long int overrideInds[numOverrides*numRegs];
1330  int flatInd = 0;
1331  for (int v=0; v<numOverrides; v++) {
1332  for (int r=0; r<numRegs; r++) {
1333  if (encoding == UNSIGNED)
1334  overrideInds[flatInd] = getRandomInt(0, 1<<numQubitsPerReg[r]);
1335  else if (encoding == TWOS_COMPLEMENT)
1336  overrideInds[flatInd] = getRandomInt(-(1<<(numQubitsPerReg[r]-1)), (1<<(numQubitsPerReg[r]-1))-1);
1337  flatInd++;
1338  }
1339  }
1340 
1341  // override to a random phase
1342  qreal overridePhases[numOverrides];
1343  for (int v=0; v<numOverrides; v++)
1344  overridePhases[v] = getRandomReal(-4, 4); // periodic in [-pi, pi]
1345 
1346 
1347  // determine the values corresponding to each register for all basis states
1348  qreal regVals[1<<totalNumQubits][numRegs];
1349  for (long long int i=0; i<(1<<totalNumQubits); i++) {
1350 
1351  long long int bits = i;
1352  for (int r=0; r<numRegs; r++) {
1353  regVals[i][r] = bits % (1 << numQubitsPerReg[r]);
1354  bits = bits >> numQubitsPerReg[r];
1355 
1356  if (encoding == TWOS_COMPLEMENT)
1357  regVals[i][r] = getTwosComplement(regVals[i][r], numQubitsPerReg[r]);
1358  }
1359  }
1360 
1361  /* a reference diagonal matrix which assumes the qubits are
1362  * contiguous and strictly increasing between the registers, and hence
1363  * only depends on the number of qubits in each register.
1364  */
1365  QMatrix diagMatr = getZeroMatrix(1 << totalNumQubits);
1366 
1367  SECTION( "NORM" ) {
1368 
1369  for (size_t i=0; i<diagMatr.size(); i++) {
1370  qreal phase = 0;
1371  for (int r=0; r<numRegs; r++)
1372  phase += pow(regVals[i][r], 2);
1373  phase = sqrt(phase);
1374  diagMatr[i][i] = expI(phase);
1375  }
1376  setDiagMatrixOverrides(diagMatr, numQubitsPerReg, numRegs, encoding, overrideInds, overridePhases, numOverrides);
1377 
1378  SECTION( "state-vector" ) {
1379 
1380  applyNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, encoding, NORM, overrideInds, overridePhases, numOverrides);
1381  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
1382  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
1383  }
1384  SECTION( "density-matrix" ) {
1385 
1386  applyNamedPhaseFuncOverrides(quregMatr, regs, numQubitsPerReg, numRegs, encoding, NORM, overrideInds, overridePhases, numOverrides);
1387  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
1388  REQUIRE( areEqual(quregMatr, refMatr, 1E4*REAL_EPS) );
1389  }
1390  }
1391  SECTION( "PRODUCT" ) {
1392 
1393  for (size_t i=0; i<diagMatr.size(); i++) {
1394  qreal phase = 1;
1395  for (int r=0; r<numRegs; r++)
1396  phase *= regVals[i][r];
1397  diagMatr[i][i] = expI(phase);
1398  }
1399 
1400  setDiagMatrixOverrides(diagMatr, numQubitsPerReg, numRegs, encoding, overrideInds, overridePhases, numOverrides);
1401 
1402  SECTION( "state-vector" ) {
1403 
1404  applyNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, encoding, PRODUCT, overrideInds, overridePhases, numOverrides);
1405  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
1406  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
1407  }
1408  SECTION( "density-matrix" ) {
1409 
1410  applyNamedPhaseFuncOverrides(quregMatr, regs, numQubitsPerReg, numRegs, encoding, PRODUCT, overrideInds, overridePhases, numOverrides);
1411  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
1412  REQUIRE( areEqual(quregMatr, refMatr, 1E4*REAL_EPS) );
1413  }
1414  }
1415  SECTION( "DISTANCE" ) {
1416 
1417  // test only if there are an even number of registers
1418  if (numRegs%2 == 0) {
1419 
1420  for (size_t i=0; i<diagMatr.size(); i++) {
1421  qreal phase = 0;
1422  for (int r=0; r<numRegs; r+=2)
1423  phase += pow(regVals[i][r+1]-regVals[i][r], 2);
1424  phase = sqrt(phase);
1425  diagMatr[i][i] = expI(phase);
1426  }
1427 
1428  setDiagMatrixOverrides(diagMatr, numQubitsPerReg, numRegs, encoding, overrideInds, overridePhases, numOverrides);
1429  }
1430 
1431  SECTION( "state-vector" ) {
1432 
1433  if (numRegs%2 == 0) {
1434  applyNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, encoding, DISTANCE, overrideInds, overridePhases, numOverrides);
1435  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
1436  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
1437  }
1438  }
1439  SECTION( "density-matrix" ) {
1440 
1441  if (numRegs%2 == 0) {
1442  applyNamedPhaseFuncOverrides(quregMatr, regs, numQubitsPerReg, numRegs, encoding, DISTANCE, overrideInds, overridePhases, numOverrides);
1443  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
1444  REQUIRE( areEqual(quregMatr, refMatr, 1E4*REAL_EPS) );
1445  }
1446  }
1447  }
1448  }
1449  SECTION( "input validation" ) {
1450 
1451  int numRegs = 2;
1452  int numQubitsPerReg[] = {2,3};
1453  int regs[] = {0,1,2,3,4};
1454 
1455  SECTION( "number of registers" ) {
1456 
1457  numRegs = GENERATE_COPY( -1, 0, 1+MAX_NUM_REGS_APPLY_ARBITRARY_PHASE );
1458  REQUIRE_THROWS_WITH( applyNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, NORM, NULL, NULL, 0), Contains("Invalid number of qubit subregisters") );
1459  }
1460  SECTION( "number of qubits" ) {
1461 
1462  numQubitsPerReg[GENERATE_COPY(range(0,numRegs))] = GENERATE( -1, 0, 1+NUM_QUBITS );
1463  REQUIRE_THROWS_WITH( applyNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, NORM, NULL, NULL, 0), Contains("Invalid number of qubits") );
1464  }
1465  SECTION( "repetition of qubits" ) {
1466 
1467  regs[GENERATE(2,3,4)] = regs[1];
1468  REQUIRE_THROWS_WITH( applyNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, NORM, NULL, NULL, 0), Contains("The qubits must be unique") );
1469  }
1470  SECTION( "qubit indices" ) {
1471 
1472  regs[GENERATE(range(0,NUM_QUBITS))] = GENERATE( -1, NUM_QUBITS );
1473  REQUIRE_THROWS_WITH( applyNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, NORM, NULL, NULL, 0), Contains("Invalid qubit index") );
1474  }
1475  SECTION( "bit encoding name" ) {
1476 
1477  enum bitEncoding enc = (enum bitEncoding) GENERATE( -1, 2 );
1478  REQUIRE_THROWS_WITH( applyNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, enc, NORM, NULL, NULL, 0), Contains("Invalid bit encoding") );
1479  }
1480  SECTION( "two's complement register" ) {
1481 
1482  numQubitsPerReg[GENERATE_COPY(range(0,numRegs))] = 1;
1483  REQUIRE_THROWS_WITH( applyNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, TWOS_COMPLEMENT, NORM, NULL, NULL, 0), Contains("A sub-register contained too few qubits to employ TWOS_COMPLEMENT encoding") );
1484  }
1485  SECTION( "phase function name" ) {
1486 
1487  enum phaseFunc func = (enum phaseFunc) GENERATE( -1, 14 );
1488  REQUIRE_THROWS_WITH( applyNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, func, NULL, NULL, 0), Contains("Invalid named phase function") );
1489  }
1490  SECTION( "phase function parameters" ) {
1491 
1493  REQUIRE_THROWS_WITH( applyNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, func, NULL, NULL, 0), Contains("Invalid number of parameters") );
1494  }
1495  SECTION( "distance pair registers" ) {
1496 
1497  int numQb[] = {1,1,1,1,1};
1498  int qb[] = {0,1,2,3,4};
1499 
1500  numRegs = GENERATE( 1, 3, 5 );
1501  REQUIRE_THROWS_WITH( applyNamedPhaseFuncOverrides(quregVec, qb, numQb, numRegs, UNSIGNED, DISTANCE, NULL, NULL, 0), Contains("Phase functions DISTANCE") && Contains("even number of sub-registers") );
1502  }
1503  SECTION( "number of overrides" ) {
1504 
1505  int numOverrides = -1;
1506  REQUIRE_THROWS_WITH( applyNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, NORM, NULL, NULL, numOverrides), Contains("Invalid number of phase function overrides specified") );
1507  }
1508  SECTION( "override indices" ) {
1509 
1510  // numQubitsPerReg = {2, 3}
1511  int numOverrides = 3;
1512  long long int overrideInds[] = {0,0, 0,0, 0,0}; // repetition not checked
1513  qreal overridePhases[] = {.1, .1, .1};
1514 
1515  // first element of overrideInds coordinate is a 2 qubit register
1516  enum bitEncoding enc = UNSIGNED;
1517  int badInd = GENERATE(0, 2, 4);
1518  overrideInds[badInd] = GENERATE( -1, (1<<2) );
1519  REQUIRE_THROWS_WITH( applyNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, enc, NORM, overrideInds, overridePhases, numOverrides), Contains("Invalid phase function override index, in the UNSIGNED encoding") );
1520  overrideInds[badInd] = 0;
1521 
1522  // second element of overrideInds coordinate is a 3 qubit register
1523  badInd += 1;
1524  overrideInds[badInd] = GENERATE( -1, (1<<3) );
1525  REQUIRE_THROWS_WITH( applyNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, enc, NORM, overrideInds, overridePhases, numOverrides), Contains("Invalid phase function override index, in the UNSIGNED encoding") );
1526  overrideInds[badInd] = 0;
1527  badInd -= 1;
1528 
1529  enc = TWOS_COMPLEMENT;
1530  int minInd = -(1<<(numQubitsPerReg[0]-1));
1531  int maxInd = (1<<(numQubitsPerReg[0]-1)) - 1;
1532  overrideInds[badInd] = GENERATE_COPY( minInd-1, maxInd+1 );
1533  REQUIRE_THROWS_WITH( applyNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, enc, NORM, overrideInds, overridePhases, numOverrides), Contains("Invalid phase function override index, in the TWOS_COMPLEMENT encoding") );
1534  overrideInds[badInd] = 0;
1535 
1536  badInd++;
1537  minInd = -(1<<(numQubitsPerReg[1]-1));
1538  maxInd = (1<<(numQubitsPerReg[1]-1)) -1;
1539  overrideInds[badInd] = GENERATE_COPY( minInd-1, maxInd+1 );
1540  REQUIRE_THROWS_WITH( applyNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, enc, NORM, overrideInds, overridePhases, numOverrides), Contains("Invalid phase function override index, in the TWOS_COMPLEMENT encoding") );
1541  }
1542  }
1543  CLEANUP_TEST( quregVec, quregMatr );
1544 }

References applyNamedPhaseFuncOverrides(), applyReferenceOp(), areEqual(), CLEANUP_TEST, DISTANCE, expI(), getRandomInt(), getRandomReal(), getTwosComplement(), getZeroMatrix(), INVERSE_DISTANCE, INVERSE_NORM, INVERSE_PRODUCT, MAX_NUM_REGS_APPLY_ARBITRARY_PHASE, NORM, NUM_QUBITS, PREPARE_TEST, PRODUCT, qreal, SCALED_DISTANCE, SCALED_INVERSE_DISTANCE, SCALED_INVERSE_NORM, SCALED_INVERSE_PRODUCT, SCALED_INVERSE_SHIFTED_DISTANCE, SCALED_INVERSE_SHIFTED_NORM, SCALED_NORM, SCALED_PRODUCT, setDiagMatrixOverrides(), sublists(), TWOS_COMPLEMENT, and UNSIGNED.

◆ TEST_CASE() [11/124]

TEST_CASE ( "applyParamNamedPhaseFunc"  ,
""  [operators] 
)
See also
applyParamNamedPhaseFunc
Author
Tyson Jones

Definition at line 1552 of file test_operators.cpp.

1552  {
1553 
1554  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1555 
1556  SECTION( "correctness" ) {
1557 
1558  // try every kind of binary encoding
1559  enum bitEncoding encoding = GENERATE( UNSIGNED,TWOS_COMPLEMENT );
1560 
1561  // try every possible number of registers
1562  // (between #qubits containing 1, and 1 containing #qubits)
1563  int numRegs;
1564  int maxNumRegs = 0;
1565  if (encoding == UNSIGNED)
1566  maxNumRegs = NUM_QUBITS;
1567  if (encoding == TWOS_COMPLEMENT)
1568  maxNumRegs = NUM_QUBITS/2; // floors
1569  numRegs = GENERATE_COPY( range(1, maxNumRegs+1) );
1570 
1571  // try every possible total number of involved qubits
1572  int totalNumQubits;
1573  int minTotalQubits = 0;
1574  if (encoding == UNSIGNED)
1575  // each register must contain at least 1 qubit
1576  minTotalQubits = numRegs;
1577  if (encoding == TWOS_COMPLEMENT)
1578  // each register must contain at least 2 qubits
1579  minTotalQubits = 2*numRegs;
1580  totalNumQubits = GENERATE_COPY( range(minTotalQubits,NUM_QUBITS+1) );
1581 
1582  // try every qubits subset and ordering
1583  int* regs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), totalNumQubits) );
1584 
1585  // assign each sub-reg its minimum length
1586  int unallocQubits = totalNumQubits;
1587  int numQubitsPerReg[numRegs];
1588  for (int i=0; i<numRegs; i++)
1589  if (encoding == UNSIGNED) {
1590  numQubitsPerReg[i] = 1;
1591  unallocQubits -= 1;
1592  }
1593  else if (encoding == TWOS_COMPLEMENT) {
1594  numQubitsPerReg[i] = 2;
1595  unallocQubits -= 2;
1596  }
1597  // and randomly allocate the remaining qubits between the registers
1598  while (unallocQubits > 0) {
1599  numQubitsPerReg[getRandomInt(0,numRegs)] += 1;
1600  unallocQubits--;
1601  }
1602 
1603  /* produce a reference diagonal matrix which assumes the qubits are
1604  * contiguous and strictly increasing between the registers, and hence
1605  * only depends on the number of qubits in each register.
1606  */
1607  QMatrix diagMatr = getZeroMatrix(1 << totalNumQubits);
1608 
1609  // determine the values corresponding to each register for all basis states
1610  qreal regVals[1<<totalNumQubits][numRegs];
1611  for (long long int i=0; i<(1<<totalNumQubits); i++) {
1612 
1613  long long int bits = i;
1614  for (int r=0; r<numRegs; r++) {
1615  regVals[i][r] = bits % (1 << numQubitsPerReg[r]);
1616  bits = bits >> numQubitsPerReg[r];
1617 
1618  if (encoding == TWOS_COMPLEMENT)
1619  regVals[i][r] = getTwosComplement(regVals[i][r], numQubitsPerReg[r]);
1620  }
1621  }
1622 
1623  SECTION( "INVERSE_NORM" ) {
1624 
1625  enum phaseFunc func = INVERSE_NORM;
1626  qreal divPhase = getRandomReal(-4, 4);
1627 
1628  for (size_t i=0; i<diagMatr.size(); i++) {
1629  qreal phase = 0;
1630  for (int r=0; r<numRegs; r++)
1631  phase += pow(regVals[i][r], 2);
1632  phase = (phase == 0.)? divPhase : 1/sqrt(phase);
1633  diagMatr[i][i] = expI(phase);
1634  }
1635 
1636  qreal params[] = {divPhase};
1637  int numParams = 1;
1638 
1639  SECTION( "state-vector" ) {
1640 
1641  applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams);
1642  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
1643  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
1644  }
1645  SECTION( "density-matrix" ) {
1646 
1647  applyParamNamedPhaseFunc(quregMatr, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams);
1648  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
1649  REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
1650  }
1651 
1652  }
1653  SECTION( "SCALED_NORM" ) {
1654 
1655  enum phaseFunc func = SCALED_NORM;
1656  qreal coeff = getRandomReal(-10, 10);
1657 
1658  for (size_t i=0; i<diagMatr.size(); i++) {
1659  qreal phase = 0;
1660  for (int r=0; r<numRegs; r++)
1661  phase += pow(regVals[i][r], 2);
1662  phase = coeff * sqrt(phase);
1663  diagMatr[i][i] = expI(phase);
1664  }
1665 
1666  qreal params[] = {coeff};
1667  int numParams = 1;
1668 
1669  SECTION( "state-vector" ) {
1670 
1671  applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams);
1672  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
1673  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
1674  }
1675  SECTION( "density-matrix" ) {
1676 
1677  applyParamNamedPhaseFunc(quregMatr, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams);
1678  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
1679  REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
1680  }
1681  }
1682  SECTION( "SCALED_INVERSE_NORM" ) {
1683 
1684  enum phaseFunc func = SCALED_INVERSE_NORM;
1685  qreal coeff = getRandomReal(-10, 10);
1686  qreal divPhase = getRandomReal(-4, 4);
1687 
1688  for (size_t i=0; i<diagMatr.size(); i++) {
1689  qreal phase = 0;
1690  for (int r=0; r<numRegs; r++)
1691  phase += pow(regVals[i][r], 2);
1692  phase = (phase == 0.)? divPhase : coeff/sqrt(phase);
1693  diagMatr[i][i] = expI(phase);
1694  }
1695 
1696  qreal params[] = {coeff, divPhase};
1697  int numParams = 2;
1698 
1699  SECTION( "state-vector" ) {
1700 
1701  applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams);
1702  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
1703  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
1704  }
1705  SECTION( "density-matrix" ) {
1706 
1707  applyParamNamedPhaseFunc(quregMatr, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams);
1708  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
1709  REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
1710  }
1711  }
1712  SECTION( "SCALED_INVERSE_SHIFTED_NORM" ) {
1713 
1715  int numParams = 2 + numRegs;
1716  qreal params[numParams];
1717  params[0] = getRandomReal(-10, 10); // scaling
1718  params[1] = getRandomReal(-4, 4); // divergence override
1719  for (int r=0; r<numRegs; r++)
1720  params[2+r] = getRandomReal(-8, 8); // shifts
1721 
1722  for (size_t i=0; i<diagMatr.size(); i++) {
1723  qreal phase = 0;
1724  for (int r=0; r<numRegs; r++)
1725  phase += pow(regVals[i][r] - params[2+r], 2);
1726  phase = sqrt(phase);
1727  phase = (phase <= REAL_EPS)? params[1] : params[0]/phase;
1728  diagMatr[i][i] = expI(phase);
1729  }
1730 
1731  SECTION( "state-vector" ) {
1732 
1733  applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams);
1734  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
1735  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
1736  }
1737  SECTION( "density-matrix" ) {
1738 
1739  applyParamNamedPhaseFunc(quregMatr, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams);
1740  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
1741  REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
1742  }
1743  }
1744  SECTION( "INVERSE_PRODUCT" ) {
1745 
1746  enum phaseFunc func = INVERSE_PRODUCT;
1747  qreal divPhase = getRandomReal(-4, 4);
1748 
1749  for (size_t i=0; i<diagMatr.size(); i++) {
1750  qreal phase = 1;
1751  for (int r=0; r<numRegs; r++)
1752  phase *= regVals[i][r];
1753  phase = (phase == 0.)? divPhase : 1. / phase;
1754  diagMatr[i][i] = expI(phase);
1755  }
1756 
1757  qreal params[] = {divPhase};
1758  int numParams = 1;
1759 
1760  SECTION( "state-vector" ) {
1761 
1762  applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams);
1763  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
1764  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
1765  }
1766  SECTION( "density-matrix" ) {
1767 
1768  applyParamNamedPhaseFunc(quregMatr, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams);
1769  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
1770  REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
1771  }
1772  }
1773  SECTION( "SCALED_PRODUCT" ) {
1774 
1775  enum phaseFunc func = SCALED_PRODUCT;
1776  qreal coeff = getRandomReal(-10, 10);
1777 
1778  for (size_t i=0; i<diagMatr.size(); i++) {
1779  qreal phase = 1;
1780  for (int r=0; r<numRegs; r++)
1781  phase *= regVals[i][r];
1782  diagMatr[i][i] = expI(coeff * phase);
1783  }
1784 
1785  qreal params[] = {coeff};
1786  int numParams = 1;
1787 
1788  SECTION( "state-vector" ) {
1789 
1790  applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams);
1791  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
1792  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
1793  }
1794  SECTION( "density-matrix" ) {
1795 
1796  applyParamNamedPhaseFunc(quregMatr, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams);
1797  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
1798  REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
1799  }
1800  }
1801  SECTION( "SCALED_INVERSE_PRODUCT" ) {
1802 
1803  enum phaseFunc func = SCALED_INVERSE_PRODUCT;
1804  qreal coeff = getRandomReal(-10, 10);
1805  qreal divPhase = getRandomReal(-4, 4);
1806  qreal params[] = {coeff, divPhase};
1807  int numParams = 2;
1808 
1809  for (size_t i=0; i<diagMatr.size(); i++) {
1810  qreal phase = 1;
1811  for (int r=0; r<numRegs; r++)
1812  phase *= regVals[i][r];
1813  phase = (phase == 0)? divPhase : coeff / phase;
1814  diagMatr[i][i] = expI(phase);
1815  }
1816 
1817  SECTION( "state-vector" ) {
1818 
1819  applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams);
1820  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
1821  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
1822  }
1823  SECTION( "density-matrix" ) {
1824 
1825  applyParamNamedPhaseFunc(quregMatr, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams);
1826  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
1827  REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
1828  }
1829  }
1830  SECTION( "INVERSE_DISTANCE" ) {
1831 
1832  enum phaseFunc func = INVERSE_DISTANCE;
1833  qreal divPhase = getRandomReal( -4, 4 );
1834  qreal params[] = {divPhase};
1835  int numParams = 1;
1836 
1837  // test only if there are an even number of registers
1838  if (numRegs%2 == 0) {
1839 
1840  for (size_t i=0; i<diagMatr.size(); i++) {
1841  qreal phase = 0;
1842  for (int r=0; r<numRegs; r+=2)
1843  phase += pow(regVals[i][r+1]-regVals[i][r], 2);
1844  phase = (phase == 0.)? divPhase : 1./sqrt(phase);
1845  diagMatr[i][i] = expI(phase);
1846  }
1847  }
1848 
1849  SECTION( "state-vector" ) {
1850 
1851  if (numRegs%2 == 0) {
1852  applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams);
1853  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
1854  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
1855  }
1856  }
1857  SECTION( "density-matrix" ) {
1858 
1859  if (numRegs%2 == 0) {
1860  applyParamNamedPhaseFunc(quregMatr, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams);
1861  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
1862  REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
1863  }
1864  }
1865  }
1866  SECTION( "SCALED_DISTANCE" ) {
1867 
1868  enum phaseFunc func = SCALED_DISTANCE;
1869  qreal coeff = getRandomReal( -10, 10 );
1870  qreal params[] = {coeff};
1871  int numParams = 1;
1872 
1873  // test only if there are an even number of registers
1874  if (numRegs%2 == 0) {
1875 
1876  for (size_t i=0; i<diagMatr.size(); i++) {
1877  qreal phase = 0;
1878  for (int r=0; r<numRegs; r+=2)
1879  phase += pow(regVals[i][r+1]-regVals[i][r], 2);
1880  phase = coeff * sqrt(phase);
1881  diagMatr[i][i] = expI(phase);
1882  }
1883  }
1884 
1885  SECTION( "state-vector" ) {
1886 
1887  if (numRegs%2 == 0) {
1888  applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams);
1889  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
1890  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
1891  }
1892  }
1893  SECTION( "density-matrix" ) {
1894 
1895  if (numRegs%2 == 0) {
1896  applyParamNamedPhaseFunc(quregMatr, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams);
1897  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
1898  REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
1899  }
1900  }
1901  }
1902  SECTION( "SCALED_INVERSE_DISTANCE" ) {
1903 
1904  enum phaseFunc func = SCALED_INVERSE_DISTANCE;
1905  qreal coeff = getRandomReal( -10, 10 );
1906  qreal divPhase = getRandomReal( -4, 4 );
1907  qreal params[] = {coeff, divPhase};
1908  int numParams = 2;
1909 
1910  // test only if there are an even number of registers
1911  if (numRegs%2 == 0) {
1912 
1913  for (size_t i=0; i<diagMatr.size(); i++) {
1914  qreal phase = 0;
1915  for (int r=0; r<numRegs; r+=2)
1916  phase += pow(regVals[i][r+1]-regVals[i][r], 2);
1917  phase = (phase == 0.)? divPhase : coeff/sqrt(phase);
1918  diagMatr[i][i] = expI(phase);
1919  }
1920  }
1921 
1922  SECTION( "state-vector" ) {
1923 
1924  if (numRegs%2 == 0) {
1925  applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams);
1926  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
1927  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
1928  }
1929  }
1930  SECTION( "density-matrix" ) {
1931 
1932  if (numRegs%2 == 0) {
1933  applyParamNamedPhaseFunc(quregMatr, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams);
1934  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
1935  REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
1936  }
1937  }
1938  }
1939  SECTION( "SCALED_INVERSE_SHIFTED_DISTANCE" ) {
1940 
1942  int numParams = 2 + numRegs/2;
1943  qreal params[numParams];
1944 
1945  // test only if there are an even number of registers
1946  if (numRegs%2 == 0) {
1947 
1948  params[0] = getRandomReal( -10, 10 ); // scaling
1949  params[1] = getRandomReal( -4, 4 ); // divergence override
1950  for (int r=0; r<numRegs/2; r++)
1951  params[2+r] = getRandomReal( -8, 8 ); // shifts
1952 
1953  for (size_t i=0; i<diagMatr.size(); i++) {
1954  qreal phase = 0;
1955  for (int r=0; r<numRegs; r+=2)
1956  phase += pow(regVals[i][r]-regVals[i][r+1]-params[2+r/2], 2);
1957  phase = sqrt(phase);
1958  phase = (phase <= REAL_EPS)? params[1] : params[0]/phase;
1959  diagMatr[i][i] = expI(phase);
1960  }
1961  }
1962 
1963  SECTION( "state-vector" ) {
1964 
1965  if (numRegs%2 == 0) {
1966  applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams);
1967  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
1968  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
1969  }
1970  }
1971  SECTION( "density-matrix" ) {
1972 
1973  if (numRegs%2 == 0) {
1974  applyParamNamedPhaseFunc(quregMatr, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams);
1975  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
1976  REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
1977  }
1978  }
1979  }
1980  }
1981  SECTION( "input validation" ) {
1982 
1983  int numRegs = 2;
1984  int numQubitsPerReg[] = {2,3};
1985  int regs[] = {0,1,2,3,4};
1986 
1987  SECTION( "number of registers" ) {
1988 
1989  numRegs = GENERATE_COPY( -1, 0, 1+MAX_NUM_REGS_APPLY_ARBITRARY_PHASE );
1990  REQUIRE_THROWS_WITH( applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, NORM, NULL, 0), Contains("Invalid number of qubit subregisters") );
1991  }
1992  SECTION( "number of qubits" ) {
1993 
1994  numQubitsPerReg[GENERATE_COPY(range(0,numRegs))] = GENERATE( -1, 0, 1+NUM_QUBITS );
1995  REQUIRE_THROWS_WITH( applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, NORM, NULL, 0), Contains("Invalid number of qubits") );
1996  }
1997  SECTION( "repetition of qubits" ) {
1998 
1999  regs[GENERATE(2,3,4)] = regs[1];
2000  REQUIRE_THROWS_WITH( applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, NORM, NULL, 0), Contains("The qubits must be unique") );
2001  }
2002  SECTION( "qubit indices" ) {
2003 
2004  regs[GENERATE(range(0,NUM_QUBITS))] = GENERATE( -1, NUM_QUBITS );
2005  REQUIRE_THROWS_WITH( applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, NORM, NULL, 0), Contains("Invalid qubit index") );
2006  }
2007  SECTION( "bit encoding name" ) {
2008 
2009  enum bitEncoding enc = (enum bitEncoding) GENERATE( -1, 2 );
2010  REQUIRE_THROWS_WITH( applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, enc, NORM, NULL, 0), Contains("Invalid bit encoding") );
2011  }
2012  SECTION( "two's complement register" ) {
2013 
2014  numQubitsPerReg[GENERATE_COPY(range(0,numRegs))] = 1;
2015  REQUIRE_THROWS_WITH( applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, TWOS_COMPLEMENT, NORM, NULL, 0), Contains("A sub-register contained too few qubits to employ TWOS_COMPLEMENT encoding") );
2016  }
2017  SECTION( "phase function name" ) {
2018 
2019  enum phaseFunc func = (enum phaseFunc) GENERATE( -1, 14 );
2020  REQUIRE_THROWS_WITH( applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, func, NULL, 0), Contains("Invalid named phase function") );
2021  }
2022  SECTION( "phase function parameters" ) {
2023 
2024  qreal params[numRegs + 3];
2025  for (int r=0; r<numRegs + 3; r++)
2026  params[r] = 0;
2027 
2028  SECTION( "no parameter functions" ) {
2029 
2030  enum phaseFunc func = GENERATE( NORM, PRODUCT, DISTANCE );
2031  int numParams = GENERATE( -1, 1, 2 );
2032  REQUIRE_THROWS_WITH( applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, func, params, numParams), Contains("Invalid number of parameters") );
2033  }
2034  SECTION( "single parameter functions" ) {
2035 
2037  int numParams = GENERATE( -1, 0, 2 );
2038  REQUIRE_THROWS_WITH( applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, func, params, numParams), Contains("Invalid number of parameters") );
2039  }
2040  SECTION( "two parameter functions" ) {
2041 
2043  int numParams = GENERATE( 0, 1, 3 );
2044  REQUIRE_THROWS_WITH( applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, func, params, numParams), Contains("Invalid number of parameters") );
2045  }
2046  SECTION( "shifted distance" ) {
2047 
2048  if (numRegs%2 == 0) {
2050  int numParams = GENERATE_COPY( 0, 1, numRegs/2 - 1, numRegs/2, numRegs/2 + 1, numRegs/2 + 3 );
2051  REQUIRE_THROWS_WITH( applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, func, params, numParams), Contains("Invalid number of parameters") );
2052  }
2053  }
2054  SECTION( "shifted norm" ) {
2055 
2057  int numParams = GENERATE_COPY( 0, 1, numRegs-1, numRegs, numRegs+1, numRegs+3 );
2058  REQUIRE_THROWS_WITH( applyParamNamedPhaseFunc(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, func, params, numParams), Contains("Invalid number of parameters") );
2059  }
2060  }
2061  SECTION( "distance pair registers" ) {
2062 
2063  int numQb[] = {1,1,1,1,1};
2064  int qb[] = {0,1,2,3,4};
2065 
2066  numRegs = GENERATE( 1, 3, 5 );
2067  REQUIRE_THROWS_WITH( applyParamNamedPhaseFunc(quregVec, qb, numQb, numRegs, UNSIGNED, DISTANCE, NULL, 0), Contains("Phase functions DISTANCE") && Contains("even number of sub-registers") );
2068  }
2069  }
2070  CLEANUP_TEST( quregVec, quregMatr );
2071 }

References applyParamNamedPhaseFunc(), applyReferenceOp(), areEqual(), CLEANUP_TEST, DISTANCE, expI(), getRandomInt(), getRandomReal(), getTwosComplement(), getZeroMatrix(), INVERSE_DISTANCE, INVERSE_NORM, INVERSE_PRODUCT, MAX_NUM_REGS_APPLY_ARBITRARY_PHASE, NORM, NUM_QUBITS, PREPARE_TEST, PRODUCT, qreal, SCALED_DISTANCE, SCALED_INVERSE_DISTANCE, SCALED_INVERSE_NORM, SCALED_INVERSE_PRODUCT, SCALED_INVERSE_SHIFTED_DISTANCE, SCALED_INVERSE_SHIFTED_NORM, SCALED_NORM, SCALED_PRODUCT, sublists(), TWOS_COMPLEMENT, and UNSIGNED.

◆ TEST_CASE() [12/124]

TEST_CASE ( "applyParamNamedPhaseFuncOverrides"  ,
""  [operators] 
)
See also
applyParamNamedPhaseFuncOverrides
Author
Tyson Jones

Definition at line 2079 of file test_operators.cpp.

2079  {
2080 
2081  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2082 
2083  SECTION( "correctness" ) {
2084 
2085  // try every kind of binary encoding
2086  enum bitEncoding encoding = GENERATE( UNSIGNED,TWOS_COMPLEMENT );
2087 
2088  // try every possible number of registers
2089  // (between #qubits containing 1, and 1 containing #qubits)
2090  int numRegs;
2091  int maxNumRegs = 0;
2092  if (encoding == UNSIGNED)
2093  maxNumRegs = NUM_QUBITS;
2094  if (encoding == TWOS_COMPLEMENT)
2095  maxNumRegs = NUM_QUBITS/2; // floors
2096  numRegs = GENERATE_COPY( range(1, maxNumRegs+1) );
2097 
2098  // try every possible total number of involved qubits
2099  int totalNumQubits;
2100  int minTotalQubits = 0;
2101  if (encoding == UNSIGNED)
2102  // each register must contain at least 1 qubit
2103  minTotalQubits = numRegs;
2104  if (encoding == TWOS_COMPLEMENT)
2105  // each register must contain at least 2 qubits
2106  minTotalQubits = 2*numRegs;
2107  totalNumQubits = GENERATE_COPY( range(minTotalQubits,NUM_QUBITS+1) );
2108 
2109  // try every qubits subset and ordering
2110  int* regs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), totalNumQubits) );
2111 
2112  // assign each sub-reg its minimum length
2113  int unallocQubits = totalNumQubits;
2114  int numQubitsPerReg[numRegs];
2115  for (int i=0; i<numRegs; i++)
2116  if (encoding == UNSIGNED) {
2117  numQubitsPerReg[i] = 1;
2118  unallocQubits -= 1;
2119  }
2120  else if (encoding == TWOS_COMPLEMENT) {
2121  numQubitsPerReg[i] = 2;
2122  unallocQubits -= 2;
2123  }
2124  // and randomly allocate the remaining qubits between the registers
2125  while (unallocQubits > 0) {
2126  numQubitsPerReg[getRandomInt(0,numRegs)] += 1;
2127  unallocQubits--;
2128  }
2129 
2130 
2131  // choose a random number of overrides (even overriding every amplitude)
2132  int numOverrides = getRandomInt(0, (1<<totalNumQubits) + 1);
2133 
2134  // randomise each override index (uniqueness isn't checked)
2135  long long int overrideInds[numOverrides*numRegs];
2136  int flatInd = 0;
2137  for (int v=0; v<numOverrides; v++) {
2138  for (int r=0; r<numRegs; r++) {
2139  if (encoding == UNSIGNED)
2140  overrideInds[flatInd] = getRandomInt(0, 1<<numQubitsPerReg[r]);
2141  else if (encoding == TWOS_COMPLEMENT)
2142  overrideInds[flatInd] = getRandomInt(-(1<<(numQubitsPerReg[r]-1)), (1<<(numQubitsPerReg[r]-1))-1);
2143  flatInd++;
2144  }
2145  }
2146 
2147  // override to a random phase
2148  qreal overridePhases[numOverrides];
2149  for (int v=0; v<numOverrides; v++)
2150  overridePhases[v] = getRandomReal(-4, 4); // periodic in [-pi, pi]
2151 
2152 
2153  // determine the values corresponding to each register for all basis states
2154  qreal regVals[1<<totalNumQubits][numRegs];
2155  for (long long int i=0; i<(1<<totalNumQubits); i++) {
2156 
2157  long long int bits = i;
2158  for (int r=0; r<numRegs; r++) {
2159  regVals[i][r] = bits % (1 << numQubitsPerReg[r]);
2160  bits = bits >> numQubitsPerReg[r];
2161 
2162  if (encoding == TWOS_COMPLEMENT)
2163  regVals[i][r] = getTwosComplement(regVals[i][r], numQubitsPerReg[r]);
2164  }
2165  }
2166 
2167  /* produce a reference diagonal matrix which assumes the qubits are
2168  * contiguous and strictly increasing between the registers, and hence
2169  * only depends on the number of qubits in each register.
2170  */
2171  QMatrix diagMatr = getZeroMatrix(1 << totalNumQubits);
2172 
2173 
2174  SECTION( "INVERSE_NORM" ) {
2175 
2176  enum phaseFunc func = INVERSE_NORM;
2177  qreal divPhase = getRandomReal(-4, 4);
2178  qreal params[] = {divPhase};
2179  int numParams = 1;
2180 
2181  for (size_t i=0; i<diagMatr.size(); i++) {
2182  qreal phase = 0;
2183  for (int r=0; r<numRegs; r++)
2184  phase += pow(regVals[i][r], 2);
2185  phase = (phase == 0.)? divPhase : 1/sqrt(phase);
2186  diagMatr[i][i] = expI(phase);
2187  }
2188  setDiagMatrixOverrides(diagMatr, numQubitsPerReg, numRegs, encoding, overrideInds, overridePhases, numOverrides);
2189 
2190  SECTION( "state-vector" ) {
2191 
2192  applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams, overrideInds, overridePhases, numOverrides);
2193  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
2194  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
2195  }
2196  SECTION( "density-matrix" ) {
2197 
2198  applyParamNamedPhaseFuncOverrides(quregMatr, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams, overrideInds, overridePhases, numOverrides);
2199  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
2200  REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
2201  }
2202  }
2203  SECTION( "SCALED_NORM" ) {
2204 
2205  enum phaseFunc func = SCALED_NORM;
2206  qreal coeff = getRandomReal(-10, 10);
2207  qreal params[] = {coeff};
2208  int numParams = 1;
2209 
2210  for (size_t i=0; i<diagMatr.size(); i++) {
2211  qreal phase = 0;
2212  for (int r=0; r<numRegs; r++)
2213  phase += pow(regVals[i][r], 2);
2214  phase = coeff * sqrt(phase);
2215  diagMatr[i][i] = expI(phase);
2216  }
2217  setDiagMatrixOverrides(diagMatr, numQubitsPerReg, numRegs, encoding, overrideInds, overridePhases, numOverrides);
2218 
2219  SECTION( "state-vector" ) {
2220 
2221  applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams, overrideInds, overridePhases, numOverrides);
2222  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
2223  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
2224  }
2225  SECTION( "density-matrix" ) {
2226 
2227  applyParamNamedPhaseFuncOverrides(quregMatr, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams, overrideInds, overridePhases, numOverrides);
2228  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
2229  REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
2230  }
2231  }
2232  SECTION( "SCALED_INVERSE_NORM" ) {
2233 
2234  enum phaseFunc func = SCALED_INVERSE_NORM;
2235  qreal coeff = getRandomReal(-10, 10);
2236  qreal divPhase = getRandomReal(-4, 4);
2237  qreal params[] = {coeff, divPhase};
2238  int numParams = 2;
2239 
2240  for (size_t i=0; i<diagMatr.size(); i++) {
2241  qreal phase = 0;
2242  for (int r=0; r<numRegs; r++)
2243  phase += pow(regVals[i][r], 2);
2244  phase = (phase == 0.)? divPhase : coeff/sqrt(phase);
2245  diagMatr[i][i] = expI(phase);
2246  }
2247  setDiagMatrixOverrides(diagMatr, numQubitsPerReg, numRegs, encoding, overrideInds, overridePhases, numOverrides);
2248 
2249  SECTION( "state-vector" ) {
2250 
2251  applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams, overrideInds, overridePhases, numOverrides);
2252  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
2253  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
2254  }
2255  SECTION( "density-matrix" ) {
2256 
2257  applyParamNamedPhaseFuncOverrides(quregMatr, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams, overrideInds, overridePhases, numOverrides);
2258  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
2259  REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
2260  }
2261  }
2262  SECTION( "SCALED_INVERSE_SHIFTED_NORM" ) {
2263 
2265  int numParams = 2 + numRegs;
2266  qreal params[numParams];
2267  params[0] = getRandomReal(-10, 10); // scaling
2268  params[1] = getRandomReal(-4, 4); // divergence override
2269  for (int r=0; r<numRegs; r++)
2270  params[2+r] = getRandomReal(-8, 8); // shifts
2271 
2272  for (size_t i=0; i<diagMatr.size(); i++) {
2273  qreal phase = 0;
2274  for (int r=0; r<numRegs; r++)
2275  phase += pow(regVals[i][r] - params[2+r], 2);
2276  phase = sqrt(phase);
2277  phase = (phase <= REAL_EPS)? params[1] : params[0]/phase;
2278  diagMatr[i][i] = expI(phase);
2279  }
2280  setDiagMatrixOverrides(diagMatr, numQubitsPerReg, numRegs, encoding, overrideInds, overridePhases, numOverrides);
2281 
2282  SECTION( "state-vector" ) {
2283 
2284  applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams, overrideInds, overridePhases, numOverrides);
2285  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
2286  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
2287  }
2288  SECTION( "density-matrix" ) {
2289 
2290  applyParamNamedPhaseFuncOverrides(quregMatr, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams, overrideInds, overridePhases, numOverrides);
2291  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
2292  REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
2293  }
2294  }
2295  SECTION( "INVERSE_PRODUCT" ) {
2296 
2297  enum phaseFunc func = INVERSE_PRODUCT;
2298  qreal divPhase = getRandomReal(-4, 4);
2299  qreal params[] = {divPhase};
2300  int numParams = 1;
2301 
2302  for (size_t i=0; i<diagMatr.size(); i++) {
2303  qreal phase = 1;
2304  for (int r=0; r<numRegs; r++)
2305  phase *= regVals[i][r];
2306  phase = (phase == 0.)? divPhase : 1. / phase;
2307  diagMatr[i][i] = expI(phase);
2308  }
2309  setDiagMatrixOverrides(diagMatr, numQubitsPerReg, numRegs, encoding, overrideInds, overridePhases, numOverrides);
2310 
2311  SECTION( "state-vector" ) {
2312 
2313  applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams, overrideInds, overridePhases, numOverrides);
2314  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
2315  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
2316  }
2317  SECTION( "density-matrix" ) {
2318 
2319  applyParamNamedPhaseFuncOverrides(quregMatr, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams, overrideInds, overridePhases, numOverrides);
2320  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
2321  REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
2322  }
2323  }
2324  SECTION( "SCALED_PRODUCT" ) {
2325 
2326  enum phaseFunc func = SCALED_PRODUCT;
2327  qreal coeff = getRandomReal(-10, 10);
2328  qreal params[] = {coeff};
2329  int numParams = 1;
2330 
2331  for (size_t i=0; i<diagMatr.size(); i++) {
2332  qreal phase = 1;
2333  for (int r=0; r<numRegs; r++)
2334  phase *= regVals[i][r];
2335  diagMatr[i][i] = expI(coeff * phase);
2336  }
2337  setDiagMatrixOverrides(diagMatr, numQubitsPerReg, numRegs, encoding, overrideInds, overridePhases, numOverrides);
2338 
2339  SECTION( "state-vector" ) {
2340 
2341  applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams, overrideInds, overridePhases, numOverrides);
2342  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
2343  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
2344  }
2345  SECTION( "density-matrix" ) {
2346 
2347  applyParamNamedPhaseFuncOverrides(quregMatr, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams, overrideInds, overridePhases, numOverrides);
2348  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
2349  REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
2350  }
2351  }
2352  SECTION( "SCALED_INVERSE_PRODUCT" ) {
2353 
2354  enum phaseFunc func = SCALED_INVERSE_PRODUCT;
2355  qreal coeff = getRandomReal(-10, 10);
2356  qreal divPhase = getRandomReal(-4, 4);
2357  qreal params[] = {coeff, divPhase};
2358  int numParams = 2;
2359 
2360  for (size_t i=0; i<diagMatr.size(); i++) {
2361  qreal phase = 1;
2362  for (int r=0; r<numRegs; r++)
2363  phase *= regVals[i][r];
2364  phase = (phase == 0)? divPhase : coeff / phase;
2365  diagMatr[i][i] = expI(phase);
2366  }
2367  setDiagMatrixOverrides(diagMatr, numQubitsPerReg, numRegs, encoding, overrideInds, overridePhases, numOverrides);
2368 
2369  SECTION( "state-vector" ) {
2370 
2371  applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams, overrideInds, overridePhases, numOverrides);
2372  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
2373  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
2374  }
2375  SECTION( "density-matrix" ) {
2376 
2377  applyParamNamedPhaseFuncOverrides(quregMatr, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams, overrideInds, overridePhases, numOverrides);
2378  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
2379  REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
2380  }
2381  }
2382  SECTION( "INVERSE_DISTANCE" ) {
2383 
2384  enum phaseFunc func = INVERSE_DISTANCE;
2385  qreal divPhase = getRandomReal( -4, 4 );
2386  qreal params[] = {divPhase};
2387  int numParams = 1;
2388 
2389  // test only if there are an even number of registers
2390  if (numRegs%2 == 0) {
2391 
2392  for (size_t i=0; i<diagMatr.size(); i++) {
2393  qreal phase = 0;
2394  for (int r=0; r<numRegs; r+=2)
2395  phase += pow(regVals[i][r+1]-regVals[i][r], 2);
2396  phase = (phase == 0.)? divPhase : 1./sqrt(phase);
2397  diagMatr[i][i] = expI(phase);
2398  }
2399  setDiagMatrixOverrides(diagMatr, numQubitsPerReg, numRegs, encoding, overrideInds, overridePhases, numOverrides);
2400  }
2401 
2402  SECTION( "state-vector" ) {
2403 
2404  if (numRegs%2 == 0) {
2405  applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams, overrideInds, overridePhases, numOverrides);
2406  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
2407  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
2408  }
2409  }
2410  SECTION( "density-matrix" ) {
2411 
2412  if (numRegs%2 == 0) {
2413  applyParamNamedPhaseFuncOverrides(quregMatr, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams, overrideInds, overridePhases, numOverrides);
2414  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
2415  REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
2416  }
2417  }
2418  }
2419  SECTION( "SCALED_DISTANCE" ) {
2420 
2421  enum phaseFunc func = SCALED_DISTANCE;
2422  qreal coeff = getRandomReal( -10, 10 );
2423  qreal params[] = {coeff};
2424  int numParams = 1;
2425 
2426  // test only if there are an even number of registers
2427  if (numRegs%2 == 0) {
2428 
2429  for (size_t i=0; i<diagMatr.size(); i++) {
2430  qreal phase = 0;
2431  for (int r=0; r<numRegs; r+=2)
2432  phase += pow(regVals[i][r+1]-regVals[i][r], 2);
2433  phase = coeff * sqrt(phase);
2434  diagMatr[i][i] = expI(phase);
2435  }
2436  setDiagMatrixOverrides(diagMatr, numQubitsPerReg, numRegs, encoding, overrideInds, overridePhases, numOverrides);
2437  }
2438 
2439  SECTION( "state-vector" ) {
2440 
2441  if (numRegs%2 == 0) {
2442  applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams, overrideInds, overridePhases, numOverrides);
2443  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
2444  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
2445  }
2446  }
2447  SECTION( "density-matrix" ) {
2448 
2449  if (numRegs%2 == 0) {
2450  applyParamNamedPhaseFuncOverrides(quregMatr, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams, overrideInds, overridePhases, numOverrides);
2451  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
2452  REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
2453  }
2454  }
2455  }
2456  SECTION( "SCALED_INVERSE_DISTANCE" ) {
2457 
2458  enum phaseFunc func = SCALED_INVERSE_DISTANCE;
2459  qreal coeff = getRandomReal( -10, 10 );
2460  qreal divPhase = getRandomReal( -4, 4 );
2461  qreal params[] = {coeff, divPhase};
2462  int numParams = 2;
2463 
2464  // test only if there are an even number of registers
2465  if (numRegs%2 == 0) {
2466 
2467  for (size_t i=0; i<diagMatr.size(); i++) {
2468  qreal phase = 0;
2469  for (int r=0; r<numRegs; r+=2)
2470  phase += pow(regVals[i][r+1]-regVals[i][r], 2);
2471  phase = (phase == 0.)? divPhase : coeff/sqrt(phase);
2472  diagMatr[i][i] = expI(phase);
2473  }
2474  setDiagMatrixOverrides(diagMatr, numQubitsPerReg, numRegs, encoding, overrideInds, overridePhases, numOverrides);
2475  }
2476 
2477  SECTION( "state-vector" ) {
2478 
2479  if (numRegs%2 == 0) {
2480  applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams, overrideInds, overridePhases, numOverrides);
2481  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
2482  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
2483  }
2484  }
2485  SECTION( "density-matrix" ) {
2486 
2487  if (numRegs%2 == 0) {
2488  applyParamNamedPhaseFuncOverrides(quregMatr, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams, overrideInds, overridePhases, numOverrides);
2489  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
2490  REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
2491  }
2492  }
2493  }
2494  SECTION( "SCALED_INVERSE_SHIFTED_DISTANCE" ) {
2495 
2497  int numParams = 2 + numRegs/2;
2498  qreal params[numParams];
2499 
2500  // test only if there are an even number of registers
2501  if (numRegs%2 == 0) {
2502 
2503  params[0] = getRandomReal( -10, 10 ); // scaling
2504  params[1] = getRandomReal( -4, 4 ); // divergence override
2505  for (int r=0; r<numRegs/2; r++)
2506  params[2+r] = getRandomReal( -8, 8 ); // shifts
2507 
2508  for (size_t i=0; i<diagMatr.size(); i++) {
2509  qreal phase = 0;
2510  for (int r=0; r<numRegs; r+=2)
2511  phase += pow(regVals[i][r]-regVals[i][r+1]-params[2+r/2], 2);
2512  phase = sqrt(phase);
2513  phase = (phase <= REAL_EPS)? params[1] : params[0]/phase;
2514  diagMatr[i][i] = expI(phase);
2515  }
2516 
2517  setDiagMatrixOverrides(diagMatr, numQubitsPerReg, numRegs, encoding, overrideInds, overridePhases, numOverrides);
2518  }
2519 
2520  SECTION( "state-vector" ) {
2521 
2522  if (numRegs%2 == 0) {
2523  applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams, overrideInds, overridePhases, numOverrides);
2524  applyReferenceOp(refVec, regs, totalNumQubits, diagMatr);
2525  REQUIRE( areEqual(quregVec, refVec, 1E2*REAL_EPS) );
2526  }
2527  }
2528  SECTION( "density-matrix" ) {
2529 
2530  if (numRegs%2 == 0) {
2531  applyParamNamedPhaseFuncOverrides(quregMatr, regs, numQubitsPerReg, numRegs, encoding, func, params, numParams, overrideInds, overridePhases, numOverrides);
2532  applyReferenceOp(refMatr, regs, totalNumQubits, diagMatr);
2533  REQUIRE( areEqual(quregMatr, refMatr, 1E2*REAL_EPS) );
2534  }
2535  }
2536  }
2537  }
2538  SECTION( "input validation" ) {
2539 
2540  int numRegs = 2;
2541  int numQubitsPerReg[] = {2,3};
2542  int regs[] = {0,1,2,3,4};
2543 
2544  SECTION( "number of registers" ) {
2545 
2546  numRegs = GENERATE_COPY( -1, 0, 1+MAX_NUM_REGS_APPLY_ARBITRARY_PHASE );
2547  REQUIRE_THROWS_WITH( applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, NORM, NULL, 0, NULL, NULL, 0), Contains("Invalid number of qubit subregisters") );
2548  }
2549  SECTION( "number of qubits" ) {
2550 
2551  numQubitsPerReg[GENERATE_COPY(range(0,numRegs))] = GENERATE( -1, 0, 1+NUM_QUBITS );
2552  REQUIRE_THROWS_WITH( applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, NORM, NULL, 0, NULL, NULL, 0), Contains("Invalid number of qubits") );
2553  }
2554  SECTION( "repetition of qubits" ) {
2555 
2556  regs[GENERATE(2,3,4)] = regs[1];
2557  REQUIRE_THROWS_WITH( applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, NORM, NULL, 0, NULL, NULL, 0), Contains("The qubits must be unique") );
2558  }
2559  SECTION( "qubit indices" ) {
2560 
2561  regs[GENERATE(range(0,NUM_QUBITS))] = GENERATE( -1, NUM_QUBITS );
2562  REQUIRE_THROWS_WITH( applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, NORM, NULL, 0, NULL, NULL, 0), Contains("Invalid qubit index") );
2563  }
2564  SECTION( "bit encoding name" ) {
2565 
2566  enum bitEncoding enc = (enum bitEncoding) GENERATE( -1, 2 );
2567  REQUIRE_THROWS_WITH( applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, enc, NORM, NULL, 0, NULL, NULL, 0), Contains("Invalid bit encoding") );
2568  }
2569  SECTION( "two's complement register" ) {
2570 
2571  numQubitsPerReg[GENERATE_COPY(range(0,numRegs))] = 1;
2572  REQUIRE_THROWS_WITH( applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, TWOS_COMPLEMENT, NORM, NULL, 0, NULL, NULL, 0), Contains("A sub-register contained too few qubits to employ TWOS_COMPLEMENT encoding") );
2573  }
2574  SECTION( "phase function name" ) {
2575 
2576  enum phaseFunc func = (enum phaseFunc) GENERATE( -1, 14 );
2577  REQUIRE_THROWS_WITH( applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, func, NULL, 0, NULL, NULL, 0), Contains("Invalid named phase function") );
2578  }
2579  SECTION( "phase function parameters" ) {
2580 
2581  qreal params[numRegs + 3];
2582  for (int r=0; r<numRegs + 3; r++)
2583  params[r] = 0;
2584 
2585  SECTION( "no parameter functions" ) {
2586 
2587  enum phaseFunc func = GENERATE( NORM, PRODUCT, DISTANCE );
2588  int numParams = GENERATE( -1, 1, 2 );
2589  REQUIRE_THROWS_WITH( applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, func, params, numParams, NULL, NULL, 0), Contains("Invalid number of parameters") );
2590  }
2591  SECTION( "single parameter functions" ) {
2592 
2594  int numParams = GENERATE( -1, 0, 2 );
2595  REQUIRE_THROWS_WITH( applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, func, params, numParams, NULL, NULL, 0), Contains("Invalid number of parameters") );
2596  }
2597  SECTION( "two parameter functions" ) {
2598 
2600  int numParams = GENERATE( 0, 1, 3 );
2601  REQUIRE_THROWS_WITH( applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, func, params, numParams, NULL, NULL, 0), Contains("Invalid number of parameters") );
2602  }
2603  SECTION( "shifted distance" ) {
2604 
2605  if (numRegs%2 == 0) {
2607  int numParams = GENERATE_COPY( 0, 1, numRegs/2 - 1, numRegs/2, numRegs/2 + 1, numRegs/2 + 3 );
2608  REQUIRE_THROWS_WITH( applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, func, params, numParams, NULL, NULL, 0), Contains("Invalid number of parameters") );
2609  }
2610  }
2611  SECTION( "shifted norm" ) {
2612 
2614  int numParams = GENERATE_COPY( 0, 1, numRegs-1, numRegs, numRegs+1, numRegs+3 );
2615  REQUIRE_THROWS_WITH( applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, func, params, numParams, NULL, NULL, 0), Contains("Invalid number of parameters") );
2616  }
2617  }
2618  SECTION( "distance pair registers" ) {
2619 
2620  int numQb[] = {1,1,1,1,1};
2621  int qb[] = {0,1,2,3,4};
2622 
2623  numRegs = GENERATE( 1, 3, 5 );
2624  REQUIRE_THROWS_WITH( applyParamNamedPhaseFuncOverrides(quregVec, qb, numQb, numRegs, UNSIGNED, DISTANCE, NULL, 0, NULL, NULL, 0), Contains("Phase functions DISTANCE") && Contains("even number of sub-registers") );
2625  }
2626  SECTION( "number of overrides" ) {
2627 
2628  int numOverrides = -1;
2629  REQUIRE_THROWS_WITH( applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, UNSIGNED, NORM, NULL, 0, NULL, NULL, numOverrides), Contains("Invalid number of phase function overrides specified") );
2630  }
2631  SECTION( "override indices" ) {
2632 
2633  // numQubitsPerReg = {2, 3}
2634  int numOverrides = 3;
2635  long long int overrideInds[] = {0,0, 0,0, 0,0}; // repetition not checked
2636  qreal overridePhases[] = {.1, .1, .1};
2637 
2638  // first element of overrideInds coordinate is a 2 qubit register
2639  enum bitEncoding enc = UNSIGNED;
2640  int badInd = GENERATE(0, 2, 4);
2641  overrideInds[badInd] = GENERATE( -1, (1<<2) );
2642  REQUIRE_THROWS_WITH( applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, enc, NORM, NULL, 0, overrideInds, overridePhases, numOverrides), Contains("Invalid phase function override index, in the UNSIGNED encoding") );
2643  overrideInds[badInd] = 0;
2644 
2645  // second element of overrideInds coordinate is a 3 qubit register
2646  badInd += 1;
2647  overrideInds[badInd] = GENERATE( -1, (1<<3) );
2648  REQUIRE_THROWS_WITH( applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, enc, NORM, NULL, 0, overrideInds, overridePhases, numOverrides), Contains("Invalid phase function override index, in the UNSIGNED encoding") );
2649  overrideInds[badInd] = 0;
2650  badInd -= 1;
2651 
2652  enc = TWOS_COMPLEMENT;
2653  int minInd = -(1<<(numQubitsPerReg[0]-1));
2654  int maxInd = (1<<(numQubitsPerReg[0]-1)) - 1;
2655  overrideInds[badInd] = GENERATE_COPY( minInd-1, maxInd+1 );
2656  REQUIRE_THROWS_WITH( applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, enc, NORM, NULL, 0, overrideInds, overridePhases, numOverrides), Contains("Invalid phase function override index, in the TWOS_COMPLEMENT encoding") );
2657  overrideInds[badInd] = 0;
2658 
2659  badInd++;
2660  minInd = -(1<<(numQubitsPerReg[1]-1));
2661  maxInd = (1<<(numQubitsPerReg[1]-1)) -1;
2662  overrideInds[badInd] = GENERATE_COPY( minInd-1, maxInd+1 );
2663  REQUIRE_THROWS_WITH( applyParamNamedPhaseFuncOverrides(quregVec, regs, numQubitsPerReg, numRegs, enc, NORM, NULL, 0, overrideInds, overridePhases, numOverrides), Contains("Invalid phase function override index, in the TWOS_COMPLEMENT encoding") );
2664  }
2665  }
2666  CLEANUP_TEST( quregVec, quregMatr );
2667 }

References applyParamNamedPhaseFuncOverrides(), applyReferenceOp(), areEqual(), CLEANUP_TEST, DISTANCE, expI(), getRandomInt(), getRandomReal(), getTwosComplement(), getZeroMatrix(), INVERSE_DISTANCE, INVERSE_NORM, INVERSE_PRODUCT, MAX_NUM_REGS_APPLY_ARBITRARY_PHASE, NORM, NUM_QUBITS, PREPARE_TEST, PRODUCT, qreal, SCALED_DISTANCE, SCALED_INVERSE_DISTANCE, SCALED_INVERSE_NORM, SCALED_INVERSE_PRODUCT, SCALED_INVERSE_SHIFTED_DISTANCE, SCALED_INVERSE_SHIFTED_NORM, SCALED_NORM, SCALED_PRODUCT, setDiagMatrixOverrides(), sublists(), TWOS_COMPLEMENT, and UNSIGNED.

◆ TEST_CASE() [13/124]

TEST_CASE ( "applyPauliHamil"  ,
""  [operators] 
)
See also
applyPauliHamil
Author
Tyson Jones

Definition at line 2675 of file test_operators.cpp.

2675  {
2676 
2681 
2682  initDebugState(vecIn);
2683  initDebugState(matIn);
2684 
2685  SECTION( "correctness" ) {
2686 
2687  /* it's too expensive to try every possible Pauli configuration, so
2688  * we'll try 10 random codes, and for each, random coefficients
2689  */
2690  GENERATE( range(0,10) );
2691 
2692  int numTerms = GENERATE( 1, 2, 10, 15 );
2693  PauliHamil hamil = createPauliHamil(NUM_QUBITS, numTerms);
2694  setRandomPauliSum(hamil);
2695  QMatrix refHamil = toQMatrix(hamil);
2696 
2697  SECTION( "state-vector" ) {
2698 
2699  QVector vecRef = toQVector(vecIn);
2700  applyPauliHamil(vecIn, hamil, vecOut);
2701 
2702  // ensure vecIn barely changes under precision
2703  REQUIRE( areEqual(vecIn, vecRef) );
2704 
2705  // ensure vecOut changed correctly
2706  REQUIRE( areEqual(vecOut, refHamil * vecRef) );
2707  }
2708  SECTION( "density-matrix" ) {
2709 
2710  QMatrix matRef = toQMatrix(matIn);
2711  applyPauliHamil(matIn, hamil, matOut);
2712 
2713  // ensure matIn barely changes under precision
2714  REQUIRE( areEqual(matIn, matRef) );
2715 
2716  // ensure matOut changed correctly
2717  REQUIRE( areEqual(matOut, refHamil * matRef, 1E2*REAL_EPS) );
2718  }
2719 
2720  destroyPauliHamil(hamil);
2721  }
2722  SECTION( "input validation" ) {
2723 
2724  SECTION( "pauli codes" ) {
2725 
2726  int numTerms = 3;
2727  PauliHamil hamil = createPauliHamil(NUM_QUBITS, numTerms);
2728 
2729  // make one pauli code wrong
2730  hamil.pauliCodes[GENERATE_COPY( range(0,numTerms*NUM_QUBITS) )] = (pauliOpType) GENERATE( -1, 4 );
2731  REQUIRE_THROWS_WITH( applyPauliHamil(vecIn, hamil, vecOut), Contains("Invalid Pauli code") );
2732 
2733  destroyPauliHamil(hamil);
2734  }
2735  SECTION( "qureg dimensions" ) {
2736 
2737  Qureg badVec = createQureg(NUM_QUBITS+1, QUEST_ENV);
2739 
2740  REQUIRE_THROWS_WITH( applyPauliHamil(vecIn, hamil, badVec), Contains("Dimensions of the qubit registers don't match") );
2741 
2742  destroyQureg(badVec, QUEST_ENV);
2743  destroyPauliHamil(hamil);
2744  }
2745  SECTION( "qureg types" ) {
2746 
2748 
2749  REQUIRE_THROWS_WITH( applyPauliHamil(vecIn, hamil, matOut), Contains("Registers must both be state-vectors or both be density matrices") );
2750 
2751  destroyPauliHamil(hamil);
2752  }
2753  SECTION( "matching hamiltonian qubits" ) {
2754 
2755  PauliHamil hamil = createPauliHamil(NUM_QUBITS + 1, 1);
2756 
2757  REQUIRE_THROWS_WITH( applyPauliHamil(vecIn, hamil, vecOut), Contains("same number of qubits") );
2758  REQUIRE_THROWS_WITH( applyPauliHamil(matIn, hamil, matOut), Contains("same number of qubits") );
2759 
2760  destroyPauliHamil(hamil);
2761  }
2762  }
2763  destroyQureg(vecIn, QUEST_ENV);
2764  destroyQureg(vecOut, QUEST_ENV);
2765  destroyQureg(matIn, QUEST_ENV);
2766  destroyQureg(matOut, QUEST_ENV);
2767 }

References applyPauliHamil(), areEqual(), createDensityQureg(), createPauliHamil(), createQureg(), destroyPauliHamil(), destroyQureg(), initDebugState(), NUM_QUBITS, PauliHamil::pauliCodes, QUEST_ENV, setRandomPauliSum(), toQMatrix(), and toQVector().

◆ TEST_CASE() [14/124]

TEST_CASE ( "applyPauliSum"  ,
""  [operators] 
)
See also
applyPauliSum
Author
Tyson Jones

Definition at line 2775 of file test_operators.cpp.

2775  {
2776 
2781 
2782  initDebugState(vecIn);
2783  initDebugState(matIn);
2784 
2785  SECTION( "correctness" ) {
2786 
2787  /* it's too expensive to try ALL Pauli sequences, via
2788  * pauliOpType* paulis = GENERATE_COPY( pauliseqs(numPaulis) );.
2789  * Furthermore, take(10, pauliseqs(numTargs)) will try the same pauli codes.
2790  * Hence, we instead opt to repeatedly randomly generate pauliseqs
2791  */
2792  GENERATE( range(0,10) ); // gen 10 random pauli-codes
2793 
2794  int numTerms = GENERATE( 1, 2, 10, 15);
2795  int numPaulis = numTerms * NUM_QUBITS;
2796 
2797  // each test will use random coefficients
2798  qreal coeffs[numTerms];
2799  pauliOpType paulis[numPaulis];
2800  setRandomPauliSum(coeffs, paulis, NUM_QUBITS, numTerms);
2801  QMatrix pauliSum = toQMatrix(coeffs, paulis, NUM_QUBITS, numTerms);
2802 
2803  SECTION( "state-vector" ) {
2804 
2805  QVector vecRef = toQVector(vecIn);
2806  applyPauliSum(vecIn, paulis, coeffs, numTerms, vecOut);
2807 
2808  // ensure vecIn barely changes under precision
2809  REQUIRE( areEqual(vecIn, vecRef) );
2810 
2811  // ensure vecOut changed correctly
2812  REQUIRE( areEqual(vecOut, pauliSum * vecRef) );
2813  }
2814  SECTION( "density-matrix" ) {
2815 
2816  QMatrix matRef = toQMatrix(matIn);
2817  applyPauliSum(matIn, paulis, coeffs, numTerms, matOut);
2818 
2819  // ensure matIn barely changes under precision
2820  REQUIRE( areEqual(matIn, matRef) );
2821 
2822  // ensure matOut changed correctly
2823  REQUIRE( areEqual(matOut, pauliSum * matRef, 1E2*REAL_EPS) );
2824  }
2825  }
2826  SECTION( "input validation" ) {
2827 
2828  SECTION( "number of terms" ) {
2829 
2830  int numTerms = GENERATE( -1, 0 );
2831  REQUIRE_THROWS_WITH( applyPauliSum(vecIn, NULL, NULL, numTerms, vecOut), Contains("Invalid number of terms") );
2832  }
2833  SECTION( "pauli codes" ) {
2834 
2835  // valid codes
2836  int numTerms = 3;
2837  int numPaulis = numTerms*NUM_QUBITS;
2838  pauliOpType paulis[numPaulis];
2839  for (int i=0; i<numPaulis; i++)
2840  paulis[i] = PAULI_I;
2841 
2842  // make one invalid
2843  paulis[GENERATE_COPY( range(0,numPaulis) )] = (pauliOpType) GENERATE( -1, 4 );
2844  REQUIRE_THROWS_WITH( applyPauliSum(vecIn, paulis, NULL, numTerms, vecOut), Contains("Invalid Pauli code") );
2845  }
2846  SECTION( "qureg dimensions" ) {
2847 
2848  Qureg badVec = createQureg(NUM_QUBITS+1, QUEST_ENV);
2849  pauliOpType paulis[NUM_QUBITS];
2850  REQUIRE_THROWS_WITH( applyPauliSum(vecIn, paulis, NULL, 1, badVec), Contains("Dimensions of the qubit registers don't match") );
2851  destroyQureg(badVec, QUEST_ENV);
2852  }
2853  SECTION( "qureg types" ) {
2854 
2855  pauliOpType paulis[NUM_QUBITS];
2856  REQUIRE_THROWS_WITH( applyPauliSum(vecIn, paulis, NULL, 1, matOut), Contains("Registers must both be state-vectors or both be density matrices") );
2857  }
2858  }
2859  destroyQureg(vecIn, QUEST_ENV);
2860  destroyQureg(vecOut, QUEST_ENV);
2861  destroyQureg(matIn, QUEST_ENV);
2862  destroyQureg(matOut, QUEST_ENV);
2863 }

References applyPauliSum(), areEqual(), createDensityQureg(), createQureg(), destroyQureg(), initDebugState(), NUM_QUBITS, PAULI_I, qreal, QUEST_ENV, setRandomPauliSum(), toQMatrix(), and toQVector().

◆ TEST_CASE() [15/124]

TEST_CASE ( "applyPhaseFunc"  ,
""  [operators] 
)
See also
applyPhaseFunc
Author
Tyson Jones

Definition at line 2871 of file test_operators.cpp.

2871  {
2872 
2873  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2874 
2875  SECTION( "correctness" ) {
2876 
2877  // try every kind of binary encodings
2878  enum bitEncoding encoding = GENERATE( UNSIGNED,TWOS_COMPLEMENT );
2879 
2880  // try every sub-register size
2881  int numQubits = GENERATE_COPY( range(1,NUM_QUBITS+1) );
2882 
2883  // force at least 2 qubits in two's compement though
2884  if (encoding == TWOS_COMPLEMENT && numQubits == 1)
2885  numQubits++;
2886 
2887  // try every possible sub-register
2888  int* qubits = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numQubits) );
2889 
2890  // choose a random number of terms in the phase function
2891  int numTerms = getRandomInt(1, 5);
2892 
2893  // populate the phase function with random but POSITIVE-power terms,
2894  // and in two's complement mode, strictly integer powers
2895  qreal coeffs[numTerms];
2896  qreal expons[numTerms];
2897  for (int t=0; t<numTerms; t++) {
2898  coeffs[t] = getRandomReal(-10,10);
2899  if (encoding == TWOS_COMPLEMENT)
2900  expons[t] = getRandomInt(0, 3+1); // repetition of power is ok
2901  else
2902  expons[t] = getRandomReal(0, 3);
2903  }
2904 
2905  // build a reference diagonal matrix, on the reduced Hilbert space
2906  QMatrix matr = getZeroMatrix( 1 << numQubits );
2907  for (size_t i=0; i<matr.size(); i++) {
2908 
2909  long long int ind = 0;
2910  if (encoding == UNSIGNED)
2911  ind = i;
2912  if (encoding == TWOS_COMPLEMENT)
2913  ind = getTwosComplement(i, numQubits);
2914 
2915  qreal phase = 0;
2916  for (int t=0; t<numTerms; t++)
2917  phase += coeffs[t] * pow(ind, expons[t]);
2918 
2919  matr[i][i] = expI(phase);
2920  }
2921 
2922  SECTION( "state-vector" ) {
2923 
2924  applyPhaseFunc(quregVec, qubits, numQubits, encoding, coeffs, expons, numTerms);
2925  applyReferenceOp(refVec, qubits, numQubits, matr);
2926  REQUIRE( areEqual(quregVec, refVec, 1E4*REAL_EPS) );
2927  }
2928  SECTION( "density-matrix" ) {
2929 
2930  applyPhaseFunc(quregMatr, qubits, numQubits, encoding, coeffs, expons, numTerms);
2931  applyReferenceOp(refMatr, qubits, numQubits, matr);
2932  REQUIRE( areEqual(quregMatr, refMatr, 1E6*REAL_EPS) );
2933  }
2934  }
2935  SECTION( "input validation" ) {
2936 
2937  int numQubits = 3;
2938  int qubits[] = {0,1,2};
2939 
2940  SECTION( "number of qubits" ) {
2941 
2942  numQubits = GENERATE_COPY( -1, 0, NUM_QUBITS+1 );
2943  REQUIRE_THROWS_WITH( applyPhaseFunc(quregVec, NULL, numQubits, UNSIGNED, NULL, NULL, 1), Contains("Invalid number of qubits") );
2944  }
2945  SECTION( "repetition of qubits" ) {
2946 
2947  qubits[GENERATE(1,2)] = qubits[0];
2948  REQUIRE_THROWS_WITH( applyPhaseFunc(quregVec, qubits, numQubits, UNSIGNED, NULL, NULL, 1), Contains("The qubits must be unique") );
2949  }
2950  SECTION( "qubit indices" ) {
2951 
2952  int inv = GENERATE( -1, NUM_QUBITS );
2953  qubits[ GENERATE_COPY( range(0,numQubits) )] = inv;
2954  REQUIRE_THROWS_WITH( applyPhaseFunc(quregVec, qubits, numQubits, UNSIGNED, NULL, NULL, 1), Contains("Invalid qubit index") );
2955  }
2956  SECTION( "number of terms" ) {
2957 
2958  int numTerms = GENERATE( -1, 0 );
2959  REQUIRE_THROWS_WITH( applyPhaseFunc(quregVec, qubits, numQubits, UNSIGNED, NULL, NULL, numTerms), Contains("Invalid number of terms in the phase function") );
2960  }
2961  SECTION( "bit encoding name" ) {
2962 
2963  enum bitEncoding enc = (enum bitEncoding) GENERATE( -1,2 );
2964  REQUIRE_THROWS_WITH( applyPhaseFunc(quregVec, qubits, numQubits, enc, NULL, NULL, 1), Contains("Invalid bit encoding") );
2965  }
2966  SECTION( "two's complement register" ) {
2967 
2968  numQubits = 1;
2969  REQUIRE_THROWS_WITH( applyPhaseFunc(quregVec, qubits, numQubits, TWOS_COMPLEMENT, NULL, NULL, 1), Contains("too few qubits to employ TWOS_COMPLEMENT") );
2970  }
2971  SECTION( "fractional exponent" ) {
2972 
2973  int numTerms = 3;
2974  qreal coeffs[] = {0,0,0};
2975  qreal expos[] = {1,2,3};
2976  expos[GENERATE_COPY( range(0,numTerms) )] = GENERATE( 0.5, 1.999, 5.0001 );
2977 
2978  REQUIRE_THROWS_WITH( applyPhaseFunc(quregVec, qubits, numQubits, TWOS_COMPLEMENT, coeffs, expos, numTerms), Contains("fractional exponent") && Contains("TWOS_COMPLEMENT") && Contains("negative indices were not overriden") );
2979  }
2980  SECTION( "negative exponent" ) {
2981 
2982  int numTerms = 3;
2983  qreal coeffs[] = {0,0,0};
2984  qreal expos[] = {1,2,3};
2985  expos[GENERATE_COPY( range(0,numTerms) )] = GENERATE( -1, -2, -1.5 );
2986 
2987  enum bitEncoding encoding = GENERATE( UNSIGNED, TWOS_COMPLEMENT );
2988 
2989  REQUIRE_THROWS_WITH( applyPhaseFunc(quregVec, qubits, numQubits, encoding, coeffs, expos, numTerms), Contains("The phase function contained a negative exponent which would diverge at zero, but the zero index was not overriden") );
2990  }
2991  }
2992  CLEANUP_TEST( quregVec, quregMatr );
2993 }

References applyPhaseFunc(), applyReferenceOp(), areEqual(), CLEANUP_TEST, expI(), getRandomInt(), getRandomReal(), getTwosComplement(), getZeroMatrix(), NUM_QUBITS, PREPARE_TEST, qreal, sublists(), TWOS_COMPLEMENT, and UNSIGNED.

◆ TEST_CASE() [16/124]

TEST_CASE ( "applyPhaseFuncOverrides"  ,
""  [operators] 
)
See also
applyPhaseFuncOverrides
Author
Tyson Jones

Definition at line 3001 of file test_operators.cpp.

3001  {
3002 
3003  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
3004 
3005  SECTION( "correctness" ) {
3006 
3007  // try every kind of binary encodings
3008  enum bitEncoding encoding = GENERATE( UNSIGNED,TWOS_COMPLEMENT );
3009 
3010  // try every sub-register size
3011  int numQubits = GENERATE_COPY( range(1,NUM_QUBITS+1) );
3012 
3013  // force at least 2 qubits in two's compement though
3014  if (encoding == TWOS_COMPLEMENT && numQubits == 1)
3015  numQubits++;
3016 
3017  // try every possible sub-register
3018  int* qubits = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numQubits) );
3019 
3020  // choose a random number of terms in the phase function
3021  int numTerms = getRandomInt(1, 21);
3022 
3023  // populate the phase function with random powers.
3024  // this includes negative powers, so we must always override 0.
3025  // in two's complement, we must use only integer powers
3026  qreal coeffs[numTerms];
3027  qreal expons[numTerms];
3028  for (int t=0; t<numTerms; t++) {
3029  coeffs[t] = getRandomReal(-10,10);
3030  if (encoding == TWOS_COMPLEMENT)
3031  expons[t] = getRandomInt(-3, 3+1); // note we COULD do getRandomReal(), and override all negatives
3032  else
3033  expons[t] = getRandomReal(-3, 3);
3034  }
3035 
3036  // choose a random number of overrides (even overriding every amplitude)
3037  int numOverrides = getRandomInt(1, (1<<numQubits) + 1);
3038 
3039  // randomise each override index (uniqueness isn't checked)
3040  long long int overrideInds[numOverrides];
3041  overrideInds[0] = 0LL;
3042  for (int i=1; i<numOverrides; i++)
3043  if (encoding == UNSIGNED)
3044  overrideInds[i] = getRandomInt(0, 1<<numQubits);
3045  else if (encoding == TWOS_COMPLEMENT)
3046  overrideInds[i] = getRandomInt(-(1<<(numQubits-1)), (1<<(numQubits-1))-1);
3047 
3048  // override to a random phase
3049  qreal overridePhases[numOverrides];
3050  for (int i=0; i<numOverrides; i++)
3051  overridePhases[i] = getRandomReal(-4, 4); // periodic in [-pi, pi]
3052 
3053  // build a reference diagonal matrix, on the reduced Hilbert space
3054  QMatrix matr = getZeroMatrix( 1 << numQubits );
3055  for (size_t i=0; i<matr.size(); i++) {
3056 
3057  long long int ind = 0;
3058  if (encoding == UNSIGNED)
3059  ind = i;
3060  if (encoding == TWOS_COMPLEMENT)
3061  ind = getTwosComplement(i, numQubits);
3062 
3063  // reference diagonal matrix incorporates overriden phases
3064  qreal phase;
3065  bool overriden = false;
3066  for (int v=0; v<numOverrides; v++) {
3067  if (ind == overrideInds[v]) {
3068  phase = overridePhases[v];
3069  overriden = true;
3070  break;
3071  }
3072  }
3073 
3074  if (!overriden) {
3075  phase = 0;
3076  for (int t=0; t<numTerms; t++)
3077  phase += coeffs[t] * pow(ind, expons[t]);
3078  }
3079 
3080  matr[i][i] = expI(phase);
3081  }
3082 
3083  SECTION( "state-vector" ) {
3084 
3085  applyPhaseFuncOverrides(quregVec, qubits, numQubits, encoding, coeffs, expons, numTerms, overrideInds, overridePhases, numOverrides);
3086  applyReferenceOp(refVec, qubits, numQubits, matr);
3087  REQUIRE( areEqual(quregVec, refVec, 1E4*REAL_EPS) );
3088  }
3089  SECTION( "density-matrix" ) {
3090 
3091  applyPhaseFuncOverrides(quregMatr, qubits, numQubits, encoding, coeffs, expons, numTerms, overrideInds, overridePhases, numOverrides);
3092  applyReferenceOp(refMatr, qubits, numQubits, matr);
3093  REQUIRE( areEqual(quregMatr, refMatr, 1E6*REAL_EPS) );
3094  }
3095  }
3096  SECTION( "input validation" ) {
3097 
3098  int numQubits = 3;
3099  int qubits[] = {0,1,2};
3100 
3101  SECTION( "number of qubits" ) {
3102 
3103  int numQubits = GENERATE_COPY( -1, 0, NUM_QUBITS+1 );
3104  REQUIRE_THROWS_WITH( applyPhaseFuncOverrides(quregVec, NULL, numQubits, UNSIGNED, NULL, NULL, 1, NULL, NULL, 0), Contains("Invalid number of qubits") );
3105  }
3106  SECTION( "repetition qubits" ) {
3107 
3108  qubits[GENERATE(1,2)] = qubits[0];
3109  REQUIRE_THROWS_WITH( applyPhaseFuncOverrides(quregVec, qubits, numQubits, UNSIGNED, NULL, NULL, 1, NULL, NULL, 0), Contains("The qubits must be unique") );
3110  }
3111  SECTION( "qubit indices" ) {
3112 
3113  int inv = GENERATE( -1, NUM_QUBITS );
3114  qubits[ GENERATE_COPY( range(0,numQubits) )] = inv;
3115  REQUIRE_THROWS_WITH( applyPhaseFuncOverrides(quregVec, qubits, numQubits, UNSIGNED, NULL, NULL, 1, NULL, NULL, 0), Contains("Invalid qubit index") );
3116  }
3117  SECTION( "number of terms" ) {
3118 
3119  int numTerms = GENERATE( -1, 0 );
3120  REQUIRE_THROWS_WITH( applyPhaseFuncOverrides(quregVec, qubits, numQubits, UNSIGNED, NULL, NULL, numTerms, NULL, NULL, 0), Contains("Invalid number of terms in the phase function") );
3121  }
3122  SECTION( "bit encoding name" ) {
3123 
3124  enum bitEncoding enc = (enum bitEncoding) GENERATE( -1,2 );
3125  REQUIRE_THROWS_WITH( applyPhaseFuncOverrides(quregVec, qubits, numQubits, enc, NULL, NULL, 1, NULL, NULL, 0), Contains("Invalid bit encoding") );
3126  }
3127  SECTION( "two's complement register" ) {
3128 
3129  numQubits = 1;
3130  REQUIRE_THROWS_WITH( applyPhaseFuncOverrides(quregVec, qubits, numQubits, TWOS_COMPLEMENT, NULL, NULL, 1, NULL, NULL, 0), Contains("too few qubits to employ TWOS_COMPLEMENT") );
3131  }
3132  SECTION( "number of overrides" ) {
3133 
3134  qreal dummyTerms[] = {0};
3135 
3136  int numOverrides = GENERATE_COPY( -1, 1 + (1<<numQubits) );
3137  REQUIRE_THROWS_WITH( applyPhaseFuncOverrides(quregVec, qubits, numQubits, UNSIGNED, dummyTerms, dummyTerms, 1, NULL, NULL, numOverrides), Contains("Invalid number of phase function overrides") );
3138  }
3139  SECTION( "override indices" ) {
3140 
3141  int numOverrides = 3;
3142  long long int overrideInds[] = {0,1,2};
3143  qreal overridePhases[] = {.1,.1,.1};
3144  qreal dummyTerms[] = {0};
3145 
3146  enum bitEncoding encoding = UNSIGNED;
3147  overrideInds[GENERATE(0,1,2)] = GENERATE_COPY( -1, (1<<numQubits) );
3148  REQUIRE_THROWS_WITH( applyPhaseFuncOverrides(quregVec, qubits, numQubits, encoding, dummyTerms, dummyTerms, 1, overrideInds, overridePhases, numOverrides), Contains("Invalid phase function override index, in the UNSIGNED encoding") );
3149 
3150  encoding = TWOS_COMPLEMENT;
3151  long long int newInds[] = {0,1,2};
3152  int minInd = -(1<<(numQubits-1));
3153  int maxInd = (1<<(numQubits-1)) -1;
3154  newInds[GENERATE(0,1,2)] = GENERATE_COPY( minInd-1, maxInd+1 );
3155  REQUIRE_THROWS_WITH( applyPhaseFuncOverrides(quregVec, qubits, numQubits, encoding, dummyTerms, dummyTerms, 1, newInds, overridePhases, numOverrides), Contains("Invalid phase function override index, in the TWOS_COMPLEMENT encoding") );
3156  }
3157  SECTION( "fractional exponent" ) {
3158 
3159  int numTerms = 3;
3160  qreal coeffs[] = {0,0,0};
3161  qreal expos[] = {1,2,3};
3162 
3163  // make one exponent fractional, thereby requiring negative overrides
3164  expos[GENERATE_COPY( range(0,numTerms) )] = GENERATE( 0.5, 1.999, 5.0001 );
3165 
3166  // catch when no negative indices are overridden
3167  REQUIRE_THROWS_WITH( applyPhaseFuncOverrides(quregVec, qubits, numQubits, TWOS_COMPLEMENT, coeffs, expos, numTerms, NULL, NULL, 0), Contains("fractional exponent") && Contains("TWOS_COMPLEMENT") && Contains("negative indices were not overriden") );
3168 
3169  int numNegs = 1 << (numQubits-1);
3170  long long int overrideInds[numNegs];
3171  qreal overridePhases[numNegs];
3172  for (int i=0; i<numNegs; i++) {
3173  overrideInds[i] = -(i+1);
3174  overridePhases[i] = 0;
3175  }
3176 
3177  // ensure no throw when all are overriden
3178  REQUIRE_NOTHROW( applyPhaseFuncOverrides(quregVec, qubits, numQubits, TWOS_COMPLEMENT, coeffs, expos, numTerms, overrideInds, overridePhases, numNegs) );
3179 
3180  // catch when at least one isn't overriden
3181  overrideInds[GENERATE_COPY( range(0,numNegs) )] = 0; // override a non-negative
3182  REQUIRE_THROWS_WITH( applyPhaseFuncOverrides(quregVec, qubits, numQubits, TWOS_COMPLEMENT, coeffs, expos, numTerms, overrideInds, overridePhases, numNegs), Contains("fractional exponent") && Contains("TWOS_COMPLEMENT") && Contains("negative indices were not overriden") );
3183  }
3184  SECTION( "negative exponent" ) {
3185 
3186  int numTerms = 3;
3187  qreal coeffs[] = {0,0,0};
3188  qreal expos[] = {1,2,3};
3189  expos[GENERATE_COPY( range(0,numTerms) )] = GENERATE( -1, -2 );
3190 
3191  enum bitEncoding encoding = GENERATE( UNSIGNED, TWOS_COMPLEMENT );
3192 
3193  // test both when giving no overrides, and giving all non-zero overrides
3194  int numOverrides = GENERATE( 0, 3 );
3195  long long int overrideInds[] = {1,2,3};
3196  qreal overridePhases[] = {0,0,0};
3197  REQUIRE_THROWS_WITH( applyPhaseFuncOverrides(quregVec, qubits, numQubits, encoding, coeffs, expos, numTerms, overrideInds, overridePhases, numOverrides), Contains("The phase function contained a negative exponent which would diverge at zero, but the zero index was not overriden") );
3198 
3199  // but ensure that when the zero IS overriden (anywhere), there's no error
3200  numOverrides = 3;
3201  overrideInds[GENERATE_COPY(range(0,numOverrides))] = 0;
3202  REQUIRE_NOTHROW( applyPhaseFuncOverrides(quregVec, qubits, numQubits, encoding, coeffs, expos, numTerms, overrideInds, overridePhases, numOverrides) );
3203  }
3204  }
3205  CLEANUP_TEST( quregVec, quregMatr );
3206 }

References applyPhaseFuncOverrides(), applyReferenceOp(), areEqual(), CLEANUP_TEST, expI(), getRandomInt(), getRandomReal(), getTwosComplement(), getZeroMatrix(), NUM_QUBITS, PREPARE_TEST, qreal, sublists(), TWOS_COMPLEMENT, and UNSIGNED.

◆ TEST_CASE() [17/124]

TEST_CASE ( "applyProjector"  ,
""  [operators] 
)
See also
applyProjector
Author
Tyson Jones

Definition at line 3214 of file test_operators.cpp.

3214  {
3215 
3218 
3219  SECTION( "correctness" ) {
3220 
3221  int qubit = GENERATE( range(0,NUM_QUBITS) );
3222  int outcome = GENERATE( 0, 1 );
3223 
3224  // repeat these random tests 10 times on every qubit, and for both outcomes
3225  GENERATE( range(0,10) );
3226 
3227  SECTION( "state-vector" ) {
3228 
3229  SECTION( "normalised" ) {
3230 
3231  // use a random L2 state for every qubit & outcome
3233  toQureg(vec, vecRef);
3234 
3235  // zero non-outcome reference amps
3236  for (size_t ind=0; ind<vecRef.size(); ind++) {
3237  int bit = (ind >> qubit) & 1; // target-th bit
3238  if (bit != outcome)
3239  vecRef[ind] = 0;
3240  }
3241 
3242  applyProjector(vec, qubit, outcome);
3243  REQUIRE( areEqual(vec, vecRef) );
3244  }
3245  SECTION( "unnormalised" ) {
3246 
3247  // use a random non-physical state for every qubit & outcome
3248  QVector vecRef = getRandomQVector(1 << NUM_QUBITS);
3249  toQureg(vec, vecRef);
3250 
3251  // zero non-outcome reference amps
3252  for (size_t ind=0; ind<vecRef.size(); ind++) {
3253  int bit = (ind >> qubit) & 1; // target-th bit
3254  if (bit != outcome)
3255  vecRef[ind] = 0;
3256  }
3257 
3258  applyProjector(vec, qubit, outcome);
3259  REQUIRE( areEqual(vec, vecRef) );
3260  }
3261  }
3262  SECTION( "density-matrix" ) {
3263 
3264  SECTION( "pure" ) {
3265 
3267  QMatrix matRef = getPureDensityMatrix(vecRef);
3268 
3269  toQureg(mat, matRef);
3270  applyProjector(mat, qubit, outcome);
3271 
3272  // zero any amplitudes that aren't |outcome><outcome|
3273  for (size_t r=0; r<matRef.size(); r++) {
3274  for (size_t c=0; c<matRef.size(); c++) {
3275  int ketBit = (c >> qubit) & 1;
3276  int braBit = (r >> qubit) & 1;
3277  if (!(ketBit == outcome && braBit == outcome))
3278  matRef[r][c] = 0;
3279  }
3280  }
3281 
3282  REQUIRE( areEqual(mat, matRef) );
3283  }
3284  SECTION( "mixed" ) {
3285 
3287 
3288  toQureg(mat, matRef);
3289  applyProjector(mat, qubit, outcome);
3290 
3291  // zero any amplitudes that aren't |outcome><outcome|
3292  for (size_t r=0; r<matRef.size(); r++) {
3293  for (size_t c=0; c<matRef.size(); c++) {
3294  int ketBit = (c >> qubit) & 1;
3295  int braBit = (r >> qubit) & 1;
3296  if (!(ketBit == outcome && braBit == outcome))
3297  matRef[r][c] = 0;
3298  }
3299  }
3300 
3301  REQUIRE( areEqual(mat, matRef) );
3302  }
3303  SECTION( "unnormalised" ) {
3304 
3305  QMatrix matRef = getRandomQMatrix(1 << NUM_QUBITS);
3306 
3307  toQureg(mat, matRef);
3308  applyProjector(mat, qubit, outcome);
3309 
3310  // zero any amplitudes that aren't |outcome><outcome|
3311  for (size_t r=0; r<matRef.size(); r++) {
3312  for (size_t c=0; c<matRef.size(); c++) {
3313  int ketBit = (c >> qubit) & 1;
3314  int braBit = (r >> qubit) & 1;
3315  if (!(ketBit == outcome && braBit == outcome))
3316  matRef[r][c] = 0;
3317  }
3318  }
3319 
3320  REQUIRE( areEqual(mat, matRef) );
3321  }
3322  }
3323  }
3324  SECTION( "input validation" ) {
3325 
3326  SECTION( "qubit index" ) {
3327 
3328  int qubit = GENERATE( -1, NUM_QUBITS );
3329  int outcome = 0;
3330  REQUIRE_THROWS_WITH( applyProjector(mat, qubit, outcome), Contains("Invalid target qubit") );
3331  }
3332  SECTION( "outcome value" ) {
3333 
3334  int qubit = 0;
3335  int outcome = GENERATE( -1, 2 );
3336  REQUIRE_THROWS_WITH( applyProjector(mat, qubit, outcome), Contains("Invalid measurement outcome") );
3337  }
3338  }
3339  destroyQureg(vec, QUEST_ENV);
3340  destroyQureg(mat, QUEST_ENV);
3341 }

References applyProjector(), areEqual(), createDensityQureg(), createQureg(), destroyQureg(), getPureDensityMatrix(), getRandomDensityMatrix(), getRandomQMatrix(), getRandomQVector(), getRandomStateVector(), NUM_QUBITS, QUEST_ENV, and toQureg().

◆ TEST_CASE() [18/124]

TEST_CASE ( "applyQFT"  ,
""  [operators] 
)
See also
applyQFT
Author
Tyson Jones

Definition at line 3349 of file test_operators.cpp.

3349  {
3350 
3351  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
3352 
3353  SECTION( "correctness" ) {
3354 
3355  // try every sub-register size
3356  int numQubits = GENERATE_COPY( range(1,NUM_QUBITS+1) );
3357 
3358  // try every possible sub-register
3359  int* qubits = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numQubits) );
3360 
3361  SECTION( "state-vector" ) {
3362 
3363  SECTION( "normalised" ) {
3364 
3366  toQureg(quregVec, refVec);
3367 
3368  applyQFT(quregVec, qubits, numQubits);
3369  refVec = getDFT(refVec, qubits, numQubits);
3370 
3371  REQUIRE( areEqual(quregVec, refVec) );
3372  }
3373  SECTION( "unnormalised" ) {
3374 
3375  QVector refVec = getRandomQVector(1 << NUM_QUBITS);
3376  toQureg(quregVec, refVec);
3377 
3378  applyQFT(quregVec, qubits, numQubits);
3379  refVec = getDFT(refVec, qubits, numQubits);
3380 
3381  REQUIRE( areEqual(quregVec, refVec) );
3382  }
3383  }
3384  SECTION( "density-matrix" ) {
3385 
3386  SECTION( "pure" ) {
3387 
3388  /* a pure density matrix should be mapped to a pure state
3389  * corresponding to the state-vector DFT
3390  */
3391 
3392  refVec = getRandomStateVector(NUM_QUBITS);
3393  refMatr = getPureDensityMatrix(refVec);
3394  toQureg(quregMatr, refMatr);
3395 
3396  applyQFT(quregMatr, qubits, numQubits);
3397  refVec = getDFT(refVec, qubits, numQubits);
3398  refMatr = getPureDensityMatrix(refVec);
3399 
3400  REQUIRE( areEqual(quregMatr, refMatr) );
3401  }
3402  SECTION( "mixed" ) {
3403 
3404  /* a mixed density matrix, conceptualised as a mixture of orthogonal
3405  * state-vectors, should be mapped to an equally weighted mixture
3406  * of DFTs of each state-vector (because QFT is unitary and hence
3407  * maintains state orthogonality)
3408  */
3409 
3410  int numStates = (1 << NUM_QUBITS)/4; // a quarter of as many states as are possible
3411  std::vector<QVector> states = getRandomOrthonormalVectors(NUM_QUBITS, numStates);
3412  std::vector<qreal> probs = getRandomProbabilities(numStates);
3413 
3414  // set qureg to random mixture of state-vectors
3415  refMatr = getMixedDensityMatrix(probs, states);
3416  toQureg(quregMatr, refMatr);
3417 
3418  // apply QFT to mixture
3419  applyQFT(quregMatr, qubits, numQubits);
3420 
3421  // compute dft of mixture, via dft of each state
3422  refMatr = getZeroMatrix(1 << NUM_QUBITS);
3423  for (int i=0; i<numStates; i++) {
3424  QVector dft = getDFT(states[i], qubits, numQubits);
3425  refMatr += probs[i] * getPureDensityMatrix(dft);
3426  }
3427 
3428  REQUIRE( areEqual(quregMatr, refMatr) );
3429  }
3430  SECTION( "unnormalised" ) {
3431 
3432  /* repeat method above, except that we use unnormalised vectors,
3433  * and mix them with arbitrary complex numbers instead of probabilities,
3434  * yielding an unnormalised density matrix
3435  */
3436 
3437  int numVecs = (1 << NUM_QUBITS)/4; // a quarter of as many states as are possible
3438  std::vector<QVector> vecs;
3439  std::vector<qcomp> coeffs;
3440  for (int i=0; i<numVecs; i++) {
3441  vecs.push_back(getRandomQVector(1 << NUM_QUBITS));
3442  coeffs.push_back(getRandomComplex());
3443  }
3444 
3445  // produce unnormalised matrix via random complex sum of random unnormalised vectors
3446  refMatr = getZeroMatrix(1 << NUM_QUBITS);
3447  for (int i=0; i<numVecs; i++)
3448  refMatr += coeffs[i] * getPureDensityMatrix(vecs[i]);
3449 
3450  toQureg(quregMatr, refMatr);
3451  applyQFT(quregMatr, qubits, numQubits);
3452 
3453  // compute target matrix via dft of each unnormalised vector
3454  refMatr = getZeroMatrix(1 << NUM_QUBITS);
3455  for (int i=0; i<numVecs; i++) {
3456  QVector dft = getDFT(vecs[i], qubits, numQubits);
3457  refMatr += coeffs[i] * getPureDensityMatrix(dft);
3458  }
3459 
3460  REQUIRE( areEqual(quregMatr, refMatr) );
3461  }
3462  }
3463  }
3464  SECTION( "input validation" ) {
3465 
3466  SECTION( "number of targets" ) {
3467 
3468  // there cannot be more targets than qubits in register
3469  int numQubits = GENERATE( -1, 0, NUM_QUBITS+1 );
3470  int qubits[NUM_QUBITS+1];
3471 
3472  REQUIRE_THROWS_WITH( applyQFT(quregVec, qubits, numQubits), Contains("Invalid number of target"));
3473  }
3474  SECTION( "repetition in targets" ) {
3475 
3476  int numQubits = 3;
3477  int qubits[] = {1,2,2};
3478 
3479  REQUIRE_THROWS_WITH( applyQFT(quregVec, qubits, numQubits), Contains("target") && Contains("unique"));
3480  }
3481  SECTION( "qubit indices" ) {
3482 
3483  int numQubits = 3;
3484  int qubits[] = {1,2,3};
3485 
3486  int inv = GENERATE( -1, NUM_QUBITS );
3487  qubits[GENERATE_COPY( range(0,numQubits) )] = inv; // make invalid target
3488  REQUIRE_THROWS_WITH( applyQFT(quregVec, qubits, numQubits), Contains("Invalid target") );
3489  }
3490  }
3491  CLEANUP_TEST( quregVec, quregMatr );
3492 }

References applyQFT(), areEqual(), CLEANUP_TEST, getDFT(), getMixedDensityMatrix(), getPureDensityMatrix(), getRandomComplex(), getRandomOrthonormalVectors(), getRandomProbabilities(), getRandomQVector(), getRandomStateVector(), getZeroMatrix(), NUM_QUBITS, PREPARE_TEST, sublists(), and toQureg().

◆ TEST_CASE() [19/124]

TEST_CASE ( "applyTrotterCircuit"  ,
""  [operators] 
)
See also
applyTrotterCircuit
Author
Tyson Jones

Definition at line 3500 of file test_operators.cpp.

3500  {
3501 
3504  initDebugState(vec);
3505  initDebugState(mat);
3506 
3507  Qureg vecRef = createCloneQureg(vec, QUEST_ENV);
3508  Qureg matRef = createCloneQureg(mat, QUEST_ENV);
3509 
3510  SECTION( "correctness" ) {
3511 
3512  SECTION( "one term" ) {
3513 
3514  // a Hamiltonian with one term has an exact (trivial) Trotterisation
3516 
3517  // H = coeff X Y Z (on qubits 0,1,2)
3518  qreal coeff = getRandomReal(-5, 5);
3519  int numTargs = 3;
3520  int targs[] = {0, 1, 2};
3521  pauliOpType codes[] = {PAULI_X, PAULI_Y, PAULI_Z};
3522  hamil.termCoeffs[0] = coeff;
3523  for (int i=0; i<numTargs; i++)
3524  hamil.pauliCodes[targs[i]] = codes[i];
3525 
3526  // time can be negative
3527  qreal time = getRandomReal(-2,2);
3528 
3529  // by commutation, all reps & orders yield the same total unitary
3530  int reps = GENERATE( range(1,5) );
3531 
3532  // applyTrotter(t, 1, 1) = exp(-i t coeff paulis)
3533  // multiRotatePauli(a) = exp(- i a / 2 paulis)
3534 
3535  SECTION( "state-vector" ) {
3536 
3537  int order = GENERATE( 1, 2, 4 );
3538 
3539  applyTrotterCircuit(vec, hamil, time, order, reps);
3540  multiRotatePauli(vecRef, targs, codes, numTargs, 2*time*coeff);
3541  REQUIRE( areEqual(vec, vecRef, 10*REAL_EPS) );
3542  }
3543  SECTION( "density-matrix" ) {
3544 
3545  int order = GENERATE( 1, 2 ); // precision bites density-matrices quickly
3546 
3547  applyTrotterCircuit(mat, hamil, time, order, reps);
3548  multiRotatePauli(matRef, targs, codes, numTargs, 2*time*coeff);
3549  REQUIRE( areEqual(mat, matRef, 1E2*REAL_EPS) );
3550  }
3551 
3552  destroyPauliHamil(hamil);
3553  }
3554  SECTION( "commuting terms" ) {
3555 
3556  // a Hamiltonian of commuting terms, Trotterises exactly
3558 
3559  // H = c0 X Y I + c1 X I Z (on qubits 0,1,2)
3560  int targs[] = {0, 1, 2};
3561  hamil.pauliCodes[0] = PAULI_X;
3562  hamil.pauliCodes[0 + NUM_QUBITS] = PAULI_X;
3563  hamil.pauliCodes[1] = PAULI_Y;
3564  hamil.pauliCodes[1 + NUM_QUBITS] = PAULI_I;
3565  hamil.pauliCodes[2] = PAULI_I;
3566  hamil.pauliCodes[2 + NUM_QUBITS] = PAULI_Z;
3567  for (int i=0; i<hamil.numSumTerms; i++)
3568  hamil.termCoeffs[i] = getRandomReal(-5,5);
3569 
3570  // time can be negative
3571  qreal time = getRandomReal(-2,2);
3572 
3573  // applyTrotter(t, 1, 1) = exp(-i t c0 paulis0) exp(-i t c1 paulis1)
3574  // multiRotatePauli(a) = exp(- i a / 2 paulis)
3575 
3576  SECTION( "state-vector" ) {
3577 
3578  int reps = GENERATE( range(1,5) );
3579  int order = GENERATE( 1, 2, 4 );
3580 
3581  applyTrotterCircuit(vec, hamil, time, order, reps);
3582  multiRotatePauli(vecRef, targs, hamil.pauliCodes, 3, 2*time*hamil.termCoeffs[0]);
3583  multiRotatePauli(vecRef, targs, &(hamil.pauliCodes[NUM_QUBITS]), 3, 2*time*hamil.termCoeffs[1]);
3584  REQUIRE( areEqual(vec, vecRef, 10*REAL_EPS) );
3585  }
3586  SECTION( "density-matrix" ) {
3587 
3588  int reps = GENERATE( range(1,5) );
3589  int order = GENERATE( 1, 2 ); // precision hurts density matrices quickly
3590 
3591  applyTrotterCircuit(mat, hamil, time, order, reps);
3592  multiRotatePauli(matRef, targs, hamil.pauliCodes, 3, 2*time*hamil.termCoeffs[0]);
3593  multiRotatePauli(matRef, targs, &(hamil.pauliCodes[NUM_QUBITS]), 3, 2*time*hamil.termCoeffs[1]);
3594  REQUIRE( areEqual(mat, matRef, 1E2*REAL_EPS) );
3595  }
3596 
3597  destroyPauliHamil(hamil);
3598  }
3599  SECTION( "general" ) {
3600 
3601  /* We'll consider an analytic time-evolved state, so that we can avoid
3602  * comparing applyTrotterCircuit to other numerical approximations.
3603  * We can construct such a state, by using a Hamiltonian with known
3604  * analytic eigenvalues, and hence a known period. Time evolution of the
3605  * period will just yield the input state.
3606  *
3607  * E.g. H = pi sqrt(2) X Y Z X Y + pi Y Z X Y Z + pi Z X Y Z X
3608  * has (degenerate) eigenvalues +- 2 pi, so the period
3609  * of the Hamiltonian is t=1.
3610  */
3611 
3612  // hardcoded 5 qubits here in the Pauli codes
3613  REQUIRE( NUM_QUBITS == 5 );
3614 
3616  qreal coeffs[] = {(qreal) (M_PI * sqrt(2.0)), M_PI, M_PI};
3617  enum pauliOpType codes[] = {
3621  initPauliHamil(hamil, coeffs, codes);
3622 
3623  // evolving to t=1 should leave the input state unchanged
3624  qreal time = 1;
3625 
3626  // since unnormalised (initDebugState), max fid is 728359.8336
3627  qreal fidNorm = 728359.8336;
3628 
3629  SECTION( "absolute" ) {
3630 
3631  // such a high order and reps should yield precise solution
3632  int order = 4;
3633  int reps = 20;
3634  applyTrotterCircuit(vec, hamil, time, 4, 20);
3635  qreal fid = calcFidelity(vec, vecRef) / fidNorm;
3636 
3637  REQUIRE( fid == Approx(1).epsilon(1E-8) );
3638  }
3639  SECTION( "repetitions scaling" ) {
3640 
3641  // exclude order 1; too few reps for monotonic increase of accuracy
3642  int order = GENERATE( 2, 4, 6 );
3643 
3644  // accuracy should increase with increasing repetitions
3645  int reps[] = {1, 5, 10};
3646 
3647  qreal prevFid = 0;
3648  for (int i=0; i<3; i++) {
3649  initDebugState(vec);
3650  applyTrotterCircuit(vec, hamil, time, order, reps[i]);
3651  qreal fid = calcFidelity(vec, vecRef) / fidNorm;
3652 
3653  REQUIRE( fid >= prevFid );
3654  prevFid = fid;
3655  }
3656  }
3657  SECTION( "order scaling" ) {
3658 
3659  // exclude order 1; too few reps for monotonic increase of accuracy
3660  int reps = GENERATE( 5, 10 );
3661 
3662  // accuracy should increase with increasing repetitions
3663  int orders[] = {1, 2, 4, 6};
3664 
3665  qreal prevFid = 0;
3666  for (int i=0; i<4; i++) {
3667  initDebugState(vec);
3668  applyTrotterCircuit(vec, hamil, time, orders[i], reps);
3669  qreal fid = calcFidelity(vec, vecRef) / fidNorm;
3670 
3671  REQUIRE( fid >= prevFid );
3672  prevFid = fid;
3673  }
3674  }
3675 
3676  destroyPauliHamil(hamil);
3677  }
3678  }
3679  SECTION( "input validation" ) {
3680 
3681  SECTION( "repetitions" ) {
3682 
3684  int reps = GENERATE( -1, 0 );
3685 
3686  REQUIRE_THROWS_WITH( applyTrotterCircuit(vec, hamil, 1, 1, reps), Contains("repetitions must be >=1") );
3687 
3688  destroyPauliHamil(hamil);
3689  }
3690  SECTION( "order" ) {
3691 
3693  int order = GENERATE( -1, 0, 3, 5, 7 );
3694 
3695  REQUIRE_THROWS_WITH( applyTrotterCircuit(vec, hamil, 1, order, 1), Contains("order must be 1, or an even number") );
3696 
3697  destroyPauliHamil(hamil);
3698  }
3699  SECTION( "pauli codes" ) {
3700 
3701  int numTerms = 3;
3702  PauliHamil hamil = createPauliHamil(NUM_QUBITS, numTerms);
3703 
3704  // make one pauli code wrong
3705  hamil.pauliCodes[GENERATE_COPY( range(0,numTerms*NUM_QUBITS) )] = (pauliOpType) GENERATE( -1, 4 );
3706  REQUIRE_THROWS_WITH( applyTrotterCircuit(vec, hamil, 1, 1, 1), Contains("Invalid Pauli code") );
3707 
3708  destroyPauliHamil(hamil);
3709  }
3710  SECTION( "matching hamiltonian qubits" ) {
3711 
3712  PauliHamil hamil = createPauliHamil(NUM_QUBITS + 1, 1);
3713 
3714  REQUIRE_THROWS_WITH( applyTrotterCircuit(vec, hamil, 1, 1, 1), Contains("same number of qubits") );
3715  REQUIRE_THROWS_WITH( applyTrotterCircuit(mat, hamil, 1, 1, 1), Contains("same number of qubits") );
3716 
3717  destroyPauliHamil(hamil);
3718  }
3719  }
3720 
3721  destroyQureg(vec, QUEST_ENV);
3722  destroyQureg(mat, QUEST_ENV);
3723  destroyQureg(vecRef, QUEST_ENV);
3724  destroyQureg(matRef, QUEST_ENV);
3725 }

References applyTrotterCircuit(), areEqual(), calcFidelity(), createCloneQureg(), createDensityQureg(), createPauliHamil(), createQureg(), destroyPauliHamil(), destroyQureg(), getRandomReal(), initDebugState(), initPauliHamil(), M_PI, multiRotatePauli(), NUM_QUBITS, PauliHamil::numSumTerms, PAULI_I, PAULI_X, PAULI_Y, PAULI_Z, PauliHamil::pauliCodes, qreal, QUEST_ENV, and PauliHamil::termCoeffs.

◆ TEST_CASE() [20/124]

TEST_CASE ( "calcDensityInnerProduct"  ,
""  [calculations] 
)
See also
calcDensityInnerProduct
Author
Tyson Jones

Definition at line 21 of file test_calculations.cpp.

21  {
22 
25 
26  SECTION( "correctness" ) {
27 
28  // repeat these random tests 10 times
29  GENERATE( range(0,10) );
30 
31  SECTION( "density-matrix" ) {
32 
33  SECTION( "pure" ) {
34 
35  // mat1 = |r1><r1|
37  toQureg(mat1, getKetBra(r1,r1));
38 
39  // mat2 = |r2><r2|
41  toQureg(mat2, getKetBra(r2,r2));
42 
43  // prod( |r1><r1|, |r2><r2| ) = |<r1|r2>|^2
44  qcomp prod = 0;
45  for (size_t i=0; i<r1.size(); i++)
46  prod += conj(r1[i]) * r2[i];
47  qreal densProd = pow(abs(prod),2);
48 
49  REQUIRE( calcDensityInnerProduct(mat1,mat2) == Approx(densProd) );
50  }
51  SECTION( "mixed" ) {
52 
55  toQureg(mat1, ref1);
56  toQureg(mat2, ref2);
57 
58  // prod(mat1, mat2) = sum_{ij} conj(mat1_{ij}) * mat2_{ij}
59  qcomp refProd = 0;
60  for (size_t i=0; i<ref1.size(); i++)
61  for (size_t j=0; j<ref1.size(); j++)
62  refProd += conj(ref1[i][j]) * ref2[i][j];
63  REQUIRE( imag(refProd) == Approx(0).margin(REAL_EPS) );
64 
65  REQUIRE( calcDensityInnerProduct(mat1,mat2) == Approx(real(refProd)) );
66 
67  // should be invariant under ordering
68  REQUIRE( calcDensityInnerProduct(mat1,mat2) == Approx(calcDensityInnerProduct(mat2,mat1)) );
69  }
70  SECTION( "unnormalised" ) {
71 
72  // set both to random (non-Hermitian) complex matrices
75  toQureg(mat1, ref1);
76  toQureg(mat2, ref2);
77 
78  // prod(mat1, mat2) = real(sum_{ij} conj(mat1_{ij}) * mat2_{ij})
79  qcomp refProd = 0;
80  for (size_t i=0; i<ref1.size(); i++)
81  for (size_t j=0; j<ref1.size(); j++)
82  refProd += conj(ref1[i][j]) * ref2[i][j];
83 
84  REQUIRE( calcDensityInnerProduct(mat1,mat2) == Approx(real(refProd)) );
85  }
86  }
87  }
88  SECTION( "input validation" ) {
89 
90  SECTION( "dimensions" ) {
91 
93  REQUIRE_THROWS_WITH( calcDensityInnerProduct(mat1,mat3), Contains("Dimensions") && Contains("don't match") );
94  destroyQureg(mat3, QUEST_ENV);
95  }
96  SECTION( "state-vectors" ) {
97 
99 
100  REQUIRE_THROWS_WITH( calcDensityInnerProduct(mat1,vec), Contains("valid only for density matrices") );
101  REQUIRE_THROWS_WITH( calcDensityInnerProduct(vec,mat1), Contains("valid only for density matrices") );
102  REQUIRE_THROWS_WITH( calcDensityInnerProduct(vec,vec), Contains("valid only for density matrices") );
103 
104  destroyQureg(vec, QUEST_ENV);
105  }
106  }
107  destroyQureg(mat1, QUEST_ENV);
108  destroyQureg(mat2, QUEST_ENV);
109 }

References calcDensityInnerProduct(), createDensityQureg(), createQureg(), destroyQureg(), getKetBra(), getRandomDensityMatrix(), getRandomQMatrix(), getRandomStateVector(), NUM_QUBITS, qcomp, qreal, QUEST_ENV, and toQureg().

◆ TEST_CASE() [21/124]

TEST_CASE ( "calcExpecDiagonalOp"  ,
""  [calculations] 
)
See also
calcExpecDiagonalOp
Author
Tyson Jones

Definition at line 117 of file test_calculations.cpp.

117  {
118 
121  initDebugState(vec);
122  initDebugState(mat);
123  QVector vecRef = toQVector(vec);
124  QMatrix matRef = toQMatrix(mat);
125 
126  SECTION( "correctness" ) {
127 
128  // try 10 random operators
129  GENERATE( range(0,10) );
130 
131  // make a totally random (non-Hermitian) diagonal oeprator
133  for (long long int i=0; i<op.numElemsPerChunk; i++) {
134  op.real[i] = getRandomReal(-5, 5);
135  op.imag[i] = getRandomReal(-5, 5);
136  }
137  syncDiagonalOp(op);
138 
139  SECTION( "state-vector" ) {
140 
141  /* calcExpecDiagOp calculates <qureg|diag|qureg> */
142 
143  QVector sumRef = toQMatrix(op) * vecRef;
144  qcomp prod = 0;
145  for (size_t i=0; i<vecRef.size(); i++)
146  prod += conj(vecRef[i]) * sumRef[i];
147 
148  Complex res = calcExpecDiagonalOp(vec, op);
149  REQUIRE( res.real == Approx(real(prod)).margin(REAL_EPS) );
150  REQUIRE( res.imag == Approx(imag(prod)).margin(REAL_EPS) );
151  }
152  SECTION( "density-matrix" ) {
153 
154  /* calcExpecDiagOp calculates Trace( diag * qureg ) */
155  matRef = toQMatrix(op) * matRef;
156  qcomp tr = 0;
157  for (size_t i=0; i<matRef.size(); i++)
158  tr += matRef[i][i];
159 
160  Complex res = calcExpecDiagonalOp(mat, op);
161  REQUIRE( res.real == Approx(real(tr)).margin(100*REAL_EPS) );
162  REQUIRE( res.imag == Approx(imag(tr)).margin(100*REAL_EPS) );
163  }
164 
166  }
167  SECTION( "input validation" ) {
168 
169  SECTION( "mismatching size" ) {
170 
172 
173  REQUIRE_THROWS_WITH( calcExpecDiagonalOp(vec, op), Contains("equal number of qubits"));
174  REQUIRE_THROWS_WITH( calcExpecDiagonalOp(mat, op), Contains("equal number of qubits"));
175 
177  }
178  }
179  destroyQureg(vec, QUEST_ENV);
180  destroyQureg(mat, QUEST_ENV);
181 }

References calcExpecDiagonalOp(), createDensityQureg(), createDiagonalOp(), createQureg(), destroyDiagonalOp(), destroyQureg(), getRandomReal(), Complex::imag, DiagonalOp::imag, initDebugState(), NUM_QUBITS, DiagonalOp::numElemsPerChunk, qcomp, QUEST_ENV, Complex::real, DiagonalOp::real, syncDiagonalOp(), toQMatrix(), and toQVector().

◆ TEST_CASE() [22/124]

TEST_CASE ( "calcExpecPauliHamil"  ,
""  [calculations] 
)
See also
calcExpecPauliHamil
Author
Tyson Jones

Definition at line 189 of file test_calculations.cpp.

189  {
190 
193  initDebugState(vec);
194  initDebugState(mat);
195  QVector vecRef = toQVector(vec);
196  QMatrix matRef = toQMatrix(mat);
197 
200 
201  SECTION( "correctness" ) {
202 
203  /* it's too expensive to try every possible Pauli configuration, so
204  * we'll try 10 random codes, and for each, random coefficients
205  */
206  GENERATE( range(0,10) );
207 
208  int numTerms = GENERATE( 1, 2, 10, 15 );
209  PauliHamil hamil = createPauliHamil(NUM_QUBITS, numTerms);
210  setRandomPauliSum(hamil);
211  QMatrix refHamil = toQMatrix(hamil);
212 
213  SECTION( "state-vector" ) {
214 
215  /* calcExpecPauliHamil calculates <qureg|pauliHum|qureg> */
216 
217  QVector sumRef = refHamil * vecRef;
218  qcomp prod = 0;
219  for (size_t i=0; i<vecRef.size(); i++)
220  prod += conj(vecRef[i]) * sumRef[i];
221  REQUIRE( imag(prod) == Approx(0).margin(10*REAL_EPS) );
222 
223  qreal res = calcExpecPauliHamil(vec, hamil, vecWork);
224  REQUIRE( res == Approx(real(prod)).margin(10*REAL_EPS) );
225  }
226  SECTION( "density-matrix" ) {
227 
228  /* calcExpecPauliHamil calculates Trace( pauliHamil * qureg ) */
229  matRef = refHamil * matRef;
230  qreal tr = 0;
231  for (size_t i=0; i<matRef.size(); i++)
232  tr += real(matRef[i][i]);
233  // (get real, since we start in a non-Hermitian state, hence diagonal isn't real)
234 
235  qreal res = calcExpecPauliHamil(mat, hamil, matWork);
236  REQUIRE( res == Approx(tr).margin(1E2*REAL_EPS) );
237  }
238 
239  destroyPauliHamil(hamil);
240  }
241  SECTION( "input validation" ) {
242 
243  SECTION( "pauli codes" ) {
244 
245  int numTerms = 3;
246  PauliHamil hamil = createPauliHamil(NUM_QUBITS, numTerms);
247 
248  // make one pauli code wrong
249  hamil.pauliCodes[GENERATE_COPY( range(0,numTerms*NUM_QUBITS) )] = (pauliOpType) GENERATE( -1, 4 );
250  REQUIRE_THROWS_WITH( calcExpecPauliHamil(vec, hamil, vecWork), Contains("Invalid Pauli code") );
251 
252  destroyPauliHamil(hamil);
253  }
254  SECTION( "workspace type" ) {
255 
256  int numTerms = 1;
257  PauliHamil hamil = createPauliHamil(NUM_QUBITS, numTerms);
258 
259  REQUIRE_THROWS_WITH( calcExpecPauliHamil(vec, hamil, mat), Contains("Registers must both be state-vectors or both be density matrices") );
260  REQUIRE_THROWS_WITH( calcExpecPauliHamil(mat, hamil, vec), Contains("Registers must both be state-vectors or both be density matrices") );
261 
262  destroyPauliHamil(hamil);
263  }
264  SECTION( "workspace dimensions" ) {
265 
266  int numTerms = 1;
267  PauliHamil hamil = createPauliHamil(NUM_QUBITS, numTerms);
268 
269  Qureg vec2 = createQureg(NUM_QUBITS + 1, QUEST_ENV);
270  REQUIRE_THROWS_WITH( calcExpecPauliHamil(vec, hamil, vec2), Contains("Dimensions") && Contains("don't match") );
271  destroyQureg(vec2, QUEST_ENV);
272 
274  REQUIRE_THROWS_WITH( calcExpecPauliHamil(mat, hamil, mat2), Contains("Dimensions") && Contains("don't match") );
275  destroyQureg(mat2, QUEST_ENV);
276 
277  destroyPauliHamil(hamil);
278  }
279  SECTION( "matching hamiltonian qubits" ) {
280 
281  int numTerms = 1;
282  PauliHamil hamil = createPauliHamil(NUM_QUBITS + 1, numTerms);
283 
284  REQUIRE_THROWS_WITH( calcExpecPauliHamil(vec, hamil, vecWork), Contains("same number of qubits") );
285  REQUIRE_THROWS_WITH( calcExpecPauliHamil(mat, hamil, matWork), Contains("same number of qubits") );
286 
287  destroyPauliHamil(hamil);
288  }
289  }
290  destroyQureg(vec, QUEST_ENV);
291  destroyQureg(mat, QUEST_ENV);
292  destroyQureg(vecWork, QUEST_ENV);
293  destroyQureg(matWork, QUEST_ENV);
294 }

References calcExpecPauliHamil(), createDensityQureg(), createPauliHamil(), createQureg(), destroyPauliHamil(), destroyQureg(), initDebugState(), NUM_QUBITS, PauliHamil::pauliCodes, qcomp, qreal, QUEST_ENV, setRandomPauliSum(), toQMatrix(), and toQVector().

◆ TEST_CASE() [23/124]

TEST_CASE ( "calcExpecPauliProd"  ,
""  [calculations] 
)
See also
calcExpecPauliProd
Author
Tyson Jones

Definition at line 302 of file test_calculations.cpp.

302  {
303 
306  initDebugState(vec);
307  initDebugState(mat);
308  QVector vecRef = toQVector(vec);
309  QMatrix matRef = toQMatrix(mat);
310 
313 
314  SECTION( "correctness" ) {
315 
316  int numTargs = GENERATE( range(1,NUM_QUBITS+1) );
317  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
318 
319  /* it's too expensive to try ALL Pauli sequences, via
320  * pauliOpType* paulis = GENERATE_COPY( pauliseqs(numTargs) );.
321  * Furthermore, take(10, pauliseqs(numTargs)) will try the same pauli codes.
322  * Hence, we instead opt to repeatedlyrandomly generate pauliseqs
323  */
324  GENERATE( range(0,10) ); // gen 10 random pauli-codes for every targs
325  pauliOpType paulis[numTargs];
326  for (int i=0; i<numTargs; i++)
327  paulis[i] = (pauliOpType) getRandomInt(0,4);
328 
329  // produce a numTargs-big matrix 'pauliProd' by pauli-matrix tensoring
330  QMatrix iMatr{{1,0},{0,1}};
331  QMatrix xMatr{{0,1},{1,0}};
332  QMatrix yMatr{{0,-qcomp(0,1)},{qcomp(0,1),0}};
333  QMatrix zMatr{{1,0},{0,-1}};
334  QMatrix pauliProd{{1}};
335  for (int i=0; i<numTargs; i++) {
336  QMatrix fac;
337  if (paulis[i] == PAULI_I) fac = iMatr;
338  if (paulis[i] == PAULI_X) fac = xMatr;
339  if (paulis[i] == PAULI_Y) fac = yMatr;
340  if (paulis[i] == PAULI_Z) fac = zMatr;
341  pauliProd = getKroneckerProduct(fac, pauliProd);
342  }
343 
344  SECTION( "state-vector" ) {
345 
346  /* calcExpecPauliProd calculates <qureg|pauliProd|qureg> */
347 
348  QVector prodRef = vecRef;
349  applyReferenceOp(prodRef, targs, numTargs, pauliProd);
350  qcomp prod = 0;
351  for (size_t i=0; i<vecRef.size(); i++)
352  prod += conj(vecRef[i]) * prodRef[i];
353  REQUIRE( imag(prod) == Approx(0).margin(REAL_EPS) );
354 
355  qreal res = calcExpecPauliProd(vec, targs, paulis, numTargs, vecWork);
356  REQUIRE( res == Approx(real(prod)).margin(REAL_EPS) );
357  }
358  SECTION( "density-matrix" ) {
359 
360  /* calcExpecPauliProd calculates Trace( pauliProd * qureg ) */
361 
362  // produce (pauliProd * mat)
363  QMatrix fullOp = getFullOperatorMatrix(NULL, 0, targs, numTargs, pauliProd, NUM_QUBITS);
364  matRef = fullOp * matRef;
365 
366  // compute real(trace(pauliProd * mat))
367  qreal tr = 0;
368  for (size_t i=0; i<matRef.size(); i++)
369  tr += real(matRef[i][i]);
370  // (get real, since we start in a non-Hermitian state, hence diagonal isn't real)
371 
372  qreal res = calcExpecPauliProd(mat, targs, paulis, numTargs, matWork);
373  REQUIRE( res == Approx(tr).margin(10*REAL_EPS) );
374  }
375  }
376  SECTION( "input validation" ) {
377 
378  SECTION( "number of targets" ) {
379 
380  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
381  REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, NULL, NULL, numTargs, vecWork), Contains("Invalid number of target") );
382  }
383  SECTION( "target indices" ) {
384 
385  int numTargs = 3;
386  int targs[3] = {0, 1, 2};
387 
388  // make one index wrong
389  targs[GENERATE( range(0,3) )] = GENERATE( -1, NUM_QUBITS );
390  REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, NULL, numTargs, vecWork), Contains("Invalid target qubit") );
391  }
392  SECTION( "repetition in targets" ) {
393 
394  int numTargs = 3;
395  int targs[3] = {0, 1, 1};
396  REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, NULL, numTargs, vecWork), Contains("target qubits must be unique") );
397  }
398  SECTION( "pauli codes" ) {
399 
400  int numTargs = 3;
401  int targs[3] = {0, 1, 2};
402  pauliOpType codes[3] = {PAULI_X, PAULI_Y, PAULI_Z};
403 
404  // make one pauli wrong
405  codes[GENERATE( range(0,3) )] = (pauliOpType) GENERATE( -1, 4 );
406  REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, codes, numTargs, vecWork), Contains("Invalid Pauli code") );
407  }
408  SECTION( "workspace type" ) {
409 
410  int numTargs = 1;
411  int targs[1] = {0};
412  pauliOpType codes[1] = {PAULI_I};
413 
414  REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, codes, numTargs, matWork), Contains("Registers must both be state-vectors or both be density matrices") );
415  REQUIRE_THROWS_WITH( calcExpecPauliProd(mat, targs, codes, numTargs, vecWork), Contains("Registers must both be state-vectors or both be density matrices") );
416  }
417  SECTION( "workspace dimensions" ) {
418 
419  int numTargs = 1;
420  int targs[1] = {0};
421  pauliOpType codes[1] = {PAULI_I};
422 
423  Qureg vec2 = createQureg(NUM_QUBITS + 1, QUEST_ENV);
424  REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, codes, numTargs, vec2), Contains("Dimensions") && Contains("don't match") );
425  destroyQureg(vec2, QUEST_ENV);
426 
428  REQUIRE_THROWS_WITH( calcExpecPauliProd(mat, targs, codes, numTargs, mat2), Contains("Dimensions") && Contains("don't match") );
429  destroyQureg(mat2, QUEST_ENV);
430  }
431  }
432  destroyQureg(vec, QUEST_ENV);
433  destroyQureg(mat, QUEST_ENV);
434  destroyQureg(vecWork, QUEST_ENV);
435  destroyQureg(matWork, QUEST_ENV);
436 }

References applyReferenceOp(), calcExpecPauliProd(), createDensityQureg(), createQureg(), destroyQureg(), getFullOperatorMatrix(), getKroneckerProduct(), getRandomInt(), initDebugState(), NUM_QUBITS, PAULI_I, PAULI_X, PAULI_Y, PAULI_Z, qcomp, qreal, QUEST_ENV, sublists(), toQMatrix(), and toQVector().

◆ TEST_CASE() [24/124]

TEST_CASE ( "calcExpecPauliSum"  ,
""  [calculations] 
)
See also
calcExpecPauliSum
Author
Tyson Jones

Definition at line 444 of file test_calculations.cpp.

444  {
445 
448  initDebugState(vec);
449  initDebugState(mat);
450  QVector vecRef = toQVector(vec);
451  QMatrix matRef = toQMatrix(mat);
452 
455 
456  SECTION( "correctness" ) {
457 
458  int numSumTerms = GENERATE( 1, 2, 10, 15 );
459 
460  /* it's too expensive to try every possible Pauli configuration, so
461  * we'll try 10 random codes, and for each, random coefficients
462  */
463  GENERATE( range(0,10) );
464  int totNumCodes = numSumTerms*NUM_QUBITS;
465  pauliOpType paulis[totNumCodes];
466  qreal coeffs[numSumTerms];
467  setRandomPauliSum(coeffs, paulis, NUM_QUBITS, numSumTerms);
468 
469  // produce a numTargs-big matrix 'pauliSum' by pauli-matrix tensoring and summing
470  QMatrix pauliSum = toQMatrix(coeffs, paulis, NUM_QUBITS, numSumTerms);
471 
472  SECTION( "state-vector" ) {
473 
474  /* calcExpecPauliSum calculates <qureg|pauliSum|qureg> */
475 
476  QVector sumRef = pauliSum * vecRef;
477  qcomp prod = 0;
478  for (size_t i=0; i<vecRef.size(); i++)
479  prod += conj(vecRef[i]) * sumRef[i];
480  REQUIRE( imag(prod) == Approx(0).margin(10*REAL_EPS) );
481 
482  qreal res = calcExpecPauliSum(vec, paulis, coeffs, numSumTerms, vecWork);
483  REQUIRE( res == Approx(real(prod)).margin(10*REAL_EPS) );
484  }
485  SECTION( "density-matrix" ) {
486 
487  /* calcExpecPauliSum calculates Trace( pauliSum * qureg ) */
488  matRef = pauliSum * matRef;
489  qreal tr = 0;
490  for (size_t i=0; i<matRef.size(); i++)
491  tr += real(matRef[i][i]);
492  // (get real, since we start in a non-Hermitian state, hence diagonal isn't real)
493 
494  qreal res = calcExpecPauliSum(mat, paulis, coeffs, numSumTerms, matWork);
495  REQUIRE( res == Approx(tr).margin(1E2*REAL_EPS) );
496  }
497  }
498  SECTION( "input validation" ) {
499 
500  SECTION( "number of sum terms" ) {
501 
502  int numSumTerms = GENERATE( -1, 0 );
503  REQUIRE_THROWS_WITH( calcExpecPauliSum(vec, NULL, NULL, numSumTerms, vecWork), Contains("Invalid number of terms in the Pauli sum") );
504  }
505  SECTION( "pauli codes" ) {
506 
507  // make valid params
508  int numSumTerms = 3;
509  qreal coeffs[numSumTerms];
510  pauliOpType codes[numSumTerms*NUM_QUBITS];
511  for (int i=0; i<numSumTerms*NUM_QUBITS; i++)
512  codes[i] = PAULI_I;
513 
514  // make one pauli wrong
515  codes[GENERATE_COPY( range(0,numSumTerms*NUM_QUBITS) )] = (pauliOpType) GENERATE( -1, 4 );
516  REQUIRE_THROWS_WITH( calcExpecPauliSum(vec, codes, coeffs, numSumTerms, vecWork), Contains("Invalid Pauli code") );
517  }
518  SECTION( "workspace type" ) {
519 
520  // make valid params
521  int numSumTerms = 1;
522  qreal coeffs[1] = {0};
523  pauliOpType codes[NUM_QUBITS];
524  for (int i=0; i<NUM_QUBITS; i++)
525  codes[i] = PAULI_I;
526 
527  REQUIRE_THROWS_WITH( calcExpecPauliSum(vec, codes, coeffs, numSumTerms, mat), Contains("Registers must both be state-vectors or both be density matrices") );
528  REQUIRE_THROWS_WITH( calcExpecPauliSum(mat, codes, coeffs, numSumTerms, vec), Contains("Registers must both be state-vectors or both be density matrices") );
529  }
530  SECTION( "workspace dimensions" ) {
531 
532  // make valid params
533  int numSumTerms = 1;
534  qreal coeffs[1] = {0};
535  pauliOpType codes[NUM_QUBITS];
536  for (int i=0; i<NUM_QUBITS; i++)
537  codes[i] = PAULI_I;
538 
539  Qureg vec2 = createQureg(NUM_QUBITS + 1, QUEST_ENV);
540  REQUIRE_THROWS_WITH( calcExpecPauliSum(vec, codes, coeffs, numSumTerms, vec2), Contains("Dimensions") && Contains("don't match") );
541  destroyQureg(vec2, QUEST_ENV);
542 
544  REQUIRE_THROWS_WITH( calcExpecPauliSum(mat, codes, coeffs, numSumTerms, mat2), Contains("Dimensions") && Contains("don't match") );
545  destroyQureg(mat2, QUEST_ENV);
546  }
547  }
548  destroyQureg(vec, QUEST_ENV);
549  destroyQureg(mat, QUEST_ENV);
550  destroyQureg(vecWork, QUEST_ENV);
551  destroyQureg(matWork, QUEST_ENV);
552 }

References calcExpecPauliSum(), createDensityQureg(), createQureg(), destroyQureg(), initDebugState(), NUM_QUBITS, PAULI_I, qcomp, qreal, QUEST_ENV, setRandomPauliSum(), toQMatrix(), and toQVector().

◆ TEST_CASE() [25/124]

TEST_CASE ( "calcFidelity"  ,
""  [calculations] 
)
See also
calcFidelity
Author
Tyson Jones

Definition at line 560 of file test_calculations.cpp.

560  {
561 
565 
566  SECTION( "correctness" ) {
567 
568  // repeat the below random tests 10 times
569  GENERATE( range(0,10) );
570 
571  SECTION( "state-vector" ) {
572 
573  /* calcFidelity computes |<vec|pure>|^2 */
574 
575  SECTION( "normalised" ) {
576 
577  // random L2 vectors
580  toQureg(vec, vecRef);
581  toQureg(pure, pureRef);
582 
583  // |<vec|vec>|^2 = |1|^2 = 1
584  REQUIRE( calcFidelity(vec,vec) == Approx(1) );
585 
586  // |<vec|pure>|^2 = |sum_j conj(vec_j) * pure_j|^2
587  qcomp dotProd = 0;
588  for (size_t i=0; i<vecRef.size(); i++)
589  dotProd += conj(vecRef[i]) * pureRef[i];
590  qreal refFid = pow(abs(dotProd), 2);
591 
592  REQUIRE( calcFidelity(vec,pure) == Approx(refFid) );
593  }
594  SECTION( "unnormalised" ) {
595 
596  // random unnormalised vectors
597  QVector vecRef = getRandomQVector(1<<NUM_QUBITS);
598  QVector pureRef = getRandomQVector(1<<NUM_QUBITS);
599  toQureg(vec, vecRef);
600  toQureg(pure, pureRef);
601 
602  // Let nv be magnitude of vec, hence |unit-vec> = 1/sqrt(nv)|vec>
603  qreal nv = 0;
604  for (size_t i=0; i<vecRef.size(); i++)
605  nv += pow(abs(vecRef[i]), 2);
606  // then <vec|vec> = sqrt(nv)*sqrt(nv) <unit-vec|unit-vec> = nv,
607  // hence |<vec|vec>|^2 = nv*nv
608  REQUIRE( calcFidelity(vec,vec) == Approx( nv*nv ) );
609 
610  qcomp dotProd = 0;
611  for (size_t i=0; i<vecRef.size(); i++)
612  dotProd += conj(vecRef[i]) * pureRef[i];
613  qreal refFid = pow(abs(dotProd), 2);
614 
615  REQUIRE( calcFidelity(vec,pure) == Approx(refFid) );
616  }
617  }
618  SECTION( "density-matrix" ) {
619 
620  /* calcFidelity computes <pure|mat|pure> */
621 
622  SECTION( "pure" ) {
623 
625  toQureg(pure, pureRef);
626 
627  // test when density matrix is the same pure state
628  QMatrix matRef = getKetBra(pureRef, pureRef);
629  toQureg(mat, matRef);
630  REQUIRE( calcFidelity(mat,pure) == Approx(1) );
631 
632  // test when density matrix is a random pure state
634  matRef = getKetBra(r1, r1); // actually pure |r1><r1|
635  toQureg(mat, matRef);
636 
637  // <pure|r1><r1|pure> = |<r1|pure>|^2 = |sum_j conj(r1_j) * pure_j|^2
638  qcomp dotProd = 0;
639  for (size_t i=0; i<r1.size(); i++)
640  dotProd += conj(r1[i]) * pureRef[i];
641  qreal refFid = pow(abs(dotProd), 2);
642 
643  REQUIRE( calcFidelity(mat,pure) == Approx(refFid) );
644  }
645  SECTION( "mixed" ) {
646 
648  toQureg(pure, pureRef);
649 
650  // test when density matrix is mixed
652  toQureg(mat, matRef);
653 
654  // <pure|mat|pure> = <pure| (Mat|pure>)
655  QVector rhs = matRef * pureRef;
656  qcomp dotProd = 0;
657  for (size_t i=0; i<rhs.size(); i++)
658  dotProd += conj(pureRef[i]) * rhs[i];
659 
660  REQUIRE( imag(dotProd) == Approx(0).margin(REAL_EPS) );
661  REQUIRE( calcFidelity(mat,pure) == Approx(real(dotProd)) );
662  }
663  SECTION( "unnormalised" ) {
664 
665  // test when both density matrix and pure state are unnormalised
666  QVector pureRef = getRandomQVector(1<<NUM_QUBITS);
667  QMatrix matRef = getRandomQMatrix(1<<NUM_QUBITS);
668  toQureg(pure, pureRef);
669  toQureg(mat, matRef);
670 
671  // real[ <pure|mat|pure> ] = real[ <pure| (Mat|pure>) ]
672  QVector rhs = matRef * pureRef;
673  qcomp dotProd = 0;
674  for (size_t i=0; i<rhs.size(); i++)
675  dotProd += conj(pureRef[i]) * rhs[i];
676 
677  REQUIRE( calcFidelity(mat,pure) == Approx(real(dotProd)) );
678  }
679  }
680  }
681  SECTION( "input validation" ) {
682 
683  SECTION( "dimensions" ) {
684 
685  // two state-vectors
687  REQUIRE_THROWS_WITH( calcFidelity(vec2,vec), Contains("Dimensions") && Contains("don't match") );
688  destroyQureg(vec2, QUEST_ENV);
689 
690  // density-matrix and state-vector
692  REQUIRE_THROWS_WITH( calcFidelity(mat2,vec), Contains("Dimensions") && Contains("don't match") );
693  destroyQureg(mat2, QUEST_ENV);
694  }
695  SECTION( "density-matrices" ) {
696 
697  // two mixed statess
698  REQUIRE_THROWS_WITH( calcFidelity(mat,mat), Contains("Second argument must be a state-vector") );
699  }
700  }
701  destroyQureg(vec, QUEST_ENV);
702  destroyQureg(mat, QUEST_ENV);
703  destroyQureg(pure, QUEST_ENV);
704 }

References calcFidelity(), createDensityQureg(), createQureg(), destroyQureg(), getKetBra(), getRandomDensityMatrix(), getRandomQMatrix(), getRandomQVector(), getRandomStateVector(), NUM_QUBITS, Qureg::numQubitsRepresented, qcomp, qreal, QUEST_ENV, and toQureg().

◆ TEST_CASE() [26/124]

TEST_CASE ( "calcHilbertSchmidtDistance"  ,
""  [calculations] 
)
See also
calcHilbertSchmidtDistance
Author
Tyson Jones

Definition at line 712 of file test_calculations.cpp.

712  {
713 
716 
717  SECTION( "correctness" ) {
718 
719  // perform these random tests 10 times
720  GENERATE( range(0,10) );
721 
722  SECTION( "density-matrix" ) {
723 
724  SECTION( "pure" ) {
725 
726  // create random |r1><r1| and |r2><r2| states
728  QMatrix m1 = getKetBra(r1,r1);
729  toQureg(mat1, m1);
731  QMatrix m2 = getKetBra(r2,r2);
732  toQureg(mat2, m2);
733 
734  // Tr{ (a-b)(a-b)^dagger } = sum_{ij} |a_{ij} - b_{ij}|^2
735  qreal tr = 0;
736  for (size_t i=0; i<m1.size(); i++)
737  for (size_t j=0; j<m1.size(); j++)
738  tr += pow(abs(m1[i][j] - m2[i][j]), 2);
739 
740  qreal res = calcHilbertSchmidtDistance(mat1, mat2);
741  REQUIRE( res == Approx(sqrt(tr)) );
742 
743  }
744  SECTION( "normalised" ) {
745 
748  toQureg(mat1, ref1);
749  toQureg(mat2, ref2);
750 
751  // Tr{ (a-b)(a-b)^dagger } = sum_{ij} |a_{ij} - b_{ij}|^2
752  qreal tr = 0;
753  for (size_t i=0; i<ref1.size(); i++)
754  for (size_t j=0; j<ref1.size(); j++)
755  tr += pow(abs(ref1[i][j] - ref2[i][j]), 2);
756 
757  qreal res = calcHilbertSchmidtDistance(mat1, mat2);
758  REQUIRE( res == Approx(sqrt(tr)) );
759  }
760  SECTION( "unnormalised" ) {
761 
762  // mat1 and mat2 are both random matrices
765  toQureg(mat1, ref1);
766  toQureg(mat2, ref2);
767 
768  // Tr{ (a-b)(a-b)^dagger } = sum_{ij} |a_{ij} - b_{ij}|^2
769  qreal tr = 0;
770  for (size_t i=0; i<ref1.size(); i++)
771  for (size_t j=0; j<ref1.size(); j++)
772  tr += pow(abs(ref1[i][j] - ref2[i][j]), 2);
773 
774  qreal res = calcHilbertSchmidtDistance(mat1, mat2);
775  REQUIRE( res == Approx(sqrt(tr)) );
776  }
777  }
778  }
779  SECTION( "input validation") {
780 
781  SECTION( "dimensions" ) {
782 
784  REQUIRE_THROWS_WITH( calcHilbertSchmidtDistance(mat1,mat3), Contains("Dimensions") && Contains("don't match") );
785  destroyQureg(mat3, QUEST_ENV);
786  }
787  SECTION( "state-vector" ) {
788 
790 
791  REQUIRE_THROWS_WITH( calcHilbertSchmidtDistance(vec,mat1), Contains("valid only for density matrices") );
792  REQUIRE_THROWS_WITH( calcHilbertSchmidtDistance(mat1,vec), Contains("valid only for density matrices") );
793  REQUIRE_THROWS_WITH( calcHilbertSchmidtDistance(vec,vec), Contains("valid only for density matrices") );
794 
795  destroyQureg(vec, QUEST_ENV);
796  }
797  }
798  destroyQureg(mat1, QUEST_ENV);
799  destroyQureg(mat2, QUEST_ENV);
800 }

References calcHilbertSchmidtDistance(), createDensityQureg(), createQureg(), destroyQureg(), getKetBra(), getRandomDensityMatrix(), getRandomQMatrix(), getRandomStateVector(), NUM_QUBITS, qreal, QUEST_ENV, and toQureg().

◆ TEST_CASE() [27/124]

TEST_CASE ( "calcInnerProduct"  ,
""  [calculations] 
)
See also
calcInnerProduct
Author
Tyson Jones

Definition at line 808 of file test_calculations.cpp.

808  {
809 
812 
813  SECTION( "correctness" ) {
814 
815  // perform these random tests 10 times
816  GENERATE( range(0,10) );
817 
818  SECTION( "state-vector" ) {
819 
820  SECTION( "normalised" ) {
821 
822  // <r1|r2> = sum_j conj(r1_j) * r2_j
825  qcomp prod = 0;
826  for (size_t i=0; i<r1.size(); i++)
827  prod += conj(r1[i]) * r2[i];
828 
829  toQureg(vec1, r1);
830  toQureg(vec2, r2);
831  Complex res = calcInnerProduct(vec1,vec2);
832 
833  REQUIRE( res.real == Approx(real(prod)) );
834  REQUIRE( res.imag == Approx(imag(prod)) );
835  }
836  SECTION( "unnormalised" ) {
837 
838  // <r1|r2> = sum_j conj(r1_j) * r2_j
841  qcomp prod = 0;
842  for (size_t i=0; i<r1.size(); i++)
843  prod += conj(r1[i]) * r2[i];
844 
845  toQureg(vec1, r1);
846  toQureg(vec2, r2);
847  Complex res = calcInnerProduct(vec1,vec2);
848 
849  REQUIRE( res.real == Approx(real(prod)) );
850  REQUIRE( res.imag == Approx(imag(prod)) );
851  }
852  }
853  }
854  SECTION( "input validation" ) {
855 
856  SECTION( "dimensions" ) {
857 
858  Qureg vec3 = createQureg(NUM_QUBITS + 1, QUEST_ENV);
859  REQUIRE_THROWS_WITH( calcInnerProduct(vec1,vec3), Contains("Dimensions") && Contains("don't match") );
860  destroyQureg(vec3, QUEST_ENV);
861  }
862  SECTION( "density-matrix" ) {
863 
865 
866  REQUIRE_THROWS_WITH( calcInnerProduct(vec1,mat), Contains("valid only for state-vectors") );
867  REQUIRE_THROWS_WITH( calcInnerProduct(mat,vec1), Contains("valid only for state-vectors") );
868  REQUIRE_THROWS_WITH( calcInnerProduct(mat,mat), Contains("valid only for state-vectors") );
869 
870  destroyQureg(mat, QUEST_ENV);
871  }
872  }
873  destroyQureg(vec1, QUEST_ENV);
874  destroyQureg(vec2, QUEST_ENV);
875 }

References calcInnerProduct(), createDensityQureg(), createQureg(), destroyQureg(), getRandomQVector(), getRandomStateVector(), Complex::imag, NUM_QUBITS, qcomp, QUEST_ENV, Complex::real, and toQureg().

◆ TEST_CASE() [28/124]

TEST_CASE ( "calcProbOfAllOutcomes"  ,
""  [calculations] 
)
See also
calcProbOfAllOutcomes
Author
Tyson Jones

Definition at line 883 of file test_calculations.cpp.

883  {
884 
887 
888  SECTION( "correctness" ) {
889 
890  // generate all possible qubit arrangements
891  int numQubits = GENERATE_COPY( range(1,NUM_QUBITS+1) );
892  int* qubits = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numQubits) );
893 
894  int numOutcomes = 1<<numQubits;
895  qreal probs[numOutcomes];
896  QVector refProbs = QVector(numOutcomes);
897 
898  SECTION( "state-vector" ) {
899 
900  SECTION( "normalised" ) {
901 
903  toQureg(vec, ref);
904 
905  // prob is sum of |amp|^2 of basis states which encode outcome
906  for (size_t i=0; i<ref.size(); i++) {
907  int outcome = 0;
908  for (int q=0; q<numQubits; q++) {
909  int bit = (i >> qubits[q]) & 1;
910  outcome += bit * (1 << q);
911  }
912  refProbs[outcome] += pow(abs(ref[i]), 2);
913  }
914 
915  calcProbOfAllOutcomes(probs, vec, qubits, numQubits);
916  REQUIRE( areEqual(refProbs, probs) );
917  }
918  SECTION( "unnormalised" ) {
919 
921  toQureg(vec, ref);
922 
923  // prob is sum of |amp|^2 of basis states which encode outcome
924  for (size_t i=0; i<ref.size(); i++) {
925  int outcome = 0;
926  for (int q=0; q<numQubits; q++) {
927  int bit = (i >> qubits[q]) & 1;
928  outcome += bit * (1 << q);
929  }
930  refProbs[outcome] += pow(abs(ref[i]), 2);
931  }
932 
933  calcProbOfAllOutcomes(probs, vec, qubits, numQubits);
934  REQUIRE( areEqual(refProbs, probs) );
935  }
936  }
937  SECTION( "density-matrix" ) {
938 
939  SECTION( "normalised" ) {
940 
942  toQureg(mat, ref);
943 
944  // prob is sum of diagonals which encode outcome
945  for (size_t i=0; i<ref.size(); i++) {
946  int outcome = 0;
947  for (int q=0; q<numQubits; q++) {
948  int bit = (i >> qubits[q]) & 1;
949  outcome += bit * (1 << q);
950  }
951  refProbs[outcome] += real(ref[i][i]);
952  }
953 
954  calcProbOfAllOutcomes(probs, mat, qubits, numQubits);
955  REQUIRE( areEqual(refProbs, probs) );
956  }
957  SECTION( "unnormalised" ) {
958 
960  toQureg(mat, ref);
961 
962  // prob is sum of diagonals which encode outcome
963  for (size_t i=0; i<ref.size(); i++) {
964  int outcome = 0;
965  for (int q=0; q<numQubits; q++) {
966  int bit = (i >> qubits[q]) & 1;
967  outcome += bit * (1 << q);
968  }
969  refProbs[outcome] += real(ref[i][i]);
970  }
971 
972  calcProbOfAllOutcomes(probs, mat, qubits, numQubits);
973  REQUIRE( areEqual(refProbs, probs) );
974  }
975  }
976  }
977  SECTION( "input validation" ) {
978 
979  int numQubits = 3;
980  int qubits[] = {0, 1, 2};
981  qreal probs[8];
982 
983  SECTION( "number of qubits" ) {
984 
985  numQubits = GENERATE( -1, 0, NUM_QUBITS+1 );
986  REQUIRE_THROWS_WITH( calcProbOfAllOutcomes(probs, mat, qubits, numQubits), Contains("Invalid number of target qubits") );
987  }
988  SECTION( "qubit indices" ) {
989 
990  qubits[GENERATE_COPY(range(0,numQubits))] = GENERATE( -1, NUM_QUBITS );
991  REQUIRE_THROWS_WITH( calcProbOfAllOutcomes(probs, mat, qubits, numQubits), Contains("Invalid target qubit") );
992  }
993  SECTION( "repetition of qubits" ) {
994 
995  qubits[GENERATE_COPY(1,2)] = qubits[0];
996  REQUIRE_THROWS_WITH( calcProbOfAllOutcomes(probs, mat, qubits, numQubits), Contains("qubits must be unique") );
997  }
998  }
999  destroyQureg(vec, QUEST_ENV);
1000  destroyQureg(mat, QUEST_ENV);
1001 }

References areEqual(), calcProbOfAllOutcomes(), createDensityQureg(), createQureg(), destroyQureg(), getRandomDensityMatrix(), getRandomQMatrix(), getRandomQVector(), getRandomStateVector(), NUM_QUBITS, qreal, QUEST_ENV, sublists(), and toQureg().

◆ TEST_CASE() [29/124]

TEST_CASE ( "calcProbOfOutcome"  ,
""  [calculations] 
)
See also
calcProbOfOutcome
Author
Tyson Jones

Definition at line 1010 of file test_calculations.cpp.

1010  {
1011 
1014 
1015  SECTION( "correctness" ) {
1016 
1017  int target = GENERATE( range(0,NUM_QUBITS) );
1018  int outcome = GENERATE( 0, 1 );
1019 
1020  SECTION( "state-vector" ) {
1021 
1022  SECTION( "normalised" ) {
1023 
1025  toQureg(vec, ref);
1026 
1027  // prob is sum of |amp|^2 of amplitudes where target bit is outcome
1028  qreal prob = 0;
1029  for (size_t ind=0; ind<ref.size(); ind++) {
1030  int bit = (ind >> target) & 1; // target-th bit
1031  if (bit == outcome)
1032  prob += pow(abs(ref[ind]), 2);
1033  }
1034 
1035  REQUIRE( calcProbOfOutcome(vec, target, outcome) == Approx(prob) );
1036  }
1037  SECTION( "unnormalised" ) {
1038 
1040  toQureg(vec, ref);
1041 
1042  // prob is (sum of |amp|^2 of amplitudes where target bit is zero)
1043  // or 1 - (this) if outcome == 1
1044  qreal prob = 0;
1045  for (size_t ind=0; ind<ref.size(); ind++) {
1046  int bit = (ind >> target) & 1; // target-th bit
1047  if (bit == 0)
1048  prob += pow(abs(ref[ind]), 2);
1049  }
1050  if (outcome == 1)
1051  prob = 1 - prob;
1052 
1053  REQUIRE( calcProbOfOutcome(vec, target, outcome) == Approx(prob) );
1054  }
1055  }
1056  SECTION( "density-matrix" ) {
1057 
1058  SECTION( "pure" ) {
1059 
1060  // set mat to a random |r><r|
1062  toQureg(mat, getKetBra(ref, ref));
1063 
1064  // calc prob of the state-vector
1065  qreal prob = 0;
1066  for (size_t ind=0; ind<ref.size(); ind++) {
1067  int bit = (ind >> target) & 1; // target-th bit
1068  if (bit == outcome)
1069  prob += pow(abs(ref[ind]), 2);
1070  }
1071 
1072  REQUIRE( calcProbOfOutcome(mat, target, outcome) == Approx(prob) );
1073  }
1074  SECTION( "mixed" ) {
1075 
1077  toQureg(mat, ref);
1078 
1079  // prob is sum of diagonal amps (should be real) where target bit is outcome
1080  qcomp tr = 0;
1081  for (size_t ind=0; ind<ref.size(); ind++) {
1082  int bit = (ind >> target) & 1; // target-th bit
1083  if (bit == outcome)
1084  tr += ref[ind][ind];
1085  }
1086  REQUIRE( imag(tr) == Approx(0).margin(REAL_EPS) );
1087 
1088  REQUIRE( calcProbOfOutcome(mat, target, outcome) == Approx(real(tr)) );
1089  }
1090  SECTION( "unnormalised" ) {
1091 
1093  toQureg(mat, ref);
1094 
1095  // prob is (sum of real of diagonal amps where target bit is outcome)
1096  // or 1 - (this) if outcome == 1
1097  qreal tr = 0;
1098  for (size_t ind=0; ind<ref.size(); ind++) {
1099  int bit = (ind >> target) & 1; // target-th bit
1100  if (bit == 0)
1101  tr += real(ref[ind][ind]);
1102  }
1103  if (outcome == 1)
1104  tr = 1 - tr;
1105 
1106  REQUIRE( calcProbOfOutcome(mat, target, outcome) == Approx(tr) );
1107  }
1108  }
1109  }
1110  SECTION( "input validation" ) {
1111 
1112  SECTION( "qubit indices" ) {
1113 
1114  int target = GENERATE( -1, NUM_QUBITS );
1115  REQUIRE_THROWS_WITH( calcProbOfOutcome(vec, target, 0), Contains("Invalid target qubit") );
1116  }
1117  SECTION( "outcome value" ) {
1118 
1119  int outcome = GENERATE( -1, 2 );
1120  REQUIRE_THROWS_WITH( calcProbOfOutcome(vec, 0, outcome), Contains("Invalid measurement outcome") );
1121  }
1122  }
1123  destroyQureg(vec, QUEST_ENV);
1124  destroyQureg(mat, QUEST_ENV);
1125 }

References calcProbOfOutcome(), createDensityQureg(), createQureg(), destroyQureg(), getKetBra(), getRandomDensityMatrix(), getRandomQMatrix(), getRandomQVector(), getRandomStateVector(), NUM_QUBITS, qcomp, qreal, QUEST_ENV, and toQureg().

◆ TEST_CASE() [30/124]

TEST_CASE ( "calcPurity"  ,
""  [calculations] 
)
See also
calcPurity
Author
Tyson Jones

Definition at line 1133 of file test_calculations.cpp.

1133  {
1134 
1136 
1137  SECTION( "correctness" ) {
1138 
1139  // perform the following random tests 10 times
1140  GENERATE( range(1,10) );
1141 
1142  SECTION( "density-matrix" ) {
1143 
1144  SECTION( "pure" ) {
1145 
1146  // pure states have unity purity
1147  initZeroState(mat);
1148  REQUIRE( calcPurity(mat) == 1 );
1149 
1150  // (try also a pure random L2-vector)
1152  QMatrix m1 = getKetBra(r1, r1); // |r><r|
1153  toQureg(mat, m1);
1154  REQUIRE( calcPurity(mat) == Approx(1) );
1155 
1156  }
1157  SECTION( "mixed" ) {
1158 
1159  // mixed states have 1/2^N < purity < 1
1161  toQureg(mat, ref);
1162  qreal purity = calcPurity(mat);
1163  REQUIRE( purity < 1 );
1164  REQUIRE( purity >= 1/pow(2.,NUM_QUBITS) );
1165 
1166  // compare to Tr(rho^2)
1167  QMatrix prod = ref*ref;
1168  qreal tr = 0;
1169  for (size_t i=0; i<prod.size(); i++)
1170  tr += real(prod[i][i]);
1171  REQUIRE( purity == Approx(tr) );
1172  }
1173  SECTION( "unnormalised" ) {
1174 
1175  // unphysical states give sum_{ij} |rho_ij|^2
1177  qreal tot = 0;
1178  for (size_t i=0; i<ref.size(); i++)
1179  for (size_t j=0; j<ref.size(); j++)
1180  tot += pow(abs(ref[i][j]), 2);
1181 
1182  toQureg(mat, ref);
1183  REQUIRE( calcPurity(mat) == Approx(tot) );
1184  }
1185  }
1186  }
1187  SECTION( "input validation" ) {
1188 
1189  SECTION( "state-vector" ) {
1190 
1192  REQUIRE_THROWS_WITH( calcPurity(vec), Contains("valid only for density matrices") );
1193  destroyQureg(vec, QUEST_ENV);
1194  }
1195  }
1196  destroyQureg(mat, QUEST_ENV);
1197 }

References calcPurity(), createDensityQureg(), createQureg(), destroyQureg(), getKetBra(), getRandomDensityMatrix(), getRandomQMatrix(), getRandomStateVector(), initZeroState(), NUM_QUBITS, qreal, QUEST_ENV, and toQureg().

◆ TEST_CASE() [31/124]

TEST_CASE ( "calcTotalProb"  ,
""  [calculations] 
)
See also
calcTotalProb
Author
Tyson Jones

Definition at line 1205 of file test_calculations.cpp.

1205  {
1206 
1209 
1210  SECTION( "correctness" ) {
1211 
1212  SECTION( "state-vector" ) {
1213 
1214  // normalised: prob(vec) = 1
1215  initPlusState(vec);
1216  REQUIRE( calcTotalProb(vec) == Approx(1) );
1217 
1218  // zero norm: prob(vec) = 0
1219  initBlankState(vec);
1220  REQUIRE( calcTotalProb(vec) == 0 );
1221 
1222  // random L2 state: prob(vec) = 1
1224  REQUIRE( calcTotalProb(vec) == Approx(1) );
1225 
1226  // unnormalised: prob(vec) = sum_i |vec_i|^2
1227  initDebugState(vec);
1228  QVector ref = toQVector(vec);
1229  qreal refProb = 0;
1230  for (size_t i=0; i<ref.size(); i++)
1231  refProb += pow(abs(ref[i]), 2);
1232  REQUIRE( calcTotalProb(vec) == Approx(refProb) );
1233  }
1234  SECTION( "density-matrix" ) {
1235 
1236  // normalised: prob(mat) = 1
1237  initPlusState(mat);
1238  REQUIRE( calcTotalProb(mat) == Approx(1) );
1239 
1240  // zero norm: prob(mat) = 0
1241  initBlankState(mat);
1242  REQUIRE( calcTotalProb(mat) == 0 );
1243 
1244  // random density matrix: prob(mat) = 1
1246  REQUIRE( calcTotalProb(mat) == Approx(1) );
1247 
1248  // unnormalised: prob(mat) = sum_i real(mat_{ii})
1249  initDebugState(mat);
1250  QMatrix ref = toQMatrix(mat);
1251  qreal refProb = 0;
1252  for (size_t i=0; i<ref.size(); i++)
1253  refProb += real(ref[i][i]);
1254  REQUIRE( calcTotalProb(mat) == Approx(refProb) );
1255  }
1256  }
1257  SECTION( "input validation" ) {
1258 
1259  // no validation
1260  SUCCEED();
1261  }
1262  destroyQureg(vec, QUEST_ENV);
1263  destroyQureg(mat, QUEST_ENV);
1264 }

References calcTotalProb(), createDensityQureg(), createQureg(), destroyQureg(), getRandomDensityMatrix(), getRandomStateVector(), initBlankState(), initDebugState(), initPlusState(), NUM_QUBITS, qreal, QUEST_ENV, toQMatrix(), toQureg(), and toQVector().

◆ TEST_CASE() [32/124]

TEST_CASE ( "cloneQureg"  ,
""  [state_initialisations] 
)
See also
cloneQureg
Author
Tyson Jones

Definition at line 15 of file test_state_initialisations.cpp.

15  {
16 
19 
20  SECTION( "correctness" ) {
21 
22  SECTION( "state-vector" ) {
23 
25 
26  // make sure states start differently
27  initDebugState(vec1);
28  initBlankState(vec2);
29  REQUIRE( !areEqual(vec1, vec2) );
30 
31  // make sure vec2 is changed
32  QVector copy1 = toQVector(vec1);
33  cloneQureg(vec2, vec1);
34  REQUIRE( areEqual(vec1, vec2) );
35 
36  // make sure vec1 unaffected
37  REQUIRE( areEqual(vec1, copy1) );
38 
39  destroyQureg(vec2, QUEST_ENV);
40  }
41  SECTION( "density-matrix" ) {
42 
44 
45  // make sure states start differently
46  initDebugState(mat1);
47  initBlankState(mat2);
48  REQUIRE( !areEqual(mat1, mat2) );
49 
50  // make sure vec2 is changed
51  QMatrix copy1 = toQMatrix(mat1);
52  cloneQureg(mat2, mat1);
53  REQUIRE( areEqual(mat1, mat2) );
54 
55  // make sure vec1 unaffected
56  REQUIRE( areEqual(mat1, copy1) );
57 
58  destroyQureg(mat2, QUEST_ENV);
59  }
60  }
61  SECTION( "input validation" ) {
62 
63  SECTION( "qureg type" ) {
64 
65  REQUIRE_THROWS_WITH( cloneQureg(mat1, vec1), Contains("both be state-vectors") && Contains("density matrices") );
66  REQUIRE_THROWS_WITH( cloneQureg(vec1, mat1), Contains("both be state-vectors") && Contains("density matrices") );
67  }
68  SECTION( "qureg dimensions" ) {
69 
72 
73  REQUIRE_THROWS_WITH( cloneQureg(vec1, vec3), Contains("Dimensions") && Contains("don't match") );
74  REQUIRE_THROWS_WITH( cloneQureg(mat1, mat3), Contains("Dimensions") && Contains("don't match") );
75 
76  destroyQureg(vec3, QUEST_ENV);
77  destroyQureg(mat3, QUEST_ENV);
78  }
79  }
80  destroyQureg(vec1, QUEST_ENV);
81  destroyQureg(mat1, QUEST_ENV);
82 }

References areEqual(), cloneQureg(), createDensityQureg(), createQureg(), destroyQureg(), initBlankState(), initDebugState(), NUM_QUBITS, Qureg::numQubitsRepresented, QUEST_ENV, toQMatrix(), and toQVector().

◆ TEST_CASE() [33/124]

TEST_CASE ( "collapseToOutcome"  ,
""  [gates] 
)
See also
collapseToOutcome
Author
Tyson Jones

Definition at line 15 of file test_gates.cpp.

15  {
16 
19 
20  SECTION( "correctness" ) {
21 
22  int qubit = GENERATE( range(0,NUM_QUBITS) );
23  int outcome = GENERATE( 0, 1 );
24 
25  // repeat these random tests 10 times on every qubit, and for both outcomes
26  GENERATE( range(0,10) );
27 
28  SECTION( "state-vector" ) {
29 
30  // use a random L2 state for every qubit & outcome
32  toQureg(vec, vecRef);
33 
34  // calculate prob of outcome
35  qreal prob = 0;
36  for (size_t ind=0; ind<vecRef.size(); ind++) {
37  int bit = (ind >> qubit) & 1; // target-th bit
38  if (bit == outcome)
39  prob += pow(abs(vecRef[ind]), 2);
40  }
41 
42  // renormalise by the outcome prob
43  for (size_t ind=0; ind<vecRef.size(); ind++) {
44  int bit = (ind >> qubit) & 1; // target-th bit
45  if (bit == outcome)
46  vecRef[ind] /= sqrt(prob);
47  else
48  vecRef[ind] = 0;
49  }
50 
51  qreal res = collapseToOutcome(vec, qubit, outcome);
52  REQUIRE( res == Approx(prob) );
53  REQUIRE( areEqual(vec, vecRef) );
54  }
55  SECTION( "density-matrix" ) {
56 
57  // use a random density matrix for every qubit & outcome
59  toQureg(mat, matRef);
60 
61  // prob is sum of diagonal amps (should be real) where target bit is outcome
62  qcomp tr = 0;
63  for (size_t ind=0; ind<matRef.size(); ind++) {
64  int bit = (ind >> qubit) & 1; // qubit-th bit
65  if (bit == outcome)
66  tr += matRef[ind][ind];
67  }
68  REQUIRE( imag(tr) == Approx(0).margin(REAL_EPS) );
69  qreal prob = real(tr);
70 
71  // renorm (/prob) every |*outcome*><*outcome*| state, zeroing all others
72  for (size_t r=0; r<matRef.size(); r++) {
73  for (size_t c=0; c<matRef.size(); c++) {
74  int ketBit = (c >> qubit) & 1;
75  int braBit = (r >> qubit) & 1;
76 
77  if (ketBit == outcome && braBit == outcome)
78  matRef[r][c] /= prob;
79  else
80  matRef[r][c] = 0;
81  }
82  }
83 
84  qreal res = collapseToOutcome(mat, qubit, outcome);
85  REQUIRE( res == Approx(prob) );
86  REQUIRE( areEqual(mat, matRef) );
87  }
88  }
89  SECTION( "input validation" ) {
90 
91  SECTION( "qubit index" ) {
92 
93  int qubit = GENERATE( -1, NUM_QUBITS );
94  int outcome = 0;
95  REQUIRE_THROWS_WITH( collapseToOutcome(mat, qubit, outcome), Contains("Invalid target qubit") );
96  }
97  SECTION( "outcome value" ) {
98 
99  int qubit = 0;
100  int outcome = GENERATE( -1, 2 );
101  REQUIRE_THROWS_WITH( collapseToOutcome(mat, qubit, outcome), Contains("Invalid measurement outcome") );
102  }
103  SECTION( "outcome probability" ) {
104 
105  initZeroState(vec);
106  REQUIRE_THROWS_WITH( collapseToOutcome(vec, 0, 1), Contains("Can't collapse to state with zero probability") );
107  initClassicalState(vec, 1);
108  REQUIRE_THROWS_WITH( collapseToOutcome(vec, 0, 0), Contains("Can't collapse to state with zero probability") );
109  }
110  }
111  destroyQureg(vec, QUEST_ENV);
112  destroyQureg(mat, QUEST_ENV);
113 }

References areEqual(), collapseToOutcome(), createDensityQureg(), createQureg(), destroyQureg(), getRandomDensityMatrix(), getRandomStateVector(), initClassicalState(), initZeroState(), NUM_QUBITS, qcomp, qreal, QUEST_ENV, and toQureg().

◆ TEST_CASE() [34/124]

TEST_CASE ( "compactUnitary"  ,
""  [unitaries] 
)
See also
compactUnitary
Author
Tyson Jones

Definition at line 46 of file test_unitaries.cpp.

46  {
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 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, compactUnitary(), expI(), getRandomReal(), M_PI, NUM_QUBITS, PREPARE_TEST, qcomp, Complex::real, toComplex, and toQMatrix().

◆ TEST_CASE() [35/124]

TEST_CASE ( "controlledCompactUnitary"  ,
""  [unitaries] 
)
See also
controlledCompactUnitary
Author
Tyson Jones

Definition at line 97 of file test_unitaries.cpp.

97  {
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 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, controlledCompactUnitary(), expI(), getRandomReal(), M_PI, NUM_QUBITS, PREPARE_TEST, qcomp, Complex::real, toComplex, and toQMatrix().

◆ TEST_CASE() [36/124]

TEST_CASE ( "controlledMultiQubitUnitary"  ,
""  [unitaries] 
)
See also
controlledMultiQubitUnitary
Author
Tyson Jones

Definition at line 155 of file test_unitaries.cpp.

155  {
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 }

References applyReferenceOp(), areEqual(), calcLog2(), CLEANUP_TEST, controlledMultiQubitUnitary(), createComplexMatrixN(), destroyComplexMatrixN(), getRandomUnitary(), ComplexMatrixN::imag, NUM_QUBITS, PREPARE_TEST, ComplexMatrixN::real, sublists(), and toComplexMatrixN().

◆ TEST_CASE() [37/124]

TEST_CASE ( "controlledNot"  ,
""  [unitaries] 
)
See also
controlledNot
Author
Tyson Jones

Definition at line 295 of file test_unitaries.cpp.

295  {
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 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, controlledNot(), NUM_QUBITS, and PREPARE_TEST.

◆ TEST_CASE() [38/124]

TEST_CASE ( "controlledPauliY"  ,
""  [unitaries] 
)
See also
controlledPauliY
Author
Tyson Jones

Definition at line 341 of file test_unitaries.cpp.

341  {
342 
343  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
344  QMatrix op{{0,-qcomp(0,1)},{qcomp(0,1),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 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, controlledPauliY(), NUM_QUBITS, PREPARE_TEST, and qcomp.

◆ TEST_CASE() [39/124]

TEST_CASE ( "controlledPhaseFlip"  ,
""  [unitaries] 
)
See also
controlledPhaseFlip
Author
Tyson Jones

Definition at line 387 of file test_unitaries.cpp.

387  {
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 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, controlledPhaseFlip(), NUM_QUBITS, and PREPARE_TEST.

◆ TEST_CASE() [40/124]

TEST_CASE ( "controlledPhaseShift"  ,
""  [unitaries] 
)
See also
controlledPhaseShift
Author
Tyson Jones

Definition at line 433 of file test_unitaries.cpp.

433  {
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 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, controlledPhaseShift(), expI(), getRandomReal(), M_PI, NUM_QUBITS, PREPARE_TEST, and qreal.

◆ TEST_CASE() [41/124]

TEST_CASE ( "controlledRotateAroundAxis"  ,
""  [unitaries] 
)
See also
controlledRotateAroundAxis
Author
Tyson Jones

Definition at line 480 of file test_unitaries.cpp.

480  {
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 - qcomp(0,1)*vec.z*s/m, -(vec.y + qcomp(0,1)*vec.x)*s/m},
494  {(vec.y - qcomp(0,1)*vec.x)*s/m, c + qcomp(0,1)*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 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, controlledRotateAroundAxis(), getRandomReal(), M_PI, NUM_QUBITS, PREPARE_TEST, qcomp, qreal, Vector::x, Vector::y, and Vector::z.

◆ TEST_CASE() [42/124]

TEST_CASE ( "controlledRotateX"  ,
""  [unitaries] 
)
See also
controlledRotateX
Author
Tyson Jones

Definition at line 542 of file test_unitaries.cpp.

542  {
543 
544  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
545  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
546  QMatrix op{
547  {cos(param/2), -sin(param/2)*qcomp(0,1)},
548  {-sin(param/2)*qcomp(0,1), cos(param/2)}};
549 
550  SECTION( "correctness" ) {
551 
552  int target = GENERATE( range(0,NUM_QUBITS) );
553  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
554 
555  SECTION( "state-vector" ) {
556 
557  controlledRotateX(quregVec, control, target, param);
558  applyReferenceOp(refVec, control, target, op);
559  REQUIRE( areEqual(quregVec, refVec) );
560  }
561  SECTION( "density-matrix" ) {
562 
563  controlledRotateX(quregMatr, control, target, param);
564  applyReferenceOp(refMatr, control, target, op);
565  REQUIRE( areEqual(quregMatr, refMatr) );
566  }
567  }
568  SECTION( "input validation" ) {
569 
570  SECTION( "control and target collision" ) {
571 
572  int qb = GENERATE( range(0,NUM_QUBITS) );
573  REQUIRE_THROWS_WITH( controlledRotateX(quregVec, qb, qb, param), Contains("Control") && Contains("target") );
574  }
575  SECTION( "qubit indices" ) {
576 
577  int qb = GENERATE( -1, NUM_QUBITS );
578  REQUIRE_THROWS_WITH( controlledRotateX(quregVec, qb, 0, param), Contains("Invalid control") );
579  REQUIRE_THROWS_WITH( controlledRotateX(quregVec, 0, qb, param), Contains("Invalid target") );
580  }
581  }
582  CLEANUP_TEST( quregVec, quregMatr );
583 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, controlledRotateX(), getRandomReal(), M_PI, NUM_QUBITS, PREPARE_TEST, qcomp, and qreal.

◆ TEST_CASE() [43/124]

TEST_CASE ( "controlledRotateY"  ,
""  [unitaries] 
)
See also
controlledRotateY
Author
Tyson Jones

Definition at line 591 of file test_unitaries.cpp.

591  {
592 
593  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
594  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
595  QMatrix op{{cos(param/2), -sin(param/2)},{sin(param/2), cos(param/2)}};
596 
597  SECTION( "correctness" ) {
598 
599  int target = GENERATE( range(0,NUM_QUBITS) );
600  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
601 
602  SECTION( "state-vector" ) {
603 
604  controlledRotateY(quregVec, control, target, param);
605  applyReferenceOp(refVec, control, target, op);
606  REQUIRE( areEqual(quregVec, refVec) );
607  }
608  SECTION( "density-matrix" ) {
609 
610  controlledRotateY(quregMatr, control, target, param);
611  applyReferenceOp(refMatr, control, target, op);
612  REQUIRE( areEqual(quregMatr, refMatr, 2*REAL_EPS) );
613  }
614  }
615  SECTION( "input validation" ) {
616 
617  SECTION( "control and target collision" ) {
618 
619  int qb = GENERATE( range(0,NUM_QUBITS) );
620  REQUIRE_THROWS_WITH( controlledRotateY(quregVec, qb, qb, param), Contains("Control") && Contains("target") );
621  }
622  SECTION( "qubit indices" ) {
623 
624  int qb = GENERATE( -1, NUM_QUBITS );
625  REQUIRE_THROWS_WITH( controlledRotateY(quregVec, qb, 0, param), Contains("Invalid control") );
626  REQUIRE_THROWS_WITH( controlledRotateY(quregVec, 0, qb, param), Contains("Invalid target") );
627  }
628  }
629  CLEANUP_TEST( quregVec, quregMatr );
630 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, controlledRotateY(), getRandomReal(), M_PI, NUM_QUBITS, PREPARE_TEST, and qreal.

◆ TEST_CASE() [44/124]

TEST_CASE ( "controlledRotateZ"  ,
""  [unitaries] 
)
See also
controlledRotateZ
Author
Tyson Jones

Definition at line 638 of file test_unitaries.cpp.

638  {
639 
640  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
641  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
642  QMatrix op{{expI(-param/2.),0},{0,expI(param/2.)}};
643 
644  SECTION( "correctness" ) {
645 
646  int target = GENERATE( range(0,NUM_QUBITS) );
647  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
648 
649  SECTION( "state-vector" ) {
650 
651  controlledRotateZ(quregVec, control, target, param);
652  applyReferenceOp(refVec, control, target, op);
653  REQUIRE( areEqual(quregVec, refVec) );
654  }
655  SECTION( "density-matrix" ) {
656 
657  controlledRotateZ(quregMatr, control, target, param);
658  applyReferenceOp(refMatr, control, target, op);
659  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
660  }
661  }
662  SECTION( "input validation" ) {
663 
664  SECTION( "control and target collision" ) {
665 
666  int qb = GENERATE( range(0,NUM_QUBITS) );
667  REQUIRE_THROWS_WITH( controlledRotateZ(quregVec, qb, qb, param), Contains("Control") && Contains("target") );
668  }
669  SECTION( "qubit indices" ) {
670 
671  int qb = GENERATE( -1, NUM_QUBITS );
672  REQUIRE_THROWS_WITH( controlledRotateZ(quregVec, qb, 0, param), Contains("Invalid control") );
673  REQUIRE_THROWS_WITH( controlledRotateZ(quregVec, 0, qb, param), Contains("Invalid target") );
674  }
675  }
676  CLEANUP_TEST( quregVec, quregMatr );
677 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, controlledRotateZ(), expI(), getRandomReal(), M_PI, NUM_QUBITS, PREPARE_TEST, and qreal.

◆ TEST_CASE() [45/124]

TEST_CASE ( "controlledTwoQubitUnitary"  ,
""  [unitaries] 
)
See also
controlledTwoQubitUnitary
Author
Tyson Jones

Definition at line 685 of file test_unitaries.cpp.

685  {
686 
687  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
688 
689  // in distributed mode, each node must be able to fit all amps modified by unitary
690  REQUIRE( quregVec.numAmpsPerChunk >= 4 );
691 
692  // every test will use a unique random matrix
693  QMatrix op = getRandomUnitary(2);
694  ComplexMatrix4 matr = toComplexMatrix4(op);
695 
696  SECTION( "correctness" ) {
697 
698  int targ1 = GENERATE( range(0,NUM_QUBITS) );
699  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
700  int control = GENERATE_COPY( filter([=](int c){ return c!=targ1 && c!=targ2; }, range(0,NUM_QUBITS)) );
701 
702  SECTION( "state-vector" ) {
703 
704  controlledTwoQubitUnitary(quregVec, control, targ1, targ2, matr);
705  applyReferenceOp(refVec, control, targ1, targ2, op);
706  REQUIRE( areEqual(quregVec, refVec) );
707  }
708  SECTION( "density-matrix" ) {
709 
710  controlledTwoQubitUnitary(quregMatr, control, targ1, targ2, matr);
711  applyReferenceOp(refMatr, control, targ1, targ2, op);
712  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
713  }
714  }
715  SECTION( "input validation" ) {
716 
717  SECTION( "repetition of targets" ) {
718  int targ = 0;
719  int ctrl = 1;
720  REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, ctrl, targ, targ, matr), Contains("target") && Contains("unique") );
721  }
722  SECTION( "control and target collision" ) {
723 
724  int targ1 = 1;
725  int targ2 = 2;
726  int ctrl = GENERATE( 1,2 ); // catch2 bug; can't do GENERATE_COPY( targ1, targ2 )
727  REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, ctrl, targ1, targ2, matr), Contains("Control") && Contains("target") );
728  }
729  SECTION( "qubit indices" ) {
730 
731  // valid config
732  int ctrl = 0;
733  int targ1 = 1;
734  int targ2 = 2;
735 
736  int qb = GENERATE( -1, NUM_QUBITS );
737  REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, qb, targ1, targ2, matr), Contains("Invalid control") );
738  REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, ctrl, qb, targ2, matr), Contains("Invalid target") );
739  REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, ctrl, targ1, qb, matr), Contains("Invalid target") );
740  }
741  SECTION( "unitarity" ) {
742 
743  matr.real[0][0] = 0; // break matr unitarity
744  REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, 0, 1, 2, matr), Contains("unitary") );
745  }
746  SECTION( "unitary fits in node" ) {
747 
748  // pretend we have a very limited distributed memory
749  quregVec.numAmpsPerChunk = 1;
750  REQUIRE_THROWS_WITH( controlledTwoQubitUnitary(quregVec, 0, 1, 2, matr), Contains("targets too many qubits"));
751  }
752  }
753  CLEANUP_TEST( quregVec, quregMatr );
754 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, controlledTwoQubitUnitary(), getRandomUnitary(), NUM_QUBITS, PREPARE_TEST, ComplexMatrix4::real, and toComplexMatrix4().

◆ TEST_CASE() [46/124]

TEST_CASE ( "controlledUnitary"  ,
""  [unitaries] 
)
See also
controlledUnitary
Author
Tyson Jones

Definition at line 762 of file test_unitaries.cpp.

762  {
763 
764  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
765  QMatrix op = getRandomUnitary(1);
766  ComplexMatrix2 matr = toComplexMatrix2(op);
767 
768  SECTION( "correctness" ) {
769 
770  int target = GENERATE( range(0,NUM_QUBITS) );
771  int control = GENERATE_COPY( filter([=](int c){ return c!=target; }, range(0,NUM_QUBITS)) );
772 
773  SECTION( "state-vector" ) {
774 
775  controlledUnitary(quregVec, control, target, matr);
776  applyReferenceOp(refVec, control, target, op);
777  REQUIRE( areEqual(quregVec, refVec) );
778  }
779  SECTION( "density-matrix" ) {
780 
781  controlledUnitary(quregMatr, control, target, matr);
782  applyReferenceOp(refMatr, control, target, op);
783  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
784  }
785  }
786  SECTION( "input validation" ) {
787 
788  SECTION( "control and target collision" ) {
789 
790  int qb = GENERATE( range(0,NUM_QUBITS) );
791  REQUIRE_THROWS_WITH( controlledUnitary(quregVec, qb, qb, matr), Contains("Control") && Contains("target") );
792  }
793  SECTION( "qubit indices" ) {
794 
795  int qb = GENERATE( -1, NUM_QUBITS );
796  REQUIRE_THROWS_WITH( controlledUnitary(quregVec, qb, 0, matr), Contains("Invalid control") );
797  REQUIRE_THROWS_WITH( controlledUnitary(quregVec, 0, qb, matr), Contains("Invalid target") );
798  }
799  SECTION( "unitarity" ) {
800 
801  matr.real[0][0] = 0; // break unitarity
802  REQUIRE_THROWS_WITH( controlledUnitary(quregVec, 0, 1, matr), Contains("unitary") );
803  }
804  }
805  CLEANUP_TEST( quregVec, quregMatr );
806 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, controlledUnitary(), getRandomUnitary(), NUM_QUBITS, PREPARE_TEST, ComplexMatrix2::real, and toComplexMatrix2().

◆ TEST_CASE() [47/124]

TEST_CASE ( "createCloneQureg"  ,
""  [data_structures] 
)
See also
createCloneQureg
Author
Tyson Jones

Definition at line 57 of file test_data_structures.cpp.

57  {
58 
59  SECTION( "state-vector" ) {
60 
63 
64  // check properties are the same
65  REQUIRE( b.isDensityMatrix == a.isDensityMatrix );
67  REQUIRE( b.numQubitsInStateVec == a.numQubitsInStateVec );
68  REQUIRE( b.numAmpsPerChunk == a.numAmpsPerChunk );
69  REQUIRE( b.numAmpsTotal == a.numAmpsTotal );
70 
71  // check state-vector is the same (works for GPU and distributed)
72  REQUIRE( areEqual(a, b) );
73 
76  }
77  SECTION( "density-matrix" ) {
78 
81 
82  // check properties are the same
83  REQUIRE( b.isDensityMatrix == a.isDensityMatrix );
85  REQUIRE( b.numQubitsInStateVec == a.numQubitsInStateVec );
86  REQUIRE( b.numAmpsPerChunk == a.numAmpsPerChunk );
87  REQUIRE( b.numAmpsTotal == a.numAmpsTotal );
88 
89  // check state-vector is the same (works for GPU and distributed)
90  REQUIRE( areEqual(a, b) );
91 
94  }
95 }

References areEqual(), createCloneQureg(), createDensityQureg(), createQureg(), destroyQureg(), Qureg::isDensityMatrix, NUM_QUBITS, Qureg::numAmpsPerChunk, Qureg::numAmpsTotal, Qureg::numQubitsInStateVec, Qureg::numQubitsRepresented, and QUEST_ENV.

◆ TEST_CASE() [48/124]

TEST_CASE ( "createComplexMatrixN"  ,
""  [data_structures] 
)
See also
createComplexMatrixN
Author
Tyson Jones

Definition at line 103 of file test_data_structures.cpp.

103  {
104 
105  SECTION( "correctness" ) {
106 
107  int numQb = GENERATE( range(1,10+1) );
109 
110  // ensure elems are created and initialised to 0
111  REQUIRE( areEqual(toQMatrix(m), getZeroMatrix(1<<numQb)) );
112 
114  }
115  SECTION( "input validation" ) {
116 
117  SECTION( "number of qubits" ) {
118 
119  int numQb = GENERATE( -1, 0 );
120  REQUIRE_THROWS_WITH( createComplexMatrixN(numQb), Contains("Invalid number of qubits") );
121  }
122  }
123 }

References areEqual(), createComplexMatrixN(), destroyComplexMatrixN(), getZeroMatrix(), and toQMatrix().

◆ TEST_CASE() [49/124]

TEST_CASE ( "createDensityQureg"  ,
""  [data_structures] 
)
See also
createDensityQureg
Author
Tyson Jones

Definition at line 131 of file test_data_structures.cpp.

131  {
132 
133  // must be at least one amplitude per node
134  int minNumQb = calcLog2(QUEST_ENV.numRanks) - 1; // density matrix has 2*numQb in state-vec
135  if (minNumQb <= 0)
136  minNumQb = 1;
137 
138  SECTION( "correctness" ) {
139 
140  // try 10 valid number of qubits
141  int numQb = GENERATE_COPY( range(minNumQb, minNumQb+10) );
142  Qureg reg = createDensityQureg(numQb, QUEST_ENV);
143 
144  // ensure elems (CPU and/or GPU) are created, and reg begins in |0><0|
145  QMatrix ref = getZeroMatrix(1<<numQb);
146  ref[0][0] = 1; // |0><0|
147  REQUIRE( areEqual(reg, ref) );
148 
149  destroyQureg(reg, QUEST_ENV);
150  }
151  SECTION( "input validation") {
152 
153  SECTION( "number of qubits" ) {
154 
155  int numQb = GENERATE( -1, 0 );
156  REQUIRE_THROWS_WITH( createDensityQureg(numQb, QUEST_ENV), Contains("Invalid number of qubits") );
157  }
158  SECTION( "number of amplitudes" ) {
159 
160  // use local QuESTEnv to safely modify
161  QuESTEnv env = QUEST_ENV;
162 
163  // too many amplitudes to store in type
164  int maxQb = (int) calcLog2(SIZE_MAX) / 2;
165  REQUIRE_THROWS_WITH( createDensityQureg(maxQb+1, env), Contains("Too many qubits") && Contains("size_t type") );
166 
167  /* n-qubit density matrix contains 2^(2n) amplitudes
168  * so can be spread between at most 2^(2n) ranks
169  */
170  int minQb = GENERATE_COPY( range(3,maxQb) );
171  env.numRanks = (int) pow(2, 2*minQb);
172  int numQb = GENERATE_COPY( range(1,minQb) );
173  REQUIRE_THROWS_WITH( createDensityQureg(numQb, env), Contains("Too few qubits") );
174  }
175  SECTION( "available memory" ) {
176 
177  /* there is no reliable way to force the malloc statements to
178  * fail, and hence trigger the matrixInit validation */
179  SUCCEED( );
180  }
181  }
182 }

References areEqual(), calcLog2(), createDensityQureg(), destroyQureg(), getZeroMatrix(), QuESTEnv::numRanks, and QUEST_ENV.

◆ TEST_CASE() [50/124]

TEST_CASE ( "createDiagonalOp"  ,
""  [data_structures] 
)
See also
createDiagonalOp
Author
Tyson Jones

Definition at line 190 of file test_data_structures.cpp.

190  {
191 
192  // must be at least one amplitude per node
193  int minNumQb = calcLog2(QUEST_ENV.numRanks);
194  if (minNumQb == 0)
195  minNumQb = 1;
196 
197  SECTION( "correctness" ) {
198 
199  // try 10 valid number of qubits
200  int numQb = GENERATE_COPY( range(minNumQb, minNumQb+10) );
202 
203  // check properties are correct
204  REQUIRE( op.numQubits == numQb );
205  REQUIRE( op.chunkId == QUEST_ENV.rank );
206  REQUIRE( op.numChunks == QUEST_ENV.numRanks );
207  REQUIRE( op.numElemsPerChunk == (1LL << numQb) / QUEST_ENV.numRanks );
208  REQUIRE( op.real != NULL );
209  REQUIRE( op.imag != NULL );
210 
211  // check all elements in CPU are zero
212  REQUIRE( areEqual(toQVector(op), QVector(1LL << numQb)) );
213 
214  // (no concise way to check this for GPU)
215 
217  }
218  SECTION( "input validation" ) {
219 
220  SECTION( "number of qubits" ) {
221 
222  int numQb = GENERATE( -1, 0 );
223  REQUIRE_THROWS_WITH( createDiagonalOp(numQb, QUEST_ENV), Contains("Invalid number of qubits") );
224  }
225  SECTION( "number of elements" ) {
226 
227  // use local QuESTEnv to safely modify
228  QuESTEnv env = QUEST_ENV;
229 
230  // too many amplitudes to store in type
231  int maxQb = (int) calcLog2(SIZE_MAX);
232  REQUIRE_THROWS_WITH( createDiagonalOp(maxQb+1, env), Contains("Too many qubits") && Contains("size_t type") );
233 
234  // too few amplitudes to distribute
235  int minQb = GENERATE_COPY( range(2,maxQb) );
236  env.numRanks = (int) pow(2, minQb);
237  int numQb = GENERATE_COPY( range(1,minQb) );
238  REQUIRE_THROWS_WITH( createDiagonalOp(numQb, env), Contains("Too few qubits") && Contains("distributed"));
239  }
240  SECTION( "available memory" ) {
241 
242  /* there is no reliable way to force the malloc statements to
243  * fail, and hence trigger the diagonalOpInit validation */
244  SUCCEED( );
245  }
246  }
247 }

References areEqual(), calcLog2(), DiagonalOp::chunkId, createDiagonalOp(), destroyDiagonalOp(), DiagonalOp::imag, DiagonalOp::numChunks, DiagonalOp::numElemsPerChunk, DiagonalOp::numQubits, QuESTEnv::numRanks, QUEST_ENV, QuESTEnv::rank, DiagonalOp::real, and toQVector().

◆ TEST_CASE() [51/124]

TEST_CASE ( "createDiagonalOpFromPauliHamilFile"  ,
""  [data_structures] 
)
See also
createDiagonalOpFromPauliHamilFile
Author
Tyson Jones

Definition at line 255 of file test_data_structures.cpp.

255  {
256 
257  // files created & populated during the test, and deleted afterward
258  char fnPrefix[] = "temp_createDiagonalOpFromPauliHamilFile";
259  char fn[100];
260 
261  // each test uses a unique filename (managed by master node), to avoid file IO locks
262  // (it's safe for sub-test to overwrite this, since after each test, all files
263  // with prefix fnPrefix are deleted)
264  setUniqueFilename(fn, fnPrefix);
265 
266  // diagonal op must have at least one amplitude per node
267  int minNumQb = calcLog2(QUEST_ENV.numRanks);
268  if (minNumQb == 0)
269  minNumQb = 1;
270 
271  SECTION( "correctness" ) {
272 
273  SECTION( "general" ) {
274 
275  // try several Pauli Hamiltonian sizes
276  int numQb = GENERATE_COPY( range(minNumQb, 6+minNumQb) );
277  int numTerms = GENERATE_COPY( 1, minNumQb, 10*minNumQb );
278 
279  // create a PauliHamil with random elements
280  PauliHamil hamil = createPauliHamil(numQb, numTerms);
282 
283  // write the Hamiltonian to file (with trailing whitespace, and trailing newline)
284  if (QUEST_ENV.rank == 0) {
285  FILE* file = fopen(fn, "w");
286  int i=0;
287  for (int n=0; n<numTerms; n++) {
288  fprintf(file, REAL_STRING_FORMAT, hamil.termCoeffs[n]);
289  fprintf(file, " ");
290  for (int q=0; q<numQb; q++)
291  fprintf(file, "%d ", (int) hamil.pauliCodes[i++]);
292  fprintf(file, "\n");
293  }
294  fprintf(file, "\n");
295  fclose(file);
296  }
298 
299  // load the file as a diagonal operator, and compare
301  REQUIRE( areEqual(toQMatrix(op), toQMatrix(hamil)) );
302 
303  destroyPauliHamil(hamil);
305  }
306  SECTION( "edge cases" ) {
307 
308  // prepare a valid single-term diagonal Pauli Hamiltonian
309  qreal coeffs[] = {.1};
310  pauliOpType codes[minNumQb];
311  for (int q=0; q<minNumQb; q++)
312  codes[q] = (q%2)? PAULI_I : PAULI_Z;
313 
314  QMatrix ref = toQMatrix(coeffs, codes, minNumQb, 1);
315 
316  // prepare basic encoding string
317  string line = to_string(coeffs[0]) + " ";
318  for (int q=0; q<minNumQb; q++)
319  line += to_string(codes[q]) + ((q<minNumQb-1)? " ":"");
320 
321  SECTION( "no trailing newline or space" ) {
322 
323  writeToFileSynch(fn, line);
324 
326  REQUIRE( areEqual(ref, toQMatrix(op)) );
327 
329  }
330  SECTION( "trailing newlines" ) {
331 
332  writeToFileSynch(fn, line + "\n\n\n");
333 
335  REQUIRE( areEqual(ref, toQMatrix(op)) );
336 
338  }
339  SECTION( "trailing spaces" ) {
340 
341  writeToFileSynch(fn, line + " ");
342 
344  REQUIRE( areEqual(ref, toQMatrix(op)) );
345 
347  }
348  }
349  }
350  SECTION( "input validation") {
351 
352  SECTION( "number of qubits" ) {
353 
354  writeToFileSynch(fn, ".1 "); // 0 qubits
355  REQUIRE_THROWS_WITH( createDiagonalOpFromPauliHamilFile(fn, QUEST_ENV), Contains("The number of qubits") && Contains("strictly positive"));
356  }
357  SECTION( "number of elements" ) {
358 
359  // too many amplitudes to store in type
360  int maxQb = (int) calcLog2(SIZE_MAX);
361 
362  // encode one more qubit than legal to file
363  string line = ".1 ";
364  for (int q=0; q<(maxQb+1); q++)
365  line += "3 "; // trailing space ok
366  writeToFileSynch(fn, line);
367 
368  REQUIRE_THROWS_WITH( createDiagonalOpFromPauliHamilFile(fn, QUEST_ENV), Contains("Too many qubits") && Contains("size_t type") );
369 
370  // use local QuESTEnv to safely modify
371  QuESTEnv env = QUEST_ENV;
372 
373  // too few elements to distribute
374  int minQb = GENERATE_COPY( range(2,maxQb) );
375  env.numRanks = (int) pow(2, minQb);
376  int numQb = GENERATE_COPY( range(1,minQb) );
377 
378  line = ".1 ";
379  for (int q=0; q<numQb; q++)
380  line += "3 "; // trailing space ok
381  setUniqueFilename(fn, fnPrefix);
382  writeToFileSynch(fn, line);
383 
384  REQUIRE_THROWS_WITH( createDiagonalOpFromPauliHamilFile(fn, env), Contains("Too few qubits") && Contains("distributed") );
385  }
386  SECTION( "coefficient type" ) {
387 
388  writeToFileSynch(fn, "notanumber 1 2 3");
389  REQUIRE_THROWS_WITH( createDiagonalOpFromPauliHamilFile(fn, QUEST_ENV), Contains("Failed to parse") && Contains("coefficient"));
390  }
391  SECTION( "pauli code" ) {
392 
393  writeToFileSynch(fn, ".1 0 3 2"); // final is invalid Y
394  REQUIRE_THROWS_WITH( createDiagonalOpFromPauliHamilFile(fn, QUEST_ENV), Contains("contained operators other than PAULI_Z and PAULI_I"));
395 
396  setUniqueFilename(fn, fnPrefix);
397  writeToFileSynch(fn, ".1 0 1 3"); // second is invalid X
398  REQUIRE_THROWS_WITH( createDiagonalOpFromPauliHamilFile(fn, QUEST_ENV), Contains("contained operators other than PAULI_Z and PAULI_I"));
399 
400  setUniqueFilename(fn, fnPrefix);
401  writeToFileSynch(fn, ".1 0 1 4"); // final is invalid Pauli code
402  REQUIRE_THROWS_WITH( createDiagonalOpFromPauliHamilFile(fn, QUEST_ENV), Contains("invalid pauli code"));
403 
404  setUniqueFilename(fn, fnPrefix);
405  writeToFileSynch(fn, ".1 3 0 notanumber"); // final is invalid type
406  REQUIRE_THROWS_WITH( createDiagonalOpFromPauliHamilFile(fn, QUEST_ENV), Contains("Failed to parse the next expected Pauli code"));
407  }
408  }
409 
410  // delete all files created above
411  deleteFilesWithPrefixSynch(fnPrefix);
412 }

References areEqual(), calcLog2(), createDiagonalOpFromPauliHamilFile(), createPauliHamil(), deleteFilesWithPrefixSynch(), destroyDiagonalOp(), destroyPauliHamil(), QuESTEnv::numRanks, PAULI_I, PAULI_Z, PauliHamil::pauliCodes, qreal, QUEST_ENV, QuESTEnv::rank, setRandomDiagPauliHamil(), setUniqueFilename(), syncQuESTEnv(), PauliHamil::termCoeffs, toQMatrix(), and writeToFileSynch().

◆ TEST_CASE() [52/124]

TEST_CASE ( "createPauliHamil"  ,
""  [data_structures] 
)
See also
createPauliHamil
Author
Tyson Jones

Definition at line 420 of file test_data_structures.cpp.

420  {
421 
422  SECTION( "correctness" ) {
423 
424  int numQb = GENERATE( range(1,5) );
425  int numTerms = GENERATE( range(1,5) );
426  PauliHamil hamil = createPauliHamil(numQb, numTerms);
427 
428  // check fields are correct
429  REQUIRE( hamil.numQubits == numQb );
430  REQUIRE( hamil.numSumTerms == numTerms );
431 
432  // check all Pauli codes are identity
433  int numPaulis = numQb * numTerms;
434  for (int i=0; i<numPaulis; i++) {
435  REQUIRE( hamil.pauliCodes[i] == PAULI_I );
436  }
437 
438  // check all term coefficients can be written to (no seg fault)
439  for (int j=0; j<numTerms; j++) {
440  hamil.termCoeffs[j] = 1;
441  REQUIRE( hamil.termCoeffs[j] == 1 );
442  }
443 
444  destroyPauliHamil(hamil);
445  }
446  SECTION( "input validation") {
447 
448  SECTION( "number of qubits" ) {
449 
450  int numQb = GENERATE( -1, 0 );
451  REQUIRE_THROWS_WITH( createPauliHamil(numQb, 1), Contains("The number of qubits and terms in the PauliHamil must be strictly positive.") );
452  }
453  SECTION( "number of terms" ) {
454 
455  int numTerms = GENERATE( -1, 0 );
456  REQUIRE_THROWS_WITH( createPauliHamil(1, numTerms), Contains("The number of qubits and terms in the PauliHamil must be strictly positive.") );
457  }
458  }
459 }

References createPauliHamil(), destroyPauliHamil(), PauliHamil::numQubits, PauliHamil::numSumTerms, PAULI_I, PauliHamil::pauliCodes, and PauliHamil::termCoeffs.

◆ TEST_CASE() [53/124]

TEST_CASE ( "createPauliHamilFromFile"  ,
""  [data_structures] 
)
See also
createPauliHamilFromFile
Author
Tyson Jones

Definition at line 467 of file test_data_structures.cpp.

467  {
468 
469  // files created & populated during the test, and deleted afterward
470  char fnPrefix[] = "temp_createPauliHamilFromFile";
471  char fn[100];
472 
473  // each test uses a unique filename (managed by master node), to avoid file IO locks
474  // (it's safe for sub-test to overwrite this, since after each test, all files
475  // with prefix fnPrefix are deleted)
476  setUniqueFilename(fn, fnPrefix);
477 
478  SECTION( "correctness" ) {
479 
480  SECTION( "general" ) {
481 
482  // for several sizes...
483  int numQb = GENERATE( 1, 5, 10, 15 );
484  int numTerms = GENERATE( 1, 10, 30 );
485  int numPaulis = numQb*numTerms;
486 
487  // create a PauliHamil with random elements
488  qreal coeffs[numTerms];
489  enum pauliOpType paulis[numPaulis];
490  setRandomPauliSum(coeffs, paulis, numQb, numTerms);
491 
492  // write the Hamiltonian to file (with trailing whitespace, and trailing newline)
493  if (QUEST_ENV.rank == 0) {
494  FILE* file = fopen(fn, "w");
495  int i=0;
496  for (int n=0; n<numTerms; n++) {
497  fprintf(file, REAL_STRING_FORMAT, coeffs[n]);
498  fprintf(file, " ");
499  for (int q=0; q<numQb; q++)
500  fprintf(file, "%d ", (int) paulis[i++]);
501  fprintf(file, "\n");
502  }
503  fprintf(file, "\n");
504  fclose(file);
505  }
507 
508  // load the file as a PauliHamil
510 
511  // check fields agree
512  REQUIRE( hamil.numQubits == numQb );
513  REQUIRE( hamil.numSumTerms == numTerms );
514 
515  // check elements agree
516  int j=0;
517  for (int n=0; n<numTerms; n++) {
518  REQUIRE( absReal(hamil.termCoeffs[n] - coeffs[n]) <= REAL_EPS );
519  for (int q=0; q<numQb; q++) {
520  REQUIRE( hamil.pauliCodes[j] == paulis[j] );
521  j++;
522  }
523  }
524 
525  destroyPauliHamil(hamil);
526  }
527  SECTION( "edge cases" ) {
528 
529  SECTION( "no trailing newline or space" ) {
530 
531  writeToFileSynch(fn, ".1 1 0 1");
532 
534  REQUIRE( hamil.numSumTerms == 1 );
535  REQUIRE( hamil.numQubits == 3 );
536 
537  destroyPauliHamil(hamil);
538  }
539  SECTION( "trailing newlines" ) {
540 
541  writeToFileSynch(fn, ".1 1 0 1\n\n\n");
542 
544  REQUIRE( hamil.numSumTerms == 1 );
545  REQUIRE( hamil.numQubits == 3 );
546 
547  destroyPauliHamil(hamil);
548  }
549  SECTION( "trailing spaces" ) {
550 
551  writeToFileSynch(fn, ".1 1 0 1 ");
552 
554  REQUIRE( hamil.numSumTerms == 1 );
555  REQUIRE( hamil.numQubits == 3 );
556 
557  destroyPauliHamil(hamil);
558  }
559  }
560  }
561  SECTION( "input validation") {
562 
563  SECTION( "number of qubits" ) {
564 
565  writeToFileSynch(fn, ".1 ");
566 
567  REQUIRE_THROWS_WITH( createPauliHamilFromFile(fn), Contains("The number of qubits") && Contains("strictly positive"));
568  }
569  SECTION( "coefficient type" ) {
570 
571  writeToFileSynch(fn, "notanumber 1 2 3");
572 
573  REQUIRE_THROWS_WITH( createPauliHamilFromFile(fn), Contains("Failed to parse") && Contains("coefficient"));
574  }
575  SECTION( "pauli code" ) {
576 
577  writeToFileSynch(fn, ".1 1 2 4"); // invalid int
578 
579  REQUIRE_THROWS_WITH( createPauliHamilFromFile(fn), Contains("invalid pauli code"));
580 
581  setUniqueFilename(fn, fnPrefix);
582  writeToFileSynch(fn, ".1 1 2 notanumber"); // invalid type
583 
584  REQUIRE_THROWS_WITH( createPauliHamilFromFile(fn), Contains("Failed to parse the next expected Pauli code"));
585  }
586  }
587 
588  // cleanup temp files
590 }

References createPauliHamilFromFile(), deleteFilesWithPrefixSynch(), destroyPauliHamil(), PauliHamil::numQubits, PauliHamil::numSumTerms, PauliHamil::pauliCodes, qreal, QUEST_ENV, QuESTEnv::rank, setRandomPauliSum(), setUniqueFilename(), syncQuESTEnv(), PauliHamil::termCoeffs, and writeToFileSynch().

◆ TEST_CASE() [54/124]

TEST_CASE ( "createQuESTEnv"  ,
""  [data_structures] 
)
See also
createQuESTEnv
Author
Tyson Jones

Definition at line 598 of file test_data_structures.cpp.

598  {
599 
600  /* there is no meaningful way to test this */
601  SUCCEED( );
602 }

◆ TEST_CASE() [55/124]

TEST_CASE ( "createQureg"  ,
""  [data_structures] 
)
See also
createQureg
Author
Tyson Jones

Definition at line 610 of file test_data_structures.cpp.

610  {
611 
612  // must be at least one amplitude per node
613  int minNumQb = calcLog2(QUEST_ENV.numRanks);
614  if (minNumQb == 0)
615  minNumQb = 1;
616 
617  SECTION( "correctness" ) {
618 
619  // try 10 valid number of qubits
620  int numQb = GENERATE_COPY( range(minNumQb, minNumQb+10) );
621  Qureg reg = createQureg(numQb, QUEST_ENV);
622 
623  // ensure elems (CPU and/or GPU) are created, and reg begins in |0>
624  QVector ref = QVector(1<<numQb);
625  ref[0] = 1; // |0>
626  REQUIRE( areEqual(reg, ref) );
627 
628  destroyQureg(reg, QUEST_ENV);
629  }
630  SECTION( "input validation") {
631 
632  SECTION( "number of qubits" ) {
633 
634  int numQb = GENERATE( -1, 0 );
635  REQUIRE_THROWS_WITH( createQureg(numQb, QUEST_ENV), Contains("Invalid number of qubits") );
636  }
637  SECTION( "number of amplitudes" ) {
638 
639  // use local QuESTEnv to safely modify
640  QuESTEnv env = QUEST_ENV;
641 
642  // too many amplitudes to store in type
643  int maxQb = (int) calcLog2(SIZE_MAX);
644  REQUIRE_THROWS_WITH( createQureg(maxQb+1, env), Contains("Too many qubits") && Contains("size_t type") );
645 
646  // too few amplitudes to distribute
647  int minQb = GENERATE_COPY( range(2,maxQb) );
648  env.numRanks = (int) pow(2, minQb);
649  int numQb = GENERATE_COPY( range(1,minQb) );
650  REQUIRE_THROWS_WITH( createQureg(numQb, env), Contains("Too few qubits") );
651  }
652  SECTION( "available memory" ) {
653 
654  /* there is no reliable way to force the malloc statements to
655  * fail, and hence trigger the matrixInit validation */
656  SUCCEED( );
657  }
658  }
659 }

References areEqual(), calcLog2(), createQureg(), destroyQureg(), QuESTEnv::numRanks, and QUEST_ENV.

◆ TEST_CASE() [56/124]

TEST_CASE ( "destroyComplexMatrixN"  ,
""  [data_structures] 
)
See also
destroyComplexMatrixN
Author
Tyson Jones

Definition at line 667 of file test_data_structures.cpp.

667  {
668 
669  SECTION( "correctness" ) {
670 
671  /* there is no meaningful way to test this */
672  SUCCEED( );
673  }
674  SECTION( "input validation" ) {
675 
676  SECTION( "matrix not created" ) {
677 
678  /* this is an artificial test case since nothing in the QuEST API
679  * automatically sets un-initialised ComplexMatrixN fields to
680  * the NULL pointer.
681  */
682  ComplexMatrixN m;
683  m.real = NULL;
684 
685  /* the error message is also somewhat unrelated, but oh well
686  */
687  REQUIRE_THROWS_WITH( destroyComplexMatrixN(m), Contains("The ComplexMatrixN was not successfully created") );
688  }
689  }
690 }

References destroyComplexMatrixN(), and ComplexMatrixN::real.

◆ TEST_CASE() [57/124]

TEST_CASE ( "destroyDiagonalOp"  ,
""  [data_structures] 
)
See also
destroyDiagonalOp
Author
Tyson Jones

Definition at line 698 of file test_data_structures.cpp.

698  {
699 
700  /* there is no meaningful way to test this */
701  SUCCEED( );
702 }

◆ TEST_CASE() [58/124]

TEST_CASE ( "destroyPauliHamil"  ,
""  [data_structures] 
)
See also
destroyPauliHamil
Author
Tyson Jones

Definition at line 710 of file test_data_structures.cpp.

710  {
711 
712  /* there is no meaningful way to test this.
713  * We e.g. cannot check that the pointers are NULL because
714  * they are not updated; this function passes the struct by value,
715  * not by reference. We also cannot reliably monitor the
716  * memory used in the heap at runtime.
717  */
718  SUCCEED( );
719 }

◆ TEST_CASE() [59/124]

TEST_CASE ( "destroyQuESTEnv"  ,
""  [data_structures] 
)
See also
destroyQuESTEnv
Author
Tyson Jones

Definition at line 727 of file test_data_structures.cpp.

727  {
728 
729  /* there is no meaningful way to test this */
730  SUCCEED( );
731 }

◆ TEST_CASE() [60/124]

TEST_CASE ( "destroyQureg"  ,
""  [data_structures] 
)
See also
destroyQureg
Author
Tyson Jones

Definition at line 739 of file test_data_structures.cpp.

739  {
740 
741  /* there is no meaningful way to test this.
742  * We e.g. cannot check that the pointers are NULL because
743  * they are not updated; this function passes the struct by value,
744  * not by reference. We also cannot reliably monitor the
745  * memory used in the heap at runtime.
746  */
747  SUCCEED( );
748 }

◆ TEST_CASE() [61/124]

TEST_CASE ( "fromComplex"  ,
""  [data_structures] 
)
See also
fromComplex
Author
Tyson Jones

Definition at line 15 of file test_data_structures.cpp.

15  {
16 
17  Complex a = {.real=.5, .imag=-.2};
18  qcomp b = fromComplex(a);
19 
20  REQUIRE( a.real == real(b) );
21  REQUIRE( a.imag == imag(b) );
22 }

References fromComplex, Complex::imag, qcomp, and Complex::real.

◆ TEST_CASE() [62/124]

TEST_CASE ( "getAmp"  ,
""  [calculations] 
)
See also
getAmp
Author
Tyson Jones

Definition at line 1272 of file test_calculations.cpp.

1272  {
1273 
1275 
1276  SECTION( "correctness" ) {
1277 
1278  SECTION( "state-vector" ) {
1279 
1280  initDebugState(vec);
1281  QVector ref = toQVector(vec);
1282 
1283  int ind = GENERATE( range(0,1<<NUM_QUBITS) );
1284  Complex amp = getAmp(vec,ind);
1285  REQUIRE( fromComplex(amp) == ref[ind] );
1286  }
1287  }
1288  SECTION( "input validation" ) {
1289 
1290  SECTION( "state index" ) {
1291 
1292  int ind = GENERATE( -1, 1<<NUM_QUBITS );
1293  REQUIRE_THROWS_WITH( getAmp(vec,ind), Contains("Invalid amplitude index") );
1294  }
1295  SECTION( "density-matrix" ) {
1296 
1298  REQUIRE_THROWS_WITH( getAmp(mat,0), Contains("valid only for state-vectors") );
1299  destroyQureg(mat, QUEST_ENV);
1300  }
1301  }
1302  destroyQureg(vec, QUEST_ENV);
1303 }

References createDensityQureg(), createQureg(), destroyQureg(), fromComplex, getAmp(), initDebugState(), NUM_QUBITS, QUEST_ENV, and toQVector().

◆ TEST_CASE() [63/124]

TEST_CASE ( "getDensityAmp"  ,
""  [calculations] 
)
See also
getDensityAmp
Author
Tyson Jones

Definition at line 1311 of file test_calculations.cpp.

1311  {
1312 
1314 
1315  SECTION( "correctness" ) {
1316 
1317  SECTION( "density-matrix" ) {
1318 
1319  initDebugState(mat);
1320  QMatrix ref = toQMatrix(mat);
1321 
1322  int row = GENERATE( range(0,1<<NUM_QUBITS) );
1323  int col = GENERATE( range(0,1<<NUM_QUBITS) );
1324 
1325  Complex amp = getDensityAmp(mat,row,col);
1326  REQUIRE( fromComplex(amp) == ref[row][col] );
1327  }
1328  }
1329  SECTION( "input validation" ) {
1330 
1331  SECTION( "state index" ) {
1332 
1333  int ind = GENERATE( -1, 1<<NUM_QUBITS );
1334  REQUIRE_THROWS_WITH( getDensityAmp(mat,ind,0), Contains("Invalid amplitude index") );
1335  REQUIRE_THROWS_WITH( getDensityAmp(mat,0,ind), Contains("Invalid amplitude index") );
1336 
1337  }
1338  SECTION( "state-vector" ) {
1339 
1341  REQUIRE_THROWS_WITH( getDensityAmp(vec,0,0), Contains("valid only for density matrices") );
1342  destroyQureg(vec, QUEST_ENV);
1343  }
1344  }
1345  destroyQureg(mat, QUEST_ENV);
1346 }

References createDensityQureg(), createQureg(), destroyQureg(), fromComplex, getDensityAmp(), initDebugState(), NUM_QUBITS, QUEST_ENV, and toQMatrix().

◆ TEST_CASE() [64/124]

TEST_CASE ( "getImagAmp"  ,
""  [calculations] 
)
See also
getImagAmp
Author
Tyson Jones

Definition at line 1354 of file test_calculations.cpp.

1354  {
1355 
1357 
1358  SECTION( "correctness" ) {
1359 
1360  SECTION( "state-vector" ) {
1361 
1362  initDebugState(vec);
1363  QVector ref = toQVector(vec);
1364 
1365  int ind = GENERATE( range(0,1<<NUM_QUBITS) );
1366  REQUIRE( getImagAmp(vec,ind) == imag(ref[ind]) );
1367  }
1368  }
1369  SECTION( "input validation" ) {
1370 
1371  SECTION( "state index" ) {
1372 
1373  int ind = GENERATE( -1, 1<<NUM_QUBITS );
1374  REQUIRE_THROWS_WITH( getImagAmp(vec,ind), Contains("Invalid amplitude index") );
1375  }
1376  SECTION( "density-matrix" ) {
1377 
1379  REQUIRE_THROWS_WITH( getImagAmp(mat,0), Contains("valid only for state-vectors") );
1380  destroyQureg(mat, QUEST_ENV);
1381  }
1382  }
1383  destroyQureg(vec, QUEST_ENV);
1384 }

References createDensityQureg(), createQureg(), destroyQureg(), getImagAmp(), initDebugState(), NUM_QUBITS, QUEST_ENV, and toQVector().

◆ TEST_CASE() [65/124]

TEST_CASE ( "getNumAmps"  ,
""  [calculations] 
)
See also
getNumAmps
Author
Tyson Jones

Definition at line 1392 of file test_calculations.cpp.

1392  {
1393 
1394  SECTION( "correctness" ) {
1395 
1396  // test >= NUM_QUBITS so as not to limit distribution size
1397  int numQb = GENERATE( range(NUM_QUBITS, NUM_QUBITS+10) );
1398 
1399  SECTION( "state-vector" ) {
1400 
1401  Qureg vec = createQureg(numQb, QUEST_ENV);
1402  REQUIRE( getNumAmps(vec) == (1<<numQb) );
1403  destroyQureg(vec, QUEST_ENV);
1404  }
1405  }
1406  SECTION( "input validation" ) {
1407 
1408  SECTION( "density-matrix" ) {
1410  REQUIRE_THROWS_WITH( getNumAmps(mat), Contains("valid only for state-vectors") );
1411  destroyQureg(mat, QUEST_ENV);
1412  }
1413  }
1414 }

References createDensityQureg(), createQureg(), destroyQureg(), getNumAmps(), NUM_QUBITS, and QUEST_ENV.

◆ TEST_CASE() [66/124]

TEST_CASE ( "getNumQubits"  ,
""  [calculations] 
)
See also
getNumQubits
Author
Tyson Jones

Definition at line 1422 of file test_calculations.cpp.

1422  {
1423 
1424  SECTION( "correctness" ) {
1425 
1426  // test >= NUM_QUBITS so as not to limit distribution size
1427  int numQb = GENERATE( range(NUM_QUBITS, NUM_QUBITS+10) );
1428 
1429  SECTION( "state-vector" ) {
1430 
1431  Qureg vec = createQureg(numQb, QUEST_ENV);
1432  REQUIRE( getNumQubits(vec) == numQb );
1433  destroyQureg(vec, QUEST_ENV);
1434  }
1435  SECTION( "density-matrix" ) {
1436 
1437  Qureg mat = createDensityQureg(numQb, QUEST_ENV);
1438  REQUIRE( getNumQubits(mat) == numQb );
1439  destroyQureg(mat, QUEST_ENV);
1440  }
1441  }
1442  SECTION( "input validation" ) {
1443 
1444  // no validation
1445  SUCCEED();
1446  }
1447 }

References createDensityQureg(), createQureg(), destroyQureg(), getNumQubits(), NUM_QUBITS, and QUEST_ENV.

◆ TEST_CASE() [67/124]

TEST_CASE ( "getProbAmp"  ,
""  [calculations] 
)
See also
getProbAmp
Author
Tyson Jones

Definition at line 1455 of file test_calculations.cpp.

1455  {
1456 
1458 
1459  SECTION( "correctness" ) {
1460 
1461  SECTION( "state-vector" ) {
1462 
1463  initDebugState(vec);
1464  QVector ref = toQVector(vec);
1465 
1466  int ind = GENERATE( range(0,1<<NUM_QUBITS) );
1467  qreal refCalc = pow(abs(ref[ind]), 2);
1468  REQUIRE( getProbAmp(vec,ind) == Approx(refCalc) );
1469  }
1470  }
1471  SECTION( "input validation" ) {
1472 
1473  SECTION( "state index" ) {
1474 
1475  int ind = GENERATE( -1, 1<<NUM_QUBITS );
1476  REQUIRE_THROWS_WITH( getProbAmp(vec,ind), Contains("Invalid amplitude index") );
1477  }
1478  SECTION( "density-matrix" ) {
1479 
1481  REQUIRE_THROWS_WITH( getProbAmp(mat,0), Contains("valid only for state-vectors") );
1482  destroyQureg(mat, QUEST_ENV);
1483  }
1484  }
1485  destroyQureg(vec, QUEST_ENV);
1486 }

References createDensityQureg(), createQureg(), destroyQureg(), getProbAmp(), initDebugState(), NUM_QUBITS, qreal, QUEST_ENV, and toQVector().

◆ TEST_CASE() [68/124]

TEST_CASE ( "getRealAmp"  ,
""  [calculations] 
)
See also
getRealAmp
Author
Tyson Jones

Definition at line 1494 of file test_calculations.cpp.

1494  {
1495 
1497 
1498  SECTION( "correctness" ) {
1499 
1500  SECTION( "state-vector" ) {
1501 
1502  initDebugState(vec);
1503  QVector ref = toQVector(vec);
1504 
1505  int ind = GENERATE( range(0,1<<NUM_QUBITS) );
1506  REQUIRE( getRealAmp(vec,ind) == real(ref[ind]) );
1507  }
1508  }
1509  SECTION( "input validation" ) {
1510 
1511  SECTION( "state index" ) {
1512 
1513  int ind = GENERATE( -1, 1<<NUM_QUBITS );
1514  REQUIRE_THROWS_WITH( getRealAmp(vec,ind), Contains("Invalid amplitude index") );
1515  }
1516  SECTION( "density-matrix" ) {
1517 
1519  REQUIRE_THROWS_WITH( getRealAmp(mat,0), Contains("valid only for state-vectors") );
1520  destroyQureg(mat, QUEST_ENV);
1521  }
1522  }
1523  destroyQureg(vec, QUEST_ENV);
1524 }

References createDensityQureg(), createQureg(), destroyQureg(), getRealAmp(), initDebugState(), NUM_QUBITS, QUEST_ENV, and toQVector().

◆ TEST_CASE() [69/124]

TEST_CASE ( "getStaticComplexMatrixN"  ,
""  [data_structures] 
)
See also
getStaticComplexMatrixN
Author
Tyson Jones

Definition at line 30 of file test_data_structures.cpp.

30  {
31 
32  /* use of this function is illegal in C++ */
33  SUCCEED( );
34 }

◆ TEST_CASE() [70/124]

TEST_CASE ( "hadamard"  ,
""  [unitaries] 
)
See also
hadamard
Author
Tyson Jones

Definition at line 814 of file test_unitaries.cpp.

814  {
815 
816  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
817  qreal a = 1/sqrt(2);
818  QMatrix op{{a,a},{a,-a}};
819 
820  SECTION( "correctness" ) {
821 
822  int target = GENERATE( range(0,NUM_QUBITS) );
823 
824  SECTION( "state-vector ") {
825 
826  hadamard(quregVec, target);
827  applyReferenceOp(refVec, target, op);
828  REQUIRE( areEqual(quregVec, refVec) );
829  }
830  SECTION( "density-matrix" ) {
831 
832  hadamard(quregMatr, target);
833  applyReferenceOp(refMatr, target, op);
834  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
835  }
836  }
837  SECTION( "input validation" ) {
838 
839  SECTION( "qubit indices" ) {
840 
841  int target = GENERATE( -1, NUM_QUBITS );
842  REQUIRE_THROWS_WITH( hadamard(quregVec, target), Contains("Invalid target") );
843  }
844  }
845  CLEANUP_TEST( quregVec, quregMatr );
846 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, hadamard(), NUM_QUBITS, PREPARE_TEST, and qreal.

◆ TEST_CASE() [71/124]

TEST_CASE ( "initBlankState"  ,
""  [state_initialisations] 
)
See also
initBlankState
Author
Tyson Jones

Definition at line 90 of file test_state_initialisations.cpp.

90  {
91 
94 
95  SECTION( "correctness" ) {
96 
97  SECTION( "state-vector" ) {
98 
99  initBlankState(vec);
100  REQUIRE( areEqual(vec, QVector(1<<NUM_QUBITS)) );
101  }
102  SECTION( "density-matrix" ) {
103 
104  initBlankState(mat);
105  REQUIRE( areEqual(mat, getZeroMatrix(1<<NUM_QUBITS)) );
106  }
107  }
108  SECTION( "input validation" ) {
109 
110  // no user validation
111  SUCCEED( );
112  }
113  destroyQureg(vec, QUEST_ENV);
114  destroyQureg(mat, QUEST_ENV);
115 }

References areEqual(), createDensityQureg(), createQureg(), destroyQureg(), getZeroMatrix(), initBlankState(), NUM_QUBITS, and QUEST_ENV.

◆ TEST_CASE() [72/124]

TEST_CASE ( "initClassicalState"  ,
""  [state_initialisations] 
)
See also
initClassicalState
Author
Tyson Jones

Definition at line 123 of file test_state_initialisations.cpp.

123  {
124 
127 
128  SECTION( "correctness" ) {
129 
130  int numInds = (1<<NUM_QUBITS);
131  int ind = GENERATE_COPY( range(0,numInds) );
132 
133  SECTION( "state-vector" ) {
134 
135  initClassicalState(vec, ind);
136  QVector vecRef = QVector(1<<NUM_QUBITS);
137  vecRef[ind] = 1;
138  REQUIRE( areEqual(vec, vecRef) );
139  }
140  SECTION( "density-matrix" ) {
141 
142  initClassicalState(mat, ind);
143  QMatrix matRef = getZeroMatrix(1<<NUM_QUBITS);
144  matRef[ind][ind] = 1;
145  REQUIRE( areEqual(mat, matRef) );
146  }
147  }
148  SECTION( "input validation" ) {
149 
150  SECTION( "state index" ) {
151 
152  int ind = GENERATE( -1, (1<<NUM_QUBITS) );
153  REQUIRE_THROWS_WITH( initClassicalState(vec, ind), Contains("Invalid state index") );
154  }
155  }
156  destroyQureg(vec, QUEST_ENV);
157  destroyQureg(mat, QUEST_ENV);
158 }

References areEqual(), createDensityQureg(), createQureg(), destroyQureg(), getZeroMatrix(), initClassicalState(), NUM_QUBITS, and QUEST_ENV.

◆ TEST_CASE() [73/124]

TEST_CASE ( "initComplexMatrixN"  ,
""  [data_structures] 
)
See also
initComplexMatrixN
Author
Tyson Jones

Definition at line 756 of file test_data_structures.cpp.

756  {
757 
758  /* use of this function is illegal in C++ */
759  SUCCEED( );
760 }

◆ TEST_CASE() [74/124]

TEST_CASE ( "initDiagonalOp"  ,
""  [data_structures] 
)
See also
initDiagonalOp
Author
Tyson Jones

Definition at line 768 of file test_data_structures.cpp.

768  {
769 
770  // must be at least one amplitude per node
771  int minNumQb = calcLog2(QUEST_ENV.numRanks);
772  if (minNumQb == 0)
773  minNumQb = 1;
774 
775  SECTION( "correctness" ) {
776 
777  // try 10 valid number of qubits
778  int numQb = GENERATE_COPY( range(minNumQb, minNumQb+10) );
780 
781  long long int len = (1LL << numQb);
782  qreal reals[len];
783  qreal imags[len];
784  long long int n;
785  for (n=0; n<len; n++) {
786  reals[n] = (qreal) n;
787  imags[n] = (qreal) -2*n; // (n - 2n i)
788  }
789  initDiagonalOp(op, reals, imags);
790 
791  // check that op.real and op.imag were modified...
792  REQUIRE( areEqual(toQVector(op), reals, imags) );
793 
794  // and also that GPU real and imag were modified
795  // via if it modifies an all-unity state-vec correctly
796  Qureg qureg = createQureg(numQb, QUEST_ENV);
797  for (long long int i=0; i<qureg.numAmpsPerChunk; i++) {
798  qureg.stateVec.real[i] = 1;
799  qureg.stateVec.imag[i] = 1;
800  }
801  copyStateToGPU(qureg);
802 
803  QVector prodRef = toQMatrix(op) * toQVector(qureg);
804 
805  // (n - 2n i) * (1 + 1i) = 3n - n*i
806  applyDiagonalOp(qureg, op);
807  copyStateFromGPU(qureg);
808  QVector result = toQVector(qureg);
809  REQUIRE( areEqual(prodRef, result) );
810 
811  destroyQureg(qureg, QUEST_ENV);
813  }
814 }

References applyDiagonalOp(), areEqual(), calcLog2(), copyStateFromGPU(), copyStateToGPU(), createDiagonalOp(), createQureg(), destroyDiagonalOp(), destroyQureg(), initDiagonalOp(), Qureg::numAmpsPerChunk, QuESTEnv::numRanks, qreal, QUEST_ENV, Qureg::stateVec, toQMatrix(), and toQVector().

◆ TEST_CASE() [75/124]

TEST_CASE ( "initDiagonalOpFromPauliHamil"  ,
""  [data_structures] 
)
See also
initDiagonalOpFromPauliHamil
Author
Tyson Jones

Definition at line 822 of file test_data_structures.cpp.

822  {
823 
824  // distributed diagonal op must contain at least one amplitude per node
825  int minNumQb = calcLog2(QUEST_ENV.numRanks);
826  if (minNumQb == 0)
827  minNumQb = 1;
828 
829  SECTION( "correctness" ) {
830 
831  // try (at most) 10 valid number of qubits (even for validation)
832  int numQb = GENERATE_COPY( range(minNumQb, min(10,minNumQb+10)) );
834 
835  // try several sized random all-Z Hamiltonians
836  int numTerms = GENERATE_COPY( 1, numQb, 5*numQb );
837  PauliHamil hamil = createPauliHamil(numQb, numTerms);
839 
840  initDiagonalOpFromPauliHamil(op, hamil);
841  REQUIRE( areEqual(toQMatrix(op), toQMatrix(hamil)) );
842 
843  destroyPauliHamil(hamil);
845  }
846  SECTION( "input validation" ) {
847 
848  SECTION( "hamiltonian parameters" ) {
849 
850  DiagonalOp op = createDiagonalOp(minNumQb, QUEST_ENV);
851  PauliHamil hamil;
852 
853  hamil.numQubits = GENERATE( -1, 0 );
854  hamil.numSumTerms = 1;
855  REQUIRE_THROWS_WITH( initDiagonalOpFromPauliHamil(op, hamil), Contains("number of qubits") && Contains("strictly positive") );
856 
857  hamil.numQubits = minNumQb;
858  hamil.numSumTerms = GENERATE( -1, 0 );
859  REQUIRE_THROWS_WITH( initDiagonalOpFromPauliHamil(op, hamil), Contains("terms") && Contains("strictly positive") );
860 
862  }
863  SECTION( "mismatching dimensions" ) {
864 
865  int numQbA = minNumQb+1;
866  int numQbB = GENERATE_COPY( numQbA-1, numQbA+1 );
867 
868  DiagonalOp op = createDiagonalOp(numQbA, QUEST_ENV);
869  PauliHamil hamil = createPauliHamil(numQbB, 1);
870 
871  REQUIRE_THROWS_WITH( initDiagonalOpFromPauliHamil(op, hamil), Contains("Pauli Hamiltonian and diagonal operator have different, incompatible dimensions") );
872 
874  destroyPauliHamil(hamil);
875  }
876  SECTION( "pauli codes" ) {
877 
878  DiagonalOp op = createDiagonalOp(minNumQb, QUEST_ENV);
879  PauliHamil hamil = createPauliHamil(minNumQb, 5); // all I
880 
881  // make only one code invalid
882  int numCodes = minNumQb * hamil.numSumTerms;
883  int ind = GENERATE_COPY( range(0,numCodes) );
884  hamil.pauliCodes[ind] = GENERATE( PAULI_X, PAULI_Y );
885 
886  REQUIRE_THROWS_WITH( initDiagonalOpFromPauliHamil(op, hamil), Contains("contained operators other than PAULI_Z and PAULI_I") );
887 
889  destroyPauliHamil(hamil);
890  }
891  }
892 }

References areEqual(), calcLog2(), createDiagonalOp(), createPauliHamil(), destroyDiagonalOp(), destroyPauliHamil(), initDiagonalOpFromPauliHamil(), PauliHamil::numQubits, QuESTEnv::numRanks, PauliHamil::numSumTerms, PAULI_X, PAULI_Y, PauliHamil::pauliCodes, QUEST_ENV, setRandomDiagPauliHamil(), and toQMatrix().

◆ TEST_CASE() [76/124]

TEST_CASE ( "initPauliHamil"  ,
""  [data_structures] 
)
See also
initPauliHamil
Author
Tyson Jones

Definition at line 900 of file test_data_structures.cpp.

900  {
901 
902  SECTION( "correctness" ) {
903 
904  PauliHamil hamil = createPauliHamil(3, 2);
905 
906  qreal coeffs[] = {-5, 5};
907  enum pauliOpType codes[] = {
910  initPauliHamil(hamil, coeffs, codes);
911 
912  // check everything written correctly
913  for (int t=0; t<2; t++) {
914  REQUIRE( coeffs[t] == hamil.termCoeffs[t] );
915  for (int q=0; q<3; q++) {
916  int ind = 3*t+q;
917  REQUIRE( codes[ind] == hamil.pauliCodes[ind] );
918  }
919  }
920 
921  destroyPauliHamil(hamil);
922  }
923  SECTION( "input validation" ) {
924 
925  SECTION( "parameters" ) {
926 
927  // parameters checked before codes, so safe to leave un-initialised
928  qreal coeffs[1];
929  enum pauliOpType codes[1];
930  PauliHamil hamil;
931 
932  hamil.numQubits = GENERATE( -1, 0 );
933  hamil.numSumTerms = 1;
934  REQUIRE_THROWS_WITH( initPauliHamil(hamil, coeffs, codes), Contains("number of qubits") && Contains("strictly positive") );
935 
936  hamil.numQubits = 1;
937  hamil.numSumTerms = GENERATE( -1, 0 );
938  REQUIRE_THROWS_WITH( initPauliHamil(hamil, coeffs, codes), Contains("terms") && Contains("strictly positive") );
939  }
940  SECTION( "Pauli codes" ) {
941 
942  int numQb = 3;
943  int numTerms = 2;
944  int numCodes = numQb * numTerms;
945  qreal coeffs[numTerms];
946  enum pauliOpType codes[numCodes];
947 
948  // make only one code invalid
949  for (int i=0; i<numCodes; i++)
950  codes[i] = PAULI_I;
951  codes[GENERATE_COPY( range(0,numCodes) )] = (pauliOpType) GENERATE( -1, 4 );
952 
953  PauliHamil hamil = createPauliHamil(numQb, numTerms);
954  REQUIRE_THROWS_WITH( initPauliHamil(hamil, coeffs, codes), Contains("Invalid Pauli code") );
955  destroyPauliHamil(hamil);
956  }
957  }
958 }

References createPauliHamil(), destroyPauliHamil(), initPauliHamil(), PauliHamil::numQubits, PauliHamil::numSumTerms, PAULI_I, PAULI_X, PAULI_Y, PAULI_Z, PauliHamil::pauliCodes, qreal, and PauliHamil::termCoeffs.

◆ TEST_CASE() [77/124]

TEST_CASE ( "initPlusState"  ,
""  [state_initialisations] 
)
See also
initPlusState
Author
Tyson Jones

Definition at line 166 of file test_state_initialisations.cpp.

166  {
167 
170 
171  SECTION( "correctness" ) {
172 
173  SECTION( "state-vector" ) {
174 
175  // |+> = 1/sqrt(N^2) sum_i |i>
176  // = 1/sqrt(N^2) {1, ..., 1}
177  initPlusState(vec);
178  QVector vecRef = QVector(1<<NUM_QUBITS);
179  for (size_t i=0; i<vecRef.size(); i++)
180  vecRef[i] = 1./sqrt(pow(2,NUM_QUBITS));
181  REQUIRE( areEqual(vec, vecRef) );
182  }
183  SECTION( "density-matrix" ) {
184 
185  // |+><+| = 1/sqrt(N^2) sum_i |i> 1/sqrt(N^2) sum_j <j|
186  // = 1/(N^2) sum_{ij} |i><j|
187  // = 1/(N^2) {{1, ..., 1}, ...}
188  initPlusState(mat);
189  QMatrix matRef = getZeroMatrix(1<<NUM_QUBITS);
190  for (size_t i=0; i<matRef.size(); i++)
191  for (size_t j=0; j<matRef.size(); j++)
192  matRef[i][j] = 1./pow(2, NUM_QUBITS);
193  REQUIRE( areEqual(mat, matRef) );
194  }
195  }
196  SECTION( "input validation" ) {
197 
198  // no user validation
199  SUCCEED( );
200  }
201  destroyQureg(vec, QUEST_ENV);
202  destroyQureg(mat, QUEST_ENV);
203 }

References areEqual(), createDensityQureg(), createQureg(), destroyQureg(), getZeroMatrix(), initPlusState(), NUM_QUBITS, and QUEST_ENV.

◆ TEST_CASE() [78/124]

TEST_CASE ( "initPureState"  ,
""  [state_initialisations] 
)
See also
initPureState
Author
Tyson Jones

Definition at line 211 of file test_state_initialisations.cpp.

211  {
212 
215 
216  SECTION( "correctness" ) {
217 
218  SECTION( "state-vector" ) {
219 
220  /* state-vector version just performs cloneQureg */
221 
223 
224  // make sure states start differently
225  initDebugState(vec1);
226  initBlankState(vec2);
227  REQUIRE( !areEqual(vec1, vec2) );
228 
229  // make sure vec2 is overwritten with vec1
230  QVector copy1 = toQVector(vec1);
231  initPureState(vec2, vec1);
232  REQUIRE( areEqual(vec1, vec2) );
233 
234  // make sure vec1 was not modified
235  REQUIRE( areEqual(vec1, copy1) );
236 
237  destroyQureg(vec2, QUEST_ENV);
238  }
239  SECTION( "density-matrix" ) {
240 
241  /* density matrix version initialises matrix in |pure><pure| */
242 
243  initDebugState(vec1); // |vec1> = sum_i a_i |i>
244  QVector copy1 = toQVector(vec1);
245 
246  // make sure mat1 is modified correctly
247  initBlankState(mat1);
248  initPureState(mat1, vec1); // mat1 = |vec1><vec1| = sum_{ij} a_i a_j* |i><j|
249 
250  QMatrix matRef = getZeroMatrix(1<<NUM_QUBITS);
251  for (size_t i=0; i<matRef.size(); i++)
252  for (size_t j=0; j<matRef.size(); j++)
253  matRef[i][j] = copy1[i] * conj(copy1[j]);
254  REQUIRE( areEqual(mat1, matRef) );
255 
256  // make sure vec1 was not modified
257  REQUIRE( areEqual(vec1, copy1) );
258  }
259  }
260  SECTION( "input validation" ) {
261 
262  SECTION( "qureg types" ) {
263 
264  // density matrix as second arg is illegal (regardless of first arg)
265  REQUIRE_THROWS_WITH( initPureState(vec1, mat1), Contains("Second argument must be a state-vector") );
266  REQUIRE_THROWS_WITH( initPureState(mat1, mat1), Contains("Second argument must be a state-vector") );
267  }
268  SECTION( "qureg dimensions" ) {
269 
270  Qureg vec2 = createQureg(NUM_QUBITS + 1, QUEST_ENV);
271  REQUIRE_THROWS_WITH( initPureState(vec1, vec2), Contains("Dimensions") && Contains("don't match") );
272  REQUIRE_THROWS_WITH( initPureState(mat1, vec2), Contains("Dimensions") && Contains("don't match") );
273  destroyQureg(vec2, QUEST_ENV);
274  }
275  }
276  destroyQureg(vec1, QUEST_ENV);
277  destroyQureg(mat1, QUEST_ENV);
278 }

References areEqual(), createDensityQureg(), createQureg(), destroyQureg(), getZeroMatrix(), initBlankState(), initDebugState(), initPureState(), NUM_QUBITS, QUEST_ENV, and toQVector().

◆ TEST_CASE() [79/124]

TEST_CASE ( "initStateFromAmps"  ,
""  [state_initialisations] 
)
See also
initStateFromAmps
Author
Tyson Jones

Definition at line 286 of file test_state_initialisations.cpp.

286  {
287 
290 
291  SECTION( "correctness" ) {
292 
293  SECTION( "state-vector" ) {
294 
295  // create random (unnormalised) vector
296  QVector vecRef = getRandomQVector(1<<NUM_QUBITS);
297 
298  qreal ampsRe[vec.numAmpsTotal];
299  qreal ampsIm[vec.numAmpsTotal];
300  for (size_t i=0; i<vecRef.size(); i++) {
301  ampsRe[i] = real(vecRef[i]);
302  ampsIm[i] = imag(vecRef[i]);
303  }
304 
305  initStateFromAmps(vec, ampsRe, ampsIm);
306  REQUIRE( areEqual(vec, vecRef) );
307  }
308  SECTION( "density-matrix" ) {
309 
310  // create random (unnormalised) matrix
311  QMatrix matRef = getRandomQMatrix(1<<NUM_QUBITS);
312 
313  qreal ampsRe[mat.numAmpsTotal];
314  qreal ampsIm[mat.numAmpsTotal];
315 
316  // populate column-wise
317  long long int i=0;
318  for (size_t c=0; c<matRef.size(); c++) {
319  for (size_t r=0; r<matRef.size(); r++) {
320  ampsRe[i] = real(matRef[r][c]);
321  ampsIm[i] = imag(matRef[r][c]);
322  i++;
323  }
324  }
325 
326  initStateFromAmps(mat, ampsRe, ampsIm);
327  REQUIRE( areEqual(mat, matRef) );
328  }
329  }
330  destroyQureg(vec, QUEST_ENV);
331  destroyQureg(mat, QUEST_ENV);
332 }

References areEqual(), createDensityQureg(), createQureg(), destroyQureg(), getRandomQMatrix(), getRandomQVector(), initStateFromAmps(), NUM_QUBITS, Qureg::numAmpsTotal, qreal, and QUEST_ENV.

◆ TEST_CASE() [80/124]

TEST_CASE ( "initZeroState"  ,
""  [state_initialisations] 
)
See also
initZeroState
Author
Tyson Jones

Definition at line 340 of file test_state_initialisations.cpp.

340  {
341 
344 
345  SECTION( "correctness" ) {
346 
347  SECTION( "state-vector" ) {
348 
349  initBlankState(vec);
350  initZeroState(vec);
351 
352  QVector refVec = QVector(vec.numAmpsTotal);
353  refVec[0] = 1;
354  REQUIRE( areEqual(vec, refVec) );
355  }
356  SECTION( "density-matrix" ) {
357 
358  initBlankState(mat);
359  initZeroState(mat);
360 
361  QMatrix refMat = getZeroMatrix(1<<mat.numQubitsRepresented);
362  refMat[0][0] = 1;
363  REQUIRE( areEqual(mat, refMat) );
364  }
365  }
366  SECTION( "input validation" ) {
367 
368  // no input validation
369  SUCCEED( );
370  }
371  destroyQureg(vec, QUEST_ENV);
372  destroyQureg(mat, QUEST_ENV);
373 }

References areEqual(), createDensityQureg(), createQureg(), destroyQureg(), getZeroMatrix(), initBlankState(), initZeroState(), NUM_QUBITS, Qureg::numAmpsTotal, Qureg::numQubitsRepresented, and QUEST_ENV.

◆ TEST_CASE() [81/124]

TEST_CASE ( "measure"  ,
""  [gates] 
)
See also
measure
Author
Tyson Jones

Definition at line 121 of file test_gates.cpp.

121  {
122 
125 
126  SECTION( "correctness" ) {
127 
128  int qubit = GENERATE( range(0,NUM_QUBITS) );
129 
130  // repeat these random tests 10 times on every qubit
131  GENERATE( range(0,10) );
132 
133  SECTION( "state-vector" ) {
134 
136  toQureg(vec, vecRef);
137 
138  int outcome = measure(vec, qubit);
139  REQUIRE( (outcome == 0 || outcome == 1) );
140 
141  // calculate prob of this outcome
142  qreal prob = 0;
143  for (size_t ind=0; ind<vecRef.size(); ind++) {
144  int bit = (ind >> qubit) & 1; // target-th bit
145  if (bit == outcome)
146  prob += pow(abs(vecRef[ind]), 2);
147  }
148 
149  REQUIRE( prob > REAL_EPS );
150 
151  // renormalise by the outcome prob
152  for (size_t ind=0; ind<vecRef.size(); ind++) {
153  int bit = (ind >> qubit) & 1; // target-th bit
154  if (bit == outcome)
155  vecRef[ind] /= sqrt(prob);
156  else
157  vecRef[ind] = 0;
158  }
159  REQUIRE( areEqual(vec, vecRef) );
160  }
161  SECTION( "density-matrix" ) {
162 
164  toQureg(mat, matRef);
165 
166  int outcome = measure(mat, qubit);
167  REQUIRE( (outcome == 0 || outcome == 1) );
168 
169  // compute prob of this outcome
170  qreal prob = 0;
171  for (size_t ind=0; ind<matRef.size(); ind++) {
172  int bit = (ind >> qubit) & 1; // qubit-th bit
173  if (bit == outcome)
174  prob += real(matRef[ind][ind]);
175  }
176 
177  REQUIRE( prob > REAL_EPS );
178 
179  // renorm (/prob) every |*outcome*><*outcome*| state, zeroing all others
180  for (size_t r=0; r<matRef.size(); r++) {
181  for (size_t c=0; c<matRef.size(); c++) {
182  int ketBit = (c >> qubit) & 1;
183  int braBit = (r >> qubit) & 1;
184 
185  if (ketBit == outcome && braBit == outcome)
186  matRef[r][c] /= prob;
187  else
188  matRef[r][c] = 0;
189  }
190  }
191 
192  REQUIRE( areEqual(mat, matRef) );
193  }
194  }
195  SECTION( "input validation" ) {
196 
197  SECTION( "qubit index" ) {
198 
199  int qubit = GENERATE( -1, NUM_QUBITS );
200  REQUIRE_THROWS_WITH( measure(vec, qubit), Contains("Invalid target qubit") );
201  }
202  }
203  destroyQureg(vec, QUEST_ENV);
204  destroyQureg(mat, QUEST_ENV);
205 }

References areEqual(), createDensityQureg(), createQureg(), destroyQureg(), getRandomDensityMatrix(), getRandomStateVector(), measure(), NUM_QUBITS, qreal, QUEST_ENV, and toQureg().

◆ TEST_CASE() [82/124]

TEST_CASE ( "measureWithStats"  ,
""  [gates] 
)
See also
measureWithStats
Author
Tyson Jones

Definition at line 213 of file test_gates.cpp.

213  {
214 
217 
218  SECTION( "correctness" ) {
219 
220  int qubit = GENERATE( range(0,NUM_QUBITS) );
221 
222  // repeat these random tests 10 times on every qubit
223  GENERATE( range(0,10) );
224 
225  SECTION( "state-vector" ) {
226 
228  toQureg(vec, vecRef);
229 
230  qreal res;
231  int outcome = measureWithStats(vec, qubit, &res);
232  REQUIRE( (outcome == 0 || outcome == 1) );
233 
234  // calculate prob of this outcome
235  qreal prob = 0;
236  for (size_t ind=0; ind<vecRef.size(); ind++) {
237  int bit = (ind >> qubit) & 1; // target-th bit
238  if (bit == outcome)
239  prob += pow(abs(vecRef[ind]), 2);
240  }
241 
242  REQUIRE( prob == Approx(res) );
243 
244  // renormalise by the outcome prob
245  for (size_t ind=0; ind<vecRef.size(); ind++) {
246  int bit = (ind >> qubit) & 1; // target-th bit
247  if (bit == outcome)
248  vecRef[ind] /= sqrt(prob);
249  else
250  vecRef[ind] = 0;
251  }
252  REQUIRE( areEqual(vec, vecRef) );
253  }
254  SECTION( "density-matrix" ) {
255 
257  toQureg(mat, matRef);
258 
259  qreal res;
260  int outcome = measureWithStats(mat, qubit, &res);
261  REQUIRE( (outcome == 0 || outcome == 1) );
262 
263  // compute prob of this outcome
264  qreal prob = 0;
265  for (size_t ind=0; ind<matRef.size(); ind++) {
266  int bit = (ind >> qubit) & 1; // qubit-th bit
267  if (bit == outcome)
268  prob += real(matRef[ind][ind]);
269  }
270 
271  REQUIRE( prob == Approx(res) );
272 
273  // renorm (/prob) every |*outcome*><*outcome*| state, zeroing all others
274  for (size_t r=0; r<matRef.size(); r++) {
275  for (size_t c=0; c<matRef.size(); c++) {
276  int ketBit = (c >> qubit) & 1;
277  int braBit = (r >> qubit) & 1;
278 
279  if (ketBit == outcome && braBit == outcome)
280  matRef[r][c] /= prob;
281  else
282  matRef[r][c] = 0;
283  }
284  }
285 
286  REQUIRE( areEqual(mat, matRef) );
287  }
288  }
289  SECTION( "input validation" ) {
290 
291  SECTION( "qubit index" ) {
292 
293  int qubit = GENERATE( -1, NUM_QUBITS );
294  qreal res;
295  REQUIRE_THROWS_WITH( measureWithStats(vec, qubit, &res), Contains("Invalid target qubit") );
296  }
297  }
298  destroyQureg(vec, QUEST_ENV);
299  destroyQureg(mat, QUEST_ENV);
300 }

References areEqual(), createDensityQureg(), createQureg(), destroyQureg(), getRandomDensityMatrix(), getRandomStateVector(), measureWithStats(), NUM_QUBITS, qreal, QUEST_ENV, and toQureg().

◆ TEST_CASE() [83/124]

TEST_CASE ( "mixDamping"  ,
""  [decoherence] 
)
See also
mixDamping
Author
Tyson Jones

Definition at line 23 of file test_decoherence.cpp.

23  {
24 
25  PREPARE_TEST(qureg, ref);
26 
27  SECTION( "correctness" ) {
28 
29  int target = GENERATE( range(0,NUM_QUBITS) );
30  qreal prob = getRandomReal(0, 1);
31  mixDamping(qureg, target, prob);
32 
33  // ref -> kraus0 ref kraus0^dagger + kraus1 ref kraus1^dagger
34  QMatrix kraus0{{1,0},{0,sqrt(1-prob)}};
35  QMatrix rho0 = ref;
36  applyReferenceOp(rho0, target, kraus0);
37  QMatrix kraus1{{0,sqrt(prob)},{0,0}};
38  QMatrix rho1 = ref;
39  applyReferenceOp(rho1, target, kraus1);
40  ref = rho0 + rho1;
41 
42  REQUIRE( areEqual(qureg, ref) );
43  }
44  SECTION( "validation ") {
45 
46  SECTION( "qubit index" ) {
47 
48  int target = GENERATE( -1, NUM_QUBITS );
49  REQUIRE_THROWS_WITH( mixDamping(qureg, target, 0), Contains("Invalid target") );
50 
51  }
52  SECTION( "probability" ) {
53 
54  REQUIRE_THROWS_WITH( mixDamping(qureg, 0, -.1), Contains("Probabilities") );
55  REQUIRE_THROWS_WITH( mixDamping(qureg, 0, 1.1), Contains("Probabilities") );
56  }
57  SECTION( "density-matrix" ) {
58 
60  REQUIRE_THROWS_WITH( mixDamping(vec, 0, 0), Contains("density matrices") );
61  destroyQureg(vec, QUEST_ENV);
62  }
63  }
64  destroyQureg(qureg, QUEST_ENV);
65 }

References applyReferenceOp(), areEqual(), createQureg(), destroyQureg(), getRandomReal(), mixDamping(), NUM_QUBITS, PREPARE_TEST, qreal, and QUEST_ENV.

◆ TEST_CASE() [84/124]

TEST_CASE ( "mixDensityMatrix"  ,
""  [decoherence] 
)
See also
mixDensityMatrix
Author
Tyson Jones

Definition at line 73 of file test_decoherence.cpp.

73  {
74 
77  initDebugState(qureg1);
78  initDebugState(qureg2);
79  QMatrix ref1 = toQMatrix(qureg1);
80  QMatrix ref2 = toQMatrix(qureg2);
81 
82  SECTION( "correctness" ) {
83 
84  // test p in {0, 1} and 10 random values in (0,1)
85  qreal prob = GENERATE( 0., 1., take(10, random(0.,1.)) );
86  mixDensityMatrix(qureg1, prob, qureg2);
87 
88  // ensure target qureg modified correctly
89  ref1 = (1-prob)*ref1 + (prob)*ref2;
90  REQUIRE( areEqual(qureg1, ref1) );
91 
92  // enure other qureg was not modified
93  REQUIRE( areEqual(qureg2, ref2) );
94  }
95  SECTION( "input validation" ) {
96 
97  SECTION( "probabilities") {
98 
99  qreal prob = GENERATE( -0.1, 1.1 );
100  REQUIRE_THROWS_WITH( mixDensityMatrix(qureg1, prob, qureg2), Contains("Probabilities") );
101  }
102  SECTION( "density matrices" ) {
103 
104  // one is statevec
106  REQUIRE_THROWS_WITH( mixDensityMatrix(qureg1, 0, state1), Contains("density matrices") );
107  REQUIRE_THROWS_WITH( mixDensityMatrix(state1, 0, qureg1), Contains("density matrices") );
108 
109  // both are statevec
111  REQUIRE_THROWS_WITH( mixDensityMatrix(state1, 0, state2), Contains("density matrices") );
112 
113  destroyQureg(state1, QUEST_ENV);
114  destroyQureg(state2, QUEST_ENV);
115  }
116  SECTION( "matching dimensions" ) {
117 
119  REQUIRE_THROWS_WITH( mixDensityMatrix(qureg1, 0, qureg3), Contains("Dimensions") );
120  REQUIRE_THROWS_WITH( mixDensityMatrix(qureg3, 0, qureg1), Contains("Dimensions") );
121  destroyQureg(qureg3, QUEST_ENV);
122  }
123  }
124  destroyQureg(qureg1, QUEST_ENV);
125  destroyQureg(qureg2, QUEST_ENV);
126 }

References areEqual(), createDensityQureg(), createQureg(), destroyQureg(), initDebugState(), mixDensityMatrix(), NUM_QUBITS, Qureg::numQubitsRepresented, qreal, QUEST_ENV, and toQMatrix().

◆ TEST_CASE() [85/124]

TEST_CASE ( "mixDephasing"  ,
""  [decoherence] 
)
See also
mixDephasing
Author
Tyson Jones

Definition at line 134 of file test_decoherence.cpp.

134  {
135 
136  PREPARE_TEST(qureg, ref);
137 
138  SECTION( "correctness " ) {
139 
140  int target = GENERATE( range(0,NUM_QUBITS) );
141  qreal prob = getRandomReal(0, 1/2.);
142  mixDephasing(qureg, target, prob);
143 
144  // ref -> (1 - prob) ref + prob Z ref Z
145  QMatrix phaseRef = ref;
146  applyReferenceOp(phaseRef, target, QMatrix{{1,0},{0,-1}}); // Z ref Z
147  ref = ((1 - prob) * ref) + (prob * phaseRef);
148 
149  REQUIRE( areEqual(qureg, ref) );
150  }
151  SECTION( "validation ") {
152 
153  SECTION( "qubit index" ) {
154 
155  int target = GENERATE( -1, NUM_QUBITS );
156  REQUIRE_THROWS_WITH( mixDephasing(qureg, target, 0), Contains("Invalid target") );
157 
158  }
159  SECTION( "probability" ) {
160 
161  REQUIRE_THROWS_WITH( mixDephasing(qureg, 0, -.1), Contains("Probabilities") );
162  REQUIRE_THROWS_WITH( mixDephasing(qureg, 0, .6), Contains("probability") && Contains("cannot exceed 1/2") );
163  }
164  SECTION( "density-matrix" ) {
165 
167  REQUIRE_THROWS_WITH( mixDephasing(vec, 0, 0), Contains("density matrices") );
168  destroyQureg(vec, QUEST_ENV);
169  }
170  }
171  destroyQureg(qureg, QUEST_ENV);
172 }

References applyReferenceOp(), areEqual(), createQureg(), destroyQureg(), getRandomReal(), mixDephasing(), NUM_QUBITS, PREPARE_TEST, qreal, and QUEST_ENV.

◆ TEST_CASE() [86/124]

TEST_CASE ( "mixDepolarising"  ,
""  [decoherence] 
)
See also
mixDepolarising
Author
Tyson Jones

Definition at line 180 of file test_decoherence.cpp.

180  {
181 
182  PREPARE_TEST(qureg, ref);
183 
184  SECTION( "correctness " ) {
185 
186  int target = GENERATE( range(0,NUM_QUBITS) );
187  qreal prob = getRandomReal(0, 3/4.);
188  mixDepolarising(qureg, target, prob);
189 
190  QMatrix xRef = ref;
191  applyReferenceOp(xRef, target, QMatrix{{0,1},{1,0}}); // X ref X
192  QMatrix yRef = ref;
193  applyReferenceOp(yRef, target, QMatrix{{0,-qcomp(0,1)},{qcomp(0,1),0}}); // Y ref Y
194  QMatrix zRef = ref;
195  applyReferenceOp(zRef, target, QMatrix{{1,0},{0,-1}}); // Z ref Z
196  ref = ((1 - prob) * ref) + ((prob/3.) * ( xRef + yRef + zRef));
197 
198  REQUIRE( areEqual(qureg, ref) );
199  }
200  SECTION( "validation ") {
201 
202  SECTION( "qubit index" ) {
203 
204  int target = GENERATE( -1, NUM_QUBITS );
205  REQUIRE_THROWS_WITH( mixDepolarising(qureg, target, 0), Contains("Invalid target") );
206 
207  }
208  SECTION( "probability" ) {
209 
210  REQUIRE_THROWS_WITH( mixDepolarising(qureg, 0, -.1), Contains("Probabilities") );
211  REQUIRE_THROWS_WITH( mixDepolarising(qureg, 0, .76), Contains("probability") && Contains("cannot exceed 3/4") );
212  }
213  SECTION( "density-matrix" ) {
214 
216  REQUIRE_THROWS_WITH( mixDepolarising(vec, 0, 0), Contains("density matrices") );
217  destroyQureg(vec, QUEST_ENV);
218  }
219  }
220  destroyQureg(qureg, QUEST_ENV);
221 }

References applyReferenceOp(), areEqual(), createQureg(), destroyQureg(), getRandomReal(), mixDepolarising(), NUM_QUBITS, PREPARE_TEST, qcomp, qreal, and QUEST_ENV.

◆ TEST_CASE() [87/124]

TEST_CASE ( "mixKrausMap"  ,
""  [decoherence] 
)
See also
mixKrausMap
Author
Tyson Jones

Definition at line 520 of file test_decoherence.cpp.

520  {
521 
522  PREPARE_TEST(qureg, ref);
523 
524  SECTION( "correctness" ) {
525 
526  int target = GENERATE( range(0,NUM_QUBITS) );
527  int numOps = GENERATE( range(1,5) ); // max 4 inclusive
528  std::vector<QMatrix> matrs = getRandomKrausMap(1, numOps);
529 
530  ComplexMatrix2 ops[numOps];
531  for (int i=0; i<numOps; i++)
532  ops[i] = toComplexMatrix2(matrs[i]);
533  mixKrausMap(qureg, target, ops, numOps);
534 
535  // set ref -> K_i ref K_i^dagger
536  QMatrix matrRefs[numOps];
537  for (int i=0; i<numOps; i++) {
538  matrRefs[i] = ref;
539  applyReferenceOp(matrRefs[i], target, matrs[i]);
540  }
541  ref = getZeroMatrix(ref.size());
542  for (int i=0; i<numOps; i++)
543  ref += matrRefs[i];
544 
545  REQUIRE( areEqual(qureg, ref, 10*REAL_EPS) );
546  }
547  SECTION( "input validation" ) {
548 
549  SECTION( "number of operators" ) {
550 
551  int numOps = GENERATE( 0, 5 );
552  REQUIRE_THROWS_WITH( mixKrausMap(qureg, 0, NULL, numOps), Contains("operators") );
553  }
554  SECTION( "trace preserving" ) {
555 
556  // valid Kraus map
557  int numOps = GENERATE( range(1,5) ); // max 4 inclusive
558  std::vector<QMatrix> matrs = getRandomKrausMap(1, numOps);
559  ComplexMatrix2 ops[numOps];
560  for (int i=0; i<numOps; i++)
561  ops[i] = toComplexMatrix2(matrs[i]);
562 
563  // make invalid
564  ops[GENERATE_REF( range(0,numOps) )].real[0][0] = 0;
565  REQUIRE_THROWS_WITH( mixKrausMap(qureg, 0, ops, numOps), Contains("trace preserving") );
566 
567  }
568  SECTION( "qubit index" ) {
569 
570  int target = GENERATE( -1, NUM_QUBITS );
571  REQUIRE_THROWS_WITH( mixKrausMap(qureg, target, NULL, 1), Contains("Invalid target qubit") );
572  }
573  SECTION( "density-matrix" ) {
574 
576  REQUIRE_THROWS_WITH( mixKrausMap(vec, 0, NULL, 1), Contains("density matrices") );
577  destroyQureg(vec, QUEST_ENV);
578  }
579  SECTION( "operators fit in node" ) {
580 
581  qureg.numAmpsPerChunk = 3; // min 4
582  REQUIRE_THROWS_WITH( mixKrausMap(qureg, 0, NULL, 1), Contains("targets too many qubits") );
583  }
584  }
585  destroyQureg(qureg, QUEST_ENV);
586 }

References applyReferenceOp(), areEqual(), createQureg(), destroyQureg(), getRandomKrausMap(), getZeroMatrix(), mixKrausMap(), NUM_QUBITS, PREPARE_TEST, QUEST_ENV, ComplexMatrix2::real, and toComplexMatrix2().

◆ TEST_CASE() [88/124]

TEST_CASE ( "mixMultiQubitKrausMap"  ,
""  [decoherence] 
)
See also
mixMultiQubitKrausMap
Author
Tyson Jones

Definition at line 229 of file test_decoherence.cpp.

229  {
230 
231  PREPARE_TEST(qureg, ref);
232 
233  // figure out max-num (inclusive) targs allowed by hardware backend
234  // (each node must contain as 2^(2*numTargs) amps)
235  int maxNumTargs = calcLog2(qureg.numAmpsPerChunk) / 2;
236 
237  SECTION( "correctness" ) {
238 
239  /* note that this function incurs a stack overhead when numTargs < 4,
240  * and a heap overhead when numTargs >= 4
241  */
242 
243  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) ); // inclusive upper bound
244 
245  // note this is very expensive to try every arrangement (2 min runtime for numTargs=5 alone)
246  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
247 
248  // try the min and max number of operators, and 2 random numbers
249  // (there are way too many to try all!)
250  int maxNumOps = (2*numTargs)*(2*numTargs);
251  int numOps = GENERATE_COPY( 1, maxNumOps, take(2,random(1,maxNumOps)) );
252 
253  // use a new random map
254  std::vector<QMatrix> matrs = getRandomKrausMap(numTargs, numOps);
255 
256  // create map in QuEST datatypes
257  ComplexMatrixN ops[numOps];
258  for (int i=0; i<numOps; i++) {
259  ops[i] = createComplexMatrixN(numTargs);
260  toComplexMatrixN(matrs[i], ops[i]);
261  }
262 
263  mixMultiQubitKrausMap(qureg, targs, numTargs, ops, numOps);
264 
265  // set ref -> K_i ref K_i^dagger
266  QMatrix matrRefs[numOps];
267  for (int i=0; i<numOps; i++) {
268  matrRefs[i] = ref;
269  applyReferenceOp(matrRefs[i], targs, numTargs, matrs[i]);
270  }
271  ref = getZeroMatrix(ref.size());
272  for (int i=0; i<numOps; i++)
273  ref += matrRefs[i];
274 
275  REQUIRE( areEqual(qureg, ref, 1E2*REAL_EPS) );
276 
277  // cleanup QuEST datatypes
278  for (int i=0; i<numOps; i++)
279  destroyComplexMatrixN(ops[i]);
280  }
281  SECTION( "input validation" ) {
282 
283  SECTION( "repetition of target" ) {
284 
285  // make valid targets
286  int targs[NUM_QUBITS];
287  for (int i=0; i<NUM_QUBITS; i++)
288  targs[i] = i;
289 
290  // duplicate one
291  int badInd = GENERATE( range(0,NUM_QUBITS) );
292  int copyInd = GENERATE_COPY( filter([=](int i){ return i!=badInd; }, range(0,NUM_QUBITS)) );
293  targs[badInd] = targs[copyInd];
294 
295  REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(qureg, targs, NUM_QUBITS, NULL, 1), Contains("target qubits") && Contains("unique") );
296  }
297  SECTION( "qubit indices" ) {
298 
299  // make valid targets
300  int targs[NUM_QUBITS];
301  for (int i=0; i<NUM_QUBITS; i++)
302  targs[i] = i;
303 
304  // make one invalid
305  targs[GENERATE( range(0,NUM_QUBITS) )] = GENERATE( -1, NUM_QUBITS );
306 
307  REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(qureg, targs, NUM_QUBITS, NULL, 1), Contains("Invalid target qubit") );
308  }
309  SECTION( "number of operators" ) {
310 
311  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
312  int maxNumOps = (2*numTargs)*(2*numTargs);
313  int numOps = GENERATE_REF( -1, 0, maxNumOps + 1 );
314 
315  // make valid targets to avoid triggering target validation
316  int targs[numTargs];
317  for (int i=0; i<numTargs; i++)
318  targs[i] = i;
319  REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(qureg, targs, numTargs, NULL, numOps), Contains("operators may be specified") );
320  }
321  SECTION( "initialisation of operators" ) {
322 
323  /* compilers don't auto-initialise to NULL; the below circumstance
324  * only really occurs when 'malloc' returns NULL in createComplexMatrixN,
325  * which actually triggers its own validation. Hence this test is useless
326  * currently.
327  */
328 
329  int numTargs = NUM_QUBITS;
330  int numOps = (2*numTargs)*(2*numTargs);
331 
332  // no need to initialise ops, but set their attribs correct to avoid triggering other validation
333  ComplexMatrixN ops[numOps];
334  for (int i=0; i<numOps; i++)
335  ops[i].numQubits = numTargs;
336 
337  // make one of the max-ops explicitly NULL
338  ops[GENERATE_COPY( range(0,numTargs) )].real = NULL;
339 
340  // make valid targets to avoid triggering target validation
341  int targs[numTargs];
342  for (int i=0; i<numTargs; i++)
343  targs[i] = i;
344 
345  REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(qureg, targs, numTargs, ops, numOps), Contains("ComplexMatrixN") && Contains("created") );
346  }
347  SECTION( "dimension of operators" ) {
348 
349  // make valid (dimension-wise) max-qubits Kraus map
350  int numTargs = NUM_QUBITS;
351  int numOps = (2*numTargs)*(2*numTargs);
352  ComplexMatrixN ops[numOps];
353  for (int i=0; i<numOps; i++)
354  ops[i] = createComplexMatrixN(numTargs);
355 
356  // make one have wrong-dimensions
357  int badInd = GENERATE_COPY( range(0,numTargs) );
358  destroyComplexMatrixN(ops[badInd]);
359  ops[badInd] = createComplexMatrixN(numTargs - 1);
360 
361  // make valid targets to avoid triggering target validation
362  int targs[numTargs];
363  for (int i=0; i<numTargs; i++)
364  targs[i] = i;
365 
366  REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(qureg, targs, numTargs, ops, numOps), Contains("same number of qubits") );
367 
368  for (int i=0; i<numOps; i++)
369  destroyComplexMatrixN(ops[i]);
370  }
371  SECTION( "trace preserving" ) {
372 
373  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
374  int maxNumOps = (2*numTargs) * (2*numTargs);
375  int numOps = GENERATE_COPY( 1, 2, maxNumOps );
376 
377  // generate a valid map
378  std::vector<QMatrix> matrs = getRandomKrausMap(numTargs, numOps);
379  ComplexMatrixN ops[numOps];
380  for (int i=0; i<numOps; i++) {
381  ops[i] = createComplexMatrixN(numTargs);
382  toComplexMatrixN(matrs[i], ops[i]);
383  }
384 
385  // make only one invalid
386  ops[GENERATE_REF( range(0,numOps) )].real[0][0] = 0;
387 
388  // make valid targets to avoid triggering target validation
389  int targs[numTargs];
390  for (int i=0; i<numTargs; i++)
391  targs[i] = i;
392 
393  REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(qureg, targs, numTargs, ops, numOps), Contains("trace preserving") );
394 
395  for (int i=0; i<numOps; i++)
396  destroyComplexMatrixN(ops[i]);
397  }
398  SECTION( "density-matrix" ) {
399 
400  Qureg statevec = createQureg(NUM_QUBITS, QUEST_ENV);
401 
402  // make valid targets to avoid triggering target validation
403  int targs[NUM_QUBITS];
404  for (int i=0; i<NUM_QUBITS; i++)
405  targs[i] = i;
406 
407  REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(statevec, targs, NUM_QUBITS, NULL, 1), Contains("valid only for density matrices") );
408  destroyQureg(statevec, QUEST_ENV);
409 
410  }
411  SECTION( "operator fits in node" ) {
412 
413  // each node requires (2 numTargs)^2 amplitudes
414  int minAmps = (2*NUM_QUBITS) * (2*NUM_QUBITS);
415 
416  // make valid targets to avoid triggering target validation
417  int targs[NUM_QUBITS];
418  for (int i=0; i<NUM_QUBITS; i++)
419  targs[i] = i;
420 
421  // make a simple Identity map
423  for (int i=0; i<(1<<NUM_QUBITS); i++)
424  ops[0].real[i][i] = 1;
425 
426  // fake a smaller qureg
427  qureg.numAmpsPerChunk = minAmps - 1;
428  REQUIRE_THROWS_WITH( mixMultiQubitKrausMap(qureg, targs, NUM_QUBITS, ops, 1), Contains("targets too many qubits") && Contains("cannot all fit") );
429 
430  destroyComplexMatrixN(ops[0]);
431  }
432  }
433  destroyQureg(qureg, QUEST_ENV);
434 }

References applyReferenceOp(), areEqual(), calcLog2(), createComplexMatrixN(), createQureg(), destroyComplexMatrixN(), destroyQureg(), getRandomKrausMap(), getZeroMatrix(), mixMultiQubitKrausMap(), NUM_QUBITS, PREPARE_TEST, QUEST_ENV, ComplexMatrixN::real, sublists(), and toComplexMatrixN().

◆ TEST_CASE() [89/124]

TEST_CASE ( "mixPauli"  ,
""  [decoherence] 
)
See also
mixPauli
Author
Tyson Jones

Definition at line 442 of file test_decoherence.cpp.

442  {
443 
444  PREPARE_TEST(qureg, ref);
445 
446  SECTION( "correctness" ) {
447 
448  int target = GENERATE( range(0,NUM_QUBITS) );
449 
450  // randomly generate valid pauli-error probabilities
451  qreal probs[3];
452  qreal max0 = 1/2.; // satisfies p1 < 1 - py
453  probs[0] = getRandomReal(0, max0);
454  qreal max1 = (max0 - probs[0])/2.; // p2 can use half of p1's "unused space"
455  probs[1] = getRandomReal(0, max1);
456  qreal max2 = (max1 - probs[1])/2.; // p3 can use half of p2's "unused space"
457  probs[2] = getRandomReal(0, max2);
458 
459  // uniformly randomly assign probs (bound to target)
460  int inds[3] = {0,1,2};
461  std::shuffle(inds,inds+3, std::default_random_engine(1E5 * target));
462  qreal probX = probs[inds[0]]; // seed:target shows no variation
463  qreal probY = probs[inds[1]];
464  qreal probZ = probs[inds[2]];
465 
466  mixPauli(qureg, target, probX, probY, probZ);
467 
468  QMatrix xRef = ref;
469  applyReferenceOp(xRef, target, QMatrix{{0,1},{1,0}}); // X ref X
470  QMatrix yRef = ref;
471  applyReferenceOp(yRef, target, QMatrix{{0,-qcomp(0,1)},{qcomp(0,1),0}}); // Y ref Y
472  QMatrix zRef = ref;
473  applyReferenceOp(zRef, target, QMatrix{{1,0},{0,-1}}); // Z ref Z
474  ref = ((1 - probX - probY - probZ) * ref) +
475  (probX * xRef) + (probY * yRef) + (probZ * zRef);
476 
477  REQUIRE( areEqual(qureg, ref) );
478  }
479  SECTION( "input validation" ) {
480 
481  SECTION( "qubit index" ) {
482 
483  int target = GENERATE( -1, NUM_QUBITS );
484  REQUIRE_THROWS_WITH( mixPauli(qureg, target, 0, 0, 0), Contains("Invalid target") );
485 
486  }
487  SECTION( "probability" ) {
488 
489  int target = 0;
490 
491  // probs clearly must be in [0, 1]
492  REQUIRE_THROWS_WITH( mixPauli(qureg, target, -.1, 0, 0), Contains("Probabilities") );
493  REQUIRE_THROWS_WITH( mixPauli(qureg, target, 0, -.1, 0), Contains("Probabilities") );
494  REQUIRE_THROWS_WITH( mixPauli(qureg, target, 0, 0, -.1), Contains("Probabilities") );
495 
496  // max single-non-zero-prob is 0.5
497  REQUIRE_THROWS_WITH( mixPauli(qureg, target, .6, 0, 0), Contains("cannot exceed the probability") );
498  REQUIRE_THROWS_WITH( mixPauli(qureg, target, 0, .6, 0), Contains("cannot exceed the probability") );
499  REQUIRE_THROWS_WITH( mixPauli(qureg, target, 0, 0, .6), Contains("cannot exceed the probability") );
500 
501  // must satisfy px, py, pz < 1 - px - py - pz
502  REQUIRE_THROWS_WITH( mixPauli(qureg, target, .3, .3, .3), Contains("cannot exceed the probability") );
503  }
504  SECTION( "density-matrix" ) {
505 
507  REQUIRE_THROWS_WITH( mixPauli(vec, 0, 0, 0, 0), Contains("density matrices") );
508  destroyQureg(vec, QUEST_ENV);
509  }
510  }
511  destroyQureg(qureg, QUEST_ENV);
512 }

References applyReferenceOp(), areEqual(), createQureg(), destroyQureg(), getRandomReal(), mixPauli(), NUM_QUBITS, PREPARE_TEST, qcomp, qreal, and QUEST_ENV.

◆ TEST_CASE() [90/124]

TEST_CASE ( "mixTwoQubitDephasing"  ,
""  [decoherence] 
)
See also
mixTwoQubitDephasing
Author
Tyson Jones

Definition at line 594 of file test_decoherence.cpp.

594  {
595 
596  PREPARE_TEST(qureg, ref);
597 
598  SECTION( "correctness" ) {
599 
600  int targ1 = GENERATE( range(0,NUM_QUBITS) );
601  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
602  qreal prob = getRandomReal(0, 3/4.);
603 
604  mixTwoQubitDephasing(qureg, targ1, targ2, prob);
605 
606  // ref -> (1 - prob) ref + prob/3 (Z1 ref Z1 + Z2 ref Z2 + Z1 Z2 ref Z1 Z2)
607  QMatrix zMatr{{1,0},{0,-1}};
608  QMatrix z1Ref = ref;
609  applyReferenceOp(z1Ref, targ1, zMatr); // Z1 ref Z1
610  QMatrix z2Ref = ref;
611  applyReferenceOp(z2Ref, targ2, zMatr); // Z2 ref Z2
612  QMatrix z1z2Ref = ref;
613  applyReferenceOp(z1z2Ref, targ1, zMatr);
614  applyReferenceOp(z1z2Ref, targ2, zMatr); // Z1 Z2 ref Z1 Z2
615  ref = ((1 - prob) * ref) + (prob/3.) * (z1Ref + z2Ref + z1z2Ref);
616 
617  REQUIRE( areEqual(qureg, ref) );
618  }
619  SECTION( "input validation" ) {
620 
621  SECTION( "qubit indices" ) {
622 
623  int targ = GENERATE( -1, NUM_QUBITS );
624  REQUIRE_THROWS_WITH( mixTwoQubitDephasing(qureg, 0, targ, 0), Contains("Invalid target") );
625  REQUIRE_THROWS_WITH( mixTwoQubitDephasing(qureg, targ, 0, 0), Contains("Invalid target") );
626  }
627  SECTION( "target collision" ) {
628 
629  int targ = GENERATE( range(0,NUM_QUBITS) );
630  REQUIRE_THROWS_WITH( mixTwoQubitDephasing(qureg, targ, targ, 0), Contains("target") && Contains("unique") );
631  }
632  SECTION( "probability" ) {
633 
634  REQUIRE_THROWS_WITH( mixTwoQubitDephasing(qureg, 0, 1, -.1), Contains("Probabilities") );
635  REQUIRE_THROWS_WITH( mixTwoQubitDephasing(qureg, 0, 1, 3/4. + .01), Contains("probability") && Contains("cannot exceed 3/4") );
636  }
637  SECTION( "density-matrix" ) {
638 
640  REQUIRE_THROWS_WITH( mixTwoQubitDephasing(vec, 0, 1, 0), Contains("density matrices") );
641  destroyQureg(vec, QUEST_ENV);
642  }
643  }
644  destroyQureg(qureg, QUEST_ENV);
645 }

References applyReferenceOp(), areEqual(), createQureg(), destroyQureg(), getRandomReal(), mixTwoQubitDephasing(), NUM_QUBITS, PREPARE_TEST, qreal, and QUEST_ENV.

◆ TEST_CASE() [91/124]

TEST_CASE ( "mixTwoQubitDepolarising"  ,
""  [decoherence] 
)
See also
mixTwoQubitDepolarising
Author
Tyson Jones

Definition at line 653 of file test_decoherence.cpp.

653  {
654 
655  PREPARE_TEST(qureg, ref);
656 
657  SECTION( "correctness" ) {
658 
659  int targ1 = GENERATE( range(0,NUM_QUBITS) );
660  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
661  qreal prob = getRandomReal(0, 15/16.);
662 
663  mixTwoQubitDepolarising(qureg, targ1, targ2, prob);
664 
665  QMatrix paulis[4] = {
666  QMatrix{{1,0},{0,1}}, // I
667  QMatrix{{0,1},{1,0}}, // X
668  QMatrix{{0,-qcomp(0,1)},{qcomp(0,1),0}}, // Y
669  QMatrix{{1,0},{0,-1}} // Z
670  };
671 
672  int targs[2] = {targ1, targ2};
673  QMatrix refInit = ref;
674  ref = (1 - (16/15.)*prob) * ref;
675  for (int i=0; i<4; i++) {
676  for (int j=0; j<4; j++) {
677  QMatrix term = refInit;
678  applyReferenceOp(term, targs, 2,
679  getKroneckerProduct(paulis[i], paulis[j]));
680  ref += (prob/15.) * term;
681  }
682  }
683 
684  REQUIRE( areEqual(qureg, ref, 1E4*REAL_EPS) );
685  }
686  SECTION( "input validation" ) {
687 
688  SECTION( "qubit indices" ) {
689 
690  int targ = GENERATE( -1, NUM_QUBITS );
691  REQUIRE_THROWS_WITH( mixTwoQubitDepolarising(qureg, 0, targ, 0), Contains("Invalid target") );
692  REQUIRE_THROWS_WITH( mixTwoQubitDepolarising(qureg, targ, 0, 0), Contains("Invalid target") );
693  }
694  SECTION( "target collision" ) {
695 
696  int targ = GENERATE( range(0,NUM_QUBITS) );
697  REQUIRE_THROWS_WITH( mixTwoQubitDepolarising(qureg, targ, targ, 0), Contains("target") && Contains("unique") );
698  }
699  SECTION( "probability" ) {
700 
701  REQUIRE_THROWS_WITH( mixTwoQubitDepolarising(qureg, 0, 1, -.1), Contains("Probabilities") );
702  REQUIRE_THROWS_WITH( mixTwoQubitDepolarising(qureg, 0, 1, 15/16. + .01), Contains("probability") && Contains("cannot exceed 15/16") );
703  }
704  SECTION( "density-matrix" ) {
705 
707  REQUIRE_THROWS_WITH( mixTwoQubitDepolarising(vec, 0, 1, 0), Contains("density matrices") );
708  destroyQureg(vec, QUEST_ENV);
709  }
710  }
711  destroyQureg(qureg, QUEST_ENV);
712 }

References applyReferenceOp(), areEqual(), createQureg(), destroyQureg(), getKroneckerProduct(), getRandomReal(), mixTwoQubitDepolarising(), NUM_QUBITS, PREPARE_TEST, qcomp, qreal, and QUEST_ENV.

◆ TEST_CASE() [92/124]

TEST_CASE ( "mixTwoQubitKrausMap"  ,
""  [decoherence] 
)
See also
mixTwoQubitKrausMap
Author
Tyson Jones

Definition at line 720 of file test_decoherence.cpp.

720  {
721 
722  PREPARE_TEST(qureg, ref);
723 
724  SECTION( "correctness" ) {
725 
726  int targ1 = GENERATE( range(0,NUM_QUBITS) );
727  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
728  int numOps = GENERATE( range(1,17) ); // max 16 inclusive
729  std::vector<QMatrix> matrs = getRandomKrausMap(2, numOps);
730 
731  ComplexMatrix4 ops[numOps];
732  for (int i=0; i<numOps; i++)
733  ops[i] = toComplexMatrix4(matrs[i]);
734  mixTwoQubitKrausMap(qureg, targ1, targ2, ops, numOps);
735 
736  // set ref -> K_i ref K_i^dagger
737  int targs[2] = {targ1, targ2};
738  QMatrix matrRefs[numOps];
739  for (int i=0; i<numOps; i++) {
740  matrRefs[i] = ref;
741  applyReferenceOp(matrRefs[i], targs, 2, matrs[i]);
742  }
743  ref = getZeroMatrix(ref.size());
744  for (int i=0; i<numOps; i++)
745  ref += matrRefs[i];
746 
747  REQUIRE( areEqual(qureg, ref, 10*REAL_EPS) );
748  }
749  SECTION( "input validation" ) {
750 
751  SECTION( "number of operators" ) {
752 
753  int numOps = GENERATE( 0, 17 );
754  REQUIRE_THROWS_WITH( mixTwoQubitKrausMap(qureg, 0,1, NULL, numOps), Contains("operators") );
755  }
756  SECTION( "trace preserving" ) {
757 
758  // valid Kraus map
759  int numOps = GENERATE( range(1,16) );
760  std::vector<QMatrix> matrs = getRandomKrausMap(2, numOps);
761  ComplexMatrix4 ops[numOps];
762  for (int i=0; i<numOps; i++)
763  ops[i] = toComplexMatrix4(matrs[i]);
764 
765  // make only one of the ops at a time invalid
766  ops[GENERATE_REF( range(0,numOps) )].real[0][0] = 0;
767  REQUIRE_THROWS_WITH( mixTwoQubitKrausMap(qureg, 0,1, ops, numOps), Contains("trace preserving") );
768  }
769  SECTION( "target collision" ) {
770 
771  int target = GENERATE( range(0,NUM_QUBITS) );
772  REQUIRE_THROWS_WITH( mixTwoQubitKrausMap(qureg, target, target, NULL, 1), Contains("target qubits") && Contains("unique") );
773  }
774  SECTION( "qubit index" ) {
775 
776  int target = GENERATE( -1, NUM_QUBITS );
777  REQUIRE_THROWS_WITH( mixTwoQubitKrausMap(qureg, 0,target, NULL, 1), Contains("Invalid target qubit") );
778  REQUIRE_THROWS_WITH( mixTwoQubitKrausMap(qureg, target,0, NULL, 1), Contains("Invalid target qubit") );
779  }
780  SECTION( "density-matrix" ) {
781 
783  REQUIRE_THROWS_WITH( mixTwoQubitKrausMap(vec, 0,1, NULL, 1), Contains("density matrices") );
784  destroyQureg(vec, QUEST_ENV);
785  }
786  SECTION( "operators fit in node" ) {
787 
788  qureg.numAmpsPerChunk = 15; // min 16
789  REQUIRE_THROWS_WITH( mixTwoQubitKrausMap(qureg, 0,1, NULL, 1), Contains("targets too many qubits") );
790  }
791  }
792  destroyQureg(qureg, QUEST_ENV);
793 }

References applyReferenceOp(), areEqual(), createQureg(), destroyQureg(), getRandomKrausMap(), getZeroMatrix(), mixTwoQubitKrausMap(), NUM_QUBITS, PREPARE_TEST, QUEST_ENV, ComplexMatrix4::real, and toComplexMatrix4().

◆ TEST_CASE() [93/124]

TEST_CASE ( "multiControlledMultiQubitNot"  ,
""  [unitaries] 
)
See also
multiControlledMultiQubitNot
Author
Tyson Jones

Definition at line 854 of file test_unitaries.cpp.

854  {
855 
856  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
857 
858  SECTION( "correctness" ) {
859 
860  // try all possible numbers of targets and controls
861  int numTargs = GENERATE_COPY( range(1,NUM_QUBITS) ); // leave space for 1 ctrl
862  int maxNumCtrls = NUM_QUBITS - numTargs;
863  int numCtrls = GENERATE_COPY( range(1,maxNumCtrls+1) );
864 
865  // generate all possible valid qubit arrangements
866  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
867  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, targs, numTargs) );
868 
869  // for each qubit arrangement, use a new random unitary
870  QMatrix notOp{{0, 1},{1,0}};
871 
872  SECTION( "state-vector" ) {
873 
874  multiControlledMultiQubitNot(quregVec, ctrls, numCtrls, targs, numTargs);
875  for (int t=0; t<numTargs; t++)
876  applyReferenceOp(refVec, ctrls, numCtrls, targs[t], notOp);
877 
878  REQUIRE( areEqual(quregVec, refVec) );
879  }
880  SECTION( "density-matrix" ) {
881 
882  multiControlledMultiQubitNot(quregMatr, ctrls, numCtrls, targs, numTargs);
883  for (int t=0; t<numTargs; t++)
884  applyReferenceOp(refMatr, ctrls, numCtrls, targs[t], notOp);
885 
886  REQUIRE( areEqual(quregMatr, refMatr) );
887  }
888  }
889  SECTION( "input validation" ) {
890 
891  SECTION( "number of targets" ) {
892 
893  // there cannot be more targets than qubits in register
894  // (numTargs=NUM_QUBITS is caught elsewhere, because that implies ctrls are invalid)
895  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
896  int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
897  int ctrls[] = {0};
898  REQUIRE_THROWS_WITH( multiControlledMultiQubitNot(quregVec, ctrls, 1, targs, numTargs), Contains("Invalid number of target"));
899  }
900  SECTION( "repetition in targets" ) {
901 
902  int ctrls[] = {0};
903  int numTargs = 3;
904  int targs[] = {1,2,2};
905  REQUIRE_THROWS_WITH( multiControlledMultiQubitNot(quregVec, ctrls, 1, targs, numTargs), Contains("target") && Contains("unique"));
906  }
907  SECTION( "number of controls" ) {
908 
909  int numCtrls = GENERATE( -1, 0, NUM_QUBITS, NUM_QUBITS+1 );
910  int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
911  int targs[1] = {0};
912  REQUIRE_THROWS_WITH( multiControlledMultiQubitNot(quregVec, ctrls, numCtrls, targs, 1), Contains("Invalid number of control"));
913  }
914  SECTION( "repetition in controls" ) {
915 
916  int ctrls[] = {0,1,1};
917  int targs[] = {3};
918  REQUIRE_THROWS_WITH( multiControlledMultiQubitNot(quregVec, ctrls, 3, targs, 1), Contains("control") && Contains("unique"));
919  }
920  SECTION( "control and target collision" ) {
921 
922  int ctrls[] = {0,1,2};
923  int targs[] = {3,1,4};
924  REQUIRE_THROWS_WITH( multiControlledMultiQubitNot(quregVec, ctrls, 3, targs, 3), Contains("Control") && Contains("target") && Contains("disjoint"));
925  }
926  SECTION( "qubit indices" ) {
927 
928  // valid inds
929  int numQb = 2;
930  int qb1[2] = {0,1};
931  int qb2[2] = {2,3};
932 
933  // make qb1 invalid
934  int inv = GENERATE( -1, NUM_QUBITS );
935  qb1[GENERATE_COPY(range(0,numQb))] = inv;
936 
937  REQUIRE_THROWS_WITH( multiControlledMultiQubitNot(quregVec, qb1, numQb, qb2, numQb), Contains("Invalid control") );
938  REQUIRE_THROWS_WITH( multiControlledMultiQubitNot(quregVec, qb2, numQb, qb1, numQb), Contains("Invalid target") );
939  }
940  }
941  CLEANUP_TEST( quregVec, quregMatr );
942 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, multiControlledMultiQubitNot(), NUM_QUBITS, PREPARE_TEST, and sublists().

◆ TEST_CASE() [94/124]

TEST_CASE ( "multiControlledMultiQubitUnitary"  ,
""  [unitaries] 
)
See also
multiControlledMultiQubitUnitary
Author
Tyson Jones

Definition at line 950 of file test_unitaries.cpp.

950  {
951 
952  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
953 
954  // figure out max-num targs (inclusive) allowed by hardware backend
955  int maxNumTargs = calcLog2(quregVec.numAmpsPerChunk);
956  if (maxNumTargs >= NUM_QUBITS)
957  maxNumTargs = NUM_QUBITS - 1; // leave room for min-number of control qubits
958 
959  SECTION( "correctness" ) {
960 
961  // try all possible numbers of targets and controls
962  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
963  int maxNumCtrls = NUM_QUBITS - numTargs;
964  int numCtrls = GENERATE_COPY( range(1,maxNumCtrls+1) );
965 
966  // generate all possible valid qubit arrangements
967  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
968  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, targs, numTargs) );
969 
970  // for each qubit arrangement, use a new random unitary
971  QMatrix op = getRandomUnitary(numTargs);
972  ComplexMatrixN matr = createComplexMatrixN(numTargs);
973  toComplexMatrixN(op, matr);
974 
975  SECTION( "state-vector" ) {
976 
977  multiControlledMultiQubitUnitary(quregVec, ctrls, numCtrls, targs, numTargs, matr);
978  applyReferenceOp(refVec, ctrls, numCtrls, targs, numTargs, op);
979  REQUIRE( areEqual(quregVec, refVec) );
980  }
981  SECTION( "density-matrix" ) {
982 
983  multiControlledMultiQubitUnitary(quregMatr, ctrls, numCtrls, targs, numTargs, matr);
984  applyReferenceOp(refMatr, ctrls, numCtrls, targs, numTargs, op);
985  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
986  }
987  destroyComplexMatrixN(matr);
988  }
989  SECTION( "input validation" ) {
990 
991  SECTION( "number of targets" ) {
992 
993  // there cannot be more targets than qubits in register
994  // (numTargs=NUM_QUBITS is caught elsewhere, because that implies ctrls are invalid)
995  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
996  int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
997  int ctrls[] = {0};
998  ComplexMatrixN matr = createComplexMatrixN(NUM_QUBITS+1); // prevent seg-fault
999  toComplexMatrixN(getRandomUnitary(NUM_QUBITS+1), matr); // ensure unitary
1000 
1001  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, numTargs, matr), Contains("Invalid number of target"));
1002  destroyComplexMatrixN(matr);
1003  }
1004  SECTION( "repetition in targets" ) {
1005 
1006  int ctrls[] = {0};
1007  int numTargs = 3;
1008  int targs[] = {1,2,2};
1009  ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
1010  toComplexMatrixN(getRandomUnitary(numTargs), matr); // ensure unitary
1011 
1012  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, numTargs, matr), Contains("target") && Contains("unique"));
1013  destroyComplexMatrixN(matr);
1014  }
1015  SECTION( "number of controls" ) {
1016 
1017  int numCtrls = GENERATE( -1, 0, NUM_QUBITS, NUM_QUBITS+1 );
1018  int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1019  int targs[1] = {0};
1021  toComplexMatrixN(getRandomUnitary(1), matr); // ensure unitary
1022 
1023  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, numCtrls, targs, 1, matr), Contains("Invalid number of control"));
1024  destroyComplexMatrixN(matr);
1025  }
1026  SECTION( "repetition in controls" ) {
1027 
1028  int ctrls[] = {0,1,1};
1029  int targs[] = {3};
1031  toComplexMatrixN(getRandomUnitary(1), matr); // ensure unitary
1032 
1033  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 3, targs, 1, matr), Contains("control") && Contains("unique"));
1034  destroyComplexMatrixN(matr);
1035  }
1036  SECTION( "control and target collision" ) {
1037 
1038  int ctrls[] = {0,1,2};
1039  int targs[] = {3,1,4};
1041  toComplexMatrixN(getRandomUnitary(3), matr); // ensure unitary
1042 
1043  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 3, targs, 3, matr), Contains("Control") && Contains("target") && Contains("disjoint"));
1044  destroyComplexMatrixN(matr);
1045  }
1046  SECTION( "qubit indices" ) {
1047 
1048  // valid inds
1049  int numQb = 2;
1050  int qb1[2] = {0,1};
1051  int qb2[2] = {2,3};
1052  ComplexMatrixN matr = createComplexMatrixN(numQb);
1053  toComplexMatrixN(getRandomUnitary(numQb), matr); // ensure unitary
1054 
1055  // make qb1 invalid
1056  int inv = GENERATE( -1, NUM_QUBITS );
1057  qb1[GENERATE_COPY(range(0,numQb))] = inv;
1058 
1059  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, qb1, numQb, qb2, numQb, matr), Contains("Invalid control") );
1060  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, qb2, numQb, qb1, numQb, matr), Contains("Invalid target") );
1061  destroyComplexMatrixN(matr);
1062  }
1063  SECTION( "unitarity" ) {
1064 
1065  int ctrls[1] = {0};
1066  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
1067  int targs[numTargs];
1068  for (int i=0; i<numTargs; i++)
1069  targs[i] = i+1;
1070 
1071  ComplexMatrixN matr = createComplexMatrixN(numTargs); // initially zero, hence not-unitary
1072  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, numTargs, matr), Contains("unitary") );
1073  destroyComplexMatrixN(matr);
1074  }
1075  SECTION( "unitary creation" ) {
1076 
1077  int ctrls[1] = {0};
1078  int targs[3] = {1,2,3};
1079 
1080  /* compilers don't auto-initialise to NULL; the below circumstance
1081  * only really occurs when 'malloc' returns NULL in createComplexMatrixN,
1082  * which actually triggers its own validation. Hence this test is useless
1083  * currently.
1084  */
1085  ComplexMatrixN matr;
1086  matr.real = NULL;
1087  matr.imag = NULL;
1088  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, 3, matr), Contains("created") );
1089  }
1090  SECTION( "unitary dimensions" ) {
1091 
1092  int ctrls[1] = {0};
1093  int targs[2] = {1,2};
1094  ComplexMatrixN matr = createComplexMatrixN(3); // intentionally wrong size
1095  toComplexMatrixN(getRandomUnitary(3), matr); // ensure unitary
1096 
1097  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, 2, matr), Contains("matrix size"));
1098  destroyComplexMatrixN(matr);
1099  }
1100  SECTION( "unitary fits in node" ) {
1101 
1102  // pretend we have a very limited distributed memory (judged by matr size)
1103  quregVec.numAmpsPerChunk = 1;
1104  int ctrls[1] = {0};
1105  int targs[2] = {1,2};
1107  toComplexMatrixN(getRandomUnitary(2), matr); // ensure unitary
1108 
1109  REQUIRE_THROWS_WITH( multiControlledMultiQubitUnitary(quregVec, ctrls, 1, targs, 2, matr), Contains("targets too many qubits"));
1110  destroyComplexMatrixN(matr);
1111  }
1112  }
1113  CLEANUP_TEST( quregVec, quregMatr );
1114 }

References applyReferenceOp(), areEqual(), calcLog2(), CLEANUP_TEST, createComplexMatrixN(), destroyComplexMatrixN(), getRandomUnitary(), ComplexMatrixN::imag, multiControlledMultiQubitUnitary(), NUM_QUBITS, PREPARE_TEST, ComplexMatrixN::real, sublists(), and toComplexMatrixN().

◆ TEST_CASE() [95/124]

TEST_CASE ( "multiControlledMultiRotatePauli"  ,
""  [unitaries] 
)
See also
multiControlledMultiRotatePauli
Author
Tyson Jones

Definition at line 1122 of file test_unitaries.cpp.

1122  {
1123 
1124  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1125  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
1126 
1127  SECTION( "correctness" ) {
1128 
1129  // try all possible numbers of targets and controls
1130  int numTargs = GENERATE_COPY( range(1,NUM_QUBITS) ); // leave space for min 1 control qubit
1131  int maxNumCtrls = NUM_QUBITS - numTargs;
1132  int numCtrls = GENERATE_COPY( range(1,maxNumCtrls+1) );
1133 
1134  // generate all possible valid qubit arrangements
1135  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1136  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, targs, numTargs) );
1137 
1138  /* it's too expensive to try ALL Pauli sequences, via
1139  * pauliOpType* paulis = GENERATE_COPY( pauliseqs(numTargs) );.
1140  * Furthermore, take(10, pauliseqs(numTargs)) will try the same pauli codes.
1141  * Hence, we instead opt to randomly generate pauliseqs
1142  */
1143  pauliOpType paulis[numTargs];
1144  for (int i=0; i<numTargs; i++)
1145  paulis[i] = (pauliOpType) getRandomInt(0,4);
1146 
1147  // exclude identities from reference matrix exp (they apply unwanted global phase)
1148  int refTargs[numTargs];
1149  int numRefTargs = 0;
1150 
1151  QMatrix xMatr{{0,1},{1,0}};
1152  QMatrix yMatr{{0,-qcomp(0,1)},{qcomp(0,1),0}};
1153  QMatrix zMatr{{1,0},{0,-1}};
1154 
1155  // build correct reference matrix by pauli-matrix exponentiation...
1156  QMatrix pauliProd{{1}};
1157  for (int i=0; i<numTargs; i++) {
1158  QMatrix fac;
1159  if (paulis[i] == PAULI_I) continue; // exclude I-targets from ref list
1160  if (paulis[i] == PAULI_X) fac = xMatr;
1161  if (paulis[i] == PAULI_Y) fac = yMatr;
1162  if (paulis[i] == PAULI_Z) fac = zMatr;
1163  pauliProd = getKroneckerProduct(fac, pauliProd);
1164 
1165  // include this target in ref list
1166  refTargs[numRefTargs++] = targs[i];
1167  }
1168 
1169  // produces exp(-i param/2 pauliProd), unless pauliProd = I
1170  QMatrix op;
1171  if (numRefTargs > 0)
1172  op = getExponentialOfPauliMatrix(param, pauliProd);
1173 
1174  SECTION( "state-vector" ) {
1175 
1176  multiControlledMultiRotatePauli(quregVec, ctrls, numCtrls, targs, paulis, numTargs, param);
1177  if (numRefTargs > 0)
1178  applyReferenceOp(refVec, ctrls, numCtrls, refTargs, numRefTargs, op);
1179  REQUIRE( areEqual(quregVec, refVec) );
1180  }
1181  SECTION( "density-matrix" ) {
1182 
1183  multiControlledMultiRotatePauli(quregMatr, ctrls, numCtrls, targs, paulis, numTargs, param);
1184  if (numRefTargs > 0)
1185  applyReferenceOp(refMatr, ctrls, numCtrls, refTargs, numRefTargs, op);
1186  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1187  }
1188  }
1189  SECTION( "input validation" ) {
1190 
1191  // test all validation on both state-vector and density-matrix.
1192  // want GENERATE_COPY( quregVec, quregMatr ), but too lazy to patch
1193  // using github.com/catchorg/Catch2/issues/1809
1194  Qureg regs[] = {quregVec, quregMatr};
1195  Qureg qureg = regs[GENERATE(0,1)];
1196 
1197  // over-sized array to prevent seg-fault in case of validation fail below
1198  pauliOpType paulis[NUM_QUBITS+1];
1199  for (int q=0; q<NUM_QUBITS+1; q++)
1200  paulis[q] = PAULI_I;
1201 
1202  SECTION( "pauli codes" ) {
1203 
1204  int numCtrls = 1;
1205  int ctrls[] = {3};
1206  int numTargs = 3;
1207  int targs[3] = {0, 1, 2};
1208 
1209  // make a single Pauli invalid
1210  paulis[GENERATE_COPY(range(0,numTargs))] = (pauliOpType) GENERATE( -1, 4 );
1211 
1212  REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, ctrls, numCtrls, targs, paulis, numTargs, param), Contains("Invalid Pauli code"));
1213  }
1214  SECTION( "number of targets" ) {
1215 
1216  // there cannot be more targets than qubits in register
1217  // (numTargs=NUM_QUBITS is caught elsewhere, because that implies ctrls are invalid)
1218  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
1219  int numCtrls = 1;
1220  int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
1221  int ctrls[] = {0};
1222 
1223  REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, ctrls, numCtrls, targs, paulis, numTargs, param), Contains("Invalid number of target") );
1224  }
1225  SECTION( "repetition in targets" ) {
1226 
1227  int numCtrls = 1;
1228  int numTargs = 3;
1229  int ctrls[] = {0};
1230  int targs[] = {1,2,2};
1231 
1232  REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, ctrls, numCtrls, targs, paulis, numTargs, param), Contains("target") && Contains("unique"));
1233  }
1234  SECTION( "number of controls" ) {
1235 
1236  int numCtrls = GENERATE( -1, 0, NUM_QUBITS, NUM_QUBITS+1 );
1237  int numTargs = 1;
1238  int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1239  int targs[1] = {0};
1240 
1241  REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, ctrls, numCtrls, targs, paulis, numTargs, param), Contains("Invalid number of control"));
1242  }
1243  SECTION( "repetition in controls" ) {
1244 
1245  int numCtrls = 3;
1246  int numTargs = 1;
1247  int ctrls[] = {0,1,1};
1248  int targs[] = {3};
1249 
1250  REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, ctrls, numCtrls, targs, paulis, numTargs, param), Contains("control") && Contains("unique"));
1251  }
1252  SECTION( "control and target collision" ) {
1253 
1254  int numCtrls = 3;
1255  int numTargs = 3;
1256  int ctrls[] = {0,1,2};
1257  int targs[] = {3,1,4};
1258 
1259  REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, ctrls, numCtrls, targs, paulis, numTargs, param), Contains("Control") && Contains("target") && Contains("disjoint"));
1260  }
1261  SECTION( "qubit indices" ) {
1262 
1263  // valid inds
1264  int numQb = 2;
1265  int qb1[2] = {0,1};
1266  int qb2[2] = {2,3};
1267 
1268  // make qb1 invalid
1269  int inv = GENERATE( -1, NUM_QUBITS );
1270  qb1[GENERATE_COPY(range(0,numQb))] = inv;
1271 
1272  REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, qb1, numQb, qb2, paulis, numQb, param), Contains("Invalid control") );
1273  REQUIRE_THROWS_WITH( multiControlledMultiRotatePauli(qureg, qb2, numQb, qb1, paulis, numQb, param), Contains("Invalid target") );
1274  }
1275  }
1276  CLEANUP_TEST( quregVec, quregMatr );
1277 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, getExponentialOfPauliMatrix(), getKroneckerProduct(), getRandomInt(), getRandomReal(), M_PI, multiControlledMultiRotatePauli(), NUM_QUBITS, PAULI_I, PAULI_X, PAULI_Y, PAULI_Z, PREPARE_TEST, qcomp, qreal, and sublists().

◆ TEST_CASE() [96/124]

TEST_CASE ( "multiControlledMultiRotateZ"  ,
""  [unitaries] 
)
See also
multiControlledMultiRotateZ
Author
Tyson Jones

Definition at line 1285 of file test_unitaries.cpp.

1285  {
1286 
1287  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1288  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
1289 
1290  SECTION( "correctness" ) {
1291 
1292  // try all possible numbers of targets and controls
1293  int numTargs = GENERATE_COPY( range(1,NUM_QUBITS) ); // leave space for min 1 control qubit
1294  int maxNumCtrls = NUM_QUBITS - numTargs;
1295  int numCtrls = GENERATE_COPY( range(1,maxNumCtrls+1) );
1296 
1297  // generate all possible valid qubit arrangements
1298  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1299  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, targs, numTargs) );
1300 
1301  // build correct reference matrix by diagonal-matrix exponentiation...
1302  QMatrix zMatr{{1,0},{0,-1}};
1303  QMatrix zProd = zMatr;
1304  for (int t=0; t<numTargs-1; t++)
1305  zProd = getKroneckerProduct(zMatr, zProd); // Z . Z ... Z
1306 
1307  // exp( -i param/2 Z . Z ... Z)
1308  QMatrix op = getExponentialOfDiagonalMatrix(qcomp(0, -param/2) * zProd);
1309 
1310  SECTION( "state-vector" ) {
1311 
1312  multiControlledMultiRotateZ(quregVec, ctrls, numCtrls, targs, numTargs, param);
1313  applyReferenceOp(refVec, ctrls, numCtrls, targs, numTargs, op);
1314  REQUIRE( areEqual(quregVec, refVec) );
1315  }
1316  SECTION( "density-matrix" ) {
1317 
1318  multiControlledMultiRotateZ(quregMatr, ctrls, numCtrls, targs, numTargs, param);
1319  applyReferenceOp(refMatr, ctrls, numCtrls, targs, numTargs, op);
1320  REQUIRE( areEqual(quregMatr, refMatr, 2*REAL_EPS) );
1321  }
1322  }
1323  SECTION( "input validation" ) {
1324 
1325  // test all validation on both state-vector and density-matrix.
1326  // want GENERATE_COPY( quregVec, quregMatr ), but too lazy to patch
1327  // using github.com/catchorg/Catch2/issues/1809
1328  Qureg regs[] = {quregVec, quregMatr};
1329  Qureg qureg = regs[GENERATE(0,1)];
1330 
1331  SECTION( "number of targets" ) {
1332 
1333  // there cannot be more targets than qubits in register
1334  // (numTargs=NUM_QUBITS is caught elsewhere, because that implies ctrls are invalid)
1335  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
1336  int numCtrls = 1;
1337  int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
1338  int ctrls[] = {0};
1339 
1340  REQUIRE_THROWS_WITH( multiControlledMultiRotateZ(qureg, ctrls, numCtrls, targs, numTargs, param), Contains("Invalid number of target") );
1341  }
1342  SECTION( "repetition in targets" ) {
1343 
1344  int numCtrls = 1;
1345  int numTargs = 3;
1346  int ctrls[] = {0};
1347  int targs[] = {1,2,2};
1348 
1349  REQUIRE_THROWS_WITH( multiControlledMultiRotateZ(qureg, ctrls, numCtrls, targs, numTargs, param), Contains("target") && Contains("unique"));
1350  }
1351  SECTION( "number of controls" ) {
1352 
1353  int numCtrls = GENERATE( -1, 0, NUM_QUBITS, NUM_QUBITS+1 );
1354  int numTargs = 1;
1355  int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1356  int targs[1] = {0};
1357 
1358  REQUIRE_THROWS_WITH( multiControlledMultiRotateZ(qureg, ctrls, numCtrls, targs, numTargs, param), Contains("Invalid number of control"));
1359  }
1360  SECTION( "repetition in controls" ) {
1361 
1362  int numCtrls = 3;
1363  int numTargs = 1;
1364  int ctrls[] = {0,1,1};
1365  int targs[] = {3};
1366 
1367  REQUIRE_THROWS_WITH( multiControlledMultiRotateZ(qureg, ctrls, numCtrls, targs, numTargs, param), Contains("control") && Contains("unique"));
1368  }
1369  SECTION( "control and target collision" ) {
1370 
1371  int numCtrls = 3;
1372  int numTargs = 3;
1373  int ctrls[] = {0,1,2};
1374  int targs[] = {3,1,4};
1375 
1376  REQUIRE_THROWS_WITH( multiControlledMultiRotateZ(qureg, ctrls, numCtrls, targs, numTargs, param), Contains("Control") && Contains("target") && Contains("disjoint"));
1377  }
1378  SECTION( "qubit indices" ) {
1379 
1380  // valid inds
1381  int numQb = 2;
1382  int qb1[2] = {0,1};
1383  int qb2[2] = {2,3};
1384 
1385  // make qb1 invalid
1386  int inv = GENERATE( -1, NUM_QUBITS );
1387  qb1[GENERATE_COPY(range(0,numQb))] = inv;
1388 
1389  REQUIRE_THROWS_WITH( multiControlledMultiRotateZ(qureg, qb1, numQb, qb2, numQb, param), Contains("Invalid control") );
1390  REQUIRE_THROWS_WITH( multiControlledMultiRotateZ(qureg, qb2, numQb, qb1, numQb, param), Contains("Invalid target") );
1391  }
1392  }
1393  CLEANUP_TEST( quregVec, quregMatr );
1394 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, getExponentialOfDiagonalMatrix(), getKroneckerProduct(), getRandomReal(), M_PI, multiControlledMultiRotateZ(), NUM_QUBITS, PREPARE_TEST, qcomp, qreal, and sublists().

◆ TEST_CASE() [97/124]

TEST_CASE ( "multiControlledPhaseFlip"  ,
""  [unitaries] 
)
See also
multiControlledPhaseFlip
Author
Tyson Jones

Definition at line 1402 of file test_unitaries.cpp.

1402  {
1403 
1404  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1405 
1406  // acts on the final control qubit
1407  QMatrix op{{1,0},{0,-1}};
1408 
1409  SECTION( "correctness" ) {
1410 
1411  // generate ALL valid qubit arrangements
1412  int numCtrls = GENERATE( range(1,NUM_QUBITS) ); // numCtrls=NUM_QUBITS stopped by overzealous validation
1413  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls) );
1414 
1415  SECTION( "state-vector" ) {
1416 
1417  multiControlledPhaseFlip(quregVec, ctrls, numCtrls);
1418  applyReferenceOp(refVec, ctrls, numCtrls-1, ctrls[numCtrls-1], op);
1419  REQUIRE( areEqual(quregVec, refVec) );
1420  }
1421  SECTION( "density-matrix" ) {
1422 
1423  multiControlledPhaseFlip(quregMatr, ctrls, numCtrls);
1424  applyReferenceOp(refMatr, ctrls, numCtrls-1, ctrls[numCtrls-1], op);
1425  REQUIRE( areEqual(quregMatr, refMatr) );
1426  }
1427  }
1428  SECTION( "input validation" ) {
1429 
1430  SECTION( "number of controls" ) {
1431 
1432  int numCtrls = GENERATE( -1, 0, NUM_QUBITS+1 );
1433  int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1434  REQUIRE_THROWS_WITH( multiControlledPhaseFlip(quregVec, ctrls, numCtrls), Contains("Invalid number of qubits"));
1435  }
1436  SECTION( "repetition of controls" ) {
1437 
1438  int numCtrls = 3;
1439  int ctrls[] = {0,1,1};
1440  REQUIRE_THROWS_WITH( multiControlledPhaseFlip(quregVec, ctrls, numCtrls), Contains("qubits must be unique"));
1441  }
1442  SECTION( "qubit indices" ) {
1443 
1444  int numCtrls = 3;
1445  int ctrls[] = { 1, 2, GENERATE( -1, NUM_QUBITS ) };
1446  REQUIRE_THROWS_WITH( multiControlledPhaseFlip(quregVec, ctrls, numCtrls), Contains("Invalid qubit") );
1447  }
1448  }
1449  CLEANUP_TEST( quregVec, quregMatr );
1450 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, multiControlledPhaseFlip(), NUM_QUBITS, PREPARE_TEST, and sublists().

◆ TEST_CASE() [98/124]

TEST_CASE ( "multiControlledPhaseShift"  ,
""  [unitaries] 
)
See also
multiControlledPhaseShift
Author
Tyson Jones

Definition at line 1458 of file test_unitaries.cpp.

1458  {
1459 
1460  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1461  qreal param = getRandomReal(-2*M_PI, 2*M_PI);
1462  QMatrix op{{1,0},{0,expI(param)}};
1463 
1464  SECTION( "correctness" ) {
1465 
1466  // generate ALL valid qubit arrangements
1467  int numCtrls = GENERATE( range(1,NUM_QUBITS) ); // numCtrls=NUM_QUBITS stopped by overzealous validation
1468  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls) );
1469 
1470  SECTION( "state-vector" ) {
1471 
1472  multiControlledPhaseShift(quregVec, ctrls, numCtrls, param);
1473  applyReferenceOp(refVec, ctrls, numCtrls-1, ctrls[numCtrls-1], op);
1474  REQUIRE( areEqual(quregVec, refVec) );
1475  }
1476  SECTION( "density-matrix" ) {
1477 
1478  multiControlledPhaseShift(quregMatr, ctrls, numCtrls, param);
1479  applyReferenceOp(refMatr, ctrls, numCtrls-1, ctrls[numCtrls-1], op);
1480  REQUIRE( areEqual(quregMatr, refMatr) );
1481  }
1482  }
1483  SECTION( "input validation" ) {
1484 
1485  SECTION( "number of controls" ) {
1486 
1487  int numCtrls = GENERATE( -1, 0, NUM_QUBITS+1 );
1488  int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1489  REQUIRE_THROWS_WITH( multiControlledPhaseShift(quregVec, ctrls, numCtrls, param), Contains("Invalid number of qubits"));
1490  }
1491  SECTION( "repetition of controls" ) {
1492 
1493  int numCtrls = 3;
1494  int ctrls[] = {0,1,1};
1495  REQUIRE_THROWS_WITH( multiControlledPhaseShift(quregVec, ctrls, numCtrls, param), Contains("qubits must be unique"));
1496  }
1497  SECTION( "qubit indices" ) {
1498 
1499  int numCtrls = 3;
1500  int ctrls[] = { 1, 2, GENERATE( -1, NUM_QUBITS ) };
1501  REQUIRE_THROWS_WITH( multiControlledPhaseShift(quregVec, ctrls, numCtrls, param), Contains("Invalid qubit") );
1502  }
1503  }
1504  CLEANUP_TEST( quregVec, quregMatr );
1505 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, expI(), getRandomReal(), M_PI, multiControlledPhaseShift(), NUM_QUBITS, PREPARE_TEST, qreal, and sublists().

◆ TEST_CASE() [99/124]

TEST_CASE ( "multiControlledTwoQubitUnitary"  ,
""  [unitaries] 
)
See also
multiControlledTwoQubitUnitary
Author
Tyson Jones

Definition at line 1513 of file test_unitaries.cpp.

1513  {
1514 
1515  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1516 
1517  // in distributed mode, each node must be able to fit all amps modified by unitary
1518  REQUIRE( quregVec.numAmpsPerChunk >= 4 );
1519 
1520  // every test will use a unique random matrix
1521  QMatrix op = getRandomUnitary(2);
1522  ComplexMatrix4 matr = toComplexMatrix4(op);
1523 
1524  SECTION( "correctness" ) {
1525 
1526  // generate ALL valid qubit arrangements
1527  int targ1 = GENERATE( range(0,NUM_QUBITS) );
1528  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
1529  int targs[] = {targ1, targ2};
1530  int numCtrls = GENERATE( range(1,NUM_QUBITS-1) ); // leave room for 2 targets (upper bound is exclusive)
1531  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, targs, 2) );
1532 
1533  SECTION( "state-vector" ) {
1534 
1535  multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr);
1536  applyReferenceOp(refVec, ctrls, numCtrls, targ1, targ2, op);
1537  REQUIRE( areEqual(quregVec, refVec) );
1538  }
1539  SECTION( "density-matrix" ) {
1540 
1541  multiControlledTwoQubitUnitary(quregMatr, ctrls, numCtrls, targ1, targ2, matr);
1542  applyReferenceOp(refMatr, ctrls, numCtrls, targ1, targ2, op);
1543  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1544  }
1545  }
1546  SECTION( "input validation" ) {
1547 
1548  SECTION( "number of controls" ) {
1549 
1550  // numCtrls=(NUM_QUBITS-1) is ok since requires ctrl qubit inds are invalid
1551  int numCtrls = GENERATE( -1, 0, NUM_QUBITS, NUM_QUBITS+1 );
1552  int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1553  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, 0, 1, matr), Contains("Invalid number of control"));
1554  }
1555  SECTION( "repetition of controls" ) {
1556 
1557  int numCtrls = 3;
1558  int ctrls[] = {0,1,1};
1559  int targ1 = 2;
1560  int targ2 = 3;
1561  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr), Contains("control") && Contains("unique"));;
1562  }
1563  SECTION( "repetition of targets" ) {
1564 
1565  int numCtrls = 3;
1566  int ctrls[] = {0,1,2};
1567  int targ1 = 3;
1568  int targ2 = targ1;
1569  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr), Contains("target") && Contains("unique"));
1570  }
1571  SECTION( "control and target collision" ) {
1572 
1573  int numCtrls = 3;
1574  int ctrls[] = {0,1,2};
1575  int targ1 = 3;
1576  int targ2 = ctrls[GENERATE_COPY( range(0,numCtrls) )];
1577  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr), Contains("Control") && Contains("target") );
1578  }
1579  SECTION( "qubit indices" ) {
1580 
1581  // valid indices
1582  int targ1 = 0;
1583  int targ2 = 1;
1584  int numCtrls = 3;
1585  int ctrls[] = { 2, 3, 4 };
1586 
1587  int inv = GENERATE( -1, NUM_QUBITS );
1588  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, inv, targ2, matr), Contains("Invalid target") );
1589  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, inv, matr), Contains("Invalid target") );
1590 
1591  ctrls[numCtrls-1] = inv; // make ctrls invalid
1592  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, numCtrls, targ1, targ2, matr), Contains("Invalid control") );
1593  }
1594  SECTION( "unitarity " ) {
1595 
1596  int ctrls[1] = {0};
1597  matr.real[0][0] = 0; // break unitarity
1598  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, 1, 1, 2, matr), Contains("unitary") );
1599  }
1600  SECTION( "unitary fits in node" ) {
1601 
1602  // pretend we have a very limited distributed memory
1603  quregVec.numAmpsPerChunk = 1;
1604  int ctrls[1] = {0};
1605  REQUIRE_THROWS_WITH( multiControlledTwoQubitUnitary(quregVec, ctrls, 1, 1, 2, matr), Contains("targets too many qubits"));
1606  }
1607  }
1608  CLEANUP_TEST( quregVec, quregMatr );
1609 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, getRandomUnitary(), multiControlledTwoQubitUnitary(), NUM_QUBITS, PREPARE_TEST, ComplexMatrix4::real, sublists(), and toComplexMatrix4().

◆ TEST_CASE() [100/124]

TEST_CASE ( "multiControlledUnitary"  ,
""  [unitaries] 
)
See also
multiControlledUnitary
Author
Tyson Jones

Definition at line 1617 of file test_unitaries.cpp.

1617  {
1618 
1619  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1620 
1621  // every test will use a unique random matrix
1622  QMatrix op = getRandomUnitary(1);
1623  ComplexMatrix2 matr = toComplexMatrix2(op);
1624 
1625  SECTION( "correctness" ) {
1626 
1627  int target = GENERATE( range(0,NUM_QUBITS) );
1628  int numCtrls = GENERATE( range(1,NUM_QUBITS) ); // leave space for one target (exclusive upper bound)
1629  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, target) );
1630 
1631  SECTION( "state-vector" ) {
1632 
1633  multiControlledUnitary(quregVec, ctrls, numCtrls, target, matr);
1634  applyReferenceOp(refVec, ctrls, numCtrls, target, op);
1635  REQUIRE( areEqual(quregVec, refVec) );
1636  }
1637  SECTION( "density-matrix" ) {
1638 
1639  multiControlledUnitary(quregMatr, ctrls, numCtrls, target, matr);
1640  applyReferenceOp(refMatr, ctrls, numCtrls, target, op);
1641  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1642  }
1643  }
1644  SECTION( "input validation" ) {
1645 
1646  SECTION( "number of controls" ) {
1647 
1648  int numCtrls = GENERATE( -1, 0, NUM_QUBITS, NUM_QUBITS+1 );
1649  int ctrls[NUM_QUBITS+1]; // avoids seg-fault if validation not triggered
1650  REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, numCtrls, 0, matr), Contains("Invalid number of control"));
1651  }
1652  SECTION( "repetition of controls" ) {
1653 
1654  int ctrls[] = {0,1,1};
1655  REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 3, 2, matr), Contains("control") && Contains("unique"));
1656  }
1657  SECTION( "control and target collision" ) {
1658 
1659  int ctrls[] = {0,1,2};
1660  int targ = ctrls[GENERATE( range(0,3) )];
1661  REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 3, targ, matr), Contains("Control") && Contains("target") );
1662  }
1663  SECTION( "qubit indices" ) {
1664 
1665  int ctrls[] = { 1, 2, GENERATE( -1, NUM_QUBITS ) };
1666  REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 3, 0, matr), Contains("Invalid control") );
1667 
1668  ctrls[2] = 3; // make ctrls valid
1669  int targ = GENERATE( -1, NUM_QUBITS );
1670  REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 3, targ, matr), Contains("Invalid target") );
1671  }
1672  SECTION( "unitarity" ) {
1673 
1674  matr.real[0][0] = 0; // break matr unitarity
1675  int ctrls[] = {0};
1676  REQUIRE_THROWS_WITH( multiControlledUnitary(quregVec, ctrls, 1, 1, matr), Contains("unitary") );
1677  }
1678  }
1679  CLEANUP_TEST( quregVec, quregMatr );
1680 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, getRandomUnitary(), multiControlledUnitary(), NUM_QUBITS, PREPARE_TEST, ComplexMatrix2::real, sublists(), and toComplexMatrix2().

◆ TEST_CASE() [101/124]

TEST_CASE ( "multiQubitNot"  ,
""  [unitaries] 
)
See also
multiQubitNot
Author
Tyson Jones

Definition at line 1688 of file test_unitaries.cpp.

1688  {
1689 
1690  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1691 
1692  SECTION( "correctness" ) {
1693 
1694  // try all possible numbers of targets and controls
1695  int numTargs = GENERATE_COPY( range(1,NUM_QUBITS+1) ); // leave space for 1 ctrl
1696 
1697  // generate all possible valid qubit arrangements
1698  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1699 
1700  // for each qubit arrangement, use a new random unitary
1701  QMatrix notOp{{0, 1},{1,0}};
1702 
1703  SECTION( "state-vector" ) {
1704 
1705  multiQubitNot(quregVec, targs, numTargs);
1706  for (int t=0; t<numTargs; t++)
1707  applyReferenceOp(refVec, targs[t], notOp);
1708 
1709  REQUIRE( areEqual(quregVec, refVec) );
1710  }
1711  SECTION( "density-matrix" ) {
1712 
1713  multiQubitNot(quregMatr, targs, numTargs);
1714  for (int t=0; t<numTargs; t++)
1715  applyReferenceOp(refMatr, targs[t], notOp);
1716 
1717  REQUIRE( areEqual(quregMatr, refMatr) );
1718  }
1719  }
1720  SECTION( "input validation" ) {
1721 
1722  SECTION( "number of targets" ) {
1723 
1724  // there cannot be more targets than qubits in register
1725  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
1726  int targs[NUM_QUBITS+1];
1727  REQUIRE_THROWS_WITH( multiQubitNot(quregVec, targs, numTargs), Contains("Invalid number of target"));
1728  }
1729  SECTION( "repetition in targets" ) {
1730 
1731  int numTargs = 3;
1732  int targs[] = {1,2,2};
1733  REQUIRE_THROWS_WITH( multiQubitNot(quregVec, targs, numTargs), Contains("target") && Contains("unique"));
1734  }
1735  SECTION( "target indices" ) {
1736 
1737  // valid inds
1738  int numQb = 5;
1739  int qubits[] = {0,1,2,3,4};
1740 
1741  // make one index invalid
1742  qubits[GENERATE_COPY(range(0,numQb))] = GENERATE( -1, NUM_QUBITS );
1743  REQUIRE_THROWS_WITH( multiQubitNot(quregVec, qubits, numQb), Contains("Invalid target") );
1744  }
1745  }
1746  CLEANUP_TEST( quregVec, quregMatr );
1747 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, multiQubitNot(), NUM_QUBITS, PREPARE_TEST, and sublists().

◆ TEST_CASE() [102/124]

TEST_CASE ( "multiQubitUnitary"  ,
""  [unitaries] 
)
See also
multiQubitUnitary
Author
Tyson Jones

Definition at line 1755 of file test_unitaries.cpp.

1755  {
1756 
1757  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1758 
1759  // figure out max-num (inclusive) targs allowed by hardware backend
1760  int maxNumTargs = calcLog2(quregVec.numAmpsPerChunk);
1761 
1762  SECTION( "correctness" ) {
1763 
1764  // generate all possible qubit arrangements
1765  int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) ); // inclusive upper bound
1766  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1767 
1768  // for each qubit arrangement, use a new random unitary
1769  QMatrix op = getRandomUnitary(numTargs);
1770  ComplexMatrixN matr = createComplexMatrixN(numTargs);
1771  toComplexMatrixN(op, matr);
1772 
1773  SECTION( "state-vector" ) {
1774 
1775  multiQubitUnitary(quregVec, targs, numTargs, matr);
1776  applyReferenceOp(refVec, targs, numTargs, op);
1777  REQUIRE( areEqual(quregVec, refVec) );
1778  }
1779  SECTION( "density-matrix" ) {
1780 
1781  multiQubitUnitary(quregMatr, targs, numTargs, matr);
1782  applyReferenceOp(refMatr, targs, numTargs, op);
1783  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1784  }
1785  destroyComplexMatrixN(matr);
1786  }
1787  SECTION( "input validation" ) {
1788 
1789  SECTION( "number of targets" ) {
1790 
1791  // there cannot be more targets than qubits in register
1792  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
1793  int targs[NUM_QUBITS+1]; // prevents seg-fault if validation doesn't trigger
1794  ComplexMatrixN matr = createComplexMatrixN(NUM_QUBITS+1); // prevent seg-fault
1795 
1796  REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), Contains("Invalid number of target"));
1797  destroyComplexMatrixN(matr);
1798  }
1799  SECTION( "repetition in targets" ) {
1800 
1801  int numTargs = 3;
1802  int targs[] = {1,2,2};
1803  ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
1804 
1805  REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), Contains("target") && Contains("unique"));
1806  destroyComplexMatrixN(matr);
1807  }
1808  SECTION( "qubit indices" ) {
1809 
1810  int numTargs = 3;
1811  int targs[] = {1,2,3};
1812  ComplexMatrixN matr = createComplexMatrixN(numTargs); // prevents seg-fault if validation doesn't trigger
1813 
1814  int inv = GENERATE( -1, NUM_QUBITS );
1815  targs[GENERATE_COPY( range(0,numTargs) )] = inv; // make invalid target
1816  REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), Contains("Invalid target") );
1817 
1818  destroyComplexMatrixN(matr);
1819  }
1820  SECTION( "unitarity" ) {
1821 
1822  int numTargs = GENERATE_COPY( range(1,maxNumTargs) );
1823  int targs[numTargs];
1824  for (int i=0; i<numTargs; i++)
1825  targs[i] = i+1;
1826 
1827  ComplexMatrixN matr = createComplexMatrixN(numTargs); // initially zero, hence not-unitary
1828 
1829  REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), Contains("unitary") );
1830  destroyComplexMatrixN(matr);
1831  }
1832  SECTION( "unitary creation" ) {
1833 
1834  int numTargs = 3;
1835  int targs[] = {1,2,3};
1836 
1837  /* compilers don't auto-initialise to NULL; the below circumstance
1838  * only really occurs when 'malloc' returns NULL in createComplexMatrixN,
1839  * which actually triggers its own validation. Hence this test is useless
1840  * currently.
1841  */
1842  ComplexMatrixN matr;
1843  matr.real = NULL;
1844  matr.imag = NULL;
1845  REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, numTargs, matr), Contains("created") );
1846  }
1847  SECTION( "unitary dimensions" ) {
1848 
1849  int targs[2] = {1,2};
1850  ComplexMatrixN matr = createComplexMatrixN(3); // intentionally wrong size
1851 
1852  REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, targs, 2, matr), Contains("matrix size"));
1853  destroyComplexMatrixN(matr);
1854  }
1855  SECTION( "unitary fits in node" ) {
1856 
1857  // pretend we have a very limited distributed memory (judged by matr size)
1858  quregVec.numAmpsPerChunk = 1;
1859  int qb[] = {1,2};
1860  ComplexMatrixN matr = createComplexMatrixN(2); // prevents seg-fault if validation doesn't trigger
1861  REQUIRE_THROWS_WITH( multiQubitUnitary(quregVec, qb, 2, matr), Contains("targets too many qubits"));
1862  destroyComplexMatrixN(matr);
1863  }
1864  }
1865  CLEANUP_TEST( quregVec, quregMatr );
1866 }

References applyReferenceOp(), areEqual(), calcLog2(), CLEANUP_TEST, createComplexMatrixN(), destroyComplexMatrixN(), getRandomUnitary(), ComplexMatrixN::imag, multiQubitUnitary(), NUM_QUBITS, PREPARE_TEST, ComplexMatrixN::real, sublists(), and toComplexMatrixN().

◆ TEST_CASE() [103/124]

TEST_CASE ( "multiRotatePauli"  ,
""  [unitaries] 
)
See also
multiRotatePauli
Author
Tyson Jones

Definition at line 1874 of file test_unitaries.cpp.

1874  {
1875 
1876  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1877  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
1878 
1879  SECTION( "correctness" ) {
1880 
1881  int numTargs = GENERATE( range(1,NUM_QUBITS+1) );
1882  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1883 
1884  /* it's too expensive to try ALL Pauli sequences, via
1885  * pauliOpType* paulis = GENERATE_COPY( pauliseqs(numTargs) );.
1886  * Furthermore, take(10, pauliseqs(numTargs)) will try the same pauli codes.
1887  * Hence, we instead opt to repeatedlyrandomly generate pauliseqs
1888  */
1889  GENERATE( range(0,10) ); // gen 10 random pauli-codes for every targs
1890  pauliOpType paulis[numTargs];
1891  for (int i=0; i<numTargs; i++)
1892  paulis[i] = (pauliOpType) getRandomInt(0,4);
1893 
1894  // exclude identities from reference matrix exp (they apply unwanted global phase)
1895  int refTargs[numTargs];
1896  int numRefTargs = 0;
1897 
1898  QMatrix xMatr{{0,1},{1,0}};
1899  QMatrix yMatr{{0,-qcomp(0,1)},{qcomp(0,1),0}};
1900  QMatrix zMatr{{1,0},{0,-1}};
1901 
1902  // build correct reference matrix by pauli-matrix exponentiation...
1903  QMatrix pauliProd{{1}};
1904  for (int i=0; i<numTargs; i++) {
1905  QMatrix fac;
1906  if (paulis[i] == PAULI_I) continue; // exclude I-targets from ref list
1907  if (paulis[i] == PAULI_X) fac = xMatr;
1908  if (paulis[i] == PAULI_Y) fac = yMatr;
1909  if (paulis[i] == PAULI_Z) fac = zMatr;
1910  pauliProd = getKroneckerProduct(fac, pauliProd);
1911 
1912  // include this target in ref list
1913  refTargs[numRefTargs++] = targs[i];
1914  }
1915 
1916  // produces exp(-i param/2 pauliProd), unless pauliProd = I
1917  QMatrix op;
1918  if (numRefTargs > 0)
1919  op = getExponentialOfPauliMatrix(param, pauliProd);
1920 
1921  SECTION( "state-vector" ) {
1922 
1923  multiRotatePauli(quregVec, targs, paulis, numTargs, param);
1924  if (numRefTargs > 0)
1925  applyReferenceOp(refVec, refTargs, numRefTargs, op);
1926  REQUIRE( areEqual(quregVec, refVec) );
1927  }
1928  SECTION( "density-matrix" ) {
1929 
1930  multiRotatePauli(quregMatr, targs, paulis, numTargs, param);
1931  if (numRefTargs > 0)
1932  applyReferenceOp(refMatr, refTargs, numRefTargs, op);
1933  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
1934  }
1935  }
1936  SECTION( "input validation" ) {
1937 
1938  SECTION( "number of targets" ) {
1939 
1940  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
1941  int targs[NUM_QUBITS+1]; // prevent seg-fault if validation isn't triggered
1942  pauliOpType paulis[NUM_QUBITS+1] = {PAULI_I};
1943  REQUIRE_THROWS_WITH( multiRotatePauli(quregVec, targs, paulis, numTargs, param), Contains("Invalid number of target"));
1944  }
1945  SECTION( "repetition of targets" ) {
1946 
1947  int numTargs = 3;
1948  int targs[3] = {0, 1, 1};
1949  pauliOpType paulis[3] = {PAULI_I};
1950  REQUIRE_THROWS_WITH( multiRotatePauli(quregVec, targs, paulis, numTargs, param), Contains("target") && Contains("unique"));
1951  }
1952  SECTION( "qubit indices" ) {
1953 
1954  int numTargs = 3;
1955  int targs[3] = {0, 1, 2};
1956  targs[GENERATE_COPY(range(0,numTargs))] = GENERATE( -1, NUM_QUBITS );
1957  pauliOpType paulis[3] = {PAULI_I};
1958  REQUIRE_THROWS_WITH( multiRotatePauli(quregVec, targs, paulis, numTargs, param), Contains("Invalid target"));
1959  }
1960  SECTION( "pauli codes" ) {
1961  int numTargs = 3;
1962  int targs[3] = {0, 1, 2};
1963  pauliOpType paulis[3] = {PAULI_I, PAULI_I, PAULI_I};
1964  paulis[GENERATE_COPY(range(0,numTargs))] = (pauliOpType) GENERATE( -1, 4 );
1965  REQUIRE_THROWS_WITH( multiRotatePauli(quregVec, targs, paulis, numTargs, param), Contains("Invalid Pauli code"));
1966  }
1967  }
1968  CLEANUP_TEST( quregVec, quregMatr );
1969 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, getExponentialOfPauliMatrix(), getKroneckerProduct(), getRandomInt(), getRandomReal(), M_PI, multiRotatePauli(), NUM_QUBITS, PAULI_I, PAULI_X, PAULI_Y, PAULI_Z, PREPARE_TEST, qcomp, qreal, and sublists().

◆ TEST_CASE() [104/124]

TEST_CASE ( "multiRotateZ"  ,
""  [unitaries] 
)
See also
multiRotateZ
Author
Tyson Jones

Definition at line 1977 of file test_unitaries.cpp.

1977  {
1978 
1979  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
1980  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
1981 
1982  SECTION( "correctness" ) {
1983 
1984  int numTargs = GENERATE( range(1,NUM_QUBITS+1) );
1985  int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
1986 
1987  // build correct reference matrix by diagonal-matrix exponentiation...
1988  QMatrix zMatr{{1,0},{0,-1}};
1989  QMatrix zProd = zMatr;
1990  for (int t=0; t<numTargs-1; t++)
1991  zProd = getKroneckerProduct(zMatr, zProd); // Z . Z ... Z
1992 
1993  // (-i param/2) Z . I . Z ...
1994  QMatrix expArg = qcomp(0, -param/2) *
1995  getFullOperatorMatrix(NULL, 0, targs, numTargs, zProd, NUM_QUBITS);
1996 
1997  // exp( -i param/2 Z . I . Z ...)
1999 
2000  // all qubits to specify full operator matrix on reference structures
2001  int allQubits[NUM_QUBITS];
2002  for (int i=0; i<NUM_QUBITS; i++)
2003  allQubits[i] = i;
2004 
2005  SECTION( "state-vector" ) {
2006 
2007  multiRotateZ(quregVec, targs, numTargs, param);
2008  applyReferenceOp(refVec, allQubits, NUM_QUBITS, op);
2009  REQUIRE( areEqual(quregVec, refVec) );
2010  }
2011  SECTION( "density-matrix" ) {
2012 
2013  multiRotateZ(quregMatr, targs, numTargs, param);
2014  applyReferenceOp(refMatr, allQubits, NUM_QUBITS, op);
2015  REQUIRE( areEqual(quregMatr, refMatr, 2*REAL_EPS) );
2016  }
2017  }
2018  SECTION( "input validation" ) {
2019 
2020  SECTION( "number of targets" ) {
2021 
2022  int numTargs = GENERATE( -1, 0, NUM_QUBITS+1 );
2023  int targs[NUM_QUBITS+1]; // prevent seg-fault if validation isn't triggered
2024  REQUIRE_THROWS_WITH( multiRotateZ(quregVec, targs, numTargs, param), Contains("Invalid number of target"));
2025 
2026  }
2027  SECTION( "repetition of targets" ) {
2028 
2029  int numTargs = 3;
2030  int targs[3] = {0, 1, 1};
2031  REQUIRE_THROWS_WITH( multiRotateZ(quregVec, targs, numTargs, param), Contains("target") && Contains("unique"));
2032  }
2033  SECTION( "qubit indices" ) {
2034 
2035  int numTargs = 3;
2036  int targs[3] = {0, 1, 2};
2037  targs[GENERATE_COPY(range(0,numTargs))] = GENERATE( -1, NUM_QUBITS );
2038  REQUIRE_THROWS_WITH( multiRotateZ(quregVec, targs, numTargs, param), Contains("Invalid target"));
2039  }
2040  }
2041  CLEANUP_TEST( quregVec, quregMatr );
2042 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, getExponentialOfDiagonalMatrix(), getFullOperatorMatrix(), getKroneckerProduct(), getRandomReal(), M_PI, multiRotateZ(), NUM_QUBITS, PREPARE_TEST, qcomp, qreal, and sublists().

◆ TEST_CASE() [105/124]

TEST_CASE ( "multiStateControlledUnitary"  ,
""  [unitaries] 
)
See also
multiStateControlledUnitary
Author
Tyson Jones

Definition at line 2050 of file test_unitaries.cpp.

2050  {
2051 
2052  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2053 
2054  // every test will use a unique random matrix
2055  QMatrix op = getRandomUnitary(1);
2056  ComplexMatrix2 matr = toComplexMatrix2(op);
2057 
2058  // the zero-conditioned control qubits can be effected by notting before/after ctrls
2059  QMatrix notOp{{0,1},{1,0}};
2060 
2061  SECTION( "correctness" ) {
2062 
2063  int target = GENERATE( range(0,NUM_QUBITS) );
2064  int numCtrls = GENERATE( range(1,NUM_QUBITS) ); // leave space for one target (exclusive upper bound)
2065  int* ctrls = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numCtrls, target) );
2066  int* ctrlState = GENERATE_COPY( bitsets(numCtrls) );
2067 
2068  SECTION( "state-vector" ) {
2069 
2070  multiStateControlledUnitary(quregVec, ctrls, ctrlState, numCtrls, target, matr);
2071 
2072  // simulate controlled-state by notting before & after controls
2073  for (int i=0; i<numCtrls; i++)
2074  if (ctrlState[i] == 0)
2075  applyReferenceOp(refVec, ctrls[i], notOp);
2076  applyReferenceOp(refVec, ctrls, numCtrls, target, op);
2077  for (int i=0; i<numCtrls; i++)
2078  if (ctrlState[i] == 0)
2079  applyReferenceOp(refVec, ctrls[i], notOp);
2080 
2081  REQUIRE( areEqual(quregVec, refVec) );
2082  }
2083  SECTION( "density-matrix" ) {
2084 
2085  multiStateControlledUnitary(quregMatr, ctrls, ctrlState, numCtrls, target, matr);
2086 
2087  // simulate controlled-state by notting before & after controls
2088  for (int i=0; i<numCtrls; i++)
2089  if (ctrlState[i] == 0)
2090  applyReferenceOp(refMatr, ctrls[i], notOp);
2091  applyReferenceOp(refMatr, ctrls, numCtrls, target, op);
2092  for (int i=0; i<numCtrls; i++)
2093  if (ctrlState[i] == 0)
2094  applyReferenceOp(refMatr, ctrls[i], notOp);
2095 
2096  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
2097  }
2098  }
2099  SECTION( "input validation" ) {
2100 
2101  SECTION( "number of controls" ) {
2102 
2103  int numCtrls = GENERATE( -1, 0, NUM_QUBITS, NUM_QUBITS+1 );
2104  int ctrls[NUM_QUBITS+1];
2105  int ctrlState[NUM_QUBITS+1] = {0};
2106  REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, numCtrls, 0, matr), Contains("Invalid number of control"));
2107  }
2108  SECTION( "repetition of controls" ) {
2109 
2110  int ctrls[] = {0,1,1};
2111  int ctrlState[] = {0, 1, 0};
2112  REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, 2, matr), Contains("control") && Contains("unique"));
2113  }
2114  SECTION( "control and target collision" ) {
2115 
2116  int ctrls[] = {0,1,2};
2117  int ctrlState[] = {0, 1, 0};
2118  int targ = ctrls[GENERATE( range(0,3) )];
2119  REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, targ, matr), Contains("Control") && Contains("target") );
2120  }
2121  SECTION( "qubit indices" ) {
2122 
2123  int ctrls[] = { 1, 2, GENERATE( -1, NUM_QUBITS ) };
2124  int ctrlState[] = {0, 1, 0};
2125  REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, 0, matr), Contains("Invalid control") );
2126 
2127  ctrls[2] = 3; // make ctrls valid
2128  int targ = GENERATE( -1, NUM_QUBITS );
2129  REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, targ, matr), Contains("Invalid target") );
2130  }
2131  SECTION( "unitarity" ) {
2132 
2133  matr.real[0][0] = 0; // break matr unitarity
2134  int ctrls[] = {0};
2135  int ctrlState[1] = {0};
2136  REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 1, 1, matr), Contains("unitary") );
2137  }
2138  SECTION( "control state bits" ) {
2139 
2140  // valid qubits
2141  int ctrls[] = {0, 1, 2};
2142  int ctrlState[] = {0, 0, 0};
2143  int targ = 3;
2144 
2145  // make invalid
2146  ctrlState[2] = GENERATE(-1, 2);
2147  REQUIRE_THROWS_WITH( multiStateControlledUnitary(quregVec, ctrls, ctrlState, 3, targ, matr), Contains("state") );
2148  }
2149  }
2150  CLEANUP_TEST( quregVec, quregMatr );
2151 }

References applyReferenceOp(), areEqual(), bitsets(), CLEANUP_TEST, getRandomUnitary(), multiStateControlledUnitary(), NUM_QUBITS, PREPARE_TEST, ComplexMatrix2::real, sublists(), and toComplexMatrix2().

◆ TEST_CASE() [106/124]

TEST_CASE ( "pauliX"  ,
""  [unitaries] 
)
See also
pauliX
Author
Tyson Jones

Definition at line 2159 of file test_unitaries.cpp.

2159  {
2160 
2161  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2162  QMatrix op{{0,1},{1,0}};
2163 
2164  SECTION( "correctness" ) {
2165 
2166  int target = GENERATE( range(0,NUM_QUBITS) );
2167 
2168  SECTION( "state-vector" ) {
2169 
2170  pauliX(quregVec, target);
2171  applyReferenceOp(refVec, target, op);
2172  REQUIRE( areEqual(quregVec, refVec) );
2173  }
2174  SECTION( "density-matrix correctness" ) {
2175 
2176  pauliX(quregMatr, target);
2177  applyReferenceOp(refMatr, target, op);
2178  REQUIRE( areEqual(quregMatr, refMatr) );
2179  }
2180  }
2181  SECTION( "input validation" ) {
2182 
2183  SECTION( "qubit indices" ) {
2184 
2185  int target = GENERATE( -1, NUM_QUBITS );
2186  REQUIRE_THROWS_WITH( pauliX(quregVec, target), Contains("Invalid target") );
2187  }
2188  }
2189  CLEANUP_TEST( quregVec, quregMatr );
2190 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, NUM_QUBITS, pauliX(), and PREPARE_TEST.

◆ TEST_CASE() [107/124]

TEST_CASE ( "pauliY"  ,
""  [unitaries] 
)
See also
pauliY
Author
Tyson Jones

Definition at line 2198 of file test_unitaries.cpp.

2198  {
2199 
2200  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2201  QMatrix op{{0,-qcomp(0,1)},{qcomp(0,1),0}};
2202 
2203  SECTION( "correctness" ) {
2204 
2205  int target = GENERATE( range(0,NUM_QUBITS) );
2206 
2207  SECTION( "state-vector" ) {
2208 
2209  pauliY(quregVec, target);
2210  applyReferenceOp(refVec, target, op);
2211  REQUIRE( areEqual(quregVec, refVec) );
2212  }
2213  SECTION( "density-matrix correctness" ) {
2214 
2215  pauliY(quregMatr, target);
2216  applyReferenceOp(refMatr, target, op);
2217  REQUIRE( areEqual(quregMatr, refMatr) );
2218  }
2219  }
2220  SECTION( "input validation" ) {
2221 
2222  SECTION( "qubit indices" ) {
2223 
2224  int target = GENERATE( -1, NUM_QUBITS );
2225  REQUIRE_THROWS_WITH( pauliY(quregVec, target), Contains("Invalid target") );
2226  }
2227  }
2228  CLEANUP_TEST( quregVec, quregMatr );
2229 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, NUM_QUBITS, pauliY(), PREPARE_TEST, and qcomp.

◆ TEST_CASE() [108/124]

TEST_CASE ( "pauliZ"  ,
""  [unitaries] 
)
See also
pauliZ
Author
Tyson Jones

Definition at line 2237 of file test_unitaries.cpp.

2237  {
2238 
2239  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2240  QMatrix op{{1,0},{0,-1}};
2241 
2242  SECTION( "correctness" ) {
2243 
2244  int target = GENERATE( range(0,NUM_QUBITS) );
2245 
2246  SECTION( "state-vector" ) {
2247 
2248  pauliZ(quregVec, target);
2249  applyReferenceOp(refVec, target, op);
2250  REQUIRE( areEqual(quregVec, refVec) );
2251  }
2252  SECTION( "density-matrix correctness" ) {
2253 
2254  pauliZ(quregMatr, target);
2255  applyReferenceOp(refMatr, target, op);
2256  REQUIRE( areEqual(quregMatr, refMatr) );
2257  }
2258  }
2259  SECTION( "input validation" ) {
2260 
2261  SECTION( "qubit indices" ) {
2262 
2263  int target = GENERATE( -1, NUM_QUBITS );
2264  REQUIRE_THROWS_WITH( pauliZ(quregVec, target), Contains("Invalid target") );
2265  }
2266  }
2267  CLEANUP_TEST( quregVec, quregMatr );
2268 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, NUM_QUBITS, pauliZ(), and PREPARE_TEST.

◆ TEST_CASE() [109/124]

TEST_CASE ( "phaseShift"  ,
""  [unitaries] 
)
See also
phaseShift
Author
Tyson Jones

Definition at line 2276 of file test_unitaries.cpp.

2276  {
2277 
2278  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2279  qreal param = getRandomReal(-2*M_PI, 2*M_PI);
2280  QMatrix op{{1,0},{0,expI(param)}};
2281 
2282  SECTION( "correctness" ) {
2283 
2284  int target = GENERATE( range(0,NUM_QUBITS) );
2285 
2286  SECTION( "state-vector ") {
2287 
2288  phaseShift(quregVec, target, param);
2289  applyReferenceOp(refVec, target, op);
2290  REQUIRE( areEqual(quregVec, refVec) );
2291  }
2292  SECTION( "density-matrix" ) {
2293 
2294  phaseShift(quregMatr, target, param);
2295  applyReferenceOp(refMatr, target, op);
2296  REQUIRE( areEqual(quregMatr, refMatr) );
2297  }
2298  }
2299  SECTION( "input validation" ) {
2300 
2301  SECTION( "qubit indices" ) {
2302 
2303  int target = GENERATE( -1, NUM_QUBITS );
2304  REQUIRE_THROWS_WITH( phaseShift(quregVec, target, param), Contains("Invalid target") );
2305  }
2306  }
2307  CLEANUP_TEST( quregVec, quregMatr );
2308 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, expI(), getRandomReal(), M_PI, NUM_QUBITS, phaseShift(), PREPARE_TEST, and qreal.

◆ TEST_CASE() [110/124]

TEST_CASE ( "rotateAroundAxis"  ,
""  [unitaries] 
)
See also
rotateAroundAxis
Author
Tyson Jones

Definition at line 2316 of file test_unitaries.cpp.

2316  {
2317 
2318  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2319 
2320  // each test will use a random parameter and axis vector
2321  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
2322  Vector vec = {.x=getRandomReal(-1,1), .y=getRandomReal(-1,1), .z=getRandomReal(-1,1)};
2323 
2324  // Rn(a) = cos(a/2)I - i sin(a/2) n . paulivector
2325  // (pg 24 of vcpc.univie.ac.at/~ian/hotlist/qc/talks/bloch-sphere-rotations.pdf)
2326  qreal c = cos(param/2);
2327  qreal s = sin(param/2);
2328  qreal m = sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z);
2329  QMatrix op{{c - qcomp(0,1)*vec.z*s/m, -(vec.y + qcomp(0,1)*vec.x)*s/m},
2330  {(vec.y - qcomp(0,1)*vec.x)*s/m, c + qcomp(0,1)*vec.z*s/m}};
2331 
2332  SECTION( "correctness" ) {
2333 
2334  int target = GENERATE( range(0,NUM_QUBITS) );
2335 
2336  SECTION( "state-vector ") {
2337 
2338  rotateAroundAxis(quregVec, target, param, vec);
2339  applyReferenceOp(refVec, target, op);
2340  REQUIRE( areEqual(quregVec, refVec) );
2341  }
2342  SECTION( "density-matrix" ) {
2343 
2344  rotateAroundAxis(quregMatr, target, param, vec);
2345  applyReferenceOp(refMatr, target, op);
2346  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
2347  }
2348  }
2349  SECTION( "input validation" ) {
2350 
2351  SECTION( "qubit indices" ) {
2352 
2353  int target = GENERATE( -1, NUM_QUBITS );
2354  REQUIRE_THROWS_WITH( rotateAroundAxis(quregVec, target, param, vec), Contains("Invalid target") );
2355  }
2356  SECTION( "zero rotation axis" ) {
2357 
2358  int target = 0;
2359  vec = {.x=0, .y=0, .z=0};
2360  REQUIRE_THROWS_WITH( rotateAroundAxis(quregVec, target, param, vec), Contains("Invalid axis") && Contains("zero") );
2361  }
2362  }
2363  CLEANUP_TEST( quregVec, quregMatr );
2364 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, getRandomReal(), M_PI, NUM_QUBITS, PREPARE_TEST, qcomp, qreal, rotateAroundAxis(), Vector::x, Vector::y, and Vector::z.

◆ TEST_CASE() [111/124]

TEST_CASE ( "rotateX"  ,
""  [unitaries] 
)
See also
rotateX
Author
Tyson Jones

Definition at line 2372 of file test_unitaries.cpp.

2372  {
2373 
2374  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2375  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
2376  QMatrix op{
2377  {cos(param/2), - sin(param/2)*qcomp(0,1)},
2378  {- sin(param/2)*qcomp(0,1), cos(param/2)}};
2379 
2380  SECTION( "correctness" ) {
2381 
2382  int target = GENERATE( range(0,NUM_QUBITS) );
2383 
2384  SECTION( "state-vector ") {
2385 
2386  rotateX(quregVec, target, param);
2387  applyReferenceOp(refVec, target, op);
2388  REQUIRE( areEqual(quregVec, refVec) );
2389  }
2390  SECTION( "density-matrix" ) {
2391 
2392  rotateX(quregMatr, target, param);
2393  applyReferenceOp(refMatr, target, op);
2394  REQUIRE( areEqual(quregMatr, refMatr) );
2395  }
2396  }
2397  SECTION( "input validation" ) {
2398 
2399  SECTION( "qubit indices" ) {
2400 
2401  int target = GENERATE( -1, NUM_QUBITS );
2402  REQUIRE_THROWS_WITH( rotateX(quregVec, target, param), Contains("Invalid target") );
2403  }
2404  }
2405  CLEANUP_TEST( quregVec, quregMatr );
2406 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, getRandomReal(), M_PI, NUM_QUBITS, PREPARE_TEST, qcomp, qreal, and rotateX().

◆ TEST_CASE() [112/124]

TEST_CASE ( "rotateY"  ,
""  [unitaries] 
)
See also
rotateY
Author
Tyson Jones

Definition at line 2414 of file test_unitaries.cpp.

2414  {
2415 
2416  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2417  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
2418  QMatrix op{{cos(param/2), -sin(param/2)},{sin(param/2), cos(param/2)}};
2419 
2420  SECTION( "correctness" ) {
2421 
2422  int target = GENERATE( range(0,NUM_QUBITS) );
2423 
2424  SECTION( "state-vector ") {
2425 
2426  rotateY(quregVec, target, param);
2427  applyReferenceOp(refVec, target, op);
2428  REQUIRE( areEqual(quregVec, refVec) );
2429  }
2430  SECTION( "density-matrix" ) {
2431 
2432  rotateY(quregMatr, target, param);
2433  applyReferenceOp(refMatr, target, op);
2434  REQUIRE( areEqual(quregMatr, refMatr, 2*REAL_EPS) );
2435  }
2436  }
2437  SECTION( "input validation" ) {
2438 
2439  SECTION( "qubit indices" ) {
2440 
2441  int target = GENERATE( -1, NUM_QUBITS );
2442  REQUIRE_THROWS_WITH( rotateY(quregVec, target, param), Contains("Invalid target") );
2443  }
2444  }
2445  CLEANUP_TEST( quregVec, quregMatr );
2446 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, getRandomReal(), M_PI, NUM_QUBITS, PREPARE_TEST, qreal, and rotateY().

◆ TEST_CASE() [113/124]

TEST_CASE ( "rotateZ"  ,
""  [unitaries] 
)
See also
rotateZ
Author
Tyson Jones

Definition at line 2454 of file test_unitaries.cpp.

2454  {
2455 
2456  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2457  qreal param = getRandomReal(-4*M_PI, 4*M_PI);
2458  QMatrix op{{expI(-param/2.),0},{0,expI(param/2.)}};
2459 
2460  SECTION( "correctness" ) {
2461 
2462  int target = GENERATE( range(0,NUM_QUBITS) );
2463 
2464  SECTION( "state-vector ") {
2465 
2466  rotateZ(quregVec, target, param);
2467  applyReferenceOp(refVec, target, op);
2468  REQUIRE( areEqual(quregVec, refVec) );
2469  }
2470  SECTION( "density-matrix" ) {
2471 
2472  rotateZ(quregMatr, target, param);
2473  applyReferenceOp(refMatr, target, op);
2474  REQUIRE( areEqual(quregMatr, refMatr) );
2475  }
2476  }
2477  SECTION( "input validation" ) {
2478 
2479  SECTION( "qubit indices" ) {
2480 
2481  int target = GENERATE( -1, NUM_QUBITS );
2482  REQUIRE_THROWS_WITH( rotateZ(quregVec, target, param), Contains("Invalid target") );
2483  }
2484  }
2485  CLEANUP_TEST( quregVec, quregMatr );
2486 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, expI(), getRandomReal(), M_PI, NUM_QUBITS, PREPARE_TEST, qreal, and rotateZ().

◆ TEST_CASE() [114/124]

TEST_CASE ( "setAmps"  ,
""  [state_initialisations] 
)
See also
setAmps
Author
Tyson Jones

Definition at line 381 of file test_state_initialisations.cpp.

381  {
382 
384 
385  int maxInd = vec.numAmpsTotal;
386  qreal reals[maxInd];
387  qreal imags[maxInd];
388 
389  SECTION( "correctness" ) {
390 
391  SECTION( "state-vector" ) {
392 
393  // all valid number of amplitudes and offsets
394  int startInd = GENERATE_COPY( range(0,maxInd) );
395  int numAmps = GENERATE_COPY( range(0,1+maxInd-startInd) ); // upper-bound allows all amps specified
396 
397  // generate random amplitudes
398  for (int i=0; i<numAmps; i++) {
399  reals[i] = getRandomReal(-5,5);
400  imags[i] = getRandomReal(-5,5);
401  }
402 
403  // check both specified and un-specified amplitudes are correctly handled
404  initDebugState(vec);
405  QVector vecRef = toQVector(vec);
406 
407  setAmps(vec, startInd, reals, imags, numAmps);
408  for (int i=0; i<numAmps; i++)
409  vecRef[startInd+i] = reals[i] + imags[i] * (qcomp) 1i;
410 
411  REQUIRE( areEqual(vec, vecRef) );
412  }
413  }
414  SECTION( "input validation" ) {
415 
416  SECTION( "start index" ) {
417 
418  int startInd = GENERATE_COPY( -1, maxInd );
419  int numAmps = 0;
420  REQUIRE_THROWS_WITH( setAmps(vec, startInd, reals, imags, numAmps), Contains("Invalid amplitude index") );
421  }
422 
423  SECTION( "number of amplitudes" ) {
424 
425  // independent
426  int startInd = 0;
427  int numAmps = GENERATE_COPY( -1, maxInd+1 );
428  REQUIRE_THROWS_WITH( setAmps(vec, startInd, reals, imags, numAmps), Contains("Invalid number of amplitudes") );
429 
430  // invalid considering start-index
431  startInd = maxInd - 1;
432  numAmps = 2;
433  REQUIRE_THROWS_WITH( setAmps(vec, startInd, reals, imags, numAmps), Contains("More amplitudes given than exist") );
434  }
435  SECTION( "density-matrix" ) {
436 
438  REQUIRE_THROWS_WITH( setAmps(mat, 0, reals, imags, 0), Contains("valid only for state-vectors") );
439  destroyQureg(mat, QUEST_ENV);
440  }
441  }
442  destroyQureg(vec, QUEST_ENV);
443 }

References areEqual(), createDensityQureg(), createQureg(), destroyQureg(), getRandomReal(), initDebugState(), NUM_QUBITS, Qureg::numAmpsTotal, qcomp, qreal, QUEST_ENV, setAmps(), and toQVector().

◆ TEST_CASE() [115/124]

TEST_CASE ( "setDiagonalOpElems"  ,
""  [data_structures] 
)
See also
setDiagonalOpElems
Author
Tyson Jones

Definition at line 966 of file test_data_structures.cpp.

966  {
967 
968  // must be at least one amplitude per node
969  int minNumQb = calcLog2(QUEST_ENV.numRanks);
970  if (minNumQb == 0)
971  minNumQb = 1;
972 
973  // try 10 valid number of qubits (even for validation)
974  int numQb = GENERATE_COPY( range(minNumQb, minNumQb+10) );
976 
977  SECTION( "correctness" ) {
978 
979  // make entire array on every node
980  long long int len = (1LL << numQb);
981  qreal reals[len];
982  qreal imags[len];
983  long long int n;
984  for (n=0; n<len; n++) {
985  reals[n] = (qreal) n;
986  imags[n] = (qreal) -2*n; // (n - 2n i)
987  }
988 
989  // set one value at a time (only relevant nodes will update)
990  for (n=0; n<len; n++)
991  setDiagonalOpElems(op, n, &reals[n], &imags[n], 1);
992 
993  // check op.real and op.imag updated correctly
994  REQUIRE( areEqual(toQVector(op), reals, imags) );
995 
996  // no check that GPU values updated (occurs in initDiagonalOp)
997  }
998  SECTION( "input validation" ) {
999 
1000  long long int maxInd = (1LL << numQb);
1001  qreal *reals;
1002  qreal *imags;
1003 
1004  SECTION( "start index" ) {
1005 
1006  int startInd = GENERATE_COPY( -1, maxInd );
1007  int numAmps = 1;
1008  REQUIRE_THROWS_WITH( setDiagonalOpElems(op, startInd, reals, imags, numAmps), Contains("Invalid element index") );
1009  }
1010 
1011  SECTION( "number of elements" ) {
1012 
1013  // independent
1014  int startInd = 0;
1015  int numAmps = GENERATE_COPY( -1, maxInd+1 );
1016  REQUIRE_THROWS_WITH( setDiagonalOpElems(op, startInd, reals, imags, numAmps), Contains("Invalid number of elements") );
1017 
1018  // invalid considering start-index
1019  startInd = maxInd - 1;
1020  numAmps = 2;
1021  REQUIRE_THROWS_WITH( setDiagonalOpElems(op, startInd, reals, imags, numAmps), Contains("More elements given than exist") );
1022  }
1023  }
1024 
1026 }

References areEqual(), calcLog2(), createDiagonalOp(), destroyDiagonalOp(), QuESTEnv::numRanks, qreal, QUEST_ENV, setDiagonalOpElems(), and toQVector().

◆ TEST_CASE() [116/124]

TEST_CASE ( "setWeightedQureg"  ,
""  [state_initialisations] 
)
See also
setWeightedQureg
Author
Tyson Jones

Definition at line 451 of file test_state_initialisations.cpp.

451  {
452 
453  SECTION( "correctness" ) {
454 
455  // repeat each test below 10 times
456  GENERATE( range(0,10) );
457 
458  /* note tolerance in areEqual increases with tests, since
459  * small differences propogate in vecC which is not re-initialised
460  */
461 
462  SECTION( "state-vector" ) {
463 
464  // make three random vectors
468  for (int j=0; j<vecA.numAmpsPerChunk; j++) {
469  vecA.stateVec.real[j] = getRandomReal(-5,5); vecA.stateVec.imag[j] = getRandomReal(-5,5);
470  vecB.stateVec.real[j] = getRandomReal(-5,5); vecB.stateVec.imag[j] = getRandomReal(-5,5);
471  vecC.stateVec.real[j] = getRandomReal(-5,5); vecC.stateVec.imag[j] = getRandomReal(-5,5);
472  }
473  copyStateToGPU(vecA); copyStateToGPU(vecB); copyStateToGPU(vecC);
474  QVector refA = toQVector(vecA);
475  QVector refB = toQVector(vecB);
476  QVector refC = toQVector(vecC);
477  QVector refOut;
478 
479  // get three random factors
480  qcomp numA = getRandomReal(-5,5) + getRandomReal(-5,5) * (qcomp) 1i;
481  qcomp numB = getRandomReal(-5,5) + getRandomReal(-5,5) * (qcomp) 1i;
482  qcomp numC = getRandomReal(-5,5) + getRandomReal(-5,5) * (qcomp) 1i;
483  Complex facA = toComplex(numA);
484  Complex facB = toComplex(numB);
485  Complex facC = toComplex(numC);
486 
487  // check out-qureg is correct, when all quregs are unique...
488  setWeightedQureg(facA, vecA, facB, vecB, facC, vecC);
489  refOut = numA*refA + numB*refB + numC*refC;
490  REQUIRE( areEqual(vecC, refOut) );
491 
492  // ... and that other qureg's aren't modified
493  REQUIRE( areEqual(vecA, refA) );
494  REQUIRE( areEqual(vecB, refB) );
495 
496  // check quregOut correct, when it's also qureg2
497  refC = toQVector(vecC);
498  setWeightedQureg(facB, vecB, facC, vecC, facA, vecC);
499  refOut = numB*refB + numC*refC + numA*refC;
500  REQUIRE( areEqual(vecC, refOut, 10*REAL_EPS) );
501 
502  // ... and that the remaining qureg is not modified
503  REQUIRE( areEqual(vecB, refB) );
504 
505  // check quregOut correct, when it's also qureg1
506  refC = toQVector(vecC);
507  setWeightedQureg(facC, vecC, facB, vecB, facA, vecC);
508  refOut = numC*refC + numB*refB + numA*refC;
509  REQUIRE( areEqual(vecC, refOut, 10*REAL_EPS) );
510 
511  // ... and that the remaining qureg is not modified
512  REQUIRE( areEqual(vecB, refB) );
513 
514  // check quregOut is correct when it's both input quregs
515  refC = toQVector(vecC);
516  setWeightedQureg(facA, vecC, facB, vecC, facC, vecC);
517  refOut = numA*refC + numB*refC + numC*refC;
518  REQUIRE( areEqual(vecC, refOut, 1E3*REAL_EPS) );
519 
520  // cleanup
521  destroyQureg(vecA, QUEST_ENV);
522  destroyQureg(vecB, QUEST_ENV);
523  destroyQureg(vecC, QUEST_ENV);
524  }
525  SECTION( "density-matrix" ) {
526 
527  // make three random matrices
531  for (int j=0; j<matA.numAmpsPerChunk; j++) {
532  matA.stateVec.real[j] = getRandomReal(-5,5); matA.stateVec.imag[j] = getRandomReal(-5,5);
533  matB.stateVec.real[j] = getRandomReal(-5,5); matB.stateVec.imag[j] = getRandomReal(-5,5);
534  matC.stateVec.real[j] = getRandomReal(-5,5); matC.stateVec.imag[j] = getRandomReal(-5,5);
535  }
536  copyStateToGPU(matA); copyStateToGPU(matB); copyStateToGPU(matC);
537  QMatrix refA = toQMatrix(matA);
538  QMatrix refB = toQMatrix(matB);
539  QMatrix refC = toQMatrix(matC);
540  QMatrix refOut;
541 
542  // get three random factors
543  qcomp numA = getRandomReal(-5,5) + getRandomReal(-5,5) * (qcomp) 1i;
544  qcomp numB = getRandomReal(-5,5) + getRandomReal(-5,5) * (qcomp) 1i;
545  qcomp numC = getRandomReal(-5,5) + getRandomReal(-5,5) * (qcomp) 1i;
546  Complex facA = toComplex(numA);
547  Complex facB = toComplex(numB);
548  Complex facC = toComplex(numC);
549 
550  // check out-qureg is correct, when all quregs are unique...
551  setWeightedQureg(facA, matA, facB, matB, facC, matC);
552  refOut = numA*refA + numB*refB + numC*refC;
553  REQUIRE( areEqual(matC, refOut) );
554 
555  // ... and that other qureg's aren't modified
556  REQUIRE( areEqual(matA, refA) );
557  REQUIRE( areEqual(matB, refB) );
558 
559  // check quregOut correct, when it's also qureg2
560  refC = toQMatrix(matC);
561  setWeightedQureg(facB, matB, facC, matC, facA, matC);
562  refOut = numB*refB + numC*refC + numA*refC;
563  REQUIRE( areEqual(matC, refOut, 10*REAL_EPS) );
564 
565  // ... and that the remaining qureg is not modified
566  REQUIRE( areEqual(matB, refB) );
567 
568  // check quregOut correct, when it's also qureg1
569  refC = toQMatrix(matC);
570  setWeightedQureg(facC, matC, facB, matB, facA, matC);
571  refOut = numC*refC + numB*refB + numA*refC;
572  REQUIRE( areEqual(matC, refOut, 1E2*REAL_EPS) );
573 
574  // ... and that the remaining qureg is not modified
575  REQUIRE( areEqual(matB, refB) );
576 
577  // check quregOut is correct when it's both input quregs
578  refC = toQMatrix(matC);
579  setWeightedQureg(facA, matC, facB, matC, facC, matC);
580  refOut = numA*refC + numB*refC + numC*refC;
581  REQUIRE( areEqual(matC, refOut, 1E3*REAL_EPS) );
582 
583  // cleanup
584  destroyQureg(matA, QUEST_ENV);
585  destroyQureg(matB, QUEST_ENV);
586  destroyQureg(matC, QUEST_ENV);
587  }
588  }
589  SECTION( "input validation" ) {
590 
591  SECTION( "qureg types" ) {
592 
595  Complex f = {.real=0, .imag=0};
596 
597  // two state-vecs, one density-matrix
598  REQUIRE_THROWS_WITH( setWeightedQureg(f, mat, f, vec, f, vec), Contains("state-vectors or") && Contains("density matrices") );
599  REQUIRE_THROWS_WITH( setWeightedQureg(f, vec, f, mat, f, vec), Contains("state-vectors or") && Contains("density matrices") );
600  REQUIRE_THROWS_WITH( setWeightedQureg(f, vec, f, vec, f, mat), Contains("state-vectors or") && Contains("density matrices") );
601 
602  // one state-vec, two density-matrices
603  REQUIRE_THROWS_WITH( setWeightedQureg(f, vec, f, mat, f, mat), Contains("state-vectors or") && Contains("density matrices") );
604  REQUIRE_THROWS_WITH( setWeightedQureg(f, mat, f, vec, f, mat), Contains("state-vectors or") && Contains("density matrices") );
605  REQUIRE_THROWS_WITH( setWeightedQureg(f, mat, f, mat, f, vec), Contains("state-vectors or") && Contains("density matrices") );
606 
607  destroyQureg(vec, QUEST_ENV);
608  destroyQureg(mat, QUEST_ENV);
609  }
610  SECTION( "qureg dimensions" ) {
611 
613  Qureg vecB = createQureg(NUM_QUBITS + 1, QUEST_ENV);
616  Complex f = {.real=0, .imag=0};
617 
618  // state-vecs
619  REQUIRE_THROWS_WITH( setWeightedQureg(f, vecA, f, vecB, f, vecB), Contains("Dimensions") );
620  REQUIRE_THROWS_WITH( setWeightedQureg(f, vecB, f, vecA, f, vecB), Contains("Dimensions") );
621  REQUIRE_THROWS_WITH( setWeightedQureg(f, vecB, f, vecB, f, vecA), Contains("Dimensions") );
622 
623  // density-matrices
624  REQUIRE_THROWS_WITH( setWeightedQureg(f, matA, f, matB, f, matB), Contains("Dimensions") );
625  REQUIRE_THROWS_WITH( setWeightedQureg(f, matB, f, matA, f, matB), Contains("Dimensions") );
626  REQUIRE_THROWS_WITH( setWeightedQureg(f, matB, f, matB, f, matA), Contains("Dimensions") );
627 
628  destroyQureg(vecA, QUEST_ENV);
629  destroyQureg(vecB, QUEST_ENV);
630  destroyQureg(matA, QUEST_ENV);
631  destroyQureg(matB, QUEST_ENV);
632  }
633  }
634 }

References areEqual(), copyStateToGPU(), createDensityQureg(), createQureg(), destroyQureg(), getRandomReal(), NUM_QUBITS, Qureg::numAmpsPerChunk, qcomp, QUEST_ENV, Complex::real, setWeightedQureg(), Qureg::stateVec, toComplex, toQMatrix(), and toQVector().

◆ TEST_CASE() [117/124]

TEST_CASE ( "sGate"  ,
""  [unitaries] 
)
See also
sGate
Author
Tyson Jones

Definition at line 2494 of file test_unitaries.cpp.

2494  {
2495 
2496  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2497  QMatrix op{{1,0},{0,qcomp(0,1)}};
2498 
2499  SECTION( "correctness" ) {
2500 
2501  int target = GENERATE( range(0,NUM_QUBITS) );
2502 
2503  SECTION( "state-vector ") {
2504 
2505  sGate(quregVec, target);
2506  applyReferenceOp(refVec, target, op);
2507  REQUIRE( areEqual(quregVec, refVec) );
2508  }
2509  SECTION( "density-matrix" ) {
2510 
2511  sGate(quregMatr, target);
2512  applyReferenceOp(refMatr, target, op);
2513  REQUIRE( areEqual(quregMatr, refMatr) );
2514  }
2515  }
2516  SECTION( "input validation" ) {
2517 
2518  SECTION( "qubit indices" ) {
2519 
2520  int target = GENERATE( -1, NUM_QUBITS );
2521  REQUIRE_THROWS_WITH( sGate(quregVec, target), Contains("Invalid target") );
2522  }
2523  }
2524  CLEANUP_TEST( quregVec, quregMatr );
2525 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, NUM_QUBITS, PREPARE_TEST, qcomp, and sGate().

◆ TEST_CASE() [118/124]

TEST_CASE ( "sqrtSwapGate"  ,
""  [unitaries] 
)
See also
sqrtSwapGate
Author
Tyson Jones

Definition at line 2533 of file test_unitaries.cpp.

2533  {
2534 
2535  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2536  qcomp a = qcomp(.5, .5);
2537  qcomp b = qcomp(.5, -.5);
2538  QMatrix op{{1,0,0,0},{0,a,b,0},{0,b,a,0},{0,0,0,1}};
2539 
2540  SECTION( "correctness" ) {
2541 
2542  int targ1 = GENERATE( range(0,NUM_QUBITS) );
2543  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
2544  int targs[] = {targ1, targ2};
2545 
2546  SECTION( "state-vector" ) {
2547 
2548  sqrtSwapGate(quregVec, targ1, targ2);
2549  applyReferenceOp(refVec, targs, 2, op);
2550  REQUIRE( areEqual(quregVec, refVec) );
2551  }
2552  SECTION( "density-matrix" ) {
2553 
2554  sqrtSwapGate(quregMatr, targ1, targ2);
2555  applyReferenceOp(refMatr, targs, 2, op);
2556  REQUIRE( areEqual(quregMatr, refMatr) );
2557  }
2558  }
2559  SECTION( "input validation" ) {
2560 
2561  SECTION( "qubit indices" ) {
2562 
2563  int targ1 = GENERATE( -1, NUM_QUBITS );
2564  int targ2 = 0;
2565  REQUIRE_THROWS_WITH( sqrtSwapGate(quregVec, targ1, targ2), Contains("Invalid target") );
2566  REQUIRE_THROWS_WITH( sqrtSwapGate(quregVec, targ2, targ1), Contains("Invalid target") );
2567  }
2568  SECTION( "repetition of targets" ) {
2569 
2570  int qb = 0;
2571  REQUIRE_THROWS_WITH( sqrtSwapGate(quregVec, qb, qb), Contains("target") && Contains("unique") );
2572  }
2573  }
2574  CLEANUP_TEST( quregVec, quregMatr );
2575 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, NUM_QUBITS, PREPARE_TEST, qcomp, and sqrtSwapGate().

◆ TEST_CASE() [119/124]

TEST_CASE ( "swapGate"  ,
""  [unitaries] 
)
See also
swapGate
Author
Tyson Jones

Definition at line 2583 of file test_unitaries.cpp.

2583  {
2584 
2585  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2586  QMatrix op{{1,0,0,0},{0,0,1,0},{0,1,0,0},{0,0,0,1}};
2587 
2588  SECTION( "correctness" ) {
2589 
2590  int targ1 = GENERATE( range(0,NUM_QUBITS) );
2591  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
2592  int targs[] = {targ1, targ2};
2593 
2594  SECTION( "state-vector" ) {
2595 
2596  swapGate(quregVec, targ1, targ2);
2597  applyReferenceOp(refVec, targs, 2, op);
2598  REQUIRE( areEqual(quregVec, refVec) );
2599  }
2600  SECTION( "density-matrix" ) {
2601 
2602  swapGate(quregMatr, targ1, targ2);
2603  applyReferenceOp(refMatr, targs, 2, op);
2604  REQUIRE( areEqual(quregMatr, refMatr) );
2605  }
2606  }
2607  SECTION( "input validation" ) {
2608 
2609  SECTION( "qubit indices" ) {
2610 
2611  int targ1 = GENERATE( -1, NUM_QUBITS );
2612  int targ2 = 0;
2613  REQUIRE_THROWS_WITH( swapGate(quregVec, targ1, targ2), Contains("Invalid target") );
2614  REQUIRE_THROWS_WITH( swapGate(quregVec, targ2, targ1), Contains("Invalid target") );
2615  }
2616  SECTION( "repetition of targets" ) {
2617 
2618  int qb = 0;
2619  REQUIRE_THROWS_WITH( swapGate(quregVec, qb, qb), Contains("target") && Contains("unique") );
2620  }
2621  }
2622  CLEANUP_TEST( quregVec, quregMatr );
2623 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, NUM_QUBITS, PREPARE_TEST, and swapGate().

◆ TEST_CASE() [120/124]

TEST_CASE ( "syncDiagonalOp"  ,
""  [data_structures] 
)
See also
syncDiagonalOp
Author
Tyson Jones

Definition at line 1034 of file test_data_structures.cpp.

1034  {
1035 
1036  // must be at least one amplitude per node
1037  int minNumQb = calcLog2(QUEST_ENV.numRanks);
1038  if (minNumQb == 0)
1039  minNumQb = 1;
1040 
1041  SECTION( "correctness" ) {
1042 
1043  // try 10 valid number of qubits
1044  int numQb = GENERATE_COPY( range(minNumQb, minNumQb+10) );
1045  DiagonalOp op = createDiagonalOp(numQb, QUEST_ENV);
1046 
1047  // check that changes get sync'd to the GPU...
1048  long long int n;
1049  for (n=0; n<op.numElemsPerChunk; n++) {
1050  op.real[n] = (qreal) n;
1051  op.imag[n] = (qreal) -2*n; // (n - 2n i)
1052  }
1053  syncDiagonalOp(op);
1054 
1055  // via if it modifies an all-unity state-vec correctly
1056  Qureg qureg = createQureg(numQb, QUEST_ENV);
1057  for (long long int i=0; i<qureg.numAmpsPerChunk; i++) {
1058  qureg.stateVec.real[i] = 1;
1059  qureg.stateVec.imag[i] = 1;
1060  }
1061  copyStateToGPU(qureg);
1062 
1063  // (n - 2n i) * (1 + 1i) = 3n - n*i
1064  applyDiagonalOp(qureg, op);
1065  copyStateFromGPU(qureg);
1066  for (n=0; n<qureg.numAmpsPerChunk; n++) {
1067  REQUIRE( qureg.stateVec.real[n] == 3*n );
1068  REQUIRE( qureg.stateVec.imag[n] == -n );
1069  }
1070 
1071  destroyQureg(qureg, QUEST_ENV);
1073  }
1074 }

References applyDiagonalOp(), calcLog2(), copyStateFromGPU(), copyStateToGPU(), createDiagonalOp(), createQureg(), destroyDiagonalOp(), destroyQureg(), DiagonalOp::imag, Qureg::numAmpsPerChunk, DiagonalOp::numElemsPerChunk, QuESTEnv::numRanks, qreal, QUEST_ENV, DiagonalOp::real, Qureg::stateVec, and syncDiagonalOp().

◆ TEST_CASE() [121/124]

TEST_CASE ( "tGate"  ,
""  [unitaries] 
)
See also
tGate
Author
Tyson Jones

Definition at line 2631 of file test_unitaries.cpp.

2631  {
2632 
2633  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2634  QMatrix op{{1,0},{0,expI(M_PI/4.)}};
2635 
2636  SECTION( "correctness" ) {
2637 
2638  int target = GENERATE( range(0,NUM_QUBITS) );
2639 
2640  SECTION( "state-vector ") {
2641 
2642  tGate(quregVec, target);
2643  applyReferenceOp(refVec, target, op);
2644  REQUIRE( areEqual(quregVec, refVec) );
2645  }
2646  SECTION( "density-matrix" ) {
2647 
2648  tGate(quregMatr, target);
2649  applyReferenceOp(refMatr, target, op);
2650  REQUIRE( areEqual(quregMatr, refMatr) );
2651  }
2652  }
2653  SECTION( "input validation" ) {
2654 
2655  SECTION( "qubit indices" ) {
2656 
2657  int target = GENERATE( -1, NUM_QUBITS );
2658  REQUIRE_THROWS_WITH( tGate(quregVec, target), Contains("Invalid target") );
2659  }
2660  }
2661  CLEANUP_TEST( quregVec, quregMatr );
2662 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, expI(), M_PI, NUM_QUBITS, PREPARE_TEST, and tGate().

◆ TEST_CASE() [122/124]

TEST_CASE ( "toComplex"  ,
""  [data_structures] 
)
See also
toComplex
Author
Tyson Jones

Definition at line 42 of file test_data_structures.cpp.

42  {
43 
44  qcomp a = qcomp(.5,-.2);
45  Complex b = toComplex(a);
46 
47  REQUIRE( real(a) == b.real );
48  REQUIRE( imag(a) == b.imag );
49 }

References Complex::imag, qcomp, Complex::real, and toComplex.

◆ TEST_CASE() [123/124]

TEST_CASE ( "twoQubitUnitary"  ,
""  [unitaries] 
)
See also
twoQubitUnitary
Author
Tyson Jones

Definition at line 2670 of file test_unitaries.cpp.

2670  {
2671 
2672  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2673 
2674  // in distributed mode, each node must be able to fit all amps modified by unitary
2675  REQUIRE( quregVec.numAmpsPerChunk >= 4 );
2676 
2677  // every test will use a unique random matrix
2678  QMatrix op = getRandomUnitary(2);
2679  ComplexMatrix4 matr = toComplexMatrix4(op);
2680 
2681  SECTION( "correctness" ) {
2682 
2683  int targ1 = GENERATE( range(0,NUM_QUBITS) );
2684  int targ2 = GENERATE_COPY( filter([=](int t){ return t!=targ1; }, range(0,NUM_QUBITS)) );
2685  int targs[] = {targ1, targ2};
2686 
2687  SECTION( "state-vector" ) {
2688 
2689  twoQubitUnitary(quregVec, targ1, targ2, matr);
2690  applyReferenceOp(refVec, targs, 2, op);
2691  REQUIRE( areEqual(quregVec, refVec) );
2692  }
2693  SECTION( "density-matrix" ) {
2694 
2695  twoQubitUnitary(quregMatr, targ1, targ2, matr);
2696  applyReferenceOp(refMatr, targs, 2, op);
2697  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
2698  }
2699  }
2700  SECTION( "input validation" ) {
2701 
2702  SECTION( "qubit indices" ) {
2703 
2704  int targ1 = GENERATE( -1, NUM_QUBITS );
2705  int targ2 = 0;
2706  REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, targ1, targ2, matr), Contains("Invalid target") );
2707  REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, targ2, targ1, matr), Contains("Invalid target") );
2708  }
2709  SECTION( "repetition of targets" ) {
2710 
2711  int qb = 0;
2712  REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, qb, qb, matr), Contains("target") && Contains("unique") );
2713  }
2714  SECTION( "unitarity" ) {
2715 
2716  matr.real[0][0] = 0; // break matr unitarity
2717  REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, 0, 1, matr), Contains("unitary") );
2718  }
2719  SECTION( "unitary fits in node" ) {
2720 
2721  // pretend we have a very limited distributed memory
2722  quregVec.numAmpsPerChunk = 1;
2723  REQUIRE_THROWS_WITH( twoQubitUnitary(quregVec, 0, 1, matr), Contains("targets too many qubits"));
2724  }
2725  }
2726  CLEANUP_TEST( quregVec, quregMatr );
2727 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, getRandomUnitary(), NUM_QUBITS, PREPARE_TEST, ComplexMatrix4::real, toComplexMatrix4(), and twoQubitUnitary().

◆ TEST_CASE() [124/124]

TEST_CASE ( "unitary"  ,
""  [unitaries] 
)
See also
unitary
Author
Tyson Jones

Definition at line 2735 of file test_unitaries.cpp.

2735  {
2736 
2737  PREPARE_TEST( quregVec, quregMatr, refVec, refMatr );
2738 
2739  // every test will use a unique random matrix
2740  QMatrix op = getRandomUnitary(1);
2741  ComplexMatrix2 matr = toComplexMatrix2(op);
2742 
2743  SECTION( "correctness" ) {
2744 
2745  int target = GENERATE( range(0,NUM_QUBITS) );
2746 
2747  SECTION( "state-vector" ) {
2748 
2749  unitary(quregVec, target, matr);
2750  applyReferenceOp(refVec, target, op);
2751  REQUIRE( areEqual(quregVec, refVec) );
2752  }
2753  SECTION( "density-matrix" ) {
2754 
2755  unitary(quregMatr, target, matr);
2756  applyReferenceOp(refMatr, target, op);
2757  REQUIRE( areEqual(quregMatr, refMatr, 10*REAL_EPS) );
2758  }
2759  }
2760  SECTION( "input validation" ) {
2761 
2762  SECTION( "qubit indices" ) {
2763 
2764  int target = GENERATE( -1, NUM_QUBITS );
2765  REQUIRE_THROWS_WITH( unitary(quregVec, target, matr), Contains("Invalid target") );
2766  }
2767  SECTION( "unitarity" ) {
2768 
2769  matr.real[0][0] = 0; // break matr unitarity
2770  REQUIRE_THROWS_WITH( unitary(quregVec, 0, matr), Contains("unitary") );
2771  }
2772  }
2773  CLEANUP_TEST( quregVec, quregMatr );
2774 }

References applyReferenceOp(), areEqual(), CLEANUP_TEST, getRandomUnitary(), NUM_QUBITS, PREPARE_TEST, ComplexMatrix2::real, toComplexMatrix2(), and unitary().

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:244
void mixDephasing(Qureg qureg, int targetQubit, qreal prob)
Mixes a density matrix qureg to induce single-qubit dephasing noise.
Definition: QuEST.c:1250
@ INVERSE_PRODUCT
Definition: QuEST.h:233
qreal getProbAmp(Qureg qureg, long long int index)
Get the probability of a state-vector at an index in the full state vector.
Definition: QuEST.c:932
void initBlankState(Qureg qureg)
Initialises a qureg to have all-zero-amplitudes.
Definition: QuEST.c:119
Represents a 3-vector of real numbers.
Definition: QuEST.h:198
pauliOpType
Codes for specifying Pauli operators.
Definition: QuEST.h:96
void applyPhaseFunc(Qureg qureg, int *qubits, int numQubits, enum bitEncoding encoding, qreal *coeffs, qreal *exponents, int numTerms)
Induces a phase change upon each amplitude of qureg, determined by the passed exponential polynomial ...
Definition: QuEST.c:726
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:304
void applyMultiControlledMatrixN(Qureg qureg, int *ctrls, int numCtrls, int *targs, int numTargs, ComplexMatrixN u)
Apply a general N-by-N matrix, which may be non-unitary, with additional controlled qubits.
Definition: QuEST.c:1114
void twoQubitUnitary(Qureg qureg, int targetQubit1, int targetQubit2, ComplexMatrix4 u)
Apply a general two-qubit unitary (including a global phase factor).
Definition: QuEST.c:256
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:220
void applyNamedPhaseFuncOverrides(Qureg qureg, int *qubits, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, enum phaseFunc functionNameCode, long long int *overrideInds, qreal *overridePhases, int numOverrides)
Induces a phase change upon each amplitude of qureg, determined by a named (and potentially multi-var...
Definition: QuEST.c:813
void copyStateFromGPU(Qureg qureg)
In GPU mode, this copies the state-vector (or density matrix) from GPU memory (qureg....
Definition: QuEST_cpu.c:45
void initPauliHamil(PauliHamil hamil, qreal *coeffs, enum pauliOpType *codes)
Initialise PauliHamil instance hamil with the given term coefficients and Pauli codes (one for every ...
Definition: QuEST.c:1504
QuESTEnv QUEST_ENV
The global QuESTEnv instance, to be created and destroyed once in this main(), so that the MPI enviro...
Definition: main.cpp:20
qreal real[4][4]
Definition: QuEST.h:177
void syncQuESTEnv(QuESTEnv env)
Guarantees that all code up to the given point has been executed on all nodes (if running in distribu...
#define fromComplex(comp)
void initPureState(Qureg qureg, Qureg pure)
Initialise qureg into to a given pure state of an equivalent Hilbert dimension.
Definition: QuEST.c:145
#define CLEANUP_TEST(quregVec, quregMatr)
Destroys the data structures made by PREPARE_TEST.
void applyProjector(Qureg qureg, int qubit, int outcome)
Force the target qubit of qureg into the given classical outcome, via a non-renormalising projection.
Definition: QuEST.c:888
@ 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:601
QVector getKroneckerProduct(QVector b, QVector a)
Returns b (otimes) a.
Definition: utilities.cpp:143
@ DISTANCE
Definition: QuEST.h:234
void mixDepolarising(Qureg qureg, int targetQubit, qreal prob)
Mixes a density matrix qureg to induce single-qubit homogeneous depolarising noise.
Definition: QuEST.c:1272
int rank
Definition: QuEST.h:364
qreal calcTotalProb(Qureg qureg)
A debugging function which calculates the probability of the qubits in qureg being in any state,...
Definition: QuEST.c:1143
void mixDamping(Qureg qureg, int targetQubit, qreal prob)
Mixes a density matrix qureg to induce single-qubit amplitude damping (decay to 0 state).
Definition: QuEST.c:1283
void destroyComplexMatrixN(ComplexMatrixN m)
Destroy a ComplexMatrixN instance created with createComplexMatrixN()
Definition: QuEST.c:1369
int numChunks
The number of nodes between which the elements of this operator are split.
Definition: QuEST.h:304
void applyNamedPhaseFunc(Qureg qureg, int *qubits, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, enum phaseFunc functionNameCode)
Induces a phase change upon each amplitude of qureg, determined by a named (and potentially multi-var...
Definition: QuEST.c:796
void calcProbOfAllOutcomes(qreal *retProbs, Qureg qureg, int *qubits, int numQubits)
Populates outcomeProbs with the probabilities of every outcome of the sub-register contained in qubit...
Definition: QuEST.c:1176
@ PAULI_I
Definition: QuEST.h:96
void multiControlledMultiQubitNot(Qureg qureg, int *ctrls, int numCtrls, int *targs, int numTargs)
Apply a NOT (or Pauli X) gate with multiple control and target qubits.
Definition: QuEST.c:549
Complex getDensityAmp(Qureg qureg, long long int row, long long int col)
Get an amplitude from a density matrix at a given row and column.
Definition: QuEST.c:949
int getRandomInt(int min, int max)
Returns a random integer between min (inclusive) and max (exclusive), from the uniform distribution.
Definition: utilities.cpp:526
std::vector< QMatrix > getRandomKrausMap(int numQb, int numOps)
Returns a random Kraus map of #numOps 2^numQb-by-2^numQb operators, from an undisclosed distribution.
Definition: utilities.cpp:578
DiagonalOp createDiagonalOpFromPauliHamilFile(char *fn, QuESTEnv env)
Creates and initialiases a diagonal operator from the Z Pauli Hamiltonian encoded in file with filena...
Definition: QuEST.c:1558
ComplexMatrixN createComplexMatrixN(int numQubits)
Allocate dynamic memory for a square complex matrix of any size, which can be passed to functions lik...
Definition: QuEST.c:1348
qreal getImagAmp(Qureg qureg, long long int index)
Get the imaginary component of the complex probability amplitude at an index in the state vector.
Definition: QuEST.c:925
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:614
void mixKrausMap(Qureg qureg, int target, ComplexMatrix2 *ops, int numOps)
Apply a general single-qubit Kraus map to a density matrix, as specified by at most four Kraus operat...
Definition: QuEST.c:1314
QMatrix getMixedDensityMatrix(std::vector< qreal > probs, std::vector< QVector > states)
Returns a mixed density matrix formed from mixing the given pure states, which are assumed normalised...
Definition: utilities.cpp:640
void syncDiagonalOp(DiagonalOp op)
Update the GPU memory with the current values in op.real and op.imag.
Definition: QuEST.c:1531
void destroyDiagonalOp(DiagonalOp op, QuESTEnv env)
Destroys a DiagonalOp created with createDiagonalOp(), freeing its memory.
Definition: QuEST.c:1524
qreal z
Definition: QuEST.h:200
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:282
#define NUM_QUBITS
The default number of qubits in the registers created for unit testing (both statevectors and density...
Definition: utilities.hpp:36
qreal collapseToOutcome(Qureg qureg, int measureQubit, int outcome)
Updates qureg to be consistent with measuring measureQubit in the given outcome (0 or 1),...
Definition: QuEST.c:966
#define CLEANUP_TEST(quregVec, quregMatr)
Destroys the data structures made by PREPARE_TEST.
@ TWOS_COMPLEMENT
Definition: QuEST.h:269
qreal calcPurity(Qureg qureg)
Calculates the purity of a density matrix, by the trace of the density matrix squared.
Definition: QuEST.c:1185
qreal calcProbOfOutcome(Qureg qureg, int measureQubit, int outcome)
Gives the probability of a specified qubit being measured in the given outcome (0 or 1).
Definition: QuEST.c:1166
int measure(Qureg qureg, int measureQubit)
Measures a single qubit, collapsing it randomly to 0 or 1.
Definition: QuEST.c:998
QMatrix getRandomUnitary(int numQb)
Returns a uniformly random (under Haar) 2^numQb-by-2^numQb unitary matrix.
Definition: utilities.cpp:530
qreal calcFidelity(Qureg qureg, Qureg pureState)
Calculates the fidelity of qureg (a state-vector or density matrix) against a reference pure state (n...
Definition: QuEST.c:1191
void writeToFileSynch(char *fn, const string &contents)
Writes contents to the file with filename fn, which is created and/or overwritten.
Definition: utilities.cpp:1362
qreal getRandomReal(qreal min, qreal max)
Returns a random real between min (inclusive) and max (exclusive), from the uniform distribution.
Definition: utilities.cpp:421
void unitary(Qureg qureg, int targetQubit, ComplexMatrix2 u)
Apply a general single-qubit unitary (including a global phase factor).
Definition: QuEST.c:348
int chunkId
The position of the chunk of the operator held by this process in the full operator.
Definition: QuEST.h:306
@ NORM
Definition: QuEST.h:232
void setDiagMatrixOverrides(QMatrix &matr, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, long long int *overrideInds, qreal *overridePhases, int numOverrides)
Modifies the given diagonal matrix such that the diagonal elements which correspond to the coordinate...
Definition: utilities.cpp:1316
QMatrix getKetBra(QVector ket, QVector bra)
Returns the matrix |ket><bra|, with ith-jth element ket(i) conj(bra(j)), since |ket><bra| = sum_i a_i...
Definition: utilities.cpp:169
void mixTwoQubitDepolarising(Qureg qureg, int qubit1, int qubit2, qreal prob)
Mixes a density matrix qureg to induce two-qubit homogeneous depolarising noise.
Definition: QuEST.c:1291
Complex calcExpecDiagonalOp(Qureg qureg, DiagonalOp op)
Computes the expected value of the diagonal operator op for state qureg.
Definition: QuEST.c:1228
void sGate(Qureg qureg, int targetQubit)
Apply the single-qubit S gate.
Definition: QuEST.c:465
void cloneQureg(Qureg targetQureg, Qureg copyQureg)
Overwrite the amplitudes of targetQureg with those from copyQureg.
Definition: QuEST.c:164
std::vector< QVector > getRandomOrthonormalVectors(int numQb, int numStates)
Returns a list of random orthonormal complex vectors, from an undisclosed distribution.
Definition: utilities.cpp:613
Represents a 4x4 matrix of complex numbers.
Definition: QuEST.h:175
@ SCALED_INVERSE_DISTANCE
Definition: QuEST.h:234
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:198
void applyPauliHamil(Qureg inQureg, PauliHamil hamil, Qureg outQureg)
Modifies outQureg to be the result of applying PauliHamil (a Hermitian but not necessarily unitary op...
Definition: QuEST.c:1059
Information about the environment the program is running in.
Definition: QuEST.h:362
void applyQFT(Qureg qureg, int *qubits, int numQubits)
Applies the quantum Fourier transform (QFT) to a specific subset of qubits of the register qureg.
Definition: QuEST.c:866
@ UNSIGNED
Definition: QuEST.h:269
PauliHamil createPauliHamilFromFile(char *fn)
Creates a PauliHamil instance, a real-weighted sum of products of Pauli operators,...
Definition: QuEST.c:1420
void applyPhaseFuncOverrides(Qureg qureg, int *qubits, int numQubits, enum bitEncoding encoding, qreal *coeffs, qreal *exponents, int numTerms, long long int *overrideInds, qreal *overridePhases, int numOverrides)
Induces a phase change upon each amplitude of qureg, determined by the passed exponential polynomial ...
Definition: QuEST.c:743
void multiControlledPhaseShift(Qureg qureg, int *controlQubits, int numControlQubits, qreal angle)
Introduce a phase factor on state of the passed qubits.
Definition: QuEST.c:510
void setDiagonalOpElems(DiagonalOp op, long long int startInd, qreal *real, qreal *imag, long long int numElems)
Modifies a subset (starting at index startInd, and ending at index startInd + numElems) of the elemen...
Definition: QuEST.c:1543
Represents a general 2^N by 2^N matrix of complex numbers.
Definition: QuEST.h:186
@ INVERSE_DISTANCE
Definition: QuEST.h:234
#define qreal
void multiRotatePauli(Qureg qureg, int *targetQubits, enum pauliOpType *targetPaulis, int numTargets, qreal angle)
Apply a multi-qubit multi-Pauli rotation, also known as a Pauli gadget, on a selected number of qubit...
Definition: QuEST.c:685
QMatrix toQMatrix(ComplexMatrix2 src)
Returns a copy of the given 2-by-2 matrix.
Definition: utilities.cpp:1044
void toQureg(Qureg qureg, QVector vec)
Initialises the state-vector qureg to have the same amplitudes as vec.
Definition: utilities.cpp:1201
void setAmps(Qureg qureg, long long int startInd, qreal *reals, qreal *imags, long long int numAmps)
Overwrites a subset of the amplitudes in state-vector qureg, with those passed in reals and imags.
Definition: QuEST.c:1021
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:587
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:296
#define PREPARE_TEST(quregVec, quregMatr, refVec, refMatr)
Prepares the needed data structures for unit testing unitaries.
void multiControlledMultiRotateZ(Qureg qureg, int *controlQubits, int numControls, int *targetQubits, int numTargets, qreal angle)
Apply a multi-controlled multi-target Z rotation, also known as a controlled phase gadget.
Definition: QuEST.c:668
@ PAULI_X
Definition: QuEST.h:96
Complex getAmp(Qureg qureg, long long int index)
Get the complex amplitude at a given index in the state vector.
Definition: QuEST.c:939
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:563
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:216
int measureWithStats(Qureg qureg, int measureQubit, qreal *outcomeProb)
Measures a single qubit, collapsing it randomly to 0 or 1, and additionally gives the probability of ...
Definition: QuEST.c:985
int numQubitsInStateVec
Number of qubits in the state-vector - this is double the number represented for mixed states.
Definition: QuEST.h:329
qreal calcExpecPauliHamil(Qureg qureg, PauliHamil hamil, Qureg workspace)
Computes the expected value of qureg under Hermitian operator hamil.
Definition: QuEST.c:1219
void setUniqueFilename(char *outFn, char *prefix)
Modifies outFn to be a filename of format prefix_NUM.txt where NUM is a new unique integer so far.
Definition: utilities.cpp:1358
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:330
void setRandomPauliSum(qreal *coeffs, pauliOpType *codes, int numQubits, int numTerms)
Populates the coeffs array with random qreals in (-5, 5), and populates codes with random Pauli codes...
Definition: utilities.cpp:1229
void toComplexMatrixN(QMatrix qm, ComplexMatrixN cm)
Initialises cm with the values of qm.
Definition: utilities.cpp:1033
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:187
void setWeightedQureg(Complex fac1, Qureg qureg1, Complex fac2, Qureg qureg2, Complex facOut, Qureg out)
Modifies qureg out to the result of (facOut out + fac1 qureg1 + fac2 qureg2), imposing no constraints...
Definition: QuEST.c:1037
void multiControlledMultiRotatePauli(Qureg qureg, int *controlQubits, int numControls, int *targetQubits, enum pauliOpType *targetPaulis, int numTargets, qreal angle)
Apply a multi-controlled multi-target multi-Pauli rotation, also known as a controlled Pauli gadget.
Definition: QuEST.c:705
qreal calcHilbertSchmidtDistance(Qureg a, Qureg b)
Computes the Hilbert Schmidt distance between two density matrices a and b, defined as the Frobenius ...
Definition: QuEST.c:1237
qreal y
Definition: QuEST.h:200
qcomp expI(qreal phase)
Returns the unit-norm complex number exp(i*phase).
Definition: utilities.cpp:417
std::vector< qcomp > QVector
A complex vector, which can be zero-initialised with QVector(numAmps).
Definition: utilities.hpp:60
qreal * imag
The imaginary values of the 2^numQubits complex elements.
Definition: QuEST.h:310
qreal x
Definition: QuEST.h:200
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:454
phaseFunc
Flags for specifying named phase functions.
Definition: QuEST.h:231
QVector toQVector(Qureg qureg)
Returns an equal-size copy of the given state-vector qureg.
Definition: utilities.cpp:1113
long long int numAmpsPerChunk
Number of probability amplitudes held in stateVec by this process In the non-MPI version,...
Definition: QuEST.h:332
void applyDiagonalOp(Qureg qureg, DiagonalOp op)
Apply a diagonal operator, which is possibly non-unitary and non-Hermitian, to the entire qureg.
Definition: QuEST.c:1127
qreal * termCoeffs
The real coefficient of each Pauli product. This is an array of length PauliHamil....
Definition: QuEST.h:283
void applyMatrix4(Qureg qureg, int targetQubit1, int targetQubit2, ComplexMatrix4 u)
Apply a general 4-by-4 matrix, which may be non-unitary.
Definition: QuEST.c:1093
void swapGate(Qureg qureg, int qb1, int qb2)
Performs a SWAP gate between qubit1 and qubit2.
Definition: QuEST.c:627
#define qcomp
enum pauliOpType * pauliCodes
The Pauli operators acting on each qubit, flattened over every operator.
Definition: QuEST.h:281
void initStateFromAmps(Qureg qureg, qreal *reals, qreal *imags)
Initialise qureg by specifying all amplitudes.
Definition: QuEST.c:157
ComplexMatrix4 toComplexMatrix4(QMatrix qm)
Returns a ComplexMatrix4 copy of QMatix qm.
Definition: utilities.cpp:1027
void copyStateToGPU(Qureg qureg)
In GPU mode, this copies the state-vector (or density matrix) from RAM (qureg.stateVec) to VRAM / GPU...
Definition: QuEST_cpu.c:42
@ SCALED_PRODUCT
Definition: QuEST.h:233
#define MAX_NUM_REGS_APPLY_ARBITRARY_PHASE
#define toComplex(scalar)
int numRanks
Definition: QuEST.h:365
qreal getRealAmp(Qureg qureg, long long int index)
Get the real component of the complex probability amplitude at an index in the state vector.
Definition: QuEST.c:918
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:575
int numQubits
The number of qubits this operator can act on (informing its size)
Definition: QuEST.h:300
int numSumTerms
The number of terms in the weighted sum, or the number of Pauli products.
Definition: QuEST.h:285
Represents a diagonal complex operator on the full Hilbert state of a Qureg.
Definition: QuEST.h:297
@ PAULI_Y
Definition: QuEST.h:96
A Pauli Hamiltonian, expressed as a real-weighted sum of pauli products, and which can hence represen...
Definition: QuEST.h:277
int getNumQubits(Qureg qureg)
Returns the number of qubits represented by qureg.
Definition: QuEST.c:908
Complex calcInnerProduct(Qureg bra, Qureg ket)
Computes the inner product of two equal-size state vectors, given by.
Definition: QuEST.c:1150
void destroyQureg(Qureg qureg, QuESTEnv env)
Deallocate a Qureg, freeing its memory.
Definition: QuEST.c:77
void applyParamNamedPhaseFuncOverrides(Qureg qureg, int *qubits, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, enum phaseFunc functionNameCode, qreal *params, int numParams, long long int *overrideInds, qreal *overridePhases, int numOverrides)
Induces a phase change upon each amplitude of qureg, determined by a named, parameterised (and potent...
Definition: QuEST.c:848
@ SCALED_INVERSE_SHIFTED_NORM
Definition: QuEST.h:232
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:313
QVector getRandomStateVector(int numQb)
Returns a random numQb-length L2-normalised state-vector from an undisclosed distribution.
Definition: utilities.cpp:468
void setRandomDiagPauliHamil(PauliHamil hamil)
Populates hamil with random coefficients and a random amount number of PAULI_I and PAULI_Z operators.
Definition: utilities.cpp:1241
void multiQubitNot(Qureg qureg, int *targs, int numTargs)
Apply a NOT (or Pauli X) gate with multiple target qubits, which has the same effect as (but is much ...
Definition: QuEST.c:536
void mixTwoQubitKrausMap(Qureg qureg, int target1, int target2, ComplexMatrix4 *ops, int numOps)
Apply a general two-qubit Kraus map to a density matrix, as specified by at most sixteen Kraus operat...
Definition: QuEST.c:1324
qreal ** real
Definition: QuEST.h:189
void initDebugState(Qureg qureg)
Initialises qureg to be in the un-normalised, non-physical state with with -th complex amplitude give...
Definition: QuEST.c:1578
void applyPauliSum(Qureg inQureg, enum pauliOpType *allPauliCodes, qreal *termCoeffs, int numSumTerms, Qureg outQureg)
Modifies outQureg to be the result of applying the weighted sum of Pauli products (a Hermitian but no...
Definition: QuEST.c:1048
QMatrix getRandomQMatrix(int dim)
Returns a dim-by-dim complex matrix, where the real and imaginary value of each element are independe...
Definition: utilities.cpp:379
void applyMatrixN(Qureg qureg, int *targs, int numTargs, ComplexMatrixN u)
Apply a general N-by-N matrix, which may be non-unitary, on any number of target qubits.
Definition: QuEST.c:1103
void applyMultiVarPhaseFunc(Qureg qureg, int *qubits, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, qreal *coeffs, qreal *exponents, int *numTermsPerReg)
Induces a phase change upon each amplitude of qureg, determined by a multi-variable exponential polyn...
Definition: QuEST.c:761
void compactUnitary(Qureg qureg, int targetQubit, Complex alpha, Complex beta)
Apply a single-qubit unitary parameterised by two given complex scalars.
Definition: QuEST.c:404
void initClassicalState(Qureg qureg, long long int stateInd)
Initialise qureg into the classical state (also known as a "computational basis state") with index st...
Definition: QuEST.c:134
void pauliY(Qureg qureg, int targetQubit)
Apply the single-qubit Pauli-Y (also known as the Y or sigma-Y) gate.
Definition: QuEST.c:443
@ INVERSE_NORM
Definition: QuEST.h:232
long long int getTwosComplement(long long int decimal, int numBits)
Returns the two's complement signed encoding of the unsigned number decimal, which must be a number b...
Definition: utilities.cpp:1286
Represents a system of qubits.
Definition: QuEST.h:322
void controlledPhaseShift(Qureg qureg, int idQubit1, int idQubit2, qreal angle)
Introduce a phase factor on state of qubits idQubit1 and idQubit2.
Definition: QuEST.c:498
void mixTwoQubitDephasing(Qureg qureg, int qubit1, int qubit2, qreal prob)
Mixes a density matrix qureg to induce two-qubit dephasing noise.
Definition: QuEST.c:1260
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:360
qreal ** imag
Definition: QuEST.h:190
void initDiagonalOp(DiagonalOp op, qreal *real, qreal *imag)
Overwrites the entire DiagonalOp op with the given real and imag complex elements.
Definition: QuEST.c:1537
void phaseShift(Qureg qureg, int targetQubit, qreal angle)
Shift the phase between and of a single qubit by a given angle.
Definition: QuEST.c:487
@ PRODUCT
Definition: QuEST.h:233
ComplexArray stateVec
Computational state amplitudes - a subset thereof in the MPI version.
Definition: QuEST.h:341
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:524
qreal real[2][2]
Definition: QuEST.h:139
long long int getNumAmps(Qureg qureg)
Returns the number of complex amplitudes in a state-vector qureg.
Definition: QuEST.c:912
void applyMultiVarPhaseFuncOverrides(Qureg qureg, int *qubits, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, qreal *coeffs, qreal *exponents, int *numTermsPerReg, long long int *overrideInds, qreal *overridePhases, int numOverrides)
Induces a phase change upon each amplitude of qureg, determined by a multi-variable exponential polyn...
Definition: QuEST.c:778
long long int numElemsPerChunk
The number of the 2^numQubits amplitudes stored on each distributed node.
Definition: QuEST.h:302
void initDiagonalOpFromPauliHamil(DiagonalOp op, PauliHamil hamil)
Populates the diagonal operator op to be equivalent to the given Pauli Hamiltonian hamil,...
Definition: QuEST.c:1550
int isDensityMatrix
Whether this instance is a density-state representation.
Definition: QuEST.h:325
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:432
Qureg createCloneQureg(Qureg qureg, QuESTEnv env)
Create a new Qureg which is an exact clone of the passed qureg, which can be either a state-vector or...
Definition: QuEST.c:64
#define PREPARE_TEST(qureg, ref)
Prepares a density matrix in the debug state, and the reference QMatrix.
std::vector< std::vector< qcomp > > QMatrix
A complex square matrix.
Definition: utilities.hpp:49
qreal calcExpecPauliSum(Qureg qureg, enum pauliOpType *allPauliCodes, qreal *termCoeffs, int numSumTerms, Qureg workspace)
Computes the expected value of a sum of products of Pauli operators.
Definition: QuEST.c:1210
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:269
ComplexMatrix2 toComplexMatrix2(QMatrix qm)
Returns a ComplexMatrix2 copy of QMatix qm.
Definition: utilities.cpp:1021
void applyFullQFT(Qureg qureg)
Applies the quantum Fourier transform (QFT) to the entirety of qureg.
Definition: QuEST.c:876
int numQubits
The number of qubits informing the Hilbert dimension of the Hamiltonian.
Definition: QuEST.h:287
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:1488
int numQubitsRepresented
The number of qubits represented in either the state-vector or density matrix.
Definition: QuEST.h:327
std::vector< qreal > getRandomProbabilities(int numProbs)
Returns a list of random real scalars, each in [0, 1], which sum to unity.
Definition: utilities.cpp:472
long long int numAmpsTotal
Total number of amplitudes, which are possibly distributed among machines.
Definition: QuEST.h:334
@ SCALED_DISTANCE
Definition: QuEST.h:234
qreal * real
The real values of the 2^numQubits complex elements.
Definition: QuEST.h:308
qreal real
Definition: QuEST.h:105
void mixDensityMatrix(Qureg combineQureg, qreal otherProb, Qureg otherQureg)
Modifies combineQureg to become (1-prob)combineProb + prob otherQureg.
Definition: QuEST.c:1012
Qureg createQureg(int numQubits, QuESTEnv env)
Creates a state-vector Qureg object representing a set of qubits which will remain in a pure state.
Definition: QuEST.c:36
void destroyPauliHamil(PauliHamil h)
Destroy a PauliHamil instance, created with either createPauliHamil() or createPauliHamilFromFile().
Definition: QuEST.c:1414
QMatrix getPureDensityMatrix(QVector state)
Returns a density matrix initialised into the given pure state.
Definition: utilities.cpp:507
void tGate(Qureg qureg, int targetQubit)
Apply the single-qubit T gate.
Definition: QuEST.c:476
void multiRotateZ(Qureg qureg, int *qubits, int numQubits, qreal angle)
Apply a multi-qubit Z rotation, also known as a phase gadget, on a selected number of qubits.
Definition: QuEST.c:652
qreal imag
Definition: QuEST.h:106
void deleteFilesWithPrefixSynch(char *prefix)
Deletes all files with filename starting with prefix.
Definition: utilities.cpp:1375
QMatrix getRandomDensityMatrix(int numQb)
Returns a random numQb-by-numQb density matrix, from an undisclosed distribution, in a very mixed sta...
Definition: utilities.cpp:490
QMatrix getExponentialOfDiagonalMatrix(QMatrix a)
Returns the matrix exponential of a diagonal, square, complex matrix.
Definition: utilities.cpp:197
void applyParamNamedPhaseFunc(Qureg qureg, int *qubits, int *numQubitsPerReg, int numRegs, enum bitEncoding encoding, enum phaseFunc functionNameCode, qreal *params, int numParams)
Induces a phase change upon each amplitude of qureg, determined by a named, paramaterized (and potent...
Definition: QuEST.c:831
@ SCALED_INVERSE_SHIFTED_DISTANCE
Definition: QuEST.h:234
void mixPauli(Qureg qureg, int qubit, qreal probX, qreal probY, qreal probZ)
Mixes a density matrix qureg to induce general single-qubit Pauli noise.
Definition: QuEST.c:1303
QMatrix getZeroMatrix(size_t dim)
Returns a dim-by-dim square complex matrix, initialised to all zeroes.
Definition: utilities.cpp:153
void hadamard(Qureg qureg, int targetQubit)
Apply the single-qubit Hadamard gate.
Definition: QuEST.c:176
Represents one complex number.
Definition: QuEST.h:103
void applyMatrix2(Qureg qureg, int targetQubit, ComplexMatrix2 u)
Apply a general 2-by-2 matrix, which may be non-unitary.
Definition: QuEST.c:1084
#define PREPARE_TEST(quregVec, quregMatr, refVec, refMatr)
Prepares the needed data structures for unit testing some operators.
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:209
QVector getRandomQVector(int dim)
Returns a dim-length vector with random complex amplitudes in the square joining {-1-i,...
Definition: utilities.cpp:435
@ SCALED_NORM
Definition: QuEST.h:232
@ SCALED_INVERSE_PRODUCT
Definition: QuEST.h:233
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:373
void applyReferenceMatrix(QVector &state, int *ctrls, int numCtrls, int *targs, int numTargs, QMatrix op)
Modifies the state-vector state to be the result of left-multiplying the multi-target operator matrix...
Definition: utilities.cpp:841
void initZeroState(Qureg qureg)
Initialise qureg into the zero state.
Definition: QuEST.c:113
QVector getDFT(QVector in)
Returns the discrete fourier transform of vector in.
Definition: utilities.cpp:652
qreal calcDensityInnerProduct(Qureg rho1, Qureg rho2)
Computes the Hilbert-Schmidt scalar product (which is equivalent to the Frobenius inner product of ma...
Definition: QuEST.c:1158
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:398
Qureg createDensityQureg(int numQubits, QuESTEnv env)
Creates a density matrix Qureg object representing a set of qubits which can enter noisy and mixed st...
Definition: QuEST.c:50
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:728
#define M_PI
Definition: QuEST_common.c:41
void applyTrotterCircuit(Qureg qureg, PauliHamil hamil, qreal time, int order, int reps)
Applies a trotterisation of unitary evolution to qureg.
Definition: QuEST.c:1070
PauliHamil createPauliHamil(int numQubits, int numSumTerms)
Dynamically allocates a Hamiltonian expressed as a real-weighted sum of products of Pauli operators.
Definition: QuEST.c:1398
Catch::Generators::GeneratorWrapper< int * > bitsets(int numBits)
Returns a Catch2 generator of every numBits-length bit-set, in increasing lexographic order,...
Definition: utilities.cpp:1557
qcomp getRandomComplex()
Returns a random complex number within the square closing (-1-i) and (1+i), from a distribution unifo...
Definition: utilities.cpp:431
void initPlusState(Qureg qureg)
Initialise qureg into the plus state.
Definition: QuEST.c:125
qreal calcExpecPauliProd(Qureg qureg, int *targetQubits, enum pauliOpType *pauliCodes, int numTargets, Qureg workspace)
Computes the expected value of a product of Pauli operators.
Definition: QuEST.c:1201
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:417
void multiStateControlledUnitary(Qureg qureg, int *controlQubits, int *controlState, int numControlQubits, int targetQubit, ComplexMatrix2 u)
Apply a general single-qubit unitary with multiple control qubits, conditioned upon a specific bit se...
Definition: QuEST.c:388
void sqrtSwapGate(Qureg qureg, int qb1, int qb2)
Performs a sqrt SWAP gate between qubit1 and qubit2.
Definition: QuEST.c:639
bitEncoding
Flags for specifying how the bits in sub-register computational basis states are mapped to indices in...
Definition: QuEST.h:269
void mixMultiQubitKrausMap(Qureg qureg, int *targets, int numTargets, ComplexMatrixN *ops, int numOps)
Apply a general N-qubit Kraus map to a density matrix, as specified by at most (2N)^2 Kraus operators...
Definition: QuEST.c:1334
DiagonalOp createDiagonalOp(int numQubits, QuESTEnv env)
Creates a DiagonalOp representing a diagonal operator on the full Hilbert space of a Qureg.
Definition: QuEST.c:1518
Represents a 2x2 matrix of complex numbers.
Definition: QuEST.h:137
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:232
@ SCALED_INVERSE_NORM
Definition: QuEST.h:232