diff --git a/pyqasm/elements.py b/pyqasm/elements.py index a8ae16c..97634a8 100644 --- a/pyqasm/elements.py +++ b/pyqasm/elements.py @@ -162,3 +162,21 @@ def __repr__(self) -> str: f"value = {self.value}, is_constant = {self.is_constant}, " f"readonly = {self.readonly}, is_register = {self.is_register})" ) + + +class BasisSet(Enum): + """ + Enum for the different basis sets in Qasm. + """ + + DEFAULT = 0 + TOFFOLI = 1 + CLIFFORD = 2 + PAULI = 3 + + def __repr__(self): + return f"<{self.__class__.__name__}.{self.name}: {self.value}>" + + @staticmethod + def get_supported_bases(): + return list(BasisSet) diff --git a/pyqasm/maps.py b/pyqasm/maps.py index fa26ac3..5233763 100644 --- a/pyqasm/maps.py +++ b/pyqasm/maps.py @@ -36,7 +36,7 @@ UintType, ) -from pyqasm.elements import InversionOp +from pyqasm.elements import BasisSet, InversionOp from pyqasm.exceptions import ValidationError from pyqasm.linalg import kak_decomposition_angles @@ -691,6 +691,31 @@ def two_qubit_gate_op( "cswap": cswap_gate, } +BASIS_GATE_MAP = { + # default basis set is the gate set of the stdgates.inc library file + BasisSet.DEFAULT: { + "id", + "rx", + "ry", + "rz", + "h", + "x", + "y", + "z", + "s", + "sx", + "t", + "sdg", + "tdg", + "cx", + "cz", + "swap", + }, + BasisSet.CLIFFORD: {"h", "t", "s", "cx"}, + BasisSet.PAULI: {"rx", "ry", "rz", "cx"}, + BasisSet.TOFFOLI: {"h", "ccx"}, +} + def map_qasm_op_to_callable(op_name: str): """ diff --git a/pyqasm/modules/base.py b/pyqasm/modules/base.py index d79f26b..3d277ce 100644 --- a/pyqasm/modules/base.py +++ b/pyqasm/modules/base.py @@ -20,7 +20,7 @@ from openqasm3.ast import Include, Program from pyqasm.analyzer import Qasm3Analyzer -from pyqasm.elements import ClbitDepthNode, QubitDepthNode +from pyqasm.elements import BasisSet, ClbitDepthNode, QubitDepthNode from pyqasm.exceptions import UnrollError, ValidationError from pyqasm.maps import QUANTUM_STATEMENTS from pyqasm.visitor import QasmVisitor @@ -445,6 +445,41 @@ def reverse_qubit_order(self, in_place=True): # 4. return the module return qasm_module + def _transform_to_basis(self, basis_set: BasisSet): + """Transform the unrolled module to a new basis set + + Args: + basis_set (BasisSet): The basis set to transform the module to + + Returns: + None + """ + if basis_set == BasisSet.DEFAULT: + return + + + def rebase(self, basis_set: BasisSet = BasisSet.DEFAULT, in_place=True): + """Rebases an openqasm program to a new gate set. + Will unroll the module if not already done. + + Args: + basis_set (BasisSet): The new gate set to rebase the program to. + + Returns: + QasmModule: The module rebased to the new gate set. If in_place is False, a new module + with the rebased gate set is returned. + + """ + + if not isinstance(basis_set, BasisSet): + raise TypeError(f"'gate_set' must be one of {BasisSet.get_supported_bases()}") + + qasm_module = self if in_place else self.copy() + qasm_module.unroll() + qasm_module._transform_to_basis(basis_set) + + return qasm_module + def validate(self): """Validate the module""" if self._validated_program is True: