From 9b31bfa047910dfc878e8ebd0cd664210d228506 Mon Sep 17 00:00:00 2001 From: simone bordoni Date: Wed, 13 Dec 2023 14:39:38 +0400 Subject: [PATCH] fix coverage and tests --- src/qibo/transpiler/pipeline.py | 11 ++++- src/qibo/transpiler/placer.py | 2 +- src/qibo/transpiler/star_connectivity.py | 2 + tests/test_transpiler_pipeline.py | 55 ++++++++++++++++++++++-- tests/test_transpiler_placer.py | 25 ++++++++++- 5 files changed, 87 insertions(+), 8 deletions(-) diff --git a/src/qibo/transpiler/pipeline.py b/src/qibo/transpiler/pipeline.py index 96e4be76d6..289429e40f 100644 --- a/src/qibo/transpiler/pipeline.py +++ b/src/qibo/transpiler/pipeline.py @@ -120,8 +120,12 @@ def assert_transpiling( if original_circuit.nqubits != transpiled_circuit.nqubits: qubit_matcher = Preprocessing(connectivity=connectivity) original_circuit = qubit_matcher(circuit=original_circuit) - assert_placement(circuit=original_circuit, layout=initial_layout) - assert_placement(circuit=transpiled_circuit, layout=final_layout) + assert_placement( + circuit=original_circuit, layout=initial_layout, connectivity=connectivity + ) + assert_placement( + circuit=transpiled_circuit, layout=final_layout, connectivity=connectivity + ) if check_circuit_equivalence: assert_circuit_equivalence( original_circuit=original_circuit, @@ -207,8 +211,10 @@ def __call__(self, circuit): final_layout = None for transpiler_pass in self.passes: if isinstance(transpiler_pass, Optimizer): + transpiler_pass.connectivity = self.connectivity circuit = transpiler_pass(circuit) elif isinstance(transpiler_pass, Placer): + transpiler_pass.connectivity = self.connectivity if self.initial_layout == None: self.initial_layout = transpiler_pass(circuit) else: @@ -217,6 +223,7 @@ def __call__(self, circuit): "You are defining more than one placer pass.", ) elif isinstance(transpiler_pass, Router): + transpiler_pass.connectivity = self.connectivity if self.initial_layout is not None: circuit, final_layout = transpiler_pass( circuit, self.initial_layout diff --git a/src/qibo/transpiler/placer.py b/src/qibo/transpiler/placer.py index 97bfc09a56..d47bc30da0 100644 --- a/src/qibo/transpiler/placer.py +++ b/src/qibo/transpiler/placer.py @@ -272,7 +272,7 @@ def __call__(self, circuit): return dict(zip(dict_keys, list(mapping.values()))) if cost < final_cost: final_graph = graph - final_mapping = {dict_keys[i]: mapping[i] for i in range(len(mapping))} + final_mapping = mapping final_cost = cost return dict(zip(dict_keys, list(final_mapping.values()))) diff --git a/src/qibo/transpiler/star_connectivity.py b/src/qibo/transpiler/star_connectivity.py index 3439211be9..693df030c1 100644 --- a/src/qibo/transpiler/star_connectivity.py +++ b/src/qibo/transpiler/star_connectivity.py @@ -3,6 +3,7 @@ from qibo.transpiler.router import ConnectivityError +# TODO: split into routing plus placer steps class StarConnectivity(Router): """Transforms an arbitrary circuit to one that can be executed on hardware. @@ -23,6 +24,7 @@ class StarConnectivity(Router): def __init__(self, connectivity=None, middle_qubit: int = 2): self.middle_qubit = middle_qubit + self.connectivity = connectivity def __call__(self, circuit: Circuit, initial_layout=None): """Apply the transpiler transformation on a given circuit. diff --git a/tests/test_transpiler_pipeline.py b/tests/test_transpiler_pipeline.py index bc82956485..feeaba4e84 100644 --- a/tests/test_transpiler_pipeline.py +++ b/tests/test_transpiler_pipeline.py @@ -14,7 +14,7 @@ restrict_connectivity_qubits, ) from qibo.transpiler.placer import Random, ReverseTraversal, Trivial -from qibo.transpiler.router import ShortestPaths +from qibo.transpiler.router import Sabre, ShortestPaths from qibo.transpiler.unroller import NativeGates, Unroller @@ -174,13 +174,24 @@ def test_is_satisfied_false_connectivity(): assert not default_transpiler.is_satisfied(circuit) +@pytest.mark.parametrize("reps", [range(3)]) +@pytest.mark.parametrize("placer", [Random, Trivial, ReverseTraversal]) +@pytest.mark.parametrize("routing", [ShortestPaths, Sabre]) @pytest.mark.parametrize( "circ", [generate_random_circuit(nqubits=5, ngates=20), small_circuit()] ) -def test_custom_passes(circ): +def test_custom_passes(circ, placer, routing, reps): custom_passes = [] custom_passes.append(Preprocessing(connectivity=star_connectivity())) - custom_passes.append(Random(connectivity=star_connectivity())) + if placer == ReverseTraversal: + custom_passes.append( + placer( + connectivity=star_connectivity(), + routing_algorithm=routing(connectivity=star_connectivity()), + ) + ) + else: + custom_passes.append(placer(connectivity=star_connectivity())) custom_passes.append(ShortestPaths(connectivity=star_connectivity())) custom_passes.append(Unroller(native_gates=NativeGates.default())) custom_pipeline = Passes( @@ -200,6 +211,44 @@ def test_custom_passes(circ): ) +@pytest.mark.parametrize("reps", [range(3)]) +@pytest.mark.parametrize("placer", [Random, Trivial, ReverseTraversal]) +@pytest.mark.parametrize("routing", [ShortestPaths, Sabre]) +def test_custom_passes_restict(reps, placer, routing): + circ = generate_random_circuit(nqubits=3, ngates=20) + custom_passes = [] + custom_passes.append(Preprocessing(connectivity=star_connectivity())) + if placer == ReverseTraversal: + custom_passes.append( + placer( + connectivity=star_connectivity(), + routing_algorithm=routing(connectivity=star_connectivity()), + ) + ) + else: + custom_passes.append(placer(connectivity=star_connectivity())) + custom_passes.append(routing(connectivity=star_connectivity())) + custom_passes.append(Unroller(native_gates=NativeGates.default())) + custom_pipeline = Passes( + custom_passes, + connectivity=star_connectivity(), + native_gates=NativeGates.default(), + on_qubits=[1, 2, 3], + ) + transpiled_circ, final_layout = custom_pipeline(circ) + initial_layout = custom_pipeline.get_initial_layout() + print(initial_layout) + print(final_layout) + assert_transpiling( + original_circuit=circ, + transpiled_circuit=transpiled_circ, + connectivity=restrict_connectivity_qubits(star_connectivity(), [1, 2, 3]), + initial_layout=initial_layout, + final_layout=final_layout, + native_gates=NativeGates.default(), + ) + + @pytest.mark.parametrize( "circ", [generate_random_circuit(nqubits=5, ngates=20), small_circuit()] ) diff --git a/tests/test_transpiler_placer.py b/tests/test_transpiler_placer.py index ae34bcec1e..c76e341981 100644 --- a/tests/test_transpiler_placer.py +++ b/tests/test_transpiler_placer.py @@ -11,6 +11,7 @@ ReverseTraversal, Subgraph, Trivial, + _find_gates_qubits_pairs, assert_mapping_consistency, assert_placement, ) @@ -92,6 +93,22 @@ def test_mapping_consistency_restricted_error(layout): assert_mapping_consistency(layout, restricted_connecyivity) +def test_gates_qubits_pairs(): + circuit = Circuit(5) + circuit.add(gates.CNOT(0, 1)) + circuit.add(gates.CNOT(1, 2)) + circuit.add(gates.M(1, 2)) + gates_qubits_pairs = _find_gates_qubits_pairs(circuit) + assert gates_qubits_pairs == [[0, 1], [1, 2]] + + +def test_gates_qubits_pairs_error(): + circuit = Circuit(5) + circuit.add(gates.TOFFOLI(0, 1, 2)) + with pytest.raises(ValueError): + gates_qubits_pairs = _find_gates_qubits_pairs(circuit) + + def test_trivial(): circuit = Circuit(5) connectivity = star_connectivity() @@ -125,12 +142,16 @@ def test_trivial_error(): "custom_layout", [[4, 3, 2, 1, 0], {"q0": 4, "q1": 3, "q2": 2, "q3": 1, "q4": 0}] ) @pytest.mark.parametrize("give_circuit", [True, False]) -def test_custom(custom_layout, give_circuit): +@pytest.mark.parametrize("give_connectivity", [True, False]) +def test_custom(custom_layout, give_circuit, give_connectivity): if give_circuit: circuit = Circuit(5) else: circuit = None - connectivity = star_connectivity() + if give_connectivity: + connectivity = star_connectivity() + else: + connectivity = None placer = Custom(connectivity=connectivity, map=custom_layout) layout = placer(circuit) assert layout == {"q0": 4, "q1": 3, "q2": 2, "q3": 1, "q4": 0}