コード例 #1
0
    def test_evolve(self):
        """Test evolve method."""
        input_psi = [0, 1]
        input_rho = [[0, 0], [0, 1]]
        # Identity channel
        chan = SuperOp(self.sopI)
        target_rho = np.array([[0, 0], [0, 1]])
        self.assertAllClose(chan._evolve(input_psi), target_rho)
        self.assertAllClose(chan._evolve(np.array(input_psi)), target_rho)
        self.assertAllClose(chan._evolve(input_rho), target_rho)
        self.assertAllClose(chan._evolve(np.array(input_rho)), target_rho)

        # Hadamard channel
        mat = np.array([[1, 1], [1, -1]]) / np.sqrt(2)
        chan = SuperOp(np.kron(mat.conj(), mat))
        target_rho = np.array([[1, -1], [-1, 1]]) / 2
        self.assertAllClose(chan._evolve(input_psi), target_rho)
        self.assertAllClose(chan._evolve(np.array(input_psi)), target_rho)
        self.assertAllClose(chan._evolve(input_rho), target_rho)
        self.assertAllClose(chan._evolve(np.array(input_rho)), target_rho)

        # Completely depolarizing channel
        chan = SuperOp(self.depol_sop(1))
        target_rho = np.eye(2) / 2
        self.assertAllClose(chan._evolve(input_psi), target_rho)
        self.assertAllClose(chan._evolve(np.array(input_psi)), target_rho)
        self.assertAllClose(chan._evolve(input_rho), target_rho)
        self.assertAllClose(chan._evolve(np.array(input_rho)), target_rho)
コード例 #2
0
 def test_multiply_except(self):
     """Test multiply method raises exceptions."""
     chan = SuperOp(self.sopI)
     self.assertRaises(QiskitError, chan.multiply, 's')
     self.assertRaises(QiskitError, chan.multiply, chan)
コード例 #3
0
 def test_negate(self):
     """Test negate method"""
     chan = SuperOp(self.sopI)
     targ = SuperOp(-self.sopI)
     self.assertEqual(-chan, targ)
コード例 #4
0
    def test_sub_qargs(self):
        """Test subtract method with qargs."""
        mat = self.rand_matrix(8**2, 8**2)
        mat0 = self.rand_matrix(4, 4)
        mat1 = self.rand_matrix(4, 4)

        op = SuperOp(mat)
        op0 = SuperOp(mat0)
        op1 = SuperOp(mat1)
        op01 = op1.tensor(op0)
        eye = SuperOp(self.sopI)

        with self.subTest(msg='qargs=[0]'):
            value = op - op0([0])
            target = op - eye.tensor(eye).tensor(op0)
            self.assertEqual(value, target)

        with self.subTest(msg='qargs=[1]'):
            value = op - op0([1])
            target = op - eye.tensor(op0).tensor(eye)
            self.assertEqual(value, target)

        with self.subTest(msg='qargs=[2]'):
            value = op - op0([2])
            target = op - op0.tensor(eye).tensor(eye)
            self.assertEqual(value, target)

        with self.subTest(msg='qargs=[0, 1]'):
            value = op - op01([0, 1])
            target = op - eye.tensor(op1).tensor(op0)
            self.assertEqual(value, target)

        with self.subTest(msg='qargs=[1, 0]'):
            value = op - op01([1, 0])
            target = op - eye.tensor(op0).tensor(op1)
            self.assertEqual(value, target)

        with self.subTest(msg='qargs=[0, 2]'):
            value = op - op01([0, 2])
            target = op - op1.tensor(eye).tensor(op0)
            self.assertEqual(value, target)

        with self.subTest(msg='qargs=[2, 0]'):
            value = op - op01([2, 0])
            target = op - op0.tensor(eye).tensor(op1)
            self.assertEqual(value, target)
コード例 #5
0
 def test_subtract_except(self):
     """Test subtract method raises exceptions."""
     chan1 = SuperOp(self.sopI)
     chan2 = SuperOp(np.eye(16))
     self.assertRaises(QiskitError, chan1.subtract, chan2)
     self.assertRaises(QiskitError, chan1.subtract, 5)
