Aller au contenu principal

Transition de phase de Nishimori

Estimation d'utilisation : 3 minutes sur un processeur Heron r2 (REMARQUE : il ne s'agit que d'une estimation. Votre temps d'exécution peut varier.)

Contexte

Ce tutoriel montre comment réaliser une transition de phase de Nishimori sur un processeur quantique IBM®. Cette expérience a été décrite à l'origine dans Realizing the Nishimori transition across the error threshold for constant-depth quantum circuits.

La transition de phase de Nishimori fait référence à la transition entre les phases ordonnées à courte et longue portée dans le modèle d'Ising à liaisons aléatoires. Sur un ordinateur quantique, la phase ordonnée à longue portée se manifeste comme un état dans lequel les qubits sont intriqués à travers l'ensemble du dispositif. Cet état fortement intriqué est préparé à l'aide du protocole de génération d'intrication par mesure (GEM). En utilisant des mesures en milieu de circuit, le protocole GEM est capable d'intriquer des qubits à travers l'ensemble du dispositif en utilisant des circuits de profondeur constante uniquement. Ce tutoriel utilise l'implémentation du protocole GEM fournie par le package logiciel GEM Suite.

Prérequis

Avant de commencer ce tutoriel, assurez-vous d'avoir installé les éléments suivants :

  • Qiskit SDK v1.0 ou ultérieur, avec le support de visualisation
  • Qiskit Runtime v0.22 ou ultérieur ( pip install qiskit-ibm-runtime )
  • GEM Suite ( pip install gem-suite )

Configuration

# Added by doQumentation — installs packages not in the Binder environment
%pip install -q gem-suite
import matplotlib.pyplot as plt

from collections import defaultdict

from qiskit_ibm_runtime import QiskitRuntimeService

from qiskit.transpiler import generate_preset_pass_manager

from gem_suite import PlaquetteLattice
from gem_suite.experiments import GemExperiment

Étape 1 : Transposer les entrées classiques en un problème quantique

Le protocole GEM fonctionne sur un processeur quantique dont la connectivité des qubits est décrite par un réseau. Les processeurs quantiques IBM actuels utilisent le réseau hexagonal lourd. Les qubits du processeur sont regroupés en plaquettes en fonction de la cellule unitaire du réseau à laquelle ils appartiennent. Comme un qubit peut apparaître dans plus d'une cellule unitaire, les plaquettes ne sont pas disjointes. Sur le réseau hexagonal lourd, une plaquette contient 12 qubits. Les plaquettes elles-mêmes forment également un réseau, où deux plaquettes sont connectées si elles partagent des qubits. Sur le réseau hexagonal lourd, les plaquettes voisines partagent 3 qubits.

Dans le package logiciel GEM Suite, la classe fondamentale pour implémenter le protocole GEM est PlaquetteLattice, qui représente le réseau de plaquettes (distinct du réseau hexagonal lourd). Un PlaquetteLattice peut être initialisé à partir d'une carte de couplage des qubits. Actuellement, seules les cartes de couplage hexagonales lourdes sont prises en charge.

La cellule de code suivante initialise un réseau de plaquettes à partir de la carte de couplage d'un processeur quantique IBM. Le réseau de plaquettes n'englobe pas toujours l'intégralité du matériel. Par exemple, ibm_torino possède 133 qubits au total, mais le plus grand réseau de plaquettes pouvant être inscrit sur le dispositif n'utilise que 125 d'entre eux et comprend un total de 18 plaquettes. Un comportement similaire peut être observé pour les dispositifs IBM Quantum® ayant un nombre différent de qubits.

# QiskitRuntimeService.save_account(channel="ibm_quantum", token="<YOUR_API_KEYN>", overwrite=True, set_as_default=True)
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)
plaquette_lattice = PlaquetteLattice.from_coupling_map(backend.coupling_map)

print(f"Number of qubits in backend: {backend.num_qubits}")
print(
f"Number of qubits in plaquette lattice: {len(list(plaquette_lattice.qubits()))}"
)
print(f"Number of plaquettes: {len(list(plaquette_lattice.plaquettes()))}")
Number of qubits in backend: 133
Number of qubits in plaquette lattice: 125
Number of plaquettes: 18

Vous pouvez visualiser le réseau de plaquettes en générant un diagramme de sa représentation sous forme de graphe. Dans le diagramme, les plaquettes sont représentées par des hexagones étiquetés, et deux plaquettes sont reliées par une arête si elles partagent des qubits.

plaquette_lattice.draw_plaquettes()

