예제 #1
0
 def test_to_channel_kraus(self):
     """Test to_channel for Kraus inputs."""
     A0 = np.array([[1, 0], [0, np.sqrt(1 - 0.3)]], dtype=complex)
     A1 = np.array([[0, 0], [0, np.sqrt(0.3)]], dtype=complex)
     B0 = np.array([[1, 0], [0, np.sqrt(1 - 0.5)]], dtype=complex)
     B1 = np.array([[0, 0], [0, np.sqrt(0.5)]], dtype=complex)
     target = SuperOp(Kraus([A0, A1])).tensor(SuperOp(Kraus([B0, B1])))
     error = QuantumError([A0, A1]).tensor(QuantumError([B0, B1]))
     self.assertEqual(target, error.to_channel())
예제 #2
0
 def _compare_negate_to_superop(self, rep, dim, samples, unitary=False):
     """Test negative channel is equivalent to SuperOp"""
     for _ in range(samples):
         if unitary:
             mat1 = self.rand_matrix(dim, dim)
             sop1 = np.kron(np.conj(mat1), mat1)
         else:
             sop1 = self.rand_matrix(dim * dim, dim * dim)
         targ = SuperOp(-1 * sop1)
         channel = SuperOp(-rep(SuperOp(sop1)))
         self.assertEqual(channel, targ)
예제 #3
0
 def test_chi_to_superop(self):
     """Test Chi to SuperOp transformation."""
     # Test unitary channels
     for chi, sop in zip(self.unitary_chi, self.unitary_sop):
         chan1 = SuperOp(sop)
         chan2 = SuperOp(Chi(chi))
         self.assertEqual(chan1, chan2)
     # Test depolarizing channels
     for p in [0.25, 0.5, 0.75, 1]:
         chan1 = SuperOp(self.depol_sop(p))
         chan2 = SuperOp(Chi(self.depol_chi(p)))
         self.assertEqual(chan1, chan2)
예제 #4
0
 def test_superop_to_choi(self):
     """Test SuperOp to Choi transformation."""
     # Test unitary channels
     for choi, sop in zip(self.unitary_choi, self.unitary_sop):
         chan1 = Choi(choi)
         chan2 = Choi(SuperOp(sop))
         self.assertEqual(chan1, chan2)
     # Test depolarizing channels
     for p in [0, 0.25, 0.5, 0.75, 1]:
         chan1 = Choi(self.depol_choi(p))
         chan2 = Choi(SuperOp(self.depol_sop(p)))
         self.assertEqual(chan1, chan2)
예제 #5
0
 def test_stinespring_to_superop(self):
     """Test Stinespring to SuperOp transformation."""
     # Test unitary channels
     for mat, sop in zip(self.unitary_mat, self.unitary_sop):
         chan1 = SuperOp(sop)
         chan2 = SuperOp(Kraus(mat))
         self.assertEqual(chan1, chan2)
     # Test depolarizing channels
     for p in [0.25, 0.5, 0.75, 1]:
         chan1 = SuperOp(self.depol_sop(p))
         chan2 = SuperOp(Stinespring(self.depol_stine(p)))
         self.assertEqual(chan1, chan2)
예제 #6
0
 def test_superop_to_ptm(self):
     """Test SuperOp to PTM transformation."""
     # Test unitary channels
     for sop, ptm in zip(self.unitary_sop, self.unitary_ptm):
         chan1 = PTM(ptm)
         chan2 = PTM(SuperOp(sop))
         self.assertEqual(chan1, chan2)
     # Test depolarizing channels
     for p in [0.25, 0.5, 0.75, 1]:
         chan1 = PTM(self.depol_ptm(p))
         chan2 = PTM(SuperOp(self.depol_sop(p)))
         self.assertEqual(chan1, chan2)
 def _compare_subtract_operator_to_superop(self, rep, dim, samples, unitary=False):
     """Test channel addition is equivalent to SuperOp"""
     for _ in range(samples):
         if unitary:
             mat1 = self.rand_matrix(dim, dim)
             sop1 = np.kron(np.conj(mat1), mat1)
         else:
             sop1 = self.rand_matrix(dim * dim, dim * dim)
         mat2 = self.rand_matrix(dim, dim)
         target = SuperOp(sop1) - SuperOp(Operator(mat2))
         channel = SuperOp(rep(SuperOp(sop1)) - Operator(mat2))
         self.assertEqual(channel, target)
