Пример #1
0
    def test_var_hermitian(self, tol, qvm):
        """Tests for variance calculation using an arbitrary Hermitian observable"""
        dev = plf.WavefunctionDevice(wires=2)

        phi = 0.543
        theta = 0.6543

        # test correct variance for <H> of a rotated state
        H = np.array([[4, -1 + 6j], [-1 - 6j, 2]])

        with qml.tape.QuantumTape() as tape:
            qml.RX(phi, wires=[0])
            qml.RY(theta, wires=[0])
            O = qml.var(qml.Hermitian(H, wires=[0]))

        # test correct variance for <Z> of a rotated state
        dev.apply(tape.operations, rotations=tape.diagonalizing_gates)

        var = dev.var(O)
        expected = 0.5 * (2 * np.sin(2 * theta) * np.cos(phi)**2 +
                          24 * np.sin(phi) * np.cos(phi) *
                          (np.sin(theta) - np.cos(theta)) +
                          35 * np.cos(2 * phi) + 39)

        self.assertAlmostEqual(var, expected, delta=tol)
Пример #2
0
    def test_apply(self, op, apply_unitary, tol):
        """Test the application of gates to a state"""
        dev = plf.WavefunctionDevice(wires=3)

        obs = qml.expval(qml.PauliZ(0))

        if op.name == "QubitUnitary":
            state = apply_unitary(U, 3)
        elif op.name == "BasisState":
            state = np.array([0, 0, 0, 0, 0, 0, 0, 1])
        elif op.name == "CPHASE":
            state = apply_unitary(test_operation_map["CPHASE"](0.432, 2), 3)
        elif op.name == "ISWAP":
            state = apply_unitary(test_operation_map["ISWAP"], 3)
        elif op.name == "PSWAP":
            state = apply_unitary(test_operation_map["PSWAP"](0.432), 3)
        else:
            state = apply_unitary(op.matrix, 3)

        with qml.tape.QuantumTape() as tape:
            qml.apply(op)
            obs

        dev.apply(tape.operations, rotations=tape.diagonalizing_gates)

        # verify the device is now in the expected state
        self.assertAllAlmostEqual(dev._state, state, delta=tol)
Пример #3
0
    def test_sample_values_hermitian(self, tol):
        """Tests if the samples of a Hermitian observable returned by sample have
        the correct values
        """
        dev = plf.WavefunctionDevice(wires=1, shots=1_000_000)
        theta = 0.543

        A = np.array([[1, 2j], [-2j, 0]])

        with qml.tape.QuantumTape() as tape:
            qml.RX(theta, wires=[0])
            O = qml.sample(qml.Hermitian(A, wires=[0]))

        # test correct variance for <Z> of a rotated state
        dev.apply(tape.operations, rotations=tape.diagonalizing_gates)

        dev._samples = dev.generate_samples()

        s1 = dev.sample(O.obs)

        # s1 should only contain the eigenvalues of
        # the hermitian matrix
        eigvals = np.linalg.eigvalsh(A)
        assert np.allclose(sorted(list(set(s1))), sorted(eigvals), atol=tol, rtol=0)

        # the analytic mean is 2*sin(theta)+0.5*cos(theta)+0.5
        assert np.allclose(
            np.mean(s1), 2 * np.sin(theta) + 0.5 * np.cos(theta) + 0.5, atol=0.1, rtol=0
        )

        # the analytic variance is 0.25*(sin(theta)-4*cos(theta))^2
        assert np.allclose(
            np.var(s1), 0.25 * (np.sin(theta) - 4 * np.cos(theta)) ** 2, atol=0.1, rtol=0
        )
    def test_expand_one(self, tol):
        """Test that a 1 qubit gate correctly expands to 3 qubits."""
        dev = plf.WavefunctionDevice(wires=3)

        # test applied to wire 0
        res = dev.expand_one(U, [0])
        expected = np.kron(np.kron(U, I), I)
        self.assertAllAlmostEqual(res, expected, delta=tol)

        # test applied to wire 1
        res = dev.expand_one(U, [1])
        expected = np.kron(np.kron(I, U), I)
        self.assertAllAlmostEqual(res, expected, delta=tol)

        # test applied to wire 2
        res = dev.expand_one(U, [2])
        expected = np.kron(np.kron(I, I), U)
        self.assertAllAlmostEqual(res, expected, delta=tol)

        # test exception raised if U is not 2x2 matrix
        with pytest.raises(ValueError, message="2x2 matrix required"):
            dev.expand_one(U2, [0])

        # test exception raised if more than one subsystem provided
        with pytest.raises(ValueError, message="One target subsystem required"):
            dev.expand_one(U, [0, 1])
