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

Deprecate qiskit/transpiler/synthesis and move to qiskit/synthesis #11426

Merged
merged 39 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
081c540
deprecate transpiler/synthesis/graysynth.py
ShellyGarion Dec 18, 2023
de19803
style
ShellyGarion Dec 18, 2023
2bf99a3
style
ShellyGarion Dec 18, 2023
f884e6d
move aqc_plugin to qiskit/transpiler/passes/synthesis
ShellyGarion Dec 19, 2023
54f0bab
remove code from qiskit/transpiler/synthesis/aqc/aqc_plugin.py
ShellyGarion Dec 25, 2023
2ea0016
copy qiskit/transpiler/synthesis/aqc to qiskit/synthesis/unitary
ShellyGarion Dec 25, 2023
05b50e5
move tests from test/python/transpiler/aqc to test/python/synthesis/aqc
ShellyGarion Dec 25, 2023
3262d00
update imports in aqc_plugin
ShellyGarion Dec 25, 2023
dc316df
add deprecation warning to AQC module
ShellyGarion Dec 25, 2023
4381198
handle cyclic imports
ShellyGarion Dec 25, 2023
6404bf9
handle cyclic imports
ShellyGarion Dec 25, 2023
f88c2ff
update link in docs
ShellyGarion Dec 25, 2023
8078f2e
update init in qiskit/transpiler/synthesis/aqc
ShellyGarion Dec 25, 2023
bfaa805
style
ShellyGarion Dec 25, 2023
cb042f3
temporary remove deprecation warning test
ShellyGarion Dec 26, 2023
3ebbc8c
remove files from qiskit/transpiler/synthesis/aqc
ShellyGarion Dec 26, 2023
aeb1a2d
update link in test
ShellyGarion Dec 26, 2023
e9fce2e
add release notes
ShellyGarion Dec 26, 2023
cc35802
update docs
ShellyGarion Dec 27, 2023
6b4cfec
update docs/apidocs/synthesis_aqc.rst
ShellyGarion Dec 27, 2023
cdb0d68
resolve conflict with main branch
ShellyGarion Jan 3, 2024
d1a5591
add deprecations to qiskit/transpiler/synthesis/__init__.py
ShellyGarion Jan 9, 2024
6ec572f
Merge branch 'main' into transpiler_synth_deprecate
ShellyGarion Jan 9, 2024
7e16f4a
Merge branch 'main' into transpiler_synth_deprecate
ShellyGarion Jan 9, 2024
947b01e
Merge branch 'main' into transpiler_synth_deprecate
ShellyGarion Jan 16, 2024
52e851f
fix link
ShellyGarion Jan 16, 2024
c81bc7b
improve docs following review
ShellyGarion Jan 18, 2024
d67d49a
update docs
ShellyGarion Jan 18, 2024
9c85c2c
add aqc to synthesis docs after review
ShellyGarion Jan 21, 2024
7ff6720
update qiskit/transpiler/synthesis/aqc/__init__.py after review
ShellyGarion Jan 21, 2024
cd93f32
update pending deprecation to deprecation in release notes
ShellyGarion Jan 21, 2024
572094b
handle cyclic imports
ShellyGarion Jan 21, 2024
a21c771
update qiskit/synthesis docs following docs error
ShellyGarion Jan 21, 2024
9e87164
another attempt to add AQC to synthesis docs
ShellyGarion Jan 22, 2024
25f93ca
another attempt to add AQC to the docs
ShellyGarion Jan 22, 2024
e7ffca0
Revert "another attempt to add AQC to the docs"
ShellyGarion Jan 22, 2024
4cd11c8
Revert "another attempt to add AQC to synthesis docs"
ShellyGarion Jan 22, 2024
c57b11f
add a deprecation test for AQC
ShellyGarion Jan 22, 2024
efd8b26
minor
ShellyGarion Jan 22, 2024
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
4 changes: 2 additions & 2 deletions docs/apidoc/synthesis_aqc.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.. _qiskit-transpiler-synthesis-aqc:
.. _qiskit-synthesis-unitary-aqc:

