Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
cf9cb72
fix of the adaptive compiler and preparations for randomized benchmar…
KevinMTO Oct 16, 2024
446a0f8
fix of the adaptive compiler and preparations for randomized benchmar…
KevinMTO Oct 16, 2024
7c4324a
Merge branch 'main' of github.com:cda-tum/mqt-qudits into compiler_int
KevinMTO Oct 16, 2024
a6d4168
🎨 pre-commit fixes
pre-commit-ci[bot] Oct 16, 2024
ffa86c7
temporary fix
KevinMTO Oct 17, 2024
62ef22b
Merge branch 'compiler_int' of github.com:cda-tum/mqt-qudits into com…
KevinMTO Oct 17, 2024
2d96939
🎨 pre-commit fixes
pre-commit-ci[bot] Oct 17, 2024
71e8009
benchmark suite
KevinMTO Oct 28, 2024
e41791b
Merge branch 'main' of github.com:cda-tum/mqt-qudits into compiler_int
KevinMTO Oct 28, 2024
968d0f4
testing and development of compiler full automation.
KevinMTO Nov 26, 2024
9283fbe
Merge branch 'main' of github.com:cda-tum/mqt-qudits into compiler_int
KevinMTO Nov 26, 2024
a73542f
Testing of compiler functionalities and of packages used during compi…
KevinMTO Dec 8, 2024
11bd39e
Merge branch 'main' of github.com:cda-tum/mqt-qudits into compiler_int
KevinMTO Dec 8, 2024
af8ab21
merge of remote changes
KevinMTO Dec 8, 2024
5678be9
code linting.
KevinMTO Dec 9, 2024
36a4a50
🎨 pre-commit fixes
pre-commit-ci[bot] Dec 9, 2024
68e0993
docstring fix
KevinMTO Dec 9, 2024
a3e5f9b
docstring fix
KevinMTO Dec 9, 2024
02606f4
🎨 pre-commit fixes
pre-commit-ci[bot] Dec 9, 2024
1f5d9fd
docstring fix for precommit
KevinMTO Dec 9, 2024
d4e29c9
docstring fix for precommit
KevinMTO Dec 9, 2024
b138525
🎨 pre-commit fixes
pre-commit-ci[bot] Dec 9, 2024
0adaf3c
codeql and pyproject issues solved
KevinMTO Dec 10, 2024
90e18cb
Merge branch 'compiler_int' of github.com:cda-tum/mqt-qudits into com…
KevinMTO Dec 10, 2024
4f65af7
🎨 pre-commit fixes
pre-commit-ci[bot] Dec 10, 2024
c65a9ff
⬆️ update lower bound for `requests`
burgholzer Dec 11, 2024
0b18994
correction to requests api
KevinMTO Dec 11, 2024
eacaece
conflict resolution
KevinMTO Dec 11, 2024
1b4aa81
changes accordig to new ruff rules
KevinMTO Dec 12, 2024
a816de6
pyproject changed
KevinMTO Dec 12, 2024
7c8d9a2
Merge branch 'compiler_int' of github.com:cda-tum/mqt-qudits into com…
KevinMTO Dec 12, 2024
e8394e0
Merge branch 'main' of github.com:cda-tum/mqt-qudits into compiler_int
KevinMTO Dec 12, 2024
ee14ff4
linting of multi pass
KevinMTO Dec 12, 2024
60ce80d
🎨 pre-commit fixes
pre-commit-ci[bot] Dec 12, 2024
e881718
Update pyproject.toml
KevinMTO Dec 12, 2024
9957b48
noise less state preparation routine
KevinMTO Dec 27, 2024
5b44d15
Merge branch 'compiler_int' of github.com:cda-tum/mqt-qudits into com…
KevinMTO Dec 27, 2024
e87cd66
fix tests accuracy
KevinMTO Dec 27, 2024
1d5a5c1
🎨 pre-commit fixes
pre-commit-ci[bot] Dec 27, 2024
3bc4acb
mypy error fixed
KevinMTO Dec 27, 2024
aa0b6cf
Merge branch 'compiler_int' of github.com:cda-tum/mqt-qudits into com…
KevinMTO Dec 27, 2024
daa1ba3
accuracy fix
KevinMTO Dec 27, 2024
bc1da6e
🎨 pre-commit fixes
pre-commit-ci[bot] Dec 27, 2024
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
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ repos:
additional_dependencies:
- pytest
- pandas-stubs
- types-requests

# Also run Black on examples in the documentation
- repo: https://github.com/adamchainz/blacken-docs
Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ dependencies = [
"matplotlib>=3.7; python_version < '3.12'",
"matplotlib>=3.8; python_version >= '3.12'",
"typing-extensions>=4.1",
"urllib3>=2.0.0",
"requests>=2.31.0",
"pytest>=8.3.4"
]
dynamic = ["version"]