예제 #8
0
 def _compare_multiply_to_superop(self, rep, dim, samples, unitary=False):
     """Test channel scalar multiplication is equivalent to SuperOp"""
     for _ in range(samples):
         if unitary:
             mat1 = self.rand_matrix(dim, dim)
             sop1 = np.kron(np.conj(mat1), mat1)
         else:
             sop1 = self.rand_matrix(dim * dim, dim * dim)
         val = 0.7
         targ = SuperOp(val * sop1)
         channel = SuperOp(rep(SuperOp(sop1))._multiply(val))
         self.assertEqual(channel, targ)
예제 #9
0
 def test_superop_to_superop(self):
     """Test SuperOp to SuperOp transformation."""
     # Test unitary channels
     for sop in self.unitary_sop:
         chan1 = SuperOp(sop)
         chan2 = SuperOp(chan1)
         self.assertEqual(chan1, chan2)
     # Test depolarizing channels
     for p in [0, 0.25, 0.5, 0.75, 1]:
         chan1 = SuperOp(self.depol_sop(p))
         chan2 = SuperOp(chan1)
         self.assertEqual(chan1, chan2)
예제 #10
0
 def test_ptm_to_superop(self):
     """Test PTM to SuperOp transformation."""
     # Test unitary channels
     for ptm, sop in zip(self.unitary_ptm, self.unitary_sop):
         chan1 = SuperOp(sop)
         chan2 = SuperOp(PTM(ptm))
         self.assertEqual(chan1, chan2)
     # Test depolarizing channels
     for p in [0.25, 0.5, 0.75, 1]:
         chan1 = SuperOp(self.depol_sop(p))
         chan2 = SuperOp(PTM(self.depol_ptm(p)))
         self.assertEqual(chan1, chan2)
예제 #11
0
 def test_superop_to_stinespring(self):
     """Test SuperOp to Stinespring transformation."""
     # Test unitary channels
     for mat, sop in zip(self.unitary_mat, self.unitary_sop):
         chan1 = Stinespring(mat)
         chan2 = Stinespring(SuperOp(sop))
         self.assertTrue(
             matrix_equal(chan2.data[0], chan1.data[0], ignore_phase=True))
     # Test depolarizing channels
     rho = np.diag([1, 0])
     for p in [0.25, 0.5, 0.75, 1]:
         targ = Stinespring(self.depol_stine(p))._evolve(rho)
         chan = Stinespring(SuperOp(self.depol_sop(p)))
         self.assertAllClose(chan._evolve(rho), targ)
예제 #12
0
 def test_superop_to_stinespring(self):
     """Test SuperOp to Stinespring transformation."""
     # Test unitary channels
     for mat, sop in zip(self.unitary_mat, self.unitary_sop):
         chan1 = Stinespring(mat)
         chan2 = Stinespring(SuperOp(sop))
         self.assertTrue(
             matrix_equal(chan2.data[0], chan1.data[0], ignore_phase=True))
     # Test depolarizing channels
     rho = DensityMatrix(np.diag([1, 0]))
     for p in [0.25, 0.5, 0.75, 1]:
         target = rho.evolve(Stinespring(self.depol_stine(p)))
         output = rho.evolve(Stinespring(SuperOp(self.depol_sop(p))))
         self.assertEqual(output, target)
예제 #13
0
 def _compare_subtract_to_superop(self, rep, dim, samples, unitary=False):
     """Test channel subtraction is equivalent to SuperOp"""
     for _ in range(samples):
         if unitary:
             mat1 = self.rand_matrix(dim, dim)
             mat2 = self.rand_matrix(dim, dim)
             sop1 = np.kron(np.conj(mat1), mat1)
             sop2 = np.kron(np.conj(mat2), mat2)
         else:
             sop1 = self.rand_matrix(dim * dim, dim * dim)
             sop2 = self.rand_matrix(dim * dim, dim * dim)
         targ = SuperOp(sop1 - sop2)
         channel = SuperOp(rep(SuperOp(sop1))._add(rep(-SuperOp(sop2))))
         self.assertEqual(channel, targ)
