Ejemplo n.º 1
0
    def __init__(self, instructions: Iterable[Instruction] = []):
        self._moments: OrderedDict[MomentsKey, Instruction] = OrderedDict()
        self._max_times: Dict[Qubit, int] = {}
        self._qubits = QubitSet()
        self._depth = 0

        self.add(instructions)
Ejemplo n.º 2
0
def test_apply_noise_to_moments_initialization_2QubitNoise_2(
    circuit_2qubit, noise_2qubit, noise_1qubit, noise_1qubit_2
):
    circ = apply_noise_to_moments(
        circuit_2qubit,
        [noise_1qubit, noise_2qubit, noise_1qubit_2],
        target_qubits=QubitSet([0, 1]),
        position="initialization",
    )

    expected = (
        Circuit()
        .add_instruction(Instruction(noise_1qubit, 0))
        .add_instruction(Instruction(noise_1qubit, 1))
        .add_instruction(Instruction(noise_2qubit, [0, 1]))
        .add_instruction(Instruction(noise_1qubit_2, 0))
        .add_instruction(Instruction(noise_1qubit_2, 1))
        .add_instruction(Instruction(Gate.X(), 0))
        .add_instruction(Instruction(Gate.Y(), 1))
        .add_instruction(Instruction(Gate.X(), 0))
        .add_instruction(Instruction(Gate.X(), 1))
        .add_instruction(Instruction(Gate.CNot(), [0, 1]))
    )

    assert circ == expected
Ejemplo n.º 3
0
    def __init__(
        self, ascii_symbols: List[str], observable: Observable, target: QubitSetInput = None
    ):
        """
        Args:
            observable (Observable): the observable for the result type
            target (int, Qubit, or iterable of int / Qubit, optional): Target qubits that the
                result type is requested for. Default is `None`, which means the observable must
                only operate on 1 qubit and it will be applied to all qubits in parallel

        Raises:
            ValueError: if target=None and the observable's qubit count is not 1.
                Or, if `target!=None` and the observable's qubit count and the number of target
                qubits are not equal. Or, if `target!=None` and the observable's qubit count and
                the number of `ascii_symbols` are not equal.
        """
        super().__init__(ascii_symbols)
        self._observable = observable
        self._target = QubitSet(target)
        if not self._target:
            if self._observable.qubit_count != 1:
                raise ValueError(
                    f"Observable {self._observable} must only operate on 1 qubit for target=None"
                )
        else:
            if self._observable.qubit_count != len(self._target):
                raise ValueError(
                    f"Observable's qubit count {self._observable.qubit_count} and "
                    f"the size of the target qubit set {self._target} must be equal"
                )
            if self._observable.qubit_count != len(self.ascii_symbols):
                raise ValueError(
                    "Observable's qubit count and the number of ASCII symbols must be equal"
                )
Ejemplo n.º 4
0
def test_apply_noise_to_gates_2QubitNoise_2(
    circuit_3qubit, noise_2qubit, noise_1qubit, noise_1qubit_2
):
    circ = apply_noise_to_gates(
        circuit_3qubit,
        [noise_1qubit, noise_2qubit, noise_1qubit_2],
        target_gates=[Gate.CZ],
        target_qubits=QubitSet([1, 2]),
    )

    expected = (
        Circuit()
        .add_instruction(Instruction(Gate.X(), 0))
        .add_instruction(Instruction(Gate.Y(), 1))
        .add_instruction(Instruction(Gate.CNot(), [0, 1]))
        .add_instruction(Instruction(Gate.Z(), 2))
        .add_instruction(Instruction(Gate.CZ(), [2, 1]))
        .add_instruction(Instruction(noise_1qubit, 1))
        .add_instruction(Instruction(noise_1qubit, 2))
        .add_instruction(Instruction(noise_2qubit, [2, 1]))
        .add_instruction(Instruction(noise_1qubit_2, 1))
        .add_instruction(Instruction(noise_1qubit_2, 2))
        .add_instruction(Instruction(Gate.CNot(), [0, 2]))
        .add_instruction(Instruction(Gate.CZ(), [1, 2]))
        .add_instruction(Instruction(noise_1qubit, 1))
        .add_instruction(Instruction(noise_1qubit, 2))
        .add_instruction(Instruction(noise_2qubit, [1, 2]))
        .add_instruction(Instruction(noise_1qubit_2, 1))
        .add_instruction(Instruction(noise_1qubit_2, 2))
    )

    assert circ == expected