Output of the previous code cell

Vous pouvez obtenir des informations sur les plaquettes individuelles, telles que les qubits qu'elles contiennent, en utilisant la méthode plaquettes.

# Get a list of the plaquettes
plaquettes = list(plaquette_lattice.plaquettes())
# Display information about plaquette 0
plaquettes[0]
PyPlaquette(index=0, qubits=[0, 1, 2, 3, 4, 15, 16, 19, 20, 21, 22, 23], neighbors=[3, 1])

Vous pouvez également produire un diagramme des qubits sous-jacents qui forment le réseau de plaquettes.

plaquette_lattice.draw_qubits()

Output of the previous code cell

En plus des étiquettes de qubits et des arêtes indiquant quels qubits sont connectés, le diagramme contient trois informations supplémentaires pertinentes pour le protocole GEM :

  • Chaque qubit est soit ombré (gris), soit non ombré. Les qubits ombrés sont des qubits « site » qui représentent les sites du modèle d'Ising, et les qubits non ombrés sont des qubits « liaison » utilisés pour médier les interactions entre les qubits site.
  • Chaque qubit site est étiqueté soit (A), soit (B), indiquant l'un des deux rôles qu'un qubit site peut jouer dans le protocole GEM (les rôles sont expliqués plus loin).
  • Chaque arête est colorée à l'aide de l'une des six couleurs, partitionnant ainsi les arêtes en six groupes. Ce partitionnement détermine comment les portes à deux qubits peuvent être parallélisées, ainsi que les différents schémas d'ordonnancement susceptibles d'engendrer des quantités différentes d'erreur sur un processeur quantique bruité. Comme les arêtes d'un groupe sont disjointes, une couche de portes à deux qubits peut être appliquée simultanément sur ces arêtes. En fait, il est possible de partitionner les six couleurs en trois groupes de deux couleurs de sorte que l'union de chaque groupe de deux couleurs reste disjointe. Par conséquent, seules trois couches de portes à deux qubits sont nécessaires pour activer chaque arête. Il existe 12 façons de partitionner ainsi les six couleurs, et chaque partition produit un schéma de portes à 3 couches différent.

Maintenant que vous avez créé un réseau de plaquettes, l'étape suivante consiste à initialiser un objet GemExperiment, en passant à la fois le réseau de plaquettes et le backend sur lequel vous avez l'intention d'exécuter l'expérience. La classe GemExperiment gère l'implémentation effective du protocole GEM, y compris la génération des circuits, la soumission des tâches et l'analyse des données. La cellule de code suivante initialise la classe d'expérience en restreignant le réseau de plaquettes à seulement deux plaquettes (21 qubits), réduisant ainsi la taille de l'expérience pour garantir que le bruit du matériel ne submerge pas le signal.

gem_exp = GemExperiment(plaquette_lattice.filter([9, 12]), backend=backend)

# visualize the plaquette lattice after filtering
plaquette_lattice.filter([9, 12]).draw_qubits()

Output of the previous code cell

Un circuit du protocole GEM est construit en suivant les étapes suivantes :

  1. Préparer l'état tout-+|+\rangle en appliquant une porte de Hadamard à chaque qubit.
  2. Appliquer une porte RZZR_{ZZ} entre chaque paire de qubits connectés. Cela peut être réalisé en 3 couches de portes. Chaque porte RZZR_{ZZ} agit sur un qubit site et un qubit liaison. Si le qubit site est étiqueté (B), alors l'angle est fixé à π2\frac{\pi}{2}. Si le qubit site est étiqueté (A), alors l'angle est libre de varier, produisant différents circuits. Par défaut, la plage d'angles est définie sur 21 points également espacés entre 00 et π2\frac{\pi}{2}, inclus.
  3. Mesurer chaque qubit liaison dans la base de Pauli XX. Comme les qubits sont mesurés dans la base de Pauli ZZ, cela peut être accompli en appliquant une porte de Hadamard avant de mesurer le qubit.

Notez que l'article cité dans l'introduction de ce tutoriel utilise une convention différente pour l'angle RZZR_{ZZ}, qui diffère de la convention utilisée dans ce tutoriel par un facteur de 2.

À l'étape 3, seuls les qubits liaison sont mesurés. Pour comprendre dans quel état se trouvent les qubits site restants, il est instructif de considérer le cas où l'angle RZZR_{ZZ} appliqué aux qubits site (A) à l'étape 2 est égal à π2\frac{\pi}{2}. Dans ce cas, les qubits site sont laissés dans un état fortement intriqué similaire à l'état GHZ,

