Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Variational Quantum Algorithms Module #123

Merged
merged 58 commits into from
Apr 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
e344da6
Add basic vqa class structure
EnBr55 Jan 10, 2022
681a789
Add basic circuit cost evaluation methods to VQA class
EnBr55 Jan 10, 2022
46cbcdd
Add optimise parameters method to VQA class
EnBr55 Jan 10, 2022
68b17f7
Add Optimization_Result class
EnBr55 Jan 10, 2022
28cf460
Allow VQA_Blocks to contain native QuTiP gates
EnBr55 Jan 11, 2022
d266bc6
Update get_free_parameters method to account for state initialisation
EnBr55 Jan 14, 2022
547d773
Allow user to specify initial guess for optimiser
EnBr55 Jan 16, 2022
6d7dc35
Add Parameterized_Hamiltonian class
EnBr55 Jan 17, 2022
8d04af3
Add limited VQA.construct_jacobian method
EnBr55 Jan 18, 2022
595262a
Generalise construct_jacobian for layers of globally-parameterized Ha…
EnBr55 Jan 19, 2022
095f75b
Refactor parameterized_hamiltonian structure
EnBr55 Jan 21, 2022
b22e38f
Begin adding method to compute jacobian with frechet derivatives
EnBr55 Jan 21, 2022
66b1625
Begin jacobian methods refactor for Parameterized_Hamiltonian
EnBr55 Jan 25, 2022
e8117e9
Finish refactoring jacobian methods
EnBr55 Jan 25, 2022
62308fc
Add layer_by_layer training option
EnBr55 Jan 27, 2022
22928b9
Improve PEP8 Comformance
EnBr55 Jan 31, 2022
1cac6c5
Allow VQA_Block to accept Parameterized_Hamiltonian
EnBr55 Jan 31, 2022
c0307a4
Use black for style reformatting
EnBr55 Feb 1, 2022
3b4be27
Update docstrings on all methods
EnBr55 Feb 1, 2022
e84d4cf
Change docstrings to work with Sphinx autodoc
EnBr55 Feb 1, 2022
3dabbd8
Add api documentation for vqa module
EnBr55 Feb 1, 2022
204984d
Rename classes with TitleCase, and move global functions into classes
EnBr55 Feb 8, 2022
221557f
Add more error checking on function parameters
EnBr55 Feb 8, 2022
5f9bc22
Add tests
EnBr55 Feb 8, 2022
ad92f23
Fix small typos
EnBr55 Feb 8, 2022
11cf0cb
Add module docstring
EnBr55 Feb 9, 2022
2c6c753
Merge branch 'qutip:master' into vqa-module
EnBr55 Feb 9, 2022
4d8fe38
Fix whitespace issues
EnBr55 Feb 9, 2022
2e33f61
Update doc/source/apidoc/qutip_qip.vqa.rst
EnBr55 Feb 9, 2022
3f5a6ff
Move matplotlib import to plot function
EnBr55 Feb 14, 2022
a1f84a1
Comply with new Black style guide and fix docstring math mode
EnBr55 Feb 14, 2022
1910be1
Fix line length issues
EnBr55 Feb 14, 2022
5d5033f
Reformat with black
EnBr55 Feb 14, 2022
f29a65d
Unify plotting functions into one
EnBr55 Mar 2, 2022
0082e06
Increase test coverage for general operations
EnBr55 Mar 2, 2022
a8516d4
Reformat with black
EnBr55 Mar 2, 2022
e3936f7
Style tests consistently
EnBr55 Mar 2, 2022
1450f69
Merge branch 'qutip:master' into vqa-module
EnBr55 Mar 15, 2022
3f728e1
Add first part of new documentation
EnBr55 Mar 22, 2022
120d0ed
Update module documentation
EnBr55 Apr 3, 2022
bca3b67
Fix error in code example
EnBr55 Apr 7, 2022
e0efcb8
Remove png export from doc codeblock and reformat
EnBr55 Apr 19, 2022
fbc3587
Add tests for Optimization Result
EnBr55 Apr 19, 2022
310b498
Whitespace issue
EnBr55 Apr 19, 2022
59b74f4
Rename variables and clarify ValueError messages
EnBr55 Apr 21, 2022
af6cca2
Remove do_nothing flag from optimization method
EnBr55 Apr 21, 2022
5d8e4a2
Use plot directive for general example and add credit
EnBr55 Apr 21, 2022
0f321aa
Fix bullet point indentation in docstring
EnBr55 Apr 21, 2022
a760b75
Whitespace
EnBr55 Apr 21, 2022
7192b24
Fix error in optimize_parameters example
EnBr55 Apr 21, 2022
083452f
Correctly specify bounds to ensure doctest consistency
EnBr55 Apr 22, 2022
90f4554
Remove unecessary variable 'jac'
EnBr55 Apr 22, 2022
7353f8e
Apply suggestions from code review
EnBr55 Apr 30, 2022
164a6a5
Rename variables in line with qutip-qip conventions
EnBr55 Apr 30, 2022
cb9228e
Update docstrings to improve apidoc rendering
EnBr55 Apr 30, 2022
ad84dd4
Update type checking in get_unitary method
EnBr55 Apr 30, 2022
39a3bec
Add return type to optimize_paramters method
EnBr55 Apr 30, 2022
bd12757
Combine get_unitary_derivative and get_unitary_frechet_derivative met…
EnBr55 Apr 30, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added doc/circ.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions doc/source/apidoc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Simulation based on operator-state multiplication.
qutip_qip.qubits
qutip_qip.decompose
qutip_qip.qasm
qutip_qip.vqa

