def __init__(
     self,
     mixture: Iterable[Tuple[float, np.ndarray]],
     key: Union[str, value.MeasurementKey, None] = None,
     validate: bool = False,
 ):
     mixture = list(mixture)
     if not mixture:
         raise ValueError('MixedUnitaryChannel must have at least one unitary.')
     if not protocols.approx_eq(sum(p[0] for p in mixture), 1):
         raise ValueError('Unitary probabilities must sum to 1.')
     m0 = mixture[0][1]
     num_qubits = np.log2(m0.shape[0])
     if not num_qubits.is_integer() or m0.shape[1] != m0.shape[0]:
         raise ValueError(
             f'Input mixture of shape {m0.shape} does not '
             'represent a square operator over qubits.'
         )
     self._num_qubits = int(num_qubits)
     for i, op in enumerate(p[1] for p in mixture):
         if not op.shape == m0.shape:
             raise ValueError(
                 f'Inconsistent unitary shapes: op[0]: {m0.shape}, op[{i}]: {op.shape}'
             )
         if validate and not linalg.is_unitary(op):
             raise ValueError(f'Element {i} of mixture is non-unitary.')
     self._mixture = mixture
     if not isinstance(key, value.MeasurementKey) and key is not None:
         key = value.MeasurementKey(key)
     self._key = key
Exemple #2
0
    def __init__(self,
                 matrix: np.ndarray,
                 *,
                 qid_shape: Optional[Iterable[int]] = None) -> None:
        """Initializes a matrix gate.
        Args:
            matrix: The matrix that defines the gate.
            qid_shape: The shape of state tensor that the matrix applies to.
                If not specified, this value is inferred by assuming that the
                matrix is supposed to apply to qubits.
        """
        if len(matrix.shape) != 2 or matrix.shape[0] != matrix.shape[1]:
            raise ValueError('`matrix` must be a square 2d numpy array.')

        if qid_shape is None:
            n = int(np.round(np.log2(matrix.shape[0] or 1)))
            if 2**n != matrix.shape[0]:
                raise ValueError(
                    f'Matrix width ({matrix.shape[0]}) is not a power of 2 and '
                    f'qid_shape is not specified.')
            qid_shape = (2, ) * n

        self._matrix = matrix
        self._qid_shape = tuple(qid_shape)
        m = int(np.prod(self._qid_shape))
        if self._matrix.shape != (m, m):
            raise ValueError('Wrong matrix shape for qid_shape.\n'
                             f'Matrix shape: {self._matrix.shape}\n'
                             f'qid_shape: {self._qid_shape}\n')

        if not linalg.is_unitary(matrix):
            raise ValueError(f'Not a unitary matrix: {self._matrix}')
Exemple #3
0
    def __init__(self, matrix: np.ndarray) -> None:
        """
        Initializes the 2-qubit matrix gate.

        Args:
            matrix: The matrix that defines the gate.
        """
        if matrix.shape != (2, 2) or not linalg.is_unitary(matrix):
            raise ValueError('Not a 2x2 unitary matrix: {}'.format(matrix))
        self._matrix = matrix
 def _strat_apply_mixture(self, val: Any, qubits: Sequence['cirq.Qid']) -> bool:
     mixture = protocols.mixture(val, None)
     if mixture is None:
         return NotImplemented
     if not all(linalg.is_unitary(m) for _, m in mixture):
         return NotImplemented  # coverage: ignore
     probabilities, unitaries = zip(*mixture)
     index = self.prng.choice(len(unitaries), p=probabilities)
     return self._strat_act_from_single_qubit_decompose(
         matrix_gates.MatrixGate(unitaries[index]), qubits
     )
Exemple #5
0
    def __init__(self, matrix: Optional[np.ndarray]) -> None:
        """
        Initializes the 2-qubit matrix gate.

        Args:
            matrix: The matrix that defines the gate. Child classes can instead
                instead implement the matrix method and pass in None.
        """
        if matrix is not None and (matrix.shape !=
                                   (2, 2) or not linalg.is_unitary(matrix)):
            raise ValueError('Not a 2x2 unitary matrix: {}'.format(matrix))
        self._matrix = matrix
Exemple #6
0
    def __init__(self, matrix: Optional[np.ndarray]) -> None:
        """
        Initializes the 2-qubit matrix gate.

        Args:
            matrix: The matrix that defines the gate. Child classes can instead
                instead implement the matrix method and pass in None.
        """
        if matrix is not None and (matrix.shape != (2, 2) or
                                   not linalg.is_unitary(matrix)):
            raise ValueError('Not a 2x2 unitary matrix: {}'.format(matrix))
        self._matrix = matrix
Exemple #7
0
    def __init__(self, matrix: np.ndarray) -> None:
        """
        Initializes the 2-qubit matrix gate.

        Args:
            matrix: The matrix that defines the gate.
        """
        if (len(matrix.shape) != 2 or matrix.shape[0] != matrix.shape[1]
                or not linalg.is_unitary(matrix)):
            raise ValueError(
                'Not a 2x2 (or d x d) unitary matrix: {}'.format(matrix))
        self._matrix = matrix