コード例 #6
0
ファイル: test_superop.py プロジェクト: v-r0/qiskit-terra
 def test_conjugate(self):
     """Test conjugate method."""
     mat = self.rand_matrix(4, 4)
     chan = SuperOp(mat)
     targ = SuperOp(np.conjugate(mat))
     self.assertEqual(chan.conjugate(), targ)
コード例 #7
0
ファイル: test_superop.py プロジェクト: v-r0/qiskit-terra
 def test_adjoint(self):
     """Test adjoint method."""
     mat = self.rand_matrix(4, 4)
     chan = SuperOp(mat)
     targ = SuperOp(np.transpose(np.conj(mat)))
     self.assertEqual(chan.adjoint(), targ)
コード例 #8
0
def process_fidelity(channel, target=None, require_cp=True, require_tp=True):
    r"""Return the process fidelity of a noisy quantum channel.


    The process fidelity :math:`F_{\text{pro}}(\mathcal{E}, \mathcal{F})`
    between two quantum channels :math:`\mathcal{E}, \mathcal{F}` is given by

    .. math::
        F_{\text{pro}}(\mathcal{E}, \mathcal{F})
            = F(\rho_{\mathcal{E}}, \rho_{\mathcal{F}})

    where :math:`F` is the :func:`~qiskit.quantum_info.state_fidelity`,
    :math:`\rho_{\mathcal{E}} = \Lambda_{\mathcal{E}} / d` is the
    normalized :class:`~qiskit.quantum_info.Choi` matrix for the channel
    :math:`\mathcal{E}`, and :math:`d` is the input dimension of
    :math:`\mathcal{E}`.

    When the target channel is unitary this is equivalent to

    .. 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:`\mathcal{E}` and *target* unitary :math:`U` respectively,
    and :math:`d` is the input dimension of the channel.

    Args:
        channel (Operator or QuantumChannel): input quantum channel.
        target (Operator or QuantumChannel or None): target quantum channel.
            If `None` target is the identity operator [Default: None].
        require_cp (bool): check if input and target channels are
                           completely-positive and if non-CP log warning
                           containing negative eigenvalues of Choi-matrix
                           [Default: True].
        require_tp (bool): check if input and target channels are
                           trace-preserving and if non-TP log warning
                           containing negative eigenvalues of partial
                           Choi-matrix :math:`Tr_{\mbox{out}}[\mathcal{E}] - I`
                           [Default: True].

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

    Raises:
        QiskitError: if the channel and target do not have the same dimensions.
    """
    # Format inputs
    channel = _input_formatter(channel, SuperOp, "process_fidelity", "channel")
    target = _input_formatter(target, Operator, "process_fidelity", "target")

    if target:
        # Validate dimensions
        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
    for label, chan in [("Input", channel), ("Target", target)]:
        if chan is not None and require_cp:
            cp_cond = _cp_condition(chan)
            neg = cp_cond < -1 * chan.atol
            if np.any(neg):
                logger.warning(
                    "%s channel is not CP. Choi-matrix has negative eigenvalues: %s",
                    label,
                    cp_cond[neg],
                )
        if chan is not None and require_tp:
            tp_cond = _tp_condition(chan)
            non_zero = np.logical_not(np.isclose(tp_cond, 0, atol=chan.atol, rtol=chan.rtol))
            if np.any(non_zero):
                logger.warning(
                    "%s channel is not TP. Tr_2[Choi] - I has non-zero eigenvalues: %s",
                    label,
                    tp_cond[non_zero],
                )

    if isinstance(target, Operator):
        # Compute fidelity with unitary target by applying the inverse
        # to channel and computing fidelity with the identity
        channel = channel.compose(target.adjoint())
        target = None

    input_dim, _ = channel.dim
    if target is None:
        # Compute process fidelity with identity channel
        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))

    # For comparing two non-unitary channels we compute the state fidelity of
    # the normalized Choi-matrices. This is equivalent to the previous definition
    # when the target is a unitary channel.
    state1 = DensityMatrix(Choi(channel).data / input_dim)
    state2 = DensityMatrix(Choi(target).data / input_dim)
    return state_fidelity(state1, state2, validate=False)
