Optimization Solver : une fonction Qiskit par Q-CTRL Fire Opal
Consultez la documentation de l'API
Les fonctions Qiskit sont une fonctionnalité expérimentale disponible uniquement pour IBM Quantum® Premium Plan, Flex Plan, et On-Prem (via IBM Quantum Platform API). Elles sont en cours de publication et peuvent être modifiées.
Le code présenté sur cette page a été développé en respectant les exigences suivantes. Nous vous recommandons d'utiliser ces versions ou des versions plus récentes.
qiskit-ibm-runtime~=0.47.0 sympy~=1.14.0
Aperçu
Avec le solveur d'optimisation Fire Opal, vous pouvez résoudre des problèmes d'optimisation à grande échelle sur du matériel quantique sans avoir besoin d'expertise quantique. Il suffit de saisir la définition du problème de haut niveau, et le Solveur s'occupe du reste. L'ensemble du flux de travail est sensible au bruit et tire parti de la gestion des performances de Fire Opal. Le Solveur fournit systématiquement des solutions précises à des problèmes classiques, même à l'échelle d'un appareil complet sur les plus grandes QPU IBM®.
Le solveur est polyvalent et peut être utilisé pour résoudre des problèmes d'optimisation combinatoire définis sous forme de fonctions objectif ou de graphes arbitraires. Il n'est pas nécessaire de faire correspondre les problèmes à la topologie du dispositif. On peut résoudre aussi bien les problèmes sans contraintes que ceux avec contraintes, à condition que ces dernières puissent être formulées sous forme de termes de pénalité. Les exemples présentés dans ce guide montrent comment résoudre un problème d'optimisation à grande échelle, avec ou sans contraintes, en utilisant différents types de données d'entrée pour le solveur. Le premier exemple porte sur un problème de coupe maximale défini sur un graphe régulier de degré 3 comptant 156 nœuds, tandis que le second exemple traite d'un problème de couverture minimale des sommets défini par une fonction de coût et portant sur un graphe de 50 nœuds.
Pour obtenir l'accès au solveur d'optimisation, contactez Q-CTRL.
Description de la fonction
Le Solver optimise et automatise entièrement l'algorithme, de la suppression des erreurs au niveau matériel à la cartographie efficace des problèmes et à l'optimisation classique en boucle fermée. En coulisses, le pipeline du Solveur réduit les erreurs à chaque étape, ce qui permet d'améliorer les performances requises pour une mise à l'échelle significative. Le processus sous-jacent s'inspire de l'algorithme d'optimisation approximative quantique (QAOA), qui est un algorithme hybride quantique-classique. Pour un résumé détaillé du flux de travail complet d'Optimization Solver, veuillez vous référer au manuscrit publié.
Pour résoudre un problème générique avec le solveur d'optimisation :
- Définissez votre problème sous la forme d'une fonction objective, d'un graphique ou d'une chaîne de spin (
SparsePauliOp). - Connectez-vous à la fonction via le catalogue de fonctions Qiskit.
- Exécutez le problème avec le Solveur et récupérez les résultats.
Formats de problèmes acceptés
- Représentation de l'expression polynomiale d'une fonction objective. Idéalement créé dans Python avec un objet Poly existant SymPy et formaté dans une chaîne de caractères à l'aide de sympy.srepr.
- Représentation graphique d'un type de problème spécifique. Le graphique doit être créé à l'aide de la bibliothèque networkx dans Python. Il doit ensuite être converti en chaîne de caractères à l'aide de la fonction networkx
[nx.readwrite.json_graph.adjacency_data](http://nx.readwrite.json_graph.adjacency_data.). - Représentation en chaîne d'un problème spécifique. La chaîne de spin doit être représentée sous la forme d'un objet
SparsePauliOp; voir la documentation pour plus de détails.
Si vous souhaitez utiliser un backend qui n'est pas encore pris en charge par cette fonction, contactez Q-CTRL pour qu'il soit ajouté.
Tests de performances
Les résultats d'étalonnage publiés montrent que le Solver résout avec succès des problèmes avec plus de 120 qubits, surpassant même les résultats précédemment publiés sur le recuit quantique et les dispositifs à ions piégés. Les mesures de référence suivantes donnent une indication approximative de la précision et de l'étendue des types de problèmes sur la base de quelques exemples. Les mesures réelles peuvent différer en fonction de diverses caractéristiques du problème, telles que le nombre de termes dans la fonction objective (densité) et leur localisation, 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 pour lesquels on peut s'attendre à une précision extrêmement constante des solutions. Des problèmes de plus grande taille ont été résolus avec succès, et les essais au-delà de ces limites sont encouragés.
La connectivité arbitraire des qubits est prise en charge pour tous les types de problèmes.
Type de problème | Nombre de qubits | Exemple | Exactitude | Durée totale (s) | Utilisation du temps d'exécution (s) | Nombre d'itérations |
|---|---|---|---|---|---|---|
| Problèmes quadratiques à connexions éparses | 156 | 3-régulier max-cut | 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 pondérée des sommets avec une densité d'arêtes de 8% | 100 % | 1074 | 215 | 10 |
Premiers pas
Commencez par vous authentifier à l'aide de votre clé API IBM Quantum. Ensuite, sélectionnez la fonction Qiskit comme suit. (Cet extrait de code part du principe que vous avez déjà enregistré votre compte dans votre environnement local.)
from qiskit_ibm_catalog import QiskitFunctionsCatalog
catalog = QiskitFunctionsCatalog(channel="ibm_quantum_platform")
# Verify that you have access to the function
catalog.list()Output:
[QiskitFunction(qunova/hivqe-chemistry),
QiskitFunction(global-data-quantum/quantum-portfolio-optimizer),
QiskitFunction(algorithmiq/tem),
QiskitFunction(qedma/qesem),
QiskitFunction(multiverse/singularity),
QiskitFunction(ibm/circuit-function),
QiskitFunction(q-ctrl/optimization-solver),
QiskitFunction(colibritd/quick-pde),
QiskitFunction(q-ctrl/performance-management),
QiskitFunction(kipu-quantum/iskay-quantum-optimizer)]
# Access Function
solver = catalog.load("q-ctrl/optimization-solver")Exemple : optimisation sans contrainte
Résolvez le problème de la coupe maximale (max-cut). L'exemple suivant illustre les capacités du Solveur sur un problème de coupe maximale dans un graphe non pondéré à 3 arêtes régulières et 156 nœuds, mais vous pouvez également résoudre des problèmes sur des graphes pondérés.
En plus de qiskit-ibm-catalog, vous utiliserez également les paquets suivants pour exécuter cet exemple : networkx et numpy. Vous pouvez installer ces paquets en décommentant la cellule suivante si vous exécutez cet exemple dans un ordinateur portable utilisant le noyau IPython.
# %pip install networkx numpy1. Définir le problème
Vous pouvez résoudre un problème de coupe maximale 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
)Output:
Le Solveur accepte une chaîne de caractères comme entrée de la définition du problème.
# Convert graph to string
problem_as_str = nx.readwrite.json_graph.adjacency_data(maxcut_graph)2. Exécutez le problème
Lors de l'utilisation de la méthode de saisie basée sur un graphique, spécifiez le type de problème.
# Solve the problem
maxcut_job = solver.run(
problem=problem_as_str,
problem_type="maxcut",
backend_name=backend_name, # E.g. "ibm_fez"
)Pour vérifier l'état de votre charge de travail Qiskit Function ou obtenir les résultats, procédez comme suit :
# Print the ID so you can use it later, if necessary
print(maxcut_job.job_id)
# Get job status
print(maxcut_job.status())Output:
34b53970-d95a-4e24-8763-fc6f3d112843
QUEUED
3. Récupérer le résultat
Récupérer la valeur de coupe optimale dans le dictionnaire des résultats.
Le mappage des variables vers la chaîne de bits peut avoir changé. Le dictionnaire de sortie contient un variables_to_bitstring_index_map sous-dictionnaire qui aide à 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}")Output:
Optimal cut value: 210.0
Vous pouvez vérifier l'exactitude du résultat en résolvant le problème de manière classique avec des solveurs open-source tels que PuLP si le graphe n'est pas densément connecté. Les problèmes de haute densité peuvent nécessiter des solveurs classiques avancés pour valider la solution.
Exemple : optimisation sous contraintes
L'exemple précédent de « max-cut » est un problème courant d'optimisation binaire quadratique sans contraintes. Le solveur d'optimisation de Q-CTRL peut être utilisé pour divers types de problèmes, y compris l'optimisation sous contraintes. Vous pouvez résoudre des problèmes de nature quelconque en saisissant la formulation du problème sous forme de polynôme, dans lequel les contraintes sont modélisées sous forme de termes de pénalité.
L'exemple suivant montre comment construire une fonction de coût pour un problème d'optimisation avec contraintes, la couverture minimale des sommets (MVC).
En plus des paquets qiskit-ibm-catalog et qiskit , vous utiliserez également les paquets suivants pour exécuter cet exemple : numpy, networkx, et sympy. Vous pouvez installer ces paquets en décommentant la cellule suivante si vous exécutez cet exemple dans un ordinateur portable utilisant le noyau IPython.
# %pip install numpy networkx sympy1. Définir le problème
Définir un problème MVC aléatoire en générant un graphe dont les nœuds sont pondérés de manière aléatoire.
import networkx as nx
from sympy import symbols, Poly, srepr
# To change the weights, change the seed to any integer.
rng_seed = 18
_rng = np.random.default_rng(rng_seed)
node_count = 50
edge_probability = 0.08
mvc_graph = nx.erdos_renyi_graph(
node_count, edge_probability, seed=rng_seed, directed=False
)
# add node weights
for i in mvc_graph.nodes:
mvc_graph.add_node(i, weight=_rng.random())
# Optionally, visualize the graph
nx.draw_networkx(mvc_graph, nx.kamada_kawai_layout(mvc_graph), node_size=200)Output:
Un modèle d'optimisation standard pour le MVC pondéré peut être formulé comme suit. Tout d'abord, une pénalité doit être ajoutée dans tous les cas où une arête n'est pas connectée à un sommet du sous-ensemble. Par conséquent, laissez si le sommet est dans la couverture (c'est-à-dire dans le sous-ensemble) et dans le cas contraire. Deuxièmement, l'objectif est de minimiser le nombre total de sommets dans le sous-ensemble, ce qui peut être représenté par la fonction suivante :
# Construct the cost function.
variables = symbols([f"n[{i}]" for i in range(node_count)])
cost_function = Poly(0, variables)
for i in mvc_graph.nodes():
weight = mvc_graph.nodes[i].get("weight", 0)
cost_function += variables[i] * weightMaintenant, chaque arête du graphique doit inclure au moins un point d'extrémité de la couverture, ce qui peut être exprimé par l'inégalité :
Tous les cas où une arête n'est pas connectée au sommet de couverture doivent être pénalisés. Cela peut être représenté dans la fonction de coût par l'ajout d'une pénalité de la forme où est une constante de pénalité positive. Ainsi, une alternative non contrainte à l'inégalité contrainte pour la CVM pondérée est :
# Add penalty term.
penalty_constant = 2
for i, j in mvc_graph.edges():
cost_function += penalty_constant * (
1 - variables[i] - variables[j] + variables[i] * variables[j]
)2. Exécutez le problème
# Solve the problem
mvc_job = solver.run(
problem=srepr(cost_function),
backend_name=backend_name, # E.g. "ibm_fez"
)Pour vérifier l'état de votre charge de travail Qiskit Function ou obtenir les résultats, procédez comme suit :
print(mvc_job.status())Output:
QUEUED
3. Obtenir le résultat
Récupérer la solution et analyser les résultats. Comme ce problème comporte des nœuds pondérés, la solution n'est pas simplement le nombre minimum de nœuds couverts. Au lieu de cela, le coût de la solution représente la somme des poids des sommets inclus dans la couverture des sommets. Il représente le "coût" ou le "poids" total de la couverture de toutes les arêtes du graphe par les sommets sélectionnés.
mvc_result = mvc_job.result()
qctrl_cost = mvc_result["solution_bitstring_cost"]
# Print results
print(f"Solution cost: {qctrl_cost}")Output:
Solution cost: 10.248198273708624
Obtenir de l'aide
Pour toute question ou problème, contactez Q-CTRL.
Journal des modifications
- 11 février 2026 : Nous prenons désormais en charge
ibm_miami
Etapes suivantes
- Demander l'accès au solveur d'optimisation Q-CTRL.
- Consultez la documentation de l'API relative à cette fonction Qiskit.
- Essayez le tutoriel Résoudre des problèmes d'optimisation binaire d'ordre supérieur avec le solveur d'optimisation de Q-CTRL.
- Critique Sachdeva, N., et al. (2024). L'optimisation quantique à l'aide d'un ordinateur quantique à 127 qubits utilisant un modèle de porte IBM peut surpasser les annealeurs quantiques pour les problèmes d'optimisation binaire non triviaux. arXiv prépublication arXiv:2406.01743.
- Critique Loco, D., et al. (2026). Prédiction pratique des sites d'hydratation des poches protéiques pour la découverte de médicaments sur un ordinateur quantique. arXiv prépublication arXiv:2512.08390.
- Consultez l'étude de cas Mazda.
- Consultez l'étude de cas Network Rail.
- Examinez l'étude de cas sur l'armée australienne.
- Consultez l'étude de cas Transport for New South Wales.