Aller au contenu principal

Atténuation des erreurs avec la fonction IBM Circuit

Remarque

Les fonctions Qiskit sont une fonctionnalité expérimentale disponible uniquement pour les utilisateurs des plans IBM Quantum® Premium, Flex et On-Prem (via l'API IBM Quantum Platform). Elles sont en version préliminaire et sont susceptibles d'être modifiées.

Estimation d'utilisation : 26 minutes sur un processeur Eagle (REMARQUE : il s'agit d'une estimation uniquement. Ton temps d'exécution peut varier.) Ce tutoriel présente un exemple de construction et d'exécution d'un workflow utilisant la fonction IBM Circuit. Cette fonction prend des Primitive Unified Blocs (PUBs) en entrée et renvoie des valeurs d'espérance avec atténuation des erreurs en sortie. Elle fournit un pipeline automatisé et personnalisé pour optimiser les circuits et les exécuter sur du matériel quantique, afin que les chercheurs puissent se concentrer sur la découverte d'algorithmes et d'applications.

Consulte la documentation pour une introduction aux fonctions Qiskit et apprends comment démarrer avec la fonction IBM Circuit.

Contexte

Ce tutoriel considère un circuit général d'évolution temporelle de Trotter, efficace pour le matériel, pour le modèle d'Ising à champ transverse en 2D, et calcule la magnétisation globale. Un tel circuit est utile dans différents domaines d'application tels que la physique de la matière condensée, la chimie et l'apprentissage automatique. Pour plus d'informations sur la structure de ce modèle, consulte Nature 618, 500-505 (2023).

La fonction IBM Circuit combine les capacités du service de transpilation Qiskit et de l'estimateur Qiskit Runtime pour fournir une interface simplifiée d'exécution des circuits. La fonction effectue la transpilation, la suppression des erreurs, l'atténuation des erreurs et l'exécution des circuits au sein d'un seul service géré, afin que nous puissions nous concentrer sur la correspondance entre le problème et les circuits plutôt que sur la construction de chaque étape du processus.

Prérequis

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

  • Qiskit SDK v1.2 ou version ultérieure (pip install qiskit)
  • Qiskit Runtime v0.28 ou version ultérieure (pip install qiskit-ibm-runtime)
  • Client IBM Qiskit Functions Catalog v0.0.0 ou version ultérieure (pip install qiskit-ibm-catalog)
  • Qiskit Aer v0.15.0 ou version ultérieure (pip install qiskit-aer)

Configuration

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-catalog qiskit-ibm-runtime rustworkx
import rustworkx
from collections import defaultdict
from numpy import pi, mean

from qiskit_ibm_runtime import QiskitRuntimeService

from qiskit_ibm_catalog import QiskitFunctionsCatalog

from qiskit.circuit import QuantumCircuit, Parameter
from qiskit.quantum_info import SparsePauliOp

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

  • Entrée : Paramètres pour créer le circuit quantique
  • Sortie : Circuit abstrait et observables

Construire le circuit

Le circuit que nous allons créer est un circuit d'évolution temporelle de Trotter, efficace pour le matériel, pour le modèle d'Ising à champ transverse en 2D. Nous commençons par sélectionner un backend. Les propriétés de ce backend (c'est-à-dire sa carte de couplage) seront utilisées pour définir le problème quantique et garantir qu'il est efficace pour le matériel.

service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)

Ensuite, nous obtenons la carte de couplage à partir du backend.

coupling_graph = backend.coupling_map.graph.to_undirected(multigraph=False)
layer_couplings = defaultdict(list)