Ejemplo n.º 5
0
    def __init__(self, operator: InstructionOperator, target: QubitSetInput):
        """
        InstructionOperator includes objects of type `Gate` only.

        Args:
            operator (InstructionOperator): Operator for the instruction.
            target (int, Qubit, or iterable of int / Qubit): Target qubits that the operator is
                applied to.

        Raises:
            ValueError: If `operator` is empty or any integer in `target` does not meet the `Qubit`
                or `QubitSet` class requirements.
            TypeError: If a `Qubit` class can't be constructed from `target` due to an incorrect
                `typing`.

        Examples:
            >>> Instruction(Gate.CNot(), [0, 1])
            Instruction('operator': CNOT, 'target': QubitSet(Qubit(0), Qubit(1)))
            >>> instr = Instruction(Gate.CNot()), QubitSet([0, 1])])
            Instruction('operator': CNOT, 'target': QubitSet(Qubit(0), Qubit(1)))
            >>> instr = Instruction(Gate.H(), 0)
            Instruction('operator': H, 'target': QubitSet(Qubit(0),))
            >>> instr = Instruction(Gate.Rx(0.12), 0)
            Instruction('operator': Rx, 'target': QubitSet(Qubit(0),))
        """
        if not operator:
            raise ValueError("Operator cannot be empty")
        self._operator = operator
        self._target = QubitSet(target)
Ejemplo n.º 6
0
    def __init__(self, target: QubitSetInput = None):
        """
        Args:
            target (int, Qubit, or iterable of int / Qubit, optional): The target qubits
                of the reduced density matrix. Default is `None`, and the
                full density matrix is returned.

        Examples:
            >>> ResultType.DensityMatrix(target=[0, 1])
        """
        self._target = QubitSet(target)
        ascii_symbols = ["DensityMatrix"] * len(self._target) if self._target else ["DensityMatrix"]
        super().__init__(ascii_symbols=ascii_symbols)
Ejemplo n.º 7
0
    def __init__(self, target: QubitSetInput = None):
        """
        Args:
            target (int, Qubit, or iterable of int / Qubit, optional): The target qubits that the
                result type is requested for. Default is `None`, which means all qubits for the
                circuit.

        Examples:
            >>> ResultType.Probability(target=[0, 1])
        """
        self._target = QubitSet(target)
        ascii_symbols = ["Probability"] * len(self._target) if self._target else ["Probability"]
        super().__init__(ascii_symbols=ascii_symbols)
Ejemplo n.º 8
0
    def i(target: QubitSetInput) -> Iterable[Instruction]:
        """Registers this function into the circuit class.

        Args:
            target (Qubit, int, or iterable of Qubit / int): Target qubit(s)

        Returns:
            Iterable[Instruction]: `Iterable` of I instructions.

        Examples:
            >>> circ = Circuit().i(0)
            >>> circ = Circuit().i([0, 1, 2])
        """
        return [Instruction(Gate.I(), target=qubit) for qubit in QubitSet(target)]
