Parameter and Gradients#

It can be useful to define custom parameters in an optimization context. For example, the rotational angles which encodes information in a Quantum Neural Network are usually built as a combination of features and trainable parameters. For doing this, the qibo.parameter.Parameter class can be used. It allows to define custom parameters which can be inserted into a qibo.models.circuit.Circuit. Moreover, it automatically precomputes the analytical derivative of the parameter function, which can be used to calculate the derivatives of a variational model with respect to its parameters.

qibo.parameter.calculate_derivatives(func)[source]#

Calculates derivatives w.r.t. to all parameters of a target function func.

class qibo.parameter.Parameter(func, trainable=None, features=None)[source]#

Object which allows for variational gate parameters. Several trainable parameters and possibly features are linked through a lambda function which returns the final gate parameter. All possible analytical derivatives of the lambda function are calculated at the object initialisation using Sympy.

Example:

from qibo.parameter import Parameter
param = Parameter(
        lambda x, th1, th2, th3: x**2 * th1 + th2 * th3**2,
        features=[7.0],
        trainable=[1.5, 2.0, 3.0],
    )

partial_derivative = param.get_partial_derivative(3)

param.update_parameters(trainable=[15.0, 10.0, 7.0], feature=[5.0])
param_value = param()
Parameters:
  • func (function) – lambda function which builds the gate parameter. If both features and trainable parameters compose the function, it must be passed by first providing the features and then the parameters, as described in the code example above.

  • features (list or np.ndarray) – array containing possible input features x.

  • trainable (list or np.ndarray) – array with initial trainable parameters theta.

property nparams#

Returns the number of trainable parameters

property nfeat#

Returns the number of features

property ncomponents#

Return the number of elements which compose the Parameter

trainable_parameter_indices(start_index)[source]#

Return list of respective indices of trainable parameters within the larger trainable parameter list of a circuit for example

unaffected_by(trainable_idx)[source]#

Retrieve constant term of lambda function with regard to a specific trainable parameter

partial_derivative(trainable_idx)[source]#

Get derivative w.r.t a trainable parameter

Gradients#

In the context of optimization, particularly when dealing with Quantum Machine Learning problems, it is often necessary to calculate the gradients of functions that are to be minimized (or maximized). Hybrid methods, which are based on the use of classical techniques for the optimization of quantum computation procedures, have been presented in the Optimizers section. This approach is very useful in simulation, but some classical methods cannot be used when using real circuits: for example, in the context of neural networks, the Back-Propagation algorithm is used, where it is necessary to know the value of a target function during the propagation of information within the network. Using a real circuit, we would not be able to access this information without taking a measurement, causing the state of the system to collapse and losing the information accumulated up to that moment. For this reason, in qibo we have also implemented methods for calculating the gradients which can be performed directly on the hardware, such as the Parameter Shift Rule.

qibo.derivative.parameter_shift(circuit, hamiltonian, parameter_index, initial_state=None, scale_factor=1, nshots=None)[source]#

In this method the parameter shift rule (PSR) is implemented.

Given a circuit \(U\) and an observable \(H\), the PSR allows to calculate the derivative of the expected value of \(H\) on the final state with respect to a variational parameter of the circuit. There is also the possibility of setting a scale factor. It is useful when a circuit’s parameter is obtained by combination of a variational parameter and an external object, such as a training variable in a Quantum Machine Learning problem. For example, performing a re-uploading strategy to embed some data into a circuit, we apply to the quantum state rotations whose angles are in the form \(\theta^{\prime} = x \, \theta\), where \(\theta\) is a variational parameter, and \(x\) an input variable. The PSR allows to calculate the derivative with respect to \(\theta^{\prime}\). However, if we want to optimize a system with respect to its variational parameters, we need to “free” this procedure from the \(x\) depencency. If the scale_factor is not provided, it is set equal to one and doesn’t affect the calculation. If the PSR is needed to be executed on a real quantum device, it is important to set nshots to some integer value. This enables the execution on the hardware by calling the proper methods.

Parameters:
  • circuit (qibo.models.circuit.Circuit) – custom quantum circuit.

  • hamiltonian (qibo.hamiltonians.Hamiltonian) – target observable. if you want to execute on hardware, a symbolic hamiltonian must be provided as follows (example with Pauli-\(Z\) and \(n = 1\)): SymbolicHamiltonian(np.prod([ Z(qubit) for qubit in range(1) ])).

  • parameter_index (int) – the index which identifies the target parameter in the circuit.get_parameters() list.

  • initial_state (ndarray, optional) – initial state on which the circuit acts. If None, defaults to the zero state \(\ket{\mathbf{0}}\). Defaults to None.

  • scale_factor (float, optional) – parameter scale factor. Defaults to \(1\).

  • nshots (int, optional) – number of shots if derivative is evaluated on hardware. If None, the simulation mode is executed. Defaults to None.

Returns:

Value of the derivative of the expectation value of the hamiltonian

with respect to the target variational parameter.

Return type:

float

Example

import numpy as np

from qibo import Circuit, gates
from qibo.hamiltonians import Hamiltonian, Z
from qibo.derivative import parameter_shift

# defining an observable
def hamiltonian(nqubits = 1):
    m0 = (1/nqubits)*Z(nqubits).matrix
    ham = Hamiltonian(nqubits, m0)

    return ham

# defining a dummy circuit
def circuit(nqubits = 1):
    circ = Circuit(nqubits = 1)
    circ.add(gates.RY(q = 0, theta = 0))
    circ.add(gates.RX(q = 0, theta = 0))
    circ.add(gates.M(0))

    return circ

# initializing the circuit
circ = circuit(nqubits = 1)

# some parameters
test_params = np.random.randn(2)
circ.set_parameters(test_params)

test_hamiltonian = hamiltonian()

# running the psr with respect to the two parameters
grad_0 = parameter_shift(circuit=circ, hamiltonian=test_hamiltonian, parameter_index=0)
grad_1 = parameter_shift(circuit=circ, hamiltonian=test_hamiltonian, parameter_index=1)
qibo.derivative.finite_differences(circuit, hamiltonian, parameter_index, initial_state=None, step_size=1e-07)[source]#

Calculate derivative of the expectation value of hamiltonian on the final state obtained by executing circuit on initial_state with respect to the variational parameter identified by parameter_index in the circuit’s parameters list. This method can be used only in exact simulation mode.

Parameters:
  • circuit (qibo.models.circuit.Circuit) – custom quantum circuit.

  • hamiltonian (qibo.hamiltonians.Hamiltonian) – target observable. To execute on hardware, a symbolic hamiltonian must be provided as follows (example with Pauli-\(Z\) and \(n = 1\)): SymbolicHamiltonian(np.prod([ Z(qubit) for qubit in range(1) ])).

  • parameter_index (int) – the index which identifies the target parameter in the qibo.models.Circuit.get_parameters() list.

  • initial_state (ndarray, optional) – initial state on which the circuit acts. If None, defaults to the zero state \(\ket{\mathbf{0}}\). Defaults to None.

  • step_size (float, optional) – step size used to evaluate the finite difference. Defaults to \(10^{-7}\).

Returns:

Value of the derivative of the expectation value of the hamiltonian

with respect to the target variational parameter.

Return type:

float