Expand Down
5 changes: 1 addition & 4 deletions src/mqt/qudits/compiler/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,4 @@
from .compiler_pass import CompilerPass
from .dit_compiler import QuditCompiler

__all__ = [
"CompilerPass",
"QuditCompiler",
]
__all__ = ["CompilerPass", "QuditCompiler"]
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@
T = TypeVar("T")


def check_lev(lev: int, dim: int) -> int:
if lev < dim:
return lev
msg = "Mapping Not Compatible with Circuit."
raise IndexError(msg)


def swap_elements(list_nodes: list[T], i: int, j: int) -> list[T]:
a = list_nodes[i]
b = list_nodes[j]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,19 @@
from mqt.qudits.quantum_circuit.gates import R, Rz, VirtRz


def mini_unitary_sim(circuit: QuantumCircuit, list_of_op: list[Gate]) -> NDArray[np.complex128, np.complex128]:
def permute_according_to_mapping(circuit: QuantumCircuit, mappings: list[list[int]]) -> NDArray:
lines = list(range(circuit.num_qudits))
dimensions = circuit.dimensions
permutation = np.eye(dimensions[0])[:, mappings[0]]
for line in lines[1:]:
permutation = np.kron(permutation, np.eye(dimensions[line])[:, mappings[line]])
return permutation


def mini_unitary_sim(circuit: QuantumCircuit) -> NDArray[np.complex128, np.complex128]:
size = reduce(operator.mul, circuit.dimensions)
id_mat = np.identity(size)
for gate in list_of_op:
for gate in circuit.instructions:
id_mat = gate.to_matrix(identities=2) @ id_mat
return id_mat

Expand All @@ -34,17 +43,41 @@ def mini_sim(circuit: QuantumCircuit) -> NDArray[np.complex128]:
return state


def phy_sdit_sim(circuit: QuantumCircuit) -> NDArray[np.complex128]:
assert circuit.mappings is not None
dim = circuit.dimensions[0]
permutation = np.eye(dim)[:, circuit.mappings[0]]
state = np.array(dim * [0.0 + 0.0j])
def mini_phy_unitary_sim(circuit: QuantumCircuit) -> NDArray[np.complex128, np.complex128]:
assert circuit.final_mappings is not None
assert circuit.initial_mappings is not None

dimensions = circuit.dimensions
size = reduce(operator.mul, dimensions)
id_mat = np.identity(size)

final_permutation = permute_according_to_mapping(circuit, circuit.final_mappings)
init_permutation = permute_according_to_mapping(circuit, circuit.initial_mappings)

id_mat = init_permutation @ id_mat
for gate in circuit.instructions:
id_mat = gate.to_matrix(identities=2) @ id_mat

return final_permutation.T @ id_mat


def naive_phy_sim(circuit: QuantumCircuit) -> NDArray[np.complex128]:
assert circuit.final_mappings is not None
assert circuit.initial_mappings is not None

dimensions = circuit.dimensions
state = np.array(np.prod(dimensions) * [0.0 + 0.0j])
state[0] = 1.0 + 0.0j
state = permutation @ state

final_permutation = permute_according_to_mapping(circuit, circuit.final_mappings)
init_permutation = permute_according_to_mapping(circuit, circuit.initial_mappings)

state = init_permutation @ state

for gate in circuit.instructions:
state = gate.to_matrix(identities=2) @ state
return state

return final_permutation.T @ state


class UnitaryVerifier:
Expand Down Expand Up @@ -103,7 +136,9 @@ def verify(self) -> bool:

if self.permutation_matrix_final is not None:
target = np.linalg.inv(self.permutation_matrix_final) @ target
target.round(3)

target /= target[0][0]
target.round(3)

return bool((abs(target - np.identity(self.dimension, dtype="complex")) < 1e-4).all())
156 changes: 121 additions & 35 deletions src/mqt/qudits/compiler/dit_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
import typing
from typing import Optional

from ..core.lanes import Lanes
from ..core.custom_python_utils import append_to_front
from ..quantum_circuit.components.extensions.gate_types import GateTypes
from . import CompilerPass
from .multidit.transpile.phy_multi_control_transp import PhyMultiSimplePass
from .naive_local_resynth import NaiveLocResynthOptPass
from .onedit import LogLocQRPass, PhyLocAdaPass, PhyLocQRPass, ZPropagationOptPass, ZRemovalOptPass
from .twodit import LogEntQRCEXPass
from .twodit.entanglement_qr.phy_ent_qr_cex_decomp import PhyEntQRCEXPass
from .twodit.transpile.phy_two_control_transp import PhyEntSimplePass

