The Quantum Exact Simulation Toolkit v4.3.0
Loading...
Searching...
No Matches
compare.cpp
1/** @file
2 * Testing utilities which compare scalars produced by the
3 * QuEST API to those produced by other test utilities, and
4 * Quregs modified by the API to qvector qmatrix references.
5 *
6 * @author Tyson Jones
7 */
8
9#include "qvector.hpp"
10#include "qmatrix.hpp"
11#include "convert.hpp"
12#include "linalg.hpp"
13#include "macros.hpp"
14
15#include "quest.h"
16
17#include <catch2/catch_test_macros.hpp>
18#include <catch2/matchers/catch_matchers_floating_point.hpp>
19
20#include <complex>
21#include <vector>
22#include <algorithm>
23
24using std::abs;
25using std::vector;
26using namespace Catch::Matchers;
27
28
29
30/*
31 * Maximum tolerated difference between API and reference
32 * scalar in order to be considered equivalent.
33 */
34
35
36#if QUEST_FLOAT_PRECISION == 1
37 qreal absoluteEpsilon = 1E-2; // default...
38 qreal relativeEpsilon = 1E-2;
39#elif QUEST_FLOAT_PRECISION == 2
40 qreal absoluteEpsilon = 1E-8;
41 qreal relativeEpsilon = 1E-8;
42#elif QUEST_FLOAT_PRECISION == 4
43 qreal absoluteEpsilon = 1E-10;
44 qreal relativeEpsilon = 1E-10;
45#endif
46
47
48qreal getTestAbsoluteEpsilon() {
49
50 return absoluteEpsilon;
51}
52
53qreal getTestRelativeEpsilon() {
54
55 return relativeEpsilon;
56}
57
58
59void setTestAbsoluteEpsilon(qreal eps) {
60 absoluteEpsilon = eps;
61}
62
63void setTestRelativeEpsilon(qreal eps) {
64 relativeEpsilon = eps;
65}
66
67void setTestEpsilon(qreal eps) {
68 setTestAbsoluteEpsilon(eps);
69 setTestRelativeEpsilon(eps);
70}
71
72
73qreal getAbsDif(qcomp a, qcomp b) {
74
75 return std::abs(a - b);
76}
77
78qreal getRelDif(qcomp a, qcomp b) {
79
80 qreal denom = std::min({std::abs(a), std::abs(b)});
81 return getAbsDif(a,b) / denom;
82}
83
84
85bool doScalarsAgree(qcomp a, qcomp b) {
86
87 // permit absolute OR relative agreement
88
89 if (getAbsDif(a, b) <= absoluteEpsilon)
90 return true;
91
92 return (getRelDif(a, b) <= relativeEpsilon);
93}
94
95bool doMatricesAgree(qmatrix a, qmatrix b) {
96 DEMAND( a.size() == b.size() );
97
98 // assumed square and equal-size
99 size_t dim = a.size();
100
101 for (size_t i=0; i<dim; i++)
102 for (size_t j=0; j<dim; j++)
103 if (!doScalarsAgree(a[i][j], b[i][j]))
104 return false;
105
106 return true;
107}
108
109
110
111/*
112 * We compare a Qureg and its reference qvector/qmatrix
113 * in a manner which avoids polluting the Catch2 console
114 * output, and which reports a single disgreeing amplitude
115 * when the comparison fails.
116 */
117
118
119void REPORT_AMP_AND_FAIL( size_t index, qcomp amplitude, qcomp reference ) {
120 qreal absolute_difference = getAbsDif(amplitude, reference);
121 qreal relative_difference = getRelDif(amplitude, reference);
122 CAPTURE(
123 index, amplitude, reference,
124 absolute_difference, absoluteEpsilon,
125 relative_difference, relativeEpsilon
126 );
127 FAIL( );
128}
129
130
131void REQUIRE_AGREE( Qureg q, qvector v1 ) {
132 DEMAND( !q.isDensityMatrix );
133 DEMAND( q.numAmps == (qindex) v1.size() );
134
135 qvector v2 = getVector(q);
136
137 for (size_t i=0; i<v1.size(); i++)
138 if (!doScalarsAgree(v1[i], v2[i]))
139 REPORT_AMP_AND_FAIL(i, v2[i], v1[i]);
140
141 SUCCEED( );
142}
143
144
145void REQUIRE_AGREE( Qureg q, qmatrix m1 ) {
146 DEMAND( q.isDensityMatrix );
147 DEMAND( getPow2(q.numQubits) == (qindex) m1.size() );
148
149 qmatrix m2 = getMatrix(q);
150
151 for (size_t i=0; i<m1.size(); i++)
152 for (size_t j=0; j<m1.size(); j++)
153 if (!doScalarsAgree(m1[i][j], m2[i][j]))
154 REPORT_AMP_AND_FAIL(j*m1.size()+i, m2[i][j], m1[i][j]);
155
156 SUCCEED( );
157}
158
159
160
161/*
162 * REAL AND COMPLEX SCALARS
163 */
164
165
166void REPORT_SCALAR_AND_FAIL( qcomp scalar, qcomp reference ) {
167 qreal absolute_difference = getAbsDif(scalar, reference);
168 qreal relative_difference = getRelDif(scalar, reference);
169 CAPTURE(
170 scalar, reference,
171 absolute_difference, absoluteEpsilon,
172 relative_difference, relativeEpsilon
173 );
174 FAIL( );
175}
176
177void REPORT_SCALAR_AND_FAIL( qreal scalar, qreal reference ) {
178
179 // like above but does not display redundant imag-components
180 qreal absolute_difference = getAbsDif(qcomp(scalar,0), qcomp(reference,0));
181 qreal relative_difference = getRelDif(qcomp(scalar,0), qcomp(reference,0));
182 CAPTURE(
183 scalar, reference,
184 absolute_difference, absoluteEpsilon,
185 relative_difference, relativeEpsilon
186 );
187 FAIL( );
188}
189
190
191void REQUIRE_AGREE( qcomp scalar, qcomp reference ) {
192
193 if (!doScalarsAgree(scalar, reference))
194 REPORT_SCALAR_AND_FAIL(scalar, reference);
195
196 SUCCEED( );
197}
198
199void REQUIRE_AGREE( qreal scalar, qreal reference ) {
200
201 if (!doScalarsAgree(qcomp(scalar,0), qcomp(reference,0)))
202 REPORT_SCALAR_AND_FAIL(scalar, reference);
203
204 SUCCEED( );
205}
206
207
208
209/*
210 * LISTS
211 */
212
213
214void REQUIRE_AGREE( vector<qreal> apiList, vector<qreal> refList ) {
215 DEMAND( apiList.size() == refList.size() );
216
217 for (size_t i=0; i<apiList.size(); i++)
218 if (!doScalarsAgree(apiList[i], refList[i]))
219 REPORT_SCALAR_AND_FAIL(apiList[i], refList[i]);
220
221 SUCCEED( );
222}
223
224
225void REQUIRE_AGREE( vector<qcomp> apiList, vector<qcomp> refList ) {
226 DEMAND( apiList.size() == refList.size() );
227
228 for (size_t i=0; i<apiList.size(); i++)
229 if (!doScalarsAgree(apiList[i], refList[i]))
230 REPORT_SCALAR_AND_FAIL(apiList[i], refList[i]);
231
232 SUCCEED( );
233}
234
235
236
237/*
238 * MATRICES
239 */
240
241
242void REPORT_ELEM_AND_FAIL( size_t row, size_t col, qcomp elem, qcomp reference ) {
243 qreal absolute_difference = getAbsDif(elem, reference);
244 qreal relative_difference = getRelDif(elem, reference);
245 CAPTURE(
246 row, col, elem, reference,
247 absolute_difference, absoluteEpsilon,
248 relative_difference, relativeEpsilon
249 );
250 FAIL( );
251}
252
253
254void REQUIRE_AGREE( qmatrix matrix, qmatrix reference ) {
255 DEMAND( matrix.size() == reference.size() );
256
257 size_t dim = matrix.size();
258
259 for (size_t r=0; r<dim; r++)
260 for (size_t c=0; c<dim; c++)
261 if (!doScalarsAgree(matrix[r][c], reference[r][c]))
262 REPORT_ELEM_AND_FAIL(r, c, matrix[r][c], reference[r][c]);
263
264 SUCCEED( );
265}
266
267
268void REQUIRE_AGREE( CompMatr1 matrix, qmatrix reference ) { REQUIRE_AGREE( getMatrix(matrix), reference ); }
269void REQUIRE_AGREE( CompMatr2 matrix, qmatrix reference ) { REQUIRE_AGREE( getMatrix(matrix), reference ); }
270void REQUIRE_AGREE( CompMatr matrix, qmatrix reference ) { REQUIRE_AGREE( getMatrix(matrix), reference ); }
271void REQUIRE_AGREE( DiagMatr1 matrix, qmatrix reference ) { REQUIRE_AGREE( getMatrix(matrix), reference ); }
272void REQUIRE_AGREE( DiagMatr2 matrix, qmatrix reference ) { REQUIRE_AGREE( getMatrix(matrix), reference ); }
273void REQUIRE_AGREE( DiagMatr matrix, qmatrix reference ) { REQUIRE_AGREE( getMatrix(matrix), reference ); }
274void REQUIRE_AGREE( SuperOp matrix, qmatrix reference ) { REQUIRE_AGREE( getMatrix(matrix), reference ); }
275
276
277
278/*
279 * we lazily compare quregs by converting one into qvector
280 * or qmatrix, rather than an optimised direct comparison,
281 * so that we can compare the states of distinct deployments
282 */
283
284
285void REQUIRE_AGREE( Qureg qureg, Qureg other ) {
286 DEMAND( qureg.numQubits == other.numQubits );
287 DEMAND( qureg.isDensityMatrix == other.isDensityMatrix );
288
289 return (qureg.isDensityMatrix)?
290 REQUIRE_AGREE( qureg, getMatrix(other) ):
291 REQUIRE_AGREE( qureg, getVector(other) );
292}
Definition qureg.h:49