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