Example #1
0
    def test_compose(self):
        """Test compose method."""

        op1 = Operator(self.UX)
        op2 = Operator(self.UY)

        targ = Operator(np.dot(self.UY, self.UX))
        self.assertEqual(op1.compose(op2), targ)
        self.assertEqual(op1 @ op2, targ)

        targ = Operator(np.dot(self.UX, self.UY))
        self.assertEqual(op2.compose(op1), targ)
        self.assertEqual(op2 @ op1, targ)
Example #2
0
    def test_compose_subsystem(self):
        """Test subsystem compose method."""
        # 3-qubit operator
        mat = self.rand_matrix(8, 8)
        mat_a = self.rand_matrix(2, 2)
        mat_b = self.rand_matrix(2, 2)
        mat_c = self.rand_matrix(2, 2)
        op = Operator(mat)
        op1 = Operator(mat_a)
        op2 = Operator(np.kron(mat_b, mat_a))
        op3 = Operator(np.kron(mat_c, np.kron(mat_b, mat_a)))

        # op3 qargs=[0, 1, 2]
        targ = np.dot(np.kron(mat_c, np.kron(mat_b, mat_a)), mat)
        self.assertEqual(op.compose(op3, qargs=[0, 1, 2]), Operator(targ))
        self.assertEqual(op.compose(op3([0, 1, 2])), Operator(targ))
        self.assertEqual(op & op3([0, 1, 2]), Operator(targ))
        # op3 qargs=[2, 1, 0]
        targ = np.dot(np.kron(mat_a, np.kron(mat_b, mat_c)), mat)
        self.assertEqual(op.compose(op3, qargs=[2, 1, 0]), Operator(targ))
        self.assertEqual(op & op3([2, 1, 0]), Operator(targ))

        # op2 qargs=[0, 1]
        targ = np.dot(np.kron(np.eye(2), np.kron(mat_b, mat_a)), mat)
        self.assertEqual(op.compose(op2, qargs=[0, 1]), Operator(targ))
        self.assertEqual(op & op2([0, 1]), Operator(targ))
        # op2 qargs=[2, 0]
        targ = np.dot(np.kron(mat_a, np.kron(np.eye(2), mat_b)), mat)
        self.assertEqual(op.compose(op2, qargs=[2, 0]), Operator(targ))
        self.assertEqual(op & op2([2, 0]), Operator(targ))

        # op1 qargs=[0]
        targ = np.dot(np.kron(np.eye(4), mat_a), mat)
        self.assertEqual(op.compose(op1, qargs=[0]), Operator(targ))
        self.assertEqual(op & op1([0]), Operator(targ))
        # op1 qargs=[1]
        targ = np.dot(np.kron(np.eye(2), np.kron(mat_a, np.eye(2))), mat)
        self.assertEqual(op.compose(op1, qargs=[1]), Operator(targ))
        self.assertEqual(op & op1([1]), Operator(targ))
        # op1 qargs=[2]
        targ = np.dot(np.kron(mat_a, np.eye(4)), mat)
        self.assertEqual(op.compose(op1, qargs=[2]), Operator(targ))
        self.assertEqual(op & op1([2]), Operator(targ))
Example #3
0
    def test_compose_front_subsystem(self):
        """Test subsystem front compose method."""
        # 3-qubit operator
        mat = self.rand_matrix(8, 8)
        mat_a = self.rand_matrix(2, 2)
        mat_b = self.rand_matrix(2, 2)
        mat_c = self.rand_matrix(2, 2)
        op = Operator(mat)
        op1 = Operator(mat_a)
        op2 = Operator(np.kron(mat_b, mat_a))
        op3 = Operator(np.kron(mat_c, np.kron(mat_b, mat_a)))

        # op3 qubits=[0, 1, 2]
        targ = np.dot(mat, np.kron(mat_c, np.kron(mat_b, mat_a)))
        self.assertEqual(op.compose(op3, qubits=[0, 1, 2], front=True), Operator(targ))
        # op3 qubits=[2, 1, 0]
        targ = np.dot(mat, np.kron(mat_a, np.kron(mat_b, mat_c)))
        self.assertEqual(op.compose(op3, qubits=[2, 1, 0], front=True), Operator(targ))

        # op2 qubits=[0, 1]
        targ = np.dot(mat, np.kron(np.eye(2), np.kron(mat_b, mat_a)))
        self.assertEqual(op.compose(op2, qubits=[0, 1], front=True), Operator(targ))
        # op2 qubits=[2, 0]
        targ = np.dot(mat, np.kron(mat_a, np.kron(np.eye(2), mat_b)))
        self.assertEqual(op.compose(op2, qubits=[2, 0], front=True), Operator(targ))

        # op1 qubits=[0]
        targ = np.dot(mat, np.kron(np.eye(4), mat_a))
        self.assertEqual(op.compose(op1, qubits=[0], front=True), Operator(targ))

        # op1 qubits=[1]
        targ = np.dot(mat, np.kron(np.eye(2), np.kron(mat_a, np.eye(2))))
        self.assertEqual(op.compose(op1, qubits=[1], front=True), Operator(targ))

        # op1 qubits=[2]
        targ = np.dot(mat, np.kron(mat_a, np.eye(4)))
        self.assertEqual(op.compose(op1, qubits=[2], front=True), Operator(targ))