Ejemplo n.º 9
0
    def phaseshift(target: QubitInput, angle: float) -> Instruction:
        """Registers this function into the circuit class.

        Args:
            target (Qubit or int): Target qubit index.
            angle (float): Angle in radians.

        Returns:
            Instruction: PhaseShift instruction.

        Examples:
            >>> circ = Circuit().phaseshift(0, 0.15)
        """
        return [Instruction(Gate.PhaseShift(angle), target=qubit) for qubit in QubitSet(target)]
    def qubit_intersection(self, qubits: QubitSetInput) -> QubitSetInput:
        """
        Returns subset of passed qubits that match the criteria.

        Args:
            qubits (QubitSetInput): A qubit or set of qubits that may match the criteria.

        Returns:
            QubitSetInput: The subset of passed qubits that match the criteria.
        """
        target_qubit = QubitSet(qubits)
        if self._qubits is None:
            return target_qubit
        return self._qubits.intersection(target_qubit)
Ejemplo n.º 11
0
    def rz(target: QubitInput, angle: float) -> Iterable[Instruction]:
        """Registers this function into the circuit class.

        Args:
            target (Qubit or int): Target qubit index.
            angle (float): Angle in radians.

        Returns:
            Iterable[Instruction]: Rz instruction.

        Examples:
            >>> circ = Circuit().rz(0, 0.15)
        """
        return [
            Instruction(Rz(angle), target=qubit) for qubit in QubitSet(target)
        ]
Ejemplo n.º 12
0
    def phase_damping(target: QubitSetInput, gamma: float) -> Iterable[Instruction]:
        """Registers this function into the circuit class.

        Args:
            target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
            gamma (float): Probability of phase damping.

        Returns:
            Iterable[Instruction]: `Iterable` of PhaseDamping instructions.

        Examples:
            >>> circ = Circuit().phase_damping(0, gamma=0.1)
        """
        return [
            Instruction(Noise.PhaseDamping(gamma=gamma), target=qubit) for qubit in QubitSet(target)
        ]
Ejemplo n.º 13
0
    def bit_flip(target: QubitSetInput, probability: float) -> Iterable[Instruction]:
        """Registers this function into the circuit class.

        Args:
            target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
            probability (float): Probability of bit flipping.

        Returns:
            Iterable[Instruction]: `Iterable` of BitFlip instructions.

        Examples:
            >>> circ = Circuit().bit_flip(0, probability=0.1)
        """
        return [
            Instruction(Noise.BitFlip(probability=probability), target=qubit)
            for qubit in QubitSet(target)
        ]
Ejemplo n.º 14
0
    def _ascii_group_items(
        circuit_qubits: QubitSet,
        items: List[Union[Instruction, ResultType]],
    ) -> List[Tuple[QubitSet, List[Instruction]]]:
        """
        Group instructions in a moment for ASCII diagram

        Args:
            circuit_qubits (QubitSet): set of qubits in circuit
            items (List[Union[Instruction, ResultType]]): list of instructions or result types

        Returns:
            List[(QubitSet, List[Union[Instruction, ResultType]])]: list of grouped instructions
            or result types
        """
        groupings = []
        for item in items:
            # Can only print Gate and Noise operators for instructions at the moment
            if isinstance(item, Instruction) and not isinstance(
                    item.operator, (Gate, Noise, CompilerDirective)):
                continue

            if (isinstance(item, ResultType) and not item.target) or (
                    isinstance(item, Instruction)
                    and isinstance(item.operator, CompilerDirective)):
                qubit_range = circuit_qubits
            else:
                qubit_range = QubitSet(
                    range(min(item.target),
                          max(item.target) + 1))

            found_grouping = False
            for group in groupings:
                qubits_added = group[0]
                instr_group = group[1]
                # Take into account overlapping multi-qubit gates
                if not qubits_added.intersection(set(qubit_range)):
                    instr_group.append(item)
                    qubits_added.update(qubit_range)
                    found_grouping = True
                    break

            if not found_grouping:
                groupings.append((qubit_range, [item]))

        return groupings