Пример #5
0
    def test_var_hermitian(self, tol, qvm):
        """Tests for variance calculation using an arbitrary Hermitian observable"""
        dev = plf.WavefunctionDevice(wires=2)

        phi = 0.543
        theta = 0.6543

        # test correct variance for <H> of a rotated state
        H = np.array([[4, -1 + 6j], [-1 - 6j, 2]])

        circuit_operations = [qml.RX(phi, wires=[0]), qml.RY(theta, wires=[0])]

        O = qml.var(qml.Hermitian(H, wires=[0]))

        observables = [O]
        circuit_graph = qml.CircuitGraph(circuit_operations + observables, {},
                                         dev.wires)

        dev.apply(circuit_graph.operations,
                  rotations=circuit_graph.diagonalizing_gates)

        var = dev.var(qml.Hermitian(H, wires=[0]))
        expected = 0.5 * (2 * np.sin(2 * theta) * np.cos(phi)**2 +
                          24 * np.sin(phi) * np.cos(phi) *
                          (np.sin(theta) - np.cos(theta)) +
                          35 * np.cos(2 * phi) + 39)

        self.assertAlmostEqual(var, expected, delta=tol)
Пример #6
0
    def test_apply(self, gate, apply_unitary, tol, qvm, compiler):
        """Test the application of gates to a state"""
        dev = plf.WavefunctionDevice(wires=3)

        try:
            # get the equivalent pennylane operation class
            op = getattr(qml.ops, gate)
        except AttributeError:
            # get the equivalent pennylane-forest operation class
            op = getattr(plf, gate)

        # the list of wires to apply the operation to
        w = list(range(op.num_wires))

        obs = qml.expval(qml.PauliZ(0))
        if op.par_domain == "A":
            # the parameter is an array
            if gate == "QubitUnitary":
                p = np.array(U)
                w = [0]
                state = apply_unitary(U, 3)
            elif gate == "BasisState":
                p = np.array([1, 1, 1])
                state = np.array([0, 0, 0, 0, 0, 0, 0, 1])
                w = list(range(dev.num_wires))

            with qml.tape.QuantumTape() as tape:
                op(p, wires=w)
                obs
        else:
            p = [0.432_423, 2, 0.324][:op.num_params]
            fn = test_operation_map[gate]
            if callable(fn):
                # if the default.qubit is an operation accepting parameters,
                # initialise it using the parameters generated above.
                O = fn(*p)
            else:
                # otherwise, the operation is simply an array.
                O = fn

            # calculate the expected output
            state = apply_unitary(O, 3)
            # Creating the tape using a parametrized operation
            if p:
                with qml.tape.QuantumTape() as tape:
                    op(*p, wires=w)
                    obs

            # Creating the tape using an operation that take no parameters
            else:
                with qml.tape.QuantumTape() as tape:
                    op(wires=w)
                    obs

        dev.apply(tape.operations, rotations=tape.diagonalizing_gates)

        res = dev.expval(obs)

        # verify the device is now in the expected state
        self.assertAllAlmostEqual(dev._state, state, delta=tol)
    def test_expand_state(self):
        """Test that a multi-qubit state is correctly expanded for a N-qubit device"""
        dev = plf.WavefunctionDevice(wires=3)

        # expand a two qubit state to the 3 qubit device
        dev.state = np.array([0, 1, 1, 0])/np.sqrt(2)
        dev.active_wires = {0, 2}
        dev.expand_state()
        self.assertAllEqual(dev.state, np.array([0, 1, 0, 0, 1, 0, 0, 0])/np.sqrt(2))

        # expand a three qubit state to the 3 qubit device
        dev.state = np.array([0, 1, 1, 0, 0, 1, 1, 0])/2
        dev.active_wires = {0, 1, 2}
        dev.expand_state()
        self.assertAllEqual(dev.state, np.array([0, 1, 1, 0, 0, 1, 1, 0])/2)