.. automodule:: qiskit.transpiler.synthesis.aqc
.. automodule:: qiskit.synthesis.unitary.aqc
:no-members:
:no-inherited-members:
:no-special-members:
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Changelog = "https://qiskit.org/documentation/release_notes.html"

[project.entry-points."qiskit.unitary_synthesis"]
default = "qiskit.transpiler.passes.synthesis.unitary_synthesis:DefaultUnitarySynthesis"
aqc = "qiskit.transpiler.synthesis.aqc.aqc_plugin:AQCSynthesisPlugin"
aqc = "qiskit.transpiler.passes.synthesis.aqc_plugin:AQCSynthesisPlugin"
sk = "qiskit.transpiler.passes.synthesis.solovay_kitaev_synthesis:SolovayKitaevSynthesis"

[project.entry-points."qiskit.synthesis"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class LinearFunction(Gate):
as a n x n matrix of 0s and 1s in numpy array format.

A linear function can be synthesized into CX and SWAP gates using the Patel–Markov–Hayes
algorithm, as implemented in :func:`~qiskit.transpiler.synthesis.cnot_synth`
algorithm, as implemented in :func:`~qiskit.synthesis.synth_cnot_count_full_pmh`
based on reference [1].

For efficiency, the internal n x n matrix is stored in the format expected
Expand Down
9 changes: 8 additions & 1 deletion qiskit/synthesis/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2017 - 2023.
# (C) Copyright IBM 2017, 2023.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
Expand Down Expand Up @@ -43,6 +43,7 @@

.. autofunction:: synth_cz_depth_line_mr
.. autofunction:: synth_cx_cz_depth_line_my
.. autofunction:: synth_cnot_phase_aam

Permutation Synthesis
=====================
Expand Down Expand Up @@ -89,6 +90,11 @@

.. autofunction:: synth_qft_line

Unitary Synthesis
=================

Cryoris marked this conversation as resolved.
Show resolved Hide resolved
The Approximate Quantum Compiler is available here: :mod:qiskit.synthesis.unitary.aqc
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The Approximate Quantum Compiler is available here: :mod:qiskit.synthesis.unitary.aqc
The Approximate Quantum Compiler is available here: :mod:`qiskit.synthesis.unitary.aqc`


"""

from .evolution import (
Expand Down Expand Up @@ -126,3 +132,4 @@
from .stabilizer import synth_stabilizer_layers, synth_stabilizer_depth_lnn
from .discrete_basis import SolovayKitaevDecomposition, generate_basic_approximations
from .qft import synth_qft_line
from .unitary import aqc
13 changes: 13 additions & 0 deletions qiskit/synthesis/unitary/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2023.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Module containing unitary synthesis methods."""
177 changes: 177 additions & 0 deletions qiskit/synthesis/unitary/aqc/__init__.py
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently the AQC docs live under the builtin transpiler plugins as only object. Would it make sense to put them with the Solovay Kitaev docs? I also don't quite understand the "builtin transpiler plugin" page, aren't there a lot more builtin plugins than AQC?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Cryoris - thanks for the detailed review!
I think that the AQCSynthesisPlugin also appears now with the other synthesis plugins here:
https://docs.quantum.ibm.com/api/qiskit/transpiler_passes#synthesis

Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2022.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

r"""
=====================================================================
Approximate Quantum Compiler (:mod:`qiskit.synthesis.unitary.aqc`)
=====================================================================

.. currentmodule:: qiskit.synthesis.unitary.aqc

Implementation of Approximate Quantum Compiler as described in the paper [1].

Interface
=========

The main public interface of this module is reached by passing ``unitary_synthesis_method='aqc'`` to
:func:`~.compiler.transpile`. This will swap the synthesis method to use
:class:`~.transpiler.passes.synthesis.AQCSynthesisPlugin`.
The individual classes are:

.. autosummary::
:toctree: ../stubs
:template: autosummary/class_no_inherited_members.rst

AQC
ApproximateCircuit
ApproximatingObjective
CNOTUnitCircuit
CNOTUnitObjective
DefaultCNOTUnitObjective
FastCNOTUnitObjective


Mathematical Detail
===================

We are interested in compiling a quantum circuit, which we formalize as finding the best
circuit representation in terms of an ordered gate sequence of a target unitary matrix
:math:`U\in U(d)`, with some additional hardware constraints. In particular, we look at
representations that could be constrained in terms of hardware connectivity, as well
as gate depth, and we choose a gate basis in terms of CNOT and rotation gates.
We recall that the combination of CNOT and rotation gates is universal in :math:`SU(d)` and
therefore it does not limit compilation.

To properly define what we mean by best circuit representation, we define the metric
as the Frobenius norm between the unitary matrix of the compiled circuit :math:`V` and
the target unitary matrix :math:`U`, i.e., :math:`\|V - U\|_{\mathrm{F}}`. This choice
is motivated by mathematical programming considerations, and it is related to other
formulations that appear in the literature. Let's take a look at the problem in more details.

Let :math:`n` be the number of qubits and :math:`d=2^n`. Given a CNOT structure :math:`ct`
and a vector of rotation angles :math:`\theta`, the parametric circuit forms a matrix
:math:`Vct(\theta)\in SU(d)`. If we are given a target circuit forming a matrix
:math:`U\in SU(d)`, then we would like to compute

.. math::

\mathrm{argmax}_{\theta}\frac{1}{d}|\langle Vct(\theta),U\rangle|

where the inner product is the Frobenius inner product. Note that
:math:`|\langle V,U\rangle|\leq d` for all unitaries :math:`U` and :math:`V`, so the objective
has range in :math:`[0,1]`.

Our strategy is to maximize

.. math::

\frac{1}{d}\Re \langle Vct(\theta),U\rangle

using its gradient. We will now discuss the specifics by going through an example.

While the range of :math:`Vct` is a subset of :math:`SU(d)` by construction, the target
circuit may form a general unitary matrix. However, for any :math:`U\in U(d)`,

.. math::

\frac{\exp(2\pi i k/d)}{\det(U)^{1/d}}U\in SU(d)\text{ for all }k\in\{0,\ldots,d-1\}.

Thus, we should normalize the target circuit by its global phase and then approximately
compile the normalized circuit. We can add the global phase back in afterwards.

In the algorithm let :math:`U'` denote the un-normalized target matrix and :math:`U`
the normalized target matrix. Now that we have :math:`U`, we give the gradient function
to the Nesterov's method optimizer and compute :math:`\theta`.

To add the global phase back in, we can form the control circuit as

.. math::

\frac{\langle Vct(\theta),U'\rangle}{|\langle Vct(\theta),U'\rangle|}Vct(\theta).

Note that while we optimized using Nesterov's method in the paper, this was for its convergence
guarantees, not its speed in practice. It is much faster to use L-BFGS which is used as a
default optimizer in this implementation.

A basic usage of the AQC algorithm should consist of the following steps::

# Define a target circuit as a unitary matrix
unitary = ...

# Define a number of qubits for the algorithm, at least 3 qubits
num_qubits = int(round(np.log2(unitary.shape[0])))

# Choose a layout of the CNOT structure for the approximate circuit, e.g. ``spin`` for
# a linear layout.
layout = options.get("layout") or "spin"

# Choose a connectivity type, e.g. ``full`` for full connectivity between qubits.
connectivity = options.get("connectivity") or "full"

# Define a targeted depth of the approximate circuit in the number of CNOT units.
depth = int(options.get("depth") or 0)

# Generate a network made of CNOT units
cnots = make_cnot_network(
num_qubits=num_qubits,
network_layout=layout,
connectivity_type=connectivity,
depth=depth
)

# Create an optimizer to be used by AQC
optimizer = partial(scipy.optimize.minimize, method="L-BFGS-B")

# Create an instance
aqc = AQC(optimizer)

# Create a template circuit that will approximate our target circuit
approximate_circuit = CNOTUnitCircuit(num_qubits=num_qubits, cnots=cnots)

# Create an objective that defines our optimization problem
approximating_objective = DefaultCNOTUnitObjective(num_qubits=num_qubits, cnots=cnots)

# Run optimization process to compile the unitary
aqc.compile_unitary(
target_matrix=unitary,
approximate_circuit=approximate_circuit,
approximating_objective=approximating_objective
)

Now ``approximate_circuit`` is a circuit that approximates the target unitary to a certain
degree and can be used instead of the original matrix.

This uses a helper function, :obj:`make_cnot_network`.

.. autofunction:: make_cnot_network

One can take advantage of accelerated version of objective function. It implements the same
mathematical algorithm as the default one ``DefaultCNOTUnitObjective`` but runs several times
faster. Instantiation of accelerated objective function class is similar to the default case:

# Create an objective that defines our optimization problem
approximating_objective = FastCNOTUnitObjective(num_qubits=num_qubits, cnots=cnots)

The rest of the code in the above example does not change.

References:

[1]: Liam Madden, Andrea Simonetto, Best Approximate Quantum Compiling Problems.
`arXiv:2106.05649 <https://arxiv.org/abs/2106.05649>`_
"""

from .approximate import ApproximateCircuit, ApproximatingObjective
from .aqc import AQC
from .cnot_structures import make_cnot_network
from .cnot_unit_circuit import CNOTUnitCircuit
from .cnot_unit_objective import CNOTUnitObjective, DefaultCNOTUnitObjective
from .fast_gradient.fast_gradient import FastCNOTUnitObjective
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from typing import Optional, SupportsFloat
import numpy as np

from qiskit import QuantumCircuit
from qiskit.circuit.quantumcircuit import QuantumCircuit


class ApproximateCircuit(QuantumCircuit, ABC):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

import numpy as np

from qiskit.circuit.library import RXGate, RZGate, RYGate
from qiskit.circuit.library.standard_gates import RXGate, RZGate, RYGate


def place_unitary(unitary: np.ndarray, n: int, j: int) -> np.ndarray:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
r"""
================================================================================
Fast implementation of objective function class
(:mod:`qiskit.transpiler.synthesis.aqc.fast_gradient`)
(:mod:`qiskit.synthesis.unitary.aqc.fast_gradient`)
================================================================================

.. currentmodule:: qiskit.transpiler.synthesis.aqc.fast_gradient
.. currentmodule:: qiskit.synthesis.unitary.aqc.fast_gradient

Extension to the implementation of Approximate Quantum Compiler as described in the paper [1].

Expand Down
2 changes: 2 additions & 0 deletions qiskit/transpiler/passes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@
HLSConfig
SolovayKitaev
SolovayKitaevSynthesis
AQCSynthesisPlugin
Cryoris marked this conversation as resolved.
Show resolved Hide resolved

Post Layout (Post transpile qubit selection)
============================================
Expand Down Expand Up @@ -253,6 +254,7 @@
from .synthesis import HLSConfig
from .synthesis import SolovayKitaev
from .synthesis import SolovayKitaevSynthesis
from .synthesis import AQCSynthesisPlugin

# calibration
from .calibration import PulseGates
Expand Down
1 change: 1 addition & 0 deletions qiskit/transpiler/passes/synthesis/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@
from .linear_functions_synthesis import LinearFunctionsSynthesis, LinearFunctionsToPermutations
from .high_level_synthesis import HighLevelSynthesis, HLSConfig
from .solovay_kitaev_synthesis import SolovayKitaev, SolovayKitaevSynthesis
from .aqc_plugin import AQCSynthesisPlugin
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,10 @@ def run(self, unitary, **options):
# Runtime imports to avoid the overhead of these imports for
# plugin discovery and only use them if the plugin is run/used
from scipy.optimize import minimize
from qiskit.transpiler.synthesis.aqc.aqc import AQC
from qiskit.transpiler.synthesis.aqc.cnot_structures import make_cnot_network
from qiskit.transpiler.synthesis.aqc.cnot_unit_circuit import CNOTUnitCircuit
from qiskit.transpiler.synthesis.aqc.fast_gradient.fast_gradient import (
FastCNOTUnitObjective,
)
from qiskit.synthesis.unitary.aqc import AQC
from qiskit.synthesis.unitary.aqc.cnot_structures import make_cnot_network
from qiskit.synthesis.unitary.aqc.cnot_unit_circuit import CNOTUnitCircuit
from qiskit.synthesis.unitary.aqc.fast_gradient.fast_gradient import FastCNOTUnitObjective

num_qubits = int(round(np.log2(unitary.shape[0])))

Expand Down
Loading