From aeae0be7d762d294c86be554a4dd981488a67384 Mon Sep 17 00:00:00 2001 From: chensgit169 Date: Sat, 23 Dec 2023 16:00:40 +0800 Subject: [PATCH 01/13] chore: restructure folder, add ZYZ decomposer to interface --- quafu/elements/element_gates/unitary/__init__.py | 1 - quafu/elements/unitary/__init__.py | 1 + quafu/elements/{element_gates => }/unitary/decomposer.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) delete mode 100644 quafu/elements/element_gates/unitary/__init__.py create mode 100644 quafu/elements/unitary/__init__.py rename quafu/elements/{element_gates => }/unitary/decomposer.py (99%) diff --git a/quafu/elements/element_gates/unitary/__init__.py b/quafu/elements/element_gates/unitary/__init__.py deleted file mode 100644 index 67c0d007..00000000 --- a/quafu/elements/element_gates/unitary/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .decomposer import UnitaryDecomposer diff --git a/quafu/elements/unitary/__init__.py b/quafu/elements/unitary/__init__.py new file mode 100644 index 00000000..49b5a1aa --- /dev/null +++ b/quafu/elements/unitary/__init__.py @@ -0,0 +1 @@ +from .decomposer import UnitaryDecomposer, zyz_decomposition diff --git a/quafu/elements/element_gates/unitary/decomposer.py b/quafu/elements/unitary/decomposer.py similarity index 99% rename from quafu/elements/element_gates/unitary/decomposer.py rename to quafu/elements/unitary/decomposer.py index e9d14f2f..45d0b58f 100644 --- a/quafu/elements/element_gates/unitary/decomposer.py +++ b/quafu/elements/unitary/decomposer.py @@ -6,7 +6,7 @@ from numpy import ndarray from quafu.elements.matrices import rz_mat, ry_mat, CXMatrix -from ...matrices import mat_utils as mu +from quafu.elements.matrices import mat_utils as mu class UnitaryDecomposer(object): From 47d76d8ad9d11b3b2fe7523c973e21e3dd1fb6dd Mon Sep 17 00:00:00 2001 From: chensgit169 Date: Sat, 23 Dec 2023 16:02:13 +0800 Subject: [PATCH 02/13] chore: move actual gate classes into a single file --- quafu/elements/__init__.py | 1 + quafu/elements/element_gates/__init__.py | 12 +- quafu/elements/element_gates/c11.py | 72 --- quafu/elements/element_gates/c12.py | 10 - quafu/elements/element_gates/clifford.py | 50 +- quafu/elements/element_gates/cm1.py | 36 -- quafu/elements/element_gates/element_gates.py | 461 ++++++++++++++++++ quafu/elements/element_gates/pauli.py | 159 +----- 8 files changed, 468 insertions(+), 333 deletions(-) delete mode 100644 quafu/elements/element_gates/c11.py delete mode 100644 quafu/elements/element_gates/c12.py delete mode 100644 quafu/elements/element_gates/cm1.py create mode 100644 quafu/elements/element_gates/element_gates.py diff --git a/quafu/elements/__init__.py b/quafu/elements/__init__.py index 79c584ee..7e5a2b67 100644 --- a/quafu/elements/__init__.py +++ b/quafu/elements/__init__.py @@ -2,3 +2,4 @@ from .pulses import Delay, XYResonance, QuantumPulse from .quantum_gate import QuantumGate, ControlledGate, MultiQubitGate, SingleQubitGate from .classical_element import Cif +from .unitary import UnitaryDecomposer diff --git a/quafu/elements/element_gates/__init__.py b/quafu/elements/element_gates/__init__.py index dd69a985..4b0d9d31 100644 --- a/quafu/elements/element_gates/__init__.py +++ b/quafu/elements/element_gates/__init__.py @@ -1,11 +1,4 @@ -from .pauli import * -from .clifford import HGate, SGate, SdgGate, TGate, TdgGate -from .rotation import RXGate, RYGate, RZGate, RXXGate, RYYGate, RZZGate, PhaseGate -from .swap import SwapGate, ISwapGate -from .c11 import CXGate, CYGate, CZGate, CSGate, CTGate, CPGate -from .c12 import FredkinGate -from .cm1 import MCXGate, MCYGate, MCZGate, ToffoliGate -from .unitary import UnitaryDecomposer +from .element_gates import * __all__ = [ "XGate", @@ -42,6 +35,5 @@ "FredkinGate", "MCXGate", "MCYGate", - "MCZGate", - "UnitaryDecomposer", + "MCZGate" ] diff --git a/quafu/elements/element_gates/c11.py b/quafu/elements/element_gates/c11.py deleted file mode 100644 index 2d773e13..00000000 --- a/quafu/elements/element_gates/c11.py +++ /dev/null @@ -1,72 +0,0 @@ -from ..quantum_gate import ControlledGate, FixedGate, QuantumGate -from abc import ABC -from quafu.elements.matrices import XMatrix, YMatrix, ZMatrix, SMatrix, TMatrix, pmatrix -from typing import Dict - - -__all__ = ['CXGate', 'CYGate', 'CZGate', - 'CSGate', 'CTGate', - 'CPGate'] - - -class _C11Gate(ControlledGate, ABC): - ct_dims = (1, 1, 2) - - -@QuantumGate.register('cx') -class CXGate(_C11Gate, FixedGate): - name = "CX" - - def __init__(self, ctrl: int, targ: int): - _C11Gate.__init__(self, "X", [ctrl], [targ], None, tar_matrix=XMatrix) - self.symbol = "+" - - -@QuantumGate.register('cy') -class CYGate(_C11Gate, FixedGate): - name = "CY" - - def __init__(self, ctrl: int, targ: int): - _C11Gate.__init__(self, "Y", [ctrl], [targ], None, tar_matrix=YMatrix) - - -@QuantumGate.register('cz') -class CZGate(_C11Gate, FixedGate): - name = "CZ" - - def __init__(self, ctrl: int, targ: int): - _C11Gate.__init__(self, "Z", [ctrl], [targ], None, tar_matrix=ZMatrix) - - -@QuantumGate.register('cs') -class CSGate(_C11Gate, FixedGate): - name = "CS" - - def __init__(self, ctrl: int, targ: int): - _C11Gate.__init__(self, "S", [ctrl], [targ], None, tar_matrix=SMatrix) - - def to_qasm(self): - return "cp(pi/2) " + "q[%d],q[%d]" % (self.pos[0], self.pos[1]) - - -@QuantumGate.register('ct') -class CTGate(_C11Gate, FixedGate): - name = "CT" - - def __init__(self, ctrl: int, targ: int): - _C11Gate.__init__(self, "T", [ctrl], [targ], None, tar_matrix=TMatrix) - - def to_qasm(self): - return "cp(pi/4) " + "q[%d],q[%d]" % (self.pos[0], self.pos[1]) - - -@QuantumGate.register('cp') -class CPGate(_C11Gate): - name = "CP" - - def __init__(self, ctrl: int, targ: int, paras): - _C11Gate.__init__(self, "P", [ctrl], [targ], paras, tar_matrix=pmatrix(paras)) - - @property - def named_paras(self) -> Dict: - return {'theta': self.paras} diff --git a/quafu/elements/element_gates/c12.py b/quafu/elements/element_gates/c12.py deleted file mode 100644 index f3360202..00000000 --- a/quafu/elements/element_gates/c12.py +++ /dev/null @@ -1,10 +0,0 @@ -from ..quantum_gate import ControlledGate, FixedGate, QuantumGate -from quafu.elements.matrices import SwapMatrix - - -@QuantumGate.register('cswap') -class FredkinGate(ControlledGate, FixedGate): - name = "CSWAP" - - def __init__(self, ctrl: int, targ1: int, targ2: int): - ControlledGate.__init__(self, "SWAP", [ctrl], [targ1, targ2], None, tar_matrix=SwapMatrix) diff --git a/quafu/elements/element_gates/clifford.py b/quafu/elements/element_gates/clifford.py index e7e099d3..c8fa0b9f 100644 --- a/quafu/elements/element_gates/clifford.py +++ b/quafu/elements/element_gates/clifford.py @@ -1,51 +1,5 @@ -import numpy as np +from .element_gates import HGate, SGate, CXGate -from quafu.elements.matrices import HMatrix, SMatrix -from ..quantum_gate import SingleQubitGate, FixedGate, QuantumGate +__all__ = ['HGate', 'SGate', 'CXGate'] -__all__ = ['HGate', 'SGate', 'SdgGate', 'TGate', 'TdgGate'] - -@QuantumGate.register('h') -class HGate(SingleQubitGate, FixedGate): - name = "H" - matrix = HMatrix - - def __init__(self, pos: int): - FixedGate.__init__(self, pos) - - -@QuantumGate.register('s') -class SGate(SingleQubitGate, FixedGate): - name = "S" - matrix = SMatrix - - def __init__(self, pos: int): - FixedGate.__init__(self, pos) - - -@QuantumGate.register('sdg') -class SdgGate(SingleQubitGate, FixedGate): - name = "Sdg" - matrix = SMatrix.conj().T - - def __init__(self, pos: int): - FixedGate.__init__(self, pos) - - -@QuantumGate.register('t') -class TGate(SingleQubitGate, FixedGate): - name = "T" - matrix = np.array([[1.0, 0.0], [0.0, np.exp(1.0j * np.pi / 4)]], dtype=complex) - - def __init__(self, pos: int): - FixedGate.__init__(self, pos) - - -@QuantumGate.register('tdg') -class TdgGate(SingleQubitGate, FixedGate): - name = "Tdg" - matrix = TGate.matrix.conj().T - - def __init__(self, pos: int): - FixedGate.__init__(self, pos) diff --git a/quafu/elements/element_gates/cm1.py b/quafu/elements/element_gates/cm1.py deleted file mode 100644 index ca217bc7..00000000 --- a/quafu/elements/element_gates/cm1.py +++ /dev/null @@ -1,36 +0,0 @@ -from ..quantum_gate import ControlledGate, FixedGate, QuantumGate -from quafu.elements.matrices import XMatrix, YMatrix, ZMatrix - -__all__ = ['MCXGate', 'MCYGate', 'MCZGate', 'ToffoliGate'] - - -@QuantumGate.register('mcx') -class MCXGate(ControlledGate, FixedGate): - name = "MCX" - - def __init__(self, ctrls, targ: int): - ControlledGate.__init__(self, "X", ctrls, [targ], None, tar_matrix=XMatrix) - - -@QuantumGate.register('mcy') -class MCYGate(ControlledGate, FixedGate): - name = "MCY" - - def __init__(self, ctrls, targ: int): - ControlledGate.__init__(self, "Y", ctrls, [targ], None, tar_matrix=YMatrix) - - -@QuantumGate.register('mcz') -class MCZGate(ControlledGate, FixedGate): - name = "MCZ" - - def __init__(self, ctrls, targ: int): - ControlledGate.__init__(self, "Z", ctrls, [targ], None, tar_matrix=ZMatrix) - - -@QuantumGate.register('ccx') -class ToffoliGate(ControlledGate, FixedGate): - name = "CCX" - - def __init__(self, ctrl1: int, ctrl2: int, targ: int): - ControlledGate.__init__(self, "X", [ctrl1, ctrl2], [targ], None, tar_matrix=XMatrix) diff --git a/quafu/elements/element_gates/element_gates.py b/quafu/elements/element_gates/element_gates.py new file mode 100644 index 00000000..0e47a228 --- /dev/null +++ b/quafu/elements/element_gates/element_gates.py @@ -0,0 +1,461 @@ +# (C) Copyright 2023 Beijing Academy of Quantum Information Sciences +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" Actual classes of quantum gates. + +The ideal about structuring is roughly "Gate + Ctrl-Gate". + + +""" + +from typing import Dict +from abc import ABC + +import quafu.elements.matrices as mat +from quafu.elements.quantum_gate import QuantumGate, ControlledGate +from quafu.elements.quantum_gate import MultiQubitGate, FixedGate, SingleQubitGate, ParametricGate + + +# # # # # # # # # # # # # # # Internal helper classes # # # # # # # # # # # # # # # + +class _C11Gate(ControlledGate, ABC): + ct_dims = (1, 1, 2) + + +# # # # # # # # # # # # # # # Paulis # # # # # # # # # # # # # # # +@QuantumGate.register('id') +class IdGate(FixedGate, SingleQubitGate): + name = "Id" + matrix = mat.XMatrix + + def __init__(self, pos: int): + FixedGate.__init__(self, pos) + + +@QuantumGate.register('x') +class XGate(FixedGate, SingleQubitGate): + name = "X" + matrix = mat.XMatrix + + def __init__(self, pos: int): + FixedGate.__init__(self, pos) + + +@QuantumGate.register('y') +class YGate(FixedGate, SingleQubitGate): + name = "Y" + matrix = mat.YMatrix + + def __init__(self, pos: int): + FixedGate.__init__(self, pos) + + +@QuantumGate.register('z') +class ZGate(FixedGate, SingleQubitGate): + name = "Z" + matrix = mat.ZMatrix + + def __init__(self, pos: int): + FixedGate.__init__(self, pos) + + +# # # # # # # # # # # # # # # Sqrt Paulis # # # # # # # # # # # # # # # +@QuantumGate.register('sx') +class SXGate(FixedGate, SingleQubitGate): + name = "SX" + matrix = mat.SXMatrix + + def __init__(self, pos: int): + FixedGate.__init__(self, pos) + + +@QuantumGate.register('sxdg') +class SXdgGate(FixedGate, SingleQubitGate): + name = "SXdg" + matrix = mat.SXMatrix.conj().T + + def __init__(self, pos: int): + FixedGate.__init__(self, pos) + self.symbol = "√X†" + + +@QuantumGate.register('sy') +class SYGate(FixedGate, SingleQubitGate): + name = "SY" + matrix = mat.SYMatrix + + def __init__(self, pos: int): + FixedGate.__init__(self, pos) + self.symbol = "√Y" + + def to_qasm(self): + return "ry(pi/2) q[%d];" % self.pos + + +@QuantumGate.register('sydg') +class SYdgGate(FixedGate, SingleQubitGate): + name = "SYdg" + matrix = mat.SYMatrix.conj().T + + def __init__(self, pos: int): + FixedGate.__init__(self, pos) + self.symbol = "√Y†" + + def to_qasm(self): + return "ry(-pi/2) q[%d]" % self.pos + + +@QuantumGate.register('s') +class SGate(SingleQubitGate, FixedGate): + """SZ""" + name = "S" + matrix = mat.SMatrix + + def __init__(self, pos: int): + FixedGate.__init__(self, pos) + + +@QuantumGate.register('sdg') +class SdgGate(SingleQubitGate, FixedGate): + name = "Sdg" + matrix = mat.SMatrix.conj().T + + def __init__(self, pos: int): + FixedGate.__init__(self, pos) + + +@QuantumGate.register('t') +class TGate(SingleQubitGate, FixedGate): + name = "T" + matrix = mat.TMatrix + + def __init__(self, pos: int): + FixedGate.__init__(self, pos) + + +@QuantumGate.register('tdg') +class TdgGate(SingleQubitGate, FixedGate): + name = "Tdg" + matrix = mat.TMatrix.conj().T + + def __init__(self, pos: int): + FixedGate.__init__(self, pos) + + +# # # # # # # # # # # # # Pauli Linear Combinations # # # # # # # # # # # # # +@QuantumGate.register('h') +class HGate(SingleQubitGate, FixedGate): + """ (X+Z)/sqrt(2) """ + name = "H" + matrix = mat.HMatrix + + def __init__(self, pos: int): + FixedGate.__init__(self, pos) + + +@QuantumGate.register('w') +class WGate(FixedGate, SingleQubitGate): + """ (X+Y)/sqrt(2) """ + name = "W" + matrix = mat.WMatrix + + def __init__(self, pos: int): + FixedGate.__init__(self, pos) + self.symbol = "W" + + def to_qasm(self): + return "rz(-pi/4) q[%d];\nrx(pi) q[%d];\nrz(pi/4) q[%d]" % ( + self.pos, + self.pos, + self.pos, + ) + + +@QuantumGate.register('sw') +class SWGate(FixedGate, SingleQubitGate): + name = "SW" + matrix = mat.SWMatrix + + def __init__(self, pos: int): + FixedGate.__init__(self, pos) + self.symbol = "√W" + + def to_qasm(self): + return "rz(-pi/4) q[%d];\nrx(pi/2) q[%d];\nrz(pi/4) q[%d]" % ( + self.pos, + self.pos, + self.pos, + ) + + +@QuantumGate.register('swdg') +class SWdgGate(FixedGate, SingleQubitGate): + name = "SWdg" + matrix = mat.SWMatrix + + def __init__(self, pos: int): + FixedGate.__init__(self, pos) + self.symbol = "√W†" + + def to_qasm(self): + return "rz(-pi/4) q[%d];\nrx(-pi/2) q[%d];\nrz(pi/4) q[%d]" % ( + self.pos, + self.pos, + self.pos, + ) + + +# # # # # # # # # # # # # Rotations # # # # # # # # # # # # # +@QuantumGate.register('rx') +class RXGate(ParametricGate, SingleQubitGate): + name = "RX" + + def __init__(self, pos: int, paras: float = 0.): + ParametricGate.__init__(self, pos, paras=paras) + + @property + def matrix(self): + return mat.rx_mat(self.paras) + + +@QuantumGate.register('ry') +class RYGate(ParametricGate, SingleQubitGate): + name = "RY" + + def __init__(self, pos: int, paras: float = 0.): + ParametricGate.__init__(self, pos, paras=paras) + + @property + def matrix(self): + return mat.ry_mat(self.paras) + + +@QuantumGate.register('rz') +class RZGate(ParametricGate, SingleQubitGate): + name = "RZ" + + def __init__(self, pos: int, paras: float = 0.): + ParametricGate.__init__(self, pos, paras=paras) + + @property + def matrix(self): + return mat.rz_mat(self.paras) + + +@SingleQubitGate.register(name='p') +class PhaseGate(SingleQubitGate): + """Ally of rz gate, with a different name and global phase.""" + name = "P" + + def __init__(self, pos: int, paras: float = 0.0): + super().__init__(pos, paras=paras) + + @property + def matrix(self): + return mat.pmatrix(self.paras) + + @property + def named_paras(self) -> Dict: + return {'phase': self.paras} + + +@QuantumGate.register('rxx') +class RXXGate(ParametricGate): + name = "RXX" + + def __init__(self, q1: int, q2: int, paras: float = 0.): + ParametricGate.__init__(self, [q1, q2], paras=paras) + + @property + def matrix(self): + return mat.rxx_mat(self.paras) + + @property + def named_pos(self) -> Dict: + return {'pos': self.pos} + + +@QuantumGate.register('ryy') +class RYYGate(ParametricGate): + name = "RYY" + + def __init__(self, q1: int, q2: int, paras: float = 0.): + ParametricGate.__init__(self, [q1, q2], paras=paras) + + @property + def matrix(self): + return mat.ryy_mat(self.paras) + + @property + def named_pos(self) -> Dict: + return {'pos': self.pos} + + +@QuantumGate.register('rzz') +class RZZGate(ParametricGate): + name = "RZZ" + + def __init__(self, q1: int, q2: int, paras: float = 0.): + ParametricGate.__init__(self, [q1, q2], paras=paras) + + @property + def matrix(self): + return mat.rzz_mat(self.paras) + + @property + def named_pos(self) -> Dict: + return {'pos': self.pos} + + +# # # # # # # # # # # # # Ctrl-Paulis # # # # # # # # # # # # # +# TODO: implement these by using the META of CtrlGate +@QuantumGate.register('cx') +class CXGate(_C11Gate, FixedGate): + name = "CX" + + def __init__(self, ctrl: int, targ: int): + _C11Gate.__init__(self, "X", [ctrl], [targ], None, tar_matrix=mat.XMatrix) + self.symbol = "+" + + +@QuantumGate.register('cy') +class CYGate(_C11Gate, FixedGate): + name = "CY" + + def __init__(self, ctrl: int, targ: int): + _C11Gate.__init__(self, "Y", [ctrl], [targ], None, tar_matrix=mat.YMatrix) + + +@QuantumGate.register('cz') +class CZGate(_C11Gate, FixedGate): + name = "CZ" + + def __init__(self, ctrl: int, targ: int): + _C11Gate.__init__(self, "Z", [ctrl], [targ], None, tar_matrix=mat.ZMatrix) + + +@QuantumGate.register('cs') +class CSGate(_C11Gate, FixedGate): + name = "CS" + + def __init__(self, ctrl: int, targ: int): + _C11Gate.__init__(self, "S", [ctrl], [targ], None, tar_matrix=mat.SMatrix) + + def to_qasm(self): + return "cp(pi/2) " + "q[%d],q[%d]" % (self.pos[0], self.pos[1]) + + +@QuantumGate.register('ct') +class CTGate(_C11Gate, FixedGate): + name = "CT" + + def __init__(self, ctrl: int, targ: int): + _C11Gate.__init__(self, "T", [ctrl], [targ], None, tar_matrix=mat.TMatrix) + + def to_qasm(self): + return "cp(pi/4) " + "q[%d],q[%d]" % (self.pos[0], self.pos[1]) + + +# # # # # # # # # # # # # Ctrl-Rotation # # # # # # # # # # # # # +# note: this is the only ctrl-gate that is not a FixedGate +@QuantumGate.register('cp') +class CPGate(_C11Gate): + name = "CP" + + def __init__(self, ctrl: int, targ: int, paras): + _C11Gate.__init__(self, "P", [ctrl], [targ], paras, tar_matrix=mat.pmatrix) + + @property + def named_paras(self) -> Dict: + return {'theta': self.paras} + + +# # # # # # # # # # # # # MultiCtrl-Paulis # # # # # # # # # # # # # +@QuantumGate.register('mcx') +class MCXGate(ControlledGate, FixedGate): + name = "MCX" + + def __init__(self, ctrls, targ: int): + ControlledGate.__init__(self, "X", ctrls, [targ], None, tar_matrix=mat.XMatrix) + + +@QuantumGate.register('mcy') +class MCYGate(ControlledGate, FixedGate): + name = "MCY" + + def __init__(self, ctrls, targ: int): + ControlledGate.__init__(self, "Y", ctrls, [targ], None, tar_matrix=mat.YMatrix) + + +@QuantumGate.register('mcz') +class MCZGate(ControlledGate, FixedGate): + name = "MCZ" + + def __init__(self, ctrls, targ: int): + ControlledGate.__init__(self, "Z", ctrls, [targ], None, tar_matrix=mat.ZMatrix) + + +@QuantumGate.register('ccx') +class ToffoliGate(ControlledGate, FixedGate): + name = "CCX" + + def __init__(self, ctrl1: int, ctrl2: int, targ: int): + ControlledGate.__init__(self, "X", [ctrl1, ctrl2], [targ], None, tar_matrix=mat.XMatrix) + + +# # # # # # # # # # # # # SWAPs # # # # # # # # # # # # # +@QuantumGate.register('swap') +class SwapGate(FixedGate, MultiQubitGate): + name = "SWAP" + matrix = mat.SwapMatrix + + def __init__(self, q1: int, q2: int): + super().__init__([q1, q2]) + self.symbol = "x" + + def get_targ_matrix(self, reverse_order=False): + return self.matrix + + @property + def named_pos(self) -> Dict: + return {'pos': self.pos} + + +@QuantumGate.register('iswap') +class ISwapGate(FixedGate, MultiQubitGate): + name = "iSWAP" + matrix = mat.ISwapMatrix + + def __init__(self, q1: int, q2: int): + super().__init__([q1, q2]) + self.symbol = "(x)" + + def get_targ_matrix(self, reverse_order=False): + return self.matrix + + @property + def named_pos(self) -> Dict: + return {'pos': self.pos} + + +@QuantumGate.register('cswap') +class FredkinGate(ControlledGate, FixedGate): + name = "CSWAP" + + def __init__(self, ctrl: int, targ1: int, targ2: int): + ControlledGate.__init__(self, "SWAP", [ctrl], [targ1, targ2], None, tar_matrix=mat.SwapMatrix) + + +QuantumGate.register_gate(ToffoliGate, 'toffoli') +QuantumGate.register_gate(FredkinGate, 'fredkin') diff --git a/quafu/elements/element_gates/pauli.py b/quafu/elements/element_gates/pauli.py index e43af7ef..8272b489 100644 --- a/quafu/elements/element_gates/pauli.py +++ b/quafu/elements/element_gates/pauli.py @@ -1,158 +1,3 @@ -import numpy as np +from .element_gates import XGate, YGate, ZGate, IdGate -from quafu.elements.matrices import XMatrix, YMatrix, ZMatrix, WMatrix, SWMatrix -from quafu.elements.quantum_gate import FixedGate, SingleQubitGate, QuantumGate - -__all__ = ['IdGate', 'XGate', 'YGate', 'ZGate', - 'WGate', 'SWGate', 'SWdgGate', - 'SXGate', 'SYGate', 'SXdgGate', 'SYdgGate'] # hint: "SZ" gate is S contained in Clifford gates - - -@QuantumGate.register('id') -class IdGate(FixedGate, SingleQubitGate): - name = "Id" - matrix = XMatrix - - def __init__(self, pos: int): - FixedGate.__init__(self, pos) - - -@QuantumGate.register('x') -class XGate(FixedGate, SingleQubitGate): - name = "X" - matrix = XMatrix - - def __init__(self, pos: int): - FixedGate.__init__(self, pos) - - -@QuantumGate.register('y') -class YGate(FixedGate, SingleQubitGate): - name = "Y" - matrix = YMatrix - - def __init__(self, pos: int): - FixedGate.__init__(self, pos) - - -@QuantumGate.register('z') -class ZGate(FixedGate, SingleQubitGate): - name = "Z" - matrix = ZMatrix - - def __init__(self, pos: int): - FixedGate.__init__(self, pos) - - -@QuantumGate.register('w') -class WGate(FixedGate, SingleQubitGate): - """ (X+Y)/sqrt(2) """ - name = "W" - matrix = WMatrix - - def __init__(self, pos: int): - FixedGate.__init__(self, pos) - self.symbol = "W" - - def to_qasm(self): - return "rz(-pi/4) q[%d];\nrx(pi) q[%d];\nrz(pi/4) q[%d]" % ( - self.pos, - self.pos, - self.pos, - ) - - -@QuantumGate.register('sw') -class SWGate(FixedGate, SingleQubitGate): - name = "SW" - matrix = SWMatrix - - def __init__(self, pos: int): - FixedGate.__init__(self, pos) - self.symbol = "√W" - - def to_qasm(self): - return "rz(-pi/4) q[%d];\nrx(pi/2) q[%d];\nrz(pi/4) q[%d]" % ( - self.pos, - self.pos, - self.pos, - ) - - -@QuantumGate.register('swdg') -class SWdgGate(FixedGate, SingleQubitGate): - name = "SWdg" - matrix = SWMatrix - - def __init__(self, pos: int): - FixedGate.__init__(self, pos) - self.symbol = "√W†" - - def to_qasm(self): - return "rz(-pi/4) q[%d];\nrx(-pi/2) q[%d];\nrz(pi/4) q[%d]" % ( - self.pos, - self.pos, - self.pos, - ) - - -@QuantumGate.register('sx') -class SXGate(FixedGate, SingleQubitGate): - name = "SX" - matrix = np.array( - [[0.5 + 0.5j, 0.5 - 0.5j], [0.5 - 0.5j, 0.5 + 0.5j]], dtype=complex - ) - - def __init__(self, pos: int): - FixedGate.__init__(self, pos) - - -@QuantumGate.register('sxdg') -class SXdgGate(FixedGate, SingleQubitGate): - name = "SXdg" - matrix = SXGate.matrix.conj().T - - def __init__(self, pos: int): - FixedGate.__init__(self, pos) - self.symbol = "√X†" - - -@QuantumGate.register('sy') -class SYGate(FixedGate, SingleQubitGate): - name = "SY" - matrix = np.array( - [[0.5 + 0.5j, -0.5 - 0.5j], [0.5 + 0.5j, 0.5 + 0.5j]], dtype=complex - ) - - def __init__(self, pos: int): - FixedGate.__init__(self, pos) - self.symbol = "√Y" - - def to_qasm(self): - return "ry(pi/2) q[%d];" % self.pos - - -@QuantumGate.register('sydg') -class SYdgGate(FixedGate, SingleQubitGate): - name = "SYdg" - matrix = SYGate.matrix.conj().T - - def __init__(self, pos: int): - FixedGate.__init__(self, pos) - self.symbol = "√Y†" - - def to_qasm(self): - return "ry(-pi/2) q[%d]" % self.pos - - -# SingleQubitGate.register_gate(IdGate) -# SingleQubitGate.register_gate(XGate) -# SingleQubitGate.register_gate(YGate) -# SingleQubitGate.register_gate(ZGate) -# SingleQubitGate.register_gate(WGate) -# SingleQubitGate.register_gate(SWGate) -# SingleQubitGate.register_gate(SWdgGate) -# SingleQubitGate.register_gate(SXGate) -# SingleQubitGate.register_gate(SXdgGate) -# SingleQubitGate.register_gate(SYGate) -# SingleQubitGate.register_gate(SYdgGate) +__all__ = ['IdGate', 'XGate', 'YGate', 'ZGate'] # hint: "SZ" gate is S contained in Clifford gates From 2e3b9dd1554b89fa677c27b0ff0a4753ff3cf7eb Mon Sep 17 00:00:00 2001 From: chensgit169 Date: Sat, 23 Dec 2023 16:02:26 +0800 Subject: [PATCH 03/13] chore: move actual gate classes into a single file --- quafu/elements/element_gates/rotation.py | 107 ----------------------- quafu/elements/element_gates/swap.py | 40 --------- 2 files changed, 147 deletions(-) delete mode 100644 quafu/elements/element_gates/rotation.py delete mode 100644 quafu/elements/element_gates/swap.py diff --git a/quafu/elements/element_gates/rotation.py b/quafu/elements/element_gates/rotation.py deleted file mode 100644 index 1200d4d9..00000000 --- a/quafu/elements/element_gates/rotation.py +++ /dev/null @@ -1,107 +0,0 @@ -from typing import Dict - -from quafu.elements.matrices import rx_mat, ry_mat, rz_mat, rxx_mat, ryy_mat, rzz_mat, pmatrix -from ..quantum_gate import QuantumGate, SingleQubitGate, ParametricGate - -__all__ = ['RXGate', 'RYGate', 'RZGate', 'RXXGate', 'RYYGate', 'RZZGate', 'PhaseGate'] - - -@QuantumGate.register('rx') -class RXGate(ParametricGate, SingleQubitGate): - name = "RX" - - def __init__(self, pos: int, paras: float = 0.): - ParametricGate.__init__(self, pos, paras=paras) - - @property - def matrix(self): - return rx_mat(self.paras) - - -@QuantumGate.register('ry') -class RYGate(ParametricGate, SingleQubitGate): - name = "RY" - - def __init__(self, pos: int, paras: float = 0.): - ParametricGate.__init__(self, pos, paras=paras) - - @property - def matrix(self): - return ry_mat(self.paras) - - -@QuantumGate.register('rz') -class RZGate(ParametricGate, SingleQubitGate): - name = "RZ" - - def __init__(self, pos: int, paras: float = 0.): - ParametricGate.__init__(self, pos, paras=paras) - - @property - def matrix(self): - return rz_mat(self.paras) - - -@QuantumGate.register('rxx') -class RXXGate(ParametricGate): - name = "RXX" - - def __init__(self, q1: int, q2: int, paras: float = 0.): - ParametricGate.__init__(self, [q1, q2], paras=paras) - - @property - def matrix(self): - return rxx_mat(self.paras) - - @property - def named_pos(self) -> Dict: - return {'pos': self.pos} - - -@QuantumGate.register('ryy') -class RYYGate(ParametricGate): - name = "RYY" - - def __init__(self, q1: int, q2: int, paras: float = 0.): - ParametricGate.__init__(self, [q1, q2], paras=paras) - - @property - def matrix(self): - return ryy_mat(self.paras) - - @property - def named_pos(self) -> Dict: - return {'pos': self.pos} - - -@QuantumGate.register('rzz') -class RZZGate(ParametricGate): - name = "RZZ" - - def __init__(self, q1: int, q2: int, paras: float = 0.): - ParametricGate.__init__(self, [q1, q2], paras=paras) - - @property - def matrix(self): - return rzz_mat(self.paras) - - @property - def named_pos(self) -> Dict: - return {'pos': self.pos} - - -@SingleQubitGate.register(name='p') -class PhaseGate(SingleQubitGate): - """Ally of rz gate, but with a different name and global phase.""" - name = "P" - - def __init__(self, pos: int, paras: float = 0.0): - super().__init__(pos, paras=paras) - - @property - def matrix(self): - return pmatrix(self.paras) - - @property - def named_paras(self) -> Dict: - return {'phase': self.paras} diff --git a/quafu/elements/element_gates/swap.py b/quafu/elements/element_gates/swap.py deleted file mode 100644 index d0ea21d0..00000000 --- a/quafu/elements/element_gates/swap.py +++ /dev/null @@ -1,40 +0,0 @@ -from ..quantum_gate import FixedGate, MultiQubitGate, QuantumGate -from quafu.elements.matrices import ISwapMatrix, SwapMatrix - -from typing import Dict - -__all__ = ['ISwapGate', 'SwapGate'] - - -@QuantumGate.register('iswap') -class ISwapGate(FixedGate, MultiQubitGate): - name = "iSWAP" - matrix = ISwapMatrix - - def __init__(self, q1: int, q2: int): - super().__init__([q1, q2]) - self.symbol = "(x)" - - def get_targ_matrix(self, reverse_order=False): - return self.matrix - - @property - def named_pos(self) -> Dict: - return {'pos': self.pos} - - -@QuantumGate.register('swap') -class SwapGate(FixedGate, MultiQubitGate): - name = "SWAP" - matrix = SwapMatrix - - def __init__(self, q1: int, q2: int): - super().__init__([q1, q2]) - self.symbol = "x" - - def get_targ_matrix(self, reverse_order=False): - return self.matrix - - @property - def named_pos(self) -> Dict: - return {'pos': self.pos} From eefaa04446c5d2f1dbec4e800369cbd8912ec3e8 Mon Sep 17 00:00:00 2001 From: chensgit169 Date: Sat, 23 Dec 2023 16:03:36 +0800 Subject: [PATCH 04/13] feat: implement targ_matrix of control-gate --- quafu/elements/quantum_gate.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/quafu/elements/quantum_gate.py b/quafu/elements/quantum_gate.py index 42168624..c537bcc7 100644 --- a/quafu/elements/quantum_gate.py +++ b/quafu/elements/quantum_gate.py @@ -1,5 +1,5 @@ from abc import ABC, abstractmethod -from typing import List, Union, Iterable, Dict +from typing import List, Union, Iterable, Dict, Callable import numpy as np @@ -164,7 +164,7 @@ def __init__(self, targe_name, ctrls: List[int], targs: List[int], paras, tar_ma dim = 2 ** n ctrl_dim = dim - targ_dim self._matrix = np.eye(dim, dtype=complex) - self._matrix[ctrl_dim:, ctrl_dim:] = tar_matrix + self._matrix[ctrl_dim:, ctrl_dim:] = self.targ_matrix self._matrix = reorder_matrix(self._matrix, self.pos) if paras is not None: @@ -187,6 +187,13 @@ def ct_nums(self): num = targ_num + ctrl_num return ctrl_num, targ_num, num + @property + def targ_matrix(self): + if isinstance(self._targ_matrix, Callable): + return self._targ_matrix(self.paras) + else: + return self._targ_matrix + def get_targ_matrix(self, reverse_order=False): targ_matrix = self._targ_matrix if reverse_order and (len(self.targs) > 1): From 03bee5f9e3f3b2591238b0c86700f2913e4766eb Mon Sep 17 00:00:00 2001 From: chensgit169 Date: Sat, 23 Dec 2023 16:04:24 +0800 Subject: [PATCH 05/13] chore: update gate unitest --- tests/quafu/instruction/gates_test.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/quafu/instruction/gates_test.py b/tests/quafu/instruction/gates_test.py index f79d6611..78c746a6 100644 --- a/tests/quafu/instruction/gates_test.py +++ b/tests/quafu/instruction/gates_test.py @@ -4,7 +4,6 @@ import quafu.elements as qe import quafu.elements.element_gates as qeg -import quafu.elements.element_gates.rotation class TestGate(unittest.TestCase): @@ -32,7 +31,7 @@ def test_instances(self): tdg = qeg.TdgGate(pos=0) # Rotation - ph = quafu.elements.element_gates.rotation.PhaseGate(pos=0, paras=pi) + ph = qeg.PhaseGate(pos=0, paras=pi) rx = qeg.RXGate(pos=0, paras=pi) ry = qeg.RYGate(pos=0, paras=pi) rz = qeg.RZGate(pos=0, paras=pi) @@ -61,7 +60,7 @@ def test_instances(self): h, s, sdg, t, tdg, ph, rx, ry, rz, rxx, ryy, rzz, swap, iswap, fredkin, cx, cy, cz, cs, ct, cp, mcx, mcy, mcz, toffoli] - self.assertEqual(len(all_gates), len(gate_classes)) + self.assertTrue(len(all_gates) <= len(gate_classes)) for gate in all_gates: self.assertIn(gate.name.lower(), gate_classes) From cb173992e8c4baad7f87c1bdcbc69ab3aae52ce2 Mon Sep 17 00:00:00 2001 From: chensgit169 Date: Sat, 23 Dec 2023 16:05:16 +0800 Subject: [PATCH 06/13] chore: nothing --- quafu/algorithms/templates/amplitude.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quafu/algorithms/templates/amplitude.py b/quafu/algorithms/templates/amplitude.py index 3dfc5082..c72ff18e 100644 --- a/quafu/algorithms/templates/amplitude.py +++ b/quafu/algorithms/templates/amplitude.py @@ -240,4 +240,4 @@ def _get_alpha_y(a, n, k): division = np.where(denominator != 0.0, division, 0.0) - return 2 * np.arcsin(np.sqrt(division)) \ No newline at end of file + return 2 * np.arcsin(np.sqrt(division)) From 20dab0ec07d3b95c6e8474a5c1f0a5b753cdc413 Mon Sep 17 00:00:00 2001 From: chensgit169 Date: Sat, 23 Dec 2023 16:47:30 +0800 Subject: [PATCH 07/13] chore: implement symbol as property so that parameters can be auto-updated --- quafu/elements/quantum_gate.py | 51 ++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/quafu/elements/quantum_gate.py b/quafu/elements/quantum_gate.py index c537bcc7..9712f053 100644 --- a/quafu/elements/quantum_gate.py +++ b/quafu/elements/quantum_gate.py @@ -8,46 +8,51 @@ class QuantumGate(Instruction, ABC): - """Base class for standard and combined quantum gates. + """Base class for standard and combined quantum gates, namely unitary operation + upon quantum states. Attributes: + pos: Position of this gate in the circuit. + paras: Parameters of this gate. + Properties: + matrix: Matrix representation of this gate. """ gate_classes = {} def __init__(self, pos: PosType, paras: Union[float, List[float]] = None, + matrix: Union[np.ndarray, Callable] = None, ): super().__init__(pos, paras) + self._matrix = matrix - if paras is not None: - if isinstance(paras, Iterable): - self.symbol = "%s(" % self.name + ",".join(["%.3f" % para for para in self.paras]) + ")" + @property + def symbol(self): + if self.paras is not None: + if isinstance(self.paras, Iterable): + symbol = "%s(" % self.name + ",".join(["%.3f" % para for para in self.paras]) + ")" else: - self.symbol = "%s(%.3f)" % (self.name, paras) + symbol = "%s(%.3f)" % (self.name, self.paras) else: - self.symbol = "%s" % self.name + symbol = "%s" % self.name + return symbol def update_params(self, paras: Union[float, List[float]]): """Update parameters of this gate""" if paras is None: return self.paras = paras - if isinstance(paras, Iterable): - self.symbol = ( - "%s(" % self.name - + ",".join(["%.3f" % para for para in self.paras]) - + ")" - ) - else: - self.symbol = "%s(%.3f)" % (self.name, paras) @property @abstractmethod def matrix(self): - raise NotImplementedError("Matrix is not implemented for %s" % self.__class__.__name__ + - ", this should never happen.") + if self._matrix is not None: + return self._matrix + else: + raise NotImplementedError("Matrix is not implemented for %s" % self.__class__.__name__ + + ", this should never happen.") @classmethod def register_gate(cls, subclass, name: str = None): @@ -167,13 +172,17 @@ def __init__(self, targe_name, ctrls: List[int], targs: List[int], paras, tar_ma self._matrix[ctrl_dim:, ctrl_dim:] = self.targ_matrix self._matrix = reorder_matrix(self._matrix, self.pos) - if paras is not None: - if isinstance(paras, Iterable): - self.symbol = "%s(" % self.targ_name + ",".join(["%.3f" % para for para in self.paras]) + ")" + @property + def symbol(self): + name = self.targ_name + if self.paras is not None: + if isinstance(self.paras, Iterable): + symbol = "%s(" % name + ",".join(["%.3f" % para for para in self.paras]) + ")" else: - self.symbol = "%s(%.3f)" % (self.targ_name, paras) + symbol = "%s(%.3f)" % (name, self.paras) else: - self.symbol = "%s" % self.targ_name + symbol = "%s" % name + return symbol @property def matrix(self): From 6321a8a900b201cb47e3113eed5c7bc25f097be4 Mon Sep 17 00:00:00 2001 From: chensgit169 Date: Sat, 23 Dec 2023 16:54:06 +0800 Subject: [PATCH 08/13] chore: enhance comments and annotations --- quafu/elements/quantum_gate.py | 58 ++++++++++++---------------------- 1 file changed, 20 insertions(+), 38 deletions(-) diff --git a/quafu/elements/quantum_gate.py b/quafu/elements/quantum_gate.py index 9712f053..bcad86a0 100644 --- a/quafu/elements/quantum_gate.py +++ b/quafu/elements/quantum_gate.py @@ -56,6 +56,10 @@ def matrix(self): @classmethod def register_gate(cls, subclass, name: str = None): + """Register a new gate class into gate_classes. + + This method is used as a decorator. + """ assert issubclass(subclass, cls) name = str(subclass.name).lower() if name is None else name @@ -68,6 +72,7 @@ def register_gate(cls, subclass, name: str = None): @classmethod def register(cls, name: str = None): + """Decorator for register_gate.""" def wrapper(subclass): cls.register_gate(subclass, name) return subclass @@ -75,7 +80,11 @@ def wrapper(subclass): return wrapper def __str__(self): - properties_names = ['pos', 'paras', 'matrix'] + # only when the gate is a known(named) gate, the matrix is not shown + if self.name.lower() in self.gate_classes: + properties_names = ['pos', 'paras'] + else: + properties_names = ['pos', 'paras', 'matrix'] properties_values = [getattr(self, x) for x in properties_names] return "%s:\n%s" % (self.__class__.__name__, '\n'.join( [f"{x} = {repr(properties_values[i])}" for i, x in enumerate(properties_names)])) @@ -84,6 +93,7 @@ def __repr__(self): return f"{self.__class__.__name__}" def to_qasm(self): + # TODO: support register naming qstr = "%s" % self.name.lower() if self.paras is not None: @@ -152,6 +162,15 @@ def named_pos(self) -> Dict: return {'pos': self.pos} +class FixedGate(QuantumGate, ABC): + def __init__(self, pos): + super().__init__(pos=pos, paras=None) + + @property + def named_paras(self) -> Dict: + return {} + + class ControlledGate(MultiQubitGate, ABC): """ Controlled gate class, where the matrix act non-trivially on target qubits""" @@ -217,40 +236,3 @@ def get_targ_matrix(self, reverse_order=False): @property def named_pos(self) -> Dict: return {'ctrls': self.ctrls, 'targs': self.targs} - - -# class ParaSingleQubitGate(SingleQubitGate, ABC): -# def __init__(self, pos, paras: float): -# if paras is None: -# raise ValueError("`paras` can not be None for ParaSingleQubitGate") -# elif isinstance(paras, int): -# paras = float(paras) -# -# if not isinstance(paras, float): -# raise TypeError(f"`paras` must be float or int for ParaSingleQubitGate, " -# f"instead of {type(paras)}") -# super().__init__(pos, paras=paras) -# -# @property -# def named_paras(self) -> Dict: -# return {'paras': self.paras} - -# class FixedMultiQubitGate(MultiQubitGate, ABC): -# def __init__(self, pos: List[int]): -# super().__init__(pos=pos, paras=None) - - -# class ParaMultiQubitGate(MultiQubitGate, ABC): -# def __init__(self, pos, paras): -# if paras is None: -# raise ValueError("`paras` can not be None for ParaMultiQubitGate") -# super().__init__(pos, paras) - - -class FixedGate(QuantumGate, ABC): - def __init__(self, pos): - super().__init__(pos=pos, paras=None) - - @property - def named_paras(self) -> Dict: - return {} From 50ae0a8a9fc448a1c919015e98b63e2013e9ef9c Mon Sep 17 00:00:00 2001 From: chensgit169 Date: Sat, 23 Dec 2023 17:01:41 +0800 Subject: [PATCH 09/13] chore: add __all__ --- quafu/elements/quantum_gate.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/quafu/elements/quantum_gate.py b/quafu/elements/quantum_gate.py index bcad86a0..d816d301 100644 --- a/quafu/elements/quantum_gate.py +++ b/quafu/elements/quantum_gate.py @@ -7,6 +7,9 @@ from .instruction import Instruction, PosType +__all__ = ['QuantumGate', 'FixedGate', 'ParametricGate', 'SingleQubitGate', 'MultiQubitGate', 'ControlledGate'] + + class QuantumGate(Instruction, ABC): """Base class for standard and combined quantum gates, namely unitary operation upon quantum states. @@ -110,7 +113,7 @@ def to_qasm(self): return qstr -# Gate types are statically implemented to support type identification +# Gate types below are statically implemented to support type identification # and provide shared attributes. However, single/multi qubit may be # inferred from ``pos``, while para/fixed type may be inferred by ``paras``. # Therefore, these types may be (partly) deprecated in the future. From 1641fc345e11d23326e3f201beafbb895d943650 Mon Sep 17 00:00:00 2001 From: chensgit169 Date: Sat, 23 Dec 2023 17:18:00 +0800 Subject: [PATCH 10/13] chore: return gates in test function --- tests/quafu/instruction/gates_test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/quafu/instruction/gates_test.py b/tests/quafu/instruction/gates_test.py index 78c746a6..9b5d2042 100644 --- a/tests/quafu/instruction/gates_test.py +++ b/tests/quafu/instruction/gates_test.py @@ -63,6 +63,7 @@ def test_instances(self): self.assertTrue(len(all_gates) <= len(gate_classes)) for gate in all_gates: self.assertIn(gate.name.lower(), gate_classes) + return all_gates # TODO: test plots # for gate in all_gates: From 008eb336da7aaa12a08c71261d9f13cda94b72e2 Mon Sep 17 00:00:00 2001 From: chensgit169 Date: Sat, 23 Dec 2023 17:44:29 +0800 Subject: [PATCH 11/13] fix: add symbol setter --- quafu/elements/quantum_gate.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/quafu/elements/quantum_gate.py b/quafu/elements/quantum_gate.py index d816d301..33cecd97 100644 --- a/quafu/elements/quantum_gate.py +++ b/quafu/elements/quantum_gate.py @@ -30,9 +30,12 @@ def __init__(self, ): super().__init__(pos, paras) self._matrix = matrix + self._symbol = None @property def symbol(self): + if self._symbol is not None: + return self._symbol if self.paras is not None: if isinstance(self.paras, Iterable): symbol = "%s(" % self.name + ",".join(["%.3f" % para for para in self.paras]) + ")" @@ -42,6 +45,10 @@ def symbol(self): symbol = "%s" % self.name return symbol + @symbol.setter + def symbol(self, symbol): + self._symbol = symbol + def update_params(self, paras: Union[float, List[float]]): """Update parameters of this gate""" if paras is None: From 8004e6b0406bbf1073460351ec55af9b81962eec Mon Sep 17 00:00:00 2001 From: chensgit169 Date: Sat, 23 Dec 2023 21:26:38 +0800 Subject: [PATCH 12/13] fix: add symbol setter of control-gate --- quafu/elements/quantum_gate.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/quafu/elements/quantum_gate.py b/quafu/elements/quantum_gate.py index 33cecd97..d4ba8e45 100644 --- a/quafu/elements/quantum_gate.py +++ b/quafu/elements/quantum_gate.py @@ -213,6 +213,10 @@ def symbol(self): symbol = "%s" % name return symbol + @symbol.setter + def symbol(self, symbol): + self._symbol = symbol + @property def matrix(self): # TODO: update matrix when paras of controlled-gate changed From a2e8644930080b603f5edc94f3a4600141a4c0b9 Mon Sep 17 00:00:00 2001 From: chensgit169 Date: Sat, 23 Dec 2023 21:33:00 +0800 Subject: [PATCH 13/13] chore: add test of plotting gates --- tests/quafu/instruction/gates_test.py | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/tests/quafu/instruction/gates_test.py b/tests/quafu/instruction/gates_test.py index 9b5d2042..4a8a6a66 100644 --- a/tests/quafu/instruction/gates_test.py +++ b/tests/quafu/instruction/gates_test.py @@ -1,9 +1,11 @@ import unittest from numpy import pi +import matplotlib.pyplot as plt import quafu.elements as qe import quafu.elements.element_gates as qeg +from quafu import QuantumCircuit class TestGate(unittest.TestCase): @@ -65,16 +67,11 @@ def test_instances(self): self.assertIn(gate.name.lower(), gate_classes) return all_gates -# TODO: test plots -# for gate in all_gates: -# print(gate.name) -# qc = QuantumCircuit(4) -# qc.add_gate(gate) -# qc.measure() -# qc.plot_circuit(title=gate.__class__.__name__) -# plt.savefig('./icons/%s.png' % gate.name, dpi=400, transparent=True) -# plt.close() - - -if __name__ == '__main__': - unittest.main() + def test_plots(self): + all_gates = self.test_instances() + for gate in all_gates: + qc = QuantumCircuit(4) + qc.add_gate(gate) + qc.measure() + qc.plot_circuit(title=gate.__class__.__name__) + plt.close()