Skip to content

Commit

Permalink
Update explanation
Browse files Browse the repository at this point in the history
  • Loading branch information
garrison committed Nov 4, 2024
1 parent b8bb097 commit f4a487e
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 42 deletions.
10 changes: 5 additions & 5 deletions INSTALL.rst
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ Note: If you are using Windows, use the following commands in PowerShell:
Option 1: Pip Installation
^^^^^^^^^^^^^^^^^^^^^^^^^^

Upgrade pip and install the AQC-Tensor package.
Upgrade pip and install the AQC-Tensor package. To meaningfully use the package, you must also install at least one tensor network backend. The below snippet installs the addon, along with quimb (for tensor network support) and jax (for automatic differentiation).

.. code:: sh
pip install --upgrade pip
pip install qiskit-addon-aqc-tensor
pip install qiskit-addon-aqc-tensor[quimb-jax]
.. _Option 2:
Expand Down Expand Up @@ -76,19 +76,19 @@ Adjust the options below to suit your needs.

.. code:: sh
pip install tox notebook -e '.[notebook-dependencies,dev]'
pip install tox jupyterlab -e '.[notebook-dependencies,dev]'
If you installed the notebook dependencies, you can get started with AQC-Tensor by running the notebooks in the docs.

.. code::
cd docs/
jupyter notebook
jupyter lab
.. _Platform Support:

Platform Support
^^^^^^^^^^^^^^^^

We expect this package to work on `any platform supported by Qiskit <https://docs.quantum.ibm.com/start/install#operating-system-support>`__.
We expect this package to work on `any Tier 1 platform supported by Qiskit <https://docs.quantum.ibm.com/start/install#operating-system-support>`__.
26 changes: 21 additions & 5 deletions docs/explanation/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -103,25 +103,41 @@ each active qubit at the start of the circuit.
Tensor-network simulation
-------------------------

The simplest tensor network is a matrix-product state (MPS). Currently, AQC-Tensor supports the Qiskit Aer MPS simulator as its only backend.
The simplest tensor network is a matrix-product state (MPS).

Currently, AQC-Tensor supports the following tensor-network simulators:

- Qiskit Aer's MPS simulator
- Quimb's `eager <https://quimb.readthedocs.io/en/latest/tensor-circuit-mps.html>`__ :class:`~quimb.tensor.CircuitMPS` simulator
- Quimb's `lazy <https://quimb.readthedocs.io/en/latest/tensor-circuit.html>`__ :class:`~quimb.tensor.Circuit` simulator (may only work on small circuits so far; we're working to fix this soon with more clever contractions)

The most important parameter of a tensor network is its maximum bond dimension, which limits how much entanglement it can represent (and thus to what depth a given circuit can be faithfully simulated). The bond dimension is often represented by the Greek letter :math:`\chi`.

Given a general circuit on :math:`L` qubits, a matrix-product state needs at most a bond dimension of :math:`\chi_\mathrm{exact} = 2^{\lfloor L/2 \rfloor}` in order to be able to simulate it to *any* depth. Of course, general circuits on 100+ qubits cannot be classically simulated, so it will be intractable to set the bond dimension this high for those circuits.

For this reason, if you are attempting to experiment with AQC-Tensor on a toy problem with few qubits, it is important to ensure that :math:`\chi < 2^{\lfloor L/2 \rfloor}`. Otherwise, any circuit can be simulated to any depth, and there is no point in performing AQC.

Optimization procedure
----------------------

Objective function
~~~~~~~~~~~~~~~~~~

Currently, this addon provides one very simple objective function, :class:`.OneMinusFidelity`, which is equivalent to Eq. (7) in Ref. [1]_. Under the hood, it calculates a gradient using the :mod:`tensor-network gradient <qiskit_addon_aqc_tensor.gradient>` functionality provided in this package.
Currently, this addon provides one very simple objective function, :class:`.OneMinusFidelity`, which is equivalent to Eq. (7) in Ref. [1]_. When an object of this class is called with an array of parameters, it will return both the value and the gradient of that objective function at that point in parameter space.

Gradient
~~~~~~~~

The package provides a few different methods for calculating the gradient.

The Aer backend always uses the explicit gradient code in the :mod:`~qiskit_addon_aqc_tensor.simulation.explicit_gradient` module.

The Quimb backend will typically be used with an automatic differentiation backend; the user is to select a backend from among those supported by Quimb. Alternatively, one can instead pass ``"explicit"`` as the ``autodiff_backend`` when instantiating the :class:`.QuimbSimulator`; in this case, the :mod:`explicit gradient module <qiskit_addon_aqc_tensor.simulation.explicit_gradient>` will be used. It is only recommended to use explicit gradients with Quimb's eager :class:`~quimb.tensor.CircuitMPS` simulator, not the lazy :class:`~quimb.tensor.Circuit` simulator.

