def _try_decompose_into_operations_and_qubits( val: Any ) -> Tuple[Optional[List['cirq.Operation']], Sequence['cirq.Qid'], Tuple[int, ...]]: """Returns the value's decomposition (if any) and the qubits it applies to. """ from cirq.protocols.decompose import (decompose_once, decompose_once_with_qubits) from cirq import LineQubit, Gate, Operation if isinstance(val, Gate): # Gates don't specify qubits, and so must be handled specially. qid_shape = qid_shape_protocol.qid_shape(val) qubits = LineQubit.range(len(qid_shape)) # type: Sequence[cirq.Qid] return decompose_once_with_qubits(val, qubits, None), qubits, qid_shape if isinstance(val, Operation): qid_shape = qid_shape_protocol.qid_shape(val) return decompose_once(val, None), val.qubits, qid_shape result = decompose_once(val, None) if result is not None: qubit_set = set() qid_shape_dict = defaultdict(lambda: 1) # type: Dict[cirq.Qid, int] for op in result: for level, q in zip(qid_shape_protocol.qid_shape(op), op.qubits): qubit_set.add(q) qid_shape_dict[q] = max(qid_shape_dict[q], level) qubits = sorted(qubit_set) return result, qubits, tuple(qid_shape_dict[q] for q in qubits) return None, (), ()
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 has_unitary(val: Any) -> bool: """Returns whether the value has a unitary matrix representation. Returns: If `val` has a _has_unitary_ method and its result is not NotImplemented, that result is returned. Otherwise, if `val` is a cirq.Operation, a decomposition will be attempted and the resulting unitary will be returned if unitaries exist for all operations of the decompostion. Otherwise, if the value has a _unitary_ method return if that has a non-default value. Returns False if neither function exists. """ from cirq.protocols.decompose import decompose_once from cirq import Operation # HACK: Avoids circular dependencies. getter = getattr(val, '_has_unitary_', None) result = NotImplemented if getter is None else getter() # Fallback to decomposition for operations if result is NotImplemented and isinstance(val, Operation): decomposed_val = decompose_once(val, None) if decomposed_val is not None: result = all(has_unitary(v) for v in decomposed_val) if result is not NotImplemented: return result # No _has_unitary_ function, use _unitary_ instead return unitary(val, None) is not None
def _try_decompose_into_operations_and_qubits( val: Any ) -> Tuple[Optional[List['cirq.Operation']], Sequence['cirq.Qid']]: """Returns the value's decomposition (if any) and the qubits it applies to. """ from cirq.protocols.decompose import (decompose_once, decompose_once_with_qubits) from cirq import LineQubit, Gate, Operation if isinstance(val, Gate): # Gates don't specify qubits, and so must be handled specially. qubits = LineQubit.range(val.num_qubits()) return decompose_once_with_qubits(val, qubits, None), qubits if isinstance(val, Operation): return decompose_once(val, None), val.qubits result = decompose_once(val, None) if result is not None: return result, sorted({q for op in result for q in op.qubits}) return 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 has_unitary(val: Any) -> bool: """Returns whether the value has a unitary matrix representation. Returns: If `val` has a _has_unitary_ method and its result is not NotImplemented, that result is returned. Otherwise, if `val` is a cirq.Gate or cirq.Operation, a decomposition is attempted and the resulting unitary is returned if has_unitary is True for all operations of the decompostion. Otherwise, if the value has a _unitary_ method return if that has a non-default value. Returns False if neither function exists. """ from cirq.protocols.decompose import (decompose_once, decompose_once_with_qubits) # HACK: Avoids circular dependencies. from cirq import Gate, Operation, LineQubit getter = getattr(val, '_has_unitary_', None) result = NotImplemented if getter is None else getter() if result is not NotImplemented: return result # Fallback to explicit _unitary_ unitary_getter = getattr(val, '_unitary_', None) if unitary_getter is not None and unitary_getter() is not NotImplemented: return True # Fallback to decomposition for gates and operations if isinstance(val, Gate): # Since gates don't know about qubits, we need to create some decomposed_val = decompose_once_with_qubits(val, LineQubit.range( val.num_qubits()), default=None) if decomposed_val is not None: return all(has_unitary(v) for v in decomposed_val) elif isinstance(val, Operation): decomposed_val = decompose_once(val, default=None) if decomposed_val is not None: return all(has_unitary(v) for v in decomposed_val) # Finally, fallback to full unitary method, including decomposition return unitary(val, None) is not None