예제 #14
0
 def test_expand_both_kraus(self):
     """Test expand of two kraus errors"""
     a_0 = np.array([[1, 0], [0, np.sqrt(1 - 0.3)]], dtype=complex)
     a_1 = np.array([[0, 0], [0, np.sqrt(0.3)]], dtype=complex)
     b_0 = np.array([[1, 0], [0, np.sqrt(1 - 0.5)]], dtype=complex)
     b_1 = np.array([[0, 0], [0, np.sqrt(0.5)]], dtype=complex)
     # Use quantum channels for reference
     target = SuperOp(Kraus([a_0, a_1]).expand(Kraus([b_0, b_1])))
     error = QuantumError([a_0, a_1]).expand(QuantumError([b_0, b_1]))
     kraus, prob = error.error_term(0)
     self.assertEqual(prob, 1)
     self.assertEqual(kraus[0]['name'], 'kraus')
     self.assertEqual(kraus[0]['qubits'], [0, 1])
     error_superop = SuperOp(Kraus(kraus[0]['params']))
     self.assertEqual(target, error_superop, msg="Incorrect expand kraus")
예제 #15
0
 def test_compose_both_kraus(self):
     """Test composition of two kraus errors"""
     A0 = np.array([[1, 0], [0, np.sqrt(1 - 0.3)]], dtype=complex)
     A1 = np.array([[0, 0], [0, np.sqrt(0.3)]], dtype=complex)
     B0 = np.array([[1, 0], [0, np.sqrt(1 - 0.5)]], dtype=complex)
     B1 = np.array([[0, 0], [0, np.sqrt(0.5)]], dtype=complex)
     # Use quantum channels for reference
     target = SuperOp(Kraus([A0, A1]).compose(Kraus([B0, B1])))
     error = QuantumError([A0, A1]).compose(QuantumError([B0, B1]))
     kraus, p = error.error_term(0)
     self.assertEqual(p, 1)
     self.assertEqual(kraus[0]['name'], 'kraus')
     self.assertEqual(kraus[0]['qubits'], [0])
     error_superop = SuperOp(Kraus(kraus[0]['params']))
     self.assertEqual(target, error_superop, msg="Incorrect compose kraus")
예제 #16
0
    def compose(self, other, qargs=None, front=False):
        """Return the composition channel self∘other.

        Args:
            other (QuantumChannel): a quantum channel subclass.
            qargs (list): a list of subsystem positions to compose other on.
            front (bool): If False compose in standard order other(self(input))
                          otherwise compose in reverse order self(other(input))
                          [default: False]

        Returns:
            Stinespring: The composition channel as a Stinespring object.

        Raises:
            QiskitError: if other cannot be converted to a channel or
            has incompatible dimensions.
        """
        if qargs is not None:
            return Stinespring(
                SuperOp(self).compose(other, qargs=qargs, front=front))

        # Convert other to Kraus
        if not isinstance(other, Kraus):
            other = Kraus(other)
        # Check dimensions match up
        if front and self._input_dim != other._output_dim:
            raise QiskitError(
                'input_dim of self must match output_dim of other')
        if not front and self._output_dim != other._input_dim:
            raise QiskitError(
                'input_dim of other must match output_dim of self')
        # Since we cannot directly compose two channels in Stinespring
        # representation we convert to the Kraus representation
        return Stinespring(Kraus(self).compose(other, front=front))
예제 #17
0
    def compose(self, other, qargs=None, front=False):
        if qargs is None:
            qargs = getattr(other, 'qargs', None)
        if qargs is not None:
            return Kraus(
                SuperOp(self).compose(other, qargs=qargs, front=front))

        if not isinstance(other, Kraus):
            other = Kraus(other)
        new_shape = self._op_shape.compose(other._op_shape, qargs, front)
        input_dims = new_shape.dims_r()
        output_dims = new_shape.dims_l()

        if front:
            ka_l, ka_r = self._data
            kb_l, kb_r = other._data
        else:
            ka_l, ka_r = other._data
            kb_l, kb_r = self._data

        kab_l = [np.dot(a, b) for a in ka_l for b in kb_l]
        if ka_r is None and kb_r is None:
            kab_r = None
        elif ka_r is None:
            kab_r = [np.dot(a, b) for a in ka_l for b in kb_r]
        elif kb_r is None:
            kab_r = [np.dot(a, b) for a in ka_r for b in kb_l]
        else:
            kab_r = [np.dot(a, b) for a in ka_r for b in kb_r]
        ret = Kraus((kab_l, kab_r), input_dims, output_dims)
        ret._op_shape = new_shape
        return ret