Regardless of which backend is chosen, the gradient code can understand linear parameter expressions (`ParameterExpression` objects). This support is essential, as linear expressions are returned by the ansatz generation code.

Optimization method
~~~~~~~~~~~~~~~~~~~

Users are encouraged to use :mod:`scipy.optimize` to perform the optimization.

L-BFGS is the optimizer demonstrated in the tutorial notebook. It works well in practice because it uses the function value and its gradient to approximate the Hessian. It works well when given an initial point and seems to work particularly well in the case of Trotter circuits. However, it might early terminate if it starts in a barren plateau. In that case, performing a handful of steps using the ADAM optimizer first may help.

References
Expand Down
24 changes: 21 additions & 3 deletions qiskit_addon_aqc_tensor/ansatz_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@


class AnsatzBlock(Gate):
"""Ansatz block."""
"""Ansatz block.
This is the base class of all blocks returned by
:func:`generate_ansatz_from_circuit`.
"""

def __init__(self, params: Sequence[Parameter]):
"""Initialize the ansatz block.
Expand Down Expand Up @@ -122,10 +126,24 @@ def generate_ansatz_from_circuit(
qc: QuantumCircuit,
/,
*,
qubits_initially_zero=False,
qubits_initially_zero: bool = False,
parameter_name: str = "theta",
) -> tuple[QuantumCircuit, list[float]]:
"""Generate an ansatz from the two-qubit connectivity structure of a circuit."""
"""Generate an ansatz from the two-qubit connectivity structure of a circuit.
See explanatatory material for motivation.
Args:
qc: A circuit, which is assumed to be unitary. Barriers are ignored.
qubits_initially_zero: If ``True``, the first Z rotation on each qubit
is removed from the ansatz under the assumption that it has no effect.
parameter_name: Name for the :class:`~qiskit.circuit.ParameterVector`
representing the free parameters in the returned ansatz circuit.
Returns:
2-tuple containing the ansatz circuit and a list of parameter values that,
when bound to the ansatz, provide a circuit equivalent to the input circuit.
"""
# FIXME: handle classical bits, measurements, resets, and barriers. maybe
# conditions too?
num_qubits = qc.num_qubits
Expand Down
2 changes: 1 addition & 1 deletion qiskit_addon_aqc_tensor/objective.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
class OneMinusFidelity:
r"""Simplest possible objective function for use with AQC-Tensor.
Its value is given by Eq. (7) in `arXiv:2301.08609v6 <https://arxiv.org/abs/2301.08609v6>`__:
Its definition is given by Eq. (7) in `arXiv:2301.08609v6 <https://arxiv.org/abs/2301.08609v6>`__:
.. math::
C = 1 - \left| \langle 0 | V^{\dagger}(\vec\theta) | \psi_\mathrm{target} \rangle \right|^2 .
Expand Down
7 changes: 7 additions & 0 deletions qiskit_addon_aqc_tensor/simulation/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ def compute_overlap(
NOTE: Unlike ``numpy.dot``, implementations of this method will perform
complex conjugation on the first argument.
Args:
psi_1: first quantum state.
psi_2: second quantum state.
Returns:
complex dot product value.
"""
raise NotImplementedError

Expand Down
28 changes: 0 additions & 28 deletions qiskit_addon_aqc_tensor/simulation/aer/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,6 @@ def _validate_mps_compatibility(mps1: QiskitAerMPS, mps2: QiskitAerMPS, /) -> No

@dispatch
def compute_overlap(mps1: QiskitAerMPS, mps2: QiskitAerMPS, /) -> complex:
"""
Compute dot product between MPS decompositions of two quantum states:
``< mps1 | mps2 >``.
NOTE: Unlike numpy.dot, this conjugates the first argument.
Args:
mps1: MPS decomposition of the left state.
mps2: MPS decomposition of the right state.
Returns:
Complex dot product value.
"""
num_qubits = len(mps1.gamma)
_validate_mps_compatibility(mps1, mps2)

Expand All @@ -100,21 +87,6 @@ def compute_overlap(mps1: QiskitAerMPS, mps2: QiskitAerMPS, /) -> complex:
def _compute_overlap_with_local_gate_applied(
mps1: QiskitAerMPS, gate: Gate, qubit: int, mps2: QiskitAerMPS, /
) -> complex:
"""
Computes dot product between MPS decompositions of two quantum states
``< mps1 | G | mps2 >`` with a single local (1-qubit) gate in the middle.
NOTE: Unlike numpy.dot, this conjugates the first argument.
Args:
mps1: MPS decomposition of the left state.
gate: Gate to apply.
qubit: position of a qubit where a local gate is applied.
mps2: MPS decomposition of the right state.
Returns:
complex dot product value.
"""
num_qubits = len(mps1.gamma)
_validate_mps_compatibility(mps1, mps2)

Expand Down

0 comments on commit f4a487e

Please sign in to comment.