def _strat_unitary_from_apply_unitary(val: Any) -> Optional[np.ndarray]: """Attempts to compute a value's unitary via its _apply_unitary_ method.""" from cirq.protocols.apply_unitary import ApplyUnitaryArgs from cirq import ops # Check for the magic method. method = getattr(val, '_apply_unitary_', None) if method is None: return NotImplemented # Infer number of qubits. if isinstance(val, ops.Gate): n = val.num_qubits() elif isinstance(val, ops.Operation): n = len(val.qubits) else: return NotImplemented # Apply unitary effect to an identity matrix. state = np.eye(1 << n, dtype=np.complex128) state.shape = (2,) * (2 * n) buffer = np.empty_like(state) result = method(ApplyUnitaryArgs(state, buffer, range(n))) if result is NotImplemented or result is None: return result return result.reshape((1 << n, 1 << n))
def _decompose_and_get_unitary(val: 'cirq.Operation') -> np.ndarray: """Try to decompose an `Operation` and return its unitary. Returns: If `val` can be decomposed into unitaries, calculate the resulting unitary and return it. If it doesn't exist, None is returned. """ from cirq.protocols.apply_unitary import apply_unitary, ApplyUnitaryArgs from cirq.protocols.decompose import decompose_once decomposed_val = decompose_once(val, None) if decomposed_val is not None: # Calculate the resulting unitary (if it exists) n = len(val.qubits) state = np.eye(1 << n, dtype=np.complex128) state.shape = (2, ) * (2 * n) buffer = np.zeros(state.shape, dtype=np.complex128) qubit_map = {q: i for i, q in enumerate(val.qubits)} result = state for op in decomposed_val: indices = [qubit_map[q] for q in op.qubits] result = apply_unitary(unitary_value=op, args=ApplyUnitaryArgs( state, buffer, indices), default=None) if result is None: return None if result is buffer: buffer = state state = result if result is not None: return result.reshape((1 << n, 1 << n))
def _apply_unitary(val: Any, args: 'ApplyChannelArgs') -> Optional[np.ndarray]: """Attempt to use `apply_unitary` and return the result. If `val` does not support `apply_unitary` returns None. """ left_args = ApplyUnitaryArgs(target_tensor=args.target_tensor, available_buffer=args.auxiliary_buffer0, axes=args.left_axes) left_result = apply_unitary(val, left_args, None) if left_result is None: return None right_args = ApplyUnitaryArgs(target_tensor=np.conjugate(left_result), available_buffer=args.out_buffer, axes=args.right_axes) right_result = apply_unitary(val, right_args) np.conjugate(right_result, out=right_result) return right_result
def _strat_has_unitary_from_apply_unitary(val: Any) -> Optional[bool]: """Attempts to infer a value's unitary-ness via its _apply_unitary_ method. """ method = getattr(val, '_apply_unitary_', None) if method is None: return None val_qid_shape = qid_shape_protocol.qid_shape(val, None) if val_qid_shape is None: return None state = linalg.one_hot(shape=val_qid_shape, dtype=np.complex64) buffer = np.empty_like(state) result = method(ApplyUnitaryArgs(state, buffer, range(len(val_qid_shape)))) if result is NotImplemented: return None return result is not None
def _decompose_and_get_unitary( val: Union['cirq.Operation', 'cirq.Gate']) -> np.ndarray: """Try to decompose a cirq.Operation or cirq.Gate, and return its unitary if it exists. Returns: If `val` can be decomposed into unitaries, calculate the resulting unitary and return it. If it doesn't exist, None is returned. """ from cirq.protocols.apply_unitary import apply_unitary, ApplyUnitaryArgs from cirq.protocols.decompose import (decompose_once, decompose_once_with_qubits) from cirq import Gate, LineQubit, Operation if isinstance(val, Operation): qubits = val.qubits decomposed_val = decompose_once(val, default=None) elif isinstance(val, Gate): # Since gates don't know about qubits, we need to create some qubits = tuple(LineQubit.range(val.num_qubits())) decomposed_val = decompose_once_with_qubits(val, qubits, default=None) if decomposed_val is not None: # Calculate the resulting unitary (if it exists) n = len(qubits) state = np.eye(1 << n, dtype=np.complex128) state.shape = (2, ) * (2 * n) buffer = np.zeros(state.shape, dtype=np.complex128) qubit_map = {q: i for i, q in enumerate(qubits)} result = state for op in decomposed_val: indices = [qubit_map[q] for q in op.qubits] result = apply_unitary(unitary_value=op, args=ApplyUnitaryArgs( state, buffer, indices), default=None) if result is None: return None if result is buffer: buffer = state state = result if result is not None: return result.reshape((1 << n, 1 << n))
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_has_unitary_from_apply_unitary(val: Any) -> Optional[bool]: """Attempts to infer a value's unitary-ness via its _apply_unitary_ method. """ from cirq.protocols.apply_unitary import ApplyUnitaryArgs from cirq import devices, linalg, ops method = getattr(val, '_apply_unitary_', None) if method is None: return None if isinstance(val, ops.Gate): val = val.on(*devices.LineQubit.range(val.num_qubits())) if not isinstance(val, ops.Operation): return None val_qid_shape = qid_shape_protocol.qid_shape(val) state = linalg.one_hot(shape=val_qid_shape, dtype=np.complex64) buffer = np.empty_like(state) result = method(ApplyUnitaryArgs(state, buffer, range(len(val_qid_shape)))) if result is NotImplemented: return None return result is not None
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))
def _strat_unitary_from_decompose(val: Any) -> Optional[np.ndarray]: """Attempts to compute a value's unitary via its _decompose_ method.""" from cirq.protocols.apply_unitary import ApplyUnitaryArgs, apply_unitaries # Check if there's a decomposition. from cirq.protocols.has_unitary import ( _try_decompose_into_operations_and_qubits) operations, qubits = _try_decompose_into_operations_and_qubits(val) if operations is None: return NotImplemented # Apply sub-operations' unitary effects to an identity matrix. n = len(qubits) state = np.eye(1 << n, dtype=np.complex128) state.shape = (2,) * (2 * n) buffer = np.empty_like(state) result = apply_unitaries(operations, qubits, ApplyUnitaryArgs(state, buffer, range(n)), None) # Package result. if result is None: return None return result.reshape((1 << n, 1 << n))