#include "catch.hpp"
#include "QuEST.h"
#include "utilities.hpp"
using Catch::Matchers::Contains;
TEST_CASE( "fromComplex", "[data_structures]" ) {
Complex a = {.real=.5, .imag=-.2};
qcomp b = fromComplex(a);
REQUIRE( a.real == real(b) );
REQUIRE( a.imag == imag(b) );
}
TEST_CASE( "getStaticComplexMatrixN", "[data_structures]" ) {
SUCCEED( );
}
TEST_CASE( "toComplex", "[data_structures]" ) {
qcomp a = qcomp(.5,-.2);
Complex b = toComplex(a);
REQUIRE( real(a) == b.real );
REQUIRE( imag(a) == b.imag );
}
TEST_CASE( "createCloneQureg", "[data_structures]" ) {
SECTION( "state-vector" ) {
Qureg a = createQureg(NUM_QUBITS, QUEST_ENV);
Qureg b = createCloneQureg(a, QUEST_ENV);
REQUIRE( b.isDensityMatrix == a.isDensityMatrix );
REQUIRE( b.numQubitsRepresented == a.numQubitsRepresented );
REQUIRE( b.numQubitsInStateVec == a.numQubitsInStateVec );
REQUIRE( b.numAmpsPerChunk == a.numAmpsPerChunk );
REQUIRE( b.numAmpsTotal == a.numAmpsTotal );
REQUIRE( areEqual(a, b) );
destroyQureg(a, QUEST_ENV);
destroyQureg(b, QUEST_ENV);
}
SECTION( "density-matrix" ) {
Qureg a = createDensityQureg(NUM_QUBITS, QUEST_ENV);
Qureg b = createCloneQureg(a, QUEST_ENV);
REQUIRE( b.isDensityMatrix == a.isDensityMatrix );
REQUIRE( b.numQubitsRepresented == a.numQubitsRepresented );
REQUIRE( b.numQubitsInStateVec == a.numQubitsInStateVec );
REQUIRE( b.numAmpsPerChunk == a.numAmpsPerChunk );
REQUIRE( b.numAmpsTotal == a.numAmpsTotal );
REQUIRE( areEqual(a, b) );
destroyQureg(a, QUEST_ENV);
destroyQureg(b, QUEST_ENV);
}
}
TEST_CASE( "createComplexMatrixN", "[data_structures]" ) {
SECTION( "correctness" ) {
int numQb = GENERATE( range(1,10+1) );
ComplexMatrixN m = createComplexMatrixN(numQb);
REQUIRE( areEqual(toQMatrix(m), getZeroMatrix(1<<numQb)) );
destroyComplexMatrixN(m);
}
SECTION( "input validation" ) {
SECTION( "number of qubits" ) {
int numQb = GENERATE( -1, 0 );
REQUIRE_THROWS_WITH( createComplexMatrixN(numQb), Contains("Invalid number of qubits") );
}
}
}
TEST_CASE( "createDensityQureg", "[data_structures]" ) {
int minNumQb = calcLog2(QUEST_ENV.numRanks) - 1; if (minNumQb <= 0)
minNumQb = 1;
SECTION( "correctness" ) {
int numQb = GENERATE_COPY( range(minNumQb, minNumQb+10) );
Qureg reg = createDensityQureg(numQb, QUEST_ENV);
QMatrix ref = getZeroMatrix(1<<numQb);
ref[0][0] = 1; REQUIRE( areEqual(reg, ref) );
destroyQureg(reg, QUEST_ENV);
}
SECTION( "input validation") {
SECTION( "number of qubits" ) {
int numQb = GENERATE( -1, 0 );
REQUIRE_THROWS_WITH( createDensityQureg(numQb, QUEST_ENV), Contains("Invalid number of qubits") );
}
SECTION( "number of amplitudes" ) {
QuESTEnv env = QUEST_ENV;
int maxQb = (int) calcLog2(SIZE_MAX) / 2;
REQUIRE_THROWS_WITH( createDensityQureg(maxQb+1, env), Contains("Too many qubits") && Contains("size_t type") );
int minQb = GENERATE_COPY( range(3,maxQb) );
env.numRanks = (int) pow(2, 2*minQb);
int numQb = GENERATE_COPY( range(1,minQb) );
REQUIRE_THROWS_WITH( createDensityQureg(numQb, env), Contains("Too few qubits") );
}
SECTION( "available memory" ) {
SUCCEED( );
}
}
}
TEST_CASE( "createDiagonalOp", "[data_structures]" ) {
int minNumQb = calcLog2(QUEST_ENV.numRanks);
if (minNumQb == 0)
minNumQb = 1;
SECTION( "correctness" ) {
int numQb = GENERATE_COPY( range(minNumQb, minNumQb+10) );
DiagonalOp op = createDiagonalOp(numQb, QUEST_ENV);
REQUIRE( op.numQubits == numQb );
REQUIRE( op.chunkId == QUEST_ENV.rank );
REQUIRE( op.numChunks == QUEST_ENV.numRanks );
REQUIRE( op.numElemsPerChunk == (1LL << numQb) / QUEST_ENV.numRanks );
REQUIRE( op.real != NULL );
REQUIRE( op.imag != NULL );
REQUIRE( areEqual(toQVector(op), QVector(1LL << numQb)) );
destroyDiagonalOp(op, QUEST_ENV);
}
SECTION( "input validation" ) {
SECTION( "number of qubits" ) {
int numQb = GENERATE( -1, 0 );
REQUIRE_THROWS_WITH( createDiagonalOp(numQb, QUEST_ENV), Contains("Invalid number of qubits") );
}
SECTION( "number of elements" ) {
QuESTEnv env = QUEST_ENV;
int maxQb = (int) calcLog2(SIZE_MAX);
REQUIRE_THROWS_WITH( createDiagonalOp(maxQb+1, env), Contains("Too many qubits") && Contains("size_t type") );
int minQb = GENERATE_COPY( range(2,maxQb) );
env.numRanks = (int) pow(2, minQb);
int numQb = GENERATE_COPY( range(1,minQb) );
REQUIRE_THROWS_WITH( createDiagonalOp(numQb, env), Contains("Too few qubits") && Contains("distributed"));
}
SECTION( "available memory" ) {
SUCCEED( );
}
}
}
TEST_CASE( "createDiagonalOpFromPauliHamilFile", "[data_structures]" ) {
char fnPrefix[] = "temp_createDiagonalOpFromPauliHamilFile";
char fn[100];
setUniqueFilename(fn, fnPrefix);
int minNumQb = calcLog2(QUEST_ENV.numRanks);
if (minNumQb == 0)
minNumQb = 1;
SECTION( "correctness" ) {
SECTION( "general" ) {
int numQb = GENERATE_COPY( range(minNumQb, 6+minNumQb) );
int numTerms = GENERATE_COPY( 1, minNumQb, 10*minNumQb );
PauliHamil hamil = createPauliHamil(numQb, numTerms);
setRandomDiagPauliHamil(hamil);
if (QUEST_ENV.rank == 0) {
FILE* file = fopen(fn, "w");
int i=0;
for (int n=0; n<numTerms; n++) {
fprintf(file, REAL_STRING_FORMAT, hamil.termCoeffs[n]);
fprintf(file, " ");
for (int q=0; q<numQb; q++)
fprintf(file, "%d ", (int) hamil.pauliCodes[i++]);
fprintf(file, "\n");
}
fprintf(file, "\n");
fclose(file);
}
syncQuESTEnv(QUEST_ENV);
DiagonalOp op = createDiagonalOpFromPauliHamilFile(fn, QUEST_ENV);
REQUIRE( areEqual(toQMatrix(op), toQMatrix(hamil)) );
destroyPauliHamil(hamil);
destroyDiagonalOp(op, QUEST_ENV);
}
SECTION( "edge cases" ) {
qreal coeffs[] = {.1};
pauliOpType codes[minNumQb];
for (int q=0; q<minNumQb; q++)
codes[q] = (q%2)? PAULI_I : PAULI_Z;
QMatrix ref = toQMatrix(coeffs, codes, minNumQb, 1);
string line = to_string(coeffs[0]) + " ";
for (int q=0; q<minNumQb; q++)
line += to_string(codes[q]) + ((q<minNumQb-1)? " ":"");
SECTION( "no trailing newline or space" ) {
writeToFileSynch(fn, line);
DiagonalOp op = createDiagonalOpFromPauliHamilFile(fn, QUEST_ENV);
REQUIRE( areEqual(ref, toQMatrix(op)) );
destroyDiagonalOp(op, QUEST_ENV);
}
SECTION( "trailing newlines" ) {
writeToFileSynch(fn, line + "\n\n\n");
DiagonalOp op = createDiagonalOpFromPauliHamilFile(fn, QUEST_ENV);
REQUIRE( areEqual(ref, toQMatrix(op)) );
destroyDiagonalOp(op, QUEST_ENV);
}
SECTION( "trailing spaces" ) {
writeToFileSynch(fn, line + " ");
DiagonalOp op = createDiagonalOpFromPauliHamilFile(fn, QUEST_ENV);
REQUIRE( areEqual(ref, toQMatrix(op)) );
destroyDiagonalOp(op, QUEST_ENV);
}
}
}
SECTION( "input validation") {
SECTION( "number of qubits" ) {
writeToFileSynch(fn, ".1 "); REQUIRE_THROWS_WITH( createDiagonalOpFromPauliHamilFile(fn, QUEST_ENV), Contains("The number of qubits") && Contains("strictly positive"));
}
SECTION( "number of elements" ) {
int maxQb = (int) calcLog2(SIZE_MAX);
string line = ".1 ";
for (int q=0; q<(maxQb+1); q++)
line += "3 "; writeToFileSynch(fn, line);
REQUIRE_THROWS_WITH( createDiagonalOpFromPauliHamilFile(fn, QUEST_ENV), Contains("Too many qubits") && Contains("size_t type") );
QuESTEnv env = QUEST_ENV;
int minQb = GENERATE_COPY( range(2,maxQb) );
env.numRanks = (int) pow(2, minQb);
int numQb = GENERATE_COPY( range(1,minQb) );
line = ".1 ";
for (int q=0; q<numQb; q++)
line += "3 "; setUniqueFilename(fn, fnPrefix);
writeToFileSynch(fn, line);
REQUIRE_THROWS_WITH( createDiagonalOpFromPauliHamilFile(fn, env), Contains("Too few qubits") && Contains("distributed") );
}
SECTION( "coefficient type" ) {
writeToFileSynch(fn, "notanumber 1 2 3");
REQUIRE_THROWS_WITH( createDiagonalOpFromPauliHamilFile(fn, QUEST_ENV), Contains("Failed to parse") && Contains("coefficient"));
}
SECTION( "pauli code" ) {
writeToFileSynch(fn, ".1 0 3 2"); REQUIRE_THROWS_WITH( createDiagonalOpFromPauliHamilFile(fn, QUEST_ENV), Contains("contained operators other than PAULI_Z and PAULI_I"));
setUniqueFilename(fn, fnPrefix);
writeToFileSynch(fn, ".1 0 1 3"); REQUIRE_THROWS_WITH( createDiagonalOpFromPauliHamilFile(fn, QUEST_ENV), Contains("contained operators other than PAULI_Z and PAULI_I"));
setUniqueFilename(fn, fnPrefix);
writeToFileSynch(fn, ".1 0 1 4"); REQUIRE_THROWS_WITH( createDiagonalOpFromPauliHamilFile(fn, QUEST_ENV), Contains("invalid pauli code"));
setUniqueFilename(fn, fnPrefix);
writeToFileSynch(fn, ".1 3 0 notanumber"); REQUIRE_THROWS_WITH( createDiagonalOpFromPauliHamilFile(fn, QUEST_ENV), Contains("Failed to parse the next expected Pauli code"));
}
}
deleteFilesWithPrefixSynch(fnPrefix);
}
TEST_CASE( "createPauliHamil", "[data_structures]" ) {
SECTION( "correctness" ) {
int numQb = GENERATE( range(1,5) );
int numTerms = GENERATE( range(1,5) );
PauliHamil hamil = createPauliHamil(numQb, numTerms);
REQUIRE( hamil.numQubits == numQb );
REQUIRE( hamil.numSumTerms == numTerms );
int numPaulis = numQb * numTerms;
for (int i=0; i<numPaulis; i++) {
REQUIRE( hamil.pauliCodes[i] == PAULI_I );
}
for (int j=0; j<numTerms; j++) {
hamil.termCoeffs[j] = 1;
REQUIRE( hamil.termCoeffs[j] == 1 );
}
destroyPauliHamil(hamil);
}
SECTION( "input validation") {
SECTION( "number of qubits" ) {
int numQb = GENERATE( -1, 0 );
REQUIRE_THROWS_WITH( createPauliHamil(numQb, 1), Contains("The number of qubits and terms in the PauliHamil must be strictly positive.") );
}
SECTION( "number of terms" ) {
int numTerms = GENERATE( -1, 0 );
REQUIRE_THROWS_WITH( createPauliHamil(1, numTerms), Contains("The number of qubits and terms in the PauliHamil must be strictly positive.") );
}
}
}
TEST_CASE( "createPauliHamilFromFile", "[data_structures]" ) {
char fnPrefix[] = "temp_createPauliHamilFromFile";
char fn[100];
setUniqueFilename(fn, fnPrefix);
SECTION( "correctness" ) {
SECTION( "general" ) {
int numQb = GENERATE( 1, 5, 10, 15 );
int numTerms = GENERATE( 1, 10, 30 );
int numPaulis = numQb*numTerms;
qreal coeffs[numTerms];
enum pauliOpType paulis[numPaulis];
setRandomPauliSum(coeffs, paulis, numQb, numTerms);
if (QUEST_ENV.rank == 0) {
FILE* file = fopen(fn, "w");
int i=0;
for (int n=0; n<numTerms; n++) {
fprintf(file, REAL_STRING_FORMAT, coeffs[n]);
fprintf(file, " ");
for (int q=0; q<numQb; q++)
fprintf(file, "%d ", (int) paulis[i++]);
fprintf(file, "\n");
}
fprintf(file, "\n");
fclose(file);
}
syncQuESTEnv(QUEST_ENV);
PauliHamil hamil = createPauliHamilFromFile(fn);
REQUIRE( hamil.numQubits == numQb );
REQUIRE( hamil.numSumTerms == numTerms );
int j=0;
for (int n=0; n<numTerms; n++) {
REQUIRE( absReal(hamil.termCoeffs[n] - coeffs[n]) <= REAL_EPS );
for (int q=0; q<numQb; q++) {
REQUIRE( hamil.pauliCodes[j] == paulis[j] );
j++;
}
}
destroyPauliHamil(hamil);
}
SECTION( "edge cases" ) {
SECTION( "no trailing newline or space" ) {
writeToFileSynch(fn, ".1 1 0 1");
PauliHamil hamil = createPauliHamilFromFile(fn);
REQUIRE( hamil.numSumTerms == 1 );
REQUIRE( hamil.numQubits == 3 );
destroyPauliHamil(hamil);
}
SECTION( "trailing newlines" ) {
writeToFileSynch(fn, ".1 1 0 1\n\n\n");
PauliHamil hamil = createPauliHamilFromFile(fn);
REQUIRE( hamil.numSumTerms == 1 );
REQUIRE( hamil.numQubits == 3 );
destroyPauliHamil(hamil);
}
SECTION( "trailing spaces" ) {
writeToFileSynch(fn, ".1 1 0 1 ");
PauliHamil hamil = createPauliHamilFromFile(fn);
REQUIRE( hamil.numSumTerms == 1 );
REQUIRE( hamil.numQubits == 3 );
destroyPauliHamil(hamil);
}
}
}
SECTION( "input validation") {
SECTION( "number of qubits" ) {
writeToFileSynch(fn, ".1 ");
REQUIRE_THROWS_WITH( createPauliHamilFromFile(fn), Contains("The number of qubits") && Contains("strictly positive"));
}
SECTION( "coefficient type" ) {
writeToFileSynch(fn, "notanumber 1 2 3");
REQUIRE_THROWS_WITH( createPauliHamilFromFile(fn), Contains("Failed to parse") && Contains("coefficient"));
}
SECTION( "pauli code" ) {
writeToFileSynch(fn, ".1 1 2 4");
REQUIRE_THROWS_WITH( createPauliHamilFromFile(fn), Contains("invalid pauli code"));
setUniqueFilename(fn, fnPrefix);
writeToFileSynch(fn, ".1 1 2 notanumber");
REQUIRE_THROWS_WITH( createPauliHamilFromFile(fn), Contains("Failed to parse the next expected Pauli code"));
}
}
deleteFilesWithPrefixSynch(fn);
}
TEST_CASE( "createQuESTEnv", "[data_structures]" ) {
SUCCEED( );
}
TEST_CASE( "createQureg", "[data_structures]" ) {
int minNumQb = calcLog2(QUEST_ENV.numRanks);
if (minNumQb == 0)
minNumQb = 1;
SECTION( "correctness" ) {
int numQb = GENERATE_COPY( range(minNumQb, minNumQb+10) );
Qureg reg = createQureg(numQb, QUEST_ENV);
QVector ref = QVector(1<<numQb);
ref[0] = 1; REQUIRE( areEqual(reg, ref) );
destroyQureg(reg, QUEST_ENV);
}
SECTION( "input validation") {
SECTION( "number of qubits" ) {
int numQb = GENERATE( -1, 0 );
REQUIRE_THROWS_WITH( createQureg(numQb, QUEST_ENV), Contains("Invalid number of qubits") );
}
SECTION( "number of amplitudes" ) {
QuESTEnv env = QUEST_ENV;
int maxQb = (int) calcLog2(SIZE_MAX);
REQUIRE_THROWS_WITH( createQureg(maxQb+1, env), Contains("Too many qubits") && Contains("size_t type") );
int minQb = GENERATE_COPY( range(2,maxQb) );
env.numRanks = (int) pow(2, minQb);
int numQb = GENERATE_COPY( range(1,minQb) );
REQUIRE_THROWS_WITH( createQureg(numQb, env), Contains("Too few qubits") );
}
SECTION( "available memory" ) {
SUCCEED( );
}
}
}
TEST_CASE( "destroyComplexMatrixN", "[data_structures]" ) {
SECTION( "correctness" ) {
SUCCEED( );
}
SECTION( "input validation" ) {
SECTION( "matrix not created" ) {
ComplexMatrixN m;
m.real = NULL;
REQUIRE_THROWS_WITH( destroyComplexMatrixN(m), Contains("The ComplexMatrixN was not successfully created") );
}
}
}
TEST_CASE( "destroyDiagonalOp", "[data_structures]" ) {
SUCCEED( );
}
TEST_CASE( "destroyPauliHamil", "[data_structures]" ) {
SUCCEED( );
}
TEST_CASE( "destroyQuESTEnv", "[data_structures]" ) {
SUCCEED( );
}
TEST_CASE( "destroyQureg", "[data_structures]" ) {
SUCCEED( );
}
TEST_CASE( "initComplexMatrixN", "[data_structures]" ) {
SUCCEED( );
}
TEST_CASE( "initDiagonalOp", "[data_structures]" ) {
int minNumQb = calcLog2(QUEST_ENV.numRanks);
if (minNumQb == 0)
minNumQb = 1;
SECTION( "correctness" ) {
int numQb = GENERATE_COPY( range(minNumQb, minNumQb+10) );
DiagonalOp op = createDiagonalOp(numQb, QUEST_ENV);
long long int len = (1LL << numQb);
qreal reals[len];
qreal imags[len];
long long int n;
for (n=0; n<len; n++) {
reals[n] = (qreal) n;
imags[n] = (qreal) -2*n; }
initDiagonalOp(op, reals, imags);
REQUIRE( areEqual(toQVector(op), reals, imags) );
Qureg qureg = createQureg(numQb, QUEST_ENV);
for (long long int i=0; i<qureg.numAmpsPerChunk; i++) {
qureg.stateVec.real[i] = 1;
qureg.stateVec.imag[i] = 1;
}
copyStateToGPU(qureg);
QVector prodRef = toQMatrix(op) * toQVector(qureg);
applyDiagonalOp(qureg, op);
copyStateFromGPU(qureg);
QVector result = toQVector(qureg);
REQUIRE( areEqual(prodRef, result) );
destroyQureg(qureg, QUEST_ENV);
destroyDiagonalOp(op, QUEST_ENV);
}
}
TEST_CASE( "initDiagonalOpFromPauliHamil", "[data_structures]" ) {
int minNumQb = calcLog2(QUEST_ENV.numRanks);
if (minNumQb == 0)
minNumQb = 1;
SECTION( "correctness" ) {
int numQb = GENERATE_COPY( range(minNumQb, min(10,minNumQb+10)) );
DiagonalOp op = createDiagonalOp(numQb, QUEST_ENV);
int numTerms = GENERATE_COPY( 1, numQb, 5*numQb );
PauliHamil hamil = createPauliHamil(numQb, numTerms);
setRandomDiagPauliHamil(hamil);
initDiagonalOpFromPauliHamil(op, hamil);
REQUIRE( areEqual(toQMatrix(op), toQMatrix(hamil)) );
destroyPauliHamil(hamil);
destroyDiagonalOp(op, QUEST_ENV);
}
SECTION( "input validation" ) {
SECTION( "hamiltonian parameters" ) {
DiagonalOp op = createDiagonalOp(minNumQb, QUEST_ENV);
PauliHamil hamil;
hamil.numQubits = GENERATE( -1, 0 );
hamil.numSumTerms = 1;
REQUIRE_THROWS_WITH( initDiagonalOpFromPauliHamil(op, hamil), Contains("number of qubits") && Contains("strictly positive") );
hamil.numQubits = minNumQb;
hamil.numSumTerms = GENERATE( -1, 0 );
REQUIRE_THROWS_WITH( initDiagonalOpFromPauliHamil(op, hamil), Contains("terms") && Contains("strictly positive") );
destroyDiagonalOp(op, QUEST_ENV);
}
SECTION( "mismatching dimensions" ) {
int numQbA = minNumQb+1;
int numQbB = GENERATE_COPY( numQbA-1, numQbA+1 );
DiagonalOp op = createDiagonalOp(numQbA, QUEST_ENV);
PauliHamil hamil = createPauliHamil(numQbB, 1);
REQUIRE_THROWS_WITH( initDiagonalOpFromPauliHamil(op, hamil), Contains("Pauli Hamiltonian and diagonal operator have different, incompatible dimensions") );
destroyDiagonalOp(op, QUEST_ENV);
destroyPauliHamil(hamil);
}
SECTION( "pauli codes" ) {
DiagonalOp op = createDiagonalOp(minNumQb, QUEST_ENV);
PauliHamil hamil = createPauliHamil(minNumQb, 5);
int numCodes = minNumQb * hamil.numSumTerms;
int ind = GENERATE_COPY( range(0,numCodes) );
hamil.pauliCodes[ind] = GENERATE( PAULI_X, PAULI_Y );
REQUIRE_THROWS_WITH( initDiagonalOpFromPauliHamil(op, hamil), Contains("contained operators other than PAULI_Z and PAULI_I") );
destroyDiagonalOp(op, QUEST_ENV);
destroyPauliHamil(hamil);
}
}
}
TEST_CASE( "initPauliHamil", "[data_structures]" ) {
SECTION( "correctness" ) {
PauliHamil hamil = createPauliHamil(3, 2);
qreal coeffs[] = {-5, 5};
enum pauliOpType codes[] = {
PAULI_X, PAULI_Y, PAULI_Z,
PAULI_Z, PAULI_Y, PAULI_X};
initPauliHamil(hamil, coeffs, codes);
for (int t=0; t<2; t++) {
REQUIRE( coeffs[t] == hamil.termCoeffs[t] );
for (int q=0; q<3; q++) {
int ind = 3*t+q;
REQUIRE( codes[ind] == hamil.pauliCodes[ind] );
}
}
destroyPauliHamil(hamil);
}
SECTION( "input validation" ) {
SECTION( "parameters" ) {
qreal coeffs[1];
enum pauliOpType codes[1];
PauliHamil hamil;
hamil.numQubits = GENERATE( -1, 0 );
hamil.numSumTerms = 1;
REQUIRE_THROWS_WITH( initPauliHamil(hamil, coeffs, codes), Contains("number of qubits") && Contains("strictly positive") );
hamil.numQubits = 1;
hamil.numSumTerms = GENERATE( -1, 0 );
REQUIRE_THROWS_WITH( initPauliHamil(hamil, coeffs, codes), Contains("terms") && Contains("strictly positive") );
}
SECTION( "Pauli codes" ) {
int numQb = 3;
int numTerms = 2;
int numCodes = numQb * numTerms;
qreal coeffs[numTerms];
enum pauliOpType codes[numCodes];
for (int i=0; i<numCodes; i++)
codes[i] = PAULI_I;
codes[GENERATE_COPY( range(0,numCodes) )] = (pauliOpType) GENERATE( -1, 4 );
PauliHamil hamil = createPauliHamil(numQb, numTerms);
REQUIRE_THROWS_WITH( initPauliHamil(hamil, coeffs, codes), Contains("Invalid Pauli code") );
destroyPauliHamil(hamil);
}
}
}
TEST_CASE( "setDiagonalOpElems", "[data_structures]" ) {
int minNumQb = calcLog2(QUEST_ENV.numRanks);
if (minNumQb == 0)
minNumQb = 1;
int numQb = GENERATE_COPY( range(minNumQb, minNumQb+10) );
DiagonalOp op = createDiagonalOp(numQb, QUEST_ENV);
SECTION( "correctness" ) {
long long int len = (1LL << numQb);
qreal reals[len];
qreal imags[len];
long long int n;
for (n=0; n<len; n++) {
reals[n] = (qreal) n;
imags[n] = (qreal) -2*n; }
for (n=0; n<len; n++)
setDiagonalOpElems(op, n, &reals[n], &imags[n], 1);
REQUIRE( areEqual(toQVector(op), reals, imags) );
}
SECTION( "input validation" ) {
long long int maxInd = (1LL << numQb);
qreal *reals;
qreal *imags;
SECTION( "start index" ) {
int startInd = GENERATE_COPY( -1, maxInd );
int numAmps = 1;
REQUIRE_THROWS_WITH( setDiagonalOpElems(op, startInd, reals, imags, numAmps), Contains("Invalid element index") );
}
SECTION( "number of elements" ) {
int startInd = 0;
int numAmps = GENERATE_COPY( -1, maxInd+1 );
REQUIRE_THROWS_WITH( setDiagonalOpElems(op, startInd, reals, imags, numAmps), Contains("Invalid number of elements") );
startInd = maxInd - 1;
numAmps = 2;
REQUIRE_THROWS_WITH( setDiagonalOpElems(op, startInd, reals, imags, numAmps), Contains("More elements given than exist") );
}
}
destroyDiagonalOp(op, QUEST_ENV);
}
TEST_CASE( "syncDiagonalOp", "[data_structures]" ) {
int minNumQb = calcLog2(QUEST_ENV.numRanks);
if (minNumQb == 0)
minNumQb = 1;
SECTION( "correctness" ) {
int numQb = GENERATE_COPY( range(minNumQb, minNumQb+10) );
DiagonalOp op = createDiagonalOp(numQb, QUEST_ENV);
long long int n;
for (n=0; n<op.numElemsPerChunk; n++) {
op.real[n] = (qreal) n;
op.imag[n] = (qreal) -2*n; }
syncDiagonalOp(op);
Qureg qureg = createQureg(numQb, QUEST_ENV);
for (long long int i=0; i<qureg.numAmpsPerChunk; i++) {
qureg.stateVec.real[i] = 1;
qureg.stateVec.imag[i] = 1;
}
copyStateToGPU(qureg);
applyDiagonalOp(qureg, op);
copyStateFromGPU(qureg);
for (n=0; n<qureg.numAmpsPerChunk; n++) {
REQUIRE( qureg.stateVec.real[n] == 3*n );
REQUIRE( qureg.stateVec.imag[n] == -n );
}
destroyQureg(qureg, QUEST_ENV);
destroyDiagonalOp(op, QUEST_ENV);
}
}