Ejemplo n.º 15
0
    def amplitude_damping(target: QubitSetInput, gamma: float) -> Iterable[Instruction]:
        """Registers this function into the circuit class.

        Args:
            target (Qubit, int, or iterable of Qubit / int): Target qubit(s).
            gamma (float): decaying rate of the amplitude damping channel.

        Returns:
            Iterable[Instruction]: `Iterable` of AmplitudeDamping instructions.

        Examples:
            >>> circ = Circuit().amplitude_damping(0, gamma=0.1)
        """
        return [
            Instruction(Noise.AmplitudeDamping(gamma=gamma), target=qubit)
            for qubit in QubitSet(target)
        ]
def test_apply_noise_to_gates_1QubitNoise_2(circuit_2qubit, noise_1qubit):
    circ = apply_noise_to_gates(
        circuit_2qubit,
        [noise_1qubit],
        target_gates=[Gate.X],
        target_qubits=QubitSet(0),
    )

    expected = (Circuit().add_instruction(Instruction(
        Gate.X(),
        0)).add_instruction(Instruction(noise_1qubit, 0)).add_instruction(
            Instruction(Gate.Y(), 1)).add_instruction(Instruction(
                Gate.X(), 0)).add_instruction(Instruction(
                    noise_1qubit, 0)).add_instruction(Instruction(
                        Gate.X(),
                        1)).add_instruction(Instruction(Gate.CNot(), [0, 1])))

    assert circ == expected
def test_apply_noise_to_moments_readout_1QubitNoise_2(circuit_2qubit,
                                                      noise_1qubit):
    circ = apply_noise_to_moments(
        circuit_2qubit,
        [noise_1qubit],
        target_qubits=QubitSet(1),
        position="readout",
    )

    expected = (Circuit().add_instruction(Instruction(
        Gate.X(),
        0)).add_instruction(Instruction(Gate.Y(), 1)).add_instruction(
            Instruction(Gate.X(), 0)).add_instruction(Instruction(
                Gate.X(), 1)).add_instruction(Instruction(
                    Gate.CNot(),
                    [0, 1])).add_instruction(Instruction(noise_1qubit, 1)))

    assert circ == expected
Ejemplo n.º 18
0
    def depolarizing(target: QubitSetInput,
                     probability: float) -> Iterable[Instruction]:
        """Registers this function into the circuit class.

        Args:
            target (QubitSetInput): Target qubit(s)
            probability (float): Probability of depolarizing.

        Returns:
            Iterable[Instruction]: `Iterable` of Depolarizing instructions.

        Examples:
            >>> circ = Circuit().depolarizing(0, probability=0.1)
        """
        return [
            Instruction(Noise.Depolarizing(probability=probability),
                        target=qubit) for qubit in QubitSet(target)
        ]
Ejemplo n.º 19
0
    def pauli_channel(
        target: QubitSetInput, probX: float, probY: float, probZ: float
    ) -> Iterable[Instruction]:
        """Registers this function into the circuit class.

        Args:
            target (Qubit, int, or iterable of Qubit / int): Target qubit(s)
                probability List[float]: Probabilities for the Pauli X, Y and Z noise
                happening in the Kraus channel.

        Returns:
            Iterable[Instruction]: `Iterable` of PauliChannel instructions.

        Examples:
            >>> circ = Circuit().pauli_channel(0,probX=0.1,probY=0.2,probZ=0.3)
        """
        return [
            Instruction(Noise.PauliChannel(probX=probX, probY=probY, probZ=probZ), target=qubit)
            for qubit in QubitSet(target)
        ]
