|
17 | 17 | import numpy as np
|
18 | 18 |
|
19 | 19 | from cirq import protocols
|
| 20 | +from cirq._compat import proper_repr |
20 | 21 | from cirq.qis import quantum_state_representation
|
21 | 22 | from cirq.value import big_endian_int_to_digits, linear_dict
|
22 | 23 |
|
@@ -137,30 +138,92 @@ class CliffordTableau(StabilizerState):
|
137 | 138 | an eigenoperator of the state vector with eigenvalue one: P|psi> = |psi>.
|
138 | 139 | """
|
139 | 140 |
|
140 |
| - def __init__(self, num_qubits, initial_state: int = 0): |
| 141 | + def __init__( |
| 142 | + self, |
| 143 | + num_qubits, |
| 144 | + initial_state: int = 0, |
| 145 | + rs: Optional[np.ndarray] = None, |
| 146 | + xs: Optional[np.ndarray] = None, |
| 147 | + zs: Optional[np.ndarray] = None, |
| 148 | + ): |
141 | 149 | """Initializes CliffordTableau
|
142 | 150 | Args:
|
143 | 151 | num_qubits: The number of qubits in the system.
|
144 | 152 | initial_state: The computational basis representation of the
|
145 | 153 | state as a big endian int.
|
146 | 154 | """
|
147 | 155 | self.n = num_qubits
|
148 |
| - |
149 |
| - # The last row (`2n+1`-th row) is the scratch row used in _measurement |
| 156 | + self.initial_state = initial_state |
| 157 | + # _reconstruct_* adds the last row (`2n+1`-th row) to the input arrays, |
| 158 | + # which is the scratch row used in _measurement |
150 | 159 | # computation process only. It should not be exposed to external usage.
|
151 |
| - self._rs = np.zeros(2 * self.n + 1, dtype=bool) |
152 |
| - |
153 |
| - for (i, val) in enumerate( |
154 |
| - big_endian_int_to_digits(initial_state, digit_count=num_qubits, base=2) |
155 |
| - ): |
156 |
| - self._rs[self.n + i] = bool(val) |
| 160 | + self._rs = self._reconstruct_rs(rs) |
| 161 | + self._xs = self._reconstruct_xs(xs) |
| 162 | + self._zs = self._reconstruct_zs(zs) |
| 163 | + |
| 164 | + def _reconstruct_rs(self, rs: Optional[np.ndarray]) -> np.ndarray: |
| 165 | + if rs is None: |
| 166 | + new_rs = np.zeros(2 * self.n + 1, dtype=bool) |
| 167 | + for (i, val) in enumerate( |
| 168 | + big_endian_int_to_digits(self.initial_state, digit_count=self.n, base=2) |
| 169 | + ): |
| 170 | + new_rs[self.n + i] = bool(val) |
| 171 | + else: |
| 172 | + shape = rs.shape |
| 173 | + if len(shape) == 1 and shape[0] == 2 * self.n and rs.dtype == np.dtype(bool): |
| 174 | + new_rs = np.append(rs, np.zeros(1, dtype=bool)) |
| 175 | + else: |
| 176 | + raise ValueError( |
| 177 | + f"The value you passed for rs is not the correct shape and/or type. " |
| 178 | + f"Please confirm that it's a single row with 2*num_qubits columns " |
| 179 | + f"and of type bool." |
| 180 | + ) |
| 181 | + return new_rs |
| 182 | + |
| 183 | + def _reconstruct_xs(self, xs: Optional[np.ndarray]) -> np.ndarray: |
| 184 | + if xs is None: |
| 185 | + new_xs = np.zeros((2 * self.n + 1, self.n), dtype=bool) |
| 186 | + for i in range(self.n): |
| 187 | + new_xs[i, i] = True |
| 188 | + else: |
| 189 | + shape = xs.shape |
| 190 | + if ( |
| 191 | + len(shape) == 2 |
| 192 | + and shape[0] == 2 * self.n |
| 193 | + and shape[1] == self.n |
| 194 | + and xs.dtype == np.dtype(bool) |
| 195 | + ): |
| 196 | + new_xs = np.append(xs, np.zeros((1, self.n), dtype=bool), axis=0) |
| 197 | + else: |
| 198 | + raise ValueError( |
| 199 | + f"The value you passed for xs is not the correct shape and/or type. " |
| 200 | + f"Please confirm that it's 2*num_qubits rows, num_qubits columns, " |
| 201 | + f"and of type bool." |
| 202 | + ) |
| 203 | + return new_xs |
157 | 204 |
|
158 |
| - self._xs = np.zeros((2 * self.n + 1, self.n), dtype=bool) |
159 |
| - self._zs = np.zeros((2 * self.n + 1, self.n), dtype=bool) |
| 205 | + def _reconstruct_zs(self, zs: Optional[np.ndarray]) -> np.ndarray: |
160 | 206 |
|
161 |
| - for i in range(self.n): |
162 |
| - self._xs[i, i] = True |
163 |
| - self._zs[self.n + i, i] = True |
| 207 | + if zs is None: |
| 208 | + new_zs = np.zeros((2 * self.n + 1, self.n), dtype=bool) |
| 209 | + for i in range(self.n): |
| 210 | + new_zs[self.n + i, i] = True |
| 211 | + else: |
| 212 | + shape = zs.shape |
| 213 | + if ( |
| 214 | + len(shape) == 2 |
| 215 | + and shape[0] == 2 * self.n |
| 216 | + and shape[1] == self.n |
| 217 | + and zs.dtype == np.dtype(bool) |
| 218 | + ): |
| 219 | + new_zs = np.append(zs, np.zeros((1, self.n), dtype=bool), axis=0) |
| 220 | + else: |
| 221 | + raise ValueError( |
| 222 | + f"The value you passed for zs is not the correct shape and/or type. " |
| 223 | + f"Please confirm that it's 2*num_qubits rows, num_qubits columns, " |
| 224 | + f"and of type bool." |
| 225 | + ) |
| 226 | + return new_zs |
164 | 227 |
|
165 | 228 | @property
|
166 | 229 | def xs(self) -> np.ndarray:
|
@@ -233,8 +296,13 @@ def copy(self, deep_copy_buffers: bool = True) -> 'CliffordTableau':
|
233 | 296 | return state
|
234 | 297 |
|
235 | 298 | def __repr__(self) -> str:
|
236 |
| - stabilizers = ", ".join([repr(stab) for stab in self.stabilizers()]) |
237 |
| - return f'stabilizers: [{stabilizers}]' |
| 299 | + return ( |
| 300 | + f"cirq.CliffordTableau({self.n}," |
| 301 | + f"rs={proper_repr(np.delete(self._rs, len(self._rs)-1))}, " |
| 302 | + f"xs={proper_repr(np.delete(self._xs, len(self._xs)-1, axis=0))}," |
| 303 | + f"zs={proper_repr(np.delete(self._zs, len(self._zs)-1, axis=0))}, " |
| 304 | + f"initial_state={self.initial_state})" |
| 305 | + ) |
238 | 306 |
|
239 | 307 | def __str__(self) -> str:
|
240 | 308 | string = ''
|
|
0 commit comments