Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

♻️ BackendV2 migration of MQT DDSIM Qiskit backends #267

Merged
merged 115 commits into from
Sep 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
115 commits
Select commit Hold shift + click to select a range
95b5eeb
BackendV2 migration of Qasmsimulator
andresbar98 Jul 24, 2023
b6ef98e
🎨 pre-commit fixes
pre-commit-ci[bot] Jul 24, 2023
c17f69c
qasmsimulator file renamed
andresbar98 Jul 25, 2023
7d4a1fe
backend_migration
andresbar98 Jul 25, 2023
cd72fa6
Included the remaining multi-controlled gates and modified some featu…
andresbar98 Aug 1, 2023
1c81a2e
modified test and QasmSimulatorFile
andresbar98 Aug 1, 2023
fd031e0
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 1, 2023
a79eb0d
more changes
andresbar98 Aug 1, 2023
2f2b268
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 1, 2023
8b12671
more changes to custom gate classes
andresbar98 Aug 2, 2023
57f65e5
Merge branch 'backend_migration' of https://github.com/andresbar98/mq…
andresbar98 Aug 2, 2023
d2ec824
More changes to qasmsimulator.py, statevectorsimulator.py and their c…
andresbar98 Aug 2, 2023
b16a2c6
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 2, 2023
d283920
more changes to qasmsimulator.py/Explicitely initializing QuantumCirc…
andresbar98 Aug 2, 2023
26f43c1
1
andresbar98 Aug 2, 2023
4855dca
more changes
andresbar98 Aug 2, 2023
5e59c8e
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 2, 2023
a255651
changed some test files, some of them were calling attributes of back…
andresbar98 Aug 3, 2023
d63d6ea
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 3, 2023
b1c3774
added header to result object in qasmsimulator.py
andresbar98 Aug 3, 2023
4b7f740
merge
andresbar98 Aug 3, 2023
9c2354c
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 3, 2023
378e659
recuperated experiment header information that was previously deleted
andresbar98 Aug 6, 2023
bab5a2c
merging
andresbar98 Aug 6, 2023
2e0248c
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 6, 2023
34018ab
Change the usage of keyword arguments in the class definitions
andresbar98 Aug 6, 2023
b7b46eb
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 6, 2023
05bc5dd
Merge branch 'main' into backend_migration
hillmich Aug 8, 2023
68240fb
Merge branch 'cda-tum:main' into backend_migration
andresbar98 Aug 8, 2023
c976612
Removed logger and reset is now supported gate
andresbar98 Aug 8, 2023
85caf9e
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 8, 2023
166a99a
🔥 remove deprecated `configuration` method and member
burgholzer Aug 8, 2023
9b1bbf9
🩹 properly return `None` for `max_circuits`
burgholzer Aug 8, 2023
4cd02e4
🩹 properly use properties for target
burgholzer Aug 8, 2023
20cf1f3
🔥 remove debugging code
burgholzer Aug 8, 2023
74c22d5
♻️ simplify constructors
burgholzer Aug 8, 2023
77eb8e7
🔥 remove the superfluous `_validate` method
burgholzer Aug 8, 2023
07ceecf
🔥 remove logger from `Job`
burgholzer Aug 8, 2023
b88b050
♻️ simplify constructor
burgholzer Aug 8, 2023
cd05ad1
🔥 `status()` is no longer required in `BackendV2`
burgholzer Aug 8, 2023
c6762e7
🔥 remove useless tests
burgholzer Aug 8, 2023
3120715
♻️ significantly simplify Provider
burgholzer Aug 8, 2023
449d7a3
🚨 better typing
burgholzer Aug 8, 2023
2585544
♻️ add dedicated target handling
burgholzer Aug 8, 2023
b419554
♻️ refactor QASM Simulator tests to use pytest
burgholzer Aug 8, 2023
e59506b
🚨 better typing
burgholzer Aug 8, 2023
42dd45d
✅ add tests for multi-qubit gate support
burgholzer Aug 8, 2023
6cb6e31
🩹 add `MCXGate` to definitions
burgholzer Aug 8, 2023
6b35974
✅ add tests for target gate set support
burgholzer Aug 8, 2023
91c3f49
♻️ simplify Job class and better typing
burgholzer Aug 9, 2023
726130e
🔥 remove unnecessary check
burgholzer Aug 9, 2023
c94b3c6
🩹 fix name of seed option
burgholzer Aug 9, 2023
5055902
♻️ simplify handling of simulator
burgholzer Aug 9, 2023
68ba5ea
migration to BackendV2 of unitarysimulator.py
andresbar98 Aug 13, 2023
653e89f
Removed useless tests from test_unitary_simulator.py
andresbar98 Aug 13, 2023
53033df
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 13, 2023
16eb3d6
Merge branch 'cda-tum:main' into backend_migration
andresbar98 Aug 13, 2023
c95986b
Removed old configuration call
andresbar98 Aug 13, 2023
18b1d68
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 13, 2023
2f807f5
Recover header object/ Build it on a different file
andresbar98 Aug 16, 2023
ed55644
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 16, 2023
57aa2ea
Minor changes to UnitarySimulatorBackend
andresbar98 Aug 16, 2023
10c40ff
Restored old configuration calls for backends that haven't been modified
andresbar98 Aug 16, 2023
e99d0c6
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 16, 2023
3414971
Fixed small error in usage.ipynb
andresbar98 Aug 16, 2023
d745245
Modified job handling
andresbar98 Aug 16, 2023
bff5212
Merge branch 'cda-tum:main' into backend_migration
andresbar98 Aug 16, 2023
477dac4
Merge branch 'backend_migration' of https://github.com/andresbar98/mq…
andresbar98 Aug 16, 2023
31336ce
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 16, 2023
94be19a
Fixed error using |: function
andresbar98 Aug 16, 2023
2c50dc6
Merge branch 'backend_migration' of https://github.com/andresbar98/mq…
andresbar98 Aug 16, 2023
1725398
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 16, 2023
0b83fdc
Fixed problem with header.py
andresbar98 Aug 17, 2023
0b7ad80
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 17, 2023
f5d553a
Fixed error in test_target
andresbar98 Aug 20, 2023
5838886
Fixed small error
andresbar98 Aug 24, 2023
c26fc88
⬆️🪝 update pre-commit hooks (#282)
pre-commit-ci[bot] Aug 22, 2023
ddd69a3
Manually merged commits from main branch
andresbar98 Aug 24, 2023
bdddec3
Merge branch 'main' into backend_migration
andresbar98 Aug 24, 2023
cb12537
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 24, 2023
77cd493
Fixed python typing
andresbar98 Aug 25, 2023
2aa10a8
Merge branch 'backend_migration' of https://github.com/andresbar98/mq…
andresbar98 Aug 25, 2023
84a959a
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 25, 2023
a05eb66
Migration of pathqasmsim and pathstatevectorsim
andresbar98 Aug 25, 2023
72edcf3
Merge branch 'backend_migration' of https://github.com/andresbar98/mq…
andresbar98 Aug 25, 2023
812d7c2
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 25, 2023
e9d9ef7
Fixed small typo
andresbar98 Aug 25, 2023
72875c7
Fixed small typo
andresbar98 Aug 25, 2023
9336ff9
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 25, 2023
c761ba6
Migration of HybridQasmSim and HybridStateVectorSim
andresbar98 Aug 26, 2023
4bca1ec
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 26, 2023
0f79433
Fixed typos
andresbar98 Aug 26, 2023
3b0f21b
FIxed more typos
andresbar98 Aug 26, 2023
fb4e540
♻️ Refactor simulator backends
burgholzer Aug 26, 2023
cc62e82
✅ improve tests
burgholzer Aug 26, 2023
4f8c6a7
🧪 make tests that should fail fail again
burgholzer Aug 26, 2023
0f7eea5
🔀 main
burgholzer Aug 28, 2023
8c54447
🩹 post-merge fixes
burgholzer Aug 28, 2023
e739943
🚨 fix mypy warnings
burgholzer Aug 28, 2023
8cbdb4e
Added test for multiple circuits in a job
andresbar98 Aug 30, 2023
3209a64
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 30, 2023
df75872
Fixed small error
andresbar98 Aug 30, 2023
2484a1e
Fixed small error
andresbar98 Aug 30, 2023
643bff0
🎨 pre-commit fixes
pre-commit-ci[bot] Aug 30, 2023
49f32c4
Merge branch 'cda-tum:main' into backend_migration
andresbar98 Aug 30, 2023
ac677af
Fixed old check warning
andresbar98 Sep 1, 2023
f2a50ff
Attribute error check for GlobalPhaseGate
andresbar98 Sep 1, 2023
6ad8119
🎨 pre-commit fixes
pre-commit-ci[bot] Sep 1, 2023
d9db534
Attribute error check for CSGate
andresbar98 Sep 1, 2023
3efbd56
Fixed Attribute error in some recent gates/Fixed error with _validate…
andresbar98 Sep 2, 2023
2f60039
🎨 pre-commit fixes
pre-commit-ci[bot] Sep 2, 2023
208d3c4
Small changes to test_target
andresbar98 Sep 5, 2023
f3c5801
Update test/python/test_target.py
andresbar98 Sep 5, 2023
f067f8e
Update test/python/test_target.py
andresbar98 Sep 5, 2023
fd2dc2f
Merge branch 'main' into backend_migration
burgholzer Sep 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions docs/source/Usage.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
"\n",
"# get the QasmSimulator and sample 100000 times\n",
"backend = provider.get_backend(\"qasm_simulator\")\n",
"print(f\"Backend version: {backend.configuration().backend_version}\")\n",
"print(f\"Backend version: {backend.backend_version}\")\n",
"job = execute(circ, backend, shots=100000)\n",
"result = job.result()\n",
"counts = result.get_counts(circ)\n",
Expand All @@ -93,7 +93,7 @@
"source": [
"# get the StatevectorSimulator and calculate the statevector\n",
"backend = provider.get_backend(\"statevector_simulator\")\n",
"print(f\"Backend version: {backend.configuration().backend_version}\")\n",
"print(f\"Backend version: {backend.backend_version}\")\n",
"job = execute(circ, backend)\n",
"result = job.result()\n",
"statevector = result.get_statevector(circ)\n",
Expand Down Expand Up @@ -128,7 +128,7 @@
"source": [
"# get the HybridQasmSimulator and sample 100000 times using the amplitude mode and 4 threads\n",
"backend = provider.get_backend(\"hybrid_qasm_simulator\")\n",
"print(f\"Backend version: {backend.configuration().backend_version}\")\n",
"print(f\"Backend version: {backend.backend_version}\")\n",
"job = execute(circ, backend, shots=100000, mode=\"amplitude\", nthreads=4)\n",
"result = job.result()\n",
"counts = result.get_counts(circ)\n",
Expand All @@ -155,7 +155,7 @@
"source": [
"# get the HybridStatevectorSimulator and calculate the statevector using the amplitude mode and 4 threads\n",
"backend = provider.get_backend(\"hybrid_statevector_simulator\")\n",
"print(f\"Backend version: {backend.configuration().backend_version}\")\n",
"print(f\"Backend version: {backend.backend_version}\")\n",
"job = execute(circ, backend, mode=\"amplitude\", nthreads=4)\n",
"result = job.result()\n",
"statevector = result.get_statevector(circ)\n",
Expand All @@ -178,7 +178,7 @@
"outputs": [],
"source": [
"backend = provider.get_backend(\"path_sim_qasm_simulator\")\n",
"print(f\"Backend version: {backend.configuration().backend_version}\")\n",
"print(f\"Backend version: {backend.backend_version}\")\n",
"job = execute(circ, backend, shots=100000) # uses the sequential strategy b\n",
"result = job.result()\n",
"counts = result.get_counts(circ)\n",
Expand Down Expand Up @@ -209,7 +209,7 @@
"source": [
"# get the UnitarySimulator and calculate the unitary functionality using the recursive mode\n",
"backend = provider.get_backend(\"unitary_simulator\")\n",
"print(f\"Backend version: {backend.configuration().backend_version}\")\n",
"print(f\"Backend version: {backend.backend_version}\")\n",
"job = execute(circ.remove_final_measurements(inplace=False), backend, mode=\"recursive\")\n",
"result = job.result()\n",
"unitary = result.get_unitary(circ)\n",
Expand Down
12 changes: 0 additions & 12 deletions src/mqt/ddsim/error.py

This file was deleted.

33 changes: 33 additions & 0 deletions src/mqt/ddsim/header.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""Utilities for constructing a Qiskit experiment header for DDSIM backends."""
from __future__ import annotations

from dataclasses import dataclass
from typing import TYPE_CHECKING

from qiskit.result.models import QobjExperimentHeader

if TYPE_CHECKING:
from qiskit import QuantumCircuit


@dataclass
class DDSIMHeader(QobjExperimentHeader):
name: str
n_qubits: int
memory_slots: int
global_phase: float
creg_sizes: list[tuple[str, int]]
clbit_labels: list[tuple[str, int]]
qreg_sizes: list[tuple[str, int]]
qubit_labels: list[tuple[str, int]]

def __init__(self, qc: QuantumCircuit):
super().__init__()
self.name = qc.name
self.n_qubits = qc.num_qubits
self.memory_slots = qc.num_clbits
self.global_phase = qc.global_phase
self.creg_sizes = [(creg.name, creg.size) for creg in qc.cregs]
self.clbit_labels = [(creg.name, j) for creg in qc.cregs for j in range(creg.size)]
self.qreg_sizes = [(qreg.name, qreg.size) for qreg in qc.qregs]
self.qubit_labels = [(qreg.name, j) for qreg in qc.qregs for j in range(qreg.size)]
221 changes: 63 additions & 158 deletions src/mqt/ddsim/hybridqasmsimulator.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,41 @@
"""Backend for DDSIM Hybrid Schrodinger-Feynman Simulator."""
from __future__ import annotations

import logging
import time
import uuid
import warnings
from math import log2

from qiskit import QiskitError, QuantumCircuit
from qiskit.compiler import assemble
from qiskit.providers import BackendV1, Options
from qiskit.providers.models import BackendConfiguration, BackendStatus
from qiskit.qobj import PulseQobj, QasmQobj, QasmQobjExperiment, Qobj
from qiskit.result import Result
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from qiskit import QuantumCircuit

from qiskit import QiskitError
from qiskit.providers import Options
from qiskit.result.models import ExperimentResult, ExperimentResultData
from qiskit.transpiler import Target
from qiskit.utils.multiprocessing import local_hardware_info

from . import __version__
from .error import DDSIMError
from .job import DDSIMJob
from .header import DDSIMHeader
from .pyddsim import HybridCircuitSimulator, HybridMode

logger = logging.getLogger(__name__)
from .qasmsimulator import QasmSimulatorBackend
from .target import DDSIMTargetBuilder


class HybridQasmSimulatorBackend(BackendV1):
class HybridQasmSimulatorBackend(QasmSimulatorBackend):
"""Python interface to MQT DDSIM Hybrid Schrodinger-Feynman Simulator."""

SHOW_STATE_VECTOR = False
_HSF_TARGET = Target(description="MQT DDSIM HSF Simulator Target", num_qubits=128)

@staticmethod
def _add_operations_to_target(target: Target) -> None:
DDSIMTargetBuilder.add_0q_gates(target)
DDSIMTargetBuilder.add_1q_gates(target)
DDSIMTargetBuilder.add_2q_controlled_gates(target)
DDSIMTargetBuilder.add_barrier(target)
DDSIMTargetBuilder.add_measure(target)

def __init__(
self, name="hybrid_qasm_simulator", description="MQT DDSIM Hybrid Schrodinger-Feynman simulator"
) -> None:
super().__init__(name=name, description=description)

@classmethod
def _default_options(cls) -> Options:
Expand All @@ -38,166 +47,62 @@ def _default_options(cls) -> Options:
nthreads=local_hardware_info()["cpus"],
)

def __init__(self, configuration=None, provider=None) -> None:
conf = {
"backend_name": "hybrid_qasm_simulator",
"backend_version": __version__,
"url": "https://github.com/cda-tum/mqt-ddsim",
"simulator": True,
"local": True,
"description": "MQT DDSIM Hybrid Schrodinger-Feynman C++ simulator",
"basis_gates": [
"gphase",
"id",
"u0",
"u1",
"u2",
"u3",
"cu3",
"x",
"cx",
"y",
"cy",
"z",
"cz",
"h",
"ch",
"s",
"sdg",
"t",
"tdg",
"rx",
"crx",
"ry",
"cry",
"rz",
"crz",
"p",
"cp",
"cu1",
"sx",
"csx",
"sxdg",
# 'swap', 'cswap', 'iswap',
"snapshot",
],
"memory": False,
"n_qubits": 128,
"coupling_map": None,
"conditional": False,
"max_shots": 1000000000,
"open_pulse": False,
"gates": [],
}
super().__init__(configuration=configuration or BackendConfiguration.from_dict(conf), provider=provider)

def run(self, quantum_circuits: QuantumCircuit | list[QuantumCircuit], **options):
if isinstance(quantum_circuits, (QasmQobj, PulseQobj)):
msg = "QasmQobj and PulseQobj are not supported."
raise QiskitError(msg)
@property
def target(self):
return self._HSF_TARGET

if not isinstance(quantum_circuits, list):
quantum_circuits = [quantum_circuits]

out_options = {}
for key in options:
if not hasattr(self.options, key):
warnings.warn("Option %s is not used by this backend" % key, UserWarning, stacklevel=2)
else:
out_options[key] = options[key]
circuit_qobj = assemble(quantum_circuits, self, **out_options)

job_id = str(uuid.uuid4())
local_job = DDSIMJob(self, job_id, self._run_job, circuit_qobj, **options)
local_job.submit()
return local_job

def _run_job(self, job_id, qobj_instance: Qobj, **options):
self._validate(qobj_instance)

start = time.time()
result_list = [self.run_experiment(qobj_exp, **options) for qobj_exp in qobj_instance.experiments]
end = time.time()

result = {
"backend_name": self.configuration().backend_name,
"backend_version": self.configuration().backend_version,
"qobj_id": qobj_instance.qobj_id,
"job_id": job_id,
"results": result_list,
"status": "COMPLETED",
"success": True,
"time_taken": (end - start),
"header": qobj_instance.header.to_dict(),
}
return Result.from_dict(result)

def run_experiment(self, qobj_experiment: QasmQobjExperiment, **options):
def _run_experiment(self, qc: QuantumCircuit, **options) -> ExperimentResult:
start_time = time.time()
seed = options.get("seed", -1)
mode = options.get("mode", "amplitude")
nthreads = int(options.get("nthreads", local_hardware_info()["cpus"]))
if mode == "amplitude":
hybrid_mode = HybridMode.amplitude
max_qubits = int(log2(local_hardware_info()["memory"] * (1024**3) / 16))
algorithm_qubits = qobj_experiment.header.n_qubits
max_qubits = self.max_qubits()
algorithm_qubits = qc.num_qubits
if algorithm_qubits > max_qubits:
msg = "Not enough memory available to simulate the circuit even on a single thread"
raise DDSIMError(msg)
raise QiskitError(msg)
qubit_diff = max_qubits - algorithm_qubits
nthreads = int(min(2**qubit_diff, nthreads))
elif mode == "dd":
hybrid_mode = HybridMode.DD
else:
msg = f"Simulation mode{mode} not supported by hybrid simulator. Available modes are 'amplitude' and 'dd'."
raise DDSIMError(msg)
raise QiskitError(msg)

sim = HybridCircuitSimulator(qobj_experiment, seed=seed, mode=hybrid_mode, nthreads=nthreads)
sim = HybridCircuitSimulator(qc, seed=seed, mode=hybrid_mode, nthreads=nthreads)

shots = options.get("shots", 1024)
if self.SHOW_STATE_VECTOR and shots > 0:
logger.info(
"Statevector can only be shown if shots == 0 when using the amplitude hybrid simulation mode. Setting shots=0."
)
if self._SHOW_STATE_VECTOR and shots > 0:
print("Statevector can only be shown if shots == 0 when using the amplitude hybrid simulation mode.")
shots = 0

counts = sim.simulate(shots)
end_time = time.time()
counts_hex = {hex(int(result, 2)): count for result, count in counts.items()}

result = {
"header": qobj_experiment.header.to_dict(),
"name": qobj_experiment.header.name,
"status": "DONE",
"time_taken": end_time - start_time,
"seed": seed,
"mode": mode,
"nthreads": nthreads,
"shots": shots,
"data": {"counts": counts_hex},
"success": True,
}
if self.SHOW_STATE_VECTOR:
if sim.get_mode() == HybridMode.DD:
result["data"]["statevector"] = sim.get_vector()
else:
result["data"]["statevector"] = sim.get_final_amplitudes()

return result

def _validate(self, _quantum_circuit):
return

def status(self):
"""Return backend status.

Returns:
BackendStatus: the status of the backend.
"""
return BackendStatus(
backend_name=self.name(),
backend_version=self.configuration().backend_version,
operational=True,
pending_jobs=0,
status_msg="",

data = ExperimentResultData(
counts={hex(int(result, 2)): count for result, count in counts.items()},
statevector=None
if not self._SHOW_STATE_VECTOR
else sim.get_vector()
if sim.get_mode() == HybridMode.DD
else sim.get_final_amplitudes(),
time_taken=end_time - start_time,
mode=mode,
nthreads=nthreads,
)

metadata = qc.metadata
if metadata is None:
metadata = {}

return ExperimentResult(
shots=shots,
success=True,
status="DONE",
seed=seed,
data=data,
metadata=metadata,
header=DDSIMHeader(qc),
)
Loading