Пример #1
0
    def _multiply(self, other):
        """Return the QuantumChannel other * self.

        Args:
            other (complex): a complex number.

        Returns:
            Stinespring: the scalar multiplication other * self.

        Raises:
            QiskitError: if other is not a valid scalar.
        """
        if not isinstance(other, Number):
            raise QiskitError("other is not a number")

        ret = copy.copy(self)
        # If the number is complex or negative we need to convert to
        # general Stinespring representation so we first convert to
        # the Choi representation
        if isinstance(other, complex) or other < 1:
            # Convert to Choi-matrix
            ret._data = Stinespring(Choi(self)._multiply(other))._data
            return ret
        # If the number is real we can update the Kraus operators
        # directly
        num = np.sqrt(other)
        stine_l, stine_r = self._data
        stine_l = num * self._data[0]
        stine_r = None
        if self._data[1] is not None:
            stine_r = num * self._data[1]
        ret._data = (stine_l, stine_r)
        return ret
Пример #2
0
    def _multiply(self, other):
        """Return the QuantumChannel other * self.

        Args:
            other (complex): a complex number.

        Returns:
            Kraus: the scalar multiplication other * self as a Kraus object.

        Raises:
            QiskitError: if other is not a valid scalar.
        """
        if not isinstance(other, Number):
            raise QiskitError("other is not a number")

        ret = copy.copy(self)
        # If the number is complex we need to convert to general
        # kraus channel so we multiply via Choi representation
        if isinstance(other, complex) or other < 0:
            # Convert to Choi-matrix
            ret._data = Kraus(Choi(self)._multiply(other))._data
            return ret
        # If the number is real we can update the Kraus operators
        # directly
        val = np.sqrt(other)
        kraus_r = None
        kraus_l = [val * k for k in self._data[0]]
        if self._data[1] is not None:
            kraus_r = [val * k for k in self._data[1]]
        ret._data = (kraus_l, kraus_r)
        return ret
Пример #3
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 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_choi_compose(self):
     """Test compose of Choi matrices is correct."""
     mats = [self.UI, self.UX, self.UY, self.UZ, self.UH]
     chans = [
         Choi(mat) for mat in
         [self.choiI, self.choiX, self.choiY, self.choiZ, self.choiH]
     ]
     self._compare_compose_to_operator(chans, mats)
Пример #5
0
 def test_choi_to_operator(self):
     """Test Choi to Operator transformation."""
     # Test unitary channels
     for mat, choi in zip(self.unitary_mat, self.unitary_choi):
         chan1 = Operator(mat)
         chan2 = Operator(Choi(choi))
         self.assertTrue(
             matrix_equal(chan2.data, chan1.data, ignore_phase=True))
Пример #6
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))
Пример #7
0
 def test_choi_compose(self):
     """Test compose of Choi matrices is correct."""
     mats = [self.matI, self.matX, self.matY, self.matZ, self.matH]
     chans = [
         Choi(mat) for mat in
         [self.choiI, self.choiX, self.choiY, self.choiZ, self.choiH]
     ]
     self._compare_compose_to_unitary(chans, mats)
Пример #8
0
 def test_choi_to_unitary(self):
     """Test Choi to UnitaryChannel transformation."""
     # Test unitary channels
     for mat, choi in zip(self.unitary_mat, self.unitary_choi):
         chan1 = UnitaryChannel(mat)
         chan2 = UnitaryChannel(Choi(choi))
         self.assertTrue(
             matrix_equal(chan2.data, chan1.data, ignore_phase=True))
Пример #9
0
 def _choi_to_other_noncp(self, rep, qubits_test_cases, repetitions):
     """Test CP Choi to Other evolution."""
     for nq in qubits_test_cases:
         dim = 2**nq
         for _ in range(repetitions):
             rho = self.rand_rho(dim)
             mat = self.rand_matrix(dim**2, dim**2)
             chan = Choi(mat)
             rho1 = DensityMatrix(rho).evolve(chan).data
             rho2 = DensityMatrix(rho).evolve(rep(chan)).data
             assert_allclose(rho1, rho2)
