30TEST_CASE(
"calcDensityInnerProduct",
"[calculations]" ) {
35 SECTION(
"correctness" ) {
38 GENERATE( range(0,10) );
40 SECTION(
"density-matrix" ) {
54 for (
size_t i=0; i<r1.size(); i++)
55 prod += conj(r1[i]) * r2[i];
56 qreal densProd = pow(abs(prod),2);
58 REQUIRE( real(calcDensityInnerProduct(mat1,mat2)) == Approx(densProd).margin(100 * REAL_EPS) );
69 for (
size_t i=0; i<ref1.size(); i++)
70 for (
size_t j=0; j<ref1.size(); j++)
71 refProd += conj(ref1[i][j]) * ref2[i][j];
72 REQUIRE( imag(refProd) == Approx(0).margin(REAL_EPS) );
74 REQUIRE( real(calcDensityInnerProduct(mat1,mat2)) == Approx(real(refProd)).margin(100 * REAL_EPS) );
77 REQUIRE( real(calcDensityInnerProduct(mat1,mat2)) == Approx(real(calcDensityInnerProduct(mat2,mat1))).margin(100 * REAL_EPS) );
79 SECTION(
"unnormalised" ) {
89 for (
size_t i=0; i<ref1.size(); i++)
90 for (
size_t j=0; j<ref1.size(); j++)
91 refProd += conj(ref1[i][j]) * ref2[i][j];
93 REQUIRE( real(calcDensityInnerProduct(mat1,mat2)) == Approx(real(refProd)).margin(100 * REAL_EPS) );
97 SECTION(
"input validation" ) {
99 SECTION(
"dimensions" ) {
102 REQUIRE_THROWS_WITH( calcDensityInnerProduct(mat1,mat3), ContainsSubstring(
"differing numbers of qubits") );
139 SECTION(
"correctness" ) {
142 GENERATE( range(0,10) );
145 DiagonalOp op = createDiagonalOp(NUM_QUBITS,
getQuESTEnv());
146 for (
long long int i=0; i<op.numElemsPerNode; i++)
150 SECTION(
"state-vector" ) {
156 for (
size_t i=0; i<vecRef.size(); i++)
157 prod += conj(vecRef[i]) * sumRef[i];
159 qcomp res = calcExpecDiagonalOp(vec, op);
160 REQUIRE( real(res) == Approx(real(prod)).margin(REAL_EPS) );
161 REQUIRE( imag(res) == Approx(imag(prod)).margin(REAL_EPS) );
163 SECTION(
"density-matrix" ) {
168 for (
size_t i=0; i<matRef.size(); i++)
171 qcomp res = calcExpecDiagonalOp(mat, op);
172 REQUIRE( real(res) == Approx(real(tr)).margin(100*REAL_EPS) );
173 REQUIRE( imag(res) == Approx(imag(tr)).margin(100*REAL_EPS) );
178 SECTION(
"input validation" ) {
180 SECTION(
"mismatching size" ) {
182 DiagonalOp op = createDiagonalOp(NUM_QUBITS + 1,
getQuESTEnv());
184 REQUIRE_THROWS_WITH( calcExpecDiagonalOp(vec, op), ContainsSubstring(
"different number of qubits"));
185 REQUIRE_THROWS_WITH( calcExpecDiagonalOp(mat, op), ContainsSubstring(
"different number of qubits"));
319 Qureg vec =
createCustomQureg(NUM_QUBITS, 0, env.isDistributed, env.isGpuAccelerated, env.isMultithreaded);
320 Qureg mat =
createCustomQureg(NUM_QUBITS, 1, env.isDistributed, env.isGpuAccelerated, env.isMultithreaded);
330 SECTION(
"correctness" ) {
332 int numTargs = GENERATE( range(1,NUM_QUBITS+1) );
333 int* targs = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numTargs) );
340 GENERATE( range(0,10) );
341 vector<pauliOpType> paulis(numTargs);
342 for (
int i=0; i<numTargs; i++)
348 QMatrix yMatr{{0,-qcomp(0,1)},{qcomp(0,1),0}};
351 for (
int i=0; i<numTargs; i++) {
353 if (paulis[i] == PAULI_I) fac = iMatr;
354 if (paulis[i] == PAULI_X) fac = xMatr;
355 if (paulis[i] == PAULI_Y) fac = yMatr;
356 if (paulis[i] == PAULI_Z) fac = zMatr;
360 SECTION(
"state-vector" ) {
367 for (
size_t i=0; i<vecRef.size(); i++)
368 prod += conj(vecRef[i]) * prodRef[i];
369 REQUIRE( imag(prod) == Approx(0).margin(REAL_EPS) );
371 qreal res = calcExpecPauliProd(vec, targs, paulis.data(), numTargs, vecWork);
372 REQUIRE( res == Approx(real(prod)).margin(REAL_EPS) );
374 SECTION(
"density-matrix" ) {
380 matRef = fullOp * matRef;
384 for (
size_t i=0; i<matRef.size(); i++)
385 tr += real(matRef[i][i]);
390 qreal res = calcExpecPauliProd(mat, targs, paulis.data(), numTargs, matWork);
393 REQUIRE( res == Approx(tr).margin(10*REAL_EPS) );
396 SECTION(
"input validation" ) {
398 pauliOpType pauliOpsToAvoidDeprecSegFault[100];
399 for (
int i=0; i<100; i++)
400 pauliOpsToAvoidDeprecSegFault[i] = PAULI_X;
402 SECTION(
"number of targets" ) {
404 int targs[NUM_QUBITS+1];
405 for (
int i=0; i<NUM_QUBITS+1; i++)
409 int numTargs = GENERATE( -1, 0 );
410 REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, pauliOpsToAvoidDeprecSegFault, numTargs, vecWork), ContainsSubstring(
"Invalid number of Paulis") );
413 numTargs = NUM_QUBITS + 1;
414 REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, pauliOpsToAvoidDeprecSegFault, numTargs, vecWork), ContainsSubstring(
"highest-index non-identity Pauli operator") && ContainsSubstring(
"exceeds the maximum target") );
416 SECTION(
"target indices" ) {
419 int targs[3] = {0, 1, 2};
421 int badInd = GENERATE( range(0,3) );
425 REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, pauliOpsToAvoidDeprecSegFault, numTargs, vecWork), ContainsSubstring(
"Pauli indices must be non-negative") );
428 targs[badInd] = NUM_QUBITS;
429 REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, pauliOpsToAvoidDeprecSegFault, numTargs, vecWork), ContainsSubstring(
"highest-index non-identity Pauli operator") );
433 REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, pauliOpsToAvoidDeprecSegFault, numTargs, vecWork), ContainsSubstring(
"exceed the maximum number of representable Pauli operators") );
435 SECTION(
"repetition in targets" ) {
438 int targs[3] = {0, 1, 1};
439 REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, pauliOpsToAvoidDeprecSegFault, numTargs, vecWork), ContainsSubstring(
"Indices must be unique") );
441 SECTION(
"pauli codes" ) {
444 int targs[3] = {0, 1, 2};
445 pauliOpType codes[3] = {PAULI_X, PAULI_Y, PAULI_Z};
448 codes[GENERATE( range(0,3) )] = (pauliOpType) GENERATE( -1, 4 );
449 REQUIRE_THROWS_WITH( calcExpecPauliProd(vec, targs, codes, numTargs, vecWork), ContainsSubstring(
"invalid Pauli code") );
504 SECTION(
"correctness" ) {
506 int numSumTerms = GENERATE( 1, 2, 10, 15 );
511 GENERATE( range(0,10) );
512 int totNumCodes = numSumTerms * NUM_QUBITS;
513 vector<pauliOpType> paulis(totNumCodes);
514 vector<qreal> coeffs(numSumTerms);
518 QMatrix pauliSum =
toQMatrix(coeffs.data(), paulis.data(), NUM_QUBITS, numSumTerms);
520 SECTION(
"state-vector" ) {
524 QVector sumRef = pauliSum * vecRef;
526 for (
size_t i=0; i<vecRef.size(); i++)
527 prod += conj(vecRef[i]) * sumRef[i];
528 REQUIRE( imag(prod) == Approx(0).margin(10*REAL_EPS) );
530 qreal res = calcExpecPauliSum(vec, paulis.data(), coeffs.data(), numSumTerms, vecWork);
531 REQUIRE( res == Approx(real(prod)).margin(10*REAL_EPS) );
533 SECTION(
"density-matrix" ) {
536 matRef = pauliSum * matRef;
538 for (
size_t i=0; i<matRef.size(); i++)
539 tr += real(matRef[i][i]);
542 qreal res = calcExpecPauliSum(mat, paulis.data(), coeffs.data(), numSumTerms, matWork);
543 REQUIRE( res == Approx(tr).margin(1E2*REAL_EPS) );
546 SECTION(
"input validation" ) {
556 SECTION(
"pauli codes" ) {
560 vector<qreal> coeffs(numSumTerms);
561 vector<pauliOpType> codes(numSumTerms*NUM_QUBITS);
562 for (
int i=0; i<numSumTerms*NUM_QUBITS; i++)
566 codes[GENERATE_COPY( range(0,numSumTerms*NUM_QUBITS) )] = (pauliOpType) GENERATE( -1, 4 );
567 REQUIRE_THROWS_WITH( calcExpecPauliSum(vec, codes.data(), coeffs.data(), numSumTerms, vecWork), ContainsSubstring(
"invalid Pauli code") );
621 SECTION(
"correctness" ) {
624 GENERATE( range(0,10) );
626 SECTION(
"state-vector" ) {
630 SECTION(
"normalised" ) {
643 for (
size_t i=0; i<vecRef.size(); i++)
644 dotProd += conj(vecRef[i]) * pureRef[i];
645 qreal refFid = pow(abs(dotProd), 2);
677 SECTION(
"density-matrix" ) {
698 for (
size_t i=0; i<r1.size(); i++)
699 dotProd += conj(r1[i]) * pureRef[i];
700 qreal refFid = pow(abs(dotProd), 2);
702 REQUIRE(
calcFidelity(mat,pure) == Approx(refFid).margin(100 * REAL_EPS) );
714 QVector rhs = matRef * pureRef;
716 for (
size_t i=0; i<rhs.size(); i++)
717 dotProd += conj(pureRef[i]) * rhs[i];
719 REQUIRE( imag(dotProd) == Approx(0).margin(REAL_EPS) );
720 REQUIRE(
calcFidelity(mat,pure) == Approx(real(dotProd)).margin(100 * REAL_EPS) );
744 SECTION(
"input validation" ) {
746 SECTION(
"dimensions" ) {
750 REQUIRE_THROWS_WITH(
calcFidelity(vec2,vec), ContainsSubstring(
"differing numbers of qubits") );
755 REQUIRE_THROWS_WITH(
calcFidelity(mat2,vec), ContainsSubstring(
"differing numbers of qubits") );
758 SECTION(
"density-matrices" ) {
761 REQUIRE_THROWS_WITH(
calcFidelity(mat,mat), ContainsSubstring(
"Quregs cannot both be density matrices") );
775TEST_CASE(
"calcHilbertSchmidtDistance",
"[calculations]" ) {
780 SECTION(
"correctness" ) {
783 GENERATE( range(0,10) );
785 SECTION(
"density-matrix" ) {
799 for (
size_t i=0; i<m1.size(); i++)
800 for (
size_t j=0; j<m1.size(); j++)
801 tr += pow(abs(m1[i][j] - m2[i][j]), 2);
803 qreal res = calcHilbertSchmidtDistance(mat1, mat2);
804 REQUIRE( res == Approx(sqrt(tr)) );
807 SECTION(
"normalised" ) {
816 for (
size_t i=0; i<ref1.size(); i++)
817 for (
size_t j=0; j<ref1.size(); j++)
818 tr += pow(abs(ref1[i][j] - ref2[i][j]), 2);
820 qreal res = calcHilbertSchmidtDistance(mat1, mat2);
821 REQUIRE( res == Approx(sqrt(tr)) );
823 SECTION(
"unnormalised" ) {
833 for (
size_t i=0; i<ref1.size(); i++)
834 for (
size_t j=0; j<ref1.size(); j++)
835 tr += pow(abs(ref1[i][j] - ref2[i][j]), 2);
837 qreal res = calcHilbertSchmidtDistance(mat1, mat2);
838 REQUIRE( res == Approx(sqrt(tr)) );
842 SECTION(
"input validation") {
844 SECTION(
"dimensions" ) {
847 REQUIRE_THROWS_WITH( calcHilbertSchmidtDistance(mat1,mat3), ContainsSubstring(
"differing numbers of qubits") );
957 SECTION(
"correctness" ) {
960 int numQubits = GENERATE_COPY( range(1,NUM_QUBITS+1) );
961 int* qubits = GENERATE_COPY( sublists(range(0,NUM_QUBITS), numQubits) );
963 int numOutcomes = 1<<numQubits;
964 vector<qreal> probs(numOutcomes);
967 SECTION(
"state-vector" ) {
969 SECTION(
"normalised" ) {
975 for (
size_t i=0; i<ref.size(); i++) {
977 for (
int q=0; q<numQubits; q++) {
978 int bit = (i >> qubits[q]) & 1;
979 outcome += bit * (1 << q);
981 refProbs[outcome] += pow(abs(ref[i]), 2);
984 calcProbOfAllOutcomes(probs.data(), vec, qubits, numQubits);
985 REQUIRE(
areEqual(refProbs, probs.data()) );
987 SECTION(
"unnormalised" ) {
993 for (
size_t i=0; i<ref.size(); i++) {
995 for (
int q=0; q<numQubits; q++) {
996 int bit = (i >> qubits[q]) & 1;
997 outcome += bit * (1 << q);
999 refProbs[outcome] += pow(abs(ref[i]), 2);
1002 calcProbOfAllOutcomes(probs.data(), vec, qubits, numQubits);
1003 REQUIRE(
areEqual(refProbs, probs.data()) );
1006 SECTION(
"density-matrix" ) {
1008 SECTION(
"normalised" ) {
1014 for (
size_t i=0; i<ref.size(); i++) {
1016 for (
int q=0; q<numQubits; q++) {
1017 int bit = (i >> qubits[q]) & 1;
1018 outcome += bit * (1 << q);
1020 refProbs[outcome] += real(ref[i][i]);
1023 calcProbOfAllOutcomes(probs.data(), mat, qubits, numQubits);
1024 REQUIRE(
areEqual(refProbs, probs.data()) );
1026 SECTION(
"unnormalised" ) {
1032 for (
size_t i=0; i<ref.size(); i++) {
1034 for (
int q=0; q<numQubits; q++) {
1035 int bit = (i >> qubits[q]) & 1;
1036 outcome += bit * (1 << q);
1038 refProbs[outcome] += real(ref[i][i]);
1041 calcProbOfAllOutcomes(probs.data(), mat, qubits, numQubits);
1042 REQUIRE(
areEqual(refProbs, probs.data()) );
1046 SECTION(
"input validation" ) {
1049 int qubits[] = {0, 1, 2};
1052 SECTION(
"number of qubits" ) {
1055 numQubits = GENERATE( -1, 0 );
1056 REQUIRE_THROWS_WITH( calcProbOfAllOutcomes(probs, mat, qubits, numQubits), ContainsSubstring(
"specified number of target qubits") && ContainsSubstring(
"invalid.") );
1059 numQubits = NUM_QUBITS + 1;
1060 REQUIRE_THROWS_WITH( calcProbOfAllOutcomes(probs, mat, qubits, numQubits), ContainsSubstring(
"target qubits") && ContainsSubstring(
"exceeds the number of qubits in the Qureg") );
1062 SECTION(
"qubit indices" ) {
1064 qubits[GENERATE_COPY(range(0,numQubits))] = GENERATE( -1, NUM_QUBITS );
1065 REQUIRE_THROWS_WITH( calcProbOfAllOutcomes(probs, mat, qubits, numQubits), ContainsSubstring(
"Invalid target qubit") );
1067 SECTION(
"repetition of qubits" ) {
1069 qubits[GENERATE_COPY(1,2)] = qubits[0];
1070 REQUIRE_THROWS_WITH( calcProbOfAllOutcomes(probs, mat, qubits, numQubits), ContainsSubstring(
"qubits must be unique") );
1089 SECTION(
"correctness" ) {
1091 int target = GENERATE( range(0,NUM_QUBITS) );
1092 int outcome = GENERATE( 0, 1 );
1094 SECTION(
"state-vector" ) {
1096 SECTION(
"normalised" ) {
1103 for (
size_t ind=0; ind<ref.size(); ind++) {
1104 int bit = (ind >> target) & 1;
1106 prob += pow(abs(ref[ind]), 2);
1109 REQUIRE( calcProbOfOutcome(vec, target, outcome) == Approx(prob) );
1111 SECTION(
"unnormalised" ) {
1118 for (
size_t ind=0; ind<ref.size(); ind++) {
1119 int bit = (ind >> target) & 1;
1121 prob += pow(abs(ref[ind]), 2);
1124 REQUIRE( calcProbOfOutcome(vec, target, outcome) == Approx(prob) );
1127 SECTION(
"density-matrix" ) {
1137 for (
size_t ind=0; ind<ref.size(); ind++) {
1138 int bit = (ind >> target) & 1;
1140 prob += pow(abs(ref[ind]), 2);
1143 REQUIRE( calcProbOfOutcome(mat, target, outcome) == Approx(prob) );
1145 SECTION(
"mixed" ) {
1152 for (
size_t ind=0; ind<ref.size(); ind++) {
1153 int bit = (ind >> target) & 1;
1155 tr += ref[ind][ind];
1158 REQUIRE( imag(tr) == Approx(0).margin(REAL_EPS) );
1160 REQUIRE( calcProbOfOutcome(mat, target, outcome) == Approx(real(tr)) );
1162 SECTION(
"unnormalised" ) {
1169 for (
size_t ind=0; ind<ref.size(); ind++) {
1170 int bit = (ind >> target) & 1;
1172 tr += real(ref[ind][ind]);
1175 REQUIRE( calcProbOfOutcome(mat, target, outcome) == Approx(tr) );
1179 SECTION(
"input validation" ) {
1181 SECTION(
"qubit indices" ) {
1183 int target = GENERATE( -1, NUM_QUBITS );
1184 REQUIRE_THROWS_WITH( calcProbOfOutcome(vec, target, 0), ContainsSubstring(
"Invalid target qubit") );
1186 SECTION(
"outcome value" ) {
1188 int outcome = GENERATE( -1, 2 );
1189 REQUIRE_THROWS_WITH( calcProbOfOutcome(vec, 0, outcome), ContainsSubstring(
"measurement outcome") && ContainsSubstring(
"invalid") );
1386 SECTION(
"correctness" ) {
1388 SECTION(
"density-matrix" ) {
1393 int row = GENERATE( range(0,1<<NUM_QUBITS) );
1394 int col = GENERATE( range(0,1<<NUM_QUBITS) );
1396 qcomp amp = getDensityAmp(mat,row,col);
1397 REQUIRE( amp == ref[row][col] );
1400 SECTION(
"input validation" ) {
1402 SECTION(
"state index" ) {
1404 int ind = GENERATE( -1, 1<<NUM_QUBITS );
1405 REQUIRE_THROWS_WITH( getDensityAmp(mat,ind,0), ContainsSubstring(
"The row and column indices") && ContainsSubstring(
"invalid") );
1406 REQUIRE_THROWS_WITH( getDensityAmp(mat,0,ind), ContainsSubstring(
"The row and column indices") && ContainsSubstring(
"invalid") );
1409 SECTION(
"state-vector" ) {
1412 REQUIRE_THROWS_WITH( getDensityAmp(vec,0,0), ContainsSubstring(
"Expected a density matrix Qureg but received a statevector") );