GHZ=0000+1111.\lvert \text{GHZ} \rangle = \lvert 00 \cdots 00 \rangle + \lvert 11 \cdots 11 \rangle.

En raison du caractère aléatoire des résultats de mesure, l'état réel des qubits site pourrait être un état différent présentant un ordre à longue portée, par exemple, 00110+11001\lvert 00110 \rangle + \lvert 11001 \rangle. Cependant, l'état GHZ peut être récupéré en appliquant une opération de décodage basée sur les résultats de mesure. Lorsque l'angle RZZR_{ZZ} est réduit à partir de π2\frac{\pi}{2}, l'ordre à longue portée peut encore être récupéré jusqu'à un angle critique, qui, en l'absence de bruit, est d'environ 0.3π0.3 \pi. En dessous de cet angle, l'état résultant ne présente plus d'intrication à longue portée. Cette transition entre la présence et l'absence d'ordre à longue portée est la transition de phase de Nishimori.

Dans la description ci-dessus, les qubits site n'étaient pas mesurés, et l'opération de décodage peut être effectuée en appliquant des portes quantiques. Dans l'expérience telle qu'implémentée dans la GEM suite, que ce tutoriel suit, les qubits site sont en réalité mesurés, et l'opération de décodage est appliquée lors d'une étape de post-traitement classique.

Dans la description ci-dessus, l'opération de décodage peut être effectuée en appliquant des portes quantiques aux qubits site pour récupérer l'état quantique. Cependant, si l'objectif est de mesurer immédiatement l'état, par exemple à des fins de caractérisation, alors les qubits site sont mesurés en même temps que les qubits liaison, et l'opération de décodage peut être appliquée lors d'une étape de post-traitement classique. C'est ainsi que l'expérience est implémentée dans la GEM suite, que ce tutoriel suit.

En plus de dépendre de l'angle RZZR_{ZZ} à l'étape 2, qui par défaut balaye 21 valeurs, le circuit du protocole GEM dépend également du schéma d'ordonnancement utilisé pour implémenter les 3 couches de portes RZZR_{ZZ}. Comme discuté précédemment, il existe 12 schémas d'ordonnancement de ce type. Par conséquent, le nombre total de circuits dans l'expérience est de 21×12=25221 \times 12 = 252.

Les circuits de l'expérience peuvent être générés en utilisant la méthode circuits de la classe GemExperiment.

circuits = gem_exp.circuits()
print(f"Total number of circuits: {len(circuits)}")
Total number of circuits: 252

Pour les besoins de ce tutoriel, il suffit de considérer un seul schéma d'ordonnancement. La cellule de code suivante restreint l'expérience au premier schéma d'ordonnancement. En conséquence, l'expérience ne comporte que 21 circuits, un pour chaque angle RZZR_{ZZ} balayé.

# Restrict experiment to the first scheduling pattern
gem_exp.set_experiment_options(schedule_idx=0)

# There are less circuits now
circuits = gem_exp.circuits()
print(f"Total number of circuits: {len(circuits)}")

# Print the RZZ angles swept over
print(f"RZZ angles:\n{gem_exp.parameters()}")
Total number of circuits: 21
RZZ angles:
[0. 0.07853982 0.15707963 0.23561945 0.31415927 0.39269908
0.4712389 0.54977871 0.62831853 0.70685835 0.78539816 0.86393798
0.9424778 1.02101761 1.09955743 1.17809725 1.25663706 1.33517688
1.41371669 1.49225651 1.57079633]

La cellule de code suivante dessine un diagramme du circuit à l'indice 5. Pour réduire la taille du diagramme, les portes de mesure à la fin du circuit sont supprimées.

# Get the circuit at index 5
circuit = circuits[5]
# Remove the final measurements to ease visualization
circuit.remove_final_measurements()
# Draw the circuit
circuit.draw("mpl", fold=-1, scale=0.5)

Output of the previous code cell

Étape 2 : Optimiser le problème pour l'exécution sur le matériel quantique

La transpilation des circuits quantiques pour l'exécution sur le matériel implique généralement un certain nombre d'étapes. En règle générale, les étapes qui entraînent le plus de surcharge de calcul sont le choix de la disposition des qubits, le routage des portes à deux qubits pour se conformer à la connectivité des qubits du matériel, et l'optimisation du circuit pour minimiser son nombre de portes et sa profondeur. Dans le protocole GEM, les étapes de disposition et de routage sont inutiles car la connectivité du matériel est déjà intégrée dans la conception du protocole. Les circuits disposent déjà d'une disposition de qubits, et les portes à deux qubits sont déjà mappées sur les connexions natives. De plus, afin de préserver la structure du circuit lorsque l'angle RZZR_{ZZ} varie, seule une optimisation de circuit très basique doit être effectuée.