Example #4
0
def process_fidelity(channel,
                     target=None,
                     require_cp=True,
                     require_tp=False,
                     require_cptp=False):
    r"""Return the process fidelity of a noisy quantum channel.

    This process fidelity :math:`F_{\text{pro}}` is given by

    .. math::
        F_{\text{pro}}(\mathcal{E}, U)
            = \frac{Tr[S_U^\dagger S_{\mathcal{E}}]}{d^2}

    where :math:`S_{\mathcal{E}}, S_{U}` are the
    :class:`~qiskit.quantum_info.SuperOp` matrices for the input quantum
    *channel* :math:`\cal{E}` and *target* unitary :math:`U` respectively,
    and :math:`d` is the dimension of the *channel*.

    Args:
        channel (QuantumChannel or Operator): noisy quantum channel.
        target (Operator or None): target unitary operator.
            If `None` target is the identity operator [Default: None].
        require_cp (bool): require channel to be completely-positive
            [Default: True].
        require_tp (bool): require channel to be trace-preserving
            [Default: False].
        require_cptp (bool): (DEPRECATED) require input channels to be
            CPTP [Default: False].

    Returns:
        float: The process fidelity :math:`F_{\text{pro}}`.

    Raises:
        QiskitError: if the channel and target do not have the same dimensions,
                     or have different input and output dimensions.
        QiskitError: if the channel and target or are not completely-positive
                     (with ``require_cp=True``) or not trace-preserving
                     (with ``require_tp=True``).
    """
    # Format inputs
    if isinstance(channel, (list, np.ndarray, Operator, Pauli, Clifford)):
        channel = Operator(channel)
    else:
        channel = SuperOp(channel)

    if target is not None:
        try:
            target = Operator(target)
        except QiskitError:
            raise QiskitError(
                'Target channel is not a unitary channel.')
        if channel.dim != target.dim:
            raise QiskitError(
                'Input quantum channel and target unitary must have the same '
                'dimensions ({} != {}).'.format(channel.dim, target.dim))

    # Validate complete-positivity and trace-preserving
    if require_cptp:
        # require_cptp kwarg is DEPRECATED
        # Remove in future qiskit version
        warnings.warn(
            "Please use `require_cp=True, require_tp=True` "
            "instead of `require_cptp=True`.", DeprecationWarning)
        require_cp = True
        require_tp = True
    if require_cp or require_tp:
        # Validate target channel
        if target is not None:
            is_unitary = target.is_unitary()
            if require_cp and not is_unitary:
                raise QiskitError('Target unitary channel is not completely-positive')
            if require_tp and not is_unitary:
                raise QiskitError('Target unitary channel is not trace-preserving')
        # Validate input channel
        if isinstance(channel, Operator):
            is_unitary = channel.is_unitary()
            # Validate as unitary
            if require_cp and not is_unitary:
                raise QiskitError('Input quantum channel is not completely-positive')
            if require_tp and not is_unitary:
                raise QiskitError('Input quantum channel is not trace-preserving')
        else:
            # Validate as QuantumChannel
            if require_cp and not channel.is_cp():
                raise QiskitError('Input quantum channel is not completely-positive')
            if require_tp and not channel.is_tp():
                raise QiskitError('Input quantum channel is not trace-preserving')

    # Compute process fidelity with identity channel
    if target is not None:
        channel = channel.compose(target.adjoint())
    input_dim, _ = channel.dim
    if isinstance(channel, Operator):
        # |Tr[U]/dim| ** 2
        fid = np.abs(np.trace(channel.data) / input_dim)**2
    else:
        # Tr[S] / (dim ** 2)
        fid = np.trace(SuperOp(channel).data) / (input_dim**2)
    return float(np.real(fid))