コード例 #9
0
    def test_compose_front_inplace(self):
        """Test inplace front compose method."""
        # UnitaryChannel evolution
        chan1 = SuperOp(self.sopX)
        chan2 = SuperOp(self.sopY)
        targ = SuperOp(self.sopZ)
        chan1.compose(chan2, inplace=True, front=True)
        self.assertEqual(chan1, targ)

        # 50% depolarizing channel
        chan1 = SuperOp(self.depol_sop(0.5))
        chan1.compose(chan1, inplace=True, front=True)
        targ = SuperOp(self.depol_sop(0.75))
        self.assertEqual(chan1, targ)

        # Random superoperator
        mat1 = self.rand_matrix(4, 4)
        mat2 = self.rand_matrix(4, 4)

        targ = SuperOp(np.dot(mat2, mat1))
        chan1 = SuperOp(mat1)
        chan2 = SuperOp(mat2)
        chan2.compose(chan1, inplace=True, front=True)
        self.assertEqual(chan2, targ)
        targ = SuperOp(np.dot(mat1, mat2))
        chan1 = SuperOp(mat1)
        chan2 = SuperOp(mat2)
        chan1.compose(chan2, inplace=True, front=True)
        self.assertEqual(chan1, targ)

        # Compose different dimensions
        chan1 = SuperOp(self.rand_matrix(16, 4), input_dim=2, output_dim=4)
        chan2 = SuperOp(self.rand_matrix(4, 16), output_dim=2)
        chan1.compose(chan2, inplace=True, front=True)
        self.assertEqual(chan1.dims, (4, 4))
        chan1 = SuperOp(self.rand_matrix(16, 4), input_dim=2, output_dim=4)
        chan2 = SuperOp(self.rand_matrix(4, 16), output_dim=2)
        chan2.compose(chan1, inplace=True, front=True)
        self.assertEqual(chan2.dims, (2, 2))
コード例 #10
0
 def test_power_except(self):
     """Test power method raises exceptions."""
     chan = SuperOp(self.depol_sop(1))
     # Non-integer power raises error
     self.assertRaises(QiskitError, chan.power, 0.5)
コード例 #11
0
ファイル: measures.py プロジェクト: wbclark/qiskit-terra
def process_fidelity(channel, target=None, require_cp=True, require_tp=False):
    r"""Return the process fidelity of a noisy quantum channel.


    The process fidelity :math:`F_{\text{pro}}(\mathcal{E}, \methcal{F})`
    between two quantum channels :math:`\mathcal{E}, \mathcal{F}` is given by

    .. math:
        F_{\text{pro}}(\mathcal{E}, \mathcal{F})
            = F(\rho_{\mathcal{E}}, \rho_{\mathcal{F}})

    where :math:`F` is the :func:`~qiskit.quantum_info.state_fidelity`,
    :math:`\rho_{\mathcal{E}} = \Lambda_{\mathcal{E}} / d` is the
    normalized :class:`~qiskit.quantum_info.Choi` matrix for the channel
    :math:`\mathcal{E}`, and :math:`d` is the input dimension of
    :math:`\mathcal{E}`.

    When the target channel is unitary this is equivalent to

    .. 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:`\mathcal{E}` and *target* unitary :math:`U` respectively,
    and :math:`d` is the input dimension of the channel.

    Args:
        channel (Operator or QuantumChannel): input quantum channel.
        target (Operator or QuantumChannel or None): target quantum channel.
            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].

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

    Raises:
        QiskitError: if the channel and target do not have the same dimensions.
        QiskitError: if the channel and target are not completely-positive
                     (with ``require_cp=True``) or not trace-preserving
                     (with ``require_tp=True``).
    """
    # Format inputs
    channel = _input_formatter(channel, SuperOp, 'process_fidelity', 'channel')
    target = _input_formatter(target, Operator, 'process_fidelity', 'target')

    if target:
        # Validate dimensions
        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
    for label, chan in [('Input', channel), ('Target', target)]:
        if isinstance(chan, Operator) and (require_cp or require_tp):
            is_unitary = chan.is_unitary()
            # Validate as unitary
            if require_cp and not is_unitary:
                raise QiskitError(
                    '{} channel is not completely-positive'.format(label))
            if require_tp and not is_unitary:
                raise QiskitError(
                    '{} channel is not trace-preserving'.format(label))
        elif chan is not None:
            # Validate as QuantumChannel
            if require_cp and not chan.is_cp():
                raise QiskitError(
                    '{} channel is not completely-positive'.format(label))
            if require_tp and not chan.is_tp():
                raise QiskitError(
                    '{} channel is not trace-preserving'.format(label))

    if isinstance(target, Operator):
        # Compute fidelity with unitary target by applying the inverse
        # to channel and computing fidelity with the identity
        channel = channel @ target.adjoint()
        target = None

    input_dim, _ = channel.dim
    if target is None:
        # Compute process fidelity with identity channel
        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))

    # For comparing two non-unitary channels we compute the state fidelity of
    # the normalized Choi-matrices. This is equivalent to the previous definition
    # when the target is a unitary channel.
    state1 = DensityMatrix(Choi(channel).data / input_dim)
    state2 = DensityMatrix(Choi(target).data / input_dim)
    return state_fidelity(state1, state2, validate=False)
