예제 #1
0
    def test_expected_tape(self):
        """Tests if QuantumPhaseEstimation populates the tape as expected for a fixed example"""

        m = qml.RX(0.3, wires=0).matrix

        op = qml.QuantumPhaseEstimation(m,
                                        target_wires=[0],
                                        estimation_wires=[1, 2])
        tape = op.expand()

        with qml.tape.QuantumTape() as tape2:
            qml.Hadamard(1),
            qml.ControlledQubitUnitary(m @ m, control_wires=[1], wires=[0]),
            qml.Hadamard(2),
            qml.ControlledQubitUnitary(m, control_wires=[2], wires=[0]),
            qml.QFT(wires=[1, 2]).inv()

        assert len(tape2.queue) == len(tape.queue)
        assert all([
            op1.name == op2.name for op1, op2 in zip(tape.queue, tape2.queue)
        ])
        assert all([
            op1.wires == op2.wires for op1, op2 in zip(tape.queue, tape2.queue)
        ])
        assert np.allclose(tape.queue[1].matrix, tape2.queue[1].matrix)
        assert np.allclose(tape.queue[3].matrix, tape2.queue[3].matrix)
예제 #2
0
 def test_id(self):
     """Tests that the id attribute can be set."""
     template = qml.QuantumPhaseEstimation(np.eye(2),
                                           target_wires=[0, 1],
                                           estimation_wires=[2, 3],
                                           id="a")
     assert template.id == "a"
예제 #3
0
    def test_same_wires(self):
        """Tests if a QuantumFunctionError is raised if target_wires and estimation_wires contain a
        common element"""

        with pytest.raises(qml.QuantumFunctionError,
                           match="The target wires and estimation wires"):
            qml.QuantumPhaseEstimation(np.eye(2),
                                       target_wires=[0, 1],
                                       estimation_wires=[1, 2])
예제 #4
0
    def test_phase_estimated_two_qubit(self):
        """Tests that the QPE circuit can correctly estimate the phase of a random two-qubit
        unitary."""

        unitary = unitary_group.rvs(4, random_state=1967)
        eigvals, eigvecs = np.linalg.eig(unitary)

        state = eigvecs[:, 0]
        eigval = eigvals[0]
        phase = np.real_if_close(np.log(eigval) / (2 * np.pi * 1j))

        estimates = []
        wire_range = range(3, 11)

        for wires in wire_range:
            dev = qml.device("default.qubit", wires=wires)

            target_wires = [0, 1]
            estimation_wires = range(2, wires)

            with qml.tape.QuantumTape() as tape:
                # We want to prepare an eigenstate of RX, in this case |+>
                qml.QubitStateVector(state, wires=target_wires)

                qml.QuantumPhaseEstimation(unitary,
                                           target_wires=target_wires,
                                           estimation_wires=estimation_wires)
                qml.probs(estimation_wires)

            tape = tape.expand(depth=2,
                               stop_at=lambda obj: obj.name in dev.operations)
            res = tape.execute(dev).flatten()

            if phase < 0:
                estimate = np.argmax(res) / 2**(wires - 2) - 1
            else:
                estimate = np.argmax(res) / 2**(wires - 2)
            estimates.append(estimate)

        # Check that the error is monotonically decreasing
        for i in range(len(estimates) - 1):
            err1 = np.abs(estimates[i] - phase)
            err2 = np.abs(estimates[i + 1] - phase)
            assert err1 >= err2

        # This is quite a large error, but we'd need to push the qubit number up more to get it
        # lower
        assert np.allclose(estimates[-1], phase, rtol=1e-2)
예제 #5
0
        def qpe_circuit():

            qml.Hadamard(wires=0)
            qml.PauliX(wires=1)
            qml.QuantumPhaseEstimation(
                qml.PauliX.matrix,
                target_wires=[0],
                estimation_wires=[1, 2],
            )

            qml.adjoint(qml.QuantumPhaseEstimation)(
                qml.PauliX.matrix,
                target_wires=[0],
                estimation_wires=[1, 2],
            )
            qml.Hadamard(wires=0)
            qml.PauliX(wires=1)

            return qml.state()
