def assert_has_consistent_apply_unitary(val: Any, *, qubit_count: Optional[int] = None, atol: float = 1e-8) -> None: """Tests whether a value's _apply_unitary_ is correct. Contrasts the effects of the value's `_apply_unitary_` with the matrix returned by the value's `_unitary_` method. Args: val: The value under test. Should have a `__pow__` method. qubit_count: Usually inferred. The number of qubits the value acts on. This argument isn't needed if the gate has a unitary matrix or implements `cirq.SingleQubitGate`/`cirq.TwoQubitGate`/ `cirq.ThreeQubitGate`. atol: Absolute error tolerance. """ expected = protocols.unitary(val, default=None) qubit_counts = [ qubit_count, # Only fall back to using the unitary size if num_qubits or qid_shape # protocols are not defined. protocols.num_qubits(val, default=expected.shape[0].bit_length() - 1 if expected is not None else None), _infer_qubit_count(val) ] qubit_counts = [e for e in qubit_counts if e is not None] if not qubit_counts: raise NotImplementedError( 'Failed to infer qubit count of <{!r}>. Specify it.'.format(val)) assert len(set(qubit_counts)) == 1, ( 'Inconsistent qubit counts from different methods: {}'.format( qubit_counts)) n = cast(int, qubit_counts[0]) qid_shape = protocols.qid_shape(val, default=(2, ) * n) eye = linalg.eye_tensor((2, ) + qid_shape, dtype=np.complex128) actual = protocols.apply_unitary( unitary_value=val, args=protocols.ApplyUnitaryArgs(target_tensor=eye, available_buffer=np.ones_like(eye) * float('nan'), axes=list(range(1, n + 1))), default=None) # If you don't have a unitary, you shouldn't be able to apply a unitary. if expected is None: assert actual is None else: expected = np.kron(np.eye(2), expected) # If you applied a unitary, it should match the one you say you have. if actual is not None: np.testing.assert_allclose(actual.reshape((np.prod( (2, ) + qid_shape, dtype=int), ) * 2), expected, atol=atol)
def _unitary_(self) -> Union[np.ndarray, NotImplementedType]: sub_matrix = protocols.unitary(self.sub_operation, None) if sub_matrix is None: return NotImplemented qid_shape = protocols.qid_shape(self) sub_n = len(qid_shape) - len(self.controls) tensor = linalg.eye_tensor(qid_shape, dtype=sub_matrix.dtype) sub_tensor = sub_matrix.reshape(qid_shape[len(self.controls):] * 2) for control_vals in itertools.product(*self.control_values): active = (*(v for v in control_vals), *(slice(None), ) * sub_n) * 2 tensor[active] = sub_tensor return tensor.reshape((np.prod(qid_shape, dtype=int), ) * 2)
def assert_has_consistent_apply_unitary(val: Any, *, atol: float = 1e-8) -> None: """Tests whether a value's _apply_unitary_ is correct. Contrasts the effects of the value's `_apply_unitary_` with the matrix returned by the value's `_unitary_` method. Args: val: The value under test. Should have a `__pow__` method. atol: Absolute error tolerance. """ # pylint: disable=unused-variable __tracebackhide__ = True # pylint: enable=unused-variable _assert_apply_unitary_works_when_axes_transposed(val, atol=atol) expected = protocols.unitary(val, default=None) qid_shape = protocols.qid_shape(val) eye = linalg.eye_tensor((2, ) + qid_shape, dtype=np.complex128) actual = protocols.apply_unitary( unitary_value=val, args=protocols.ApplyUnitaryArgs(target_tensor=eye, available_buffer=np.ones_like(eye) * float('nan'), axes=list(range(1, len(qid_shape) + 1))), default=None) # If you don't have a unitary, you shouldn't be able to apply a unitary. if expected is None: assert actual is None else: expected = np.kron(np.eye(2), expected) # If you applied a unitary, it should match the one you say you have. if actual is not None: np.testing.assert_allclose(actual.reshape((np.prod( (2, ) + qid_shape, dtype=int), ) * 2), expected, atol=atol)
def _strat_unitary_from_decompose(val: Any) -> Optional[np.ndarray]: """Attempts to compute a value's unitary via its _decompose_ method.""" # Check if there's a decomposition. operations, qubits, val_qid_shape = ( _try_decompose_into_operations_and_qubits(val)) if operations is None: return NotImplemented # Apply sub-operations' unitary effects to an identity matrix. state = linalg.eye_tensor(val_qid_shape, dtype=np.complex128) buffer = np.empty_like(state) result = apply_unitaries( operations, qubits, ApplyUnitaryArgs(state, buffer, range(len(val_qid_shape))), None) # Package result. if result is None: return None state_len = np.prod(val_qid_shape, dtype=int) return result.reshape((state_len, state_len))
def _strat_unitary_from_apply_unitary(val: Any) -> Optional[np.ndarray]: """Attempts to compute a value's unitary via its _apply_unitary_ method.""" # Check for the magic method. method = getattr(val, '_apply_unitary_', None) if method is None: return NotImplemented # Get the qid_shape. val_qid_shape = qid_shape_protocol.qid_shape(val, None) if val_qid_shape is None: return NotImplemented # Apply unitary effect to an identity matrix. state = linalg.eye_tensor(val_qid_shape, dtype=np.complex128) buffer = np.empty_like(state) result = method(ApplyUnitaryArgs(state, buffer, range(len(val_qid_shape)))) if result is NotImplemented or result is None: return result state_len = np.prod(val_qid_shape, dtype=int) return result.reshape((state_len, state_len))