From 17a778040bdebdc9e6caf9d622254ace1cd28dd3 Mon Sep 17 00:00:00 2001 From: changsookim <> Date: Mon, 28 Oct 2024 18:44:53 +0400 Subject: [PATCH] fix: update compiler/rules to use circuit.wire_names --- src/qibolab/backends.py | 15 +++++----- src/qibolab/compilers/compiler.py | 24 ++++++++++++++-- src/qibolab/compilers/default.py | 46 +++++++++++++++---------------- tests/test_compilers_default.py | 2 ++ 4 files changed, 53 insertions(+), 34 deletions(-) diff --git a/src/qibolab/backends.py b/src/qibolab/backends.py index ea80aebffb..4c1c31a3a8 100644 --- a/src/qibolab/backends.py +++ b/src/qibolab/backends.py @@ -125,14 +125,9 @@ def execute_circuit(self, circuit, initial_state=None, nshots=1000): "Hardware backend only supports circuits as initial states.", ) + # This should be done in qibo side + # Temporary fix: overwrite the wire names if not all(q in circuit.wire_names for q in self.platform.qubits): - # This should be done in qibo side - # raise_error( - # ValueError, - # "Circuit qubits do not match the platform qubits.", - # ) - - # Temporary fix: overwrite the wire names circuit._wire_names = self.qubits self.platform.wire_names = circuit.wire_names @@ -179,6 +174,12 @@ def execute_circuits(self, circuits, initial_states=None, nshots=1000): "Hardware backend only supports circuits as initial states.", ) + # This should be done in qibo side + # Temporary fix: overwrite the wire names + for circuit in circuits: + if not all(q in circuit.wire_names for q in self.platform.qubits): + circuit._wire_names = self.qubits + # TODO: Maybe these loops can be parallelized sequences, measurement_maps = zip( *(self.compiler.compile(circuit, self.platform) for circuit in circuits) diff --git a/src/qibolab/compilers/compiler.py b/src/qibolab/compilers/compiler.py index 316fde2586..38fb9c7628 100644 --- a/src/qibolab/compilers/compiler.py +++ b/src/qibolab/compilers/compiler.py @@ -99,12 +99,24 @@ def inner(func): return inner def _compile_gate( - self, gate, platform, sequence, virtual_z_phases, moment_start, delays + self, + gate, + platform, + sequence, + virtual_z_phases, + moment_start, + delays, + wire_names, ): """Adds a single gate to the pulse sequence.""" rule = self[gate.__class__] + # get local sequence and phases for the current gate - gate_sequence, gate_phases = rule(gate, platform) + qubits_ids = ( + [wire_names[qubit] for qubit in gate.control_qubits], + [wire_names[qubit] for qubit in gate.target_qubits], + ) + gate_sequence, gate_phases = rule(qubits_ids, platform, gate.parameters) # update global pulse sequence # determine the right start time based on the availability of the qubits involved @@ -154,7 +166,13 @@ def compile(self, circuit, platform): delays[qubit] += gate.delay continue gate_sequence, gate_phases = self._compile_gate( - gate, platform, sequence, virtual_z_phases, moment_start, delays + gate, + platform, + sequence, + virtual_z_phases, + moment_start, + delays, + circuit.wire_names, ) for qubit in gate.qubits: delays[qubit] = 0 diff --git a/src/qibolab/compilers/default.py b/src/qibolab/compilers/default.py index 2c91b211c1..317a22ac32 100644 --- a/src/qibolab/compilers/default.py +++ b/src/qibolab/compilers/default.py @@ -8,52 +8,48 @@ from qibolab.pulses import PulseSequence -def identity_rule(gate, platform): +def identity_rule(qubits_ids, platform, parameters=None): """Identity gate skipped.""" return PulseSequence(), {} -def z_rule(gate, platform): +def z_rule(qubits_ids, platform, parameters=None): """Z gate applied virtually.""" - qubit = platform.get_qubit(gate.target_qubits[0]) - return PulseSequence(), {qubit: math.pi} + return PulseSequence(), {qubits_ids[1][0]: math.pi} -def rz_rule(gate, platform): +def rz_rule(qubits_ids, platform, parameters=None): """RZ gate applied virtually.""" - qubit = platform.get_qubit(gate.target_qubits[0]) - return PulseSequence(), {qubit: -gate.parameters[0]} + return PulseSequence(), {qubits_ids[1][0]: -parameters[0]} -def gpi2_rule(gate, platform): +def gpi2_rule(qubits_ids, platform, parameters=None): """Rule for GPI2.""" - qubit = platform.get_qubit(gate.target_qubits[0]) - theta = gate.parameters[0] + theta = parameters[0] sequence = PulseSequence() - pulse = platform.create_RX90_pulse(qubit, start=0, relative_phase=theta) + pulse = platform.create_RX90_pulse(qubits_ids[1][0], start=0, relative_phase=theta) sequence.add(pulse) return sequence, {} -def gpi_rule(gate, platform): +def gpi_rule(qubits_ids, platform, parameters=None): """Rule for GPI.""" - qubit = platform.get_qubit(gate.target_qubits[0]) - theta = gate.parameters[0] + theta = parameters[0] sequence = PulseSequence() # the following definition has a global phase difference compare to # to the matrix representation. See # https://github.com/qiboteam/qibolab/pull/804#pullrequestreview-1890205509 # for more detail. - pulse = platform.create_RX_pulse(qubit, start=0, relative_phase=theta) + pulse = platform.create_RX_pulse(qubits_ids[1][0], start=0, relative_phase=theta) sequence.add(pulse) return sequence, {} -def u3_rule(gate, platform): +def u3_rule(qubits_ids, platform, parameters=None): """U3 applied as RZ-RX90-RZ-RX90-RZ.""" - qubit = platform.get_qubit(gate.target_qubits[0]) + qubit = qubits_ids[1][0] # Transform gate to U3 and add pi/2-pulses - theta, phi, lam = gate.parameters + theta, phi, lam = parameters # apply RZ(lam) virtual_z_phases = {qubit: lam} sequence = PulseSequence() @@ -79,24 +75,26 @@ def u3_rule(gate, platform): return sequence, virtual_z_phases -def cz_rule(gate, platform): +def cz_rule(qubits_ids, platform, parameters=None): """CZ applied as defined in the platform runcard. Applying the CZ gate may involve sending pulses on qubits that the gate is not directly acting on. """ - return platform.create_CZ_pulse_sequence(gate.qubits) + qubits = qubits_ids[0] + qubits_ids[1] + return platform.create_CZ_pulse_sequence(qubits) -def cnot_rule(gate, platform): +def cnot_rule(qubits_ids, platform, parameters=None): """CNOT applied as defined in the platform runcard.""" - return platform.create_CNOT_pulse_sequence(gate.qubits) + qubits = qubits_ids[0] + qubits_ids[1] + return platform.create_CNOT_pulse_sequence(qubits) -def measurement_rule(gate, platform): +def measurement_rule(qubits_ids, platform, parameters=None): """Measurement gate applied using the platform readout pulse.""" sequence = PulseSequence() - for qubit in gate.target_qubits: + for qubit in qubits_ids[1]: MZ_pulse = platform.create_MZ_pulse(qubit, start=0) sequence.add(MZ_pulse) return sequence, {} diff --git a/tests/test_compilers_default.py b/tests/test_compilers_default.py index a1a85c3667..fdadbef49c 100644 --- a/tests/test_compilers_default.py +++ b/tests/test_compilers_default.py @@ -32,6 +32,8 @@ def test_u3_sim_agreement(): def compile_circuit(circuit, platform): """Compile a circuit to a pulse sequence.""" compiler = Compiler.default() + # Temporary fix: overwrite the wire names + circuit._wire_names = list(platform.qubits) sequence, _ = compiler.compile(circuit, platform) return sequence