Nous devons être attentifs à la conception des couches de notre circuit. Pour cela, nous allons colorer les arêtes de la carte de couplage (c'est-à-dire regrouper les arêtes disjointes) et utiliser cette coloration pour placer plus efficacement les portes dans le circuit. Cela produira un circuit moins profond avec des couches de portes pouvant être exécutées simultanément sur le matériel.

edge_coloring = rustworkx.graph_bipartite_edge_color(coupling_graph)

for edge_idx, color in edge_coloring.items():
layer_couplings[color].append(
coupling_graph.get_edge_endpoints_by_index(edge_idx)
)
layer_couplings = [
sorted(layer_couplings[i]) for i in sorted(layer_couplings.keys())
]

Ensuite, nous écrivons une fonction auxiliaire simple qui implémente le circuit d'évolution temporelle de Trotter, efficace pour le matériel, pour le modèle d'Ising à champ transverse en 2D, en utilisant la coloration des arêtes obtenue ci-dessus.

def construct_trotter_circuit(
num_qubits: int,
num_trotter_steps: int,
layer_couplings: list,
barrier: bool = True,
) -> QuantumCircuit:
theta, phi = Parameter("theta"), Parameter("phi")
circuit = QuantumCircuit(num_qubits)

for _ in range(num_trotter_steps):
circuit.rx(theta, range(num_qubits))
for layer in layer_couplings:
for edge in layer:
if edge[0] < num_qubits and edge[1] < num_qubits:
circuit.rzz(phi, edge[0], edge[1])
if barrier:
circuit.barrier()

return circuit

Nous allons choisir le nombre de qubits et d'étapes de Trotter, puis construire le circuit.

num_qubits = 100
num_trotter_steps = 2

circuit = construct_trotter_circuit(
num_qubits, num_trotter_steps, layer_couplings
)
circuit.draw("mpl", fold=-1)

Sortie de la cellule de code précédente

Afin d'évaluer la qualité de l'exécution, nous devons la comparer avec le résultat idéal. Le circuit choisi dépasse les capacités de simulation classique par force brute. Nous fixons donc les paramètres de toutes les portes Rx du circuit à 00, et ceux de toutes les portes Rzz à π\pi. Cela rend le circuit de type Clifford, ce qui permet d'effectuer la simulation idéale et d'obtenir le résultat idéal pour la comparaison. Dans ce cas, nous savons que le résultat sera 1.0.

parameters = [0, pi]

Construire l'observable

Tout d'abord, calculez la magnétisation globale selon z^\hat{z} pour le problème à NN qubits : Mz=i=1NZi/NM_z = \sum_{i=1}^N \langle Z_i \rangle / N. Cela nécessite d'abord de calculer la magnétisation par site Zi\langle Z_i \rangle pour chaque qubit ii, qui est définie dans le code suivant.

observables = []
for i in range(num_qubits):
obs = "I" * (i) + "Z" + "I" * (num_qubits - i - 1)
observables.append(SparsePauliOp(obs))

print(observables[0])
SparsePauliOp(['ZIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII'],
coeffs=[1.+0.j])

Étapes 2 et 3 : Optimiser le problème pour l'exécution sur matériel quantique et exécuter avec la fonction IBM Circuit

  • Entrée : Circuit abstrait et observables
  • Sortie : Valeurs d'espérance avec atténuation des erreurs

Nous pouvons maintenant transmettre le circuit abstrait et les observables à la fonction IBM Circuit. Elle se chargera de la transpilation et de l'exécution sur le matériel quantique pour nous, et renverra des valeurs d'espérance avec atténuation des erreurs. Tout d'abord, nous chargeons la fonction depuis le catalogue IBM Qiskit Functions.

catalog = QiskitFunctionsCatalog(
token="<YOUR_API_KEY>"
) # Use the 44-character API_KEY you created and saved from the IBM Quantum Platform Home dashboard
function = catalog.load("ibm/circuit-function")

La fonction IBM Circuit prend des pubs, un backend_name, ainsi que des entrées optionnelles pour configurer la transpilation, l'atténuation des erreurs, etc. Nous créons le pub à partir du circuit abstrait, des observables et des paramètres du circuit. Le nom du backend doit être spécifié sous forme de chaîne de caractères.

pubs = [(circuit, observables, parameters)]
backend_name = backend.name

Nous pouvons également configurer les options pour la transpilation, la suppression des erreurs et l'atténuation des erreurs. Les paramètres par défaut seront utilisés si nous ne souhaitons pas les spécifier. La fonction IBM Circuit propose des options couramment utilisées pour optimization_level, qui contrôle le degré d'optimisation du circuit, et mitigation_level, qui spécifie le degré de suppression et d'atténuation des erreurs à appliquer. Note que le mitigation_level de la fonction IBM Circuit est distinct du resilience_level utilisé dans l'estimateur Qiskit Runtime. Pour une description détaillée de ces options courantes ainsi que d'autres options avancées, consulte la documentation de la fonction IBM Circuit.

Dans ce tutoriel, nous définirons default_precision, optimization_level: 3 et mitigation_level: 3, ce qui activera le twirling de portes et l'extrapolation de bruit zéro (ZNE) via l'amplification probabiliste des erreurs (PEA) en plus des paramètres par défaut du niveau 1.

options = {
"default_precision": 0.011,
"optimization_level": 3,
"mitigation_level": 3,
}

Avec les entrées spécifiées, nous soumettons la tâche à la fonction IBM Circuit pour optimisation et exécution.

job = function.run(backend_name=backend_name, pubs=pubs, options=options)

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

  • Entrée : Résultats de la fonction IBM Circuit
  • Sortie : Magnétisation globale

Calculer la magnétisation globale

Le résultat de l'exécution de la fonction a le même format que l'estimateur.

result = job.result()[0]

Nous obtenons les valeurs d'espérance avec et sans atténuation des erreurs à partir de ce résultat. Ces valeurs d'espérance représentent la magnétisation par site selon la direction z^\hat{z}. Nous les moyennons pour obtenir la magnétisation globale et comparons avec la valeur idéale de 1.0 pour cette instance du problème.

mitigated_expvals = result.data.evs
magnetization_mitigated = mean(mitigated_expvals)

print("mitigated:", magnetization_mitigated)

unmitigated_expvals = [
result.data.evs_extrapolated[i][0][1] for i in range(num_qubits)
]
magnetization_unmitigated = mean(unmitigated_expvals)

print("unmitigated:", magnetization_unmitigated)
mitigated: 0.9749883476088692
unmitigated: 0.7832977198447583

Enquête sur le tutoriel

Réponds à cette courte enquête pour nous faire part de tes commentaires sur ce tutoriel. Tes retours nous aideront à améliorer nos contenus et l'expérience utilisateur.

Lien vers l'enquête