Source code for mimiqcircuits.operations.gates.standard.interactions

#
# Copyright © 2022-2023 University of Strasbourg. All Rights Reserved.
#
# 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.
#

import mimiqcircuits as mc
from mimiqcircuits.matrices import cis
from symengine import I, Matrix, cos, sin, pi


[docs] class GateRXX(mc.Gate): r"""Two qubit RXX gate (rotation about XX). This gate is symmetric, and is maximally entangling at :math:`(\theta = \frac{\pi}{2})` **Matrix representation:** .. math:: \operatorname{RXX}(\theta) =\begin{pmatrix} \cos(\frac{\theta}{2}) & 0 & 0 & -i\sin(\frac{\theta}{2}) \\ 0 & \cos(\frac{\theta}{2}) & -i\sin(\frac{\theta}{2}) & 0 \\ 0 & -i\sin(\frac{\theta}{2}) & \cos(\frac{\theta}{2}) & 0 \\ -i\sin(\frac{\theta}{2}) & 0 & 0 & \cos(\frac{\theta}{2}) \end{pmatrix} Parameters: theta: The angle in radians. Examples: >>> from mimiqcircuits import * >>> from symengine import * >>> theta = Symbol('theta') >>> GateRXX(theta) RXX(theta) >>> c = Circuit() >>> c.push(GateRXX(theta), 0, 1) 2-qubit circuit with 1 instructions: └── RXX(theta) @ q[0,1] <BLANKLINE> >>> GateRXX(theta).power(2), GateRXX(theta).inverse() (RXX(theta)**2, RXX(-theta)) >>> GateRXX(theta).matrix() [cos((1/2)*theta), 0, 0, -I*sin((1/2)*theta)] [0, cos((1/2)*theta), -I*sin((1/2)*theta), 0] [0, -I*sin((1/2)*theta), cos((1/2)*theta), 0] [-I*sin((1/2)*theta), 0, 0, cos((1/2)*theta)] <BLANKLINE> >>> GateRXX(theta).decompose() 2-qubit circuit with 7 instructions: ├── H @ q[0] ├── H @ q[1] ├── CX @ q[0], q[1] ├── RZ(theta) @ q[1] ├── CX @ q[0], q[1] ├── H @ q[1] └── H @ q[0] <BLANKLINE> """ _name = 'RXX' _num_qubits = 2 _qregsizes = [2] _parnames = ('theta',) def __init__(self, theta): self.theta = theta def _matrix(self): theta = self.theta cos2 = cos(theta / 2) sin2 = sin(theta / 2) return (Matrix([[cos2, 0, 0, -I * sin2], [0, cos2, -I * sin2, 0], [0, -I * sin2, cos2, 0], [-I * sin2, 0, 0, cos2]]))
[docs] def inverse(self): return GateRXX(-self.theta)
def _decompose(self, circ, qubits, bits): a, b = range(self.num_qubits) circ.push(mc.GateH(), a) circ.push(mc.GateH(), b) circ.push(mc.GateCX(), a, b) circ.push(mc.GateRZ(self.theta), b) circ.push(mc.GateCX(), a, b) circ.push(mc.GateH(), b) circ.push(mc.GateH(), a) return circ
[docs] class GateRYY(mc.Gate): r"""Two qubit RYY gate (rotation about YY). This gate is symmetric, and is maximally entangling at :math:`(\theta = \frac{\pi}{2})` **Matrix representation:** .. math:: \operatorname{RYY}(\theta) =\begin{pmatrix} \cos(\frac{\theta}{2}) & 0 & 0 & i\sin(\frac{\theta}{2}) \\ 0 & \cos(\frac{\theta}{2}) & -i\sin(\frac{\theta}{2}) & 0 \\ 0 & -i\sin(\frac{\theta}{2}) & \cos(\frac{\theta}{2}) & 0 \\ i\sin(\frac{\theta}{2}) & 0 & 0 & \cos(\frac{\theta}{2}) \end{pmatrix} Parameters: theta (float): The angle in radians. Examples: >>> from mimiqcircuits import * >>> from symengine import * >>> theta = Symbol('theta') >>> GateRYY(theta) RYY(theta) >>> GateRYY(theta).matrix() [cos((1/2)*theta), 0, 0, I*sin((1/2)*theta)] [0, cos((1/2)*theta), -I*sin((1/2)*theta), 0] [0, -I*sin((1/2)*theta), cos((1/2)*theta), 0] [I*sin((1/2)*theta), 0, 0, cos((1/2)*theta)] <BLANKLINE> >>> c = Circuit().push(GateRYY(theta), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── RYY(theta) @ q[0,1] <BLANKLINE> >>> GateRYY(theta).power(2), GateRYY(theta).inverse() (RYY(theta)**2, RYY(-theta)) >>> GateRYY(theta).decompose() 2-qubit circuit with 7 instructions: ├── RX((1/2)*pi) @ q[0] ├── RX((1/2)*pi) @ q[1] ├── CX @ q[0], q[1] ├── RZ(theta) @ q[1] ├── CX @ q[0], q[1] ├── RX((-1/2)*pi) @ q[0] └── RX((-1/2)*pi) @ q[1] <BLANKLINE> """ _name = 'RYY' _num_qubits = 2 _qregsizes = [2] _parnames = ('theta',) def __init__(self, theta): self.theta = theta def _matrix(self): theta = self.theta cos2 = cos(theta / 2) sin2 = sin(theta / 2) return Matrix([[cos2, 0, 0, I * sin2], [0, cos2, -I * sin2, 0], [0, -I * sin2, cos2, 0], [I * sin2, 0, 0, cos2]])
[docs] def inverse(self): return GateRYY(-self.theta)
def _decompose(self, circ, qubits, bits): a, b = range(self.num_qubits) circ.push(mc.GateRX(pi/2), a) circ.push(mc.GateRX(pi/2), b) circ.push(mc.GateCX(), a, b) circ.push(mc.GateRZ(self.theta), b) circ.push(mc.GateCX(), a, b) circ.push(mc.GateRX(-pi/2), a) circ.push(mc.GateRX(-pi/2), b) return circ
[docs] class GateRZZ(mc.Gate): r"""Two qubit RZZ gate (rotation about ZZ).. This gate is symmetric, and is maximally entangling at :math:`(\theta = \frac{\pi}{2})` **Matrix representation:** .. math:: \operatorname{RZZ}(\theta) = \begin{pmatrix} e^{-i\frac{\theta}{2}} & 0 & 0 & 0 \\ 0 & e^{i\frac{\theta}{2}} & 0 & 0 \\ 0 & 0 & e^{i\frac{\theta}{2}} & 0 \\ 0 & 0 & 0 & e^{-i\frac{\theta}{2}} \end{pmatrix} Parameters: theta (float): The angle in radians. Examples: >>> from mimiqcircuits import * >>> from symengine import * >>> theta = Symbol('theta') >>> GateRZZ(theta) RZZ(theta) >>> GateRZZ(theta).matrix() [exp(-1/2*I*theta), 0, 0, 0] [0, exp(1/2*I*theta), 0, 0] [0, 0, exp(1/2*I*theta), 0] [0, 0, 0, exp(-1/2*I*theta)] <BLANKLINE> >>> c = Circuit().push(GateRZZ(theta), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── RZZ(theta) @ q[0,1] <BLANKLINE> >>> GateRZZ(theta).power(2), GateRZZ(theta).inverse() (RZZ(theta)**2, RZZ(-theta)) >>> GateRZZ(theta).decompose() 2-qubit circuit with 3 instructions: ├── CX @ q[0], q[1] ├── RZ(theta) @ q[1] └── CX @ q[0], q[1] <BLANKLINE> """ _num_qubits = 2 _name = 'RZZ' _parnames = ('theta',) _qregsizes = [2] def __init__(self, theta): self.theta = theta def _matrix(self): return Matrix([[cis(-self.theta / 2), 0, 0, 0], [0, cis(self.theta / 2), 0, 0], [0, 0, cis(self.theta / 2), 0], [0, 0, 0, cis(-self.theta / 2)]])
[docs] def inverse(self): return GateRZZ(-self.theta)
def _decompose(self, circ, qubits, bits): a, b = qubits circ.push(mc.GateCX(), a, b) circ.push(mc.GateRZ(self.theta), b) circ.push(mc.GateCX(), a, b) return circ
[docs] class GateRZX(mc.Gate): r"""Two qubit RZX gate. This gate is maximally entangling at :math:`(\theta = \frac{\pi}{2})` **Matrix representation:** .. math:: \operatorname{RZX}(\theta) =\begin{pmatrix} \cos(\frac{\theta}{2}) & -i\sin(\frac{\theta}{2}) & 0 & 0 \\ -i\sin(\frac{\theta}{2}) & \cos(\frac{\theta}{2}) & 0 & 0 \\ 0 & 0 & \cos(\frac{\theta}{2}) & i\sin(\frac{\theta}{2}) \\ 0 & 0 & i\sin(\frac{\theta}{2}) & \cos(\frac{\theta}{2}) \end{pmatrix} Parameters: theta (float): The angle in radians. Examples: >>> from mimiqcircuits import * >>> from symengine import * >>> theta = Symbol('theta') >>> GateRZX(theta) RZX(theta) >>> GateRZX(theta).matrix() [cos((1/2)*theta), -I*sin((1/2)*theta), 0, 0] [-I*sin((1/2)*theta), cos((1/2)*theta), 0, 0] [0, 0, cos((1/2)*theta), I*sin((1/2)*theta)] [0, 0, I*sin((1/2)*theta), cos((1/2)*theta)] <BLANKLINE> >>> c = Circuit().push(GateRZX(theta), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── RZX(theta) @ q[0,1] <BLANKLINE> >>> GateRZX(theta).power(2), GateRZX(theta).inverse() (RZX(theta)**2, RZX(-theta)) >>> GateRZX(theta).decompose() 2-qubit circuit with 5 instructions: ├── H @ q[1] ├── CX @ q[0], q[1] ├── RZ(theta) @ q[1] ├── CX @ q[0], q[1] └── H @ q[1] <BLANKLINE> """ _num_qubits = 2 _name = 'RZX' _parnames = ('theta',) _qregsizes = [2] def __init__(self, theta): self.theta = theta def _matrix(self): theta = self.theta cos2 = cos(theta / 2) sin2 = sin(theta / 2) return Matrix([ [cos2, -I * sin2, 0, 0], [-I * sin2, cos2, 0, 0], [0, 0, cos2, I * sin2], [0, 0, I * sin2, cos2] ])
[docs] def inverse(self): return GateRZX(-self.theta)
def _decompose(self, circ, qubits, bits): a, b = range(self.num_qubits) circ.push(mc.GateH(), b) circ.push(mc.GateCX(), a, b) circ.push(mc.GateRZ(self.theta), b) circ.push(mc.GateCX(), a, b) circ.push(mc.GateH(), b) return circ
[docs] class GateXXplusYY(mc.Gate): r"""Two qubit parametric XXplusYY gate. Also known as an XY gate. Its action is to induce a coherent rotation by some angle between :math:`\ket{10}` and :math:`\ket{01}`. **Matrix representation:** .. math:: \operatorname{(XX+YY)}(\theta, \beta)= \begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & \cos(\frac{\theta}{2}) & -i\sin(\frac{\theta}{2})e^{i\beta} & 0\\ 0 & -i\sin(\frac{\theta}{2})e^{-i\beta} & \cos(\frac{\theta}{2}) & 0\\ 0 & 0 & 0 & 1 \end{pmatrix} Parameters: theta: The angle in radians. beta: The phase angle in radians. Examples: >>> from mimiqcircuits import * >>> from symengine import * >>> theta, beta = symbols('theta beta') >>> GateXXplusYY(theta, beta) XXplusYY(theta, beta) >>> GateXXplusYY(theta, beta).matrix() [1.0, 0, 0, 0] [0, cos((1/2)*theta), (sin(beta) - I*cos(beta))*sin((1/2)*theta), 0] [0, I*(I*sin(beta) - cos(beta))*sin((1/2)*theta), cos((1/2)*theta), 0] [0, 0, 0, 1.0] <BLANKLINE> >>> c = Circuit().push(GateXXplusYY(theta, beta), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── XXplusYY(theta, beta) @ q[0,1] <BLANKLINE> >>> GateXXplusYY(theta, beta).power(2), GateXXplusYY(theta, beta).inverse() (XXplusYY(theta, beta)**2, XXplusYY(-theta, beta)) >>> GateXXplusYY(theta, beta).decompose() 2-qubit circuit with 14 instructions: ├── RZ(beta) @ q[0] ├── RZ((-1/2)*pi) @ q[1] ├── SX @ q[1] ├── RZ((1/2)*pi) @ q[1] ├── S @ q[0] ├── CX @ q[1], q[0] ├── RY((-1/2)*theta) @ q[1] ├── RY((-1/2)*theta) @ q[0] ├── CX @ q[1], q[0] ├── S† @ q[0] ├── RZ((-1/2)*pi) @ q[1] ├── SX† @ q[1] ├── RZ((1/2)*pi) @ q[1] └── RZ(-beta) @ q[0] <BLANKLINE> """ _num_qubits = 2 _name = 'XXplusYY' _parnames = ('theta', 'beta') _qregsizes = [2] def __init__(self, theta, beta): self.theta = theta self.beta = beta def _matrix(self): theta = self.theta beta = self.beta cos2 = cos(theta / 2) sin2 = sin(theta / 2) return Matrix([ [1, 0, 0, 0], [0, cos2, -I * sin2 * cis(beta), 0], [0, -I * sin2 * cis(-beta), cos2, 0], [0, 0, 0, 1] ])
[docs] def inverse(self): return GateXXplusYY(-self.theta, self.beta)
def _decompose(self, circ, qubits, bits): a, b = range(self.num_qubits) circ.push(mc.GateRZ(self.beta), a) circ.push(mc.GateRZ(-pi/2), b) circ.push(mc.GateSX(), b) circ.push(mc.GateRZ(pi/2), b) circ.push(mc.GateS(), a) circ.push(mc.GateCX(), b, a) circ.push(mc.GateRY(-self.theta/2), b) circ.push(mc.GateRY(-self.theta/2), a) circ.push(mc.GateCX(), b, a) circ.push(mc.GateSDG(), a) circ.push(mc.GateRZ(-pi/2), b) circ.push(mc.GateSXDG(), b) circ.push(mc.GateRZ(pi/2), b) circ.push(mc.GateRZ(-self.beta), a) return circ
[docs] class GateXXminusYY(mc.Gate): r"""Two qubit parametric GateXXminusYY gate. Its action is to induce a coherent rotation by some angle between :math:`\ket{00}` and :math:`\ket{11}` **Matrix representation:** .. math:: \operatorname{(XX-YY)}(\theta, \beta)=\begin{pmatrix} \cos(\frac{\theta}{2}) & 0 & 0 & -i\sin(\frac{\theta}{2})e^{-i\beta} \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ -i\sin(\frac{\theta}{2})e^{i\beta} & 0 & 0 & \cos(\frac{\theta}{2}) \end{pmatrix} Parameters: theta (float): The angle in radians. beta (float): The angle in radians. Examples: >>> from mimiqcircuits import * >>> from symengine import * >>> theta, beta = symbols('theta beta') >>> GateXXminusYY(theta, beta) XXminusYY(theta, beta) >>> GateXXminusYY(theta, beta).matrix() [cos((1/2)*theta), 0, 0, I*(I*sin(beta) - cos(beta))*sin((1/2)*theta)] [0, 1.0, 0, 0] [0, 0, 1.0, 0] [(sin(beta) - I*cos(beta))*sin((1/2)*theta), 0, 0, cos((1/2)*theta)] <BLANKLINE> >>> c = Circuit().push(GateXXminusYY(theta, beta), 0, 1) >>> c 2-qubit circuit with 1 instructions: └── XXminusYY(theta, beta) @ q[0,1] <BLANKLINE> >>> GateXXminusYY(theta, beta).power(2), GateXXminusYY(theta, beta).inverse() (XXminusYY(theta, beta)**2, XXminusYY(-theta, beta)) >>> GateXXminusYY(theta, beta).decompose() 2-qubit circuit with 14 instructions: ├── RZ(-beta) @ q[1] ├── RZ((-1/2)*pi) @ q[0] ├── SX @ q[0] ├── RZ((1/2)*pi) @ q[0] ├── S @ q[1] ├── CX @ q[0], q[1] ├── RY((1/2)*theta) @ q[0] ├── RY((-1/2)*theta) @ q[1] ├── CX @ q[0], q[1] ├── S† @ q[1] ├── RZ((-1/2)*pi) @ q[0] ├── SX† @ q[0] ├── RZ((1/2)*pi) @ q[0] └── RZ(beta) @ q[1] <BLANKLINE> """ _num_qubits = 2 _name = 'XXminusYY' _parnames = ('theta', 'beta') _qregsizes = [2] def __init__(self, theta, beta): self.theta = theta self.beta = beta def _matrix(self): theta = self.theta beta = self.beta cos2 = cos(theta / 2) sin2 = sin(theta / 2) return Matrix([ [cos2, 0, 0, -I * sin2 * cis(-beta)], [0, 1, 0, 0], [0, 0, 1, 0], [-I * sin2 * cis(beta), 0, 0, cos2] ])
[docs] def inverse(self): return GateXXminusYY(-self.theta, self.beta)
def _decompose(self, circ, qubits, bits): a, b = range(self.num_qubits) circ.push(mc.GateRZ(-self.beta), b) circ.push(mc.GateRZ(-pi/2), a) circ.push(mc.GateSX(), a) circ.push(mc.GateRZ(pi/2), a) circ.push(mc.GateS(), b) circ.push(mc.GateCX(), a, b) circ.push(mc.GateRY(self.theta/2), a) circ.push(mc.GateRY(-self.theta/2), b) circ.push(mc.GateCX(), a, b) circ.push(mc.GateSDG(), b) circ.push(mc.GateRZ(-pi/2), a) circ.push(mc.GateSXDG(), a) circ.push(mc.GateRZ(pi/2), a) circ.push(mc.GateRZ(self.beta), b) return circ