-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This gives a canonical single qubit operation to optimize into when doing microwave rotations with virtual Zs
- Loading branch information
Showing
8 changed files
with
469 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -234,6 +234,7 @@ | |
PhaseGradientGate, | ||
PhasedISwapPowGate, | ||
PhasedXPowGate, | ||
PhasedXZGate, | ||
PhaseFlipChannel, | ||
QFT, | ||
Qid, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
import numbers | ||
from typing import Union, TYPE_CHECKING, Tuple, Optional, Sequence | ||
|
||
import numpy as np | ||
import sympy | ||
|
||
from cirq import value, ops, protocols, linalg | ||
from cirq.ops import gate_features | ||
from cirq._compat import proper_repr | ||
|
||
if TYPE_CHECKING: | ||
import cirq | ||
|
||
|
||
@value.value_equality(approximate=True) | ||
class PhasedXZGate(gate_features.SingleQubitGate): | ||
"""A single qubit operation expressed as $Z^z Z^a X^x Z^{-a}$. | ||
The above expression is a matrix multiplication with time going to the left. | ||
In quantum circuit notation, this operation decomposes into this circuit: | ||
───Z^(-a)──X^x──Z^a────Z^z───$ | ||
The axis phase exponent (a) decides which axis in the XY plane to rotate | ||
around. The amount of rotation around that axis is decided by the x | ||
exponent (x). Then the z exponent (z) decides how much to phase the qubit. | ||
""" | ||
|
||
def __init__(self, *, x_exponent: Union[numbers.Real, sympy.Basic], | ||
z_exponent: Union[numbers.Real, sympy.Basic], | ||
axis_phase_exponent: Union[numbers.Real, sympy.Basic]) -> None: | ||
""" | ||
Args: | ||
x_exponent: Determines how much to rotate during the | ||
axis-in-XY-plane rotation. The $x$ in $Z^z Z^a X^x Z^{-a}$. | ||
z_exponent: The amount of phasing to apply after the | ||
axis-in-XY-plane rotation. The $z$ in $Z^z Z^a X^x Z^{-a}$. | ||
axis_phase_exponent: Determines which axis to rotate around during | ||
the axis-in-XY-plane rotation. The $a$ in $Z^z Z^a X^x Z^{-a}$. | ||
""" | ||
self._x_exponent = x_exponent | ||
self._z_exponent = z_exponent | ||
self._axis_phase_exponent = axis_phase_exponent | ||
|
||
def _canonical(self) -> 'cirq.PhasedXZGate': | ||
x = self.x_exponent | ||
z = self.z_exponent | ||
a = self.axis_phase_exponent | ||
|
||
# Canonicalize X exponent into (-1, +1]. | ||
if isinstance(x, numbers.Real): | ||
x %= 2 | ||
if x > 1: | ||
x -= 2 | ||
# Axis phase exponent is irrelevant if there is no X exponent. | ||
if x == 0: | ||
a = 0 | ||
# For 180 degree X rotations, the axis phase and z exponent overlap. | ||
if x == 1 and z != 0: | ||
a -= z / 2 | ||
z = 0 | ||
|
||
# Canonicalize Z exponent into (-1, +1]. | ||
if isinstance(z, numbers.Real): | ||
z %= 2 | ||
if z > 1: | ||
z -= 2 | ||
|
||
# Canonicalize axis phase exponent into (-0.5, +0.5]. | ||
if isinstance(a, numbers.Real): | ||
a %= 2 | ||
if a > 1: | ||
a -= 2 | ||
if a <= -0.5: | ||
a += 1 | ||
x = -x | ||
elif a > 0.5: | ||
a -= 1 | ||
x = -x | ||
|
||
return PhasedXZGate(x_exponent=x, z_exponent=z, axis_phase_exponent=a) | ||
|
||
@property | ||
def x_exponent(self) -> Union[numbers.Real, sympy.Basic]: | ||
return self._x_exponent | ||
|
||
@property | ||
def z_exponent(self) -> Union[numbers.Real, sympy.Basic]: | ||
return self._z_exponent | ||
|
||
@property | ||
def axis_phase_exponent(self) -> Union[numbers.Real, sympy.Basic]: | ||
return self._axis_phase_exponent | ||
|
||
def _value_equality_values_(self): | ||
c = self._canonical() | ||
return ( | ||
value.PeriodicValue(c._x_exponent, 2), | ||
value.PeriodicValue(c._z_exponent, 2), | ||
value.PeriodicValue(c._axis_phase_exponent, 2), | ||
) | ||
|
||
@staticmethod | ||
def from_matrix(mat: np.array) -> 'cirq.PhasedXZGate': | ||
pre_phase, rotation, post_phase = ( | ||
linalg.deconstruct_single_qubit_matrix_into_angles(mat)) | ||
pre_phase /= np.pi | ||
post_phase /= np.pi | ||
rotation /= np.pi | ||
pre_phase -= 0.5 | ||
post_phase += 0.5 | ||
return PhasedXZGate(x_exponent=rotation, | ||
axis_phase_exponent=-pre_phase, | ||
z_exponent=post_phase + pre_phase)._canonical() | ||
|
||
def _qasm_(self, args: 'cirq.QasmArgs', | ||
qubits: Tuple['cirq.Qid', ...]) -> Optional[str]: | ||
from cirq.circuits import qasm_output | ||
qasm_gate = qasm_output.QasmUGate(lmda=0.5 - self._axis_phase_exponent, | ||
theta=self._x_exponent, | ||
phi=self._z_exponent + | ||
self._axis_phase_exponent - 0.5) | ||
return protocols.qasm(qasm_gate, args=args, qubits=qubits) | ||
|
||
def _decompose_(self, qubits: Sequence['cirq.Qid']) -> 'cirq.OP_TREE': | ||
q = qubits[0] | ||
yield ops.Z(q)**-self._axis_phase_exponent | ||
yield ops.X(q)**self._x_exponent | ||
yield ops.Z(q)**(self._axis_phase_exponent + self._z_exponent) | ||
|
||
def __pow__(self, exponent: Union[float, int]) -> 'PhasedXZGate': | ||
if exponent == 1: | ||
return self | ||
if exponent == -1: | ||
return PhasedXZGate( | ||
x_exponent=-self._x_exponent, | ||
z_exponent=-self._z_exponent, | ||
axis_phase_exponent=self._z_exponent + self.axis_phase_exponent, | ||
) | ||
return NotImplemented | ||
|
||
def _is_parameterized_(self) -> bool: | ||
"""See `cirq.SupportsParameterization`.""" | ||
return (protocols.is_parameterized(self._x_exponent) or | ||
protocols.is_parameterized(self._z_exponent) or | ||
protocols.is_parameterized(self._axis_phase_exponent)) | ||
|
||
def _resolve_parameters_(self, param_resolver) -> 'cirq.PhasedXZGate': | ||
"""See `cirq.SupportsParameterization`.""" | ||
return PhasedXZGate( | ||
z_exponent=param_resolver.value_of(self._z_exponent), | ||
x_exponent=param_resolver.value_of(self._x_exponent), | ||
axis_phase_exponent=param_resolver.value_of( | ||
self._axis_phase_exponent), | ||
) | ||
|
||
def _phase_by_(self, phase_turns, qubit_index) -> 'cirq.PhasedXZGate': | ||
"""See `cirq.SupportsPhase`.""" | ||
assert qubit_index == 0 | ||
return PhasedXZGate(x_exponent=self._x_exponent, | ||
z_exponent=self._z_exponent, | ||
axis_phase_exponent=self._axis_phase_exponent + | ||
phase_turns * 2) | ||
|
||
def _circuit_diagram_info_(self, | ||
args: 'cirq.CircuitDiagramInfoArgs') -> str: | ||
"""See `cirq.SupportsCircuitDiagramInfo`.""" | ||
return (f'PhXZ(' | ||
f'a={args.format_real(self._axis_phase_exponent)},' | ||
f'x={args.format_real(self._x_exponent)},' | ||
f'z={args.format_real(self._z_exponent)})') | ||
|
||
def __str__(self): | ||
return protocols.circuit_diagram_info(self).wire_symbols[0] | ||
|
||
def __repr__(self): | ||
return (f'cirq.PhasedXZGate(' | ||
f'axis_phase_exponent={proper_repr(self._axis_phase_exponent)},' | ||
f' x_exponent={proper_repr(self._x_exponent)}, ' | ||
f'z_exponent={proper_repr(self._z_exponent)})') | ||
|
||
def _json_dict_(self): | ||
return protocols.obj_to_dict_helper( | ||
self, ['axis_phase_exponent', 'x_exponent', 'z_exponent']) |
Oops, something went wrong.