/
test_optimize_qng.py
92 lines (68 loc) · 2.83 KB
/
test_optimize_qng.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# Copyright 2018 Xanadu Quantum Technologies Inc.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Tests for the QNG optimizer"""
import pytest
import scipy as sp
import pennylane as qml
from pennylane import numpy as np
class TestExceptions:
"""Test exceptions are raised for incorrect usage"""
def test_obj_func_not_a_qnode(self):
"""Test that if the objective function is not a
QNode, an error is raised."""
dev = qml.device("default.qubit", wires=1)
@qml.qnode(dev)
def circuit(a):
qml.RX(a, wires=0)
return qml.expval(qml.PauliZ(0))
def cost(a):
return circuit(a)
opt = qml.QNGOptimizer()
params = 0.5
with pytest.raises(
ValueError, match="Objective function must be encoded as a single QNode"
):
opt.step(cost, params)
class TestOptimize:
"""Test basic optimization integration"""
def test_qubit_rotation(self, tol):
"""Test qubit rotation has the correct QNG value
every step, the correct parameter updates,
and correct cost after 200 steps"""
dev = qml.device("default.qubit", wires=1)
@qml.qnode(dev)
def circuit(params):
qml.RX(params[0], wires=0)
qml.RY(params[1], wires=0)
return qml.expval(qml.PauliZ(0))
def gradient(params):
"""Returns the gradient of the above circuit"""
da = -np.sin(params[0]) * np.cos(params[1])
db = -np.cos(params[0]) * np.sin(params[1])
return np.array([da, db])
eta = 0.01
init_params = np.array([0.011, 0.012])
num_steps = 200
opt = qml.QNGOptimizer(eta)
theta = init_params
# optimization for 200 steps total
for t in range(num_steps):
theta_new = opt.step(circuit, theta)
# check metric tensor
res = opt.metric_tensor
exp = np.diag([0.25, (np.cos(theta[0]) ** 2)/4])
assert np.allclose(res, exp, atol=tol, rtol=0)
# check parameter update
dtheta = eta * sp.linalg.pinvh(exp) @ gradient(theta)
assert np.allclose(dtheta, theta - theta_new, atol=tol, rtol=0)
theta = theta_new
# check final cost
assert np.allclose(circuit(theta), -0.9963791, atol=tol, rtol=0)