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