10#include "quest/include/quest.h"
12#include <catch2/catch_test_macros.hpp>
13#include <catch2/matchers/catch_matchers_string.hpp>
14#include <catch2/generators/catch_generators_range.hpp>
16#include "tests/utils/qvector.hpp"
17#include "tests/utils/qmatrix.hpp"
18#include "tests/utils/macros.hpp"
19#include "tests/utils/cache.hpp"
20#include "tests/utils/convert.hpp"
21#include "tests/utils/compare.hpp"
22#include "tests/utils/linalg.hpp"
23#include "tests/utils/random.hpp"
32using Catch::Matchers::ContainsSubstring;
40#define TEST_CATEGORY \
41 LABEL_UNIT_TAG "[paulis]"
55 SECTION( LABEL_CORRECTNESS ) {
57 GENERATE( range(0,10) );
59 std::string charSet = GENERATE(
"IXYZ",
"ixyz",
"0123",
"iX2z" );
61 int numPaulis = GENERATE( 1, 2, 5, 10, 20, 30, 31, 32, 33, 60, 64 );
62 auto targets = getRandomSubRange(0, 64, numPaulis);
65 vector<char> pauliChars(numPaulis,
'I');
66 vector<int> pauliInts(numPaulis, 0);
67 long long unsigned lowValue = 0;
68 long long unsigned highValue = 0;
70 for (
int i=0; i<numPaulis; i++) {
73 pauliChars[i] = charSet[v];
77 (lowValue += v * getPow2(2 * t)):
78 (highValue += v * getPow2(2 * (t-32)));
81 SECTION( LABEL_C_INTERFACE ) {
83 SECTION(
"from chars" ) {
85 CAPTURE( targets, pauliChars );
89 REQUIRE( str.lowPaulis == lowValue );
90 REQUIRE( str.highPaulis == highValue );
93 SECTION(
"from ints" ) {
95 CAPTURE( targets, pauliChars );
99 REQUIRE( str.lowPaulis == lowValue );
100 REQUIRE( str.highPaulis == highValue );
103 SECTION(
"from literal" ) {
107 int targ = targets[0];
110 const char* in =
"X";
112 REQUIRE( str.lowPaulis == ((targ < 32)? getPow2(2*targ) : 0) );
113 REQUIRE( str.highPaulis == ((targ >= 32)? getPow2(2*(targ-32)) : 0) );
117 SECTION( LABEL_CPP_INTERFACE ) {
120 pauliChars.push_back(
'\0');
121 std::string in = std::string(pauliChars.data());
123 SECTION(
"from string" ) {
125 CAPTURE( targets, pauliChars );
129 REQUIRE( str.lowPaulis == lowValue );
130 REQUIRE( str.highPaulis == highValue );
133 SECTION(
"from vector" ) {
135 CAPTURE( targets, pauliChars );
139 REQUIRE( str.lowPaulis == lowValue );
140 REQUIRE( str.highPaulis == highValue );
143 SECTION(
"from literal" ) {
147 int targ = targets[0];
151 REQUIRE( str.lowPaulis == ((targ < 32)? getPow2(2*targ) : 0) );
152 REQUIRE( str.highPaulis == ((targ >= 32)? getPow2(2*(targ-32)) : 0) );
155 SECTION(
"from only string" ) {
157 CAPTURE( targets, pauliChars );
161 for (
int i=0; i<64; i++)
165 for (
int i=0; i<numPaulis; i++)
166 chars[64-targets[i]-1] = pauliChars[i];
168 std::string all = std::string(chars);
172 REQUIRE( str.lowPaulis == lowValue );
173 REQUIRE( str.highPaulis == highValue );
178 SECTION( LABEL_VALIDATION ) {
180 SECTION(
"invalid target" ) {
182 int target = GENERATE( -1, 64, 65, 9999 );
184 REQUIRE_THROWS_WITH(
getPauliStr(
"X", {target}), ContainsSubstring(
"Invalid index") );
187 SECTION(
"duplicated target" ) {
189 REQUIRE_THROWS_WITH(
getPauliStr(
"XY", {0,0}), ContainsSubstring(
"duplicate") );
192 SECTION(
"invalid number of paulis" ) {
194 int numPaulis = GENERATE( -1, 0 );
196 REQUIRE_THROWS_WITH(
getPauliStr(
"X",
nullptr, numPaulis), ContainsSubstring(
"must contain at least one Pauli operator") );
199 SECTION(
"string terminated early" ) {
201 REQUIRE_THROWS_WITH(
getPauliStr(
"X", {1,2}), ContainsSubstring(
"different number of Pauli operators") && ContainsSubstring(
"qubit indices") );
204 SECTION(
"unrecognised char" ) {
206 REQUIRE_THROWS_WITH(
getPauliStr(
"hi", {1,2}), ContainsSubstring(
"unrecognised Pauli character") );
212TEST_CASE(
"getInlinePauliStr", TEST_CATEGORY ) {
214 SECTION( LABEL_CORRECTNESS ) {
217 long long unsigned val;
219 val = 1 + 2*4 + 3*4*4 + 0*4*4*4;
221 REQUIRE( str.lowPaulis == val );
223 REQUIRE( str.lowPaulis == val );
225 REQUIRE( str.lowPaulis == val );
227 val = (1*4*4*4 + 2*4*4 + 3*4 + 0*4);
229 REQUIRE( str.lowPaulis == val );
231 REQUIRE( str.lowPaulis == val );
233 REQUIRE( str.lowPaulis == val );
235 val *= (1ULL << (2 * (63 - 3 - 32)));
237 REQUIRE( str.highPaulis == val );
239 REQUIRE( str.highPaulis == val );
241 REQUIRE( str.highPaulis == val );
244 SECTION( LABEL_VALIDATION ) {
248 SECTION(
"invalid target" ) {
250 int target = GENERATE( -1, 64, 65, 9999 );
252 REQUIRE_THROWS_WITH(
getInlinePauliStr(
"X", {target}), ContainsSubstring(
"Invalid index") );
255 SECTION(
"duplicated target" ) {
257 REQUIRE_THROWS_WITH(
getInlinePauliStr(
"XY", {0,0}), ContainsSubstring(
"duplicate") );
260 SECTION(
"string terminated early" ) {
262 REQUIRE_THROWS_WITH(
getInlinePauliStr(
"X", {1,2}), ContainsSubstring(
"different number of Pauli operators") && ContainsSubstring(
"qubit indices") );
265 SECTION(
"unrecognised char" ) {
267 REQUIRE_THROWS_WITH(
getInlinePauliStr(
"ABC", {1,2,3}), ContainsSubstring(
"unrecognised Pauli character") );
273TEST_CASE(
"createPauliStrSum", TEST_CATEGORY ) {
275 SECTION( LABEL_CORRECTNESS ) {
284 vector<PauliStr> strings = {
289 vector<qcomp> coeffs = {1, 2, 3_i};
297 SECTION( LABEL_C_INTERFACE ) {
301 REQUIRE( sum.numTerms == (qindex) strings.size() );
302 REQUIRE( *(sum.isApproxHermitian) == -1 );
304 REQUIRE_AGREE( getMatrix(sum,numQubits), ref );
309 SECTION( LABEL_CPP_INTERFACE ) {
313 REQUIRE( sum.numTerms == (qindex) strings.size() );
314 REQUIRE( *(sum.isApproxHermitian) == -1 );
316 REQUIRE_AGREE( getMatrix(sum,numQubits), ref );
322 SECTION( LABEL_VALIDATION ) {
324 SECTION(
"number of terms" ) {
326 int numTerms = GENERATE( -1, 0 );
328 REQUIRE_THROWS_WITH(
createPauliStrSum(
nullptr,
nullptr, numTerms), ContainsSubstring(
"number of terms must be a positive integer") );
331 SECTION(
"mismatching lengths" ) {
335 REQUIRE_THROWS_WITH(
createPauliStrSum({}, {.1}), ContainsSubstring(
"different number of Pauli strings") && ContainsSubstring(
"coefficients") );
341TEST_CASE(
"createInlinePauliStrSum", TEST_CATEGORY ) {
343 SECTION( LABEL_CORRECTNESS ) {
347 SECTION(
"pauli parsing" ) {
350 unsigned ref = 0 + 1*4 + 2*4*4 + 3*4*4*4;
352 ".1i ZYXI",
".1I Z Y X I",
".1j ZY X I ",
353 ".1i zyxi",
".1I z y x i",
".1j zy x i ",
354 ".1i 3210",
".1I 3 2 1 0",
".1J 32 1 0 ",
355 ".1i Zy1i",
".1I 3 Y X 0",
".1J Zy 1 I "
359 REQUIRE( sum.strings[0].lowPaulis == ref );
363 SECTION(
"coefficient parsing" ) {
365 vector<std::string> strs = {
"1 X",
"0 X",
"0.1 X",
"5E2-1i X",
"-1E-50i X",
"1 - 6E-5i X",
"-1.5E-15 - 5.123E-30i 0"};
366 vector<qcomp> coeffs = { 1, 0, 0.1, 5E2-1_i, -(1E-50)*1_i, 1 -(6E-5)*1_i, qcomp(-1.5E-15, -5.123E-30) };
368 size_t i = GENERATE_REF( range(0, (
int) strs.size()) );
369 CAPTURE( strs[i], coeffs[i] );
372 REQUIRE_AGREE( sum.coeffs[0], coeffs[i] );
376 SECTION(
"newlines" ) {
387 REQUIRE( sum.numTerms == 6 );
388 REQUIRE( sum.strings[3].lowPaulis == 0ULL );
389 REQUIRE_AGREE( sum.coeffs[5], qcomp(.5,0) );
395 SECTION( LABEL_VALIDATION ) {
397 SECTION(
"env not init" ) {
405 auto str = GENERATE(
"",
" ",
"\n",
" \n " );
410 SECTION(
"uninterpretable" ) {
412 auto str = GENERATE(
"X",
"1",
"a X",
"-1 H",
"0 .3",
"1 23456" );
419 SECTION(
"inconsistent number of qubits" ) {
424 SECTION(
"too many qubits" ) {
427 std::string str =
"1 XXXXXYYYYYZZZZZIIIIIXXXXXYYYYYZZZZZIIIIIXXXXXYYYYYZZZZZIIIIIXXXXX";
435TEST_CASE(
"createPauliStrSumFromFile", TEST_CATEGORY ) {
437 SECTION( LABEL_CORRECTNESS ) {
439 std::string fn =
"test.txt";
461 REQUIRE( sum.strings[0].lowPaulis == 3 + 2*4 + 1*4*4 );
463 REQUIRE( sum.numTerms == 6 );
464 REQUIRE( sum.coeffs[0] == qcomp(500, -1) );
465 REQUIRE( sum.strings[3].lowPaulis == 0ULL );
466 REQUIRE( sum.coeffs[5] == qcomp(.5,0) );
471 SECTION( LABEL_VALIDATION ) {
478 SECTION(
"bad file name" ) {
480 auto fn = GENERATE(
"",
" ",
"\n",
"nonexistentfile.txt" );
488TEST_CASE(
"createPauliStrSumFromReversedFile", TEST_CATEGORY ) {
490 SECTION( LABEL_CORRECTNESS ) {
492 std::string fn =
"test.txt";
515 REQUIRE( sum.strings[0].lowPaulis == 1 + 2*4 + 3*4*4 );
517 REQUIRE( sum.numTerms == 6 );
518 REQUIRE( sum.coeffs[0] == qcomp(500, -1) );
519 REQUIRE( sum.strings[3].lowPaulis == 0ULL );
520 REQUIRE( sum.coeffs[5] == qcomp(.5,0) );
525 SECTION( LABEL_VALIDATION ) {
532 SECTION(
"bad file name" ) {
534 auto fn = GENERATE(
"",
" ",
"\n",
"nonexistentfile.txt" );
542TEST_CASE(
"destroyPauliStrSum", TEST_CATEGORY ) {
544 SECTION( LABEL_CORRECTNESS ) {
550 SECTION( LABEL_VALIDATION ) {
555 #ifndef SANITIZER_IS_ACTIVE
556 SECTION(
"not created" ) {
564 sum.isApproxHermitian =
nullptr;
567 ContainsSubstring(
"invalid fields") ||
568 ContainsSubstring(
"heap pointers was unexpectedly NULL") ||
569 ContainsSubstring(
"It is likely the structure was not created by its proper function")
PauliStr getInlinePauliStr(const char *paulis, { list })
PauliStrSum createPauliStrSumFromFile(const char *fn)
PauliStrSum createPauliStrSum(PauliStr *strings, qcomp *coeffs, qindex numTerms)
PauliStrSum createInlinePauliStrSum(const char *str)
PauliStrSum createPauliStrSumFromReversedFile(const char *fn)
PauliStr getPauliStr(const char *paulis, int *indices, int numPaulis)
void destroyPauliStrSum(PauliStrSum sum)
void reportPauliStrSum(PauliStrSum str)
void reportPauliStr(PauliStr str)
int getRandomInt(int min, int maxExcl)
TEST_CASE("getPauliStr", TEST_CATEGORY)