Optimization Solver : une fonction Qiskit de Q-CTRL Fire Opal
Consulte la référence API
Les fonctions Qiskit sont une fonctionnalité expérimentale réservée aux utilisateurs des plans IBM Quantum® Premium, Flex et On-Prem (via l'API IBM Quantum Platform). Elles sont en version préliminaire et susceptibles d'évoluer.
Package versions
The code on this page was developed using the following requirements. We recommend using these versions or newer.
qiskit-ibm-runtime~=0.46.1
sympy~=1.14.0
Vue d'ensemble
Avec le Fire Opal Optimization Solver, tu peux résoudre des problèmes d'optimisation à l'échelle utilitaire sur du matériel quantique, sans avoir besoin d'expertise en informatique quantique. Il suffit de fournir la définition du problème de haut niveau — le Solver s'occupe du reste. L'ensemble du flux de travail est sensible au bruit et exploite la gestion des performances Fire Opal en arrière-plan. Le Solver fournit de manière constante des solutions précises à des problèmes difficiles à résoudre classiquement, même à l'échelle complète d'un appareil sur les plus grands QPU IBM®.
Le Solver est flexible et peut être utilisé pour résoudre des problèmes d'optimisation combinatoire définis comme des fonctions objectif ou des graphes arbitraires. Les problèmes n'ont pas à être mappés à la topologie de l'appareil. Les problèmes non contraints et contraints sont résolubles, à condition que les contraintes puissent être formulées comme des termes de pénalité. Les exemples de ce guide montrent comment résoudre un problème d'optimisation non contraint et un problème contraint à l'échelle utilitaire en utilisant différents types d'entrées du Solver. Le premier exemple porte sur un problème max-cut défini sur un graphe 3-régulier à 156 nœuds, tandis que le second aborde un problème de couverture minimale de sommets (Minimum Vertex Cover) à 50 nœuds défini par une fonction de coût.
Pour accéder à l'Optimization Solver, contacte Q-CTRL.
Description de la fonction
Le Solver optimise et automatise entièrement l'algorithme, depuis la suppression des erreurs au niveau matériel jusqu'au mappage efficace du problème et à l'optimisation classique en boucle fermée. En coulisses, le pipeline du Solver réduit les erreurs à chaque étape, permettant d'atteindre les performances nécessaires pour monter en charge de façon significative. Le flux de travail sous-jacent s'inspire de l'algorithme QAOA (Quantum Approximate Optimization Algorithm), un algorithme hybride quantique-classique. Pour un résumé détaillé du flux de travail complet de l'Optimization Solver, consulte le manuscrit publié.
Pour résoudre un problème générique avec l'Optimization Solver :
- Définis ton problème sous forme de fonction objectif, de graphe ou de chaîne de spin
SparsePauliOp. - Connecte-toi à la fonction via le catalogue de fonctions Qiskit.
- Lance le problème avec le Solver et récupère les résultats.
Formats de problèmes acceptés
- Représentation polynomiale d'une fonction objectif. Idéalement créée en Python à partir d'un objet SymPy Poly existant et mise en chaîne avec sympy.srepr.
- Représentation par graphe d'un type de problème spécifique. Le graphe doit être créé avec la bibliothèque networkx en Python, puis converti en chaîne via la fonction networkx
[nx.readwrite.json_graph.adjacency_data](http://nx.readwrite.json_graph.adjacency_data.). - Représentation en chaîne de spin d'un problème spécifique. La chaîne de spin doit être représentée sous la forme d'un objet
SparsePauliOp; consulte la documentation pour plus de détails.
Backends pris en charge
Exécute le code suivant pour voir la liste des backends actuellement pris en charge. Si ton appareil n'est pas listé, contacte Q-CTRL pour en demander la prise en charge.
# Added by doQumentation — required packages for this notebook
!pip install -q networkx numpy qiskit-ibm-catalog qiskit-ibm-runtime sympy
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
service.backends()
[<IBMBackend('ibm_boston')>,
<IBMBackend('ibm_pittsburgh')>,
<IBMBackend('ibm_fez')>,
<IBMBackend('ibm_marrakesh')>,
<IBMBackend('ibm_kingston')>,
<IBMBackend('ibm_miami')>]
Benchmarks
Les résultats de benchmarking publiés montrent que le Solver résout avec succès des problèmes dépassant 120 qubits, surpassant même des résultats précédemment publiés sur des recuits quantiques et des appareils à ions piégés. Les métriques de benchmark suivantes donnent une indication approximative de la précision et de la mise à l'échelle des types de problèmes, sur la base de quelques exemples. Les métriques réelles peuvent varier selon les caractéristiques du problème, comme le nombre de termes dans la fonction objectif (densité) et leur localité, le nombre de variables et l'ordre polynomial.
Le « Nombre de qubits » indiqué n'est pas une limite absolue, mais représente des seuils approximatifs en dessous desquels tu peux t'attendre à une précision de solution extrêmement constante. Des tailles de problèmes plus importantes ont été résolues avec succès, et les tests au-delà de ces limites sont encouragés.
La connectivité arbitraire entre qubits est prise en charge pour tous les types de problèmes.
| Type de problème | Nombre de qubits | Exemple | Précision | Temps total (s) | Utilisation du runtime (s) | Nombre d'itérations |
|---|---|---|---|---|---|---|
| Problèmes quadratiques faiblement connectés | 156 | Max-Cut 3-régulier | 100 % | 1764 | 293 | 16 |
| Optimisation binaire d'ordre supérieur | 156 | Modèle de verre de spin d'Ising | 100 % | 1461 | 272 | 16 |
| Problèmes quadratiques densément connectés | 50 | Max-Cut entièrement connecté | 100 % | 1758 | 268 | 12 |
| Problème contraint avec termes de pénalité | 50 | Couverture minimale de sommets pondérée avec 8 % de densité d'arêtes | 100 % | 1074 | 215 | 10 |
Premiers pas
Commence par t'authentifier avec ta clé API IBM Quantum. Sélectionne ensuite la fonction Qiskit comme suit. (Cet extrait suppose que tu as déjà enregistré ton compte dans ton environnement local.)
from qiskit_ibm_catalog import QiskitFunctionsCatalog
catalog = QiskitFunctionsCatalog(channel="ibm_quantum_platform")
# Access Function
solver = catalog.load("q-ctrl/optimization-solver")
Exemple : optimisation non contrainte
Lance le problème de coupe maximale (Max-Cut). L'exemple suivant illustre les capacités du Solver sur un problème Max-Cut avec un graphe non pondéré 3-régulier à 156 nœuds, mais tu peux aussi résoudre des problèmes de graphes pondérés.
En plus de qiskit-ibm-catalog, tu utiliseras également les packages suivants pour cet exemple : networkx et numpy. Tu peux les installer en décommentant la cellule suivante si tu exécutes cet exemple dans un notebook avec le noyau IPython.
# %pip install networkx numpy
1. Définir le problème
Tu peux lancer un problème Max-Cut en définissant un problème de graphe et en spécifiant problem_type='maxcut'.
import networkx as nx
import numpy as np
# Generate a random graph with 156 nodes
maxcut_graph = nx.random_regular_graph(d=3, n=156, seed=8)
# Optionally, visualize the graph
nx.draw_networkx(
maxcut_graph, nx.kamada_kawai_layout(maxcut_graph), node_size=100
)
Le Solver accepte une chaîne de caractères comme entrée pour la définition du problème.
# Convert graph to string
problem_as_str = nx.readwrite.json_graph.adjacency_data(maxcut_graph)
2. Lancer le problème
Lorsque tu utilises la méthode d'entrée par graphe, spécifie le type de problème.
# This cell is hidden from users
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
backend_name = service.least_busy(n_qubits=156).name
# Solve the problem
maxcut_job = solver.run(
problem=problem_as_str,
problem_type="maxcut",
backend_name=backend_name, # E.g. "ibm_fez"
)
Vérifie le statut de ta charge de travail de fonction Qiskit ou récupère les résultats comme suit :
# Get job status
print(maxcut_job.status())
QUEUED
3. Récupérer le résultat
Récupère la valeur de coupe optimale depuis le dictionnaire de résultats.
La correspondance des variables vers la chaîne de bits peut avoir changé. Le dictionnaire de sortie contient un sous-dictionnaire variables_to_bitstring_index_map qui permet de vérifier l'ordre.
# Poll for results
maxcut_result = maxcut_job.result()
# Take the absolute value of the solution since the cost function is minimized
qctrl_maxcut = abs(maxcut_result["solution_bitstring_cost"])
# Print the optimal cut value found by the Optimization Solver
print(f"Optimal cut value: {qctrl_maxcut}")
Optimal cut value: 210.0
Tu peux vérifier la précision du résultat en résolvant le problème classiquement avec des solveurs open-source comme PuLP si le graphe n'est pas densément connecté. Les problèmes à haute densité peuvent nécessiter des solveurs classiques avancés pour valider la solution.