Пример #8
0
    def test_sample_values_hermitian_multi_qubit(self, tol):
        """Tests if the samples of a multi-qubit Hermitian observable returned by sample have
        the correct values
        """
        shots = 1_000_000
        dev = plf.WavefunctionDevice(wires=2, shots=shots)
        theta = 0.543

        A = np.array([
            [1, 2j, 1 - 2j, 0.5j],
            [-2j, 0, 3 + 4j, 1],
            [1 + 2j, 3 - 4j, 0.75, 1.5 - 2j],
            [-0.5j, 1, 1.5 + 2j, -1],
        ])

        circuit_operations = [
            qml.RX(theta, wires=[0]),
            qml.RY(2 * theta, wires=[1]),
            qml.CNOT(wires=[0, 1]),
        ]

        O = qml.sample(qml.Hermitian(A, wires=[0, 1]))

        observables = [O]
        circuit_graph = qml.CircuitGraph(circuit_operations + observables, {},
                                         dev.wires)

        dev.apply(circuit_graph.operations,
                  rotations=circuit_graph.diagonalizing_gates)

        dev._samples = dev.generate_samples()

        s1 = dev.sample(O)

        # s1 should only contain the eigenvalues of
        # the hermitian matrix
        eigvals = np.linalg.eigvalsh(A)
        assert np.allclose(sorted(list(set(s1))),
                           sorted(eigvals),
                           atol=tol,
                           rtol=0)

        # make sure the mean matches the analytic mean
        expected = (88 * np.sin(theta) + 24 * np.sin(2 * theta) -
                    40 * np.sin(3 * theta) + 5 * np.cos(theta) -
                    6 * np.cos(2 * theta) + 27 * np.cos(3 * theta) + 6) / 32
        assert np.allclose(np.mean(s1), expected, atol=0.1, rtol=0)
    def test_var(self, tol):
        """Tests for variance calculation"""
        dev = plf.WavefunctionDevice(wires=2)
        dev.active_wires = {0}

        phi = 0.543
        theta = 0.6543

        # test correct variance for <Z> of a rotated state
        dev.apply("RX", wires=[0], par=[phi])
        dev.apply("RY", wires=[0], par=[theta])
        dev.pre_measure()

        var = dev.var("PauliZ", [0], [])
        expected = 0.25 * (3 - np.cos(2 * theta) -
                           2 * np.cos(theta)**2 * np.cos(2 * phi))

        self.assertAlmostEqual(var, expected, delta=tol)
    def test_expand_one(self, tol):
        """Test that a 1 qubit gate correctly expands to 3 qubits."""
        dev = plf.WavefunctionDevice(wires=3)

        # test applied to wire 0
        res = dev.expand(U, [0])
        expected = np.kron(np.kron(U, I), I)
        self.assertAllAlmostEqual(res, expected, delta=tol)

        # test applied to wire 1
        res = dev.expand(U, [1])
        expected = np.kron(np.kron(I, U), I)
        self.assertAllAlmostEqual(res, expected, delta=tol)

        # test applied to wire 2
        res = dev.expand(U, [2])
        expected = np.kron(np.kron(I, I), U)
        self.assertAllAlmostEqual(res, expected, delta=tol)
    def test_apply(self, gate, apply_unitary, tol, qvm, compiler):
        """Test the application of gates to a state"""
        dev = plf.WavefunctionDevice(wires=3)

        try:
            # get the equivalent pennylane operation class
            op = getattr(qml.ops, gate)
        except AttributeError:
            # get the equivalent pennylane-forest operation class
            op = getattr(plf, gate)

        # the list of wires to apply the operation to
        w = list(range(op.num_wires))

        if op.par_domain == 'A':
            # the parameter is an array
            if gate == 'QubitUnitary':
                p = [U]
                w = [0]
                expected_out = apply_unitary(U, 3)
            elif gate == 'BasisState':
                p = [np.array([1, 1, 1])]
                expected_out = np.array([0, 0, 0, 0, 0, 0, 0, 1])
        else:
            p = [0.432423, 2, 0.324][:op.num_params]
            fn = test_operation_map[gate]

            if callable(fn):
                # if the default.qubit is an operation accepting parameters,
                # initialise it using the parameters generated above.
                O = fn(*p)
            else:
                # otherwise, the operation is simply an array.
                O = fn

            # calculate the expected output
            expected_out = apply_unitary(O, 3)

        dev.apply(gate, wires=w, par=p)
        dev.pre_expval()

        # verify the device is now in the expected state
        self.assertAllAlmostEqual(dev.state, expected_out, delta=tol)
