Skip to main content
IBM Quantum Platform

Approches et formes variationnelles

Au cœur de tous les algorithmes variationnels se trouve l'idée clé d'analyser les différences entre les états, qui sont commodément liés par une cartographie bien conçue (par exemple, continue, différentiable) à partir d'un ensemble de paramètres ou de variables - d'où le nom.

Tout d'abord, nous verrons comment construire des circuits paramétrés à la main. Nous utiliserons ces circuits pour définir un site Couches de portes paramétrées qui sont répétées un certain nombre de fois et dont les paramètres sont optimisés au cours de l'algorithme pour minimiser la fonction de coût. qui représente une collection d'états paramétrés à explorer par notre algorithme variationnel. Ensuite, nous construirons notre site Combinaison d'un opérateur de référence et d'une forme variationnelle, pour décrire l'espace de recherche que nous explorons. en appliquant cette forme variationnelle à notre état de référence.

Nous verrons également comment arbitrer entre vitesse et précision lors de l'exploration de cet espace de recherche.

Un diagramme montrant les éléments clés de la discussion sur les ansatz, y compris les ansaetze heuristiques et les ansaetze spécifiques à un problème.

Circuits quantiques paramétrés

Les algorithmes variationnels fonctionnent en explorant et en comparant une gamme d'états quantiques ψ(θ)|\psi(\vec{\theta})\rangle, qui dépendent d'un ensemble fini de paramètres kk θ=(θ0,,θk1)\vec{\theta} = (\theta^0, \ldots, \theta^{k-1}). Ces états peuvent être préparés à l'aide d'un circuit quantique paramétré, où les portes sont définies avec des paramètres accordables. Il est possible de créer ce circuit paramétré sans lier des angles spécifiques pour l'instant :

from qiskit.circuit import QuantumCircuit, Parameter

theta = Parameter("θ")

qc = QuantumCircuit(3)
qc.rx(theta, 0)
qc.cx(0, 1)
qc.x(2)

qc.draw("mpl")

Output:

Output of the previous code cell
from math import pi

angle_list = [pi / 3, pi / 2]
circuits = [qc.assign_parameters({theta: angle}) for angle in angle_list]

for circuit in circuits:
    display(circuit.draw("mpl"))

Output:

Output of the previous code cell Output of the previous code cell

Forme variationnelle et Ansatz

Pour optimiser de manière itérative à partir d'un état de référence ρ|\rho\rangle vers un état cible ψ(θ)|\psi(\vec\theta)\rangle, nous devons définir une forme variationnelle UV(θ)U_V(\vec{\theta}) qui représente une collection d'états paramétrés que notre algorithme variationnel doit explorer :

0URUR0=ρUV(θ)UA(θ)0=UV(θ)UR0=UV(θ)ρ=ψ(θ)\begin{aligned} |0\rangle \xrightarrow{U_R} U_R|0\rangle & = |\rho\rangle \xrightarrow{U_V(\vec{\theta})} U_A(\vec{\theta})|0\rangle \\[1mm] & = U_V(\vec{\theta})U_R|0\rangle \\[1mm] & = U_V(\vec{\theta})|\rho\rangle \\[1mm] & = |\psi(\vec{\theta})\rangle \\[1mm] \end{aligned}

Notez que l'état paramétré dépend à la fois de l'état de référence ρ|\rho\rangle, qui ne dépend d'aucun paramètre, et de la forme variationnelle UV(θ)U_V(\vec{\theta}), qui dépend toujours de paramètres. Nous appelons la combinaison de ces deux moitiés un ansatz : UA(θ):=UV(θ)URU_A(\vec\theta) := U_V(\vec\theta)U_R.