예제 #6
0
    def test_expected_circuit(self):
        """Test if the circuit applied when using the QMC template is the same as the expected
        circuit for a fixed example"""
        p = np.ones(4) / 4
        target_wires, estimation_wires = Wires(range(3)), Wires(range(3, 5))

        op = QuantumMonteCarlo(p, self.func, target_wires, estimation_wires)
        tape = op.expand()

        # Do expansion in two steps to avoid also decomposing the first QubitUnitary
        queue_before_qpe = tape.operations[:2]

        # 2-qubit decomposition has 10 operations, and after is a 3-qubit gate so start at 11
        queue_after_qpe = tape.expand().operations[11:]

        A = probs_to_unitary(p)
        R = func_to_unitary(self.func, 4)

        assert len(queue_before_qpe) == 2
        assert queue_before_qpe[0].name == "QubitUnitary"
        assert queue_before_qpe[1].name == "QubitUnitary"
        assert np.allclose(queue_before_qpe[0].matrix, A)
        assert np.allclose(queue_before_qpe[1].matrix, R)
        assert queue_before_qpe[0].wires == target_wires[:-1]
        assert queue_before_qpe[1].wires == target_wires

        Q = make_Q(A, R)

        with qml.tape.QuantumTape() as qpe_tape:
            qml.QuantumPhaseEstimation(Q, target_wires, estimation_wires)

        qpe_tape = qpe_tape.expand()

        assert len(queue_after_qpe) == len(qpe_tape.operations)
        assert all(o1.name == o2.name
                   for o1, o2 in zip(queue_after_qpe, qpe_tape.operations))
        assert all(
            np.allclose(o1.matrix, o2.matrix)
            for o1, o2 in zip(queue_after_qpe, qpe_tape.operations))
        assert all(o1.wires == o2.wires
                   for o1, o2 in zip(queue_after_qpe, qpe_tape.operations))
예제 #7
0
    def test_phase_estimated(self, phase):
        """Tests that the QPE circuit can correctly estimate the phase of a simple RX rotation."""
        estimates = []
        wire_range = range(2, 10)

        for wires in wire_range:
            dev = qml.device("default.qubit", wires=wires)
            m = qml.RX(phase, wires=0).matrix
            target_wires = [0]
            estimation_wires = range(1, wires)

            with qml.tape.QuantumTape() as tape:
                # We want to prepare an eigenstate of RX, in this case |+>
                qml.Hadamard(wires=target_wires)

                qml.QuantumPhaseEstimation(m,
                                           target_wires=target_wires,
                                           estimation_wires=estimation_wires)
                qml.probs(estimation_wires)

            tape = tape.expand(depth=2,
                               stop_at=lambda obj: obj.name in dev.operations)

            res = tape.execute(dev).flatten()
            initial_estimate = np.argmax(res) / 2**(wires - 1)

            # We need to rescale because RX is exp(- i theta X / 2) and we expect a unitary of the
            # form exp(2 pi i theta X)
            rescaled_estimate = (1 - initial_estimate) * np.pi * 4
            estimates.append(rescaled_estimate)

        # Check that the error is monotonically decreasing
        for i in range(len(estimates) - 1):
            err1 = np.abs(estimates[i] - phase)
            err2 = np.abs(estimates[i + 1] - phase)
            assert err1 >= err2

        # This is quite a large error, but we'd need to push the qubit number up more to get it
        # lower
        assert np.allclose(estimates[-1], phase, rtol=1e-2)
예제 #8
0
    def test_nested_tapes(self):

        with qml.tape.QuantumTape() as tape:
            with qml.tape.QuantumTape():
                qml.PauliX(0)
                qml.CNOT(wires=[0, 2])
                with qml.tape.QuantumTape():
                    qml.QuantumPhaseEstimation(
                        qml.PauliY.matrix, target_wires=[1], estimation_wires=[2]
                    )
                    qml.CNOT(wires=[1, 2])
            qml.Hadamard(1)
            with qml.tape.QuantumTape():
                qml.SWAP(wires=[0, 1])
            qml.state()

        expected = (
            " 0: ──╭QuantumTape:T0─────╭QuantumTape:T1──╭┤ State \n"
            + " 1: ──├QuantumTape:T0──H──╰QuantumTape:T1──├┤ State \n"
            + " 2: ──╰QuantumTape:T0──────────────────────╰┤ State \n"
            + "T0 =\n"
            + " 0: ──X──╭C───────────────────┤  \n"
            + " 2: ─────╰X──╭QuantumTape:T2──┤  \n"
            + " 1: ─────────╰QuantumTape:T2──┤  \n"
            + "T2 =\n"
            + " 1: ──╭QuantumPhaseEstimation(M0)──╭C──┤  \n"
            + " 2: ──╰QuantumPhaseEstimation(M0)──╰X──┤  \n"
            + "M0 =\n"
            + "[[ 0.+0.j -0.-1.j]\n"
            + " [ 0.+1.j  0.+0.j]]\n"
            + "\n"
            + "\n"
            + "T1 =\n"
            + " 0: ──╭SWAP──┤  \n"
            + " 1: ──╰SWAP──┤  \n"
            + "\n"
        )

        assert tape.draw(wire_order=qml.wires.Wires([0, 1, 2])) == expected