La classe GemExperiment transpile les circuits de manière transparente lors de l'exécution de l'expérience. Les étapes de disposition et de routage sont déjà remplacées par défaut pour ne rien faire, et l'optimisation du circuit est effectuée à un niveau qui n'optimise que les portes à un seul qubit. Cependant, vous pouvez remplacer ou passer des options supplémentaires en utilisant la méthode set_transpile_options. À des fins de visualisation, la cellule de code suivante transpile manuellement le circuit affiché précédemment et dessine le circuit transpilé.

# Demonstrate setting transpile options
gem_exp.set_transpile_options(
optimization_level=1 # This is the default optimization level
)
pass_manager = generate_preset_pass_manager(
backend=backend,
initial_layout=list(gem_exp.physical_qubits),
**dict(gem_exp.transpile_options),
)
transpiled = pass_manager.run(circuit)
transpiled.draw("mpl", idle_wires=False, fold=-1, scale=0.5)

Output of the previous code cell

Étape 3 : Exécuter à l'aide des primitives Qiskit

Pour exécuter les circuits du protocole GEM sur le matériel, appelez la méthode run de l'objet GemExperiment. Vous pouvez spécifier le nombre de tirs que vous souhaitez échantillonner pour chaque circuit. La méthode run renvoie un objet ExperimentData que vous devez enregistrer dans une variable. Notez que la méthode run soumet uniquement les tâches sans attendre leur achèvement, il s'agit donc d'un appel non bloquant.

exp_data = gem_exp.run(shots=10_000)

Pour attendre les résultats, appelez la méthode block_for_results de l'objet ExperimentData. Cet appel fera attendre l'interpréteur jusqu'à ce que les tâches soient terminées.

exp_data.block_for_results()
ExperimentData(GemExperiment, d0d5880a-34c1-4aab-a7b6-c4f58516bc03, job_ids=['cwg12ptmptp00082khhg'], metadata=<5 items>, figure_names=['two_point_correlation.svg', 'normalized_variance.svg', 'plaquette_ops.svg', 'bond_ops.svg'])

Étape 4 : Post-traiter et renvoyer le résultat dans le format classique souhaité

À un angle RZZR_{ZZ} de π2\frac{\pi}{2}, l'état décodé serait l'état GHZ en l'absence de bruit. L'ordre à longue portée de l'état GHZ peut être visualisé en traçant l'aimantation des chaînes de bits mesurées. L'aimantation MM est définie comme la somme des opérateurs de Pauli ZZ à un seul qubit,

M=j=1NZj,M = \sum_{j=1}^N Z_j,

NN est le nombre de qubits site. Sa valeur pour une chaîne de bits est égale à la différence entre le nombre de zéros et le nombre de uns. Mesurer l'état GHZ donne l'état tout zéros ou l'état tout uns avec une probabilité égale, de sorte que l'aimantation serait +N+N la moitié du temps et N-N l'autre moitié du temps. En présence d'erreurs dues au bruit, d'autres valeurs apparaîtraient également, mais si le bruit n'est pas trop important, la distribution resterait piquée près de +N+N et N-N.

Pour les chaînes de bits brutes avant décodage, la distribution de l'aimantation serait équivalente à celle de chaînes de bits uniformément aléatoires, en l'absence de bruit.

La cellule de code suivante trace l'aimantation des chaînes de bits brutes et des chaînes de bits décodées à l'angle RZZR_{ZZ} de π2\frac{\pi}{2}.

def magnetization_distribution(
counts_dict: dict[str, int],
) -> dict[str, float]:
"""Compute magnetization distribution from counts dictionary."""
# Construct dictionary from magnetization to count
mag_dist = defaultdict(float)
for bitstring, count in counts_dict.items():
mag = bitstring.count("0") - bitstring.count("1")
mag_dist[mag] += count
# Normalize
shots = sum(counts_dict.values())
for mag in mag_dist:
mag_dist[mag] /= shots
return mag_dist