예제 #18
0
    def _chanmul(self, other, qargs=None, left_multiply=False):
        """Multiply two quantum channels.

        Args:
            other (QuantumChannel): a quantum channel.
            qargs (list): a list of subsystem positions to compose other on.
            left_multiply (bool): If True return other * self
                                  If False return self * other [Default:False]

        Returns:
            Choi: The composition channel as a Chi object.

        Raises:
            QiskitError: if other is not a QuantumChannel subclass, or
            has incompatible dimensions.
        """
        if qargs is not None:
            return Chi(
                SuperOp(self)._chanmul(other,
                                       qargs=qargs,
                                       left_multiply=left_multiply))

        # Convert other to Choi since we convert via Choi
        if not isinstance(other, Choi):
            other = Choi(other)
        # Check dimensions match up
        if not left_multiply and self._input_dim != other._output_dim:
            raise QiskitError(
                'input_dim of self must match output_dim of other')
        if left_multiply and self._output_dim != other._input_dim:
            raise QiskitError(
                'input_dim of other must match output_dim of self')
        # Since we cannot directly multiply two channels in the Chi
        # representation we convert to the Choi representation
        return Chi(Choi(self)._chanmul(other, left_multiply=left_multiply))
예제 #19
0
    def compose(self, other, qargs=None, front=False):
        """Return the composed quantum channel self @ other.

        Args:
            other (QuantumChannel): a quantum channel.
            qargs (list or None): a list of subsystem positions to apply
                                  other on. If None apply on all
                                  subsystems [default: None].
            front (bool): If True compose using right operator multiplication,
                          instead of left multiplication [default: False].

        Returns:
            PTM: The quantum channel self @ other.

        Raises:
            QiskitError: if other has incompatible dimensions.

        Additional Information:
            Composition (``@``) is defined as `left` matrix multiplication for
            :class:`SuperOp` matrices. That is that ``A @ B`` is equal to ``B * A``.
            Setting ``front=True`` returns `right` matrix multiplication
            ``A * B`` and is equivalent to the :meth:`dot` method.
        """
        if qargs is not None:
            return PTM(SuperOp(self).compose(other, qargs=qargs, front=front))

        # Convert other to PTM
        if not isinstance(other, PTM):
            other = PTM(other)
        input_dims, output_dims = self._get_compose_dims(other, qargs, front)
        if front:
            data = np.dot(self._data, other.data)
        else:
            data = np.dot(other.data, self._data)
        return PTM(data, input_dims, output_dims)
예제 #20
0
    def compose(self, other, qargs=None, front=False):
        """Return the composed quantum channel self @ other.

        Args:
            other (QuantumChannel): a quantum channel.
            qargs (list or None): a list of subsystem positions to apply
                                  other on. If None apply on all
                                  subsystems [default: None].
            front (bool): If True compose using right operator multiplication,
                          instead of left multiplication [default: False].

        Returns:
            Chi: The quantum channel self @ other.

        Raises:
            QiskitError: if other has incompatible dimensions.

        Additional Information:
            Composition (``@``) is defined as `left` matrix multiplication for
            :class:`SuperOp` matrices. That is that ``A @ B`` is equal to ``B * A``.
            Setting ``front=True`` returns `right` matrix multiplication
            ``A * B`` and is equivalent to the :meth:`dot` method.
        """
        if qargs is not None:
            return Chi(SuperOp(self).compose(other, qargs=qargs, front=front))
        # If no qargs we compose via Choi representation to avoid an additional
        # representation conversion to SuperOp and then convert back to Chi
        return Chi(Choi(self).compose(other, front=front))