Пример #12
0
    def test_var(self, tol, qvm):
        """Tests for variance calculation"""
        dev = plf.WavefunctionDevice(wires=2)

        phi = 0.543
        theta = 0.6543

        with qml.tape.QuantumTape() as tape:
            qml.RX(phi, wires=[0])
            qml.RY(theta, wires=[0])
            O = qml.var(qml.PauliZ(wires=[0]))

        # test correct variance for <Z> of a rotated state
        dev.apply(tape.operations, rotations=tape.diagonalizing_gates)

        var = dev.var(O)
        expected = 0.25 * (3 - np.cos(2 * theta) - 2 * np.cos(theta) ** 2 * np.cos(2 * phi))

        self.assertAlmostEqual(var, expected, delta=tol)
    def test_sample_values_hermitian(self, tol):
        """Tests if the samples of a Hermitian observable returned by sample have
        the correct values
        """
        dev = plf.WavefunctionDevice(wires=1, shots=1000_000)
        theta = 0.543

        A = np.array([[1, 2j], [-2j, 0]])

        circuit_operations = [qml.RX(theta, wires=[0])]

        O = qml.sample(qml.Hermitian(A, wires=[0]))

        observables = [O]
        circuit_graph = qml.CircuitGraph(circuit_operations + observables, {})

        dev.apply(circuit_graph.operations,
                  rotations=circuit_graph.diagonalizing_gates)

        dev.generate_samples()

        s1 = dev.sample(O)

        # s1 should only contain the eigenvalues of
        # the hermitian matrix
        eigvals = np.linalg.eigvalsh(A)
        assert np.allclose(sorted(list(set(s1))),
                           sorted(eigvals),
                           atol=tol,
                           rtol=0)

        # the analytic mean is 2*sin(theta)+0.5*cos(theta)+0.5
        assert np.allclose(np.mean(s1),
                           2 * np.sin(theta) + 0.5 * np.cos(theta) + 0.5,
                           atol=0.1,
                           rtol=0)

        # the analytic variance is 0.25*(sin(theta)-4*cos(theta))^2
        assert np.allclose(np.var(s1),
                           0.25 * (np.sin(theta) - 4 * np.cos(theta))**2,
                           atol=0.1,
                           rtol=0)
Пример #14
0
    def test_sample_values(self, tol):
        """Tests if the samples returned by sample have
        the correct values
        """
        dev = plf.WavefunctionDevice(wires=1, shots=10)
        theta = 1.5708

        circuit_operations = [qml.RX(theta, wires=[0])]

        O = qml.sample(qml.PauliZ(0))

        observables = [O]
        circuit_graph = qml.CircuitGraph(circuit_operations + observables, {})

        dev.apply(circuit_graph.operations,
                  rotations=circuit_graph.diagonalizing_gates)
        dev._samples = dev.generate_samples()
        s1 = dev.sample(O)

        # s1 should only contain 1 and -1
        self.assertAllAlmostEqual(s1**2, 1, delta=tol)
    def test_var_hermitian(self, tol):
        """Tests for variance calculation using an arbitrary Hermitian observable"""
        dev = plf.WavefunctionDevice(wires=2)
        dev.active_wires = {0}

        phi = 0.543
        theta = 0.6543

        # test correct variance for <H> of a rotated state
        H = np.array([[4, -1 + 6j], [-1 - 6j, 2]])
        dev.apply("RX", wires=[0], par=[phi])
        dev.apply("RY", wires=[0], par=[theta])
        dev.pre_measure()

        var = dev.var("Hermitian", [0], [H])
        expected = 0.5 * (2 * np.sin(2 * theta) * np.cos(phi)**2 +
                          24 * np.sin(phi) * np.cos(phi) *
                          (np.sin(theta) - np.cos(theta)) +
                          35 * np.cos(2 * phi) + 39)

        self.assertAlmostEqual(var, expected, delta=tol)
    def test_expand_three(self, tol):
        """Test that a 3 qubit gate correctly expands to 4 qubits."""
        dev = plf.WavefunctionDevice(wires=4)

        # test applied to wire 0,1,2
        res = dev.expand(U_toffoli, [0, 1, 2])
        expected = np.kron(U_toffoli, I)
        self.assertAllAlmostEqual(res, expected, delta=tol)

        # test applied to wire 1,2,3
        res = dev.expand(U_toffoli, [1, 2, 3])
        expected = np.kron(I, U_toffoli)
        self.assertAllAlmostEqual(res, expected, delta=tol)

        # test applied to wire 0,2,3
        res = dev.expand(U_toffoli, [0, 2, 3])
        expected = (np.kron(SWAP, np.kron(I, I)) @ np.kron(I, U_toffoli)
                    @ np.kron(SWAP, np.kron(I, I)))
        self.assertAllAlmostEqual(res, expected, delta=tol)

        # test applied to wire 0,1,3
        res = dev.expand(U_toffoli, [0, 1, 3])
        expected = (np.kron(np.kron(I, I), SWAP) @ np.kron(U_toffoli, I)
                    @ np.kron(np.kron(I, I), SWAP))
        self.assertAllAlmostEqual(res, expected, delta=tol)

        # test applied to wire 3, 1, 2
        res = dev.expand(U_toffoli, [3, 1, 2])
        # change the control qubit on the Toffoli gate
        rows = np.array([0, 4, 1, 5, 2, 6, 3, 7])
        expected = np.kron(I, U_toffoli[:, rows][rows])
        self.assertAllAlmostEqual(res, expected, delta=tol)

        # test applied to wire 3, 0, 2
        res = dev.expand(U_toffoli, [3, 0, 2])
        # change the control qubit on the Toffoli gate
        rows = np.array([0, 4, 1, 5, 2, 6, 3, 7])
        expected = (np.kron(SWAP, np.kron(I, I)) @ np.kron(
            I, U_toffoli[:, rows][rows]) @ np.kron(SWAP, np.kron(I, I)))
        self.assertAllAlmostEqual(res, expected, delta=tol)
    def test_ev(self, ev, tol):
        """Test that expectation values are calculated correctly"""
        dev = plf.WavefunctionDevice(wires=2)

        # start in the following initial state
        dev.state = np.array([1, 0, 1, 1])/np.sqrt(3)
        dev.active_wires = {0, 1}

        # get the equivalent pennylane operation class
        op = getattr(qml.expval.qubit, ev)

        O = test_operation_map[ev]

        # calculate the expected output
        if op.num_wires == 1 or op.num_wires == 0:
            expected_out = dev.state.conj() @ np.kron(O, I) @ dev.state
        elif op.num_wires == 2:
            expected_out = dev.state.conj() @ O @ dev.state

        res = dev.ev(O, wires=[0])

        # verify the device is now in the expected state
        self.assertAllAlmostEqual(res, expected_out, delta=tol)
