Coverage for tests/test_expressiblity.py: 36%
61 statements
« prev ^ index » next coverage.py v7.6.12, created at 2025-03-07 14:54 +0000
« prev ^ index » next coverage.py v7.6.12, created at 2025-03-07 14:54 +0000
1from qml_essentials.model import Model
2from qml_essentials.expressibility import Expressibility
4import pennylane.numpy as np
5import logging
6import math
7import pytest
9logger = logging.getLogger(__name__)
12def get_test_cases():
13 # Results taken from: https://doi.org/10.1002/qute.201900070
15 circuits = [9, 1, 2, 16, 3, 18, 10, 12, 15, 17, 4, 11, 7, 8, 19, 5, 13, 14, 6]
17 results_n_layers_1 = [
18 0.6773,
19 0.2999,
20 0.2860,
21 0.2602,
22 0.2396,
23 0.2340,
24 0.2286,
25 0.1984,
26 0.1892,
27 0.1359,
28 0.1343,
29 0.1312,
30 0.0977,
31 0.0858,
32 0.0809,
33 0.0602,
34 0.0516,
35 0.0144,
36 0.0043,
37 ]
39 results_n_layers_3 = [
40 0.0322,
41 0.2079,
42 0.0084,
43 0.0375,
44 0.0403,
45 0.0221,
46 0.1297,
47 0.0089,
48 0.1152,
49 0.0180,
50 0.0107,
51 0.0038,
52 0.0162,
53 0.0122,
54 0.0040,
55 0.0030,
56 0.0049,
57 0.0035,
58 0.0039,
59 ]
61 # Circuits [5,7,8,11,12,13,14] are not included in the test cases,
62 # because not implemented in ansaetze.py
64 # Circuit 10 excluded because implementation with current setup not possible
65 skip_indices = [5, 7, 8, 11, 12, 13, 14, 10]
66 skip_indices += [16, 2, 3] # exclude these for now as order is failing
68 return circuits, results_n_layers_1, results_n_layers_3, skip_indices
71@pytest.mark.unittest
72def test_divergence() -> None:
73 test_cases = [
74 {
75 "n_qubits": 2,
76 "n_bins": 10,
77 "result": 0.000,
78 },
79 ]
81 for test_case in test_cases:
82 _, y_haar_a = Expressibility.haar_integral(
83 n_qubits=test_case["n_qubits"],
84 n_bins=test_case["n_bins"],
85 cache=True,
86 )
88 # We also test here the chache functionality
89 _, y_haar_b = Expressibility.haar_integral(
90 n_qubits=test_case["n_qubits"],
91 n_bins=test_case["n_bins"],
92 cache=False,
93 )
95 # Calculate the mean (over all inputs, if required)
96 kl_dist = Expressibility.kullback_leibler_divergence(y_haar_a, y_haar_b).mean()
98 assert math.isclose(
99 kl_dist.mean(), test_case["result"], abs_tol=1e-3
100 ), "Distance between two identical haar measures not equal."
103@pytest.mark.unittest
104@pytest.mark.expensive
105def test_expressibility() -> None:
106 circuits, results_n_layers_1, results_n_layers_3, skip_indices = get_test_cases()
108 test_cases = []
109 for circuit_id, res_1l, res_3l in zip(
110 circuits, results_n_layers_1, results_n_layers_3
111 ):
112 if circuit_id in skip_indices:
113 continue
114 test_cases.append(
115 {
116 "circuit_type": f"Circuit_{circuit_id}",
117 "n_qubits": 4,
118 "n_layers": 1,
119 "result": res_1l,
120 }
121 )
122 # test_cases.append({
123 # "circuit_type": f"Circuit_{circuit_id}",
124 # "n_qubits": 4,
125 # "n_layers": 3,
126 # "result": res_3l,
127 # })
129 tolerance = 0.35 # FIXME: reduce when reason for discrepancy is found
130 kl_distances: list[tuple[int, float]] = []
131 for test_case in test_cases:
132 print(f"--- Running Expressibility test for {test_case['circuit_type']} ---")
133 model = Model(
134 n_qubits=test_case["n_qubits"],
135 n_layers=test_case["n_layers"],
136 circuit_type=test_case["circuit_type"],
137 initialization_domain=[0, 2 * np.pi],
138 data_reupload=False,
139 )
141 _, _, z = Expressibility.state_fidelities(
142 seed=1000,
143 n_bins=75,
144 n_samples=5000,
145 model=model,
146 scale=False,
147 )
149 _, y_haar = Expressibility.haar_integral(
150 n_qubits=test_case["n_qubits"],
151 n_bins=75,
152 cache=False,
153 scale=False,
154 )
156 # Calculate the mean (over all inputs, if required)
157 kl_dist = Expressibility.kullback_leibler_divergence(z, y_haar).mean()
159 circuit_number = int(test_case["circuit_type"].split("_")[1])
160 kl_distances.append((circuit_number, kl_dist.item()))
162 difference = abs(kl_dist - test_case["result"])
163 if math.isclose(difference, 0.0, abs_tol=1e-10):
164 error = 0
165 else:
166 error = abs(kl_dist - test_case["result"]) / (test_case["result"])
168 print(
169 f"KL Divergence: {kl_dist},\t"
170 + f"Expected Result: {test_case['result']},\t"
171 + f"Error: {error}"
172 )
173 assert (
174 error < tolerance
175 ), f"Expressibility of circuit {test_case['circuit_type']} is not\
176 {test_case['result']} but {kl_dist} instead.\
177 Deviation {(error*100):.1f}>{tolerance*100}%"
179 references = sorted(
180 [
181 (circuit, result)
182 for circuit, result in zip(circuits, results_n_layers_1)
183 if circuit not in skip_indices
184 ],
185 key=lambda x: x[1],
186 )
188 actuals = sorted(kl_distances, key=lambda x: x[1])
190 print("Expected \t| Actual")
191 for reference, actual in zip(references, actuals):
192 print(f"{reference[0]}, {reference[1]} \t| {actual[0]}, {actual[1]}")
193 assert [circuit for circuit, _ in references] == [
194 circuit for circuit, _ in actuals
195 ], f"Order of circuits does not match: {actuals} != {references}"
198@pytest.mark.unittest
199@pytest.mark.expensive
200def test_scaling() -> None:
201 model = Model(
202 n_qubits=2,
203 n_layers=1,
204 circuit_type="Circuit_1",
205 )
207 _, _, z = Expressibility.state_fidelities(
208 seed=1000,
209 n_bins=4,
210 n_samples=10,
211 n_input_samples=0,
212 input_domain=[0, 2 * np.pi],
213 model=model,
214 scale=True,
215 )
217 assert z.shape == (8,)
219 _, y = Expressibility.haar_integral(
220 n_qubits=model.n_qubits,
221 n_bins=4,
222 cache=False,
223 scale=True,
224 )
226 assert y.shape == (8,)