if typing.TYPE_CHECKING:
from ..quantum_circuit import QuantumCircuit
Expand All @@ -29,14 +32,24 @@
"LogEntQRCEXPass": LogEntQRCEXPass,
"PhyEntQRCEXPass": PhyEntQRCEXPass,
"NaiveLocResynthOptPass": NaiveLocResynthOptPass,
"PhyEntSimplePass": PhyEntSimplePass,
"PhyMultiSimplePass": PhyMultiSimplePass,
}

def __init__(self) -> None:
pass

def compile(self, backend: Backend, circuit: QuantumCircuit, passes_names: list[str]) -> QuantumCircuit:
"""Method compiles with passes chosen."""
transpiled_circuit = circuit.copy()
final_mappings = []
for i, graph in enumerate(backend.energy_level_graphs):
if i < circuit.num_qudits:
final_mappings.append([lev for lev in graph.log_phy_map if lev < circuit.dimensions[i]])
transpiled_circuit.set_final_mappings(final_mappings)

passes_dict = {}
new_instr = []
new_instr: list[Gate] = []
# Instantiate and execute created classes
for compiler_pass_name in passes_names:
compiler_pass = self.passes_enabled[compiler_pass_name]
Expand All @@ -47,76 +60,149 @@
passes_dict[GateTypes.TWO] = decomposition
elif "Multi" in str(compiler_pass):
passes_dict[GateTypes.MULTI] = decomposition
for gate in circuit.instructions:

for gate in reversed(circuit.instructions):
decomposer = typing.cast("Optional[CompilerPass]", passes_dict.get(gate.gate_type))
if decomposer is not None:
new_instructions = decomposer.transpile_gate(gate)
new_instr.extend(new_instructions)
append_to_front(new_instr, new_instructions)
else:
new_instr.append(gate)

transpiled_circuit = circuit.copy()
mappings = []
append_to_front(new_instr, gate)
initial_mappings = []
for i, graph in enumerate(backend.energy_level_graphs):
if i < circuit.num_qudits:
mappings.append([lev for lev in graph.log_phy_map if lev < circuit.dimensions[i]])
transpiled_circuit.set_mapping(mappings)
initial_mappings.append([lev for lev in graph.log_phy_map if lev < circuit.dimensions[i]])
transpiled_circuit.set_initial_mappings(initial_mappings)
return transpiled_circuit.set_instructions(new_instr)

def compile_O0(self, backend: Backend, circuit: QuantumCircuit) -> QuantumCircuit: # noqa: N802
passes = ["PhyLocQRPass", "PhyEntQRCEXPass"]
"""Method compiles with PHY LOC QR and PHY ENT QR CEX with no optimization."""
final_mappings = []
for i, graph in enumerate(backend.energy_level_graphs):
if i < circuit.num_qudits:
final_mappings.append([lev for lev in graph.log_phy_map if lev < circuit.dimensions[i]])

passes = ["PhyLocQRPass", "PhyEntQRCEXPass", "PhyMultiSimplePass"]
compiled = self.compile(backend, circuit, passes)

mappings = []
initial_mappings = []
for i, graph in enumerate(backend.energy_level_graphs):
if i < circuit.num_qudits:
mappings.append([lev for lev in graph.log_phy_map if lev < circuit.dimensions[i]])
compiled.set_mapping(mappings)
initial_mappings.append([lev for lev in graph.log_phy_map if lev < circuit.dimensions[i]])
compiled.set_initial_mappings(initial_mappings)
compiled.set_final_mappings(final_mappings)
return compiled

@staticmethod
def compile_O1(backend: Backend, circuit: QuantumCircuit) -> QuantumCircuit: # noqa: N802
def compile_O1_resynth(backend: Backend, circuit: QuantumCircuit) -> QuantumCircuit: # noqa: N802
"""Method compiles with PHY LOC QR and PHY ENT QR CEX with a resynth steps."""
phyloc = PhyLocQRPass(backend)
phyent = PhyEntQRCEXPass(backend)
resynth = NaiveLocResynthOptPass(backend)
phymulti = PhyMultiSimplePass(backend)

transpiled_circuit = circuit.copy()
final_mappings = []
for i, graph in enumerate(backend.energy_level_graphs):
if i < circuit.num_qudits:
final_mappings.append([lev for lev in graph.log_phy_map if lev < circuit.dimensions[i]])
transpiled_circuit.set_final_mappings(final_mappings)

circuit = resynth.transpile(circuit)
new_instructions = []
for gate in circuit.instructions:
new_instructions: list[Gate] = []
for gate in reversed(circuit.instructions):
ins: list[Gate] = []
if gate.gate_type is GateTypes.SINGLE:
ins = phyloc.transpile_gate(gate)
new_instructions.extend(ins)
else:
append_to_front(new_instructions, ins)
elif gate.gate_type is GateTypes.TWO:
ins = phyent.transpile_gate(gate)
new_instructions.extend(ins)
transpiled_circuit = circuit.copy()
mappings = []
append_to_front(new_instructions, ins)
else:
ins = phymulti.transpile_gate(gate)
append_to_front(new_instructions, ins)