Пример #18
0
    def test_sample_values(self, tol):
        """Tests if the samples returned by sample have
        the correct values
        """
        dev = plf.WavefunctionDevice(wires=1, shots=10)
        theta = 1.5708

        circuit_operations = []

        O = qml.sample(qml.PauliZ(0))

        observables = [O]

        with qml.tape.QuantumTape() as tape:
            qml.RX(theta, wires=[0])
            qml.sample(qml.PauliZ(0))

        dev.apply(tape._ops, rotations=tape.diagonalizing_gates)
        dev._samples = dev.generate_samples()
        s1 = dev.sample(O.obs)

        # s1 should only contain 1 and -1
        self.assertAllAlmostEqual(s1**2, 1, delta=tol)
Пример #19
0
    def test_var(self, tol, qvm):
        """Tests for variance calculation"""
        dev = plf.WavefunctionDevice(wires=2)

        phi = 0.543
        theta = 0.6543

        circuit_operations = [qml.RX(phi, wires=[0]), qml.RY(theta, wires=[0])]

        O = qml.var(qml.PauliZ(wires=[0]))

        observables = [O]
        circuit_graph = qml.CircuitGraph(circuit_operations + observables, {})

        # test correct variance for <Z> of a rotated state
        dev.apply(circuit_graph.operations,
                  rotations=circuit_graph.diagonalizing_gates)

        var = dev.var(qml.PauliZ(0))
        expected = 0.25 * (3 - np.cos(2 * theta) -
                           2 * np.cos(theta)**2 * np.cos(2 * phi))

        self.assertAlmostEqual(var, expected, delta=tol)
    def test_expand_two(self, tol):
        """Test that a 2 qubit gate correctly expands to 3 qubits."""
        dev = plf.WavefunctionDevice(wires=4)

        # test applied to wire 0+1
        res = dev.expand(U2, [0, 1])
        expected = np.kron(np.kron(U2, I), I)
        self.assertAllAlmostEqual(res, expected, delta=tol)

        # test applied to wire 1+2
        res = dev.expand(U2, [1, 2])
        expected = np.kron(np.kron(I, U2), I)
        self.assertAllAlmostEqual(res, expected, delta=tol)

        # test applied to wire 2+3
        res = dev.expand(U2, [2, 3])
        expected = np.kron(np.kron(I, I), U2)
        self.assertAllAlmostEqual(res, expected, delta=tol)

        # CNOT with target on wire 1
        res = dev.expand(CNOT, [1, 0])
        rows = np.array([0, 2, 1, 3])
        expected = np.kron(np.kron(CNOT[:, rows][rows], I), I)
        self.assertAllAlmostEqual(res, expected, delta=tol)

        # test exception raised if unphysical subsystems provided
        with pytest.raises(
                ValueError,
                match="Invalid target subsystems provided in 'wires' argument."
        ):
            dev.expand(U2, [-1, 5])

        # test exception raised if incorrect sized matrix provided
        with pytest.raises(ValueError,
                           match="Matrix parameter must be of size"):
            dev.expand(U, [0, 1])