Пример #10
0
    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.
        """
        return Choi(self)._evolve(state, qargs)
Пример #11
0
    def _add(self, other):
        """Return the QuantumChannel self + other.

        Args:
            other (QuantumChannel): a quantum channel subclass.

        Returns:
            Stinespring: the linear addition channel self + other.

        Raises:
            QiskitError: if other cannot be converted to a channel or
            has incompatible dimensions.
        """
        # Since we cannot directly add two channels in the Stinespring
        # representation we convert to the Choi representation
        return Stinespring(Choi(self).add(other))
Пример #12
0
    def _add(self, other):
        """Return the QuantumChannel self + other.

        Args:
            other (QuantumChannel): a quantum channel subclass.

        Returns:
            Kraus: the linear addition channel self + other.

        Raises:
            QiskitError: if other cannot be converted to a channel, or
            has incompatible dimensions.
        """
        # Since we cannot directly add two channels in the Kraus
        # representation we try and use the other channels method
        # or convert to the Choi representation
        return Kraus(Choi(self).add(other))
Пример #13
0
    def subtract(self, other):
        """Return the QuantumChannel self - other.

        Args:
            other (QuantumChannel): a quantum channel subclass.

        Returns:
            Stinespring: the linear subtraction self - other as
            Stinespring object.

        Raises:
            QiskitError: if other cannot be converted to a channel or
            has incompatible dimensions.
        """
        # Since we cannot directly subtract two channels in the Stinespring
        # representation we convert to the Choi representation
        return Stinespring(Choi(self).subtract(other))
Пример #14
0
    def _multiply(self, other):
        if not isinstance(other, Number):
            raise QiskitError("other is not a number")

        ret = copy.copy(self)
        # If the number is complex we need to convert to general
        # kraus channel so we multiply via Choi representation
        if isinstance(other, complex) or other < 0:
            # Convert to Choi-matrix
            ret._data = Kraus(Choi(self)._multiply(other))._data
            return ret
        # If the number is real we can update the Kraus operators
        # directly
        val = np.sqrt(other)
        kraus_r = None
        kraus_l = [val * k for k in self._data[0]]
        if self._data[1] is not None:
            kraus_r = [val * k for k in self._data[1]]
        ret._data = (kraus_l, kraus_r)
        return ret
Пример #15
0
    def _add(self, other, qargs=None):
        """Return the QuantumChannel self + other.

        If ``qargs`` are specified the other operator will be added
        assuming it is identity on all other subsystems.

        Args:
            other (QuantumChannel): a quantum channel subclass.
            qargs (None or list): optional subsystems to add on
                                  (Default: None)

        Returns:
            Stinespring: the linear addition channel self + other.

        Raises:
            QiskitError: if other cannot be converted to a channel or
                         has incompatible dimensions.
        """
        # Since we cannot directly add two channels in the Stinespring
        # representation we convert to the Choi representation
        return Stinespring(Choi(self)._add(other, qargs=qargs))
    def _multiply(self, other):
        if not isinstance(other, Number):
            raise QiskitError("other is not a number")

        ret = copy.copy(self)
        # If the number is complex or negative we need to convert to
        # general Stinespring representation so we first convert to
        # the Choi representation
        if isinstance(other, complex) or other < 1:
            # Convert to Choi-matrix
            ret._data = Stinespring(Choi(self)._multiply(other))._data
            return ret
        # If the number is real we can update the Kraus operators
        # directly
        num = np.sqrt(other)
        stine_l, stine_r = self._data
        stine_l = num * self._data[0]
        stine_r = None
        if self._data[1] is not None:
            stine_r = num * self._data[1]
        ret._data = (stine_l, stine_r)
        return ret
 def test_choi_conjugate(self):
     """Test conjugate of Choi matrices is correct."""
     mats = self.unitaries
     chans = [Choi(mat) for mat in self.chois]
     self._compare_conjugate_to_operator(chans, mats)
 def test_choi_adjoint(self):
     """Test adjoint of Choi matrices is correct."""
     mats = self.unitaries
     chans = [Choi(mat) for mat in self.chois]
     self._compare_adjoint_to_operator(chans, mats)
 def test_choi_adjoint_random(self):
     """Test adjoint of Choi matrices is correct."""
     mats = [self.rand_matrix(4, 4) for _ in range(4)]
     chans = [Choi(Operator(mat)) for mat in mats]
     self._compare_adjoint_to_operator(chans, mats)
Пример #20
0
 def transpose(self):
     """Return the transpose of the QuantumChannel."""
     # Since conjugation is basis dependent we transform
     # to the Choi representation to compute the
     # conjugate channel
     return Chi(Choi(self).transpose())
Пример #21
0
 def adjoint(self):
     return Chi(Choi(self).adjoint())
Пример #22
0
 def test_choi_subtract_other_rep(self):
     """Test subtraction of Choi matrices is correct."""
     chan = Choi(self.choiI)
     self._check_subtract_other_reps(chan)
Пример #23
0
 def _add(self, other, qargs=None):
     # Since we cannot directly add two channels in the Kraus
     # representation we try and use the other channels method
     # or convert to the Choi representation
     return Kraus(Choi(self)._add(other, qargs=qargs))
 def test_choi_compose_other_reps(self):
     """Test compose of Choi works with other reps."""
     chan = Choi(self.choiI)
     self._check_compose_other_reps(chan)
Пример #25
0
 def test_choi_add_other_rep(self):
     """Test addition of Choi matrices is correct."""
     chan = Choi(self.choiI)
     self._check_add_other_reps(chan)
 def __sub__(self, other):
     qargs = getattr(other, "qargs", None)
     if not isinstance(other, QuantumChannel):
         other = Choi(other)
     return self._add(-other, qargs=qargs)
 def test_choi_expand_other_reps(self):
     """Test expand of Choi works with other reps."""
     chan = Choi(self.choiI)
     self._check_expand_other_reps(chan)
 def test_choi_expand_random(self):
     """Test expand of random Choi matrices is correct."""
     mats = [self.rand_matrix(2, 2) for _ in range(4)]
     chans = [Choi(Operator(mat)) for mat in mats]
     self._compare_expand_to_operator(chans, mats)
 def test_choi_tensor_other_reps(self):
     """Test tensor of Choi works with other reps."""
     chan = Choi(self.choiI)
     self._check_tensor_other_reps(chan)
 def _add(self, other, qargs=None):
     # Since we cannot directly add two channels in the Stinespring
     # representation we convert to the Choi representation
     return Stinespring(Choi(self)._add(other, qargs=qargs))