Alors que nous construisons notre ansatz pour représenter une collection d'états paramétrés à explorer par notre algorithme variationnel, nous nous rendons compte d'un problème important : la dimensionnalité. Un système nn -qubit (c'est-à-dire un espace de Hilbert) possède un grand nombre d'états quantiques distincts dans l'espace de configuration. Nous aurions besoin d'un nombre considérable de paramètres pour l'explorer pleinement. D'un point de vue quantitatif, sa dimensionnalité est D=22nD = 2^{2n}. Pour aggraver les choses, la complexité d'exécution des algorithmes de recherche, et d'autres, croît de manière exponentielle avec cette dimensionnalité, un phénomène souvent désigné dans la littérature comme la malédiction de la dimensionnalité.

Pour pallier cet inconvénient, il est courant d'imposer des contraintes raisonnables sur la forme variationnelle, de sorte que seuls les états les plus pertinents soient explorés. La recherche d'un ansatz tronqué efficace est un domaine de recherche actif, mais nous couvrirons deux modèles courants.


Approches heuristiques et compromis

Si vous ne disposez d'aucune information sur votre problème particulier permettant de limiter la dimensionnalité, vous pouvez essayer une famille arbitraire de circuits paramétrés comportant moins de 22n2^{2n} paramètres. Cependant, il y a des compromis à prendre en compte :

  • Vitesse : en réduisant l'espace de recherche, l'algorithme peut fonctionner plus rapidement.
  • Précision : En réduisant l'espace, on risque d'exclure la solution réelle du problème, ce qui conduit à des solutions sous-optimales.
  • Le bruit : Les circuits plus profonds sont affectés par le bruit, et nous devons donc expérimenter la connectivité, les portes et la fidélité des portes de notre ansatz.

Il existe un compromis fondamental entre la qualité (ou même la solvabilité) et la rapidité : plus il y a de paramètres, plus vous avez de chances d'obtenir un résultat précis, mais plus l'exécution de l'algorithme prendra de temps.

Circuits N-locaux

L'un des exemples les plus répandus de réponses heuristiques est celui des circuits N-locaux, et ce pour plusieurs raisons :

  • Mise en œuvre efficace : L'ansatz N-local est généralement composé de portes locales simples qui peuvent être mises en œuvre efficacement sur un ordinateur quantique, en utilisant un petit nombre de qubits physiques. Cela facilite la construction et l'optimisation des circuits quantiques.
  • Capture des corrélations importantes : L'ansatz N-local peut capturer des corrélations importantes entre les qubits d'un système quantique, même avec un petit nombre de portes. En effet, les portes locales peuvent agir sur les qubits voisins et créer un enchevêtrement entre eux, ce qui peut être important pour simuler des systèmes quantiques complexes.

Ces circuits sont constitués de couches de rotation et d'enchevêtrement qui sont répétées alternativement une ou plusieurs fois comme suit :

  • Chaque couche est constituée de portes d'une taille maximale de NN, où NN doit être inférieur au nombre de qubits.
  • Pour une couche de rotation, les portes sont empilées les unes sur les autres. Nous pouvons utiliser des opérations de rotation standard, telles que RX ou CRZ.
  • Pour une couche d'intrication, nous pouvons utiliser des portes comme Toffoli portes ou CX avec une stratégie d'enchevêtrement.
  • Les deux types de couches peuvent être paramétrés ou non, mais au moins l'une d'entre elles doit contenir des paramètres. Sinon, sans au moins un paramètre, il n'y aurait pas de variations!
  • En option, une couche de rotation supplémentaire est ajoutée à la fin du circuit.

Par exemple, créons un circuit de cinq qubits NLocal avec des blocs de rotation formés par RX et CRZ des blocs d'intrication formés par des portes Toffoli qui agissent sur les qubits [0,1,2][0,1,2], [0,2,3][0,2,3], [4,2,1][4,2,1] et [3,1,0][3,1,0] et 22 des répétitions de chaque couche.

from qiskit.circuit.library import NLocal, CCXGate, CRZGate, RXGate
from qiskit.circuit import Parameter

theta = Parameter("θ")
ansatz = NLocal(
    num_qubits=5,
    rotation_blocks=[RXGate(theta), CRZGate(theta)],
    entanglement_blocks=CCXGate(),
    entanglement=[[0, 1, 2], [0, 2, 3], [4, 2, 1], [3, 1, 0]],
    reps=2,
    insert_barriers=True,
)
ansatz.decompose().draw("mpl")

Output:

Output of the previous code cell

Dans l'exemple ci-dessus, la plus grande porte est la porte de Toffoli, qui agit sur trois qubits, ce qui rend le circuit 33 -local. Le type de circuits NN -locaux le plus couramment utilisé est 22 -local avec des portes de rotation à qubit unique et 22 -qubit entanglement gates.

Créons un circuit 22 -local en utilisant la classe Qiskit TwoLocal de Qiskit. La syntaxe est la même que celle de NLocal, mais il y a quelques différences. Par exemple, la plupart des portes, telles que RX, RZ, et CNOT, peuvent être transmises sous forme de chaînes de caractères sans importer les portes ou créer une instance Parameter .

from qiskit.circuit.library import TwoLocal

ansatz = TwoLocal(
    num_qubits=5,
    rotation_blocks=["rx", "rz"],
    entanglement_blocks="cx",
    entanglement="linear",
    reps=2,
    insert_barriers=True,
)
ansatz.decompose().draw("mpl")

Output:

Output of the previous code cell

Dans ce cas, nous avons utilisé la distribution d'intrication linéaire, où chaque qubit est intriqué avec le suivant. Pour en savoir plus sur les autres stratégies, consultez la documentation de TwoLocal .

SU2 efficace

efficient_su2 est un circuit efficace sur le plan matériel qui consiste en des couches d'opérations à qubit unique couvrant SU(2) et CX enchevêtrements. Il s'agit d'un modèle heuristique qui peut être utilisé pour préparer des fonctions d'onde d'essai pour les algorithmes quantiques variationnels ou comme circuit de classification pour l'apprentissage automatique.

from qiskit.circuit.library import efficient_su2

ansatz = efficient_su2(4, su2_gates=["rx", "y"], entanglement="linear", reps=1)
ansatz.decompose().draw("mpl")

Output:

Output of the previous code cell

Approches spécifiques au problème

Alors que les réponses heuristiques et matérielles efficaces nous aident à résoudre un problème de manière naïve, nous pouvons utiliser des connaissances spécifiques au problème pour restreindre l'espace de recherche de notre circuit à un type spécifique. Cela nous permettra de gagner en rapidité sans perdre en précision dans notre processus de recherche.

Optimisation

Dans un problème de coupe maximale, nous voulons partitionner les nœuds d'un graphe de manière à maximiser le nombre d'arêtes entre les nœuds de groupes différents. La partition max-cut souhaitée pour le graphe ci-dessous est claire : le 0e nœud à gauche doit être séparé du reste des nœuds à droite par une coupure.

import rustworkx as rx
from rustworkx.visualization import mpl_draw

n = 4
G = rx.PyGraph()
G.add_nodes_from(range(n))
# The edge syntax is (start, end, weight)
edges = [(0, 1, 1.0), (0, 2, 1.0), (0, 3, 1.0), (1, 2, 1.0), (2, 3, 1.0)]
G.add_edges_from(edges)

mpl_draw(
    G, pos=rx.shell_layout(G), with_labels=True, edge_labels=str, node_color="#1192E8"
)

Output:

Output of the previous code cell

Pour utiliser l'algorithme QAOA pour un problème de coupe maximale, nous avons besoin d'un hamiltonien de Pauli qui code le coût de manière à ce que la valeur d'espérance minimale de l'opérateur corresponde au nombre maximal d'arêtes entre les nœuds de deux groupes différents.

Pour cet exemple simple, l'opérateur est une combinaison linéaire de termes avec des opérateurs Z sur des nœuds reliés par une arête (rappelons que le 0e qubit est le plus à droite) : ZZII+IZZI+ZIIZ+IZIZ+IIZZZZII + IZZI + ZIIZ + IZIZ + IIZZ. Une fois l'opérateur construit, l'ansatz pour l'algorithme QAOA peut facilement être construit en utilisant le circuit QAOAAnsatz de la bibliothèque de circuits Qiskit.

# Pre-defined ansatz circuit, operator class and visualization tools
from qiskit.circuit.library import QAOAAnsatz
from qiskit.quantum_info import SparsePauliOp

# Problem to Hamiltonian operator
hamiltonian = SparsePauliOp.from_list(
    [("ZZII", 1), ("IZZI", 1), ("ZIIZ", 1), ("IZIZ", 1), ("IIZZ", 1)]
)
# QAOA ansatz circuit
ansatz = QAOAAnsatz(hamiltonian, reps=2)
# Draw
ansatz.decompose(reps=3).draw("mpl")

Output:

Output of the previous code cell

L'image précédente illustre l'ansatz en portes de base pour plus de clarté. Cependant, il peut être exprimé en plusieurs niveaux de décomposition en changeant l'argument reps ou en dessinant le circuit sans la méthode de décomposition. Par exemple, la représentation suivante montre directement la structure du QAOA avec la valeur par défaut des reps, qui est reps=1.

ansatz.decompose(reps=2).draw("mpl")

Output:

Output of the previous code cell

Apprentissage automatique quantique

Dans le domaine de l'apprentissage automatique, une application courante est la classification des données en deux catégories ou plus. Il s'agit d'encoder un point de données dans une carte de caractéristiques qui fait correspondre des vecteurs de caractéristiques classiques à l'espace de Hilbert quantique. La construction de cartes de caractéristiques quantiques basées sur des circuits quantiques paramétrés qui sont difficiles à simuler classiquement est une étape importante vers l'obtention d'un avantage potentiel sur les approches classiques d'apprentissage automatique et constitue un domaine actif de la recherche actuelle.

Le site zz_feature_map peut être utilisé pour créer un circuit paramétré. Nous pouvons transmettre nos points de données à la carte de caractéristiques ( xx ) et une forme variationnelle distincte pour transmettre les poids en tant que paramètres ( θ\theta ).

from qiskit.circuit.library import zz_feature_map, TwoLocal

data = [0.1, 0.2]

zz_feature_map_reference = zz_feature_map(feature_dimension=2, reps=2)
zz_feature_map_reference = zz_feature_map_reference.assign_parameters(data)

variation_form = TwoLocal(2, ["ry", "rz"], "cz", reps=2)
vqc_ansatz = zz_feature_map_reference.compose(variation_form)
vqc_ansatz.decompose().draw("mpl")

Output:

Output of the previous code cell

Récapitulatif

Cette leçon vous a appris à définir votre espace de recherche à l'aide d'une forme variationnelle :

  • Préparer des états avec un circuit quantique paramétré, où les portes sont définies avec des paramètres accordables
  • Comment construire des réponses qui permettent de trouver un compromis entre vitesse et précision?
  • Réponses heuristiques
  • Réponses spécifiques aux problèmes

Notre charge de travail variationnelle de haut niveau se présente comme suit :

Un schéma de circuit montrant deux unités : l'une préparant l'état de référence et l'autre préparant l'ansatz.

Pour chaque paramètre variationnel θ\vec\theta, un état quantique différent sera produit. Pour trouver les paramètres optimaux, nous devons définir une fonction de coût spécifique au problème pour mettre à jour de manière itérative les paramètres de notre ansatz.

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