#include "catch.hpp"
#include "QuEST.h"
#include "utilities.hpp"
using Catch::Matchers::Contains;
TEST_CASE( "collapseToOutcome", "[gates]" ) {
Qureg vec = createQureg(NUM_QUBITS, QUEST_ENV);
Qureg mat = createDensityQureg(NUM_QUBITS, QUEST_ENV);
SECTION( "correctness" ) {
int qubit = GENERATE( range(0,NUM_QUBITS) );
int outcome = GENERATE( 0, 1 );
GENERATE( range(0,10) );
SECTION( "state-vector" ) {
QVector vecRef = getRandomStateVector(NUM_QUBITS);
toQureg(vec, vecRef);
qreal prob = 0;
for (size_t ind=0; ind<vecRef.size(); ind++) {
int bit = (ind >> qubit) & 1; if (bit == outcome)
prob += pow(abs(vecRef[ind]), 2);
}
for (size_t ind=0; ind<vecRef.size(); ind++) {
int bit = (ind >> qubit) & 1; if (bit == outcome)
vecRef[ind] /= sqrt(prob);
else
vecRef[ind] = 0;
}
qreal res = collapseToOutcome(vec, qubit, outcome);
REQUIRE( res == Approx(prob) );
REQUIRE( areEqual(vec, vecRef) );
}
SECTION( "density-matrix" ) {
QMatrix matRef = getRandomDensityMatrix(NUM_QUBITS);
toQureg(mat, matRef);
qcomp tr = 0;
for (size_t ind=0; ind<matRef.size(); ind++) {
int bit = (ind >> qubit) & 1; if (bit == outcome)
tr += matRef[ind][ind];
}
REQUIRE( imag(tr) == Approx(0).margin(REAL_EPS) );
qreal prob = real(tr);
for (size_t r=0; r<matRef.size(); r++) {
for (size_t c=0; c<matRef.size(); c++) {
int ketBit = (c >> qubit) & 1;
int braBit = (r >> qubit) & 1;
if (ketBit == outcome && braBit == outcome)
matRef[r][c] /= prob;
else
matRef[r][c] = 0;
}
}
qreal res = collapseToOutcome(mat, qubit, outcome);
REQUIRE( res == Approx(prob) );
REQUIRE( areEqual(mat, matRef) );
}
}
SECTION( "input validation" ) {
SECTION( "qubit index" ) {
int qubit = GENERATE( -1, NUM_QUBITS );
int outcome = 0;
REQUIRE_THROWS_WITH( collapseToOutcome(mat, qubit, outcome), Contains("Invalid target qubit") );
}
SECTION( "outcome value" ) {
int qubit = 0;
int outcome = GENERATE( -1, 2 );
REQUIRE_THROWS_WITH( collapseToOutcome(mat, qubit, outcome), Contains("Invalid measurement outcome") );
}
SECTION( "outcome probability" ) {
initZeroState(vec);
REQUIRE_THROWS_WITH( collapseToOutcome(vec, 0, 1), Contains("Can't collapse to state with zero probability") );
initClassicalState(vec, 1);
REQUIRE_THROWS_WITH( collapseToOutcome(vec, 0, 0), Contains("Can't collapse to state with zero probability") );
}
}
destroyQureg(vec, QUEST_ENV);
destroyQureg(mat, QUEST_ENV);
}
TEST_CASE( "measure", "[gates]" ) {
Qureg vec = createQureg(NUM_QUBITS, QUEST_ENV);
Qureg mat = createDensityQureg(NUM_QUBITS, QUEST_ENV);
SECTION( "correctness" ) {
int qubit = GENERATE( range(0,NUM_QUBITS) );
GENERATE( range(0,10) );
SECTION( "state-vector" ) {
QVector vecRef = getRandomStateVector(NUM_QUBITS);
toQureg(vec, vecRef);
int outcome = measure(vec, qubit);
REQUIRE( (outcome == 0 || outcome == 1) );
qreal prob = 0;
for (size_t ind=0; ind<vecRef.size(); ind++) {
int bit = (ind >> qubit) & 1; if (bit == outcome)
prob += pow(abs(vecRef[ind]), 2);
}
REQUIRE( prob > REAL_EPS );
for (size_t ind=0; ind<vecRef.size(); ind++) {
int bit = (ind >> qubit) & 1; if (bit == outcome)
vecRef[ind] /= sqrt(prob);
else
vecRef[ind] = 0;
}
REQUIRE( areEqual(vec, vecRef) );
}
SECTION( "density-matrix" ) {
QMatrix matRef = getRandomDensityMatrix(NUM_QUBITS);
toQureg(mat, matRef);
int outcome = measure(mat, qubit);
REQUIRE( (outcome == 0 || outcome == 1) );
qreal prob = 0;
for (size_t ind=0; ind<matRef.size(); ind++) {
int bit = (ind >> qubit) & 1; if (bit == outcome)
prob += real(matRef[ind][ind]);
}
REQUIRE( prob > REAL_EPS );
for (size_t r=0; r<matRef.size(); r++) {
for (size_t c=0; c<matRef.size(); c++) {
int ketBit = (c >> qubit) & 1;
int braBit = (r >> qubit) & 1;
if (ketBit == outcome && braBit == outcome)
matRef[r][c] /= prob;
else
matRef[r][c] = 0;
}
}
REQUIRE( areEqual(mat, matRef) );
}
}
SECTION( "input validation" ) {
SECTION( "qubit index" ) {
int qubit = GENERATE( -1, NUM_QUBITS );
REQUIRE_THROWS_WITH( measure(vec, qubit), Contains("Invalid target qubit") );
}
}
destroyQureg(vec, QUEST_ENV);
destroyQureg(mat, QUEST_ENV);
}
TEST_CASE( "measureWithStats", "[gates]" ) {
Qureg vec = createQureg(NUM_QUBITS, QUEST_ENV);
Qureg mat = createDensityQureg(NUM_QUBITS, QUEST_ENV);
SECTION( "correctness" ) {
int qubit = GENERATE( range(0,NUM_QUBITS) );
GENERATE( range(0,10) );
SECTION( "state-vector" ) {
QVector vecRef = getRandomStateVector(NUM_QUBITS);
toQureg(vec, vecRef);
qreal res;
int outcome = measureWithStats(vec, qubit, &res);
REQUIRE( (outcome == 0 || outcome == 1) );
qreal prob = 0;
for (size_t ind=0; ind<vecRef.size(); ind++) {
int bit = (ind >> qubit) & 1; if (bit == outcome)
prob += pow(abs(vecRef[ind]), 2);
}
REQUIRE( prob == Approx(res) );
for (size_t ind=0; ind<vecRef.size(); ind++) {
int bit = (ind >> qubit) & 1; if (bit == outcome)
vecRef[ind] /= sqrt(prob);
else
vecRef[ind] = 0;
}
REQUIRE( areEqual(vec, vecRef) );
}
SECTION( "density-matrix" ) {
QMatrix matRef = getRandomDensityMatrix(NUM_QUBITS);
toQureg(mat, matRef);
qreal res;
int outcome = measureWithStats(mat, qubit, &res);
REQUIRE( (outcome == 0 || outcome == 1) );
qreal prob = 0;
for (size_t ind=0; ind<matRef.size(); ind++) {
int bit = (ind >> qubit) & 1; if (bit == outcome)
prob += real(matRef[ind][ind]);
}
REQUIRE( prob == Approx(res) );
for (size_t r=0; r<matRef.size(); r++) {
for (size_t c=0; c<matRef.size(); c++) {
int ketBit = (c >> qubit) & 1;
int braBit = (r >> qubit) & 1;
if (ketBit == outcome && braBit == outcome)
matRef[r][c] /= prob;
else
matRef[r][c] = 0;
}
}
REQUIRE( areEqual(mat, matRef) );
}
}
SECTION( "input validation" ) {
SECTION( "qubit index" ) {
int qubit = GENERATE( -1, NUM_QUBITS );
qreal res;
REQUIRE_THROWS_WITH( measureWithStats(vec, qubit, &res), Contains("Invalid target qubit") );
}
}
destroyQureg(vec, QUEST_ENV);
destroyQureg(mat, QUEST_ENV);
}