Skip to content

Commit e55d456

Browse files
✨ Added QASM3 support (#518)
Extracted from #429: 8. adds a qasm3 export function (resolves #389) 12. adds a algorithm level benchmark generation function for qiskit that only supports qasm3
2 parents ef8462b + 74175fe commit e55d456

File tree

9 files changed

+311
-331
lines changed

9 files changed

+311
-331
lines changed

pyproject.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,11 @@ dependencies = [
2323
"pytket-qiskit>=0.53.0",
2424
# lowest version that supports the used pytket AutoRebase pass instead of auto_rebase
2525
"pytket>=1.29.0",
26-
# there is a bug in 1.2.0 that causes an error some benchmarks, see https://github.com/Qiskit/qiskit/issues/12969
27-
"qiskit!=1.2.0",
26+
# Qiskit 1.2.1 contains some fixes for importing OpenQASM 3 files
27+
"qiskit>=1.2.1",
2828
"qiskit_ibm_runtime<0.37.0", # FakeBackends have been removed with 0.37.0
2929
"qiskit-aer!=0.16.1", # excludig 0.16.1 due to an CI error for linux arm64 runners
30+
"qiskit_qasm3_import>=0.5.0",
3031
"networkx>=2.8.8",
3132
"joblib>=1.3.0",
3233
"numpy>=1.26; python_version >= '3.12'",

src/mqt/bench/benchmark_generator.py

Lines changed: 84 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ def generate_all_benchmarks(
142142
file_precheck: bool,
143143
) -> None:
144144
"""Generate all benchmarks for a given benchmark."""
145+
self.generate_alg_levels(file_precheck, lib, parameter_space)
145146
self.generate_indep_levels(file_precheck, lib, parameter_space)
146147
self.generate_native_gates_levels(file_precheck, lib, parameter_space)
147148
self.generate_mapped_levels(file_precheck, lib, parameter_space)
@@ -154,104 +155,124 @@ def generate_mapped_levels(
154155
) -> None:
155156
"""Generate mapped level benchmarks for a given benchmark."""
156157
for provider in get_available_providers():
157-
for device in provider.get_available_devices():
158-
for opt_level in [0, 1, 2, 3]:
158+
for qasm_format in ["qasm2", "qasm3"]:
159+
for device in provider.get_available_devices():
160+
for opt_level in [0, 1, 2, 3]:
161+
for parameter_instance in parameter_space:
162+
qc = timeout_watcher(lib.create_circuit, self.timeout, parameter_instance)
163+
if not qc:
164+
break
165+
assert isinstance(qc, QuantumCircuit)
166+
if qc.num_qubits <= device.num_qubits:
167+
res = timeout_watcher(
168+
qiskit_helper.get_mapped_level,
169+
self.timeout,
170+
[
171+
qc,
172+
qc.num_qubits,
173+
device,
174+
opt_level,
175+
file_precheck,
176+
False,
177+
self.qasm_output_path,
178+
qasm_format,
179+
],
180+
)
181+
if not res:
182+
break
183+
else:
184+
break
185+
159186
for parameter_instance in parameter_space:
160187
qc = timeout_watcher(lib.create_circuit, self.timeout, parameter_instance)
161188
if not qc:
162189
break
163190
assert isinstance(qc, QuantumCircuit)
164191
if qc.num_qubits <= device.num_qubits:
165192
res = timeout_watcher(
166-
qiskit_helper.get_mapped_level,
193+
tket_helper.get_mapped_level,
167194
self.timeout,
168-
[
169-
qc,
170-
qc.num_qubits,
171-
device,
172-
opt_level,
173-
file_precheck,
174-
False,
175-
self.qasm_output_path,
176-
],
195+
[qc, qc.num_qubits, device, file_precheck, False, self.qasm_output_path, qasm_format],
177196
)
178197
if not res:
179198
break
180199
else:
181200
break
182201

183-
for parameter_instance in parameter_space:
184-
qc = timeout_watcher(lib.create_circuit, self.timeout, parameter_instance)
185-
if not qc:
186-
break
187-
assert isinstance(qc, QuantumCircuit)
188-
if qc.num_qubits <= device.num_qubits:
202+
def generate_native_gates_levels(
203+
self,
204+
file_precheck: bool,
205+
lib: ModuleType,
206+
parameter_space: list[tuple[int, str]] | list[int] | list[str] | range,
207+
) -> None:
208+
"""Generate native gates level benchmarks for a given benchmark."""
209+
for provider in get_available_providers():
210+
for qasm_format in ["qasm2", "qasm3"]:
211+
for opt_level in [0, 1, 2, 3]:
212+
for parameter_instance in parameter_space:
213+
qc = timeout_watcher(lib.create_circuit, self.timeout, parameter_instance)
214+
if not qc:
215+
break
216+
assert isinstance(qc, QuantumCircuit)
189217
res = timeout_watcher(
190-
tket_helper.get_mapped_level,
218+
qiskit_helper.get_native_gates_level,
191219
self.timeout,
192220
[
193221
qc,
222+
provider,
194223
qc.num_qubits,
195-
device,
224+
opt_level,
196225
file_precheck,
197226
False,
198227
self.qasm_output_path,
228+
qasm_format,
199229
],
200230
)
201231
if not res:
202232
break
203-
else:
204-
break
205233

206-
def generate_native_gates_levels(
207-
self,
208-
file_precheck: bool,
209-
lib: ModuleType,
210-
parameter_space: list[tuple[int, str]] | list[int] | list[str] | range,
211-
) -> None:
212-
"""Generate native gates level benchmarks for a given benchmark."""
213-
for provider in get_available_providers():
214-
for opt_level in [0, 1, 2, 3]:
215234
for parameter_instance in parameter_space:
216235
qc = timeout_watcher(lib.create_circuit, self.timeout, parameter_instance)
217236
if not qc:
218237
break
219238
assert isinstance(qc, QuantumCircuit)
220239
res = timeout_watcher(
221-
qiskit_helper.get_native_gates_level,
240+
tket_helper.get_native_gates_level,
222241
self.timeout,
223242
[
224243
qc,
225244
provider,
226245
qc.num_qubits,
227-
opt_level,
228246
file_precheck,
229247
False,
230248
self.qasm_output_path,
249+
qasm_format,
231250
],
232251
)
233252
if not res:
234253
break
235254

255+
def generate_alg_levels(
256+
self,
257+
file_precheck: bool,
258+
lib: ModuleType,
259+
parameter_space: list[tuple[int, str]] | list[int] | list[str] | range,
260+
) -> None:
261+
"""Generate algorithm level benchmarks for a given benchmark."""
262+
for function in [qiskit_helper.get_alg_level]:
236263
for parameter_instance in parameter_space:
237-
qc = timeout_watcher(lib.create_circuit, self.timeout, parameter_instance)
238-
if not qc:
239-
break
240-
assert isinstance(qc, QuantumCircuit)
241-
res = timeout_watcher(
242-
tket_helper.get_native_gates_level,
243-
self.timeout,
244-
[
245-
qc,
246-
provider,
247-
qc.num_qubits,
248-
file_precheck,
249-
False,
250-
self.qasm_output_path,
251-
],
252-
)
253-
if not res:
254-
break
264+
for qasm_format in ["qasm3"]:
265+
qc = timeout_watcher(lib.create_circuit, self.timeout, parameter_instance)
266+
if not qc:
267+
break
268+
assert isinstance(qc, QuantumCircuit)
269+
res = timeout_watcher(
270+
function,
271+
self.timeout,
272+
[qc, qc.num_qubits, file_precheck, False, self.qasm_output_path, qasm_format],
273+
)
274+
if not res:
275+
break
255276

256277
def generate_indep_levels(
257278
self,
@@ -262,17 +283,18 @@ def generate_indep_levels(
262283
"""Generate independent level benchmarks for a given benchmark."""
263284
for function in [qiskit_helper.get_indep_level, tket_helper.get_indep_level]:
264285
for parameter_instance in parameter_space:
265-
qc = timeout_watcher(lib.create_circuit, self.timeout, parameter_instance)
266-
if not qc:
267-
break
268-
assert isinstance(qc, QuantumCircuit)
269-
res = timeout_watcher(
270-
function,
271-
self.timeout,
272-
[qc, qc.num_qubits, file_precheck, False, self.qasm_output_path],
273-
)
274-
if not res:
275-
break
286+
for qasm_format in ["qasm2", "qasm3"]:
287+
qc = timeout_watcher(lib.create_circuit, self.timeout, parameter_instance)
288+
if not qc:
289+
break
290+
assert isinstance(qc, QuantumCircuit)
291+
res = timeout_watcher(
292+
function,
293+
self.timeout,
294+
[qc, qc.num_qubits, file_precheck, False, self.qasm_output_path, qasm_format],
295+
)
296+
if not res:
297+
break
276298

277299

278300
@overload

src/mqt/bench/benchmarks/ae.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def create_circuit(num_qubits: int, probability: float = 0.2) -> QuantumCircuit:
4747
qc.compose(state_preparation, list(range(num_eval_qubits, qc.num_qubits)), inplace=True)
4848

4949
# Compose the phase estimation component.
50-
qc.compose(pe, inplace=True)
50+
qc.compose(pe.decompose(gates_to_decompose="unitary"), inplace=True)
5151

5252
# Name the circuit and add measurements to all evaluation qubits.
5353
qc.name = "ae"

src/mqt/bench/benchmarks/graphstate.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,4 @@ def create_circuit(num_qubits: int, degree: int = 2) -> QuantumCircuit:
2121
a = nx.convert_matrix.to_numpy_array(g)
2222
qc.compose(GraphState(a), inplace=True)
2323
qc.measure_all()
24-
25-
return qc
24+
return qc.decompose(gates_to_decompose="graph_state")

0 commit comments

Comments
 (0)