# Get counts dictionaries with and without decoding
data = exp_data.data()
# Get the last data point, which is at the angle for the GHZ state
raw_counts = data[-1]["counts"]
# Without decoding
site_indices = [
i for i, q in enumerate(gem_exp.plaquettes.qubits()) if q.role == "Site"
]
site_raw_counts = defaultdict(int)
for key, val in raw_counts.items():
site_str = "".join(key[-1 - i] for i in site_indices)
site_raw_counts[site_str] += val
# With decoding
_, site_decoded_counts = gem_exp.plaquettes.decode_outcomes(
raw_counts, return_counts=True
)

# Compute magnetization distribution
raw_magnetization = magnetization_distribution(site_raw_counts)
decoded_magnetization = magnetization_distribution(site_decoded_counts)

# Plot
plt.bar(*zip(*raw_magnetization.items()), label="raw")
plt.bar(*zip(*decoded_magnetization.items()), label="decoded", width=0.3)
plt.legend()
plt.xlabel("Magnetization")
plt.ylabel("Frequency")
plt.title("Magnetization distribution with and without decoding")
Text(0.5, 1.0, 'Magnetization distribution with and without decoding')

Output of the previous code cell

Pour caractériser plus rigoureusement l'ordre à longue portée, vous pouvez examiner la corrélation moyenne à deux points ff, définie comme

f=1N2(M2M2).f = \frac{1}{N^2} \left(\langle M^2 \rangle - \langle M \rangle ^2\right).

Une valeur plus élevée indique un degré d'intrication plus important. La classe GemExperiment calcule automatiquement cette valeur pour les chaînes de bits décodées dans le cadre du traitement des données expérimentales. Elle stocke une figure accessible via la méthode figure de la classe de données expérimentales. Dans ce cas, le nom de la figure est two_point_correlation.

exp_data.figure("two_point_correlation")

Output of the previous code cell

Pour déterminer le point critique de la transition de phase de Nishimori, vous pouvez examiner la variance normalisée de M2/NM^2 / N, définie comme

g=1N3(M4M22),g = \frac{1}{N^3} \left(\langle M^4 \rangle - \langle M^2 \rangle^2\right),

qui quantifie la quantité de fluctuation de l'aimantation au carré. Cette valeur est maximisée au point critique de la transition de phase de Nishimori. En l'absence de bruit, le point critique se situe à environ 0.3π0.3 \pi. En présence de bruit, le point critique est décalé vers le haut, mais la transition de phase est toujours observée tant que le point critique se situe en dessous de 0.5π0.5 \pi.

exp_data.figure("normalized_variance")

Output of the previous code cell

Mise à l'échelle de l'expérience

Les cellules de code suivantes exécutent l'expérience pour six plaquettes (49 qubits) et l'ensemble des 12 plaquettes (125 qubits) et tracent la variance normalisée. À mesure que l'expérience est mise à l'échelle vers des tailles plus grandes, la quantité plus importante de bruit décale le point critique vers la droite.

gem_exp = GemExperiment(
plaquette_lattice.filter(range(3, 9)), backend=backend
)
gem_exp.set_experiment_options(schedule_idx=0)
exp_data = gem_exp.run(shots=10_000)
exp_data.block_for_results()
exp_data.figure("normalized_variance")

Output of the previous code cell

gem_exp = GemExperiment(plaquette_lattice, backend=backend)
gem_exp.set_experiment_options(schedule_idx=0)
exp_data = gem_exp.run(shots=10_000)
exp_data.block_for_results()
exp_data.figure("normalized_variance")

Output of the previous code cell

Conclusion

Dans ce tutoriel, vous avez réalisé une transition de phase de Nishimori sur un processeur quantique en utilisant le protocole GEM. Les métriques que vous avez examinées lors du post-traitement, en particulier la corrélation à deux points et la variance normalisée, servent de benchmarks de la capacité du dispositif à générer des états intriqués à longue portée. Ces benchmarks étendent l'utilité du protocole GEM au-delà de l'exploration de phénomènes physiques intéressants. Dans le cadre du protocole, vous avez intriqué des qubits à travers l'ensemble du dispositif en utilisant des circuits de profondeur constante uniquement. Cet exploit n'est possible que grâce à l'utilisation par le protocole de mesures en milieu de circuit. Dans cette expérience, l'état intriqué a été immédiatement mesuré, mais une piste intéressante à explorer serait de continuer à utiliser cet état dans un traitement quantique supplémentaire !

Enquête sur le tutoriel

Veuillez répondre à cette courte enquête pour nous faire part de vos commentaires sur ce tutoriel. Vos retours nous aideront à améliorer nos contenus et l'expérience utilisateur.

Lien vers l'enquête