-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathglobal_model.py
94 lines (75 loc) · 2.58 KB
/
global_model.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
93
94
from typing import Tuple
import pennylane as qml
import pennylane.numpy as np
from pennylane.operation import Operation as qml_Operation
from pennylane.templates.embeddings import AngleEmbedding as qml_AngleEmbedding
# This has the same structure as the local model, however, it uses the global Z^{\otimes n} observable.
def global_circuit_generator(
dev: qml.Device,
n_qubits: int,
n_layers: int,
angle_encoding_axis: str = "Y",
variational_unitary: qml_Operation = qml.RX,
entangling_gate: qml_Operation = qml.CZ,
) -> qml.QNode:
qubits_range = range(n_qubits)
def ntk_circuit(x, weights):
qml_AngleEmbedding(x, qubits_range, angle_encoding_axis)
for i in range(n_layers):
layer_weights = weights[i].flatten()
qml.broadcast(
unitary=variational_unitary,
wires=qubits_range,
pattern="single",
parameters=layer_weights,
)
qml.broadcast(unitary=entangling_gate, wires=qubits_range, pattern="ring")
obs = qml.PauliZ(0)
for i in range(1, n_qubits):
obs = obs @ qml.PauliZ(i)
return qml.expval(obs)
return qml.QNode(ntk_circuit, dev, diff_method="parameter-shift")
# Given the weights and the inputs, calculates the following of the global model if asked:
# f_x: the output of the global model
# grad: the gradient of the global model
# hess: the hessian of the global model
def global_results(
x: np.ndarray,
w: np.ndarray,
n_qubits: int,
n_layers: int,
do_fx: bool = True,
do_grad: bool = True,
do_hess: bool = True,
) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
device = qml.device("qulacs.simulator", wires=range(n_qubits))
global_circ = global_circuit_generator(device, n_qubits, n_layers)
param_count = n_qubits * n_layers
f_x = np.zeros(1)
gradient = np.zeros_like(w)
hessian = np.zeros((param_count, param_count))
if do_fx:
f_x = global_circ(x, w)
if do_grad or do_hess:
grad_fn = qml.grad(global_circ, argnum=1)
if do_grad:
gradient = grad_fn(x, w)
if do_hess:
hess_fn = qml.jacobian(grad_fn)
hessian = hess_fn(x, w)
return (
f_x,
gradient,
hessian,
)
# Shorthand for getting only the output f(x) of the global model
def global_model(
x: np.ndarray,
w: np.ndarray,
n_qubits: int,
n_layers: int,
) -> np.ndarray:
f_x, _, _ = global_results(
x, w, n_qubits, n_layers, do_fx=True, do_grad=False, do_hess=False
)
return f_x