Skip to content

Commit

Permalink
Add equivalence library entry for swap to ECR or CZ (#12312)
Browse files Browse the repository at this point in the history
* Add equivalence library entry for swap to ECR or CZ

This commit adds two new equivalence library entries to cover the
conversion from a SWAP gate to either ecr or cz directly. These are
common 2q basis gates and without these entries in the equivalence
library the path found from a lookup ends up with a much less efficient
translation. This commit adds the two new entries so that the
BasisTranslator will use a more efficient decomposition from the start
when targeting these basis. This will hopefully result in less work for
the optimization stage as the output will already be optimal and not
require simplification.

Testing for this PR is handled automatically by the built-in testing
harness in test_gate_definitions.py that evaluates all the entries in
the standard equivalence library for unitary equivalence.

* Add name to annotated gate circuit in qpy backwards compat tests

* Fix equivalence library tests

As fallout from the addition of SingletonGate and
SingletonControlledGate we were accidentally not running large portions
of the unit tests which validate the default session equivalence
library. This test dynamically runs based on all members of the standard
gate library by looking at all defined subclasses of Gate and
ControlledGate. But with the introduction of SingletonGate and
SingletonControlledGate all the unparameterized gates in the library
were not being run through the tests. This commit fixes this to catch
that the swap definition added in the previous commit on this PR branch
used an incorrect definition of SwapGate using ECRGate. The definition
will be fixed in a follow up PR.

* Use a more efficient and actually correct circuit for ECR target

The previous definition of a swap gate using ECR rz and sx was incorrect
and also not as efficient as possible. This was missed because the tests
were accidently broken since #10314 which was fixed in the previous
commit. This commit updates the definition to use one that is actually
correct and also more efficient with fewer 1 qubit gates.

Co-authored-by: Alexander Ivrii <alexi@il.ibm.com>

* Update ECR circuit diagram in comment

* Simplify cz equivalent circuit

* Simplify cz circuit even more

Co-authored-by: Shelly Garion <46566946+ShellyGarion@users.noreply.github.com>
Co-authored-by: Alexander Ivrii <alexi@il.ibm.com>

---------

Co-authored-by: Alexander Ivrii <alexi@il.ibm.com>
Co-authored-by: Shelly Garion <46566946+ShellyGarion@users.noreply.github.com>
  • Loading branch information
3 people authored May 2, 2024
1 parent d6c74c2 commit c53984f
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 3 deletions.
50 changes: 50 additions & 0 deletions qiskit/circuit/library/standard_gates/equivalence_library.py
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,56 @@ def _cnot_rxx_decompose(plus_ry: bool = True, plus_rxx: bool = True):
def_swap.append(inst, qargs, cargs)
_sel.add_equivalence(SwapGate(), def_swap)

# SwapGate
#
# q_0: ─X─
# │ ≡
# q_1: ─X─
#
# ┌──────────┐┌──────┐ ┌────┐ ┌──────┐┌──────────┐┌──────┐
# q_0: ┤ Rz(-π/2) ├┤0 ├───┤ √X ├───┤1 ├┤ Rz(-π/2) ├┤0 ├
# └──┬────┬──┘│ Ecr │┌──┴────┴──┐│ Ecr │└──┬────┬──┘│ Ecr │
# q_1: ───┤ √X ├───┤1 ├┤ Rz(-π/2) ├┤0 ├───┤ √X ├───┤1 ├
# └────┘ └──────┘└──────────┘└──────┘ └────┘ └──────┘
#
q = QuantumRegister(2, "q")
def_swap_ecr = QuantumCircuit(q)
def_swap_ecr.rz(-pi / 2, 0)
def_swap_ecr.sx(1)
def_swap_ecr.ecr(0, 1)
def_swap_ecr.rz(-pi / 2, 1)
def_swap_ecr.sx(0)
def_swap_ecr.ecr(1, 0)
def_swap_ecr.rz(-pi / 2, 0)
def_swap_ecr.sx(1)
def_swap_ecr.ecr(0, 1)
_sel.add_equivalence(SwapGate(), def_swap_ecr)

# SwapGate
#
# q_0: ─X─
# │ ≡
# q_1: ─X─
#
# global phase: 3π/2
# ┌────┐ ┌────┐ ┌────┐
# q_0: ┤ √X ├─■─┤ √X ├─■─┤ √X ├─■─
# ├────┤ │ ├────┤ │ ├────┤ │
# q_1: ┤ √X ├─■─┤ √X ├─■─┤ √X ├─■─
# └────┘ └────┘ └────┘
q = QuantumRegister(2, "q")
def_swap_cz = QuantumCircuit(q, global_phase=-pi / 2)
def_swap_cz.sx(0)
def_swap_cz.sx(1)
def_swap_cz.cz(0, 1)
def_swap_cz.sx(0)
def_swap_cz.sx(1)
def_swap_cz.cz(0, 1)
def_swap_cz.sx(0)
def_swap_cz.sx(1)
def_swap_cz.cz(0, 1)
_sel.add_equivalence(SwapGate(), def_swap_cz)

# iSwapGate
#
# ┌────────┐ ┌───┐┌───┐ ┌───┐
Expand Down
14 changes: 12 additions & 2 deletions test/python/circuit/test_gate_definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from qiskit import QuantumCircuit, QuantumRegister
from qiskit.quantum_info import Operator
from qiskit.circuit import ParameterVector, Gate, ControlledGate
from qiskit.circuit.singleton import SingletonGate, SingletonControlledGate
from qiskit.circuit.library import standard_gates
from qiskit.circuit.library import (
HGate,
Expand Down Expand Up @@ -260,7 +261,12 @@ class TestGateEquivalenceEqual(QiskitTestCase):
"""Test the decomposition of a gate in terms of other gates
yields the same matrix as the hardcoded matrix definition."""

class_list = Gate.__subclasses__() + ControlledGate.__subclasses__()
class_list = (
SingletonGate.__subclasses__()
+ SingletonControlledGate.__subclasses__()
+ Gate.__subclasses__()
+ ControlledGate.__subclasses__()
)
exclude = {
"ControlledGate",
"DiagonalGate",
Expand Down Expand Up @@ -313,7 +319,11 @@ def test_equivalence_phase(self, gate_class):
with self.subTest(msg=gate.name + "_" + str(ieq)):
op1 = Operator(gate)
op2 = Operator(equivalency)
self.assertEqual(op1, op2)
msg = (
f"Equivalence entry from '{gate.name}' to:\n"
f"{str(equivalency.draw('text'))}\nfailed"
)
self.assertEqual(op1, op2, msg)


@ddt
Expand Down
2 changes: 1 addition & 1 deletion test/qpy_compat/test_qpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,7 @@ def generate_annotated_circuits():
CXGate(), [InverseModifier(), ControlModifier(1), PowerModifier(1.4), InverseModifier()]
)
op2 = AnnotatedOperation(XGate(), InverseModifier())
qc = QuantumCircuit(6, 1)
qc = QuantumCircuit(6, 1, name="Annotated circuits")
qc.cx(0, 1)
qc.append(op1, [0, 1, 2])
qc.h(4)
Expand Down

0 comments on commit c53984f

Please sign in to comment.