diff --git a/cirq/sim/clifford/clifford_simulator.py b/cirq/sim/clifford/clifford_simulator.py index 0c39bbf3e54..70d54e445b8 100644 --- a/cirq/sim/clifford/clifford_simulator.py +++ b/cirq/sim/clifford/clifford_simulator.py @@ -36,6 +36,7 @@ from cirq.sim import simulator from cirq.sim.clifford import clifford_tableau, stabilizer_state_ch_form from cirq.ops import raw_types +from cirq.ops.dense_pauli_string import DensePauliString from cirq import circuits, study, ops, protocols @@ -252,9 +253,12 @@ def __str__(self): def to_numpy(self): return self.ch_form.to_state_vector() - def stabilizers(self): + def stabilizers(self) -> List[DensePauliString]: return self.tableau.stabilizers() + def destabilizers(self) -> List[DensePauliString]: + return self.tableau.destabilizers() + def wave_function(self): return self.ch_form.wave_function() diff --git a/cirq/sim/clifford/clifford_simulator_test.py b/cirq/sim/clifford/clifford_simulator_test.py index 012e0135dd0..3b8846ef35a 100644 --- a/cirq/sim/clifford/clifford_simulator_test.py +++ b/cirq/sim/clifford/clifford_simulator_test.py @@ -211,7 +211,9 @@ def test_clifford_state_stabilizers(): state.apply_unitary(cirq.H(q1)) state.apply_unitary(cirq.S(q1)) - assert (state.stabilizers() == ['X0', 'Y1', 'Z2']) + f = cirq.DensePauliString + assert (state.stabilizers() == [f('XII'), f('IYI'), f('IIZ')]) + assert (state.destabilizers() == [f('ZII'), f('IZI'), f('IIX')]) def test_clifford_state_wave_function(): @@ -235,8 +237,9 @@ def test_clifford_tableau_str(): def test_clifford_tableau_repr(): (q0, q1) = (cirq.LineQubit(0), cirq.LineQubit(1)) state = cirq.CliffordState(qubit_map={q0: 0, q1: 1}) - - assert (repr(state.tableau) == "stabilizers: [Z0, Z1]") + f = cirq.DensePauliString + assert (repr(state.tableau) == "stabilizers: [{!r}, {!r}]".format( + f("ZI"), f("IZ"))) def test_clifford_tableau_str_full(): diff --git a/cirq/sim/clifford/clifford_tableau.py b/cirq/sim/clifford/clifford_tableau.py index f96a50bca05..d77c83cea80 100644 --- a/cirq/sim/clifford/clifford_tableau.py +++ b/cirq/sim/clifford/clifford_tableau.py @@ -12,8 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. +from typing import List import numpy as np +import cirq +from cirq.ops.dense_pauli_string import DensePauliString + class CliffordTableau(): """ Tableau representation of a stabilizer state @@ -55,7 +59,8 @@ def copy(self): return state def __repr__(self): - return "stabilizers: [{}]".format(", ".join(self.stabilizers())) + return "stabilizers: [{}]".format(", ".join( + [repr(stab) for stab in self.stabilizers()])) def __str__(self): string = "" @@ -163,25 +168,31 @@ def g(x1, z1, x2, z2): self.xs[q1, :] ^= self.xs[q2, :] self.zs[q1, :] ^= self.zs[q2, :] - def stabilizers(self): - """Returns the stabilizer generators of the state. These - are n operators {S_1,S_2,...,S_n} such thate S_i |psi> = |psi> """ - stabilizers = [] - - for i in range(self.n, 2 * self.n): - stabilizer = "-" if self.rs[i] else "" - - for k in range(self.n): - if self.xs[i, k] & (not self.zs[i, k]): - stabilizer += "X%d" % k - elif (not self.xs[i, k]) & self.zs[i, k]: - stabilizer += "Z%d" % k - elif self.xs[i, k] & self.zs[i, k]: - stabilizer += "Y%d" % k - - stabilizers.append(stabilizer) + def _row_to_dense_pauli(self, i: int) -> DensePauliString: + coefficient = -1 if self.rs[i] else 1 + pauli_mask = "" + + for k in range(self.n): + if self.xs[i, k] & (not self.zs[i, k]): + pauli_mask += "X" + elif (not self.xs[i, k]) & self.zs[i, k]: + pauli_mask += "Z" + elif self.xs[i, k] & self.zs[i, k]: + pauli_mask += "Y" + else: + pauli_mask += "I" + return cirq.DensePauliString(pauli_mask, coefficient=coefficient) - return stabilizers + def stabilizers(self) -> List[DensePauliString]: + """Returns the stabilizer generators of the state. These + are n operators {S_1,S_2,...,S_n} such that S_i |psi> = |psi> """ + return [self._row_to_dense_pauli(i) for i in range(self.n, 2 * self.n)] + + def destabilizers(self) -> List[DensePauliString]: + """Returns the destabilizer generators of the state. These + are n operators {S_1,S_2,...,S_n} such that along with the stabilizer + generators above generate the full Pauli group on n qubits.""" + return [self._row_to_dense_pauli(i) for i in range(0, self.n)] def _measure(self, q): """ Performs a projective measurement on the q'th qubit.