コード例 #12
0
    def test_compose_front_subsystem(self):
        """Test subsystem front compose method."""
        # 3-qubit operator
        mat = self.rand_matrix(64, 64)
        mat_a = self.rand_matrix(4, 4)
        mat_b = self.rand_matrix(4, 4)
        mat_c = self.rand_matrix(4, 4)
        iden = SuperOp(np.eye(4))
        op = SuperOp(mat)
        op1 = SuperOp(mat_a)
        op2 = SuperOp(mat_b).tensor(SuperOp(mat_a))
        op3 = SuperOp(mat_c).tensor(SuperOp(mat_b)).tensor(SuperOp(mat_a))

        # op3 qargs=[0, 1, 2]
        full_op = SuperOp(mat_c).tensor(SuperOp(mat_b)).tensor(SuperOp(mat_a))
        targ = np.dot(mat, full_op.data)
        self.assertEqual(
            op.compose(op3, qargs=[0, 1, 2], front=True), SuperOp(targ))
        # op3 qargs=[2, 1, 0]
        full_op = SuperOp(mat_a).tensor(SuperOp(mat_b)).tensor(SuperOp(mat_c))
        targ = np.dot(mat, full_op.data)
        self.assertEqual(
            op.compose(op3, qargs=[2, 1, 0], front=True), SuperOp(targ))

        # op2 qargs=[0, 1]
        full_op = iden.tensor(SuperOp(mat_b)).tensor(SuperOp(mat_a))
        targ = np.dot(mat, full_op.data)
        self.assertEqual(
            op.compose(op2, qargs=[0, 1], front=True), SuperOp(targ))
        # op2 qargs=[2, 0]
        full_op = SuperOp(mat_a).tensor(iden).tensor(SuperOp(mat_b))
        targ = np.dot(mat, full_op.data)
        self.assertEqual(
            op.compose(op2, qargs=[2, 0], front=True), SuperOp(targ))

        # op1 qargs=[0]
        full_op = iden.tensor(iden).tensor(SuperOp(mat_a))
        targ = np.dot(mat, full_op.data)
        self.assertEqual(
            op.compose(op1, qargs=[0], front=True), SuperOp(targ))

        # op1 qargs=[1]
        full_op = iden.tensor(SuperOp(mat_a)).tensor(iden)
        targ = np.dot(mat, full_op.data)
        self.assertEqual(
            op.compose(op1, qargs=[1], front=True), SuperOp(targ))

        # op1 qargs=[2]
        full_op = SuperOp(mat_a).tensor(iden).tensor(iden)
        targ = np.dot(mat, full_op.data)
        self.assertEqual(
            op.compose(op1, qargs=[2], front=True), SuperOp(targ))
