Skip to main content
IBM Quantum Platform

Compilateur quantique approximatif

qiskit.synthesis.unitary.aqc

Implémentation d'un compilateur quantique approximatif tel que décrit dans l'article [1.]


Interface

L'interface publique principale de ce module est accessible en passant unitary_synthesis_method='aqc' à transpile(). La méthode de synthèse sera alors modifiée pour utiliser AQCSynthesisPlugin. Les classes individuelles sont les suivantes

AQC( [optimiseur, graine] )Une implémentation générique du compilateur quantique approximatif.
ApproximateCircuit(nombre_de_qubits[, nom] )Une classe de base qui représente un circuit approximatif.
ApproximatingObjective()Classe de base pour la définition d'un problème d'optimisation.
CNOTUnitCircuit(num_qubits, cnots[, tol, name] )Une classe qui représente un circuit approximatif basé sur les blocs d'unités du CNOT.
CNOTUnitObjective(n_qubits, cnœuds)Classe de base pour la définition d'un problème basé sur l'unité CNOT.
DefaultCNOTUnitObjective(n_qubits, cnœuds)Une implémentation naïve de la fonction objective basée sur les unités CNOT.
FastCNOTUnitObjective(n_qubits, cnœuds)Implémentation d'une fonction objective et d'un calculateur de gradient, similaire à DefaultCNOTUnitObjective mais plusieurs fois plus rapide.

Détails mathématiques

Nous nous intéressons à la compilation d'un circuit quantique, que nous formalisons comme la recherche de la meilleure représentation du circuit en termes de séquence de portes ordonnée d'une matrice unitaire cible UU(d)U\in U(d), avec quelques contraintes matérielles supplémentaires. En particulier, nous recherchons des représentations qui pourraient être limitées en termes de connectivité matérielle et de profondeur de porte, et nous choisissons une base de porte en termes de CNOT et de portes de rotation. Nous rappelons que la combinaison des portes CNOT et de rotation est universelle sur le site SU(d)SU(d) et qu'elle ne limite donc pas la compilation.

Pour définir clairement ce que nous entendons par « meilleure représentation du circuit », nous définissons cette mesure comme la norme de Frobenius entre la matrice unitaire du circuit compilé VV et la matrice unitaire cible UU, c'est-à-dire VUF\|V - U\|_{\mathrm{F}}. Ce choix s'appuie sur des considérations de programmation mathématique et s'inscrit dans le prolongement d'autres formulations présentes dans la littérature. Examinons ce problème plus en détail.

Soit nn le nombre de qubits et d=2nd=2^n. Étant donné une structure CNOT ctct et un vecteur d'angles de rotation θ\theta, le circuit paramétrique forme une matrice Vct(θ)SU(d)Vct(\theta)\in SU(d). Si l'on nous donne un circuit cible formant une matrice USU(d)U\in SU(d), nous aimerions calculer

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

où le produit intérieur est le produit intérieur de Frobenius. Notez que V,Ud|\langle V,U\rangle|\leq d pour tous les unitaires UU et VV, de sorte que l'objectif a une portée dans [0,1][0,1].

Notre stratégie consiste à maximiser

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

à l'aide de son gradient. Nous allons maintenant en aborder les spécificités à l'aide d'un exemple.

Bien que la plage de VctVct soit un sous-ensemble de SU(d)SU(d) par construction, le circuit cible peut former une matrice unitaire générale. Cependant, pour tout UU(d)U\in U(d),

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

Il convient donc de normaliser le circuit cible en fonction de sa phase globale, puis de compiler approximativement le circuit normalisé. Nous pourrons ajouter la phase globale par la suite.

Dans l'algorithme, UU' désigne la matrice cible non normalisée et UU la matrice cible normalisée. Maintenant que nous avons UU, nous donnons la fonction de gradient à l'optimiseur de la méthode de Nesterov et calculons θ\theta.

Pour ajouter la phase globale, nous pouvons former le circuit de commande comme suit

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

Notez que si nous avons optimisé en utilisant la méthode de Nesterov dans le document, c'était pour ses garanties de convergence, et non pour sa rapidité en pratique. Il est beaucoup plus rapide d'utiliser L-BFGS qui est utilisé comme optimiseur par défaut dans cette implémentation.

Une utilisation de base de l'algorithme AQC devrait comprendre les étapes suivantes :

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

# Define a number of qubits for the algorithm, at least 3 qubits
num_qubits = round(math.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
)

Maintenant, approximate_circuit est un circuit qui approxime l'unité cible à un certain degré et peut être utilisé à la place de la matrice originale.

Cette fonction utilise une fonction d'aide, make_cnot_network.

make_cnot_network

qiskit.synthesis.unitary.aqc.make_cnot_network(num_qubits, network_layout='spin', connectivity_type='full', depth=0)

GitHub

Génère un réseau composé de blocs de construction contenant chacun une porte CNOT et éventuellement des portes à qubit unique. Ce réseau modélise un opérateur quantique en question. Il est à noter que chaque bloc de construction possède deux entrées et deux sorties correspondant à une paire de qubits. Ce que nous renvoyons ici est une chaîne d'indices de paires de qubits partagés par chaque bloc de construction d'une rangée.

Paramètres

  • num_qubits (int) – le nombre de qubits.
  • network_layout (str) – le type de géométrie du réseau, {"sequ", "spin", "cart", "cyclic_spin", "cyclic_line"}.
  • connectivity_type (str) – type de connectivité inter-qubit, {"full", "line", "star"}.
  • depth (int) – profondeur du réseau CNOT, c'est-à-dire le nombre de couches, chaque couche étant constituée d'un seul bloc CNOT; la valeur par défaut sera sélectionnée si L <= 0.

Retours

Une matrice de taille (2, N) qui définit les couches dans le réseau cnot, où N

est soit égal à L, soit défini par un type concret du réseau.

Augmentations

ValueError - si le type de réseau CNOT, le nombre de qubits ou la combinaison de paramètres transmis ne sont pas pris en compte.

Type de retour

ndarray

On peut tirer parti de la version accélérée de la fonction objective. Il met en œuvre le même algorithme mathématique que l'algorithme par défaut DefaultCNOTUnitObjective mais s'exécute plusieurs fois plus rapidement. L'instanciation de la classe de fonction objective accélérée est similaire au cas par défaut :

# Créer un objectif qui définit notre problème d'optimisation approximativement_objectif = FastCNOTUnitObjective(num_qubits=num_qubits, cnots=cnots)

Le reste du code de l'exemple ci-dessus ne change pas.

Références

[1] : Liam Madden, Andrea Simonetto, Best Approximate Quantum Compiling Problems.

arXiv:2106.05649

Cette page a-t-elle été utile ?
Signaler un bogue, une coquille ou proposer du contenu sur GitHub.