Pulse-level simulation
----------------------
Expand Down
26 changes: 26 additions & 0 deletions doc/source/apidoc/qutip_qip.vqa.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
qutip\_qip.vqa
==============

.. automodule:: qutip_qip.vqa
:members:
:show-inheritance:







.. rubric:: Classes

.. autosummary::

OptimizationResult
ParameterizedHamiltonian
VQA
VQABlock





Binary file added doc/source/figures/vqa_circuit_with_x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions doc/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ qutip-qip |version|: QuTiP quantum information processing
qip-basics.rst
qip-simulator.rst
qip-processor.rst
qip-vqa.rst

.. toctree::
:maxdepth: 2
Expand Down
124 changes: 124 additions & 0 deletions doc/source/qip-vqa.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
.. _qip_vqa:

******************************
Variational Quantum Algorithms
******************************

BoxiLi marked this conversation as resolved.
Show resolved Hide resolved
Implemented by `Ben Braham <https://benbraham.com>`_ as part of a `Unitary Fund microgrant <https://unitary.fund/grants.html>`_.

Overview
========

Variational Quantum Algorithms (VQAs) are a hybrid quantum-classical optimization algorithm in which an objective function (usually encoded by a parameterized quantum circuit) is evaluated by quantum computation, and the parameters of this function are updated using classical optimization methods. Such algorithms have been proposed for use in NISQ-era quantum computers as they typically scale well with the number of available qubits, and can function without high fault-tolerance.

In QuTiP, VQAs are represented by a parameterized quantum circuit, and include methods for defining a cost function for the circuit, and finding parameters that minimize this cost.


Constructing a VQA circuit
==========================

The :class:`.VQA` class allows for the construction of a parameterized circuit from :class:`.VQABlock` instances, which act as the gates of the circuit. In the most basic instance, a :class:`.VQA` should have:

==================== ==================================================
Property Description
==================== ==================================================
``num_qubits`` Positive integer number of qubits for the circuit.
``num_layers`` Positive integer number of repetitions of the
layered elements of the circuit.
``cost_method`` String referring to the method used to
evaluate the circuit's cost.

Either "OBSERVABLE", "BITSTRING", or "STATE".
==================== ==================================================

For example:

.. code-block::

from qutip_qip.vqa import VQA

VQA_circuit = VQA(
num_qubits=1,
num_layers=1,
cost_method="OBSERVABLE",
)

After constructing this instance, we are ready to begin adding elements to our parameterized circuit. Circuit elements in this module are represented by :class:`.VQABlock` instances. Fundamentally, the role of this class is to generate an operator for the circuit. To do this, it keeps track of its free parameters, and gives information to the :class:`.VQA` instance on how to update them. The operator itself can be generated by a user-defined function call, a parameterized Hamiltonian to exponentiate, a pre-computed unitary operator, or a string referring to a gate that has already been defined (either by the user already, or a gate native to QuTiP).