コード例 #13
0
    def test_compose_front(self):
        """Test front compose method."""
        # UnitaryChannel evolution
        chan1 = SuperOp(self.sopX)
        chan2 = SuperOp(self.sopY)
        chan = chan1.compose(chan2, front=True)
        targ = SuperOp(self.sopZ)
        self.assertEqual(chan, targ)

        # 50% depolarizing channel
        chan1 = SuperOp(self.depol_sop(0.5))
        chan = chan1.compose(chan1, front=True)
        targ = SuperOp(self.depol_sop(0.75))
        self.assertEqual(chan, targ)

        # Random superoperator
        mat1 = self.rand_matrix(4, 4)
        mat2 = self.rand_matrix(4, 4)
        chan1 = SuperOp(mat1)
        chan2 = SuperOp(mat2)
        targ = SuperOp(np.dot(mat2, mat1))
        self.assertEqual(chan2.compose(chan1, front=True), targ)
        targ = SuperOp(np.dot(mat1, mat2))
        self.assertEqual(chan1.compose(chan2, front=True), targ)

        # Compose different dimensions
        chan1 = SuperOp(self.rand_matrix(16, 4))
        chan2 = SuperOp(self.rand_matrix(4, 16))
        chan = chan1.compose(chan2, front=True)
        self.assertEqual(chan.dim, (4, 4))
        chan = chan2.compose(chan1, front=True)
        self.assertEqual(chan.dim, (2, 2))
コード例 #14
0
 def test_circuit_init(self):
     """Test initialization from a circuit."""
     circuit, target = self.simple_circuit_no_measure()
     op = SuperOp(circuit)
     target = SuperOp(target)
     self.assertEqual(op, target)
コード例 #15
0
ファイル: test_superop.py プロジェクト: v-r0/qiskit-terra
    def test_evolve_subsystem(self):
        """Test subsystem evolve method."""

        # Single-qubit random superoperators
        op_a = SuperOp(self.rand_matrix(4, 4))
        op_b = SuperOp(self.rand_matrix(4, 4))
        op_c = SuperOp(self.rand_matrix(4, 4))
        id1 = SuperOp(np.eye(4))
        id2 = SuperOp(np.eye(16))
        rho = DensityMatrix(self.rand_rho(8))

        # Test evolving single-qubit of 3-qubit system
        op = op_a

        # Evolve on qubit 0
        full_op = id2.tensor(op_a)
        rho_targ = rho.evolve(full_op)
        rho_test = rho.evolve(op, qargs=[0])
        self.assertEqual(rho_test, rho_targ)

        # Evolve on qubit 1
        full_op = id1.tensor(op_a).tensor(id1)
        rho_targ = rho.evolve(full_op)
        rho_test = rho.evolve(op, qargs=[1])
        self.assertEqual(rho_test, rho_targ)

        # Evolve on qubit 2
        full_op = op_a.tensor(id2)
        rho_targ = rho.evolve(full_op)
        rho_test = rho.evolve(op, qargs=[2])
        self.assertEqual(rho_test, rho_targ)

        # Test 2-qubit evolution
        op = op_b.tensor(op_a)

        # Evolve on qubits [0, 2]
        full_op = op_b.tensor(id1).tensor(op_a)
        rho_targ = rho.evolve(full_op)
        rho_test = rho.evolve(op, qargs=[0, 2])
        self.assertEqual(rho_test, rho_targ)
        # Evolve on qubits [2, 0]
        full_op = op_a.tensor(id1).tensor(op_b)
        rho_targ = rho.evolve(full_op)
        rho_test = rho.evolve(op, qargs=[2, 0])
        self.assertEqual(rho_test, rho_targ)

        # Test 3-qubit evolution
        op = op_c.tensor(op_b).tensor(op_a)

        # Evolve on qubits [0, 1, 2]
        full_op = op
        rho_targ = rho.evolve(full_op)
        rho_test = rho.evolve(op, qargs=[0, 1, 2])
        self.assertEqual(rho_test, rho_targ)

        # Evolve on qubits [2, 1, 0]
        full_op = op_a.tensor(op_b).tensor(op_c)
        rho_targ = rho.evolve(full_op)
        rho_test = rho.evolve(op, qargs=[2, 1, 0])
        self.assertEqual(rho_test, rho_targ)
