Skip to content

Commit

Permalink
move SU2RotationGate to basic_gates/ (#802)
Browse files Browse the repository at this point in the history
* move `SU2RotationGate` to `basic_gates/`

* add cirq_op and wire_symbol

* add bloq_example

* add tensor

* add more bloq examples

* add autotest, tensor test

* support global shift, verify unitaries for examples

* comment: can't use `lambda` for var name

* add `from_matrix`

* `_unitary_` + test

* test T complexity

* eps

* support parameterized

* regenerate notebook

* use GlobalPhase bloq

* 2024

* fix TComplexity for `cirq.GlobalPhaseGate` and `cirq.global_phase_operation`

* test call graph

* code cleanup
  • Loading branch information
anurudhp authored Apr 1, 2024
1 parent 4dffc97 commit c77e59d
Show file tree
Hide file tree
Showing 12 changed files with 488 additions and 69 deletions.
5 changes: 5 additions & 0 deletions dev_tools/autogenerate-bloqs-notebooks-v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@
module=qualtran.bloqs.basic_gates.hadamard,
bloq_specs=[qualtran.bloqs.basic_gates.hadamard._HADAMARD_DOC],
),
NotebookSpecV2(
title='SU2 Rotation',
module=qualtran.bloqs.basic_gates.su2_rotation,
bloq_specs=[qualtran.bloqs.basic_gates.su2_rotation._SU2_ROTATION_GATE_DOC],
),
NotebookSpecV2(
title='S Gate',
module=qualtran.bloqs.basic_gates.s_gate,
Expand Down
1 change: 1 addition & 0 deletions qualtran/bloqs/basic_gates/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from .on_each import OnEach
from .rotation import CZPowGate, Rx, Ry, Rz, XPowGate, YPowGate, ZPowGate
from .s_gate import SGate
from .su2_rotation import SU2RotationGate
from .swap import CSwap, Swap, TwoBitCSwap, TwoBitSwap
from .t_gate import TGate
from .toffoli import Toffoli
Expand Down
181 changes: 181 additions & 0 deletions qualtran/bloqs/basic_gates/su2_rotation.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "d6d914da",
"metadata": {
"cq.autogen": "title_cell"
},
"source": [
"# SU2 Rotation"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ded96bc8",
"metadata": {
"cq.autogen": "top_imports"
},
"outputs": [],
"source": [
"from qualtran import Bloq, CompositeBloq, BloqBuilder, Signature, Register\n",
"from qualtran import QBit, QInt, QUInt, QAny\n",
"from qualtran.drawing import show_bloq, show_call_graph, show_counts_sigma\n",
"from typing import *\n",
"import numpy as np\n",
"import sympy\n",
"import cirq"
]
},
{
"cell_type": "markdown",
"id": "4b2a9c14",
"metadata": {
"cq.autogen": "SU2RotationGate.bloq_doc.md"
},
"source": [
"## `SU2RotationGate`\n",
"Implements an arbitrary SU(2) rotation.\n",
"\n",
"The rotation is represented by the matrix:\n",
"\n",
"$$\n",
" e^{i \\alpha}\n",
" \\begin{pmatrix}\n",
" e^{i(\\lambda + \\phi)} \\cos(\\theta) & e^{i\\phi} \\sin(\\theta) \\\\\n",
" e^{i\\lambda} \\sin(\\theta) & - \\cos(\\theta)\n",
" \\end{pmatrix}\n",
"$$\n",
"\n",
"#### Parameters\n",
" - `theta`: rotation angle $\\theta$ in the above matrix.\n",
" - `phi`: phase angle $\\phi$ in the above matrix.\n",
" - `lambd`: phase angle $\\lambda$ in the above matrix.\n",
" - `global_shift`: phase angle $\\alpha$, i.e. apply a global phase shift of $e^{i \\alpha}$. \n",
"\n",
"#### References\n",
" - [Generalized Quantum Signal Processing](https://arxiv.org/abs/2308.01501). Motlagh and Wiebe. (2023). Equation 7.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "950a1fe9",
"metadata": {
"cq.autogen": "SU2RotationGate.bloq_doc.py"
},
"outputs": [],
"source": [
"from qualtran.bloqs.basic_gates import SU2RotationGate"
]
},
{
"cell_type": "markdown",
"id": "26277091",
"metadata": {
"cq.autogen": "SU2RotationGate.example_instances.md"
},
"source": [
"### Example Instances"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5d165eae",
"metadata": {
"cq.autogen": "SU2RotationGate.su2_rotation_gate"
},
"outputs": [],
"source": [
"su2_rotation_gate = SU2RotationGate(np.pi / 4, np.pi / 2, np.pi / 2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6b034a9b",
"metadata": {
"cq.autogen": "SU2RotationGate.hadamard"
},
"outputs": [],
"source": [
"hadamard = SU2RotationGate(np.pi / 4, 0, 0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "baa38dac",
"metadata": {
"cq.autogen": "SU2RotationGate.t_gate"
},
"outputs": [],
"source": [
"t_gate = SU2RotationGate(0, 3 * np.pi / 4, 0, -3 * np.pi / 4)"
]
},
{
"cell_type": "markdown",
"id": "e85d6f3f",
"metadata": {
"cq.autogen": "SU2RotationGate.graphical_signature.md"
},
"source": [
"#### Graphical Signature"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1469a240",
"metadata": {
"cq.autogen": "SU2RotationGate.graphical_signature.py"
},
"outputs": [],
"source": [
"from qualtran.drawing import show_bloqs\n",
"show_bloqs([su2_rotation_gate, hadamard, t_gate],\n",
" ['`su2_rotation_gate`', '`hadamard`', '`t_gate`'])"
]
},
{
"cell_type": "markdown",
"id": "eb5742c2",
"metadata": {
"cq.autogen": "SU2RotationGate.call_graph.md"
},
"source": [
"### Call Graph"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1198abe9",
"metadata": {
"cq.autogen": "SU2RotationGate.call_graph.py"
},
"outputs": [],
"source": [
"from qualtran.resource_counting.generalizers import ignore_split_join\n",
"su2_rotation_gate_g, su2_rotation_gate_sigma = su2_rotation_gate.call_graph(max_depth=1, generalizer=ignore_split_join)\n",
"show_call_graph(su2_rotation_gate_g)\n",
"show_counts_sigma(su2_rotation_gate_sigma)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
170 changes: 170 additions & 0 deletions qualtran/bloqs/basic_gates/su2_rotation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
# Copyright 2024 Google LLC
#
# 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
#
# https://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.
from functools import cached_property
from typing import Any, Dict, TYPE_CHECKING

import cirq
import numpy as np
import sympy
from attrs import frozen
from numpy.typing import NDArray

from qualtran import bloq_example, BloqDocSpec, GateWithRegisters, Signature
from qualtran.bloqs.basic_gates import GlobalPhase, Ry, ZPowGate
from qualtran.cirq_interop.t_complexity_protocol import TComplexity
from qualtran.drawing import TextBox

if TYPE_CHECKING:
import quimb.tensor as qtn

from qualtran import BloqBuilder, Soquet, SoquetT
from qualtran.drawing import WireSymbol


@frozen
class SU2RotationGate(GateWithRegisters):
r"""Implements an arbitrary SU(2) rotation.
The rotation is represented by the matrix:
$$
e^{i \alpha}
\begin{pmatrix}
e^{i(\lambda + \phi)} \cos(\theta) & e^{i\phi} \sin(\theta) \\
e^{i\lambda} \sin(\theta) & - \cos(\theta)
\end{pmatrix}
$$
Args:
theta: rotation angle $\theta$ in the above matrix.
phi: phase angle $\phi$ in the above matrix.
lambd: phase angle $\lambda$ in the above matrix.
global_shift: phase angle $\alpha$, i.e. apply a global phase shift of $e^{i \alpha}$.
References:
[Generalized Quantum Signal Processing](https://arxiv.org/abs/2308.01501)
Motlagh and Wiebe. (2023). Equation 7.
"""

theta: float
phi: float
lambd: float # cannot use `lambda` as it is a python keyword
global_shift: float = 0
eps: float = 1e-11

@cached_property
def signature(self) -> Signature:
return Signature.build(q=1)

@cached_property
def rotation_matrix(self) -> NDArray[np.complex_]:
return np.exp(1j * self.global_shift) * np.array(
[
[
np.exp(1j * (self.lambd + self.phi)) * np.cos(self.theta),
np.exp(1j * self.phi) * np.sin(self.theta),
],
[np.exp(1j * self.lambd) * np.sin(self.theta), -np.cos(self.theta)],
]
)

@staticmethod
def from_matrix(mat: NDArray[np.complex_]) -> 'SU2RotationGate':
theta = np.arctan2(np.abs(mat[1, 0]), np.abs(mat[0, 0]))
if np.isclose(np.cos(theta), 0):
alpha = 0
phi = np.angle(mat[0, 1] / np.sin(theta))
lambd = np.angle(mat[1, 0] / np.sin(theta))
else:
alpha = np.angle(-mat[1, 1] / np.cos(theta))
if np.isclose(np.sin(theta), 0):
phi = np.angle(mat[0, 0] / np.cos(theta) * np.exp(-1j * alpha))
lambd = 0
else:
phi = np.angle(mat[0, 1] / np.sin(theta) * np.exp(-1j * alpha))
lambd = np.angle(mat[1, 0] / np.sin(theta) * np.exp(-1j * alpha))

return SU2RotationGate(theta, phi, lambd, alpha)

def add_my_tensors(
self,
tn: 'qtn.TensorNetwork',
tag: Any,
*,
incoming: Dict[str, 'SoquetT'],
outgoing: Dict[str, 'SoquetT'],
):
import quimb.tensor as qtn

tn.add(
qtn.Tensor(
data=self.rotation_matrix,
inds=(outgoing['q'], incoming['q']),
tags=[self.short_name(), tag],
)
)

def _unitary_(self):
if self._is_parameterized_():
return None
return self.rotation_matrix

def build_composite_bloq(self, bb: 'BloqBuilder', q: 'SoquetT') -> Dict[str, 'SoquetT']:
pi = sympy.pi if self._is_parameterized_() else np.pi
exp = sympy.exp if self._is_parameterized_() else np.exp

bb.add(GlobalPhase(coefficient=-exp(1j * self.global_shift), eps=self.eps / 4))
q = bb.add(ZPowGate(exponent=1 - self.lambd / pi, global_shift=-1, eps=self.eps / 4), q=q)
q = bb.add(Ry(angle=2 * self.theta, eps=self.eps / 4), q=q)
q = bb.add(ZPowGate(exponent=-self.phi / pi, global_shift=-1, eps=self.eps / 4), q=q)
return {'q': q}

def pretty_name(self) -> str:
return 'SU_2'

def wire_symbol(self, soq: 'Soquet') -> 'WireSymbol':
return TextBox(
f"{self.pretty_name()}({self.theta}, {self.phi}, {self.lambd}, {self.global_shift})"
)

def _t_complexity_(self) -> TComplexity:
return TComplexity(rotations=3)

def _is_parameterized_(self) -> bool:
return cirq.is_parameterized((self.theta, self.phi, self.lambd, self.global_shift))


@bloq_example
def _su2_rotation_gate() -> SU2RotationGate:
su2_rotation_gate = SU2RotationGate(np.pi / 4, np.pi / 2, np.pi / 2)
return su2_rotation_gate


@bloq_example
def _hadamard() -> SU2RotationGate:
hadamard = SU2RotationGate(np.pi / 4, 0, 0)
return hadamard


@bloq_example
def _t_gate() -> SU2RotationGate:
t_gate = SU2RotationGate(0, 3 * np.pi / 4, 0, -3 * np.pi / 4)
return t_gate


_SU2_ROTATION_GATE_DOC = BloqDocSpec(
bloq_cls=SU2RotationGate,
import_line='from qualtran.bloqs.basic_gates import SU2RotationGate',
examples=[_su2_rotation_gate, _hadamard, _t_gate],
)
Loading

0 comments on commit c77e59d

Please sign in to comment.