In the absence of specification, a VQA block takes a :class:`~.Qobj` as the Hamiltonian :math:`H`, and will generate a unitary with free parameter, :math:`\theta`, as :math:`U(\theta) = e^{-i \theta H}`. For example,

.. testcode::

from qutip_qip.vqa import VQA, VQABlock
from qutip import tensor, sigmax

VQA_circuit = VQA(num_qubits=1, num_layers=1)

R_x_block = VQABlock(
sigmax() / 2, name="R_x(\\theta)"
)

VQA_circuit.add_block(R_x_block)


We added our block to the ``VQA_circuit`` with the :meth:`.VQA.add_block` method. Calling the :meth:`.VQA.export_image` method renders an image of our circuit in its current form:

.. image:: /figures/vqa_circuit_with_x.png


--------------


Optimisation Loop
=================

After specifying a cost method and function to the :class:`.VQA` instance, there are various options for optimization of the free circuit parameters. Calling :meth:`.VQA.optimize_parameters` will begin the optimization process and return an :class:`.OptimizationResult` instance. By default, the method will randomize initial parameters, and use the non-gradient-based ``COBYLA`` method for parameter optimization. Users can specify:


* **Initial parameters**. Given as a list, with length corresponding to the number of free parameters in the circuit. The number of free parameters can be computed automatically with the :meth:`.VQA.get_free_parameters_num` method. Alternatively, the string 'zeros' will initialize all parameters as 0; and 'random' will initialize parameters randomly between 0 and 1. Defaults to 'random'.

* **Optimization method**. This can be a string referring to a pre-defined ``SciPy`` method `listed here <https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html>`_, or a callable function.

* **Jacobian computation**. A flag will tell the optimization method to compute the Jacobian at each step, which is passed to the optimizer so that it can use gradient information.

* **Layer-by-layer training**. Optimize parameters for the circuit with only a single layer, and hold these fixed while adding additional layers, up to ``VQA.num_layers``.

* **Bounds and constraints**. To be passed to the optimizer.

The :class:`.OptimizationResult` class provides information about the completed optimization process. For example, the probability amplitudes of different measurement outcomes of the circuit post-optimization can be plotted with :meth:`.OptimizationResult.plot`.

Below, we run an optimization on a toy circuit, tuning a parameterized :math:`x`-rotation gate to try to maximise the probability amplitude of the :math:`|1\rangle` state.

.. plot::
:context:

>>> from qutip_qip.vqa import VQA, VQABlock
>>> from qutip import sigmax, sigmaz
>>> circ = VQA(num_qubits=1, cost_method="OBSERVABLE")

Picking the Pauli Z operator as our cost observable, our circuit's cost function will be: :math:`\langle\psi(t)| \sigma_z | \psi(t)\rangle`

>>> circ.cost_observable = sigmaz()


Adding a Pauli X operator as a block to the circuit, the operation of the entire circuit becomes: :math:`e^{-i t X /2}`.


>>> circ.add_block(VQABlock(sigmax() / 2))

We can now try to find a minimum in our cost function using the SciPy in-built L-BFGS-B (L-BFGS with box constraints) method. We specify the bounds so that our parameter is :math:`0 \leq t \leq 4`.

>>> result = circ.optimize_parameters(method="L-BFGS-B", use_jac=True, bounds=[[0, 4]])

Accessing ``result.res.x``, we have the array of parameters found during optimization. In our case, we only had one free parameter, so we examine the first element of this array.

>>> angle = round(result.res.x[0], 2)
>>> print(f"Angle found: {angle}")
Angle found: 3.14

Finally, we can plot our the measurement outcome probabilities of our circuit after optimization.

>>> result.plot()


In this simple example, our optimization found that (neglecting phase) :math:`R_x(\pi) |0\rangle = |1\rangle`. Of course, this very basic usage generalizes to circuits on multiple qubits, with more complicated cost functions and optimization procedures.
Loading