예제 #21
0
    def compose(self, other, qargs=None, front=False):
        if qargs is None:
            qargs = getattr(other, "qargs", None)
        if qargs is not None:
            return Choi(SuperOp(self).compose(other, qargs=qargs, front=front))

        if not isinstance(other, Choi):
            other = Choi(other)
        new_shape = self._op_shape.compose(other._op_shape, qargs, front)
        output_dim, input_dim = new_shape.shape

        if front:
            first = np.reshape(other._data, other._bipartite_shape)
            second = np.reshape(self._data, self._bipartite_shape)
        else:
            first = np.reshape(self._data, self._bipartite_shape)
            second = np.reshape(other._data, other._bipartite_shape)

        # Contract Choi matrices for composition
        data = np.reshape(
            np.einsum("iAjB,AkBl->ikjl", first, second),
            (input_dim * output_dim, input_dim * output_dim),
        )
        ret = Choi(data)
        ret._op_shape = new_shape
        return ret
예제 #22
0
파일: choi.py 프로젝트: danmills0/qiskit
    def _evolve(self, state, qargs=None):
        """Evolve a quantum state by the QuantumChannel.

        Args:
            state (QuantumState): The input statevector or density matrix.
            qargs (list): a list of QuantumState subsystem positions to apply
                           the operator on.

        Returns:
            DensityMatrix: the output quantum state as a density matrix.

        Raises:
            QiskitError: if the operator dimension does not match the
            specified QuantumState subsystem dimensions.
        """
        # If subsystem evolution we use the SuperOp representation
        if qargs is not None:
            return SuperOp(self)._evolve(state, qargs)
        # Otherwise we compute full evolution directly
        state = self._format_state(state, density_matrix=True)
        if state.shape[0] != self._input_dim:
            raise QiskitError(
                "QuantumChannel input dimension is not equal to state dimension."
            )
        return np.einsum('AB,AiBj->ij', state,
                         np.reshape(self._data, self._bipartite_shape))
예제 #23
0
def circuit2superop(circuit, min_qubits=1):
    """Return the SuperOp for a standard instruction."""
    # Get number of qubits
    max_qubits = 1
    for instr in circuit:
        qubits = []
        if hasattr(instr, 'qubits'):
            qubits = instr.qubits
        elif isinstance(instr, dict):
            qubits = instr.get('qubits', [])
        max_qubits = max(max_qubits, 1 + max(qubits))

    num_qubits = max(max_qubits, min_qubits)

    # Initialize N-qubit identity superoperator
    superop = SuperOp(np.eye(4**num_qubits))
    # compose each circuit element with the superoperator
    for instr in circuit:
        instr_op = standard_instruction_channel(instr)
        if instr_op is None:
            raise NoiseError('Cannot convert instruction {} to SuperOp'.format(instr))
        if hasattr(instr, 'qubits'):
            qubits = instr.qubits
        else:
            qubits = instr['qubits']
        superop = superop.compose(instr_op, qubits)
    return superop
예제 #24
0
    def reset(self, qargs=None):
        """Reset state or subsystems to the 0-state.

        Args:
            qargs (list or None): subsystems to reset, if None all
                                  subsystems will be reset to their 0-state
                                  (Default: None).

        Returns:
            DensityMatrix: the reset state.

        Additional Information:
            If all subsystems are reset this will return the ground state
            on all subsystems. If only a some subsystems are reset this
            function will perform evolution by the reset
            :class:`~qiskit.quantum_info.SuperOp` of the reset subsystems.
        """
        if qargs is None:
            # Resetting all qubits does not require sampling or RNG
            ret = copy.copy(self)
            state = np.zeros(self._op_shape.shape, dtype=complex)
            state[0, 0] = 1
            ret._data = state
            return ret

        # Reset by evolving by reset SuperOp
        dims = self.dims(qargs)
        reset_superop = SuperOp(ScalarOp(dims, coeff=0))
        reset_superop.data[0] = Operator(ScalarOp(dims)).data.ravel()
        return self.evolve(reset_superop, qargs=qargs)
