Skip to content

Commit

Permalink
Test one dit (#18)
Browse files Browse the repository at this point in the history
Tested the compiler passes for single qudit uniaries.

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Lukas Burgholzer <[email protected]>
  • Loading branch information
3 people authored Apr 30, 2024
1 parent c1dee1a commit c5af9f9
Show file tree
Hide file tree
Showing 9 changed files with 249 additions and 193 deletions.
5 changes: 1 addition & 4 deletions src/mqt/qudits/compiler/dit_manager.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from __future__ import annotations

from .onedit import LogLocAdaPass, LogLocQRPass, PhyLocAdaPass, PhyLocQRPass, ZPropagationPass, ZRemovalPass
from .twodit import LogEntQRCEXPass
from .onedit import LogLocQRPass, PhyLocAdaPass, PhyLocQRPass, ZPropagationPass, ZRemovalPass


class QuditCompiler:
Expand All @@ -10,9 +9,7 @@ class QuditCompiler:
"PhyLocAdaPass": PhyLocAdaPass,
"LocQRPass": PhyLocQRPass,
"LocAdaPass": PhyLocAdaPass,
"LogLocAdaPass": LogLocAdaPass,
"LogLocQRPass": LogLocQRPass,
"LogEntQRCEXPass": LogEntQRCEXPass,
"ZPropagationPass": ZPropagationPass,
"ZRemovalPass": ZRemovalPass,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,6 @@
from ....quantum_circuit import gates
from ....quantum_circuit.components.extensions.gate_types import GateTypes
from ... import CompilerPass
from ...compilation_minitools import new_mod
from ..local_operation_swap import (
cost_calculator,
gate_chain_condition,
graph_rule_ongate,
graph_rule_update,
)
from ..mapping_aware_transpilation import PhyQrDecomp

np.seterr(all="ignore")
Expand Down Expand Up @@ -90,10 +83,9 @@ def execute(self):
matrices_decomposed, best_cost, final_graph = self.TREE.retrieve_decomposition(self.TREE.root)

if matrices_decomposed != []:
pass
# matrices_decomposed, final_graph = self.Z_extraction(
# matrices_decomposed, final_graph, self.phase_propagation
# )
matrices_decomposed, final_graph = self.z_extraction(
matrices_decomposed, final_graph, self.phase_propagation
)
else:
pass

Expand Down Expand Up @@ -131,49 +123,18 @@ def z_extraction(self, decomposition, placement, phase_propagation):

for i in range(dimension):
if abs(np.angle(diag_U[i])) > 1.0e-4:
if phase_propagation:
inode = placement._1stInode
if "phase_storage" in placement.nodes[inode]:
placement.nodes[i]["phase_storage"] += np.angle(diag_U[i])
placement.nodes[i]["phase_storage"] = new_mod(placement.nodes[i]["phase_storage"])
else:
n_i = placement.nodes[i] # ["lpmap"]

phase_gate = gates.VirtRz(
self.circuit, "VRz", self.qudit_index, [n_i, np.angle(diag_U[i])], self.dimension
) # old version: VirtRz(np.angle(diag_U[i]), phy_n_i,
# dimension)

U_ = phase_gate.to_matrix(identities=0) @ U_ # matmul(phase_gate.to_matrix(identities=0), U_)

matrices.append(phase_gate)

if not phase_propagation:
inode = placement._1stInode
if "phase_storage" in placement.nodes[inode]:
for i in range(len(list(placement.nodes))):
thetaZ = new_mod(placement.nodes[i]["phase_storage"])
if abs(thetaZ) > 1.0e-4:
phase_gate = gates.VirtRz(
self.circuit,
"VRz",
self.qudit_index,
[i, thetaZ],
self.dimension,
) # VirtRz(thetaZ, placement.nodes[i]['lpmap'], # [placement.nodes[i]["lpmap"], thetaZ],
# dimension)
matrices.append(phase_gate)
# reset the node
placement.nodes[i]["phase_storage"] = 0
phase_gate = gates.VirtRz(
self.circuit, "VRz", self.qudit_index, [i, np.angle(diag_U[i])], self.dimension
) # old version: VirtRz(np.angle(diag_U[i]), phy_n_i, dimension)
U_ = phase_gate.to_matrix(identities=0) @ U_
matrices.append(phase_gate)

return matrices, placement

def DFS(self, current_root, level=0) -> None:
# check if close to diagonal
Ucopy = current_root.U_of_level.copy()

current_placement = current_root.graph

# is the diagonal noisy?
valid_diag = any(abs(np.diag(Ucopy)) > 1.0e-4)

Expand Down Expand Up @@ -204,7 +165,6 @@ def DFS(self, current_root, level=0) -> None:
for r2 in range(r + 1, dimension):
if abs(U_[r2, c]) > 1.0e-8 and (abs(U_[r, c]) > 1.0e-18 or abs(U_[r, c]) == 0):
theta = 2 * np.arctan2(abs(U_[r2, c]), abs(U_[r, c]))

phi = -(np.pi / 2 + np.angle(U_[r, c]) - np.angle(U_[r2, c]))

rotation_involved = gates.R(
Expand All @@ -213,18 +173,7 @@ def DFS(self, current_root, level=0) -> None:

U_temp = rotation_involved.to_matrix(identities=0) @ U_ # matmul(rotation_involved.matrix, U_)

non_zeros = np.count_nonzero(abs(U_temp) > 1.0e-4)

(
estimated_cost,
pi_pulses_routing,
new_placement,
cost_of_pi_pulses,
gate_cost,
) = cost_calculator(rotation_involved, current_placement, non_zeros)

next_step_cost = estimated_cost + current_root.current_cost
decomp_next_step_cost = cost_of_pi_pulses + gate_cost + current_root.current_decomp_cost
decomp_next_step_cost = rotation_involved.cost + current_root.current_decomp_cost

branch_condition = current_root.max_cost[1] - decomp_next_step_cost

Expand All @@ -234,54 +183,12 @@ def DFS(self, current_root, level=0) -> None:
self.TREE.global_id_counter += 1
new_key = self.TREE.global_id_counter

if new_placement.nodes[r]["lpmap"] > new_placement.nodes[r2]["lpmap"]:
phi *= -1
physical_rotation = gates.R(
self.circuit,
"R",
self.qudit_index,
[new_placement.nodes[r]["lpmap"], new_placement.nodes[r2]["lpmap"], theta, phi],
self.dimension,
)
# R(theta, phi, new_placement.nodes[r]['lpmap'],
# new_placement.nodes[r2]['lpmap'], dimension)
#
physical_rotation = gate_chain_condition(pi_pulses_routing, physical_rotation)
physical_rotation = graph_rule_ongate(physical_rotation, new_placement)

# take care of phases accumulated by not pi-pulsing back
p_backs = []
for ppulse in pi_pulses_routing:
p_backs.append(
gates.R(
self.circuit,
"R",
self.qudit_index,
[ppulse.lev_a, ppulse.lev_b, ppulse.theta, -ppulse.phi],
self.dimension,
)
)
# p_backs.append(R(ppulse.theta, -ppulse.phi, ppulse.lev_a, ppulse.lev_b, dimension))

for p_back in p_backs:
graph_rule_update(p_back, new_placement)
"""
current_root.add(
new_key,
physical_rotation,
U_temp,
new_placement,
next_step_cost,
decomp_next_step_cost,
current_root.max_cost,
pi_pulses_routing
)"""
current_root.add(
new_key,
rotation_involved,
U_temp,
new_placement,
next_step_cost,
None, # new_placement,
0, # next_step_cost,
decomp_next_step_cost,
current_root.max_cost,
[],
Expand Down
67 changes: 34 additions & 33 deletions test/python/compiler/onedit/test_log_local_adaptive_decomp.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,40 @@ def test_transpile(self):


class TestLogAdaptiveDecomposition(TestCase):
def test_execute(self):
pass
# dim = 5
# test_sample_edges = [(0, 4, {"delta_m": 0, "sensitivity": 1}),
# (0, 3, {"delta_m": 1, "sensitivity": 3}),
# (0, 2, {"delta_m": 1, "sensitivity": 3}),
# (1, 4, {"delta_m": 0, "sensitivity": 1}),
# (1, 3, {"delta_m": 1, "sensitivity": 3}),
# (1, 2, {"delta_m": 1, "sensitivity": 3})
# ]
# test_sample_nodes = [0, 1, 2, 3, 4]
# test_sample_nodes_map = [3, 2, 4, 1, 0]
#
# graph_1 = level_Graph(test_sample_edges, test_sample_nodes, test_sample_nodes_map, [0])
# graph_1.phase_storing_setup()
#
# Htest = H(dim)
#
# #-----------------
# QR = QR_decomp( Htest, graph_1, Z_prop = False, not_stand_alone = True )
#
# decomp_qr, algorithmic_cost_qr, total_cost_qr = QR.execute()
# #----------------
#
# ADA = Adaptive_decomposition(Htest, graph_1, cost_limit=(1.1 * algorithmic_cost_qr, 1.1 * total_cost_qr), dimension=dim, Z_prop=False)
#
# matrices_decomposed, best_cost, final_graph = ADA.execute()
"""def test_execute(self):
dim = 3
test_sample_edges = [(0, 4, {"delta_m": 0, "sensitivity": 1}),
(0, 3, {"delta_m": 1, "sensitivity": 3}),
(0, 2, {"delta_m": 1, "sensitivity": 3}),
(1, 4, {"delta_m": 0, "sensitivity": 1}),
(1, 3, {"delta_m": 1, "sensitivity": 3}),
(1, 2, {"delta_m": 1, "sensitivity": 3})
]
test_sample_nodes = [0, 1, 2, 3, 4]
test_sample_nodes_map = [3, 2, 4, 1, 0]
circuit_5 = QuantumCircuit(1, [5], 0)
graph_1 = LevelGraph(test_sample_edges, test_sample_nodes, test_sample_nodes_map, [0], 0, circuit_5)
Htest = circuit_5.h(0)
graph_1.phase_storing_setup()
QR = QrDecomp(Htest, graph_1, Z_prop=False, not_stand_alone=False)
# gate, graph_orig, Z_prop=False, not_stand_alone=True
decomp, _algorithmic_cost, _total_cost = QR.execute()
ADA = LogAdaptiveDecomposition(Htest, graph_1, cost_limit=(1.1 * _algorithmic_cost, 1.1 * _total_cost),
dimension=5, Z_prop=False)
# gate, graph_orig, cost_limit=(0, 0), dimension=-1, Z_prop=False
matrices_decomposed, best_cost, final_graph = ADA.execute()
# ##############################################
#
#
# V = Verifier(matrices_decomposed, Htest, test_sample_nodes, test_sample_nodes_map, graph_1.lpmap, dim)
# self.assertEqual( len(matrices_decomposed), 17)
# self.assertTrue(V.verify())
V = UnitaryVerifier(
matrices_decomposed, Htest, [dim], test_sample_nodes, test_sample_nodes_map, graph_1.log_phy_map
)
# self.assertEqual(len(matrices_decomposed), 17)
self.assertTrue(V.verify())
def test_dfs(self):
pass
pass"""
5 changes: 1 addition & 4 deletions test/python/compiler/onedit/test_log_local_qr_decomp.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ def test_transpile(self):

class TestQrDecomp(TestCase):
def test_execute(self):
# DIM 3
dim = 3
test_sample_edges = [
(0, 2, {"delta_m": 0, "sensitivity": 1}),
Expand All @@ -34,9 +33,7 @@ def test_execute(self):

decomp, _algorithmic_cost, _total_cost = QR.execute()

V = UnitaryVerifier(
decomp, Htest.to_matrix(identities=0), [dim], test_sample_nodes, test_sample_nodes_map, graph_1.log_phy_map
)
V = UnitaryVerifier(decomp, Htest, [dim], test_sample_nodes, test_sample_nodes_map, graph_1.log_phy_map)
# sequence, target, dimensions, nodes=None, initial_map=None, final_map=None
assert len(decomp) == 5
assert V.verify()
Expand Down
55 changes: 55 additions & 0 deletions test/python/compiler/onedit/test_phy_local_adaptive_decomp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from __future__ import annotations

from unittest import TestCase

from mqt.qudits.compiler.compilation_minitools import UnitaryVerifier
from mqt.qudits.compiler.onedit.mapping_aware_transpilation import PhyAdaptiveDecomposition, PhyQrDecomp
from mqt.qudits.core import LevelGraph
from mqt.qudits.quantum_circuit import QuantumCircuit


class TestPhyLocAdaPass(TestCase):
def test_transpile(self):
pass


class TestPhyAdaptiveDecomposition(TestCase):
def test_execute(self):
dim = 5
test_sample_edges = [
(0, 4, {"delta_m": 0, "sensitivity": 1}),
(0, 3, {"delta_m": 1, "sensitivity": 3}),
(0, 2, {"delta_m": 1, "sensitivity": 3}),
(1, 4, {"delta_m": 0, "sensitivity": 1}),
(1, 3, {"delta_m": 1, "sensitivity": 3}),
(1, 2, {"delta_m": 1, "sensitivity": 3}),
]
test_sample_nodes = [0, 1, 2, 3, 4]
test_sample_nodes_map = [3, 2, 4, 1, 0]

circuit_5 = QuantumCircuit(1, [5], 0)
graph_1 = LevelGraph(test_sample_edges, test_sample_nodes, test_sample_nodes_map, [0], 0, circuit_5)

Htest = circuit_5.h(0)
graph_1.phase_storing_setup()

QR = PhyQrDecomp(Htest, graph_1, Z_prop=False, not_stand_alone=False)
# gate, graph_orig, Z_prop=False, not_stand_alone=True

_decomp, _algorithmic_cost, _total_cost = QR.execute()

ADA = PhyAdaptiveDecomposition(
Htest, graph_1, cost_limit=(1.1 * _algorithmic_cost, 1.1 * _total_cost), dimension=5, Z_prop=False
)
# gate, graph_orig, cost_limit=(0, 0), dimension=-1, Z_prop=False
matrices_decomposed, _best_cost, final_graph = ADA.execute()
# ##############################################

V = UnitaryVerifier(
matrices_decomposed, Htest, [dim], test_sample_nodes, test_sample_nodes_map, final_graph.log_phy_map
)
assert len(matrices_decomposed) == 17
assert V.verify()

def test_dfs(self):
pass
45 changes: 45 additions & 0 deletions test/python/compiler/onedit/test_phy_local_qr_decomp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from __future__ import annotations

from unittest import TestCase

from mqt.qudits.compiler.compilation_minitools import UnitaryVerifier
from mqt.qudits.compiler.onedit.mapping_aware_transpilation import PhyQrDecomp
from mqt.qudits.core import LevelGraph
from mqt.qudits.quantum_circuit import QuantumCircuit


class TestPhyLocQRPass(TestCase):
def test_transpile(self):
pass


class TestPhyQRDecomposition(TestCase):
def test_execute(self):
dim = 5
test_sample_edges = [
(0, 4, {"delta_m": 0, "sensitivity": 1}),
(0, 3, {"delta_m": 1, "sensitivity": 3}),
(0, 2, {"delta_m": 1, "sensitivity": 3}),
(1, 4, {"delta_m": 0, "sensitivity": 1}),
(1, 3, {"delta_m": 1, "sensitivity": 3}),
(1, 2, {"delta_m": 1, "sensitivity": 3}),
]
test_sample_nodes = [0, 1, 2, 3, 4]
test_sample_nodes_map = [3, 2, 4, 1, 0]

circuit_5 = QuantumCircuit(1, [5], 0)
graph_1 = LevelGraph(test_sample_edges, test_sample_nodes, test_sample_nodes_map, [0], 0, circuit_5)

Htest = circuit_5.h(0)
graph_1.phase_storing_setup()

QR = PhyQrDecomp(Htest, graph_1, Z_prop=False, not_stand_alone=False)
# gate, graph_orig, Z_prop=False, not_stand_alone=True

decomp, _algorithmic_cost, _total_cost = QR.execute()

# ##############################################

V = UnitaryVerifier(decomp, Htest, [dim], test_sample_nodes, test_sample_nodes_map, graph_1.log_phy_map)
assert len(decomp) == 30
assert V.verify()
Loading

0 comments on commit c5af9f9

Please sign in to comment.