Ejemplo n.º 20
0
def test_apply_noise_to_gates_1QubitNoise_not_dense(circuit_2qubit_not_dense, noise_1qubit):
    circ = apply_noise_to_gates(
        circuit_2qubit_not_dense,
        [noise_1qubit],
        target_qubits=QubitSet([0, 1]),
        target_gates=None,
    )

    expected_moments = Moments()
    expected_moments._add(Instruction(Gate.X(), 0), noise_index=1)
    expected_moments.add_noise(Instruction(noise_1qubit, 0), "gate_noise", 1)
    expected_moments._add(Instruction(Gate.Y(), 1), noise_index=1)
    expected_moments.add_noise(Instruction(noise_1qubit, 1), "gate_noise", 1)
    expected_moments._add(Instruction(Gate.X(), 0), noise_index=1)
    expected_moments.add_noise(Instruction(noise_1qubit, 0), "gate_noise", 1)
    expected_moments._add(Instruction(Gate.CNot(), [0, 1]), noise_index=2)
    expected_moments.add_noise(Instruction(noise_1qubit, 0), "gate_noise", 1)
    expected_moments.add_noise(Instruction(noise_1qubit, 1), "gate_noise", 2)

    assert circ.moments == expected_moments
Ejemplo n.º 21
0
    def __init__(self,
                 operator: InstructionOperator,
                 target: QubitSetInput = None):
        """
        InstructionOperator includes objects of type `Gate` only.

        Args:
            operator (InstructionOperator): Operator for the instruction.
            target (int, Qubit, or iterable of int / Qubit): Target qubits that the operator is
                applied to.

        Raises:
            ValueError: If `operator` is empty or any integer in `target` does not meet the `Qubit`
                or `QubitSet` class requirements. Also, if operator qubit count does not equal
                the size of the target qubit set.
            TypeError: If a `Qubit` class can't be constructed from `target` due to an incorrect
                `typing`.

        Examples:
            >>> Instruction(Gate.CNot(), [0, 1])
            Instruction('operator': CNOT, 'target': QubitSet(Qubit(0), Qubit(1)))
            >>> instr = Instruction(Gate.CNot()), QubitSet([0, 1])])
            Instruction('operator': CNOT, 'target': QubitSet(Qubit(0), Qubit(1)))
            >>> instr = Instruction(Gate.H(), 0)
            Instruction('operator': H, 'target': QubitSet(Qubit(0),))
            >>> instr = Instruction(Gate.Rx(0.12), 0)
            Instruction('operator': Rx, 'target': QubitSet(Qubit(0),))
        """
        if not operator:
            raise ValueError("Operator cannot be empty")
        target_set = QubitSet(target)
        if isinstance(
                operator,
                QuantumOperator) and len(target_set) != operator.qubit_count:
            raise ValueError(
                f"Operator qubit count {operator.qubit_count} must be equal to"
                f" size of target qubit set {target_set}")
        self._operator = operator
        self._target = target_set
Ejemplo n.º 22
0
def check_noise_target_qubits(
    circuit: Circuit, target_qubits: Optional[QubitSetInput] = None
) -> QubitSet:
    """
    Helper function to check whether all the target_qubits are positive integers.
    Args:
        target_qubits (Optional[QubitSetInput] = None): Index or indices of qubit(s).
    Returns:
        target_qubits: QubitSet
    """
    if target_qubits is None:
        target_qubits = circuit.qubits
    else:
        target_qubits = wrap_with_list(target_qubits)
        if not all(isinstance(q, int) for q in target_qubits):
            raise TypeError("target_qubits must be integer(s)")
        if not all(q >= 0 for q in target_qubits):
            raise ValueError("target_qubits must contain only non-negative integers.")

        target_qubits = QubitSet(target_qubits)

    return target_qubits
Ejemplo n.º 23
0
    def generalized_amplitude_damping(
        target: QubitSetInput, gamma: float, probability: float
    ) -> Iterable[Instruction]:
        """Registers this function into the circuit class.

        Args:
            target (Qubit, int, or iterable of Qubit / int): Target qubit(s).
            p(float): Probability of the system being excited by the environment.
            gamma (float): The damping rate of the amplitude damping channel.

        Returns:
            Iterable[Instruction]: `Iterable` of GeneralizedAmplitudeDamping instructions.

        Examples:
            >>> circ = Circuit().generalized_amplitude_damping(0, probability = 0.9, gamma=0.1)
        """
        return [
            Instruction(
                Noise.GeneralizedAmplitudeDamping(gamma=gamma, probability=probability),
                target=qubit,
            )
            for qubit in QubitSet(target)
        ]
