Source code for squid.models.vqc_multiq

import math

import numpy as np
import torch

from .abstract_models import QuantumModel
from .quantum_utils import measure_vqc_output, validate_model


[docs]class VQC(QuantumModel): """ .. todo:: TODO: Write description of VQC .. list-table:: Valid combinations of `num_quantum_params` and `num_qubits` :widths: 15 15 :header-rows: 1 * - :code:`num_quantum_params` - :code:`num_qubits` * - 6 - 2 * - 9 - 2 * - 12 - 4 * - 15 - 2 * - 18 - 6 * - 30 - 4 * - 39 - 4 * - 45 - 6 * - 57 - 4 :param num_quantum_params: Number of quantum parameters/angles to use in the model. :type num_quantum_params: int :param num_qubits: Number of qubits to use in the model. :type num_qubits: int """ def __init__(self, num_quantum_params: int, num_qubits: int, *args, **kwargs): self.grad = np.empty(0) num_u2, num_u4 = validate_model(num_quantum_params, num_qubits) self.vqc_params = [num_quantum_params, num_qubits, num_u2, num_u4] self.sigmoid = torch.nn.Sigmoid()
[docs] def clip(self, x: torch.Tensor, *args) -> torch.Tensor: """ Scales inputs, using sigmoid, to :math:`[0, 2\pi]`, which is required by VQC forward method. """ x = 2.0 * math.pi * self.sigmoid(x) return x
def forward(self, x: np.ndarray, *args): if len(x.shape) == 1: # One element per batch result, self.grad = measure_vqc_output(x, self.vqc_params, do_grad=True) elif len(x.shape) == 2: # Multiple elements per batch # Go through every sample and calculate result and gradient for it. _result = [] _grad = [] for x_sample in x: result_sample, grad_sample = measure_vqc_output( x_sample, self.vqc_params, do_grad=True ) _grad.append(grad_sample) _result.append(result_sample) # Switch to numpy arrays to be compatible with everything else result = np.array(_result) self.grad = np.array(_grad) return result def backward(self, prev_gradient: np.ndarray) -> np.ndarray: return np.matmul(prev_gradient, self.grad)