Example #1
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
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
Example #3
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
    def apply_gate_noise(
        self,
        noise: Union[Type[Noise], Iterable[Type[Noise]]],
        target_gates: Optional[Union[Type[Gate], Iterable[Type[Gate]]]] = None,
        target_unitary: np.ndarray = None,
        target_qubits: Optional[QubitSetInput] = None,
    ) -> Circuit:
        """Apply `noise` to the circuit according to `target_gates`, `target_unitary` and
        `target_qubits`.

        For any parameter that is None, that specification is ignored (e.g. if `target_gates`
        is None then the noise is applied after every gate in `target_qubits`).
        If `target_gates` and `target_qubits` are both None, then `noise` is
        applied to every qubit after every gate.

        Noise is either applied to `target_gates` or `target_unitary`, so they cannot be
        provided at the same time.

        When `noise.qubit_count` == 1, ie. `noise` is single-qubit, `noise` is added to all
        qubits in `target_gates` or `target_unitary` (or to all qubits in `target_qubits`
        if `target_gates` is None).

        When `noise.qubit_count` > 1 and `target_gates` is not None, the number of qubits of
        any gate in `target_gates` must be the same as `noise.qubit_count`.

        When `noise.qubit_count` > 1, `target_gates` and `target_unitary` is None, noise is
        only applied to gates with the same qubit_count in target_qubits.

        Args:
            noise (Union[Type[Noise], Iterable[Type[Noise]]]): Noise channel(s) to be applied
            to the circuit.
            target_gates (Union[Type[Gate], Iterable[Type[Gate]], optional]): Gate class or
                List of Gate classes which `noise` is applied to. Default=None.
            target_unitary (np.ndarray): matrix of the target unitary gates. Default=None.
            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_gates` is not a Gate type, Iterable[Gate].
                If `target_unitary` is not a np.ndarray type.
                If `target_qubits` has non-integers or negative integers.
            IndexError:
                If applying noise to an empty circuit.
                If `target_qubits` is out of range of circuit.qubits.
            ValueError:
                If both `target_gates` and `target_unitary` are provided.
                If `target_unitary` is not a unitary.
                If `noise` is multi-qubit noise and `target_gates` contain gates
                with the number of qubits not the same as `noise.qubit_count`.
            Warning:
                If `noise` is multi-qubit noise while there is no gate with the same
                number of qubits in `target_qubits` or in the whole circuit when
                `target_qubits` is not given.
                If no `target_gates` or  `target_unitary` exist in `target_qubits` or
                in the whole circuit when they are not given.

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

            q0 : -X-Z-C-
                      |
            q1 : -Y-X-X-

            T  : |0|1|2|

            >>> noise = Noise.Depolarizing(probability=0.1)
            >>> circ = Circuit().x(0).y(1).z(0).x(1).cnot(0,1)
            >>> print(circ.apply_gate_noise(noise, target_gates = Gate.X))
            T  : |     0     |     1     |2|

            q0 : -X-DEPO(0.1)-Z-----------C-
                                          |
            q1 : -Y-----------X-DEPO(0.1)-X-

            T  : |     0     |     1     |2|

            >>> circ = Circuit().x(0).y(1).z(0).x(1).cnot(0,1)
            >>> print(circ.apply_gate_noise(noise, target_qubits = 1))
            T  : |     0     |     1     |     2     |

            q0 : -X-----------Z-----------C-----------
                                          |
            q1 : -Y-DEPO(0.1)-X-DEPO(0.1)-X-DEPO(0.1)-

            T  : |     0     |     1     |     2     |

            >>> circ = Circuit().x(0).y(1).z(0).x(1).cnot(0,1)
            >>> print(circ.apply_gate_noise(noise,
            ...                             target_gates = [Gate.X,Gate.Y],
            ...                             target_qubits = [0,1])
            ... )
            T  : |     0     |     1     |2|

            q0 : -X-DEPO(0.1)-Z-----------C-
                                          |
            q1 : -Y-DEPO(0.1)-X-DEPO(0.1)-X-

            T  : |     0     |     1     |2|

        """
        # check whether gate noise is applied to an empty circuit
        if not self.qubits:
            raise IndexError(
                "Gate noise cannot be applied to an empty circuit.")

        # check if target_gates and target_unitary are both given
        if (target_unitary is not None) and (target_gates is not None):
            raise ValueError(
                "target_unitary and target_gates cannot be input at the same time."
            )

        # check target_qubits
        target_qubits = check_noise_target_qubits(self, target_qubits)
        if not all(qubit in self.qubits for qubit in target_qubits):
            raise IndexError(
                "target_qubits must be within the range of the current circuit."
            )

        # make noise a list
        noise = wrap_with_list(noise)

        # make target_gates a list
        if target_gates is not None:
            target_gates = wrap_with_list(target_gates)
            # remove duplicate items
            target_gates = list(dict.fromkeys(target_gates))

        for noise_channel in noise:
            if not isinstance(noise_channel, Noise):
                raise TypeError("Noise must be an instance of the Noise class")
                # check whether target_gates is valid
            if target_gates is not None:
                check_noise_target_gates(noise_channel, target_gates)
            if target_unitary is not None:
                check_noise_target_unitary(noise_channel, target_unitary)

        if target_unitary is not None:
            return apply_noise_to_gates(self, noise, target_unitary,
                                        target_qubits)
        else:
            return apply_noise_to_gates(self, noise, target_gates,
                                        target_qubits)