-
Notifications
You must be signed in to change notification settings - Fork 154
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding pass to turn arbitrary circuit into Clifford circuit (#1887)
Co-authored-by: joshuasn <53916441+joshuasn@users.noreply.github.com>
- Loading branch information
1 parent
a41738a
commit e9f8524
Showing
6 changed files
with
199 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
qiskit_ibm_runtime/transpiler/passes/cliffordization/__init__.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# This code is part of Qiskit. | ||
# | ||
# (C) Copyright IBM 2022. | ||
# | ||
# This code is licensed under the Apache License, Version 2.0. You may | ||
# obtain a copy of this license in the LICENSE.txt file in the root directory | ||
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. | ||
# | ||
# Any modifications or derivative works of this code must retain this | ||
# copyright notice, and modified files need to carry a notice indicating | ||
# that they have been altered from the originals. | ||
|
||
"""Passes to transform a circuit into a Clifford circuit.""" | ||
|
||
from .convert_isa_to_clifford import ConvertISAToClifford |
81 changes: 81 additions & 0 deletions
81
qiskit_ibm_runtime/transpiler/passes/cliffordization/convert_isa_to_clifford.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
# This code is part of Qiskit. | ||
# | ||
# (C) Copyright IBM 2022. | ||
# | ||
# This code is licensed under the Apache License, Version 2.0. You may | ||
# obtain a copy of this license in the LICENSE.txt file in the root directory | ||
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. | ||
# | ||
# Any modifications or derivative works of this code must retain this | ||
# copyright notice, and modified files need to carry a notice indicating | ||
# that they have been altered from the originals. | ||
|
||
""" | ||
Pass to convert the gates of an ISA circuit to Clifford gates. | ||
""" | ||
|
||
from random import choices | ||
import numpy as np | ||
|
||
from qiskit.circuit import Barrier, Measure | ||
from qiskit.circuit.library import CXGate, CZGate, ECRGate, IGate, RZGate, SXGate, XGate | ||
from qiskit.dagcircuit import DAGCircuit | ||
from qiskit.transpiler.basepasses import TransformationPass | ||
|
||
SUPPORTED_INSTRUCTIONS = (CXGate, CZGate, ECRGate, IGate, RZGate, SXGate, XGate, Barrier, Measure) | ||
"""The set of instructions supported by the :class:`~.ConvertISAToClifford` pass.""" | ||
|
||
|
||
class ConvertISAToClifford(TransformationPass): | ||
""" | ||
Convert the gates of an ISA circuit to Clifford gates. | ||
ISA circuits only contain Clifford gates from a restricted set or | ||
:class:`qiskit.circuit.library.RZGate`\\s by arbitrary angles. To convert them to Clifford | ||
circuits, this pass rounds the angle of every :class:`qiskit.circuit.library.RZGate` to the | ||
closest multiple of `pi/2` (or to a random multiple of `pi/2` if the angle is unspecified), | ||
while it skips every Clifford gate, measurement, and barrier. | ||
.. code-block:: python | ||
import numpy as np | ||
from qiskit.circuit import QuantumCircuit, Parameter | ||
from qiskit.transpiler import PassManager | ||
from qiskit_ibm_runtime.transpiler.passes import ConvertISAToClifford | ||
# An ISA circuit ending with a Z rotation by pi/3 | ||
qc = QuantumCircuit(2, 2) | ||
qc.sx(0) | ||
qc.rz(np.pi/2, 0) | ||
qc.sx(0) | ||
qc.barrier() | ||
qc.cx(0, 1) | ||
qc.rz(np.pi/3, 0) # non-Clifford Z rotation | ||
qc.rz(Parameter("th"), 0) # Z rotation with unspecified angle | ||
# Turn into a Clifford circuit | ||
pm = PassManager([ConvertISAToClifford()]) | ||
clifford_qc = pm.run(qc) | ||
Raises: | ||
ValueError: If the given circuit contains unsupported operations, such as non-ISA gates. | ||
""" | ||
|
||
def run(self, dag: DAGCircuit) -> DAGCircuit: | ||
for node in dag.op_nodes(): | ||
if not isinstance(node.op, SUPPORTED_INSTRUCTIONS): | ||
raise ValueError(f"Operation ``{node.op.name}`` not supported.") | ||
|
||
# Round the angle of `RZ`s to a multiple of pi/2 and skip the other instructions. | ||
if isinstance(node.op, RZGate): | ||
if isinstance(angle := node.op.params[0], float): | ||
rem = angle % (np.pi / 2) | ||
new_angle = angle - rem if rem < np.pi / 4 else angle + np.pi / 2 - rem | ||
else: | ||
# special handling of parametric gates | ||
new_angle = choices([0, np.pi / 2, np.pi, 3 * np.pi / 2])[0] | ||
dag.substitute_node(node, RZGate(new_angle), inplace=True) | ||
|
||
return dag |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Added ``ConvertISAToClifford`` transpilation pass to convert the gates of a circuit to Clifford gates. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# This code is part of Qiskit. | ||
# | ||
# (C) Copyright IBM 2024. | ||
# | ||
# This code is licensed under the Apache License, Version 2.0. You may | ||
# obtain a copy of this license in the LICENSE.txt file in the root directory | ||
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. | ||
# | ||
# Any modifications or derivative works of this code must retain this | ||
# copyright notice, and modified files need to carry a notice indicating | ||
# that they have been altered from the originals. |
87 changes: 87 additions & 0 deletions
87
test/unit/transpiler/passes/cliffordization/test_to_clifford.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
# This code is part of Qiskit. | ||
# | ||
# (C) Copyright IBM 2024. | ||
# | ||
# This code is licensed under the Apache License, Version 2.0. You may | ||
# obtain a copy of this license in the LICENSE.txt file in the root directory | ||
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0. | ||
# | ||
# Any modifications or derivative works of this code must retain this | ||
# copyright notice, and modified files need to carry a notice indicating | ||
# that they have been altered from the originals. | ||
|
||
"""Test the cliffordization pass.""" | ||
|
||
import numpy as np | ||
|
||
from qiskit.circuit import QuantumCircuit | ||
from qiskit.transpiler.passmanager import PassManager | ||
|
||
from qiskit_ibm_runtime.transpiler.passes import ConvertISAToClifford | ||
|
||
from .....ibm_test_case import IBMTestCase | ||
|
||
|
||
class TestConvertISAToClifford(IBMTestCase): | ||
"""Tests the ConvertISAToClifford pass.""" | ||
|
||
def test_clifford_isa_circuit(self): | ||
"""Test the pass on a Clifford circuit with ISA gates.""" | ||
qc = QuantumCircuit(2, 2) | ||
qc.id(0) | ||
qc.sx(0) | ||
qc.barrier() | ||
qc.measure(0, 1) | ||
qc.rz(0, 0) | ||
qc.rz(np.pi / 2, 0) | ||
qc.rz(np.pi, 0) | ||
qc.rz(3 * np.pi / 2, 0) | ||
qc.cx(0, 1) | ||
qc.cz(0, 1) | ||
qc.ecr(0, 1) | ||
|
||
pm = PassManager([ConvertISAToClifford()]) | ||
transformed = pm.run(qc) | ||
|
||
self.assertEqual(qc, transformed) | ||
|
||
def test_error_clifford_non_isa_circuit(self): | ||
"""Test that the pass errors when run on a Clifford circuit with non-ISA gates.""" | ||
qc = QuantumCircuit(2) | ||
qc.id(0) | ||
qc.sx(0) | ||
qc.s(1) | ||
qc.h(1) | ||
qc.cx(0, 1) | ||
qc.cz(0, 1) | ||
qc.ecr(0, 1) | ||
|
||
pm = PassManager([ConvertISAToClifford()]) | ||
with self.assertRaises(ValueError): | ||
pm.run(qc) | ||
|
||
def test_error_non_clifford_isa_circuit(self): | ||
"""Test that the pass errors when run on a non-Clifford circuit with ISA gates.""" | ||
qc = QuantumCircuit(2) | ||
qc.id(0) | ||
qc.sx(0) | ||
qc.rx(np.pi / 2 - 0.1, 0) | ||
qc.cx(0, 1) | ||
qc.cz(0, 1) | ||
qc.ecr(0, 1) | ||
|
||
pm = PassManager([ConvertISAToClifford()]) | ||
with self.assertRaises(ValueError): | ||
pm.run(qc) | ||
|
||
def test_error_reset(self): | ||
"""Test that the pass errors when run on circuits with resets.""" | ||
qc = QuantumCircuit(2) | ||
qc.x(1) | ||
qc.barrier(0) | ||
qc.reset(1) | ||
qc.rx(np.pi / 2 - 0.1, 1) | ||
|
||
pm = PassManager([ConvertISAToClifford()]) | ||
with self.assertRaises(ValueError): | ||
pm.run(qc) |