import pennylane as qml import torch import torch.nn as nn from torch.nn.parameter import Parameter def encode(n_qubits, inputs): for wire in range(n_qubits): qml.RX(inputs[wire], wires=wire) def layer(n_qubits, y_weight, z_weight): for wire, y_weight in enumerate(y_weight): qml.RY(y_weight, wires=wire) for wire, z_weight in enumerate(z_weight): qml.RZ(z_weight, wires=wire) for wire in range(n_qubits): qml.CZ(wires=[wire, (wire + 1) % n_qubits]) def measure(n_qubits): return [qml.expval(qml.PauliZ(wire)) for wire in range(n_qubits)] def get_model(n_qubits, n_layers, data_reupload): # NOTE: need to select an appropriate device # dev = qml.device('lightning.gpu', wires=n_qubits) dev = qml.device("default.qubit", wires=n_qubits) shapes = { "y_weights": (n_layers, n_qubits), "z_weights": (n_layers, n_qubits) } @qml.qnode(dev, interface='torch') def circuit(inputs, y_weights, z_weights): for layer_idx in range(n_layers): if (layer_idx == 0) or data_reupload: encode(n_qubits, inputs) layer(n_qubits, y_weights[layer_idx], z_weights[layer_idx]) return measure(n_qubits) model = qml.qnn.TorchLayer(circuit, shapes) return model class QuantumNet(nn.Module): def __init__(self, n_layers, w_input, w_output, data_reupload): super(QuantumNet, self).__init__() self.n_qubits = 2 self.n_actions = 3 self.data_reupload = data_reupload self.q_layers = get_model(n_qubits=self.n_qubits, n_layers=n_layers, data_reupload=data_reupload) # convert from 2 qubits to 3 actions # not adding more complexity here because we want to learn through quantum circuit self.layer1 = nn.Linear(2, 3) if w_input: self.w_input = Parameter(torch.Tensor(self.n_qubits)) nn.init.normal_(self.w_input) else: self.register_parameter("w_input", None) if w_output: self.w_output = Parameter(torch.Tensor(self.n_actions)) nn.init.normal_(self.w_output, mean=90.0) else: self.register_parameter("w_output", None) def forward(self, inputs): if self.w_input is not None: inputs = inputs * self.w_input inputs = torch.atan(inputs) q_outputs = self.q_layers(inputs) q_outputs = (1 + q_outputs) / 2 outputs = self.layer1(q_outputs) if self.w_output is not None: outputs = outputs * self.w_output else: outputs = 90 * outputs return outputs