Exemple #8
0
    def __init__(self, matrix: np.ndarray) -> None:
        """
        Initializes the 2-qubit matrix gate.

        Args:
            matrix: The matrix that defines the gate.
        """
        if matrix.shape not in [(cirq.QUDIT_LEVELS, cirq.QUDIT_LEVELS)
                                ] or not linalg.is_unitary(matrix):
            raise ValueError(
                'Unitary matrix has wrong dimensions: {}'.format(matrix))
        self._matrix = matrix
    def __init__(
        self,
        matrix: np.ndarray,
        *,
        name: str = None,
        qid_shape: Optional[Iterable[int]] = None,
        unitary_check_rtol: float = 1e-5,
        unitary_check_atol: float = 1e-8,
    ) -> None:
        """Initializes a matrix gate.

        Args:
            matrix: The matrix that defines the gate.
            name: The optional name of the gate to be displayed.
            qid_shape: The shape of state tensor that the matrix applies to.
                If not specified, this value is inferred by assuming that the
                matrix is supposed to apply to qubits.
            unitary_check_rtol: The relative tolerance for checking whether the supplied matrix
                is unitary. See `cirq.is_unitary`.
            unitary_check_atol: The absolute tolerance for checking whether the supplied matrix
                is unitary. See `cirq.is_unitary`.

        Raises:
            ValueError: If the matrix is not a square numpy array, if the matrix does not match
                the `qid_shape`, if `qid_shape` is not supplied and the matrix dimension is
                not a power of 2, or if the matrix not unitary (to the supplied precisions).
        """
        if len(matrix.shape) != 2 or matrix.shape[0] != matrix.shape[1]:
            raise ValueError('`matrix` must be a square 2d numpy array.')

        if qid_shape is None:
            n = int(np.round(np.log2(matrix.shape[0] or 1)))
            if 2**n != matrix.shape[0]:
                raise ValueError(
                    f'Matrix width ({matrix.shape[0]}) is not a power of 2 and '
                    f'qid_shape is not specified.')
            qid_shape = (2, ) * n

        self._matrix = matrix
        self._qid_shape = tuple(qid_shape)
        self._name = name
        m = int(np.prod(self._qid_shape, dtype=np.int64))
        if self._matrix.shape != (m, m):
            raise ValueError('Wrong matrix shape for qid_shape.\n'
                             f'Matrix shape: {self._matrix.shape}\n'
                             f'qid_shape: {self._qid_shape}\n')

        if not linalg.is_unitary(
                matrix, rtol=unitary_check_rtol, atol=unitary_check_atol):
            raise ValueError(f'Not a unitary matrix: {self._matrix}')
Exemple #10
0
    def from_unitary(u: np.ndarray) -> Optional['SingleQubitCliffordGate']:
        """Creates Clifford gate with given unitary (up to global phase).

        Args:
            u: 2x2 unitary matrix of a Clifford gate.

        Returns:
            SingleQubitCliffordGate, whose matrix is equal to given matrix (up
            to global phase), or `None` if `u` is not a matrix of a single-qubit
            Clifford gate.
        """
        if u.shape != (2, 2) or not linalg.is_unitary(u):
            return None
        x = protocols.unitary(pauli_gates.X)
        z = protocols.unitary(pauli_gates.Z)
        x_to = _to_pauli_transform(u @ x @ u.conj().T)
        z_to = _to_pauli_transform(u @ z @ u.conj().T)
        if x_to is None or z_to is None:
            return None
        return SingleQubitCliffordGate.from_double_map({pauli_gates.X: x_to, pauli_gates.Z: z_to})
Exemple #11
0
def decompose_multi_controlled_rotation(
        matrix: np.ndarray, controls: List['cirq.Qid'],
        target: 'cirq.Qid') -> List['cirq.Operation']:
    """Implements action of multi-controlled unitary gate.

    Returns a sequence of operations, which is equivalent to applying
    single-qubit gate with matrix `matrix` on `target`, controlled by
    `controls`.

    Result is guaranteed to consist exclusively of 1-qubit, CNOT and CCNOT
    gates.

    If matrix is special unitary, result has length `O(len(controls))`.
    Otherwise result has length `O(len(controls)**2)`.

    References:
        [1] Barenco, Bennett et al.
            Elementary gates for quantum computation. 1995.
            https://arxiv.org/pdf/quant-ph/9503016.pdf

    Args:
        matrix - 2x2 numpy unitary matrix (of real or complex dtype).
        controls - control qubits.
        targets - target qubits.

    Returns:
        A list of operations which, applied in a sequence, are equivalent to
        applying `MatrixGate(matrix).on(target).controlled_by(*controls)`.
    """
    assert is_unitary(matrix)
    assert matrix.shape == (2, 2)

    if len(controls) == 0:
        return [ops.MatrixGate(matrix).on(target)]
    elif len(controls) == 1:
        return _decompose_single_ctrl(matrix, controls[0], target)
    elif is_special_unitary(matrix):
        return _decompose_su(matrix, controls, target)
    else:
        return _decompose_recursive(matrix, 1.0, controls, target, [])
Exemple #12
0
 def _has_unitary_(self) -> bool:
     return linalg.is_unitary(self.matrix())
Exemple #13
0
 def _unitary_(self) -> np.ndarray:
     m = self.matrix()
     if linalg.is_unitary(m):
         return m
     raise ValueError(f'{self} is not unitary')
Exemple #14
0
 def _has_unitary_(self) -> bool:
     m = self.matrix()
     return m is not NotImplemented and linalg.is_unitary(m)
Exemple #15
0
def test_random_unitary():
    u1 = random_unitary(2)
    u2 = random_unitary(2)
    assert is_unitary(u1)
    assert is_unitary(u2)
    assert not np.allclose(u1, u2)
Exemple #16
0
def test_random_unitary():
    u1 = random_unitary(2)
    u2 = random_unitary(2)
    assert is_unitary(u1)
    assert is_unitary(u2)
    assert not np.allclose(u1, u2)