From 5631d9639281026dfbd45e198d419e62f807c38c Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Tue, 21 Mar 2023 15:06:29 -0400 Subject: [PATCH] Add full path transpile() tests --- .../passes/layout/disjoint_utils.py | 6 +- test/python/compiler/test_transpiler.py | 194 +++++++++++++++++- 2 files changed, 197 insertions(+), 3 deletions(-) diff --git a/qiskit/transpiler/passes/layout/disjoint_utils.py b/qiskit/transpiler/passes/layout/disjoint_utils.py index dac0013f7656..3fd331e627bc 100644 --- a/qiskit/transpiler/passes/layout/disjoint_utils.py +++ b/qiskit/transpiler/passes/layout/disjoint_utils.py @@ -46,8 +46,10 @@ def run_pass_over_connected_components( dag = dag_components[dag_index] out_dag.add_qubits(dag.qubits) out_dag.add_clbits(dag.clbits) - out_dag.add_qreg(dag.qregs) - out_dag.add_cregs(dag.cregs) + for qreg in dag.qregs: + out_dag.add_qreg(qreg) + for creg in dag.cregs: + out_dag.add_cregs(creg) out_dag.compose(dag, qubits=dag.qubits, clbits=dag.clbits) out_component_pairs.append((out_dag, cmap_components[cmap_index])) res = [run_func(out_dag, cmap) for out_dag, cmap in out_component_pairs] diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py index 15cec11eeb5a..39ec63cd6348 100644 --- a/test/python/compiler/test_transpiler.py +++ b/test/python/compiler/test_transpiler.py @@ -24,6 +24,7 @@ from test import combine # pylint: disable=wrong-import-order import numpy as np +import rustworkx as rx from qiskit.exceptions import QiskitError from qiskit import BasicAer @@ -42,9 +43,12 @@ RZGate, UGate, CZGate, + XGate, + SXGate, ) from qiskit.circuit import IfElseOp, WhileLoopOp, ForLoopOp, ControlFlowOp from qiskit.circuit.measure import Measure +from qiskit.circuit.delay import Delay from qiskit.test import QiskitTestCase from qiskit.providers.fake_provider import ( FakeMelbourne, @@ -55,7 +59,7 @@ ) from qiskit.transpiler import Layout, CouplingMap from qiskit.transpiler import PassManager, TransformationPass -from qiskit.transpiler.target import Target +from qiskit.transpiler.target import Target, InstructionProperties from qiskit.transpiler.exceptions import TranspilerError from qiskit.transpiler.passes import BarrierBeforeFinalMeasurements, GateDirection from qiskit.quantum_info import Operator, random_unitary @@ -63,6 +67,8 @@ from qiskit.transpiler.preset_passmanagers import level_0_pass_manager from qiskit.tools import parallel from qiskit.pulse import InstructionScheduleMap +from qiskit.providers.backend import BackendV2 +from qiskit.providers.options import Options class CustomCX(Gate): @@ -1971,3 +1977,189 @@ def test_backend_and_custom_gate(self, opt_level): self.assertEqual(tqc.data[0].operation, newgate) qubits = tuple(tqc.find_bit(x).index for x in tqc.data[0].qubits) self.assertIn(qubits, backend.target.qargs) + + +@ddt +class TestTranspileMultiChipTarget(QiskitTestCase): + """Test transpile() with a disjoint coupling map.""" + + def setUp(self): + super().setUp() + + class FakeMultiChip(BackendV2): + """Fake multi chip backend.""" + + def __init__(self): + super().__init__() + graph = rx.generators.directed_heavy_hex_graph(3) + num_qubits = len(graph) * 3 + rng = np.random.default_rng(seed=12345678942) + rz_props = {} + x_props = {} + sx_props = {} + measure_props = {} + delay_props = {} + self._target = Target("Fake multi-chip backend", num_qubits=num_qubits) + for i in range(num_qubits): + qarg = (i,) + rz_props[qarg] = InstructionProperties(error=0.0, duration=0.0) + x_props[qarg] = InstructionProperties( + error=rng.uniform(1e-6, 1e-4), duration=rng.uniform(1e-8, 9e-7) + ) + sx_props[qarg] = InstructionProperties( + error=rng.uniform(1e-6, 1e-4), duration=rng.uniform(1e-8, 9e-7) + ) + measure_props[qarg] = InstructionProperties( + error=rng.uniform(1e-3, 1e-1), duration=rng.uniform(1e-8, 9e-7) + ) + delay_props[qarg] = None + self._target.add_instruction(XGate(), x_props) + self._target.add_instruction(SXGate(), sx_props) + self._target.add_instruction(RZGate(Parameter("theta")), rz_props) + self._target.add_instruction(Measure(), measure_props) + self._target.add_instruction(Delay(Parameter("t")), delay_props) + cz_props = {} + for i in range(3): + for root_edge in graph.edge_list(): + offset = i * len(graph) + edge = (root_edge[0] + offset, root_edge[1] + offset) + cz_props[edge] = InstructionProperties( + error=rng.uniform(1e-5, 5e-3), duration=rng.uniform(1e-8, 9e-7) + ) + self._target.add_instruction(CZGate(), cz_props) + + @property + def target(self): + return self._target + + @property + def max_circuits(self): + return None + + @classmethod + def _default_options(cls): + return Options(shots=1024) + + def run(self, circuit, **kwargs): + raise NotImplementedError + + self.backend = FakeMultiChip() + + # Add level 0 and 1 when TrivialLayout supports disjoint coupling maps + @data(2, 3) + def test_basic_connected_circuit(self, opt_level): + """Test basic connected circuit on disjoint backend""" + qc = QuantumCircuit(5) + qc.h(0) + qc.cx(0, 1) + qc.cx(0, 2) + qc.cx(0, 3) + qc.cx(0, 4) + qc.measure_all() + tqc = transpile(qc, self.backend, optimization_level=opt_level) + for inst in tqc.data: + qubits = tuple(tqc.find_bit(x).index for x in inst.qubits) + op_name = inst.operation.name + if op_name == "barrier": + continue + self.assertIn(qubits, self.backend.target[op_name]) + + # Add level 0 and 1 when TrivialLayout supports disjoint coupling maps + @data(2, 3) + def test_triple_circuit(self, opt_level): + """Test a split circuit with one circuit component per chip.""" + qc = QuantumCircuit(30) + qc.h(0) + qc.h(10) + qc.h(20) + qc.cx(0, 1) + qc.cx(0, 2) + qc.cx(0, 3) + qc.cx(0, 4) + qc.cx(0, 5) + qc.cx(0, 6) + qc.cx(0, 7) + qc.cx(0, 8) + qc.cx(0, 9) + qc.ecr(10, 11) + qc.ecr(10, 12) + qc.ecr(10, 13) + qc.ecr(10, 14) + qc.ecr(10, 15) + qc.ecr(10, 16) + qc.ecr(10, 17) + qc.ecr(10, 18) + qc.ecr(10, 19) + qc.cy(20, 21) + qc.cy(20, 22) + qc.cy(20, 23) + qc.cy(20, 24) + qc.cy(20, 25) + qc.cy(20, 26) + qc.cy(20, 27) + qc.cy(20, 28) + qc.cy(20, 29) + qc.measure_all() + tqc = transpile(qc, self.backend, optimization_level=opt_level, seed_transpiler=42) + for inst in tqc.data: + qubits = tuple(tqc.find_bit(x).index for x in inst.qubits) + op_name = inst.operation.name + if op_name == "barrier": + continue + self.assertIn(qubits, self.backend.target[op_name]) + + # Add level 0 and 1 when TrivialLayout supports disjoint coupling maps + @data(2, 3) + def test_six_component_circuit(self, opt_level): + """Test input circuit with more than 1 component per backend component.""" + qc = QuantumCircuit(42) + qc.h(0) + qc.h(10) + qc.h(20) + qc.cx(0, 1) + qc.cx(0, 2) + qc.cx(0, 3) + qc.cx(0, 4) + qc.cx(0, 5) + qc.cx(0, 6) + qc.cx(0, 7) + qc.cx(0, 8) + qc.cx(0, 9) + qc.ecr(10, 11) + qc.ecr(10, 12) + qc.ecr(10, 13) + qc.ecr(10, 14) + qc.ecr(10, 15) + qc.ecr(10, 16) + qc.ecr(10, 17) + qc.ecr(10, 18) + qc.ecr(10, 19) + qc.cy(20, 21) + qc.cy(20, 22) + qc.cy(20, 23) + qc.cy(20, 24) + qc.cy(20, 25) + qc.cy(20, 26) + qc.cy(20, 27) + qc.cy(20, 28) + qc.cy(20, 29) + qc.h(30) + qc.cx(30, 31) + qc.cx(30, 32) + qc.cx(30, 33) + qc.h(34) + qc.cx(34, 35) + qc.cx(34, 36) + qc.cx(34, 37) + qc.h(38) + qc.cx(38, 39) + qc.cx(39, 40) + qc.cx(39, 41) + qc.measure_all() + tqc = transpile(qc, self.backend, optimization_level=opt_level, seed_transpiler=42) + for inst in tqc.data: + qubits = tuple(tqc.find_bit(x).index for x in inst.qubits) + op_name = inst.operation.name + if op_name == "barrier": + continue + self.assertIn(qubits, self.backend.target[op_name])