Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document dimension of X/ZPowGate #5648

Merged
merged 4 commits into from
Jul 8, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 52 additions & 2 deletions cirq-core/cirq/ops/common_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,9 @@ def _pi(rads):
class XPowGate(eigen_gate.EigenGate):
r"""A gate that rotates around the X axis of the Bloch sphere.

The unitary matrix of `cirq.XPowGate(exponent=t)` is:
The unitary matrix of `cirq.XPowGate(exponent=t, global_shift=s)` is:
$$
e^{i \pi s t}
\begin{bmatrix}
e^{i \pi t /2} \cos(\pi t) & -i e^{i \pi t /2} \sin(\pi t) \\
-i e^{i \pi t /2} \sin(\pi t) & e^{i \pi t /2} \cos(\pi t)
Expand All @@ -92,6 +93,30 @@ class XPowGate(eigen_gate.EigenGate):
def __init__(
self, *, exponent: value.TParamVal = 1.0, global_shift: float = 0.0, dimension: int = 2
):
"""Initialize an XPowGate.

Args:
exponent: The t in gate**t. Determines how much the eigenvalues of
the gate are phased by. For example, eigenvectors phased by -1
when `gate**1` is applied will gain a relative phase of
e^{i pi exponent} when `gate**exponent` is applied (relative to
eigenvectors unaffected by `gate**1`).
global_shift: Offsets the eigenvalues of the gate at exponent=1.
In effect, this controls a global phase factor on the gate's
unitary matrix. The factor for global_shift=s is:

exp(i * pi * s * t)

For example, `cirq.X**t` uses a `global_shift` of 0 but
`cirq.rx(t)` uses a `global_shift` of -0.5, which is why
`cirq.unitary(cirq.rx(pi))` equals -iX instead of X.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider updating the formula on line 75 above to account for global shift. Then you can refer to whatever letter you choose to use for global shift in the formula from the description of the argument here. This is what you effectively do on line 98 for exponent=t.

The benefit of this is that it allows the reader to unambiguously identify the gate they will get for given arguments.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, assuming I understood you correctly. PTAL

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's exactly it! :-)

I haven't checked that the math is correct. Might be worth calling np.linalg.eig(cirq.unitary(...)) on one of the gates with a few values of exponent and global_shift and check that the eigenvalues are correct.

Copy link
Collaborator

@viathor viathor Jul 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(To be clear: I think we do this in unit tests, but doing it manually would give you an opportunity to compare the output against the math in the comment.)

dimension: Qudit dimension of this gate. For qu*b*its (the default),
this is set to 2.

Raises:
ValueError: If the supplied exponent is a complex number with an
imaginary component.
"""
super().__init__(exponent=exponent, global_shift=global_shift)
self._dimension = dimension

Expand Down Expand Up @@ -501,8 +526,9 @@ def _from_json_dict_(cls, rads, **kwargs) -> 'Ry':
class ZPowGate(eigen_gate.EigenGate):
r"""A gate that rotates around the Z axis of the Bloch sphere.

The unitary matrix of `cirq.ZPowGate(exponent=t)` is:
The unitary matrix of `cirq.ZPowGate(exponent=t, global_shift=s)` is:
$$
e^{i \pi s t}
\begin{bmatrix}
1 & 0 \\
0 & e^{i \pi t}
Expand All @@ -523,6 +549,30 @@ class ZPowGate(eigen_gate.EigenGate):
def __init__(
self, *, exponent: value.TParamVal = 1.0, global_shift: float = 0.0, dimension: int = 2
):
"""Initialize a ZPowGate.

Args:
exponent: The t in gate**t. Determines how much the eigenvalues of
the gate are phased by. For example, eigenvectors phased by -1
when `gate**1` is applied will gain a relative phase of
e^{i pi exponent} when `gate**exponent` is applied (relative to
eigenvectors unaffected by `gate**1`).
global_shift: Offsets the eigenvalues of the gate at exponent=1.
In effect, this controls a global phase factor on the gate's
unitary matrix. The factor for global_shift=s is:

exp(i * pi * s * t)

For example, `cirq.X**t` uses a `global_shift` of 0 but
`cirq.rx(t)` uses a `global_shift` of -0.5, which is why
`cirq.unitary(cirq.rx(pi))` equals -iX instead of X.
dimension: Qudit dimension of this gate. For qu*b*its (the default),
this is set to 2.

Raises:
ValueError: If the supplied exponent is a complex number with an
imaginary component.
"""
super().__init__(exponent=exponent, global_shift=global_shift)
self._dimension = dimension

Expand Down
2 changes: 1 addition & 1 deletion cirq-core/cirq/ops/eigen_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def __init__(

Args:
exponent: The t in gate**t. Determines how much the eigenvalues of
the gate are scaled by. For example, eigenvectors phased by -1
the gate are phased by. For example, eigenvectors phased by -1
when `gate**1` is applied will gain a relative phase of
e^{i pi exponent} when `gate**exponent` is applied (relative to
eigenvectors unaffected by `gate**1`).
Expand Down