示例#1
0
    def power(self, n, inplace=False):
        """Return the compose of a QuantumChannel with itself n times.

        Args:
            n (int): the number of times to compose with self (n>0).
            inplace (bool): If True modify the current object inplace
                            [Default: False]

        Returns:
            SuperOp: the n-times composition channel as a SuperOp object.

        Raises:
            QiskitError: if the input and output dimensions of the
            QuantumChannel are not equal, or the power is not a positive
            integer.
        """
        if not isinstance(n, int) or n < 1:
            raise QiskitError("Can only power with positive integer powers.")
        if self._input_dim != self._output_dim:
            raise QiskitError("Can only power with input_dim = output_dim.")
        # Override base class power so we can implement more efficiently
        # using Numpy.matrix_power
        if inplace:
            if n == 1:
                return self
            self._data = np.linalg.matrix_power(self._data, n)
            return self
        # Return new object
        return SuperOp(np.linalg.matrix_power(self._data, n), *self.dims)
示例#2
0
    def compose(self, other, qubits=None, front=False):
        """Return the composition channel self∘other.

        Args:
            other (QuantumChannel): a quantum channel subclass.
            qubits (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 qubits is not None:
            # TODO
            raise QiskitError("NOT IMPLEMENTED: subsystem composition.")

        # 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))
示例#3
0
    def power(self, n, inplace=False):
        """Return the compose of a QuantumChannel with itself n times.

        Args:
            n (int): the number of times to compose with self (n>0).
            inplace (bool): If True modify the current object inplace
                            [Default: False]

        Returns:
            QuantumChannel: the n-times composition channel.

        Raises:
            QiskitError: if the input and output dimensions of the
            QuantumChannel are not equal, or the power is not a positive
            integer.
        """
        if not isinstance(n, int) or n < 1:
            raise QiskitError("Can only power with positive integer powers.")
        if self._input_dim != self._output_dim:
            raise QiskitError("Can only power with input_dim = output_dim.")
        # Update inplace
        if inplace:
            if n == 1:
                return self
            # cache current state to apply n-times
            cache = self.copy()
            for _ in range(1, n):
                self.compose(cache, inplace=True)
            return self
        # Return new object
        ret = self.copy()
        for _ in range(1, n):
            ret = ret.compose(self)
        return ret
示例#4
0
    def subtract(self, other, inplace=False):
        """Return the QuantumChannel self - other.

        Args:
            other (QuantumChannel): a quantum channel subclass
            inplace (bool): If True modify the current object inplace
                           [Default: False]

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

        Raises:
            QiskitError: if other is not a QuantumChannel subclass, or
            has incompatible dimensions.
        """
        if not issubclass(other.__class__, QuantumChannel):
            raise QiskitError('other is not a QuantumChannel subclass')
        if self.dims != other.dims:
            raise QiskitError("other QuantumChannel dimensions are not equal")
        if not isinstance(other, SuperOp):
            other = SuperOp(other)
        if inplace:
            self._data -= other.data
            return self
        input_dim, output_dim = self.dims
        return SuperOp(self._data - other.data, input_dim, output_dim)
示例#5
0
    def compose(self, other, front=False):
        """Return the composition channel self∘other.

        Args:
            other (QuantumChannel): a quantum channel subclass.
            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 is not a QuantumChannel subclass, or
            has incompatible dimensions.
        """
        if not issubclass(other.__class__, QuantumChannel):
            raise QiskitError('other is not a QuantumChannel subclass')
        # 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))
示例#6
0
 def __init__(self, data, input_dim=None, output_dim=None):
     # Check if input is a quantum channel object
     # If so we disregard the dimension kwargs
     if issubclass(data.__class__, QuantumChannel):
         input_dim, output_dim = data.dims
         choi_mat = _to_choi(data.rep, data._data, input_dim, output_dim)
     else:
         choi_mat = np.array(data, dtype=complex)
         # Determine input and output dimensions
         dim_l, dim_r = choi_mat.shape
         if dim_l != dim_r:
             raise QiskitError('Invalid Choi-matrix input.')
         if output_dim is None and input_dim is None:
             output_dim = int(np.sqrt(dim_l))
             input_dim = dim_l // output_dim
         elif input_dim is None:
             input_dim = dim_l // output_dim
         elif output_dim is None:
             output_dim = dim_l // input_dim
         # Check dimensions
         if input_dim * output_dim != dim_l:
             raise QiskitError(
                 "Invalid input and output dimension for Choi-matrix input."
             )
     super().__init__('Choi', choi_mat, input_dim, output_dim)
示例#7
0
def measure(self, qubit, cbit):
    """Measure quantum bit into classical bit (tuples).

    Args:
        qubit (QuantumRegister|tuple): quantum register
        cbit (ClassicalRegister|tuple): classical register

    Returns:
        qiskit.Instruction: the attached measure instruction.

    Raises:
        QiskitError: if qubit is not in this circuit or bad format;
            if cbit is not in this circuit or not creg.
    """
    if isinstance(qubit, QuantumRegister) and isinstance(cbit, ClassicalRegister) \
            and len(qubit) == len(cbit):
        instructions = InstructionSet()
        for i in range(qubit.size):
            instructions.add(self.measure((qubit, i), (cbit, i)))
        return instructions
    elif isinstance(qubit, QuantumRegister) and isinstance(
            cbit, ClassicalRegister) and len(qubit) != len(cbit):
        raise QiskitError(
            "qubit (%s) and cbit (%s) should have the same length" %
            (len(qubit), len(cbit)))
    elif not (isinstance(qubit, tuple) and isinstance(cbit, tuple)):
        raise QiskitError(
            "Both qubit <%s> and cbit <%s> should be Registers or formated as tuples. "
            "Hint: You can use subscript eg. cbit[0] to convert it into tuple."
            % (type(qubit).__name__, type(cbit).__name__))

    self._check_qubit(qubit)
    self._check_creg(cbit[0])
    cbit[0].check_range(cbit[1])
    return self._attach(Measure(qubit, cbit, self))
示例#8
0
 def _append_instruction(self, obj, qargs=None):
     """Update the current Operator by apply an instruction."""
     if isinstance(obj, Instruction):
         mat = None
         if hasattr(obj, 'to_matrix'):
             # If instruction is a gate first we see if it has a
             # `to_matrix` definition and if so use that.
             try:
                 mat = obj.to_matrix()
             except QiskitError:
                 pass
         if mat is not None:
             # Perform the composition and inplace update the current state
             # of the operator
             op = self.compose(mat, qargs=qargs)
             self._data = op.data
         else:
             # If the instruction doesn't have a matrix defined we use its
             # circuit decomposition definition if it exists, otherwise we
             # cannot compose this gate and raise an error.
             if obj.definition is None:
                 raise QiskitError('Cannot apply Instruction: {}'.format(
                     obj.name))
             for instr, qregs, cregs in obj.definition:
                 if cregs:
                     raise QiskitError(
                         'Cannot apply instruction with classical registers: {}'
                         .format(instr.name))
                 # Get the integer position of the flat register
                 new_qargs = [tup[1] for tup in qregs]
                 self._append_instruction(instr, qargs=new_qargs)
     else:
         raise QiskitError('Input is not an instruction.')
示例#9
0
    def _reshape(self, input_dims=None, output_dims=None):
        """Reshape input and output dimensions of operator.

        Arg:
            input_dims (tuple): new subsystem input dimensions.
            output_dims (tuple): new subsystem output dimensions.

        Returns:
            Operator: returns self with reshaped input and output dimensions.

        Raises:
            QiskitError: if combined size of all subsystem input dimension or
            subsystem output dimensions is not constant.
        """
        if input_dims is not None:
            if np.product(input_dims) != self._input_dim:
                raise QiskitError(
                    "Reshaped input_dims are incompatible with combined input dimension."
                )
            self._input_dims = tuple(input_dims)
        if output_dims is not None:
            if np.product(output_dims) != self._output_dim:
                raise QiskitError(
                    "Reshaped input_dims are incompatible with combined input dimension."
                )
            self._output_dims = tuple(output_dims)
        return self
示例#10
0
    def to_instruction(self):
        """Convert to a Kraus or UnitaryGate circuit instruction.

        If the channel is unitary it will be added as a unitary gate,
        otherwise it will be added as a kraus simulator instruction.

        Returns:
            Instruction: A kraus instruction for the channel.

        Raises:
            QiskitError: if input data is not an N-qubit CPTP quantum channel.
        """
        from qiskit.circuit.instruction import Instruction
        # Check if input is an N-qubit CPTP channel.
        n_qubits = int(np.log2(self._input_dim))
        if self._input_dim != self._output_dim or 2**n_qubits != self._input_dim:
            raise QiskitError(
                'Cannot convert QuantumChannel to Instruction: channel is not an N-qubit channel.'
            )
        if not self.is_cptp():
            raise QiskitError(
                'Cannot convert QuantumChannel to Instruction: channel is not CPTP.'
            )
        # Next we convert to the Kraus representation. Since channel is CPTP we know
        # that there is only a single set of Kraus operators
        kraus, _ = _to_kraus(self.rep, self._data, *self.dim)
        # If we only have a single Kraus operator then the channel is
        # a unitary channel so can be converted to a UnitaryGate. We do this by
        # converting to an Operator and using its to_instruction method
        if len(kraus) == 1:
            return Operator(kraus[0]).to_instruction()
        return Instruction('kraus', n_qubits, 0, kraus)
示例#11
0
 def __init__(self, data, input_dims=None, output_dims=None):
     """Initialize a SuperOp quantum channel operator."""
     if issubclass(data.__class__, BaseOperator):
         # If not a channel we use `to_operator` method to get
         # the unitary-representation matrix for input
         if not issubclass(data.__class__, QuantumChannel):
             data = data.to_operator()
         input_dim, output_dim = data.dim
         super_mat = _to_superop(data.rep, data._data, input_dim,
                                 output_dim)
         if input_dims is None:
             input_dims = data.input_dims()
         if output_dims is None:
             output_dims = data.output_dims()
     elif isinstance(data, (list, np.ndarray)):
         # We initialize directly from superoperator matrix
         super_mat = np.array(data, dtype=complex)
         # Determine total input and output dimensions
         dout, din = super_mat.shape
         input_dim = int(np.sqrt(din))
         output_dim = int(np.sqrt(dout))
         if output_dim**2 != dout or input_dim**2 != din:
             raise QiskitError("Invalid shape for SuperOp matrix.")
     else:
         raise QiskitError("Invalid input data format for SuperOp")
     # Check and format input and output dimensions
     input_dims = self._automatic_dims(input_dims, input_dim)
     output_dims = self._automatic_dims(output_dims, output_dim)
     super().__init__('SuperOp', super_mat, input_dims, output_dims)
示例#12
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))
示例#13
0
 def __init__(self, data, input_dim=None, output_dim=None):
     # Check if input is a quantum channel object
     # If so we disregard the dimension kwargs
     if issubclass(data.__class__, QuantumChannel):
         input_dim, output_dim = data.dims
         if input_dim != output_dim:
             raise QiskitError(
                 "Cannot convert to Chi-matrix: input_dim " +
                 "({}) != output_dim ({})".format(input_dim, output_dim))
         chi_mat = _to_chi(data.rep, data._data, input_dim, output_dim)
     else:
         chi_mat = np.array(data, dtype=complex)
         # Determine input and output dimensions
         dim_l, dim_r = chi_mat.shape
         if dim_l != dim_r:
             raise QiskitError('Invalid Choi-matrix input.')
         if output_dim is None and input_dim is None:
             output_dim = int(np.sqrt(dim_l))
             input_dim = dim_l // output_dim
         elif input_dim is None:
             input_dim = dim_l // output_dim
         elif output_dim is None:
             output_dim = dim_l // input_dim
         # Check dimensions
         if input_dim * output_dim != dim_l:
             raise QiskitError(
                 "Invalid input and output dimension for Chi-matrix input.")
         nqubits = int(np.log2(input_dim))
         if 2**nqubits != input_dim:
             raise QiskitError("Input is not an n-qubit Chi matrix.")
     super().__init__('Chi', chi_mat, input_dim, output_dim)
示例#14
0
    def add(self, other, inplace=False):
        """Return the QuantumChannel self + other.

        Args:
            other (QuantumChannel): a quantum channel subclass
            inplace (bool): If True modify the current object inplace
                           [Default: False]

        Returns:
            Chi: the linear addition self + other as a Chi object.

        Raises:
            QiskitError: if other is not a QuantumChannel subclass, or
            has incompatible dimensions.
        """
        if not issubclass(other.__class__, QuantumChannel):
            raise QiskitError('other is not a QuantumChannel subclass')
        if self.dims != other.dims:
            raise QiskitError("other QuantumChannel dimensions are not equal")
        if not isinstance(other, Chi):
            other = Chi(other)
        if inplace:
            self._data += other._data
            return self
        input_dim, output_dim = self.dims
        return Chi(self._data + other.data, input_dim, output_dim)
 def _check_qreg(self, register):
     """Raise exception if r is not in this circuit or not qreg."""
     if not isinstance(register, QuantumRegister):
         raise QiskitError("expected quantum register")
     if not self.has_register(register):
         raise QiskitError("register '%s' not in this circuit" %
                           register.name)
示例#16
0
    def compose(self, other, inplace=False, front=False):
        """Return the composition channel self∘other.

        Args:
            other (QuantumChannel): a quantum channel subclass
            inplace (bool): If True modify the current object inplace
                            [Default: False]
            front (bool): If False compose in standard order other(self(input))
                          otherwise compose in reverse order self(other(input))
                          [default: False]

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

        Raises:
            QiskitError: if other is not a QuantumChannel subclass, has
            incompatible dimensions, or is a non-unitary channel.
        """
        if not issubclass(other.__class__, QuantumChannel):
            raise QiskitError('Other is not a channel rep')
        # 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')
        # Convert to UnitaryChannel matrix
        if not isinstance(other, UnitaryChannel):
            other = UnitaryChannel(other)

        if front:
            # Composition A(B(input))
            if self._input_dim != other._output_dim:
                raise QiskitError(
                    'input_dim of self must match output_dim of other')
            input_dim = other._input_dim
            output_dim = self._output_dim
            if inplace:
                np.dot(self._data, other.data, out=self._data)
                self._input_dim = input_dim
                self._output_dim = output_dim
                return self
            return UnitaryChannel(np.dot(self._data, other.data), input_dim,
                                  output_dim)
        # Composition B(A(input))
        if self._output_dim != other._input_dim:
            raise QiskitError(
                'input_dim of other must match output_dim of self')
        input_dim = self._input_dim
        output_dim = other._output_dim
        if inplace:
            # Numpy out raises error if we try and use out=self._data here
            self._data = np.dot(other.data, self._data)
            self._input_dim = input_dim
            self._output_dim = output_dim
            return self
        return UnitaryChannel(np.dot(other.data, self._data), input_dim,
                              output_dim)
 def _check_creg(self, register):
     """Raise exception if r is not in this circuit or not creg."""
     if not isinstance(register, ClassicalRegister):
         raise QiskitError("Expected ClassicalRegister, but %s given" %
                           type(register))
     if not self.has_register(register):
         raise QiskitError("register '%s' not in this circuit" %
                           register.name)
示例#18
0
    def compose(self, other, inplace=False, front=False):
        """Return the composition channel self∘other.

        Args:
            other (QuantumChannel): a quantum channel subclass
            inplace (bool): If True modify the current object inplace
                            [Default: False]
            front (bool): If False compose in standard order other(self(input))
                          otherwise compose in reverse order self(other(input))
                          [default: False]

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

        Raises:
            QiskitError: if other is not a QuantumChannel subclass, or
            has incompatible dimensions.
        """
        if not issubclass(other.__class__, QuantumChannel):
            raise QiskitError('other is not a QuantumChannel subclass')
        # 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')
        # Convert to Choi matrix
        if not isinstance(other, Kraus):
            other = Kraus(other)

        if front:
            ka_l, ka_r = self._data
            kb_l, kb_r = other._data
            input_dim = other._input_dim
            output_dim = self._output_dim
        else:
            ka_l, ka_r = other._data
            kb_l, kb_r = self._data
            input_dim = self._input_dim
            output_dim = other._output_dim

        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]
        data = (kab_l, kab_r)
        if inplace:
            self._data = data
            self._input_dim = input_dim
            self._output_dim = output_dim
            return self
        return Kraus(data, input_dim, output_dim)
示例#19
0
 def rtol(self, rtol):
     """Set the relative tolerence parameter for float comparisons."""
     max_tol = QuantumChannel.MAX_TOL
     if rtol < 0:
         raise QiskitError("Invalid rtol: must be non-negative.")
     if rtol > max_tol:
         raise QiskitError(
             "Invalid rtol: must be less than {}.".format(max_tol))
     QuantumChannel.RTOL = rtol
示例#20
0
def _check_nqubit_dim(input_dim, output_dim):
    """Return true if dims correspond to an n-qubit channel."""
    if input_dim != output_dim:
        raise QiskitError(
            'Not an n-qubit channel: input_dim' +
            ' ({}) != output_dim ({})'.format(input_dim, output_dim))
    num_qubits = int(np.log2(input_dim))
    if 2**num_qubits != input_dim:
        raise QiskitError('Not an n-qubit channel: input_dim != 2 ** n')
示例#21
0
    def compose(self, other, inplace=False, front=False):
        """Return the composition channel self∘other.

        Args:
            other (QuantumChannel): a quantum channel subclass
            inplace (bool): If True modify the current object inplace
                            [Default: False]
            front (bool): If False compose in standard order other(self(input))
                          otherwise compose in reverse order self(other(input))
                          [default: False]

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

        Raises:
            QiskitError: if other is not a QuantumChannel subclass, or
            has incompatible dimensions.
        """
        if not issubclass(other.__class__, QuantumChannel):
            raise QiskitError('Other is not a channel rep')
        # 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')
        # Convert other to SuperOp
        if not isinstance(other, SuperOp):
            other = SuperOp(other)

        if front:
            # Composition A(B(input))
            input_dim = other._input_dim
            output_dim = self._output_dim
            if inplace:
                if self.dims == other.dims:
                    np.dot(self._data, other.data, out=self._data)
                else:
                    self._data = np.dot(self._data, other.data)
                self._input_dim = input_dim
                self._output_dim = output_dim
                return self
            return SuperOp(np.dot(self._data, other.data), input_dim,
                           output_dim)
        # Composition B(A(input))
        input_dim = self._input_dim
        output_dim = other._output_dim
        if inplace:
            if self.dims == other.dims:
                np.dot(other.data, self._data, out=self._data)
            else:
                self._data = np.dot(other.data, self._data)
            self._input_dim = input_dim
            self._output_dim = output_dim
            return self
        return SuperOp(np.dot(other.data, self._data), input_dim, output_dim)
示例#22
0
    def __init__(self, data, input_dims=None, output_dims=None):
        """Initialize a Stinespring quantum channel operator."""
        if issubclass(data.__class__, BaseOperator):
            # If not a channel we use `to_operator` method to get
            # the unitary-representation matrix for input
            if not issubclass(data.__class__, QuantumChannel):
                data = data.to_operator()
            input_dim, output_dim = data.dim
            stine = _to_stinespring(data.rep, data._data, input_dim,
                                    output_dim)
            if input_dims is None:
                input_dims = data.input_dims()
            if output_dims is None:
                output_dims = data.output_dims()
        elif isinstance(data, (list, tuple, np.ndarray)):
            if not isinstance(data, tuple):
                # Convert single Stinespring set to length 1 tuple
                stine = (np.array(data, dtype=complex), None)
            if isinstance(data, tuple) and len(data) == 2:
                if data[1] is None:
                    stine = (np.array(data[0], dtype=complex), None)
                else:
                    stine = (np.array(data[0], dtype=complex),
                             np.array(data[1], dtype=complex))

            dim_left, dim_right = stine[0].shape
            # If two stinespring matrices check they are same shape
            if stine[1] is not None:
                if stine[1].shape != (dim_left, dim_right):
                    raise QiskitError("Invalid Stinespring input.")
            input_dim = dim_right
            if output_dims:
                output_dim = np.product(output_dims)
            else:
                output_dim = input_dim
            if dim_left % output_dim != 0:
                raise QiskitError("Invalid output_dim")
        else:
            raise QiskitError("Invalid input data format for Stinespring")

        # Check and format input and output dimensions
        input_dims = self._automatic_dims(input_dims, input_dim)
        output_dims = self._automatic_dims(output_dims, output_dim)
        # Initialize either single or general Stinespring
        if stine[1] is None or (stine[1] == stine[0]).all():
            # Standard Stinespring map
            super().__init__(
                'Stinespring', (stine[0], None),
                input_dims=input_dims,
                output_dims=output_dims)
        else:
            # General (non-CPTP) Stinespring map
            super().__init__(
                'Stinespring',
                stine,
                input_dims=input_dims,
                output_dims=output_dims)
示例#23
0
 def _rtol(self, rtol):
     """Set the relative tolerence parameter for float comparisons."""
     # NOTE: that this overrides the class value so applies to all
     # instances of the class.
     max_tol = self.__class__.MAX_TOL
     if rtol < 0:
         raise QiskitError("Invalid rtol: must be non-negative.")
     if rtol > max_tol:
         raise QiskitError(
             "Invalid rtol: must be less than {}.".format(max_tol))
     self.__class__.RTOL = rtol
 def add_register(self, *regs):
     """Add registers."""
     for register in regs:
         if register in self.qregs or register in self.cregs:
             raise QiskitError("register name \"%s\" already exists" %
                               register.name)
         if isinstance(register, QuantumRegister):
             self.qregs.append(register)
         elif isinstance(register, ClassicalRegister):
             self.cregs.append(register)
         else:
             raise QiskitError("expected a register")
示例#25
0
    def compose(self, other, qubits=None, front=False):
        """Return the composition channel self∘other.

        Args:
            other (QuantumChannel): a quantum channel subclass.
            qubits (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:
            Kraus: The composition channel as a Kraus object.

        Raises:
            QiskitError: if other cannot be converted to a channel, or
            has incompatible dimensions.
        """
        if qubits is not None:
            # TODO
            raise QiskitError("NOT IMPLEMENTED: subsystem composition.")

        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')

        if front:
            ka_l, ka_r = self._data
            kb_l, kb_r = other._data
            input_dim = other._input_dim
            output_dim = self._output_dim
        else:
            ka_l, ka_r = other._data
            kb_l, kb_r = self._data
            input_dim = self._input_dim
            output_dim = other._output_dim

        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]
        return Kraus((kab_l, kab_r), input_dim, output_dim)
示例#26
0
def _best_subset(backend, n_qubits):
    """Computes the qubit mapping with the best
    connectivity.

    Parameters:
        backend (BaseBackend): A Qiskit backend instance.
        n_qubits (int): Number of subset qubits to consider.

    Returns:
        ndarray: Array of qubits to use for best
                connectivity mapping.

    Raises:
        QiskitError: Wrong number of qubits given.
    """
    if n_qubits == 1:
        return np.array([0])
    elif n_qubits <= 0:
        raise QiskitError('Number of qubits <= 0.')

    device_qubits = backend.configuration().n_qubits
    if n_qubits > device_qubits:
        raise QiskitError('Number of qubits greater than device.')

    cmap = np.asarray(getattr(backend.configuration(), 'coupling_map', None))
    data = np.ones_like(cmap[:, 0])
    sp_cmap = sp.coo_matrix((data, (cmap[:, 0], cmap[:, 1])),
                            shape=(device_qubits, device_qubits)).tocsr()
    best = 0
    best_map = None
    # do bfs with each node as starting point
    for k in range(sp_cmap.shape[0]):
        bfs = cs.breadth_first_order(sp_cmap,
                                     i_start=k,
                                     directed=False,
                                     return_predecessors=False)

        connection_count = 0
        for i in range(n_qubits):
            node_idx = bfs[i]
            for j in range(sp_cmap.indptr[node_idx],
                           sp_cmap.indptr[node_idx + 1]):
                node = sp_cmap.indices[j]
                for counter in range(n_qubits):
                    if node == bfs[counter]:
                        connection_count += 1
                        break

        if connection_count > best:
            best = connection_count
            best_map = bfs[0:n_qubits]
    return best_map
示例#27
0
文件: choi.py 项目: danmills0/qiskit
    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:
            Choi: The composition channel as a Choi object.

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

        # Convert to Choi matrix
        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')

        if front:
            first = np.reshape(other._data, other._bipartite_shape)
            second = np.reshape(self._data, self._bipartite_shape)
            input_dim = other._input_dim
            input_dims = other.input_dims()
            output_dim = self._output_dim
            output_dims = self.output_dims()
        else:
            first = np.reshape(self._data, self._bipartite_shape)
            second = np.reshape(other._data, other._bipartite_shape)
            input_dim = self._input_dim
            input_dims = self.input_dims()
            output_dim = other._output_dim
            output_dims = other.output_dims()

        # Contract Choi matrices for composition
        data = np.reshape(np.einsum('iAjB,AkBl->ikjl', first, second),
                          (input_dim * output_dim, input_dim * output_dim))
        return Choi(data, input_dims, output_dims)
示例#28
0
 def _format_state(self, state):
     """Format input state so it is statevector or density matrix"""
     state = np.array(state)
     shape = state.shape
     ndim = state.ndim
     if ndim > 2:
         raise QiskitError('Input state is not a vector or matrix.')
     # Flatten column-vector to vector
     if ndim == 2:
         if shape[1] != 1 and shape[1] != shape[0]:
             raise QiskitError('Input state is not a vector or matrix.')
         if shape[1] == 1:
             # flatten colum-vector to vector
             state = np.reshape(state, shape[0])
     return state
示例#29
0
    def multiply(self, other):
        """Return the QuantumChannel self + other.

        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")
        # 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
            return Kraus(Choi(self).multiply(other))
        # 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]]
        return Kraus((kraus_l, kraus_r), self._input_dim, self._output_dim)
示例#30
0
    def _einsum_matmul(cls, tensor, mat, indices, shift=0, right_mul=False):
        """Perform a contraction using Numpy.einsum

        Args:
            tensor (np.array): a vector or matrix reshaped to a rank-N tensor.
            mat (np.array): a matrix reshaped to a rank-2M tensor.
            indices (list): tensor indices to contract with mat.
            shift (int): shift for indicies of tensor to contract [Default: 0].
            right_mul (bool): if True right multiply tensor by mat
                              (else left multiply) [Default: False].

        Returns:
            Numpy.ndarray: the matrix multiplied rank-N tensor.

        Raises:
            QiskitError: if mat is not an even rank tensor.
        """
        rank = tensor.ndim
        rank_mat = mat.ndim
        if rank_mat % 2 != 0:
            raise QiskitError(
                "Contracted matrix must have an even number of indices.")
        # Get einsum indices for tensor
        indices_tensor = list(range(rank))
        for j, index in enumerate(indices):
            indices_tensor[index + shift] = rank + j
        # Get einsum indces for mat
        mat_contract = list(reversed(range(rank, rank + len(indices))))
        mat_free = [index + shift for index in reversed(indices)]
        if right_mul:
            indices_mat = mat_contract + mat_free
        else:
            indices_mat = mat_free + mat_contract
        return np.einsum(tensor, indices_tensor, mat, indices_mat)