@@ -620,6 +620,29 @@ def from_unitary(u: np.ndarray) -> Optional['SingleQubitCliffordGate']:
620
620
_to_clifford_tableau (x_to = x_to , z_to = z_to )
621
621
)
622
622
623
+ @classmethod
624
+ def from_unitary_with_global_phase (
625
+ cls , u : np .ndarray
626
+ ) -> Optional [Tuple ['SingleQubitCliffordGate' , complex ]]:
627
+ """Creates Clifford gate with given unitary, including global phase.
628
+
629
+ Args:
630
+ u: 2x2 unitary matrix of a Clifford gate.
631
+
632
+ Returns:
633
+ A tuple of a SingleQubitCliffordGate and a global phase, such that
634
+ the gate unitary (as given by `cirq.unitary`) times the global phase
635
+ is identical to the given unitary `u`; or `None` if `u` is not the
636
+ matrix of a single-qubit Clifford gate.
637
+ """
638
+ gate = cls .from_unitary (u )
639
+ if gate is None :
640
+ return None
641
+ # Find the entry with the largest magnitude in the input unitary, to find
642
+ # the global phase difference between the input unitary and the gate unitary.
643
+ k = max (np .ndindex (* u .shape ), key = lambda t : abs (u [t ]))
644
+ return gate , u [k ] / protocols .unitary (gate )[k ]
645
+
623
646
def pauli_tuple (self , pauli : Pauli ) -> Tuple [Pauli , bool ]:
624
647
"""Returns a tuple of a Pauli operator and a boolean.
625
648
@@ -730,10 +753,7 @@ def _act_on_(
730
753
# Single Clifford Gate decomposition is more efficient than the general Tableau decomposition.
731
754
def _decompose_ (self , qubits : Sequence ['cirq.Qid' ]) -> 'cirq.OP_TREE' :
732
755
(qubit ,) = qubits
733
- if self == SingleQubitCliffordGate .H :
734
- return (common_gates .H (qubit ),)
735
- rotations = self .decompose_rotation ()
736
- return tuple (r .on (qubit ) ** (qt / 2 ) for r , qt in rotations )
756
+ return tuple (gate .on (qubit ) for gate in self .decompose_gate ())
737
757
738
758
def _commutes_ (
739
759
self , other : Any , * , atol : float = 1e-8
@@ -773,10 +793,29 @@ def _unitary_(self) -> np.ndarray:
773
793
mat = protocols .unitary (op ).dot (mat )
774
794
return mat
775
795
796
+ def decompose_gate (self ) -> Sequence ['cirq.Gate' ]:
797
+ """Decomposes this clifford into a series of H and pauli rotation gates.
798
+
799
+ Returns:
800
+ A sequence of H and pauli rotation gates which are equivalent to this
801
+ clifford gate if applied in order. This decomposition agrees with
802
+ cirq.unitary(self), including global phase.
803
+ """
804
+ if self == SingleQubitCliffordGate .H :
805
+ return [common_gates .H ]
806
+ rotations = self .decompose_rotation ()
807
+ return [r ** (qt / 2 ) for r , qt in rotations ]
808
+
776
809
def decompose_rotation (self ) -> Sequence [Tuple [Pauli , int ]]:
777
- """Returns ((first_rotation_axis, first_rotation_quarter_turns), ...)
810
+ """Decomposes this clifford into a series of pauli rotations.
778
811
779
- This is a sequence of zero, one, or two rotations."""
812
+ Each rotation is given as a tuple of (axis, quarter_turns),
813
+ where axis is a Pauli giving the axis to rotate about. The
814
+ result will be a sequence of zero, one, or two rotations.
815
+
816
+ Note that the combined unitary effect of these rotations may
817
+ differ from cirq.unitary(self) by a global phase.
818
+ """
780
819
x_rot = self .pauli_tuple (pauli_gates .X )
781
820
y_rot = self .pauli_tuple (pauli_gates .Y )
782
821
z_rot = self .pauli_tuple (pauli_gates .Z )
0 commit comments