예제 #25
0
    def compose(self, other, qargs=None, front=False):
        """Return the composition channel self∘other.

        Args:
            other (QuantumChannel): a quantum channel.
            qargs (list): a list of subsystem positions to compose other on.
            front (bool): If False compose in standard order other(self(input))
                          otherwise compose in reverse order self(other(input))
                          [default: False]

        Returns:
            Chi: The composition channel as a Chi object.

        Raises:
            QiskitError: if other is not a QuantumChannel subclass, or
            has incompatible dimensions.
        """
        if qargs is not None:
            return Chi(SuperOp(self).compose(other, qargs=qargs, front=front))

        # Convert other to Choi since we convert via Choi
        if not isinstance(other, Choi):
            other = Choi(other)
        # Check dimensions match up
        if front and self._input_dim != other._output_dim:
            raise QiskitError(
                'input_dim of self must match output_dim of other')
        if not front and self._output_dim != other._input_dim:
            raise QiskitError(
                'input_dim of other must match output_dim of self')
        # Since we cannot directly add two channels in the Chi
        # representation we convert to the Choi representation
        return Chi(Choi(self).compose(other, front=front))
예제 #26
0
    def compose(self, other, qargs=None, front=False):
        """Return the composed quantum channel self @ other.

        Args:
            other (QuantumChannel): a quantum channel.
            qargs (list or None): a list of subsystem positions to apply
                                  other on. If None apply on all
                                  subsystems [default: None].
            front (bool): If True compose using right operator multiplication,
                          instead of left multiplication [default: False].

        Returns:
            Stinespring: The quantum channel self @ other.

        Raises:
            QiskitError: if other cannot be converted to a Stinespring or has
                         incompatible dimensions.

        Additional Information:
            Composition (``@``) is defined as `left` matrix multiplication for
            :class:`SuperOp` matrices. That is that ``A @ B`` is equal to ``B * A``.
            Setting ``front=True`` returns `right` matrix multiplication
            ``A * B`` and is equivalent to the :meth:`dot` method.
        """
        if qargs is None:
            qargs = getattr(other, 'qargs', None)
        if qargs is not None:
            return Stinespring(
                SuperOp(self).compose(other, qargs=qargs, front=front))

        # Otherwise we convert via Kraus representation rather than
        # superoperator to avoid unnecessary representation conversions
        return Stinespring(Kraus(self).compose(other, front=front))
예제 #27
0
def circuit2superop(circuit, min_qubits=1):
    """Return the SuperOp for a standard instruction."""
    warnings.warn(
        'circuit2superop has been deprecated as of qiskit-aer 0.10.0'
        ' and will be removed no earlier than 3 months from that release date.',
        DeprecationWarning, stacklevel=2)

    # Get number of qubits
    max_qubits = 1
    for instr in circuit:
        qubits = []
        if hasattr(instr, 'qubits'):
            qubits = instr.qubits
        elif isinstance(instr, dict):
            qubits = instr.get('qubits', [])
        max_qubits = max(max_qubits, 1 + max(qubits))

    num_qubits = max(max_qubits, min_qubits)

    # Initialize N-qubit identity superoperator
    superop = SuperOp(np.eye(4**num_qubits))
    # compose each circuit element with the superoperator
    for instr in circuit:
        instr_op = standard_instruction_channel(instr)
        if instr_op is None:
            raise NoiseError('Cannot convert instruction {} to SuperOp'.format(instr))
        if hasattr(instr, 'qubits'):
            qubits = instr.qubits
        else:
            qubits = instr['qubits']
        superop = superop.compose(instr_op, qubits)
    return superop
예제 #28
0
 def test_superop_compose(self):
     """Test compose of SuperOp matrices is correct."""
     mats = [self.matI, self.matX, self.matY, self.matZ, self.matH]
     chans = [
         SuperOp(mat)
         for mat in [self.sopI, self.sopX, self.sopY, self.sopZ, self.sopH]
     ]
     self._compare_compose_to_unitary(chans, mats)
예제 #29
0
 def compose(self, other, qargs=None, front=False):
     if qargs is None:
         qargs = getattr(other, "qargs", None)
     if qargs is not None:
         return Chi(SuperOp(self).compose(other, qargs=qargs, front=front))
     # If no qargs we compose via Choi representation to avoid an additional
     # representation conversion to SuperOp and then convert back to Chi
     return Chi(Choi(self).compose(other, front=front))
 def test_superop_compose(self):
     """Test compose of SuperOp matrices is correct."""
     mats = [self.UI, self.UX, self.UY, self.UZ, self.UH]
     chans = [
         SuperOp(mat)
         for mat in [self.sopI, self.sopX, self.sopY, self.sopZ, self.sopH]
     ]
     self._compare_compose_to_operator(chans, mats)