コード例 #16
0
    def test_tensorinplace(self):
        """Test inplace tensor method."""
        rho0, rho1 = np.diag([1, 0]), np.diag([0, 1])
        rho_init = np.kron(rho0, rho0)

        # X \otimes I
        chan1 = SuperOp(self.sopI)
        chan2 = SuperOp(self.sopX)
        chan2.tensor(chan1, inplace=True)
        rho_targ = np.kron(rho1, rho0)
        self.assertEqual(chan2.dims, (4, 4))
        self.assertAllClose(chan2._evolve(rho_init), rho_targ)
        chan1 = SuperOp(self.sopI)
        chan2 = SuperOp(self.sopX)
        chan2 ^= chan1
        self.assertEqual(chan2.dims, (4, 4))
        self.assertAllClose(chan2._evolve(rho_init), rho_targ)

        # I \otimes X
        chan1 = SuperOp(self.sopI)
        chan2 = SuperOp(self.sopX)
        chan1.tensor(chan2, inplace=True)
        rho_targ = np.kron(rho0, rho1)
        self.assertEqual(chan1.dims, (4, 4))
        self.assertAllClose(chan1._evolve(rho_init), rho_targ)
        chan1 = SuperOp(self.sopI)
        chan2 = SuperOp(self.sopX)
        chan1 ^= chan2
        self.assertEqual(chan1.dims, (4, 4))
        self.assertAllClose(chan1._evolve(rho_init), rho_targ)
コード例 #17
0
ファイル: test_superop.py プロジェクト: v-r0/qiskit-terra
 def test_is_cptp(self):
     """Test is_cptp method."""
     self.assertTrue(SuperOp(self.depol_sop(0.25)).is_cptp())
     # Non-CPTP should return false
     self.assertFalse(
         SuperOp(1.25 * self.sopI - 0.25 * self.depol_sop(1)).is_cptp())
コード例 #18
0
 def test_equal(self):
     """Test __eq__ method"""
     mat = self.rand_matrix(4, 4)
     self.assertEqual(SuperOp(mat), SuperOp(mat))
コード例 #19
0
ファイル: test_superop.py プロジェクト: v-r0/qiskit-terra
 def test_transpose(self):
     """Test transpose method."""
     mat = self.rand_matrix(4, 4)
     chan = SuperOp(mat)
     targ = SuperOp(np.transpose(mat))
     self.assertEqual(chan.transpose(), targ)
コード例 #20
0
 def test_add_except(self):
     """Test add method raises exceptions."""
     chan1 = SuperOp(self.sopI)
     chan2 = SuperOp(np.eye(16))
     self.assertRaises(QiskitError, chan1.add, chan2)
     self.assertRaises(QiskitError, chan1.add, 5)
コード例 #21
0
ファイル: test_superop.py プロジェクト: v-r0/qiskit-terra
 def test_compose_except(self):
     """Test compose different dimension exception"""
     self.assertRaises(QiskitError,
                       SuperOp(np.eye(4)).compose, SuperOp(np.eye(16)))
     self.assertRaises(QiskitError, SuperOp(np.eye(4)).compose, 2)
コード例 #22
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): 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)):
        channel = Operator(channel)
    else:
        channel = SuperOp(channel)
    input_dim, output_dim = channel.dim
    if input_dim != output_dim:
        raise QiskitError(
            'Quantum channel must have equal input and output dimensions.')

    if target is not None:
        # Multiple channel by adjoint of target
        target = Operator(target)
        if (input_dim, output_dim) != target.dim:
            raise QiskitError(
                'Quantum channel and target must have the same dimensions.')
        channel = channel @ target.adjoint()

    # 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 isinstance(channel, Operator) and (require_cp or require_tp):
        is_unitary = channel.is_unitary()
        # Validate as unitary
        if require_cp and not is_unitary:
            raise QiskitError('channel is not completely-positive')
        if require_tp and not is_unitary:
            raise QiskitError('channel is not trace-preserving')
    else:
        # Validate as QuantumChannel
        if require_cp and not channel.is_cp():
            raise QiskitError('channel is not completely-positive')
        if require_tp and not channel.is_tp():
            raise QiskitError('channel is not trace-preserving')

    # Compute process fidelity with identity channel
    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(channel.data) / (input_dim**2)
    return float(np.real(fid))