The Quantum Exact Simulation Toolkit v4.1.0
Loading...
Searching...
No Matches
initialisations.cpp
1/** @file
2 * Unit tests of the initialisations module.
3 *
4 * @author Tyson Jones
5 *
6 * @defgroup unitinit Initialisation
7 * @ingroup unittests
8 */
9
10#include "quest.h"
11
12#include <catch2/catch_test_macros.hpp>
13#include <catch2/matchers/catch_matchers_string.hpp>
14#include <catch2/generators/catch_generators_range.hpp>
15
16#include "tests/utils/qvector.hpp"
17#include "tests/utils/qmatrix.hpp"
18#include "tests/utils/cache.hpp"
19#include "tests/utils/compare.hpp"
20#include "tests/utils/convert.hpp"
21#include "tests/utils/evolve.hpp"
22#include "tests/utils/linalg.hpp"
23#include "tests/utils/lists.hpp"
24#include "tests/utils/macros.hpp"
25#include "tests/utils/measure.hpp"
26#include "tests/utils/random.hpp"
27
28using Catch::Matchers::ContainsSubstring;
29
30
31
32/*
33 * UTILITIES
34 */
35
36
37#define TEST_CATEGORY \
38 LABEL_UNIT_TAG "[initialisations]"
39
40
41void TEST_ON_CACHED_QUREGS(quregCache quregs, auto testFunc) {
42
43 for (auto& [label, qureg]: quregs) {
44
45 DYNAMIC_SECTION( label ) {
46
47 testFunc(qureg);
48 }
49 }
50}
51
52
53void TEST_ON_CACHED_QUREGS(quregCache quregs, auto apiFunc, auto refState) {
54
55 // assumes refState is already initialised
56
57 auto testFunc = [&](Qureg qureg) {
58 apiFunc(qureg);
59 REQUIRE_AGREE( qureg, refState );
60 };
61
62 TEST_ON_CACHED_QUREGS(quregs, testFunc);
63}
64
65
66
67/**
68 * TESTS
69 *
70 * @ingroup unitinit
71 * @{
72 */
73
74
75TEST_CASE( "initBlankState", TEST_CATEGORY ) {
76
77 SECTION( LABEL_CORRECTNESS ) {
78
79 SECTION( LABEL_STATEVEC ) { TEST_ON_CACHED_QUREGS(getCachedStatevecs(), initBlankState, getRefStatevec()); }
80 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), initBlankState, getRefDensmatr()); }
81 }
82
83 /// @todo input validation
84}
85
86
87TEST_CASE( "initZeroState", TEST_CATEGORY ) {
88
89 SECTION( LABEL_CORRECTNESS ) {
90
91 qvector refVec = getRefStatevec(); refVec[0] = 1; // |0> = {1, 0...}
92 qmatrix refMat = getRefDensmatr(); refMat[0][0] = 1; // |0><0| = {{1,0...},{0...}...}
93
94 SECTION( LABEL_STATEVEC ) { TEST_ON_CACHED_QUREGS(getCachedStatevecs(), initZeroState, refVec); }
95 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), initZeroState, refMat); }
96 }
97
98 /// @todo input validation
99}
100
101
102TEST_CASE( "initPlusState", TEST_CATEGORY ) {
103
104 SECTION( LABEL_CORRECTNESS ) {
105
106 int numQubits = getNumCachedQubits();
107 qreal vecElem = 1. / std::sqrt(getPow2(numQubits));
108 qreal matElem = 1. / getPow2(numQubits);
109
110 qvector refVec = getConstantVector(getPow2(numQubits), vecElem); // |+> = 1/sqrt(2^N) {1, ...}
111 qmatrix refMat = getConstantMatrix(getPow2(numQubits), matElem); // |+><+| = 1/2^N {{1, ...}, ...}
112
113 SECTION( LABEL_STATEVEC ) { TEST_ON_CACHED_QUREGS(getCachedStatevecs(), initPlusState, refVec); }
114 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), initPlusState, refMat); }
115 }
116
117 /// @todo input validation
118}
119
120
121TEST_CASE( "initClassicalState", TEST_CATEGORY ) {
122
123 SECTION( LABEL_CORRECTNESS ) {
124
125 int numQubits = getNumCachedQubits();
126 int numInds = (int) getPow2(numQubits);
127 int stateInd = GENERATE_COPY( range(0,numInds) );
128
129 qvector refVec = getRefStatevec(); refVec[stateInd] = 1; // |i> = {0, ..., 1, 0, ...}
130 qmatrix refMat = getRefDensmatr(); refMat[stateInd][stateInd] = 1; // |i><i|
131
132 auto apiFunc = [&](Qureg qureg) { initClassicalState(qureg, stateInd); };
133
134 SECTION( LABEL_STATEVEC ) { TEST_ON_CACHED_QUREGS(getCachedStatevecs(), apiFunc, refVec); }
135 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), apiFunc, refMat); }
136 }
137
138 /// @todo input validation
139}
140
141
142TEST_CASE( "initDebugState", TEST_CATEGORY ) {
143
144 SECTION( LABEL_CORRECTNESS ) {
145
146 qvector refVec = getRefStatevec(); setToDebugState(refVec); // |debug>
147 qmatrix refMat = getRefDensmatr(); setToDebugState(refMat); // ||debug>>
148
149 SECTION( LABEL_STATEVEC ) { TEST_ON_CACHED_QUREGS(getCachedStatevecs(), initDebugState, refVec); }
150 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), initDebugState, refMat); }
151 }
152
153 /// @todo input validation
154}
155
156
157TEST_CASE( "initRandomPureState", TEST_CATEGORY ) {
158
159 SECTION( LABEL_CORRECTNESS ) {
160
161 // this test does not use reference states
162 GENERATE( range(0,10) );
163
164 auto testFunc = [&](Qureg qureg) {
165
166 initRandomPureState(qureg);
167
168 /// @todo
169 /// these not-all-same-amp checks can be made much more rigorous,
170 /// by e.g. asserting distinct nodes haven't generated all the same
171 /// amplitudes (we currently observe this by eye)
172 syncQuregFromGpu(qureg);
173 REQUIRE( qureg.cpuAmps[0] != qureg.cpuAmps[1] );
174
175 qreal prob = calcTotalProb(qureg);
176 REQUIRE_AGREE( prob, 1 );
177
178 qreal purity = calcPurity(qureg);
179 REQUIRE_AGREE( purity, 1 );
180 };
181
182 SECTION( LABEL_STATEVEC ) { TEST_ON_CACHED_QUREGS(getCachedStatevecs(), testFunc); }
183 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), testFunc); }
184 }
185
186 /// @todo input validation
187}
188
189
190TEST_CASE( "initRandomMixedState", TEST_CATEGORY ) {
191
192 SECTION( LABEL_CORRECTNESS ) {
193
194 // this test does not use reference states
195
196 GENERATE( range(0,10) );
197 int numPureStates = GENERATE( 1, 2, 10 );
198
199 auto testFunc = [&](Qureg qureg) {
200
201 initRandomMixedState(qureg, numPureStates);
202
203 /// @todo
204 /// these not-all-same-amp checks can be made much more rigorous,
205 /// by e.g. asserting distinct nodes haven't generated all the same
206 /// amplitudes (we currently observe this by eye)
207 syncQuregFromGpu(qureg);
208 REQUIRE( qureg.cpuAmps[0] != qureg.cpuAmps[1] ); // performed on all nodes
209
210 qreal prob = calcTotalProb(qureg);
211 REQUIRE_AGREE( prob, 1 );
212
213 qreal purity = calcPurity(qureg);
214 if (numPureStates == 1)
215 REQUIRE_AGREE( purity, 1 );
216 else
217 REQUIRE( purity < 1 );
218 };
219
220 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), testFunc); }
221 }
222
223 /// @todo input validation
224}
225
226
227TEST_CASE( "initArbitraryPureState", TEST_CATEGORY ) {
228
229 SECTION( LABEL_CORRECTNESS ) {
230
231 // works for unnormalised states
232 qvector refVec = getRandomVector(getPow2(getNumCachedQubits()));
233 qmatrix refMat = getOuterProduct(refVec, refVec);
234
235 auto apiFunc = [&](Qureg qureg) { initArbitraryPureState(qureg, refVec.data()); };
236
237 SECTION( LABEL_STATEVEC ) { TEST_ON_CACHED_QUREGS(getCachedStatevecs(), apiFunc, refVec); }
238 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), apiFunc, refMat); }
239 }
240
241 /// @todo input validation
242}
243
244
245
246
247TEST_CASE( "setQuregAmps", TEST_CATEGORY ) {
248
249 SECTION( LABEL_CORRECTNESS ) {
250
251 int numTotalAmps = getPow2(getNumCachedQubits());
252 int numSetAmps = GENERATE_COPY( range(0,numTotalAmps+1) );
253 int startInd = GENERATE_COPY( range(0,numTotalAmps-numSetAmps) );
254 qvector amps = getRandomVector(numSetAmps);
255
256 auto testFunc = [&](Qureg qureg) {
257
258 // initialise qureg randomly
259 qvector refVec = getRandomVector(numTotalAmps);
260 setQuregToReference(qureg, refVec);
261
262 // modify only subset of refVec amps and qureg...
263 setSubVector(refVec, amps, startInd);
264 setQuregAmps(qureg, startInd, amps.data(), numSetAmps);
265
266 // so that we simultaneously check targeted amps
267 // are modified while non-targeted are not
268 REQUIRE_AGREE( qureg, refVec );
269 };
270
271 SECTION( LABEL_STATEVEC ) { TEST_ON_CACHED_QUREGS(getCachedStatevecs(), testFunc); }
272 }
273
274 /// @todo input validation
275}
276
277
278TEST_CASE( "setDensityQuregFlatAmps", TEST_CATEGORY ) {
279
280 SECTION( LABEL_CORRECTNESS ) {
281
282 int numTotalRows = getPow2(getNumCachedQubits());
283 int numTotalAmps = numTotalRows * numTotalRows;
284
285 // systematic iteration is WAY too slow
286 GENERATE( range(0,1000) );
287 int numSetAmps = getRandomInt(0, numTotalAmps + 1);
288 int startInd = getRandomInt(0, numTotalAmps - numSetAmps);
289 qvector amps = getRandomVector(numSetAmps);
290
291 auto testFunc = [&](Qureg qureg) {
292
293 // initialise qureg randomly
294 qmatrix refMat = getRandomMatrix(numTotalRows);
295 setQuregToReference(qureg, refMat);
296
297 // overwrite a contiguous region of row-major refMat, column-wise
298 refMat = getTranspose(refMat);
299 setSubMatrix(refMat, amps, startInd);
300 refMat = getTranspose(refMat);
301
302 // modify the same contiguous region of column-major qureg
303 setDensityQuregFlatAmps(qureg, startInd, amps.data(), numSetAmps);
304
305 // check that both targeted and non-targeted amps agree
306 REQUIRE_AGREE( qureg, refMat );
307 };
308
309 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), testFunc); }
310 }
311
312 /// @todo input validation
313}
314
315
316TEST_CASE( "setDensityQuregAmps", TEST_CATEGORY ) {
317
318 //void setDensityQuregAmps(Qureg qureg, qindex startRow, qindex startCol, qcomp** amps, qindex numRows, qindex numCols);
319
320
321 SECTION( LABEL_CORRECTNESS ) {
322
323 int numTotalRowsCols = getPow2(getNumCachedQubits());
324
325 // systematic iteration is WAY too slow
326 GENERATE( range(0,1000) );
327 int numSetRows = getRandomInt(1, numTotalRowsCols+1);
328 int numSetCols = getRandomInt(1, numTotalRowsCols+1);
329 int startRow = getRandomInt(0, numTotalRowsCols - numSetRows);
330 int startCol = getRandomInt(0, numTotalRowsCols - numSetCols);
331
332 // caution that amps is 'qmatrix' despite not being square
333 qmatrix amps = getRandomNonSquareMatrix(numSetRows, numSetCols);
334
335 auto testFunc = [&](Qureg qureg) {
336
337 // initialise qureg randomly
338 qmatrix refMat = getRandomMatrix(numTotalRowsCols);
339 setQuregToReference(qureg, refMat);
340
341 // API needs nested pointers
342 std::vector<qcomp*> rowPtrs(numSetRows);
343 for (size_t r=0; r<numSetRows; r++)
344 rowPtrs[r] = amps[r].data();
345
346 // overwrite a sub-matrix of refMat and Qureg
347 setSubMatrix(refMat, amps, startRow, startCol);
348 setDensityQuregAmps(qureg, startRow, startCol, rowPtrs.data(), numSetRows, numSetCols);
349
350 // check that both targeted and non-targeted amps agree
351 REQUIRE_AGREE( qureg, refMat );
352 };
353
354 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), testFunc); }
355
356 }
357
358 /// @todo input validation
359}
360
361
362TEST_CASE( "setQuregToRenormalized", TEST_CATEGORY ) {
363
364 SECTION( LABEL_CORRECTNESS ) {
365
366 GENERATE( range(0,10) );
367 qindex dim = getPow2(getNumCachedQubits());
368 qvector refVec = getRandomVector(dim);
369 qmatrix refMat = getRandomMatrix(dim);
370
371 // eliminate random chance of tr(refMat)=0, triggering validation
372 if (doScalarsAgree(getTrace(refMat), 0))
373 refMat[0][0] += 1/(qreal) dim;
374
375 // [=] stores current (pre-normalised) reference objects
376 auto funcVec = [=](Qureg qureg) { setQuregToReference(qureg, refVec); setQuregToRenormalized(qureg); };
377 auto funcMat = [=](Qureg qureg) { setQuregToReference(qureg, refMat); setQuregToRenormalized(qureg); };
378
379 // setQuregToRenormalized() makes statevectors become valid
380 refVec = getNormalised(refVec);
381
382 // but it only divides density matrices by the sum of the real-elems of their diagonals
383 refMat /= getReferenceProbability(refMat);
384
385 SECTION( LABEL_STATEVEC ) { TEST_ON_CACHED_QUREGS(getCachedStatevecs(), funcVec, refVec); }
386 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), funcMat, refMat); }
387 }
388
389 /// @todo input validation
390}
391
392
393TEST_CASE( "setQuregToPauliStrSum", TEST_CATEGORY ) {
394
395 SECTION( LABEL_CORRECTNESS ) {
396
397 GENERATE( range(0,10) );
398 int numQubits = getNumCachedQubits();
399 int numTerms = GENERATE_COPY( 1, numQubits, getPow2(2*numQubits) );
400 PauliStrSum sum = createRandomPauliStrSum(numQubits, numTerms);
401 qmatrix refMat = getMatrix(sum, numQubits);
402
403 auto apiFunc = [&](Qureg qureg) { setQuregToPauliStrSum(qureg, sum); };
404
405 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(getCachedDensmatrs(), apiFunc, refMat); }
406 }
407
408 /// @todo input validation
409}
410
411
412/** @} (end defgroup) */
413
414
415
416/**
417 * @todo
418 * UNTESTED FUNCTIONS
419 */
420
421// these require we deploy the Quregs differently
422// to thoroughly test all QuEST control flows
423
424void initPureState(Qureg qureg, Qureg pure);
425
426void setQuregToClone(Qureg targetQureg, Qureg copyQureg);
427
428void setQuregToSuperposition(qcomp facOut, Qureg out, qcomp fac1, Qureg qureg1, qcomp fac2, Qureg qureg2);
429
430void setQuregToPartialTrace(Qureg out, Qureg in, int* traceOutQubits, int numTraceQubits);
431
432void setQuregToReducedDensityMatrix(Qureg out, Qureg in, int* retainQubits, int numRetainQubits);
qreal calcPurity(Qureg qureg)
qreal calcTotalProb(Qureg qureg)
void setDensityQuregFlatAmps(Qureg qureg, qindex startInd, qcomp *amps, qindex numAmps)
void setQuregToReducedDensityMatrix(Qureg out, Qureg in, int *retainQubits, int numRetainQubits)
void setQuregToPauliStrSum(Qureg qureg, PauliStrSum sum)
void setQuregAmps(Qureg qureg, qindex startInd, qcomp *amps, qindex numAmps)
void setQuregToPartialTrace(Qureg out, Qureg in, int *traceOutQubits, int numTraceQubits)
qreal setQuregToRenormalized(Qureg qureg)
void setQuregToClone(Qureg targetQureg, Qureg copyQureg)
void setDensityQuregAmps(Qureg qureg, qindex startRow, qindex startCol, qcomp **amps, qindex numRows, qindex numCols)
void setQuregToSuperposition(qcomp facOut, Qureg out, qcomp fac1, Qureg qureg1, qcomp fac2, Qureg qureg2)
void initArbitraryPureState(Qureg qureg, qcomp *amps)
void initRandomPureState(Qureg qureg)
void initPlusState(Qureg qureg)
void initZeroState(Qureg qureg)
void initPureState(Qureg qureg, Qureg pure)
void initDebugState(Qureg qureg)
void initRandomMixedState(Qureg qureg, qindex numPureStates)
void initClassicalState(Qureg qureg, qindex stateInd)
void initBlankState(Qureg qureg)
void syncQuregFromGpu(Qureg qureg)
Definition qureg.cpp:402
void setSubMatrix(qmatrix &dest, qmatrix sub, size_t r, size_t c)
Definition qmatrix.cpp:203
int getRandomInt(int min, int maxExcl)
Definition random.cpp:90
TEST_CASE("initBlankState", TEST_CATEGORY)
Definition qureg.h:49