Repository: qiboteam/qibolab

Issue:
Missing GPI2 decomposition
In https://github.com/qiboteam/qibocal/pull/452 I'm trying to run a circuit on hardware containing the `GPI2` gate implemented in Qibo and I got the following error.
```sh
KeyError: <class 'qibo.gates.gates.GPI2'>
````
If I understood correctly the reason for this is that we are missing the GPI2 gate in the [gate decomposition](https://github.com/qiboteam/qibolab/blob/main/src/qibolab/transpilers/gate_decompositions.py) the transpiler.

Actually it would nice to make sure that all gate represented in Qibo have their decomposition also in the transpiler.

Comments:

Patch:
diff --git a/src/qibolab/compilers/compiler.py b/src/qibolab/compilers/compiler.py
index 1ba19a6a..1b2af972 100644
--- a/src/qibolab/compilers/compiler.py
+++ b/src/qibolab/compilers/compiler.py
@@ -6,6 +6,7 @@ from qibo.config import raise_error
 
 from qibolab.compilers.default import (
     cz_rule,
+    gpi2_rule,
     identity_rule,
     measurement_rule,
     rz_rule,
@@ -46,6 +47,7 @@ class Compiler:
                 gates.RZ: rz_rule,
                 gates.U3: u3_rule,
                 gates.CZ: cz_rule,
+                gates.GPI2: gpi2_rule,
                 gates.M: measurement_rule,
             }
         )
diff --git a/src/qibolab/compilers/default.py b/src/qibolab/compilers/default.py
index c8840d61..1bc5393b 100644
--- a/src/qibolab/compilers/default.py
+++ b/src/qibolab/compilers/default.py
@@ -24,6 +24,17 @@ def rz_rule(gate, platform):
     return PulseSequence(), {qubit: gate.parameters[0]}
 
 
+def gpi2_rule(gate, platform):
+    """Rule for GPI2."""
+    qubit = gate.target_qubits[0]
+    theta = gate.parameters[0]
+
+    sequence = PulseSequence()
+    pulse = platform.create_RX90_pulse(qubit, start=0, relative_phase=theta)
+    sequence.add(pulse)
+    return sequence, {}
+
+
 def u3_rule(gate, platform):
     """U3 applied as RZ-RX90-RZ-RX90-RZ."""
     qubit = gate.target_qubits[0]
diff --git a/src/qibolab/transpilers/gate_decompositions.py b/src/qibolab/transpilers/gate_decompositions.py
index be12f885..94cd1016 100644
--- a/src/qibolab/transpilers/gate_decompositions.py
+++ b/src/qibolab/transpilers/gate_decompositions.py
@@ -121,6 +121,8 @@ onequbit_dec.add(gates.RY, lambda gate: [gates.U3(0, gate.parameters[0], 0, 0)])
 # apply virtually by changing ``phase`` instead of using pulses
 onequbit_dec.add(gates.RZ, lambda gate: [gates.RZ(0, gate.parameters[0])])
 # apply virtually by changing ``phase`` instead of using pulses
+onequbit_dec.add(gates.GPI2, lambda gate: [gates.GPI2(0, gate.parameters[0])])
+# implemented as single RX90 pulse
 onequbit_dec.add(gates.U1, lambda gate: [gates.RZ(0, gate.parameters[0])])
 onequbit_dec.add(gates.U2, lambda gate: [gates.U3(0, np.pi / 2, gate.parameters[0], gate.parameters[1])])
 onequbit_dec.add(gates.U3, lambda gate: [gates.U3(0, gate.parameters[0], gate.parameters[1], gate.parameters[2])])


Test patch:
diff --git a/tests/test_compilers_default.py b/tests/test_compilers_default.py
index dc9cb748..55ef88cc 100644
--- a/tests/test_compilers_default.py
+++ b/tests/test_compilers_default.py
@@ -100,6 +100,20 @@ def test_rz_to_sequence(platform):
     assert len(sequence) == 0
 
 
+def test_GPI2_to_sequence(platform):
+    circuit = Circuit(1)
+    circuit.add(gates.GPI2(0, phi=0.2))
+    sequence = compile_circuit(circuit, platform)
+    assert len(sequence.pulses) == 1
+    assert len(sequence.qd_pulses) == 1
+
+    RX90_pulse = platform.create_RX90_pulse(0, start=0, relative_phase=0.2)
+    s = PulseSequence(RX90_pulse)
+
+    np.testing.assert_allclose(sequence.duration, RX90_pulse.duration)
+    assert sequence.serial == s.serial
+
+
 def test_u3_to_sequence(platform):
     circuit = Circuit(1)
     circuit.add(gates.U3(0, 0.1, 0.2, 0.3))
diff --git a/tests/test_transpilers_gate_decompositions.py b/tests/test_transpilers_gate_decompositions.py
index 007223c3..65a7538e 100644
--- a/tests/test_transpilers_gate_decompositions.py
+++ b/tests/test_transpilers_gate_decompositions.py
@@ -63,6 +63,11 @@ def test_u3_to_native():
     assert_matrices_allclose(gate, two_qubit_natives=NativeType.CZ)
 
 
+def test_gpi2_to_native():
+    gate = gates.GPI2(0, phi=0.123)
+    assert_matrices_allclose(gate, two_qubit_natives=NativeType.CZ)
+
+
 @pytest.mark.parametrize("gatename", ["CNOT", "CZ", "SWAP", "iSWAP", "FSWAP"])
 @pytest.mark.parametrize(
     "natives",