Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.

Commit 4e7f38d

Browse files
authored
Merge pull request #849 from thomashaener/feature/sparse-simulator
Update Sparse Simulator to use Catch2 for testing.
2 parents 5c02b2d + ef46fcb commit 4e7f38d

File tree

13 files changed

+1085
-1353
lines changed

13 files changed

+1085
-1353
lines changed

src/Simulation/Simulators/SparseSimulator/Native/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,12 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
2020
endif()
2121

2222
message("Compiler flags: ${CMAKE_CXX_FLAGS_RELEASE}")
23+
24+
include(CTest)
25+
enable_testing()
26+
27+
foreach(TEST SparseSimulatorTests CSharpIntegrationTests)
28+
add_executable(${TEST} ${TEST}.cpp TestHelpers.cpp)
29+
target_include_directories(${TEST} PRIVATE ../../../../Qir/Common/Externals/catch2)
30+
add_test(${TEST} ${TEST})
31+
endforeach()
Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
#define CATCH_CONFIG_MAIN
5+
#include <catch.hpp>
6+
7+
#include "SparseSimulator.h"
8+
#include "capi.hpp"
9+
#include "capi.cpp" // yes really
10+
#include "factory.hpp"
11+
#include "factory.cpp"
12+
#include "TestHelpers.hpp"
13+
14+
#include <cmath>
15+
#include <iostream>
16+
#include <cstdint>
17+
18+
using namespace Microsoft::Quantum::SPARSESIMULATOR;
19+
using namespace SparseSimulatorTestHelpers;
20+
21+
#ifndef M_PI
22+
#define M_PI 3.14159265358979323846
23+
#endif
24+
25+
26+
template<size_t num_qubits>
27+
void MultiExpReferenceTest(
28+
std::function<void(unsigned)> qubit_prep,
29+
std::function<void(unsigned)> qubit_clear
30+
) {
31+
const qubit_label_type<num_qubits> zero(0);
32+
logical_qubit_id* qubits = new logical_qubit_id[3];
33+
qubits[0] = 0;
34+
qubits[1] = 1;
35+
qubits[2] = 2;
36+
int* Paulis = new int[3];
37+
for (int intPaulis = 0; intPaulis < 4 * 4 * 4; intPaulis++) {
38+
Paulis[0] = intPaulis % 4;
39+
Paulis[1] = (intPaulis / 4 ) % 4;
40+
Paulis[2] = intPaulis / 16;
41+
42+
for (double angle = 0.0; angle < M_PI / 2.0; angle += 0.1) {
43+
unsigned sim = init_cpp(32);
44+
qubit_prep(sim);
45+
46+
std::vector<amplitude> vector_rep(8, 0.0);
47+
for (unsigned i = 0; i < 8; i++) {
48+
vector_rep[i] = getSimulator(sim)->probe(std::bitset<3>(i).to_string());
49+
}
50+
// New simulator Exp
51+
Exp_cpp(sim, 3, Paulis, angle, qubits);
52+
// Old simulator Exp
53+
std::vector<Gates::Basis> actualPaulis = { (Gates::Basis)Paulis[0],(Gates::Basis)Paulis[1], (Gates::Basis)Paulis[2] };
54+
apply_exp(vector_rep, actualPaulis, angle, std::vector<unsigned>{ 0, 1, 2 });
55+
for (unsigned i = 0; i < 8; i++) {
56+
amplitude result = getSimulator(sim)->probe(std::bitset<3>(i).to_string());
57+
assert_amplitude_equality(vector_rep[i], result);
58+
}
59+
Exp_cpp(sim, 3, Paulis, -angle, qubits);
60+
qubit_clear(sim);
61+
}
62+
}
63+
}
64+
65+
TEST_CASE("initializationTest") {
66+
unsigned sim = init_cpp(32);
67+
}
68+
69+
TEST_CASE("AllocationTest") {
70+
unsigned sim = init_cpp(32);
71+
allocateQubit_cpp(sim, 0);
72+
releaseQubit_cpp(sim, 0);
73+
}
74+
TEST_CASE("AllocateRebuildTest") {
75+
unsigned sim = init_cpp(64);
76+
for (int i = 0; i < 1024; i++) {
77+
allocateQubit_cpp(sim, i);
78+
getSimulator(sim)->X(i);
79+
getSimulator(sim)->update_state();
80+
}
81+
for (int i = 0; i < 1024; i++) {
82+
getSimulator(sim)->X(i);
83+
releaseQubit_cpp(sim, i);
84+
}
85+
}
86+
87+
TEST_CASE("XTest") {
88+
unsigned sim = init_cpp(32);
89+
allocateQubit_cpp(sim, 0);
90+
X_cpp(sim, 0);
91+
assert_amplitude_equality(getSimulator(sim)->probe("0"), 0.0, 0.0);
92+
assert_amplitude_equality(getSimulator(sim)->probe("1"), 1.0, 0.0);
93+
X_cpp(sim, 0);
94+
releaseQubit_cpp(sim, 0);
95+
}
96+
TEST_CASE("ZTest") {
97+
unsigned sim = init_cpp(32);
98+
allocateQubit_cpp(sim, 0);
99+
Z_cpp(sim, 0);
100+
assert_amplitude_equality(getSimulator(sim)->probe("0"), 1.0, 0.0);
101+
assert_amplitude_equality(getSimulator(sim)->probe("1"), 0.0, 0.0);
102+
Z_cpp(sim, 0);
103+
assert_amplitude_equality(getSimulator(sim)->probe("0"), 1.0, 0.0);
104+
assert_amplitude_equality(getSimulator(sim)->probe("1"), 0.0, 0.0);
105+
X_cpp(sim, 0);
106+
Z_cpp(sim, 0);
107+
assert_amplitude_equality(getSimulator(sim)->probe("0"), 0.0, 0.0);
108+
assert_amplitude_equality(getSimulator(sim)->probe("1"), -1.0, 0.0);
109+
Z_cpp(sim, 0);
110+
assert_amplitude_equality(getSimulator(sim)->probe("0"), 0.0, 0.0);
111+
assert_amplitude_equality(getSimulator(sim)->probe("1"), 1.0, 0.0);
112+
X_cpp(sim, 0);
113+
releaseQubit_cpp(sim, 0);
114+
}
115+
TEST_CASE("HTest") {
116+
unsigned sim = init_cpp(32);
117+
allocateQubit_cpp(sim, 0);
118+
H_cpp(sim, 0);
119+
assert_amplitude_equality(getSimulator(sim)->probe("0"), 1.0 / sqrt(2.0), 0.0);
120+
assert_amplitude_equality(getSimulator(sim)->probe("1"), 1.0 / sqrt(2.0), 0.0);
121+
H_cpp(sim, 0);
122+
assert_amplitude_equality(getSimulator(sim)->probe("0"), 1.0, 0.0);
123+
assert_amplitude_equality(getSimulator(sim)->probe("1"), 0.0, 0.0);
124+
X_cpp(sim, 0);
125+
H_cpp(sim, 0);
126+
assert_amplitude_equality(getSimulator(sim)->probe("0"), 1.0 / sqrt(2.0), 0.0);
127+
assert_amplitude_equality(getSimulator(sim)->probe("1"), -1.0 / sqrt(2.0), 0.0);
128+
H_cpp(sim, 0);
129+
assert_amplitude_equality(getSimulator(sim)->probe("0"), 0.0, 0.0);
130+
assert_amplitude_equality(getSimulator(sim)->probe("1"), 1.0, 0.0);
131+
X_cpp(sim, 0);
132+
releaseQubit_cpp(sim, 0);
133+
}
134+
135+
TEST_CASE("TGateTest") {
136+
unsigned sim = init_cpp(32);
137+
allocateQubit_cpp(sim, 0);
138+
T_cpp(sim, 0);
139+
assert_amplitude_equality(getSimulator(sim)->probe("0"), 1.0, 0.0);
140+
assert_amplitude_equality(getSimulator(sim)->probe("1"), 0.0, 0.0);
141+
X_cpp(sim, 0);
142+
T_cpp(sim, 0);
143+
assert_amplitude_equality(getSimulator(sim)->probe("0"), 0.0, 0.0);
144+
assert_amplitude_equality(getSimulator(sim)->probe("1"), 1.0 / sqrt(2.0), 1.0 / sqrt(2.0));
145+
T_cpp(sim, 0);
146+
assert_amplitude_equality(getSimulator(sim)->probe("0"), 0.0, 0.0);
147+
assert_amplitude_equality(getSimulator(sim)->probe("1"), 0.0, 1.0);
148+
T_cpp(sim, 0);
149+
assert_amplitude_equality(getSimulator(sim)->probe("0"), 0.0, 0.0);
150+
assert_amplitude_equality(getSimulator(sim)->probe("1"), -1.0 / sqrt(2.0), 1.0 / sqrt(2.0));
151+
T_cpp(sim, 0);
152+
assert_amplitude_equality(getSimulator(sim)->probe("0"), 0.0, 0.0);
153+
assert_amplitude_equality(getSimulator(sim)->probe("1"), -1.0, 0.0);
154+
T_cpp(sim, 0);
155+
assert_amplitude_equality(getSimulator(sim)->probe("0"), 0.0, 0.0);
156+
assert_amplitude_equality(getSimulator(sim)->probe("1"), -1.0 / sqrt(2.0), -1.0 / sqrt(2.0));
157+
T_cpp(sim, 0);
158+
assert_amplitude_equality(getSimulator(sim)->probe("0"), 0.0, 0.0);
159+
assert_amplitude_equality(getSimulator(sim)->probe("1"), 0.0, -1.0);
160+
T_cpp(sim, 0);
161+
assert_amplitude_equality(getSimulator(sim)->probe("0"), 0.0, 0.0);
162+
assert_amplitude_equality(getSimulator(sim)->probe("1"), 1.0 / sqrt(2.0), -1.0 / sqrt(2.0));
163+
T_cpp(sim, 0);
164+
assert_amplitude_equality(getSimulator(sim)->probe("0"), 0.0, 0.0);
165+
assert_amplitude_equality(getSimulator(sim)->probe("1"), 1.0, 0.0);
166+
X_cpp(sim, 0);
167+
releaseQubit_cpp(sim, 0);
168+
}
169+
170+
TEST_CASE("HCancellationTest")
171+
{
172+
int n_qubits = 16;
173+
unsigned sim = init_cpp(n_qubits);
174+
size_t buckets = 0;
175+
for (int i = 0; i < n_qubits; i++) {
176+
allocateQubit_cpp(sim, i);
177+
H_cpp(sim, i);
178+
}
179+
for (int i = n_qubits - 1; i >= 0; i--) {
180+
H_cpp(sim, i);
181+
// If the H do not cancel out, release will fail in an opaque way
182+
releaseQubit_cpp(sim, i);
183+
}
184+
}
185+
186+
TEST_CASE("HXZCommutationTest")
187+
{
188+
const int n_qubits = 16;
189+
unsigned sim = init_cpp(n_qubits);
190+
for (int i = 0; i < n_qubits; i++) {
191+
allocateQubit_cpp(sim, i);
192+
H_cpp(sim, i);
193+
}
194+
std::bitset<n_qubits> one_state = 0;
195+
for (int i = 0; i < n_qubits - 1; i += 2) {
196+
Z_cpp(sim, i);
197+
X_cpp(sim, i+1);
198+
one_state.set(i);
199+
}
200+
for (int i = n_qubits - 1; i >= 0; i--) {
201+
H_cpp(sim, i);
202+
}
203+
for (std::uint64_t i = 0; i < (std::uint64_t{1} << n_qubits); i++) {
204+
amplitude state = getSimulator(sim)->probe(std::bitset<n_qubits>(i).to_string());
205+
if (i == one_state.to_ulong()) {
206+
assert_amplitude_equality(state, 1.0, 0.0);
207+
}
208+
else {
209+
assert_amplitude_equality(state, 0.0, 0.0);
210+
}
211+
}
212+
}
213+
214+
TEST_CASE("ResetTest")
215+
{
216+
const int n_qubits = 16;
217+
unsigned sim = init_cpp(n_qubits);
218+
allocateQubit_cpp(sim, 0);
219+
Reset_cpp(sim, 0);
220+
amplitude state = getSimulator(sim)->probe("0");
221+
assert_amplitude_equality(state, 1.0, 0.0);
222+
X_cpp(sim, 0);
223+
Reset_cpp(sim, 0);
224+
state = getSimulator(sim)->probe("0");
225+
// No qubit exists; should have amplitude 0
226+
assert_amplitude_equality(state, 1.0, 0.0);
227+
allocateQubit_cpp(sim, 1);
228+
X_cpp(sim, 0);
229+
logical_qubit_id* controls = new logical_qubit_id{ 0 };
230+
MCX_cpp(sim, 1, controls, 1);
231+
Reset_cpp(sim, 0);
232+
state = getSimulator(sim)->probe("00");
233+
assert_amplitude_equality(state, 0.0, 0.0);
234+
state = getSimulator(sim)->probe("10");
235+
assert_amplitude_equality(state, 1.0, 0.0);
236+
Reset_cpp(sim, 1);
237+
state = getSimulator(sim)->probe("00");
238+
assert_amplitude_equality(state, 1.0, 0.0);
239+
state = getSimulator(sim)->probe("10");
240+
assert_amplitude_equality(state, 0.0, 0.0);
241+
releaseQubit_cpp(sim, 1);
242+
releaseQubit_cpp(sim, 0);
243+
}
244+
245+
TEST_CASE("MultiExpWithHTest") {
246+
const int num_qubits = 32;
247+
auto qubit_prep = [](unsigned sim ) {
248+
H_cpp(sim, 0);
249+
H_cpp(sim, 1);
250+
H_cpp(sim, 2);
251+
};
252+
auto qubit_clear = [](unsigned sim) {
253+
H_cpp(sim, 2);
254+
releaseQubit_cpp(sim, 2);
255+
H_cpp(sim, 1);
256+
releaseQubit_cpp(sim, 1);
257+
H_cpp(sim, 0);
258+
releaseQubit_cpp(sim, 0);
259+
};
260+
MultiExpReferenceTest<num_qubits>(qubit_prep, qubit_clear);
261+
}
262+
263+
TEST_CASE("MultiExpBasisTest") {
264+
const int num_qubits = 32;
265+
auto qubit_prep = [](unsigned sim, int index) {
266+
if ((index & 1) == 0) { X_cpp(sim, 0); }
267+
if ((index & 2) == 0) { X_cpp(sim, 1); }
268+
if ((index & 4) == 0) { X_cpp(sim, 2); }
269+
};
270+
auto qubit_clear = [](unsigned sim, int index) {
271+
if ((index & 1) == 0) { X_cpp(sim, 0); }
272+
releaseQubit_cpp(sim, 0);
273+
if ((index & 2) == 0) { X_cpp(sim, 1); }
274+
releaseQubit_cpp(sim, 1);
275+
if ((index & 4) == 0) { X_cpp(sim, 2); }
276+
releaseQubit_cpp(sim, 2);
277+
};
278+
for (int i = 0; i < 8; i++) {
279+
MultiExpReferenceTest<num_qubits>([=](unsigned sim) {qubit_prep(sim, i); }, [=](unsigned sim) {qubit_clear(sim, i); });
280+
}
281+
}
282+
283+
TEST_CASE("R1Test") {
284+
const int num_qubits = 32;
285+
amplitude result0;
286+
amplitude result1;
287+
for (double angle = 0.0; angle < M_PI / 2.0; angle += 0.1) {
288+
unsigned sim = init_cpp(num_qubits);
289+
H_cpp(sim, 0);
290+
R1_cpp(sim, angle, 0);
291+
result0 = getSimulator(sim)->probe("0");
292+
result1 = getSimulator(sim)->probe("1");
293+
assert_amplitude_equality(result0, 1.0 / sqrt(2.0));
294+
assert_amplitude_equality(result1, amplitude(cos(angle), sin(angle))/sqrt(2.0));
295+
R1_cpp(sim, -angle, 0);
296+
result0 = getSimulator(sim)->probe("0");
297+
result1 = getSimulator(sim)->probe("1");
298+
assert_amplitude_equality(result0, 1.0 / sqrt(2.0));
299+
assert_amplitude_equality(result1, 1.0 / sqrt(2.0));
300+
H_cpp(sim, 0);
301+
releaseQubit_cpp(sim, 0);
302+
destroy_cpp(sim);
303+
}
304+
}

0 commit comments

Comments
 (0)