Ejemplo n.º 24
0
 def target(self, target: QubitSetInput) -> None:
     self._target = QubitSet(target)
Ejemplo n.º 25
0
    def apply_readout_noise(
        self,
        noise: Union[Type[Noise], Iterable[Type[Noise]]],
        target_qubits: Optional[QubitSetInput] = None,
    ) -> Circuit:
        """Apply `noise` right before measurement in every qubit (default) or target_qubits`.

        Only when `target_qubits` is given can the noise be applied to an empty circuit.

        When `noise.qubit_count` > 1, the number of qubits in target_qubits must be equal
        to `noise.qubit_count`.

        Args:
            noise (Union[Type[Noise], Iterable[Type[Noise]]]): Noise channel(s) to be applied
            to the circuit.
            target_qubits (Union[QubitSetInput, optional]): Index or indices of qubit(s).
                Default=None.

        Returns:
            Circuit: self

        Raises:
            TypeError:
                If `noise` is not Noise type.
                If `target_qubits` has non-integers.
            IndexError:
                If applying noise to an empty circuit.
            ValueError:
                If `target_qubits` has negative integers.
                If `noise.qubit_count` > 1 and the number of qubits in target_qubits is
                not the same as `noise.qubit_count`.

        Examples:
            >>> circ = Circuit().x(0).y(1).z(0).x(1).cnot(0,1)
            >>> print(circ)

            >>> noise = Noise.Depolarizing(probability=0.1)
            >>> circ = Circuit().x(0).y(1).z(0).x(1).cnot(0,1)
            >>> print(circ.apply_initialization_noise(noise))

            >>> circ = Circuit().x(0).y(1).z(0).x(1).cnot(0,1)
            >>> print(circ.apply_initialization_noise(noise, target_qubits = 1))

            >>> circ = Circuit()
            >>> print(circ.apply_initialization_noise(noise, target_qubits = [0, 1]))

        """
        if (len(self.qubits) == 0) and (target_qubits is None):
            raise IndexError(
                "target_qubits must be provided in order to apply the readout noise \
to an empty circuit.")

        if target_qubits is None:
            target_qubits = self.qubits
        else:
            if not isinstance(target_qubits, list):
                target_qubits = [target_qubits]
            if not all(isinstance(q, int) for q in target_qubits):
                raise TypeError("target_qubits must be integer(s)")
            if not all(q >= 0 for q in target_qubits):
                raise ValueError(
                    "target_qubits must contain only non-negative integers.")
            target_qubits = QubitSet(target_qubits)

        # make noise a list
        noise = wrap_with_list(noise)
        for noise_channel in noise:
            if not isinstance(noise_channel, Noise):
                raise TypeError("Noise must be an instance of the Noise class")
            if noise_channel.qubit_count > 1 and noise_channel.qubit_count != len(
                    target_qubits):
                raise ValueError(
                    "target_qubits needs to be provided for this multi-qubit noise channel, and \
the number of qubits in target_qubits must be the same as defined by the multi-qubit noise channel."
                )

        return apply_noise_to_moments(self, noise, target_qubits, "readout")
Ejemplo n.º 26
0
 def qubits(self) -> QubitSet:
     """QubitSet: Get a copy of the qubits for this circuit."""
     return QubitSet(self._moments.qubits.union(self._qubit_observable_set))
Ejemplo n.º 27
0
 def qubits(self) -> QubitSet:
     """QubitSet: Get a copy of the qubits for this circuit."""
     return QubitSet(self._moments.qubits)
Ejemplo n.º 28
0
 def target(self, target: QubitSetInput) -> None:
     """Sets the target.
     Args:
         target (QubitSetInput): The new target.
     """
     self._target = QubitSet(target)