Variational Quantum Algorithms
from mpqp.execution.vqa import *
In order to support Variational Quantum Algorithms (VQA for short), the parametrized gates of our circuits accept sympy’s symbolic variable as arguments.
A symbolic variable is a variable aimed at being a numeric value but without the value attributed. It can be created as such:
from sympy import symbols
theta, k = symbols("Θ k")
This concept exists more or less in all quantum circuit libraries: braket
has FreeExpression
, qiskit
has Parameter
, qlm
has Variable
,
cirq
uses sympy
’s Symbol
, etc…
Once you define a circuit with variables, you have two options:
either the measure of the circuit is an
ExpectationMeasure
and can directly feed it in the optimizer;or you can define a custom cost function for more complicated cases.
Detailed example for those two options can be found in our example notebooks.
- minimize(optimizable, method, device=None, init_params=None, nb_params=None, optimizer_options=None)[source]
This function runs an optimization on the parameters of the circuit, in order to minimize the measured expectation value of observables associated with the given circuit. Note that this means that the latter should contain an
ExpectationMeasure
.- Parameters
optimizable (Union[QCircuit, Callable[[Union[list[float], ndarray[Any, dtype[float32]]]], float]]) – Either the circuit, containing symbols and an expectation measure, or the evaluation function.
method (Union[Optimizer, Callable[[Callable[[Union[list[float], ndarray[Any, dtype[float32]]]], float], Optional[Union[list[float], ndarray[Any, dtype[float32]]]]], tuple[float, Union[list[float], numpy.ndarray[Any, numpy.dtype[numpy.float32]]]]]]) – The method used to optimize most of those methods come from
scipy
. If the choices offered in this package are not covering your needs, you can define your own optimizer. This should be a function taking as input a function representing the circuit, with as many inputs as the circuit has parameters, and any optional initialization parameters, and returning the optimal value reached and the parameters used to reach this value.device (Optional[AvailableDevice]) – The device on which the circuit should be run.
init_params (Optional[Union[list[float], ndarray[Any, dtype[float32]]]]) – The optional initialization parameters (the value attributed to the symbols in the first loop of the optimizer).
nb_params (Optional[int]) – Number of variables to input in
optimizable
. It is only useful ifoptimizable
is a Callable and ifinit_params
was not given. If not this argument is not taken into account.optimizer_options (Optional[dict[str, Any]]) – Options used to configure the VQA optimizer (maximum iterations, convergence threshold, etc…). These options are passed as is to the minimizer.
- Returns
The optimal value reached and the parameters corresponding to this value.
- Return type
tuple[float, Union[list[float], numpy.ndarray[Any, numpy.dtype[numpy.float32]]]]
Examples
>>> alpha, beta = symbols("α β") >>> circuit = QCircuit([ ... H(0), ... Rx(alpha, 1), ... CNOT(1,0), ... Rz(beta, 0), ... ExpectationMeasure( ... [0,1], ... observable=Observable(np.diag([1,2,-3,4])), ... shots=0, ... ), ... ]) >>> minimize( ... circuit, ... Optimizer.BFGS, ... ATOSDevice.MYQLM_PYLINALG, ... optimizer_options={"maxiter":50}, ... ) (-0.9999999999999996, array([0., 0.]))
>>> def cost_func(params): ... run_res = run( ... circuit, ... ATOSDevice.MYQLM_PYLINALG, ... {alpha: params[0], beta: params[1]} ... ) ... return 1 - run_res.expectation_value ** 2 >>> minimize( ... cost_func, ... Optimizer.BFGS, ... nb_params=2, ... optimizer_options={"maxiter":50}, ... ) (8.881784197001252e-16, array([0., 0.]))
For now, our minimizer is a wrapper around scipy
’s minimizer. The
Optimizer
enum lists all the methods validated with the rest of the
library.