The Quantum Exact Simulation Toolkit v4.1.0
Loading...
Searching...
No Matches
decoherence.cpp
1/** @file
2 * Unit tests of the decoherence module.
3 *
4 * @author Tyson Jones
5 *
6 * @defgroup unitdeco Decoherence
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/random.hpp"
26
27#include <vector>
28#include <algorithm>
29
30using Catch::Matchers::ContainsSubstring;
31using std::vector;
32
33
34
35/*
36 * UTILITIES
37 */
38
39
40#define TEST_CATEGORY "[unit][decoherence]"
41
42
43void TEST_ON_CACHED_QUREGS(auto apiFunc, vector<int> targs, vector<qmatrix> kraus) {
44
45 // all tests use a fixed-size density matrix
46 qmatrix reference = getRefDensmatr();
47
48 for (auto& [label, qureg]: getCachedDensmatrs()) {
49
50 DYNAMIC_SECTION( label ) {
51
52 // no need to validate whether qureg successfully
53 // enters the debug state here, because the below
54 // serial setToDebugState() is guaranteed to succeed
55 initDebugState(qureg);
56 setToDebugState(reference);
57
58 apiFunc(qureg);
59 applyReferenceOperator(reference, targs, kraus);
60
61 REQUIRE_AGREE( qureg, reference );
62 }
63 }
64}
65
66
67void TEST_ON_MIXED_CACHED_QUREGS(auto altQuregCache, auto apiFunc, auto refAlt, auto refFunc) {
68
69 // test all combinations of deployments (where cacheA != cacheB)
70
71 for (auto& [labelA, quregOut]: getCachedDensmatrs()) {
72 for (auto& [labelB, quregAlt]: altQuregCache) {
73
74 // skip illegal (local densitymatrix, distributed statevector) combo
75 if (!quregOut.isDistributed && quregAlt.isDistributed && !quregAlt.isDensityMatrix)
76 continue;
77
78 // skip illegal (local densitymatrix, distributed densitymatrix) combo
79 if (quregAlt.isDensityMatrix && quregOut.isDistributed != quregAlt.isDistributed)
80 continue;
81
82 DYNAMIC_SECTION( labelA + LABEL_DELIMITER + labelB ) {
83
84 // randomise the output density matrix (both qureg and reference)
85 qmatrix refOut = getRandomDensityMatrix(getNumCachedQubits());
86 setQuregToReference(quregOut, refOut);
87
88 // randomise the alternate state (may be statevector or density matrix)
89 setToRandomState(refAlt);
90 setQuregToReference(quregAlt, refAlt);
91
92 apiFunc(quregOut, quregAlt);
93 refFunc(refOut, refAlt);
94 REQUIRE_AGREE( quregOut, refOut );
95 }
96 }
97 }
98}
99
100
101
102/**
103 * TESTS
104 *
105 * @ingroup unitdeco
106 * @{
107 */
108
109
110TEST_CASE( "mixDephasing", TEST_CATEGORY ) {
111
112 SECTION( LABEL_CORRECTNESS ) {
113
114 int numQubits = getNumCachedQubits();
115 int targ = GENERATE_COPY( range(0,numQubits) );
116 qreal prob = getRandomReal(0, 1/2.);
117
118 vector<qmatrix> kraus = {
119 std::sqrt(1-prob) * getPauliMatrix(0),
120 std::sqrt(prob) * getPauliMatrix(3)
121 };
122
123 auto apiFunc = [&](Qureg qureg) { mixDephasing(qureg, targ, prob); };
124
125 CAPTURE( targ, prob );
126 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(apiFunc, {targ}, kraus); }
127 }
128
129 /// @todo input validation
130}
131
132
133TEST_CASE( "mixDepolarising", TEST_CATEGORY ) {
134
135 SECTION( LABEL_CORRECTNESS ) {
136
137 int numQubits = getNumCachedQubits();
138 int targ = GENERATE_COPY( range(0,numQubits) );
139 qreal prob = getRandomReal(0, 3/4.);
140
141 vector<qmatrix> kraus = {
142 std::sqrt(1-prob) * getPauliMatrix(0),
143 std::sqrt(prob/3) * getPauliMatrix(1),
144 std::sqrt(prob/3) * getPauliMatrix(2),
145 std::sqrt(prob/3) * getPauliMatrix(3),
146 };
147
148 auto apiFunc = [&](Qureg qureg) { mixDepolarising(qureg, targ, prob); };
149
150 CAPTURE( targ, prob );
151 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(apiFunc, {targ}, kraus); }
152 }
153
154 /// @todo input validation
155}
156
157
158TEST_CASE( "mixDamping", TEST_CATEGORY ) {
159
160 SECTION( LABEL_CORRECTNESS ) {
161
162 int numQubits = getNumCachedQubits();
163 int targ = GENERATE_COPY( range(0,numQubits) );
164 qreal prob = getRandomReal(0, 1);
165
166 vector<qmatrix> kraus = {
167 {{1,0},{0,std::sqrt(1-prob)}},
168 {{0,std::sqrt(prob)}, {0,0}}
169 };
170
171 auto apiFunc = [&](Qureg qureg) { mixDamping(qureg, targ, prob); };
172
173 CAPTURE( targ, prob );
174 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(apiFunc, {targ}, kraus); }
175 }
176
177 /// @todo input validation
178}
179
180
181TEST_CASE( "mixPaulis", TEST_CATEGORY ) {
182
183 SECTION( LABEL_CORRECTNESS ) {
184
185 int numQubits = getNumCachedQubits();
186 int targ = GENERATE_COPY( range(0,numQubits) );
187
188 qreal pX = getRandomReal(0, 1);
189 qreal pY = getRandomReal(0, 1);
190 qreal pZ = getRandomReal(0, 1);
191
192 // we require pX+pY+pZ <= 1
193 qreal norm = pX + pY + pZ;
194 pX /= norm;
195 pY /= norm;
196 pZ /= norm;
197
198 // and max(pX,pY,pZ) <= 1-pX-pY-pZ, which we'll
199 // lazily achieve with iteration (truly stinky)
200 qreal pI = 1 - pX - pY - pZ;
201 while (std::max({pX,pY,pZ}) > pI) {
202 pX /= 1.1;
203 pY /= 1.1;
204 pZ /= 1.1;
205 pI = 1 - pX - pY - pZ;
206 }
207
208 vector<qmatrix> kraus = {
209 std::sqrt(pI) * getPauliMatrix(0),
210 std::sqrt(pX) * getPauliMatrix(1),
211 std::sqrt(pY) * getPauliMatrix(2),
212 std::sqrt(pZ) * getPauliMatrix(3)
213 };
214
215 auto apiFunc = [&](Qureg qureg) { mixPaulis(qureg, targ, pX, pY, pZ); };
216
217 CAPTURE( targ, pX, pY, pZ );
218 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(apiFunc, {targ}, kraus); }
219 }
220
221 /// @todo input validation
222}
223
224
225TEST_CASE( "mixTwoQubitDephasing", TEST_CATEGORY ) {
226
227 SECTION( LABEL_CORRECTNESS ) {
228
229 auto targs = GENERATE_TARGS( getNumCachedQubits(), 2 );
230 qreal prob = getRandomReal(0, 3/4.);
231
232 qmatrix i = getPauliMatrix(0);
233 qmatrix z = getPauliMatrix(3);
234
235 vector<qmatrix> kraus = {
236 std::sqrt(1-prob) * getKroneckerProduct(i, i),
237 std::sqrt(prob/3) * getKroneckerProduct(i, z),
238 std::sqrt(prob/3) * getKroneckerProduct(z, i),
239 std::sqrt(prob/3) * getKroneckerProduct(z, z)
240 };
241
242 auto apiFunc = [&](Qureg qureg) { mixTwoQubitDephasing(qureg, targs[0], targs[1], prob); };
243
244 CAPTURE( targs, prob );
245 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(apiFunc, targs, kraus); }
246 }
247
248 /// @todo input validation
249}
250
251
252TEST_CASE( "mixTwoQubitDepolarising", TEST_CATEGORY ) {
253
254 SECTION( LABEL_CORRECTNESS ) {
255
256 auto targs = GENERATE_TARGS( getNumCachedQubits(), 2 );
257 qreal prob = getRandomReal(0, 15/16.);
258
259 vector<qmatrix> kraus = { std::sqrt(1-16*prob/15) * getIdentityMatrix(4) };
260 for (int a=0; a<4; a++)
261 for (int b=0; b<4; b++)
262 kraus.push_back( std::sqrt(prob/15) *
263 getKroneckerProduct(getPauliMatrix(a), getPauliMatrix(b)));
264
265 auto apiFunc = [&](Qureg qureg) { mixTwoQubitDepolarising(qureg, targs[0], targs[1], prob); };
266
267 CAPTURE( targs, prob );
268 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(apiFunc, targs, kraus); }
269 }
270
271 /// @todo input validation
272}
273
274
275TEST_CASE( "mixKrausMap", TEST_CATEGORY ) {
276
277 SECTION( LABEL_CORRECTNESS ) {
278
279 int maxFlag = TEST_MAX_NUM_SUPEROP_TARGETS;
280 int numQubits = getNumCachedQubits();
281 int maxNumTargs = (maxFlag != 0 && numQubits > maxFlag)?
282 maxFlag : numQubits;
283
284 int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
285 int numKraus = GENERATE( 1, 2, 10 );
286 auto targs = GENERATE_TARGS( numQubits, numTargs );
287 auto matrices = getRandomKrausMap(numTargs, numKraus);
288
289 KrausMap map = createKrausMap(numTargs, numKraus);
290 setKrausMap(map, matrices);
291 auto apiFunc = [&](Qureg qureg) { mixKrausMap(qureg, targs.data(), numTargs, map); };
292
293 CAPTURE( maxNumTargs, targs, numKraus );
294 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(apiFunc, targs, matrices); }
295
296 destroyKrausMap(map);
297 }
298
299 /// @todo input validation
300}
301
302
303TEST_CASE( "mixSuperOp", TEST_CATEGORY ) {
304
305 SECTION( LABEL_CORRECTNESS ) {
306
307 int numQubits = getNumCachedQubits();
308 int maxFlag = TEST_MAX_NUM_SUPEROP_TARGETS;
309 int maxNumTargs = (maxFlag != 0 && numQubits > maxFlag)?
310 maxFlag : numQubits;
311
312 int numTargs = GENERATE_COPY( range(1,maxNumTargs+1) );
313 auto targs = GENERATE_TARGS( numQubits, numTargs );
314 auto matrices = getRandomKrausMap(numTargs, getRandomInt(1,4+1));
315
316 SuperOp superOp = createSuperOp(numTargs);
317 setSuperOp(superOp, getSuperOperator(matrices));
318 auto apiFunc = [&](Qureg qureg) { mixSuperOp(qureg, targs.data(), numTargs, superOp); };
319
320 CAPTURE( targs );
321 SECTION( LABEL_DENSMATR ) { TEST_ON_CACHED_QUREGS(apiFunc, targs, matrices); }
322
323 destroySuperOp(superOp);
324 }
325
326 /// @todo input validation
327}
328
329
330TEST_CASE( "mixQureg", TEST_CATEGORY LABEL_MIXED_DEPLOY_TAG ) {
331
332 SECTION( LABEL_CORRECTNESS ) {
333
334 qreal prob = getRandomReal(0, 1);
335 auto apiFunc = [&](Qureg a, Qureg b) { mixQureg(a, b, prob); };
336
337 CAPTURE( prob );
338
339 GENERATE( range(0, TEST_NUM_MIXED_DEPLOYMENT_REPETITIONS) );
340
341 SECTION( LABEL_DENSMATR LABEL_DELIMITER LABEL_STATEVEC ) {
342
343 auto refFunc = [&](qmatrix& a, qvector b) { a = (1-prob)*a + prob*getOuterProduct(b,b); };
344
345 TEST_ON_MIXED_CACHED_QUREGS( getAltCachedStatevecs(), apiFunc, getRefStatevec(), refFunc);
346 }
347
348 SECTION( LABEL_DENSMATR LABEL_DELIMITER LABEL_DENSMATR ) {
349
350 auto refFunc = [&](qmatrix& a, qmatrix b) { a = (1-prob)*a + prob*b; };
351
352 TEST_ON_MIXED_CACHED_QUREGS( getAltCachedDensmatrs(), apiFunc, getRefDensmatr(), refFunc);
353 }
354 }
355
356 /// @todo input validation
357}
358
359
360/** @} (end defgroup) */
KrausMap createKrausMap(int numQubits, int numOperators)
Definition channels.cpp:176
SuperOp createSuperOp(int numQubits)
Definition channels.cpp:162
void destroySuperOp(SuperOp op)
Definition channels.cpp:203
void destroyKrausMap(KrausMap map)
Definition channels.cpp:210
void setSuperOp(SuperOp op, qcomp **matrix)
Definition channels.cpp:271
void setKrausMap(KrausMap map, qcomp ***matrices)
Definition channels.cpp:309
void mixQureg(Qureg qureg, Qureg other, qreal prob)
void mixPaulis(Qureg qureg, int target, qreal probX, qreal probY, qreal probZ)
void mixKrausMap(Qureg qureg, int *targets, int numTargets, KrausMap map)
void mixSuperOp(Qureg qureg, int *targets, int numTargets, SuperOp superop)
void mixTwoQubitDephasing(Qureg qureg, int target1, int target2, qreal prob)
void mixTwoQubitDepolarising(Qureg qureg, int target1, int target2, qreal prob)
void mixDamping(Qureg qureg, int target, qreal prob)
void mixDephasing(Qureg qureg, int target, qreal prob)
void mixDepolarising(Qureg qureg, int target, qreal prob)
void initDebugState(Qureg qureg)
qmatrix getKroneckerProduct(qmatrix a, qmatrix b)
Definition linalg.cpp:523
const int TEST_MAX_NUM_SUPEROP_TARGETS
Definition macros.hpp:57
const int TEST_NUM_MIXED_DEPLOYMENT_REPETITIONS
Definition macros.hpp:63
qmatrix getIdentityMatrix(size_t dim)
Definition qmatrix.cpp:30
qreal getRandomReal(qreal min, qreal maxExcl)
Definition random.cpp:63
qmatrix getRandomDensityMatrix(int numQb)
Definition random.cpp:308
vector< qmatrix > getRandomKrausMap(int numQb, int numOps)
Definition random.cpp:405
int getRandomInt(int min, int maxExcl)
Definition random.cpp:90
TEST_CASE("mixDephasing", TEST_CATEGORY)
Definition qureg.h:49