15#include <catch2/catch_test_macros.hpp>
16#include <catch2/generators/catch_generators_range.hpp>
17#include <catch2/matchers/catch_matchers_floating_point.hpp>
18#include <catch2/matchers/catch_matchers_string.hpp>
20#include "tests/utils/macros.hpp"
21#include "tests/utils/cache.hpp"
22#include "tests/utils/compare.hpp"
23#include "tests/utils/random.hpp"
30using namespace Catch::Matchers;
36#define TEST_CATEGORY \
37 LABEL_UNIT_TAG "[trotterisation]"
39void TEST_ON_CACHED_QUREGS(quregCache quregs,
auto& refFunc,
auto& regularFunc,
auto& randFunc) {
40 for (
auto& [label, refQureg]: quregs) {
42 DYNAMIC_SECTION( label ) {
49 regularFunc(regularQureg);
52 double regularDistance =
calcDistance(regularQureg, refQureg);
55 REQUIRE( randDistance < regularDistance );
63void TEST_ON_CACHED_QUREGS(quregCache quregs, qvector& referenceResult,
auto& testFunction,
PauliStrSum& testHamiltonian) {
64 for (
auto& [label, qureg]: quregs) {
66 DYNAMIC_SECTION( label ) {
67 testFunction(qureg, testHamiltonian);
68 REQUIRE_AGREE(qureg, referenceResult);
76void TEST_ON_CACHED_QUREGS(quregCache quregs, qmatrix& referenceResult,
auto& testFunction,
PauliStrSum& testHamiltonian) {
77 for (
auto& [label, qureg]: quregs) {
79 DYNAMIC_SECTION( label ) {
80 testFunction(qureg, testHamiltonian);
81 REQUIRE_AGREE(qureg, referenceResult);
89void TEST_OBSERVABLES_ON_QUREGS(quregCache quregs, qvector& referenceResult,
auto& testFunction,
PauliStrSum testHamiltonian,
PauliStrSum testObservable) {
90 for (
auto& [label, qureg]: quregs) {
92 DYNAMIC_SECTION( label ) {
93 qvector testResult = testFunction(qureg, testHamiltonian, testObservable);
95 REQUIRE_AGREE(testResult, referenceResult);
113PauliStrSum createHeisenbergHamiltonian(
int numQubits) {
121 vector<string> operators = {
"XX",
"YY",
"ZZ",
"Z"};
122 vector<qcomp> coefficients = {.1, .2, .3, .4};
127 vector<PauliStr> allStrings;
128 vector<qcomp> allCoeffs;
131 for (
int p=0; p<3; p++) {
132 for (
int i=0; i<numQubits; i++) {
135 vector<int> targs = {i, (i+1)%numQubits};
138 allStrings.push_back(str);
139 allCoeffs.push_back(coefficients[p]);
144 for (
int i=0; i<numQubits; i++) {
145 allStrings.push_back(
getPauliStr(operators[3], {i}));
146 allCoeffs.push_back(coefficients[3]);
162PauliStrSum createAlternatingPauliObservable(
int numQubits) {
169 vector<PauliStr> strings(numQubits);
170 vector<qcomp> coeffs(numQubits);
172 for (
int i=0; i<numQubits; i++) {
196PauliStrSum createIsingHamiltonian(
int numQubits, qreal magField,
197 qreal interactionStrength, qreal asymmetricBias) {
198 const int NTERMS = 2 * numQubits + 1;
200 vector<qcomp> coeffs;
201 vector<PauliStr> pauli_terms;
202 coeffs.reserve(NTERMS);
203 pauli_terms.reserve(NTERMS);
205 for (
int i = 0; i < numQubits; ++i) {
207 coeffs.push_back(
getQcomp(-magField, 0));
209 int next = (i + 1) % numQubits;
210 pauli_terms.push_back(
getPauliStr(
"ZZ", {i, next}));
211 coeffs.push_back(
getQcomp(-interactionStrength, 0));
215 coeffs.push_back(
getQcomp(-asymmetricBias, 0));
231TEST_CASE(
"randomisedTrotter", TEST_CATEGORY ) {
233 SECTION( LABEL_CORRECTNESS ) {
235 int numQubits = getNumCachedQubits();
241 int order = GENERATE_COPY(1, 2);
243 GENERATE( range(0, 10) );
244 PauliStrSum sum = createRandomPauliStrSum(numQubits, numTerms);
250 TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), refFunc, regularFunc, randFunc);
251 TEST_ON_CACHED_QUREGS(getCachedStatevecs(), refFunc, regularFunc, randFunc);
262TEST_CASE(
"applyTrotterizedUnitaryTimeEvolution", TEST_CATEGORY ) {
264 SECTION( LABEL_CORRECTNESS ) {
274 const int NUM_QUBITS = 8;
278 const int STEPS = 20;
279 bool permutePaulis = GENERATE(
true,
false);
281 auto unitaryTimeEvoFunc =
284 qvector observations = getZeroVector(STEPS);
287 for (
int i = 0; i < STEPS; i++) {
295 PauliStrSum hamil = createHeisenbergHamiltonian(NUM_QUBITS);
296 PauliStrSum observ = createAlternatingPauliObservable(NUM_QUBITS);
298 qvector refObservables = {
321 SECTION(
"Time Evolve Statevectors") {
322 quregCache eightQubitSVCache = createCustomCachedQuregs(NUM_QUBITS,
false);
323 TEST_OBSERVABLES_ON_QUREGS(eightQubitSVCache, refObservables, unitaryTimeEvoFunc, hamil, observ);
324 destroyCustomCachedQuregs(eightQubitSVCache);
327 SECTION(
"Time Evolve Density Matrices") {
328 quregCache eightQubitDMCache = createCustomCachedQuregs(NUM_QUBITS,
true);
329 TEST_OBSERVABLES_ON_QUREGS(eightQubitDMCache, refObservables, unitaryTimeEvoFunc, hamil, observ);
330 destroyCustomCachedQuregs(eightQubitDMCache);
340 SECTION( LABEL_VALIDATION ) {
342 Qureg qureg = getArbitraryCachedStatevec();
343 PauliStrSum hamil = createHeisenbergHamiltonian(qureg.numQubits);
344 bool permuteTerms =
false;
346 SECTION(
"qureg uninitialised" ) {
348 Qureg badQureg = qureg;
349 badQureg.numQubits = -1;
352 ContainsSubstring(
"invalid Qureg")
356 SECTION(
"pauli sum uninitialized" ) {
359 badHamil.numTerms = 0;
362 ContainsSubstring(
"Pauli")
366 SECTION(
"hamiltonian not hermitian" ) {
368 vector<PauliStr> strings;
369 vector<qcomp> coeffs;
371 coeffs.push_back(
getQcomp(1.0, 1.0));
376 ContainsSubstring(
"Hermitian")
381 SECTION(
"pauli sum exceeds qureg qubits" ) {
383 PauliStrSum largeHamil = createHeisenbergHamiltonian(qureg.numQubits + 1);
386 ContainsSubstring(
"only compatible")
391 SECTION(
"invalid trotter order (zero)" ) {
395 ContainsSubstring(
"order")
399 SECTION(
"invalid trotter order (negative)" ) {
403 ContainsSubstring(
"order")
407 SECTION(
"invalid trotter order (odd, not 1)" ) {
411 ContainsSubstring(
"order")
415 SECTION(
"invalid trotter reps (zero)" ) {
419 ContainsSubstring(
"repetitions")
423 SECTION(
"invalid trotter reps (negative)" ) {
427 ContainsSubstring(
"repetitions")
431 SECTION(
"sum ordering allocation failure" ) {
442TEST_CASE(
"applyTrotterizedImaginaryTimeEvolution", TEST_CATEGORY ) {
443 int numQubits = getNumCachedQubits();
444 auto statevecQuregs = getCachedStatevecs();
445 auto densmatrQuregs = getCachedDensmatrs();
447 SECTION( LABEL_CORRECTNESS ) {
453 bool permutePaulis = GENERATE(
true,
false);
455 auto driveToGroundFunc = [steps, tau, order, reps, permutePaulis](
Qureg qureg,
PauliStrSum& hamil) {
458 for (
int i = 0; i < steps; ++i) {
465#if QUEST_FLOAT_PRECISION == 4
474 qreal initialEps = getTestAbsoluteEpsilon();
475 setTestAbsoluteEpsilon(300 * initialEps);
480 SECTION(
"Spin Down Field")
482 PauliStrSum ising = createIsingHamiltonian(numQubits, 10.0, 0.0, 0.0);
484 qvector statevecRef = getZeroVector(getPow2(numQubits));
485 statevecRef.at(0) = 1;
488 densmatrRef[0][0] = 1;
490 TEST_ON_CACHED_QUREGS(statevecQuregs, statevecRef, driveToGroundFunc, ising);
491 TEST_ON_CACHED_QUREGS(densmatrQuregs, densmatrRef, driveToGroundFunc, ising);
497 SECTION(
"Spin Up Field")
499 PauliStrSum ising = createIsingHamiltonian(numQubits, -10.0, 0.0, 0.0);
501 qindex namps = getPow2(numQubits);
503 qvector statevecRef = getZeroVector(namps);
504 statevecRef.at(namps - 1) = 1;
507 densmatrRef[namps-1][namps-1] = 1;
509 TEST_ON_CACHED_QUREGS(statevecQuregs, statevecRef, driveToGroundFunc, ising);
510 TEST_ON_CACHED_QUREGS(densmatrQuregs, densmatrRef, driveToGroundFunc, ising);
516 SECTION(
"Ferromagnetic Interaction")
518 PauliStrSum ising = createIsingHamiltonian(numQubits, 0.0, 10.0, 10.0);
520 qvector statevecRef = getZeroVector(getPow2(numQubits));
521 statevecRef.at(0) = 1;
524 densmatrRef[0][0] = 1;
526 TEST_ON_CACHED_QUREGS(statevecQuregs, statevecRef, driveToGroundFunc, ising);
527 TEST_ON_CACHED_QUREGS(densmatrQuregs, densmatrRef, driveToGroundFunc, ising);
533 SECTION(
"Antiferromagnetic Interaction")
535 PauliStrSum ising = createIsingHamiltonian(numQubits, 0.0, -10.0, 10.0);
539 unsigned long long idx = 0;
540 for (
int i = 0; i < numQubits / 2; ++i) {
541 idx += (1ULL << (2*i + 1));
544 qvector statevecRef = getZeroVector(getPow2(numQubits));
545 statevecRef.at(idx) = 1;
548 densmatrRef[idx][idx] = 1;
550 TEST_ON_CACHED_QUREGS(statevecQuregs, statevecRef, driveToGroundFunc, ising);
551 TEST_ON_CACHED_QUREGS(densmatrQuregs, densmatrRef, driveToGroundFunc, ising);
556#if QUEST_FLOAT_PRECISION == 4
557 setTestEpsilon(initialEps);
561 SECTION( LABEL_VALIDATION ) {
563 Qureg qureg = getArbitraryCachedStatevec();
564 PauliStrSum ising = createIsingHamiltonian(qureg.numQubits, 1.0, 1.0, 0.0);
565 bool permuteTerms =
false;
567 SECTION(
"qureg uninitialised" ) {
569 Qureg badQureg = qureg;
570 badQureg.numQubits = -1;
573 ContainsSubstring(
"invalid Qureg")
577 SECTION(
"pauli sum uninitialized" ) {
580 badIsing.numTerms = 0;
583 ContainsSubstring(
"Pauli")
587 SECTION(
"pauli sum exceeds qureg qubits" ) {
589 PauliStrSum largeIsing = createIsingHamiltonian(qureg.numQubits+1, 1.0, 1.0, 0.0);
592 ContainsSubstring(
"only compatible")
597 SECTION(
"hamiltonian not hermitian" ) {
599 vector<PauliStr> strings;
600 vector<qcomp> coeffs;
602 coeffs.push_back(
getQcomp(1.0, 1.0));
607 ContainsSubstring(
"Hermitian")
612 SECTION(
"invalid trotter order (zero)" ) {
616 ContainsSubstring(
"order")
620 SECTION(
"invalid trotter order (negative)" ) {
624 ContainsSubstring(
"order")
628 SECTION(
"invalid trotter order (odd, not 1)" ) {
632 ContainsSubstring(
"order")
636 SECTION(
"invalid trotter reps (zero)" ) {
640 ContainsSubstring(
"repetitions")
644 SECTION(
"invalid trotter reps (negative)" ) {
648 ContainsSubstring(
"repetitions")
652 SECTION(
"sum ordering allocation failure" ) {
qreal calcDistance(Qureg qureg, Qureg other)
qreal calcExpecPauliStrSum(Qureg qureg, PauliStrSum sum)
qreal calcTotalProb(Qureg qureg)
qreal getQuESTValidationEpsilon()
void setQuESTValidationEpsilon(qreal eps)
qreal setQuregToRenormalized(Qureg qureg)
void initPlusState(Qureg qureg)
void initDebugState(Qureg qureg)
PauliStrSum createPauliStrSum(PauliStr *strings, qcomp *coeffs, qindex numTerms)
PauliStr getPauliStr(const char *paulis, int *indices, int numPaulis)
void destroyPauliStrSum(PauliStrSum sum)
Qureg createCloneQureg(Qureg qureg)
void destroyQureg(Qureg qureg)
qmatrix getZeroMatrix(size_t dim)
void applyTrotterizedMultiControlledPauliStrSumGadget(Qureg qureg, int *controls, int numControls, PauliStrSum sum, qreal angle, int order, int reps, bool permuteTerms)
void applyTrotterizedPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qreal angle, int order, int reps, bool permuteTerms)
void applyTrotterizedControlledPauliStrSumGadget(Qureg qureg, int control, PauliStrSum sum, qreal angle, int order, int reps, bool permuteTerms)
void applyTrotterizedNonUnitaryPauliStrSumGadget(Qureg qureg, PauliStrSum sum, qcomp angle, int order, int reps, bool permuteTerms)
void applyTrotterizedMultiStateControlledPauliStrSumGadget(Qureg qureg, int *controls, int *states, int numControls, PauliStrSum sum, qreal angle, int order, int reps, bool permuteTerms)
void applyTrotterizedNoisyTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal *damps, PauliStrSum *jumps, int numJumps, qreal time, int order, int reps, bool permuteTerms)
void applyTrotterizedUnitaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal time, int order, int reps, bool permuteTerms)
void applyTrotterizedImaginaryTimeEvolution(Qureg qureg, PauliStrSum hamil, qreal tau, int order, int reps, bool permuteTerms)
static qcomp getQcomp(qreal re, qreal im)
TEST_CASE("calcExpecPauliStr", TEST_CATEGORY)