initial_mappings = []
for i, graph in enumerate(backend.energy_level_graphs):
if i < circuit.num_qudits:
mappings.append([lev for lev in graph.log_phy_map if lev < circuit.dimensions[i]])
transpiled_circuit.set_mapping(mappings)
initial_mappings.append([lev for lev in graph.log_phy_map if lev < circuit.dimensions[i]])
transpiled_circuit.set_initial_mappings(initial_mappings)
return transpiled_circuit.set_instructions(new_instructions)

@staticmethod
def compile_O2(backend: Backend, circuit: QuantumCircuit) -> QuantumCircuit: # noqa: N802
def compile_O1_adaptive(backend: Backend, circuit: QuantumCircuit) -> QuantumCircuit: # noqa: N802
"""Method compiles with PHY LOC ADA and PHY ENT QR CEX."""
phyent = PhyEntQRCEXPass(backend)
phyloc = PhyLocAdaPass(backend)
phymulti = PhyMultiSimplePass(backend)
transpiled_circuit = circuit.copy()
final_mappings = []
for i, graph in enumerate(backend.energy_level_graphs):
if i < circuit.num_qudits:
final_mappings.append([lev for lev in graph.log_phy_map if lev < circuit.dimensions[i]])

lanes = Lanes(circuit)
new_instructions = []
for gate in circuit.instructions:
new_instructions: list[Gate] = []
for gate in reversed(circuit.instructions):
ins: list[Gate] = []
if gate.gate_type is GateTypes.SINGLE:
phyloc = PhyLocAdaPass(backend, lanes.next_is_local(gate))
ins = phyloc.transpile_gate(gate)
new_instructions.extend(ins)
else:
append_to_front(new_instructions, ins)
elif gate.gate_type is GateTypes.TWO:
ins = phyent.transpile_gate(gate)
new_instructions.extend(ins)
append_to_front(new_instructions, ins)
else:
ins = phymulti.transpile_gate(gate)
append_to_front(new_instructions, ins)

transpiled_circuit.set_instructions(new_instructions)
z_propagation_pass = ZPropagationOptPass(backend=backend, back=False)
transpiled_circuit = z_propagation_pass.transpile(transpiled_circuit)

initial_mappings = []
for i, graph in enumerate(backend.energy_level_graphs):
if i < circuit.num_qudits:
initial_mappings.append([lev for lev in graph.log_phy_map if lev < circuit.dimensions[i]])
transpiled_circuit.set_initial_mappings(initial_mappings)
transpiled_circuit.set_final_mappings(final_mappings)

return transpiled_circuit

@staticmethod
def compile_O2(backend: Backend, circuit: QuantumCircuit) -> QuantumCircuit: # noqa: N802
"""Method compiles with PHY LOC ADA and PHY ENT QR CEX with a resynth steps."""
phyloc = PhyLocAdaPass(backend)
phyent = PhyEntQRCEXPass(backend)
resynth = NaiveLocResynthOptPass(backend)
phymulti = PhyMultiSimplePass(backend)
transpiled_circuit = circuit.copy()
mappings = []

final_mappings = []
for i, graph in enumerate(backend.energy_level_graphs):
if i < circuit.num_qudits:
final_mappings.append([lev for lev in graph.log_phy_map if lev < circuit.dimensions[i]])

circuit = resynth.transpile(circuit)
new_instructions: list[Gate] = []
for gate in reversed(circuit.instructions):
ins: list[Gate] = []
if gate.gate_type is GateTypes.SINGLE:
ins = phyloc.transpile_gate(gate)
append_to_front(new_instructions, ins)
elif gate.gate_type is GateTypes.TWO:
ins = phyent.transpile_gate(gate)
append_to_front(new_instructions, ins)
else:
ins = phymulti.transpile_gate(gate)
append_to_front(new_instructions, ins)

transpiled_circuit.set_instructions(new_instructions)
z_propagation_pass = ZPropagationOptPass(backend=backend, back=False)
transpiled_circuit = z_propagation_pass.transpile(transpiled_circuit)

initial_mappings = []
for i, graph in enumerate(backend.energy_level_graphs):
if i < circuit.num_qudits:
mappings.append([lev for lev in graph.log_phy_map if lev < circuit.dimensions[i]])
transpiled_circuit.set_mapping(mappings)
initial_mappings.append([lev for lev in graph.log_phy_map if lev < circuit.dimensions[i]])
transpiled_circuit.set_initial_mappings(initial_mappings)
transpiled_circuit.set_final_mappings(final_mappings)
return transpiled_circuit.set_instructions(new_instructions)
Empty file.
Empty file.
Loading
Loading