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