diff --git a/.gitignore b/.gitignore index 18cb8929a..7dfa8fe1a 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ .hypothesis/ .venv/ .vscode/ +.idea/ .mypy_cache/ .DS_Store docs/source/autogen diff --git a/bqskit/ir/gates/constant/__init__.py b/bqskit/ir/gates/constant/__init__.py index 5492fa12a..b6bd7a1e0 100644 --- a/bqskit/ir/gates/constant/__init__.py +++ b/bqskit/ir/gates/constant/__init__.py @@ -8,6 +8,7 @@ from bqskit.ir.gates.constant.clock import ClockGate from bqskit.ir.gates.constant.cpi import CPIGate from bqskit.ir.gates.constant.cs import CSGate +from bqskit.ir.gates.constant.csdg import CSDGGate from bqskit.ir.gates.constant.csum import CSUMGate from bqskit.ir.gates.constant.ct import CTGate from bqskit.ir.gates.constant.cx import CNOTGate @@ -17,6 +18,7 @@ from bqskit.ir.gates.constant.h import HGate from bqskit.ir.gates.constant.identity import IdentityGate from bqskit.ir.gates.constant.iswap import ISwapGate +from bqskit.ir.gates.constant.iswapdg import ISwapDGGate from bqskit.ir.gates.constant.itoffoli import IToffoliGate from bqskit.ir.gates.constant.pd import PDGate from bqskit.ir.gates.constant.permutation import PermutationGate @@ -27,21 +29,28 @@ from bqskit.ir.gates.constant.sdg import SdgGate from bqskit.ir.gates.constant.shift import ShiftGate from bqskit.ir.gates.constant.sqrtcnot import SqrtCNOTGate +from bqskit.ir.gates.constant.sqrtcnotdg import SqrtCNOTDGGate from bqskit.ir.gates.constant.sqrtiswap import SqrtISwapGate +from bqskit.ir.gates.constant.sqrtiswapdg import SqrtISwapDGGate from bqskit.ir.gates.constant.subswap import SubSwapGate from bqskit.ir.gates.constant.swap import SwapGate from bqskit.ir.gates.constant.sx import SqrtXGate from bqskit.ir.gates.constant.sx import SXGate +from bqskit.ir.gates.constant.sxdg import SqrtXDGGate +from bqskit.ir.gates.constant.sxdg import SXDGGate from bqskit.ir.gates.constant.sycamore import SycamoreGate from bqskit.ir.gates.constant.t import TGate from bqskit.ir.gates.constant.tdg import TdgGate from bqskit.ir.gates.constant.unitary import ConstantUnitaryGate from bqskit.ir.gates.constant.x import XGate from bqskit.ir.gates.constant.xx import XXGate +from bqskit.ir.gates.constant.xxdg import XXDGGate from bqskit.ir.gates.constant.y import YGate from bqskit.ir.gates.constant.yy import YYGate +from bqskit.ir.gates.constant.yydg import YYDGGate from bqskit.ir.gates.constant.z import ZGate from bqskit.ir.gates.constant.zz import ZZGate +from bqskit.ir.gates.constant.zzdg import ZZDGGate __all__ = [ 'BGate', @@ -51,6 +60,7 @@ 'ClockGate', 'CPIGate', 'CSGate', + 'CSDGGate', 'CSUMGate', 'CTGate', 'CNOTGate', @@ -60,6 +70,7 @@ 'HGate', 'IdentityGate', 'ISwapGate', + 'ISwapDGGate', 'IToffoliGate', 'PDGate', 'PermutationGate', @@ -70,19 +81,26 @@ 'SdgGate', 'ShiftGate', 'SqrtCNOTGate', + 'SqrtCNOTDGGate', 'SqrtISwapGate', + 'SqrtISwapDGGate', 'SubSwapGate', 'SwapGate', 'SqrtXGate', 'SXGate', + 'SqrtXDGGate', + 'SXDGGate', 'SycamoreGate', 'TGate', 'TdgGate', 'ConstantUnitaryGate', 'XGate', 'XXGate', + 'XXDGGate', 'YGate', 'YYGate', + 'YYDGGate', 'ZGate', 'ZZGate', + 'ZZDGGate', ] diff --git a/bqskit/ir/gates/constant/cs.py b/bqskit/ir/gates/constant/cs.py index 6908c6891..2b0a403f3 100644 --- a/bqskit/ir/gates/constant/cs.py +++ b/bqskit/ir/gates/constant/cs.py @@ -1,6 +1,7 @@ """This module implements the CSGate.""" from __future__ import annotations +from bqskit.ir.gate import Gate from bqskit.ir.gates.constantgate import ConstantGate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix @@ -32,3 +33,21 @@ class CSGate(ConstantGate, QubitGate): [0, 0, 0, 1j], ], ) + + def get_qasm_gate_def(self) -> str: + """Returns a qasm gate definition block for this gate.""" + return ( + 'gate cs a,b\n' + '{\n' + '\tp(pi/4) a;\n' + '\tcx a, b;\n' + '\tp(-pi/4) b;\n' + '\tcx a, b;\n' + '\tp(pi/4) b;\n' + '}\n' + ) + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + from bqskit.ir.gates.constant.csdg import CSDGGate + return CSDGGate() diff --git a/bqskit/ir/gates/constant/csdg.py b/bqskit/ir/gates/constant/csdg.py new file mode 100644 index 000000000..43e6ca719 --- /dev/null +++ b/bqskit/ir/gates/constant/csdg.py @@ -0,0 +1,53 @@ +"""This module implements the CSDGGate.""" +from __future__ import annotations + +from bqskit.ir.gate import Gate +from bqskit.ir.gates.constantgate import ConstantGate +from bqskit.ir.gates.qubitgate import QubitGate +from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix + + +class CSDGGate(ConstantGate, QubitGate): + """ + The Controlled-S Dagger gate. + + The CS Dagger gate is given by the following unitary: + + .. math:: + + \\begin{pmatrix} + 1 & 0 & 0 & 0 \\\\ + 0 & 1 & 0 & 0 \\\\ + 0 & 0 & 1 & 0 \\\\ + 0 & 0 & 0 & -i \\\\ + \\end{pmatrix} + """ + + _num_qudits = 2 + _qasm_name = 'csdg' + _utry = UnitaryMatrix( + [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 1, 0], + [0, 0, 0, -1j], + ], + ) + + def get_qasm_gate_def(self) -> str: + """Returns a qasm gate definition block for this gate.""" + return ( + 'gate csdg a,b\n' + '{\n' + '\tp(-pi/4) a;\n' + '\tcx a, b;\n' + '\tp(pi/4) b;\n' + '\tcx a, b;\n' + '\tp(-pi/4) b;\n' + '}\n' + ) + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + from bqskit.ir.gates.constant.cs import CSGate + return CSGate() diff --git a/bqskit/ir/gates/constant/iswap.py b/bqskit/ir/gates/constant/iswap.py index d120d0f9d..149db672b 100644 --- a/bqskit/ir/gates/constant/iswap.py +++ b/bqskit/ir/gates/constant/iswap.py @@ -1,6 +1,7 @@ """This module implements the ISwapGate.""" from __future__ import annotations +from bqskit.ir.gate import Gate from bqskit.ir.gates.constantgate import ConstantGate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix @@ -46,3 +47,8 @@ def get_qasm_gate_def(self) -> str: '\th b;\n' '}\n' ) + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + from bqskit.ir.gates.constant.iswapdg import ISwapDGGate + return ISwapDGGate() diff --git a/bqskit/ir/gates/constant/iswapdg.py b/bqskit/ir/gates/constant/iswapdg.py new file mode 100644 index 000000000..1f2795c0b --- /dev/null +++ b/bqskit/ir/gates/constant/iswapdg.py @@ -0,0 +1,55 @@ +"""This module implements the ISwapDGGate.""" +from __future__ import annotations + +from bqskit.ir.gate import Gate +from bqskit.ir.gates.constantgate import ConstantGate +from bqskit.ir.gates.qubitgate import QubitGate +from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix + + +class ISwapDGGate(ConstantGate, QubitGate): + """ + The two qubit swap and phase iSWAP Dagger gate. + + The ISwap Dagger gate is given by the following unitary: + + .. math:: + + \\begin{pmatrix} + 1 & 0 & 0 & 0 \\\\ + 0 & 0 & -i & 0 \\\\ + 0 & -i & 0 & 0 \\\\ + 0 & 0 & 0 & 1 \\\\ + \\end{pmatrix} + """ + + _num_qudits = 2 + _qasm_name = 'iswap_dg' + _utry = UnitaryMatrix( + [ + [1, 0, 0, 0], + [0, 0, -1j, 0], + [0, -1j, 0, 0], + [0, 0, 0, 1], + ], + ) + + def get_qasm_gate_def(self) -> str: + """Returns a qasm gate definition block for this gate.""" + """iswap_dg q0,q1 { h q1; cx q1,q0; cx q0,q1; h q0; sdg q1; sdg q0; }""" + return ( + 'gate iswap_dg a,b\n' + '{\n' + '\th b;\n' + '\tcx b, a;\n' + '\tcx a, b;\n' + '\th a;\n' + '\tsdg b;\n' + '\tsdg a;\n' + '}\n' + ) + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + from bqskit.ir.gates.constant.iswap import ISwapGate + return ISwapGate() diff --git a/bqskit/ir/gates/constant/s.py b/bqskit/ir/gates/constant/s.py index 46bd37f39..f57a797eb 100644 --- a/bqskit/ir/gates/constant/s.py +++ b/bqskit/ir/gates/constant/s.py @@ -1,6 +1,7 @@ """This module implements the SGate.""" from __future__ import annotations +from bqskit.ir.gate import Gate from bqskit.ir.gates.constantgate import ConstantGate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix @@ -26,3 +27,8 @@ class SGate(ConstantGate, QubitGate): [0, 1j], ], ) + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + from bqskit.ir.gates.constant.sdg import SdgGate + return SdgGate() diff --git a/bqskit/ir/gates/constant/sdg.py b/bqskit/ir/gates/constant/sdg.py index f9a9e4a9c..07d2fec97 100644 --- a/bqskit/ir/gates/constant/sdg.py +++ b/bqskit/ir/gates/constant/sdg.py @@ -1,6 +1,7 @@ """This module implements the SdgGate.""" from __future__ import annotations +from bqskit.ir.gate import Gate from bqskit.ir.gates.constantgate import ConstantGate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix @@ -26,3 +27,8 @@ class SdgGate(ConstantGate, QubitGate): [0, -1j], ], ) + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + from bqskit.ir.gates.constant.s import SGate + return SGate() diff --git a/bqskit/ir/gates/constant/sqrtcnot.py b/bqskit/ir/gates/constant/sqrtcnot.py index 61f222b14..a610e8629 100644 --- a/bqskit/ir/gates/constant/sqrtcnot.py +++ b/bqskit/ir/gates/constant/sqrtcnot.py @@ -1,6 +1,7 @@ """This module implements the SqrtCNOTGate.""" from __future__ import annotations +from bqskit.ir.gate import Gate from bqskit.ir.gates.constantgate import ConstantGate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix @@ -32,3 +33,8 @@ class SqrtCNOTGate(ConstantGate, QubitGate): [0, 0, 0.5 - 0.5j, 0.5 + 0.5j], ], ) + + def get_inverse(self) -> Gate: + """"Return the inverse of this gate.""" + from bqskit.ir.gates.constant.sqrtcnotdg import SqrtCNOTDGGate + return SqrtCNOTDGGate() diff --git a/bqskit/ir/gates/constant/sqrtcnotdg.py b/bqskit/ir/gates/constant/sqrtcnotdg.py new file mode 100644 index 000000000..ef3c16605 --- /dev/null +++ b/bqskit/ir/gates/constant/sqrtcnotdg.py @@ -0,0 +1,61 @@ +"""This module implements the SqrtCNOTDGGate.""" +from __future__ import annotations + +from bqskit.ir.gate import Gate +from bqskit.ir.gates.constantgate import ConstantGate +from bqskit.ir.gates.qubitgate import QubitGate +from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix + + +class SqrtCNOTDGGate(ConstantGate, QubitGate): + """ + The Square root Controlled-X gate. + + The SqrtCNOT Dagger gate is given by the following unitary: + + .. math:: + + \\begin{pmatrix} + 1 & 0 & 0 & 0 \\\\ + 0 & 1 & 0 & 0 \\\\ + 0 & 0 & \\frac{1}{2} - \\frac{1}{2}i & \\frac{1}{2} + \\frac{1}{2}i \\\\ + 0 & 0 & \\frac{1}{2} + \\frac{1}{2}i & \\frac{1}{2} - \\frac{1}{2}i \\\\ + \\end{pmatrix} + """ + + _num_qudits = 2 + _qasm_name = 'csxdg' + _utry = UnitaryMatrix( + [ + [1, 0, 0, 0], + [0, 1, 0, 0], + [0, 0, 0.5 - 0.5j, 0.5 + 0.5j], + [0, 0, 0.5 + 0.5j, 0.5 - 0.5j], + ], + ) + + def get_qasm_gate_def(self) -> str: + """Returns a qasm gate definition block for this gate.""" + """Gate csxdg q0,q1 { u(0,0,pi/4) q1; cx q0,q1; u(0,0,-pi/4) q1; cx + q0,q1; cu(pi/2,0,pi,0) q0,q1; u(0,0,pi/4) q1; cx q0,q1; u(0,0,-pi/4) q1; + cx q0,q1; p(pi/4) q0; }""" + return ( + 'gate csxdg a,b\n' + '{\n' + '\tu(0,0,pi/4) b;\n' + '\tcx a,b;\n' + '\tu(0,0,-pi/4) b;\n' + '\tcx a,b;\n' + '\tcu(pi/2,0,pi,0) a,b;\n' + '\tu(0,0,pi/4) b;\n' + '\tcx a,b;\n' + '\tu(0,0,-pi/4) b;\n' + '\tcx a,b;\n' + '\tp(pi/4) a;\n' + '}\n' + ) + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + from bqskit.ir.gates.constant.sqrtcnot import SqrtCNOTGate + return SqrtCNOTGate() diff --git a/bqskit/ir/gates/constant/sqrtiswap.py b/bqskit/ir/gates/constant/sqrtiswap.py index be60d1292..4bc3158bb 100644 --- a/bqskit/ir/gates/constant/sqrtiswap.py +++ b/bqskit/ir/gates/constant/sqrtiswap.py @@ -3,6 +3,7 @@ import math +from bqskit.ir.gate import Gate from bqskit.ir.gates.constantgate import ConstantGate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix @@ -34,3 +35,24 @@ class SqrtISwapGate(ConstantGate, QubitGate): [0, 0, 0, 1], ], ) + + def get_qasm_gate_def(self) -> str: + """Returns a qasm gate definition block for this gate.""" + return ( + 'gate sqisw a,b\n' + '{\n' + '\tcx a,b;\n' + '\th a;\n' + '\tcx b,a;\n' + '\tt a;\n' + '\tcx b,a;\n' + '\ttdg a;\n' + '\th a;\n' + '\tcx a,b;\n' + '}\n' + ) + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + from bqskit.ir.gates.constant.sqrtiswapdg import SqrtISwapDGGate + return SqrtISwapDGGate() diff --git a/bqskit/ir/gates/constant/sqrtiswapdg.py b/bqskit/ir/gates/constant/sqrtiswapdg.py new file mode 100644 index 000000000..64669fe24 --- /dev/null +++ b/bqskit/ir/gates/constant/sqrtiswapdg.py @@ -0,0 +1,58 @@ +"""This module implements the SqrtISwapDGGate.""" +from __future__ import annotations + +import math + +from bqskit.ir.gate import Gate +from bqskit.ir.gates.constantgate import ConstantGate +from bqskit.ir.gates.qubitgate import QubitGate +from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix + + +class SqrtISwapDGGate(ConstantGate, QubitGate): + """ + The square root two qubit swap and phase iSWAP Dagger gate. + + The SqrtISwap Dagger gate is given by the following unitary: + + .. math:: + + \\begin{pmatrix} + 1 & 0 & 0 & 0 \\\\ + 0 & \\frac{1}{\\sqrt{2}} & - \\frac{i}{\\sqrt{2}} & 0 \\\\ + 0 & - \\frac{i}{\\sqrt{2}} & \\frac{1}{\\sqrt{2}} & 0 \\\\ + 0 & 0 & 0 & 1 \\\\ + \\end{pmatrix} + """ + + _num_qudits = 2 + _qasm_name = 'sqiswdg' + _utry = UnitaryMatrix( + [ + [1, 0, 0, 0], + [0, 1 / math.sqrt(2), -1j / math.sqrt(2), 0], + [0, -1j / math.sqrt(2), 1 / math.sqrt(2), 0], + [0, 0, 0, 1], + ], + ) + + def get_qasm_gate_def(self) -> str: + """Returns a qasm gate definition block for this gate.""" + return ( + 'gate sqiswdg a,b\n' + '{\n' + '\tcx a,b;\n' + '\th a;\n' + '\tt a;\n' + '\tcx b,a;\n' + '\ttdg a;\n' + '\tcx b,a;\n' + '\th a;\n' + '\tcx a,b;\n' + '}\n' + ) + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + from bqskit.ir.gates.constant.sqrtiswap import SqrtISwapGate + return SqrtISwapGate() diff --git a/bqskit/ir/gates/constant/swap.py b/bqskit/ir/gates/constant/swap.py index 44f98224e..cd397bd6e 100644 --- a/bqskit/ir/gates/constant/swap.py +++ b/bqskit/ir/gates/constant/swap.py @@ -2,11 +2,12 @@ from __future__ import annotations from bqskit.ir.gates.constantgate import ConstantGate +from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.permutation import PermutationMatrix from bqskit.utils.typing import is_integer -class SwapGate(ConstantGate): +class SwapGate(ConstantGate, QubitGate): """ The two-qudit swap gate. diff --git a/bqskit/ir/gates/constant/sx.py b/bqskit/ir/gates/constant/sx.py index fad4a3d5a..b85d042c0 100644 --- a/bqskit/ir/gates/constant/sx.py +++ b/bqskit/ir/gates/constant/sx.py @@ -1,6 +1,7 @@ """This module implements the SqrtXGate/SXGate.""" from __future__ import annotations +from bqskit.ir.gate import Gate from bqskit.ir.gates.constantgate import ConstantGate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix @@ -29,5 +30,10 @@ class SqrtXGate(ConstantGate, QubitGate): ], ) + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + from bqskit.ir.gates.constant.sxdg import SXDGGate + return SXDGGate() + SXGate = SqrtXGate diff --git a/bqskit/ir/gates/constant/sxdg.py b/bqskit/ir/gates/constant/sxdg.py new file mode 100644 index 000000000..6890ed359 --- /dev/null +++ b/bqskit/ir/gates/constant/sxdg.py @@ -0,0 +1,39 @@ +"""This module implements the SqrtXDGGate/SXDGGate.""" +from __future__ import annotations + +from bqskit.ir.gate import Gate +from bqskit.ir.gates.constantgate import ConstantGate +from bqskit.ir.gates.qubitgate import QubitGate +from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix + + +class SqrtXDGGate(ConstantGate, QubitGate): + """ + The Sqrt(X) Dagger gate. + + The SX Dagger gate is given by the following unitary: + + .. math:: + + \\begin{pmatrix} + \\frac{1}{2} - \\frac{1}{2}i & \\frac{1}{2} + \\frac{1}{2}i \\\\ + \\frac{1}{2} + \\frac{1}{2}i & \\frac{1}{2} - \\frac{1}{2}i \\\\ + \\end{pmatrix} + """ + + _num_qudits = 1 + _qasm_name = 'sxdg' + _utry = UnitaryMatrix( + [ + [0.5 - 0.5j, 0.5 + 0.5j], + [0.5 + 0.5j, 0.5 - 0.5j], + ], + ) + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + from bqskit.ir.gates.constant.sx import SXGate + return SXGate() + + +SXDGGate = SqrtXDGGate diff --git a/bqskit/ir/gates/constant/t.py b/bqskit/ir/gates/constant/t.py index d575c6158..48aca2cc5 100644 --- a/bqskit/ir/gates/constant/t.py +++ b/bqskit/ir/gates/constant/t.py @@ -3,6 +3,7 @@ import cmath +from bqskit.ir.gate import Gate from bqskit.ir.gates.constantgate import ConstantGate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix @@ -28,3 +29,8 @@ class TGate(ConstantGate, QubitGate): [0, cmath.exp(1j * cmath.pi / 4)], ], ) + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + from bqskit.ir.gates.constant.tdg import TdgGate + return TdgGate() diff --git a/bqskit/ir/gates/constant/tdg.py b/bqskit/ir/gates/constant/tdg.py index efcce3d10..e4a7e8566 100644 --- a/bqskit/ir/gates/constant/tdg.py +++ b/bqskit/ir/gates/constant/tdg.py @@ -3,6 +3,7 @@ import cmath +from bqskit.ir.gate import Gate from bqskit.ir.gates.constantgate import ConstantGate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix @@ -28,3 +29,8 @@ class TdgGate(ConstantGate, QubitGate): [0, cmath.exp(-1j * cmath.pi / 4)], ], ) + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + from bqskit.ir.gates.constant.t import TGate + return TGate() diff --git a/bqskit/ir/gates/constant/unitary.py b/bqskit/ir/gates/constant/unitary.py index fb3f80c50..e42d1daf4 100644 --- a/bqskit/ir/gates/constant/unitary.py +++ b/bqskit/ir/gates/constant/unitary.py @@ -12,9 +12,9 @@ class ConstantUnitaryGate(ConstantGate): """An arbitrary constant unitary operator.""" def __init__( - self, - utry: UnitaryLike, - radixes: Sequence[int] = [], + self, + utry: UnitaryLike, + radixes: Sequence[int] = [], ) -> None: """ Construct a constant unitary operator. diff --git a/bqskit/ir/gates/constant/xx.py b/bqskit/ir/gates/constant/xx.py index 5ac5c8a33..268b72b5f 100644 --- a/bqskit/ir/gates/constant/xx.py +++ b/bqskit/ir/gates/constant/xx.py @@ -3,6 +3,7 @@ import math +from bqskit.ir.gate import Gate from bqskit.ir.gates.constantgate import ConstantGate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix @@ -34,3 +35,8 @@ class XXGate(ConstantGate, QubitGate): [-1j * math.sqrt(2) / 2, 0, 0, math.sqrt(2) / 2], ], ) + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + from bqskit.ir.gates.constant.xxdg import XXDGGate + return XXDGGate() diff --git a/bqskit/ir/gates/constant/xxdg.py b/bqskit/ir/gates/constant/xxdg.py new file mode 100644 index 000000000..447dc1a0f --- /dev/null +++ b/bqskit/ir/gates/constant/xxdg.py @@ -0,0 +1,42 @@ +"""This module implements the XXDGGate.""" +from __future__ import annotations + +import math + +from bqskit.ir.gate import Gate +from bqskit.ir.gates.constantgate import ConstantGate +from bqskit.ir.gates.qubitgate import QubitGate +from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix + + +class XXDGGate(ConstantGate, QubitGate): + """ + The Ising XX coupling Dagger gate. + + The XX Dagger gate is given by the following unitary: + + .. math:: + + \\begin{pmatrix} + \\frac{\\sqrt{2}}{2} & 0 & 0 & \\frac{\\sqrt{2}}{2}i \\\\ + 0 & \\frac{\\sqrt{2}}{2} & -\\frac{\\sqrt{2}}{2}i & 0 \\\\ + 0 & \\frac{\\sqrt{2}}{2}i & \\frac{\\sqrt{2}}{2} & 0 \\\\ + \\frac{\\sqrt{2}}{2}i & 0 & 0 & \\frac{\\sqrt{2}}{2} \\\\ + \\end{pmatrix} + """ + + _num_qudits = 2 + _qasm_name = 'rxx(-pi/2)' + _utry = UnitaryMatrix( + [ + [math.sqrt(2) / 2, 0, 0, 1j * math.sqrt(2) / 2], + [0, math.sqrt(2) / 2, 1j * math.sqrt(2) / 2, 0], + [0, 1j * math.sqrt(2) / 2, math.sqrt(2) / 2, 0], + [1j * math.sqrt(2) / 2, 0, 0, math.sqrt(2) / 2], + ], + ) + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + from bqskit.ir.gates.constant.xx import XXGate + return XXGate() diff --git a/bqskit/ir/gates/constant/yy.py b/bqskit/ir/gates/constant/yy.py index c140609c4..671a95855 100644 --- a/bqskit/ir/gates/constant/yy.py +++ b/bqskit/ir/gates/constant/yy.py @@ -3,6 +3,7 @@ import math +from bqskit.ir.gate import Gate from bqskit.ir.gates.constantgate import ConstantGate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix @@ -34,3 +35,8 @@ class YYGate(ConstantGate, QubitGate): [1j * math.sqrt(2) / 2, 0, 0, math.sqrt(2) / 2], ], ) + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + from bqskit.ir.gates.constant.yydg import YYDGGate + return YYDGGate() diff --git a/bqskit/ir/gates/constant/yydg.py b/bqskit/ir/gates/constant/yydg.py new file mode 100644 index 000000000..b3cbb68f3 --- /dev/null +++ b/bqskit/ir/gates/constant/yydg.py @@ -0,0 +1,42 @@ +"""This module implements the YYDGGate.""" +from __future__ import annotations + +import math + +from bqskit.ir.gate import Gate +from bqskit.ir.gates.constantgate import ConstantGate +from bqskit.ir.gates.qubitgate import QubitGate +from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix + + +class YYDGGate(ConstantGate, QubitGate): + """ + The Ising YY Dagger coupling gate. + + The YY Dagger gate is given by the following unitary: + + .. math:: + + \\begin{pmatrix} + \\frac{\\sqrt{2}}{2} & 0 & 0 & -\\frac{\\sqrt{2}}{2}i \\\\ + 0 & \\frac{\\sqrt{2}}{2} & +\\frac{\\sqrt{2}}{2}i & 0 \\\\ + 0 & \\frac{\\sqrt{2}}{2}i & \\frac{\\sqrt{2}}{2} & 0 \\\\ + -\\frac{\\sqrt{2}}{2}i & 0 & 0 & \\frac{\\sqrt{2}}{2} \\\\ + \\end{pmatrix} + """ + + _num_qudits = 2 + _qasm_name = 'ryy(-pi/2)' + _utry = UnitaryMatrix( + [ + [math.sqrt(2) / 2, 0, 0, -1j * math.sqrt(2) / 2], + [0, math.sqrt(2) / 2, 1j * math.sqrt(2) / 2, 0], + [0, 1j * math.sqrt(2) / 2, math.sqrt(2) / 2, 0], + [-1j * math.sqrt(2) / 2, 0, 0, math.sqrt(2) / 2], + ], + ) + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + from bqskit.ir.gates.constant.yy import YYGate + return YYGate() diff --git a/bqskit/ir/gates/constant/zz.py b/bqskit/ir/gates/constant/zz.py index 6a6e32626..2fb959aad 100644 --- a/bqskit/ir/gates/constant/zz.py +++ b/bqskit/ir/gates/constant/zz.py @@ -3,6 +3,7 @@ import math +from bqskit.ir.gate import Gate from bqskit.ir.gates.constantgate import ConstantGate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix @@ -34,3 +35,8 @@ class ZZGate(ConstantGate, QubitGate): [0, 0, 0, math.sqrt(2) / 2 - 1j * math.sqrt(2) / 2], ], ) + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + from bqskit.ir.gates.constant.zzdg import ZZDGGate + return ZZDGGate() diff --git a/bqskit/ir/gates/constant/zzdg.py b/bqskit/ir/gates/constant/zzdg.py new file mode 100644 index 000000000..d8c29817c --- /dev/null +++ b/bqskit/ir/gates/constant/zzdg.py @@ -0,0 +1,42 @@ +"""This module implements the ZZDGGate.""" +from __future__ import annotations + +import math + +from bqskit.ir.gate import Gate +from bqskit.ir.gates.constantgate import ConstantGate +from bqskit.ir.gates.qubitgate import QubitGate +from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix + + +class ZZDGGate(ConstantGate, QubitGate): + """ + The Ising ZZ Dagger coupling gate. + + The ZZ Dagger gate is given by the following unitary: + + .. math:: + + \\begin{pmatrix} + \\frac{\\sqrt{2}}{2} + \\frac{\\sqrt{2}}{2}i & 0 & 0 & 0 \\\\ + 0 & \\frac{\\sqrt{2}}{2} - \\frac{\\sqrt{2}}{2}i & 0 & 0 \\\\ + 0 & 0 & \\frac{\\sqrt{2}}{2} - \\frac{\\sqrt{2}}{2}i & 0 \\\\ + 0 & 0 & 0 & \\frac{\\sqrt{2}}{2} + \\frac{\\sqrt{2}}{2}i \\\\ + \\end{pmatrix} + """ + + _num_qudits = 2 + _qasm_name = 'rzz(-pi/2)' + _utry = UnitaryMatrix( + [ + [math.sqrt(2) / 2 + 1j * math.sqrt(2) / 2, 0, 0, 0], + [0, math.sqrt(2) / 2 - 1j * math.sqrt(2) / 2, 0, 0], + [0, 0, math.sqrt(2) / 2 - 1j * math.sqrt(2) / 2, 0], + [0, 0, 0, math.sqrt(2) / 2 + 1j * math.sqrt(2) / 2], + ], + ) + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + from bqskit.ir.gates.constant.zz import ZZGate + return ZZGate() diff --git a/bqskit/ir/gates/parameterized/ccp.py b/bqskit/ir/gates/parameterized/ccp.py index c8d0faa14..d6b30aa85 100644 --- a/bqskit/ir/gates/parameterized/ccp.py +++ b/bqskit/ir/gates/parameterized/ccp.py @@ -4,6 +4,7 @@ import numpy as np import numpy.typing as npt +from bqskit.ir.gate import Gate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.differentiable import DifferentiableUnitary from bqskit.qis.unitary.unitary import RealVector @@ -82,3 +83,12 @@ def get_grad(self, params: RealVector = []) -> npt.NDArray[np.complex128]: ], ], dtype=np.complex128, ) + + def get_inverse_params(self, params: RealVector = []) -> RealVector: + """Return the parameters for the inverse of this gate.""" + self.check_parameters(params) + return [-params[0]] + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + return CCPGate() diff --git a/bqskit/ir/gates/parameterized/cp.py b/bqskit/ir/gates/parameterized/cp.py index 58830f442..4f2b029f1 100644 --- a/bqskit/ir/gates/parameterized/cp.py +++ b/bqskit/ir/gates/parameterized/cp.py @@ -4,6 +4,7 @@ import numpy as np import numpy.typing as npt +from bqskit.ir.gate import Gate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.differentiable import DifferentiableUnitary from bqskit.qis.unitary.unitary import RealVector @@ -70,3 +71,12 @@ def get_grad(self, params: RealVector = []) -> npt.NDArray[np.complex128]: ], ], dtype=np.complex128, ) + + def get_inverse_params(self, params: RealVector = []) -> RealVector: + """Return the inverse parameters for this gate.""" + self.check_parameters(params) + return [-params[0]] + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + return CPGate() diff --git a/bqskit/ir/gates/parameterized/cphase.py b/bqskit/ir/gates/parameterized/cphase.py index 6f9c2b684..243a4ce91 100644 --- a/bqskit/ir/gates/parameterized/cphase.py +++ b/bqskit/ir/gates/parameterized/cphase.py @@ -75,3 +75,12 @@ def __eq__(self, other: object) -> bool: def __hash__(self) -> int: return hash(self.radixes) + + def get_inverse_params(self, params: RealVector = []) -> RealVector: + """Return the inverse parameters for this gate.""" + self.check_parameters(params) + return [-params[0]] + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + return ArbitraryCPhaseGate(self.radixes) diff --git a/bqskit/ir/gates/parameterized/crx.py b/bqskit/ir/gates/parameterized/crx.py index 0f49fcbdc..f215b1f25 100644 --- a/bqskit/ir/gates/parameterized/crx.py +++ b/bqskit/ir/gates/parameterized/crx.py @@ -4,6 +4,7 @@ import numpy as np import numpy.typing as npt +from bqskit.ir.gate import Gate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.differentiable import DifferentiableUnitary from bqskit.qis.unitary.unitary import RealVector @@ -72,3 +73,12 @@ def get_grad(self, params: RealVector = []) -> npt.NDArray[np.complex128]: ], ], dtype=np.complex128, ) + + def get_inverse_params(self, params: RealVector = []) -> RealVector: + """Return the inverse parameters for this gate.""" + self.check_parameters(params) + return [-params[0]] + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + return CRXGate() diff --git a/bqskit/ir/gates/parameterized/cry.py b/bqskit/ir/gates/parameterized/cry.py index 871735fc7..1904482bb 100644 --- a/bqskit/ir/gates/parameterized/cry.py +++ b/bqskit/ir/gates/parameterized/cry.py @@ -4,6 +4,7 @@ import numpy as np import numpy.typing as npt +from bqskit.ir.gate import Gate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.differentiable import DifferentiableUnitary from bqskit.qis.unitary.unitary import RealVector @@ -72,3 +73,12 @@ def get_grad(self, params: RealVector = []) -> npt.NDArray[np.complex128]: ], ], dtype=np.complex128, ) + + def get_inverse_params(self, params: RealVector = []) -> RealVector: + """Return the inverse parameters for this gate.""" + self.check_parameters(params) + return [-params[0]] + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + return CRYGate() diff --git a/bqskit/ir/gates/parameterized/crz.py b/bqskit/ir/gates/parameterized/crz.py index 0fc5b6a21..718ad565a 100644 --- a/bqskit/ir/gates/parameterized/crz.py +++ b/bqskit/ir/gates/parameterized/crz.py @@ -4,6 +4,7 @@ import numpy as np import numpy.typing as npt +from bqskit.ir.gate import Gate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.differentiable import DifferentiableUnitary from bqskit.qis.unitary.unitary import RealVector @@ -72,3 +73,12 @@ def get_grad(self, params: RealVector = []) -> npt.NDArray[np.complex128]: ], ], dtype=np.complex128, ) + + def get_inverse_params(self, params: RealVector = []) -> RealVector: + """Return the inverse parameters for this gate.""" + self.check_parameters(params) + return [-params[0]] + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + return CRZGate() diff --git a/bqskit/ir/gates/parameterized/cu.py b/bqskit/ir/gates/parameterized/cu.py index fc949859e..e3df4681a 100644 --- a/bqskit/ir/gates/parameterized/cu.py +++ b/bqskit/ir/gates/parameterized/cu.py @@ -4,6 +4,7 @@ import numpy as np import numpy.typing as npt +from bqskit.ir.gate import Gate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.differentiable import DifferentiableUnitary from bqskit.qis.unitary.unitary import RealVector @@ -113,3 +114,12 @@ def get_grad(self, params: RealVector = []) -> npt.NDArray[np.complex128]: ], ], dtype=np.complex128, ) + + def get_inverse_params(self, params: RealVector = []) -> RealVector: + """Return the parameters for the inverse of this gate.""" + self.check_parameters(params) + return [params[0], -params[2], -params[1], -params[3]] + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + return CUGate() diff --git a/bqskit/ir/gates/parameterized/fsim.py b/bqskit/ir/gates/parameterized/fsim.py index 274e62f63..ac00f4097 100644 --- a/bqskit/ir/gates/parameterized/fsim.py +++ b/bqskit/ir/gates/parameterized/fsim.py @@ -4,6 +4,7 @@ import numpy as np import numpy.typing as npt +from bqskit.ir.gate import Gate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.differentiable import DifferentiableUnitary from bqskit.qis.unitary.unitary import RealVector @@ -85,3 +86,12 @@ def get_grad(self, params: RealVector = []) -> npt.NDArray[np.complex128]: ], ], dtype=np.complex128, ) + + def get_inverse_params(self, params: RealVector = []) -> RealVector: + """Return the parameters for the inverse of this gate.""" + self.check_parameters(params) + return [params[0], -params[1]] + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + return FSIMGate() diff --git a/bqskit/ir/gates/parameterized/phasedxz.py b/bqskit/ir/gates/parameterized/phasedxz.py index 7b7ee4392..6a9e34ac6 100644 --- a/bqskit/ir/gates/parameterized/phasedxz.py +++ b/bqskit/ir/gates/parameterized/phasedxz.py @@ -4,6 +4,7 @@ import numpy as np import numpy.typing as npt +from bqskit.ir.gate import Gate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.differentiable import DifferentiableUnitary from bqskit.qis.unitary.unitary import RealVector @@ -86,3 +87,20 @@ def get_grad(self, params: RealVector = []) -> npt.NDArray[np.complex128]: ], ], dtype=np.complex128, ) + + def get_qasm_gate_def(self) -> str: + """Return the QASM gate definition for this gate.""" + theta0 = 'x*pi' + theta1 = '(z+a-0.5)*pi' + theta2 = '(0.5-a)*pi' + return (f'gate {self._qasm_name} a,b,c' + f' {{ u3({theta0},{theta1},{theta2}); }}') + + def get_inverse_params(self, params: RealVector = []) -> RealVector: + """Return the inverse parameters for this gate.""" + self.check_parameters(params) + return [-params[0], -params[1], params[1] + params[2]] + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + return PhasedXZGate() diff --git a/bqskit/ir/gates/parameterized/rx.py b/bqskit/ir/gates/parameterized/rx.py index 7db98bf0b..cfbf7af9b 100644 --- a/bqskit/ir/gates/parameterized/rx.py +++ b/bqskit/ir/gates/parameterized/rx.py @@ -4,6 +4,7 @@ import numpy as np import numpy.typing as npt +from bqskit.ir.gate import Gate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.differentiable import DifferentiableUnitary from bqskit.qis.unitary.optimizable import LocallyOptimizableUnitary @@ -81,3 +82,12 @@ def optimize(self, env_matrix: npt.NDArray[np.complex128]) -> list[float]: theta = 2 * np.arccos(a / np.sqrt(a ** 2 + b ** 2)) theta *= -1 if b < 0 else 1 return [theta] + + def get_inverse_params(self, params: RealVector = []) -> RealVector: + """Return the inverse parameters for this gate.""" + self.check_parameters(params) + return [-params[0]] + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + return RXGate() diff --git a/bqskit/ir/gates/parameterized/rxx.py b/bqskit/ir/gates/parameterized/rxx.py index 7696ed0e3..379a95030 100644 --- a/bqskit/ir/gates/parameterized/rxx.py +++ b/bqskit/ir/gates/parameterized/rxx.py @@ -4,6 +4,7 @@ import numpy as np import numpy.typing as npt +from bqskit.ir.gate import Gate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.differentiable import DifferentiableUnitary from bqskit.qis.unitary.optimizable import LocallyOptimizableUnitary @@ -93,3 +94,12 @@ def optimize(self, env_matrix: npt.NDArray[np.complex128]) -> list[float]: theta = np.arccos(a / np.sqrt(a ** 2 + b ** 2)) theta *= -2 if b < 0 else 2 return [theta] + + def get_inverse_params(self, params: RealVector = []) -> RealVector: + """Return the inverse parameters for this gate.""" + self.check_parameters(params) + return [-params[0]] + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + return RXXGate() diff --git a/bqskit/ir/gates/parameterized/ry.py b/bqskit/ir/gates/parameterized/ry.py index c094aa355..07ea57260 100644 --- a/bqskit/ir/gates/parameterized/ry.py +++ b/bqskit/ir/gates/parameterized/ry.py @@ -4,6 +4,7 @@ import numpy as np import numpy.typing as npt +from bqskit.ir.gate import Gate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.differentiable import DifferentiableUnitary from bqskit.qis.unitary.optimizable import LocallyOptimizableUnitary @@ -81,3 +82,12 @@ def optimize(self, env_matrix: npt.NDArray[np.complex128]) -> list[float]: theta = 2 * np.arccos(a / np.sqrt(a ** 2 + b ** 2)) theta *= -1 if b > 0 else 1 return [theta] + + def get_inverse_params(self, params: RealVector = []) -> RealVector: + """Return the parameters for the inverse of this gate.""" + self.check_parameters(params) + return [-params[0]] + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + return RYGate() diff --git a/bqskit/ir/gates/parameterized/ryy.py b/bqskit/ir/gates/parameterized/ryy.py index dd9e7440d..754569a7f 100644 --- a/bqskit/ir/gates/parameterized/ryy.py +++ b/bqskit/ir/gates/parameterized/ryy.py @@ -4,6 +4,7 @@ import numpy as np import numpy.typing as npt +from bqskit.ir.gate import Gate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.differentiable import DifferentiableUnitary from bqskit.qis.unitary.unitary import RealVector @@ -74,3 +75,12 @@ def get_grad(self, params: RealVector = []) -> npt.NDArray[np.complex128]: ], ], dtype=np.complex128, ) + + def get_inverse_params(self, params: RealVector = []) -> RealVector: + """Return the parameters for the inverse of this gate.""" + self.check_parameters(params) + return [-params[0]] + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + return RYYGate() diff --git a/bqskit/ir/gates/parameterized/rz.py b/bqskit/ir/gates/parameterized/rz.py index 09a8ce7e2..3906bdc83 100644 --- a/bqskit/ir/gates/parameterized/rz.py +++ b/bqskit/ir/gates/parameterized/rz.py @@ -4,6 +4,7 @@ import numpy as np import numpy.typing as npt +from bqskit.ir.gate import Gate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.differentiable import DifferentiableUnitary from bqskit.qis.unitary.unitary import RealVector @@ -62,3 +63,12 @@ def get_grad(self, params: RealVector = []) -> npt.NDArray[np.complex128]: ], ], dtype=np.complex128, ) + + def get_inverse_params(self, params: RealVector = []) -> RealVector: + """Return the inverse parameters for this gate.""" + self.check_parameters(params) + return [-params[0]] + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + return RZGate() diff --git a/bqskit/ir/gates/parameterized/rzz.py b/bqskit/ir/gates/parameterized/rzz.py index 967bef2d0..eafdf9d7f 100644 --- a/bqskit/ir/gates/parameterized/rzz.py +++ b/bqskit/ir/gates/parameterized/rzz.py @@ -4,6 +4,7 @@ import numpy as np import numpy.typing as npt +from bqskit.ir.gate import Gate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.differentiable import DifferentiableUnitary from bqskit.qis.unitary.unitary import RealVector @@ -72,3 +73,12 @@ def get_grad(self, params: RealVector = []) -> npt.NDArray[np.complex128]: ], ], dtype=np.complex128, ) + + def get_inverse_params(self, params: RealVector = []) -> RealVector: + """Return the parameters for the inverse of this gate.""" + self.check_parameters(params) + return [-params[0]] + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + return RZZGate() diff --git a/bqskit/ir/gates/parameterized/u1.py b/bqskit/ir/gates/parameterized/u1.py index 57a0cbade..14774159b 100644 --- a/bqskit/ir/gates/parameterized/u1.py +++ b/bqskit/ir/gates/parameterized/u1.py @@ -4,6 +4,7 @@ import numpy as np import numpy.typing as npt +from bqskit.ir.gate import Gate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.differentiable import DifferentiableUnitary from bqskit.qis.unitary.optimizable import LocallyOptimizableUnitary @@ -84,3 +85,12 @@ def optimize(self, env_matrix: npt.NDArray[np.complex128]) -> list[float]: arctan -= np.pi return [-arctan] + + def get_inverse_params(self, params: RealVector = []) -> RealVector: + """Return the parameters for the inverse of this gate.""" + self.check_parameters(params) + return [-params[0]] + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + return U1Gate() diff --git a/bqskit/ir/gates/parameterized/u2.py b/bqskit/ir/gates/parameterized/u2.py index 9f6a3816e..247ca952c 100644 --- a/bqskit/ir/gates/parameterized/u2.py +++ b/bqskit/ir/gates/parameterized/u2.py @@ -1,9 +1,12 @@ """This module implements the U2Gate.""" from __future__ import annotations +import math + import numpy as np import numpy.typing as npt +from bqskit.ir.gate import Gate from bqskit.ir.gates.qubitgate import QubitGate from bqskit.qis.unitary.differentiable import DifferentiableUnitary from bqskit.qis.unitary.unitary import RealVector @@ -72,3 +75,13 @@ def get_grad(self, params: RealVector = []) -> npt.NDArray[np.complex128]: ], ], dtype=np.complex128, ) + + def get_inverse_params(self, params: RealVector = []) -> RealVector: + """Return the parameters for the inverse of this gate.""" + self.check_parameters(params) + return [- math.pi / 2, -params[1], -params[0]] + + def get_inverse(self) -> Gate: + """Return the inverse of this gate.""" + from bqskit.ir.gates.parameterized.u3 import U3Gate + return U3Gate() diff --git a/bqskit/passes/mapping/placement/trivial.py b/bqskit/passes/mapping/placement/trivial.py index df54d94e5..e4b02fc6f 100644 --- a/bqskit/passes/mapping/placement/trivial.py +++ b/bqskit/passes/mapping/placement/trivial.py @@ -20,7 +20,7 @@ async def run(self, circuit: Circuit, data: PassData) -> None: model = BasePass.get_model(circuit, data) data['placement'] = trivial_placement - _logger.info(f'Placed qudits on {data["placement"]}') + _logger.info(f"Placed qudits on {data['placement']}") # Raise an error if this is not a valid placement sg = model.coupling_graph.get_subgraph(data['placement']) diff --git a/tests/conftest.py b/tests/conftest.py index 18104b002..5d9f8ef24 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -24,7 +24,10 @@ from bqskit.ir.gate import Gate from bqskit.ir.gates import CNOTGate from bqskit.ir.gates import ConstantUnitaryGate +from bqskit.ir.gates import CPGate from bqskit.ir.gates import CPIGate +from bqskit.ir.gates import CSDGGate +from bqskit.ir.gates import CSGate from bqskit.ir.gates import CSUMGate from bqskit.ir.gates import CXGate from bqskit.ir.gates import CYGate @@ -33,16 +36,22 @@ from bqskit.ir.gates import FrozenParameterGate from bqskit.ir.gates import HGate from bqskit.ir.gates import IdentityGate +from bqskit.ir.gates import ISwapDGGate from bqskit.ir.gates import ISwapGate from bqskit.ir.gates import PauliGate +from bqskit.ir.gates import PhasedXZGate from bqskit.ir.gates import RXGate from bqskit.ir.gates import RYGate from bqskit.ir.gates import RZGate from bqskit.ir.gates import SdgGate from bqskit.ir.gates import SGate +from bqskit.ir.gates import SqrtCNOTDGGate from bqskit.ir.gates import SqrtCNOTGate +from bqskit.ir.gates import SqrtISwapDGGate +from bqskit.ir.gates import SqrtISwapGate from bqskit.ir.gates import SqrtXGate from bqskit.ir.gates import SwapGate +from bqskit.ir.gates import SXDGGate from bqskit.ir.gates import SXGate from bqskit.ir.gates import TaggedGate from bqskit.ir.gates import TdgGate @@ -55,9 +64,12 @@ from bqskit.ir.gates import XGate from bqskit.ir.gates import XXGate from bqskit.ir.gates import YGate +from bqskit.ir.gates import YYGate from bqskit.ir.gates import ZGate +from bqskit.ir.gates import ZZGate from bqskit.qis.unitary.unitarymatrix import UnitaryMatrix from bqskit.utils.typing import is_sequence + # from bqskit.ir.gates import CircuitGate # from bqskit.ir.gates import ControlledGate # from bqskit.ir.gates import PermutationGate @@ -246,18 +258,27 @@ def gen_invalid_utry_np( CNOTGate(), CYGate(), CZGate(), + CSGate(), + CSDGGate(), + CPGate(), + SqrtISwapGate(), + SqrtISwapDGGate(), + PhasedXZGate(), + ISwapGate(), + ISwapDGGate(), + SqrtCNOTGate(), + SqrtCNOTDGGate(), + SXGate(), + SXDGGate(), HGate(), IdentityGate(1), IdentityGate(2), IdentityGate(3), IdentityGate(4), - ISwapGate(), # PermutationGate(), # TODO SGate(), SdgGate(), - SqrtCNOTGate(), SwapGate(), - SXGate(), SqrtXGate(), TGate(), TdgGate(), @@ -265,7 +286,9 @@ def gen_invalid_utry_np( XGate(), XXGate(), YGate(), + YYGate(), ZGate(), + ZZGate(), # PauliGate(), # TODO RXGate(), RYGate(), @@ -401,6 +424,7 @@ def multi_qutrit_gate(request: Any) -> Gate: """Provides all of MULTI_QUTRIT_GATES as a gate fixture.""" return request.param + # endregion # region Circuits @@ -450,11 +474,11 @@ def toffoli_circuit() -> Circuit: def circuit_gen( - size: int, - radixes: Sequence[int] = [], - depth: int = 10, - constant: bool = False, - gateset: list[Gate] = BQSKIT_GATES, + size: int, + radixes: Sequence[int] = [], + depth: int = 10, + constant: bool = False, + gateset: list[Gate] = BQSKIT_GATES, ) -> Circuit: """ Generate a random circuit according to input specifications. @@ -517,9 +541,9 @@ def circuit_gen( # must be compatible with circuit radix if not all( - gate.radixes.count(unique_radix) - <= circuit.radixes.count(unique_radix) - for unique_radix in set(gate.radixes) + gate.radixes.count(unique_radix) + <= circuit.radixes.count(unique_radix) + for unique_radix in set(gate.radixes) ): continue @@ -543,9 +567,9 @@ def circuit_gen( iter = 0 qudit = None while ( - qudit is None - or qudit in location_selected - or qudit == qudit_selected + qudit is None + or qudit in location_selected + or qudit == qudit_selected ): qudit = circuit.radixes[iter:].index(radix) + iter iter = qudit + 1 @@ -563,6 +587,7 @@ def gen_random_circuit() -> Callable[[int, Sequence[int], int, bool], Circuit]: """Provide a function to generate random circuits.""" return circuit_gen + # Pregenerated random circuit fixtures: @@ -633,5 +658,4 @@ def r6_qudit_circuit(request: Any) -> Circuit: """Provide random 6-qudit random-radix circuits as a fixture.""" return request.param[1].copy() - # endregion diff --git a/tests/ir/test_gate.py b/tests/ir/test_gate.py index a98ae867d..ae69836f4 100644 --- a/tests/ir/test_gate.py +++ b/tests/ir/test_gate.py @@ -137,3 +137,37 @@ def test_pickle(self, gate: Gate) -> None: utry = gate.get_unitary(params) pickled_utry = pickle.loads(pickle.dumps(gate)).get_unitary(params) assert utry == pickled_utry + + def test_get_inverse(self, gate: Gate) -> None: + from bqskit.ir.gates.constantgate import ConstantGate + from bqskit.qis.unitary.differentiable import DifferentiableUnitary + from bqskit.ir.gates.qubitgate import QubitGate + from bqskit.ir.operation import Operation + if isinstance(gate, QubitGate): + if isinstance(gate, ConstantGate): + assert hasattr(gate, 'get_inverse') + inv_gate = gate.get_inverse() + assert inv_gate._qasm_name, \ + 'All inverses should have an effective _qasm_name' + iden = np.identity(gate.dim) + inv_gate = gate.get_inverse() + supposed_to_be_iden = ( + inv_gate.get_unitary() @ gate.get_unitary() + ) + dist = supposed_to_be_iden.get_distance_from(iden, 1) + assert dist < 1e-10 + + if isinstance(gate, DifferentiableUnitary): + assert hasattr(gate, 'get_inverse') + inv_gate = gate.get_inverse() + assert inv_gate._qasm_name, \ + 'All inverses should have an effective _qasm_name' + op = Operation( + gate, list(range(gate.num_qudits)), + np.random.rand(gate.num_params), + ) + inv_op = op.get_inverse() + iden = np.identity(gate.dim) + supposed_to_be_iden = (inv_op.get_unitary() @ op.get_unitary()) + dist = supposed_to_be_iden.get_distance_from(iden, 1) + assert dist < 1e-10