#include "catch.hpp"
#include "QuEST.h"
#include "utilities.hpp"
using Catch::Matchers::Contains;
TEST_CASE( "applyPauliSum", "[operators]" ) {
Qureg vecIn = createQureg(NUM_QUBITS, QUEST_ENV);
Qureg vecOut = createQureg(NUM_QUBITS, QUEST_ENV);
Qureg matIn = createDensityQureg(NUM_QUBITS, QUEST_ENV);
Qureg matOut = createDensityQureg(NUM_QUBITS, QUEST_ENV);
initDebugState(vecIn);
initDebugState(matIn);
SECTION( "correctness" ) {
int numTerms = GENERATE( 1, 2, 10, 15);
int numPaulis = numTerms * NUM_QUBITS;
qreal coeffs[numTerms];
for (int i=0; i<numTerms; i++)
coeffs[i] = getRandomReal(-5, 5);
GENERATE( range(0,10) ); pauliOpType paulis[numPaulis];
for (int i=0; i<numPaulis; i++)
paulis[i] = (pauliOpType) getRandomInt(0,4);
QMatrix iMatr{{1,0},{0,1}};
QMatrix xMatr{{0,1},{1,0}};
QMatrix yMatr{{0,-1i},{1i,0}};
QMatrix zMatr{{1,0},{0,-1}};
QMatrix pauliSum = getZeroMatrix(1<<NUM_QUBITS);
for (int t=0; t<numTerms; t++) {
QMatrix pauliProd = QMatrix{{1}};
for (int q=0; q<NUM_QUBITS; q++) {
int i = q + t*NUM_QUBITS;
QMatrix fac;
if (paulis[i] == PAULI_I) fac = iMatr;
if (paulis[i] == PAULI_X) fac = xMatr;
if (paulis[i] == PAULI_Y) fac = yMatr;
if (paulis[i] == PAULI_Z) fac = zMatr;
pauliProd = getKroneckerProduct(fac, pauliProd);
}
pauliSum += coeffs[t] * pauliProd;
}
SECTION( "state-vector" ) {
QVector vecRef = toQVector(vecIn);
applyPauliSum(vecIn, paulis, coeffs, numTerms, vecOut);
REQUIRE( areEqual(vecIn, vecRef) );
REQUIRE( areEqual(vecOut, pauliSum * vecRef) );
}
SECTION( "density-matrix" ) {
QMatrix matRef = toQMatrix(matIn);
applyPauliSum(matIn, paulis, coeffs, numTerms, matOut);
REQUIRE( areEqual(matIn, matRef) );
REQUIRE( areEqual(matOut, pauliSum * matRef, 1E2*REAL_EPS) );
}
}
SECTION( "input validation" ) {
SECTION( "number of terms" ) {
int numTerms = GENERATE( -1, 0 );
REQUIRE_THROWS_WITH( applyPauliSum(vecIn, NULL, NULL, numTerms, vecOut), Contains("Invalid number of terms") );
}
SECTION( "pauli codes" ) {
int numTerms = 3;
int numPaulis = numTerms*NUM_QUBITS;
pauliOpType paulis[numPaulis];
for (int i=0; i<numPaulis; i++)
paulis[i] = PAULI_I;
paulis[GENERATE_COPY( range(0,numPaulis) )] = (pauliOpType) GENERATE( -1, 4 );
REQUIRE_THROWS_WITH( applyPauliSum(vecIn, paulis, NULL, numTerms, vecOut), Contains("Invalid Pauli code") );
}
SECTION( "qureg dimensions" ) {
Qureg badVec = createQureg(NUM_QUBITS+1, QUEST_ENV);
pauliOpType paulis[NUM_QUBITS];
REQUIRE_THROWS_WITH( applyPauliSum(vecIn, paulis, NULL, 1, badVec), Contains("Dimensions of the qubit registers don't match") );
destroyQureg(badVec, QUEST_ENV);
}
SECTION( "qureg types" ) {
pauliOpType paulis[NUM_QUBITS];
REQUIRE_THROWS_WITH( applyPauliSum(vecIn, paulis, NULL, 1, matOut), Contains("Registers must both be state-vectors or both be density matrices") );
}
}
destroyQureg(vecIn, QUEST_ENV);
destroyQureg(vecOut, QUEST_ENV);
destroyQureg(matIn, QUEST_ENV);
destroyQureg(matOut, QUEST_ENV);
}