Skip to content

pablovegan/QubitApproximant

Repository files navigation

QubitApproximant

documentation pypi version GitHub release black Tests License: GPL v3

A python package for approximating quantum circuits with a single qubit.

alt text

Documentation and examples

Documentation created with mkdocs can be found in https://pablovegan.github.io/QubitApproximant/.

Installation

With pip:

pip install qubit-approximant

Quick usage

Importing a function

In the submodule benchmarking.functions there are multiple test functions to choose from

import numpy as np
from qubit_approximant.benchmarking.functions import gaussian

x = np.linspace(-2.5, 2.5, 1000)
fn_kwargs = {'mean': 0.0, 'std': 0.5, 'coef': 1}
fn = gaussian(x, **fn_kwargs)

Creating a circuit

To create a circuit just choose the ansaz (CircuitRxRyRz, CircuitRxRy or CircuitRy) and the encoding ('prob' or 'amp').

from qubit_approximant.core import CircuitRxRyRz

circuit = CircuitRxRyRz(x, encoding='prob')

Cost function

To find the optimum parameters of the circuit, we need to choose a cost function. This can be done with the Cost class, where we input the function to approximate, the circuit ansatz and a metric to quantify the error in the approximation (options are 'mse', 'rmse', 'mse_weighted', 'kl_divergence' or 'log_cosh')

from qubit_approximant.core import Cost

cost = Cost(fn, circuit, metric='mse')

Optimizer

Choose an optimizer (BlackBoxOptimizer, GDOptimizer or AdamOptimizer)

from qubit_approximant.core import BlackBoxOptimizer

optimizer = BlackBoxOptimizer(method="L-BFGS-B")

and find the optimum parameters for the chosen circuit

layers = 6
init_params = np.random.default_rng().standard_normal(4 * layers)
opt_params = optimizer(cost, cost.grad, init_params)

Multilayer optimizer

We may also optimize an ansatz for multiple layers using the LayerwiseOptimizer, which uses the optimum parameters for a circuit with $L$ layers as initial parameters for the optimization of a circuit with $L+1$ layers. A list with the optimum parameters for each layer is returned.

from qubit_approximant.core import LayerwiseOptimizer

layerwise_opt = LayerwiseOptimizer(
    optimizer,
    min_layer=3,
    max_layer=7, 
    new_layer_coef=0.3,
    new_layer_position='random'
    )
params_list = layerwise_opt(cost, cost.grad, init_params)

Note: a MultilayerOptimizer which doesn't reuse the optimized parameters from previous layers is also available.

Error metrics

To benchmark the optimization we can use some common metrics, like the $L^1$ norm, $L^2$ norm, $L^\infty$ norm or infidelity $1-F$, to compare the function encoded in the circuit with the desired function. Following our example, fn is a gaussian:

l1_list, l2_list, inf_list, infidelity_list = metric_results(
    params_list,
    circuit,
    fn = gaussian,
    fn_kwargs = {'mean': 0.0, 'std': 0.5, 'coef': 1}
    )

Wrapping up

Test the library yourself!

import numpy as np

from qubit_approximant.benchmarking.functions import gaussian
from qubit_approximant.core import CircuitRxRyRz, Cost, BlackBoxOptimizer, LayerwiseOptimizer
from qubit_approximant.benchmarking import metric_results

x = np.linspace(-2.5, 2.5, 1000)
fn_kwargs = {'mean': 0.0, 'std': 0.5, 'coef': 1}
fn = gaussian(x, **fn_kwargs)

circuit = CircuitRxRyRz(x, encoding='prob')
cost = Cost(fn, circuit, metric='mse')
optimizer = BlackBoxOptimizer(method="L-BFGS-B")

min_layer = 3
init_params = np.random.default_rng().standard_normal(4 * min_layer)
layerwise_opt = LayerwiseOptimizer(
    optimizer,
    min_layer=min_layer,
    max_layer=7,
    new_layer_coef=0.3,
    new_layer_position='random'
    )
params_list = layerwise_opt(cost, cost.grad, init_params)

l1_list, l2_list, inf_list, infidelity_list = metric_results(
    fn=gaussian,
    fn_kwargs={'mean': 0.0, 'std': 0.5, 'coef': 1},
    circuit=circuit,
    params_list=params_list
    )

Bonus: benchmarking multiple initial parameters

The initial paramenters for the optimizer are generated at random with a seed of our choice. We can benchmark the optimizer against multiple seeds (since it is a time consuming task it is parallelized using mpi).

benchmark_seeds(
    num_seeds = 4,
    fn = gaussian,
    fn_kwargs = fn_kwargs,
    circuit = circuit,
    cost = cost,
    optimizer = multilayer_opt,
    filename = "results",
)

References

This library is based on Adrian Pérez Salinas article Data re-uploading for a universal quantum classifier.

Contributing

Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.

Please make sure to update tests as appropriate.

License

This software is under the GNU General Public License v3.0.