Constrained Quantum Optimizer – Eine Qiskit-Funktion von Aqarios
Siehe API-Referenz
Qiskit Functions sind eine experimentelle Funktion, die ausschließlich Nutzern der Tarife „ IBM Quantum® Premium Plan “, „Flex Plan“ und „ On-Prem “ (über die „ IBM Quantum Platform “-API) zur Verfügung steht. Sie befinden sich im Preview-Status und können sich noch ändern.
Übersicht
Mit dem „Constrained Quantum Optimizer“ von Aqarios können Sie binäre Optimierungsprobleme mit Nebenbedingungen auf der „ IBM® “-Quantenhardware lösen, ohne dass eine manuelle Neuformulierung und Schaltkreismappung erforderlich ist. Liefern Sie das Problem einfach als LP-Datei, MPS-Datei oder Luna-Modell. Die Funktion übernimmt automatisch die Umformulierung, die Schaltungssynthese, die Transpilation und die Hardware-Ausführung. Der Solver nutzt den iterativen Warm-Start [1] des „ FlexQAOA “-Algorithmus, einer für Beschränkungen optimierten Erweiterung des Quantum Approximate Optimization Algorithm (QAOA).
Der Optimierer ist auf binäre Probleme mit Nebenbedingungen ausgerichtet. Insbesondere können One-Hot-Beschränkungen und Set-Packing-Beschränkungen mithilfe von XY-Mixern nativ durchgesetzt werden. Andere Arten von Nebenbedingungen werden automatisch als Strafterme umformuliert.
Die Funktion löst ausschließlich diskrete Probleme. Jede Entscheidungsvariable muss binär sein oder eine Ganzzahl mit einer expliziten Unter- und Obergrenze, damit sie in Qubits kodiert werden kann. Kontinuierliche (reellwertige) Variablen werden nicht unterstützt: Ein Modell, das solche Variablen enthält, wird mit dem Fehlercode abgelehnt 4710.
Beschreibung
Die Leistung kann sowohl von der konkreten Problemstellung als auch von den nachfolgenden Verarbeitungsschritten abhängen. In manchen Fällen können klassische Stichproben und quantengenerierte Stichproben nach einer gleichwertigen Nachbearbeitung eine ähnliche Qualität der Endlösung erzielen. Bei der Bewertung sollte daher der gesamte Optimierungsablauf berücksichtigt werden.
Der „Constrained Quantum Optimizer“ implementiert den iterativen Warm-Start-XY-Mixer-QAOA (IWS-QAOA) [1]. Der Algorithmus führt QAOA-Schaltungen mit festem Winkel auf Quantenhardware aus und aktualisiert die anfänglichen Warm-Start-Wahrscheinlichkeiten jeder Schaltung anhand der Messergebnisse aus der vorherigen Iteration. Es ist kein Training mit Variationsparametern erforderlich; stattdessen wird eine feste lineare Rampenparametrisierung gewählt.
Durch den Einsatz von XY-Mixern zur Durchsetzung von One-Hot-Beschränkungen lässt sich die Lösungsqualität bei beschränkten Problemen drastisch verbessern, da der Suchraum praktisch auf einen kleineren zulässigen Unterraum reduziert wird – und dabei keine zusätzliche Komplexität durch Strafterme in die Optimierungslandschaft eingeführt wird.
Arbeitsablauf
Der Ablauf der Funktion wird im Folgenden beschrieben:
- Vorverarbeitung : Vor der Schaltungssynthese analysiert der Optimierer die Nebenbedingungsstruktur des Eingabeproblems:
- Vorverarbeitung als Graph: Sofern dies für das Problem relevant ist, wird es als Graph analysiert, wobei Kanten die Beziehungen zwischen den Variablen bestimmen. Diese Graphenanalyse ermöglicht zwei Verbesserungen bei der Vorverarbeitung. Zunächst können einzelne Nebenbedingungen mithilfe der Clique-Zusammenführung zu einer großen Nebenbedingung zusammengefasst werden, sodass sie durch einen einzigen XY-Mixer dargestellt werden. Zweitens können Variablen mit nur einem Nachbarn deterministisch festgelegt werden, wodurch sich der Umfang und die Komplexität des Problems verringern.
- Auflösung von Nebenbedingungen: Der Präprozessor behandelt jede Nebenbedingung separat: Handelt es sich um eine „One-Hot“-Nebenbedingung, kann diese mithilfe von XY-Mixern durchgesetzt werden. Handelt es sich um eine Set-Packing-Beschränkung, wird diese zunächst in eine One-Hot-Beschränkung umgewandelt. Gleichheitsbedingungen werden durch quadratische Straffunktionen berücksichtigt, Ungleichheitsbedingungen durch eine asymmetrische Straffunktion.
- Ableitung der Strafterme: Einschränkungen, die nicht als One-Hot-Gleichheitsbedingungen ausgedrückt werden können, werden in Strafterme umgewandelt. Der Optimierer leitet die Stärke der Straffunktion automatisch aus der Problemstruktur ab.
- Iterativer Warmstart : Der Optimierer führt mehrere parallele Warmstart-Ketten aus. Jede Kette enthält eine Wahrscheinlichkeitsverteilung über Variablenzuordnungen, die als Startwahrscheinlichkeit der QAOA-Schaltung dient (Warm-Start-Zustand). Bei jeder Iteration entnimmt eine Kette Stichproben aus dem Quantenschaltkreis, führt eine klassische Nachbearbeitung durch und aktualisiert ihre Verteilung auf der Grundlage des Auftretens der Stichproben. Über mehrere Iterationen hinweg konzentriert dies die Suche auf hochwertige Lösungen, ohne dass eine Variationsoptimierungsschleife erforderlich ist.
Die Anzahl der Ketten (num_parallel), das gesamte Schussbudget pro Kette (total_shots) und die Anzahl der QAOA-Wiederholungen (reps) sind die wichtigsten Steuergrößen für den Kompromiss zwischen Lösungsqualität und Laufzeit.
Benchmarks
Die folgenden Benchmark-Ergebnisse zeigen, dass die Qiskit-Funktion „Constrained Quantum Optimizer“ in der Lage ist, qualitativ hochwertige, realisierbare Lösungen für Optimierungsprobleme mit Nebenbedingungen und weit über 100 binären Variablen zu finden. Die Genauigkeit ist das Verhältnis des ermittelten objektiven Werts zum bekannten Optimum. Die Laufzeit ist die tatsächliche Zeit vom Aufruf der Funktion bis zur Ausgabe des Ergebnisses. Die QPU-Nutzung entspricht der abrechnungsfähigen Quantum-Compute-Zeit.
Es wurden zwei Probleme untersucht: das Problem der maximalen unabhängigen Menge (MIS) und das „Max- -Cut“-Problem, bei dem es sich um eine Erweiterung des bekannten Problems der maximalen unabhängigen Menge ( MaxCut ) auf mehr als zwei Kategorien handelt. Max- -Cut ist zudem das Optimierungsproblem, das dem Entscheidungsproblem der Graphenfärbung entspricht (wenn alle Kanten durchtrennt werden, ist der Graph „ -färbbar“).
Fehler | Variablen | Einschränkungen | Qubits | Genauigkeit | Durchführbarkeit | Gesamtlaufzeit (s) | CPU-Auslastung (s) | Gesamtzahl der Schüsse |
|---|---|---|---|---|---|---|---|---|
| MIS- es60fst02 | 186 | 280 | 124 | 100.0% | Ja | 940.2 | 147.0 | 25.0k |
| MIS- sloane_2dc_128 | 128 | 5173 | 74 | 100.0% | Ja | 347.6 | 106.0 | 12.5k |
| Max-3-Cut Karate-Club | 99 | 33 | 99 | 98.7% | Ja | 279.5 | 166.0 | 25.0k |
| Max-4-Cut Karate-Club | 132 | 33 | 132 | 100.0% | Ja | 258.3 | 200.0 | 25.0k |
Benchmark-Hinweise
- Die oben genannten Ergebnisse wurden auf dem
ibm_marrakeshHeron- r2 -Prozessor mit den Standardoptionen unduse_sessionaktivierter Funktion erzielt. In diesemsloane_2dc_128Falltotal_shots=12500wurde … verwendet. - Die geringere Anzahl an Qubits bei MIS-Instanzen (74 und 124 gegenüber 128 und 186 Variablen) spiegelt die Festlegung von Variablen in der Vorverarbeitung wider.
- Die Beispielinstanzen für MIS stammen aus der „Quantum Optimization Benchmarking Library “. – Die Instanz für das Max- -Cut-Problem ist der „Zachary Karate Club“-Graph, der eine chromatische Zahl von 5 aufweist.
Erste Schritte
Diese Anleitung veranschaulicht die grundlegende Verwendung des „Constrained Quantum Optimizer“, indem sie zeigt, wie man die Funktion lädt und einfache Aufgaben ausführt. Eine ausführlichere Anleitung finden Sie unter „Ermitteln der maximalen unabhängigen Menge mit dem Aqarios Constrained Quantum Optimizer “.
Melden Sie sich mit Ihrem API-Schlüssel für die „ IBM Quantum “ und der Instanz- CRN an und laden Sie anschließend die Funktion aus dem Katalog.
Der folgende Code setzt voraus, dass Sie Ihre Anmeldedaten gespeichert haben. Befolgen Sie zur Einrichtung die Anweisungen unter „Speichern Sie Ihre Anmeldedaten für das IBM Cloud -Konto “.
from qiskit_ibm_catalog import QiskitFunctionsCatalog
catalog = QiskitFunctionsCatalog(channel="ibm_quantum_platform")
# Verify that you have access to the function
catalog.list()Output:
[QiskitFunction(aqarios/constrained-quantum-optimizer)]
# Load the function
optimizer = catalog.load("aqarios/constrained-quantum-optimizer")# Check the list of backends you have access to
catalog.backends()Output:
[<IBMBackend('ibm_pittsburgh')>,
<IBMBackend('ibm_boston')>,
<IBMBackend('ibm_phoenix')>,
<IBMBackend('ibm_fez')>,
<IBMBackend('ibm_miami')>,
<IBMBackend('ibm_marrakesh')>,
<IBMBackend('ibm_kingston')>]
# Select the backend you want to use
backend = catalog.backend("ibm_phoenix")Beispiel 1: Ein einfaches Problem mit Nebenbedingungen
Das erste Beispiel zeigt, wie die Funktion mit LP-Dateien verwendet wird, einer gängigen Spezifikation für Optimierungsprobleme in der Operationsforschung. Sie formulieren das folgende beliebige Optimierungsproblem mit fünf binären Variablen , das zwei Nebenbedingungen unterliegt:
1. Formulieren Sie das Problem
Geben Sie den mathematischen Ausdruck direkt im folgenden LP-String-Format an:
lp_str = """\\Problem name: Example
Minimize
obj: [ 2 x_1 x_2 + 4 x_2 x_3 - 2 x_3 x_4 - 4 x_4 x_5 - 4 x_1 x_3 - 8 x_2 x_5 ] / 2
Subject To
c1: x_1 + x_2 + x_3 <= 1
c2: x_3 - x_4 + x_5 = 0
Binaries
x_1 x_2 x_3 x_4 x_5
End
"""Beachten Sie, dass eine gemäß dem LP-Standard vorgeschriebene Notation für quadratische Zielfunktionen [...] / 2 ist.
2. Den Optimierer ausführen
Lösen Sie das Problem mit dem Optimierer.
# Set up low-resource options for the simple problem
options = {"total_shots": 2000, "num_parallel": 5, "use_session": True}
# Dispatch the job
job_1 = optimizer.run(
problem=lp_str, backend_name=backend.name, options=options
)
print(f"Job ID: {job_1.job_id}")Output:
Job ID: 2e06a3a8-7c29-4c76-94d7-194293363f4a
# Monitor the job status
job_1.status()Output:
'RUNNING: WAITING_FOR_QPU'
3. Das Ergebnis abrufen
Die Lösung, bei der die Variablennamen den zugehörigen Zuweisungen zugeordnet werden, ergibt sich aus dem Ergebnis.
result = job_1.result()
resultOutput:
{'solutions': [{'x_1': 0, 'x_2': 1, 'x_3': 0, 'x_4': 1, 'x_5': 1}],
'solution_bitstrings': ['01011'],
'raw_energy': -6.0,
'objective_value': -6.0,
'feasible': True,
'metadata': {'resource_usage': {'RUNNING: MAPPING': {'CPU': 5.405},
'RUNNING: OPTIMIZING_FOR_HARDWARE': {'CPU': 9.902},
'RUNNING: WAITING_FOR_QPU': {'CPU': 25.456},
'RUNNING: EXECUTING_QPU': {'CPU': 25.202},
'RUNNING: POST_PROCESSING': {'CPU': 6.481}},
'circuit_metrics': {'before_transpilation': {'num_qubits': 6,
'gate_count': 42,
'depth': 15,
'two_qubit_gate_count': 12,
'two_qubit_gate_depth': 7,
'operations': {'rz': 12,
'p': 8,
'ry': 7,
'rzz': 4,
'cx': 3,
'xx_plus_yy': 3,
'global_phase': 2,
'cry': 2,
'x': 1}},
'after_transpilation': {'num_qubits': 6,
'gate_count': 254,
'depth': 100,
'two_qubit_gate_count': 48,
'two_qubit_gate_depth': 33,
'operations': {'rz': 78, 'sx': 122, 'cz': 48, 'measure': 6, 'x': 0}}},
'solver_info': {'variable_mapping': {'x_1': 0,
'x_2': 1,
'x_3': 2,
'x_4': 3,
'x_5': 4}}}}
Das solutions Feld im Rückgabewörterbuch enthält alle gefundenen degenerierten Bestlösungen in Form von Wörterbüchern, die jeden Variablennamen seiner Zuweisung zuordnen. Die gleichen Lösungen werden auch als Bitstrings zurückgegeben solution_bitstrings; metadata.solver_info.variable_mapping gibt an, welche Zeichenposition eines Bitstrings zu welcher Variablen gehört. Neben den Lösungsdaten metadata werden das objective_value, ein Flag feasible und weitere bereitgestellt.
Beispiel 2: Maximale unabhängige Menge
Beim Problem der maximalen unabhängigen Menge (MIS) soll die größte Teilmenge von Knoten in einem Graphen ermittelt werden, bei der sich keine zwei Knoten dieser Teilmenge eine Kante teilen. In diesem Beispiel wird das MIS-Problem auf einem regulären Graphen mit 12 Knoten gelöst. Weitere Informationen zu diesem Problem sowie ein ausführlicheres Beispiel finden Sie im Tutorial.
Das Problem wurde mit „qiskit-addon-opt-mapper“ erstellt. Installieren Sie gegebenenfalls die erforderlichen Pakete:
# %pip install networkx qiskit-addon-opt-mapperSchritt 1: Das Problem definieren
Erstellen Sie einen zufälligen 3-regulären Graphen und definieren Sie das MIS-Optimierungsproblem. Jeder Knoten des Graphen wird zu einer binären Variablen, und jede Kante führt eine Nebenbedingung ein, die sicherstellt, dass höchstens ein Endpunkt ausgewählt wird.
import networkx as nx
from qiskit_addon_opt_mapper.applications import IndependentSet
from qiskit_addon_opt_mapper.translators import to_docplex_mp
# 12-node random 3-regular graph
G = nx.random_regular_graph(3, 12, seed=7)
# Build MIS problem and export as LP string
mis = IndependentSet(G)
mis_problem = mis.to_optimization_problem()
lp_str = to_docplex_mp(mis_problem).export_as_lp_string()
print(lp_str)Output:
\ This file has been generated by DOcplex
\ ENCODING=ISO-8859-1
\Problem name: Independent set
Maximize
obj: x_0 + x_1 + x_2 + x_3 + x_4 + x_5 + x_6 + x_7 + x_8 + x_9 + x_10 + x_11
Subject To
c0: x_0 + x_4 <= 1
c1: x_0 + x_9 <= 1
c2: x_0 + x_8 <= 1
c3: x_1 + x_2 <= 1
c4: x_1 + x_7 <= 1
c5: x_1 + x_3 <= 1
c6: x_2 + x_4 <= 1
c7: x_2 + x_11 <= 1
c8: x_3 + x_10 <= 1
c9: x_3 + x_11 <= 1
c10: x_4 + x_5 <= 1
c11: x_5 + x_10 <= 1
c12: x_5 + x_6 <= 1
c13: x_6 + x_8 <= 1
c14: x_6 + x_7 <= 1
c15: x_7 + x_9 <= 1
c16: x_8 + x_11 <= 1
c17: x_9 + x_10 <= 1
Bounds
0 <= x_0 <= 1
0 <= x_1 <= 1
0 <= x_2 <= 1
0 <= x_3 <= 1
0 <= x_4 <= 1
0 <= x_5 <= 1
0 <= x_6 <= 1
0 <= x_7 <= 1
0 <= x_8 <= 1
0 <= x_9 <= 1
0 <= x_10 <= 1
0 <= x_11 <= 1
Binaries
x_0 x_1 x_2 x_3 x_4 x_5 x_6 x_7 x_8 x_9 x_10 x_11
End
Schritt 2: Den Optimierer ausführen
Lösen Sie das Problem mit dem Optimierer.
options = {"total_shots": 2000, "use_session": True}
# Dispatch the job
job_2 = optimizer.run(
problem=lp_str, backend_name=backend.name, options=options
)
print(f"Job ID: {job_2.job_id}")Output:
Job ID: f041431c-b42e-4627-afe5-522fea61faf6
# Monitor the job status
job_2.status()Output:
'QUEUED'
Schritt 3: Ergebnisse abrufen und auswerten
Schließlich rufen wir die Lösung ab und überprüfen sie auf ihre Richtigkeit.
result = job_2.result()
print(f"Feasible: {result['feasible']}")
print(f"Independent set size: {int(result['objective_value'])}")
# Extract the selected nodes
solution = result["solutions"][0]
independent_set = [
int(k.split("_")[1]) for k, v in solution.items() if v == 1
]
print(f"Selected nodes: {sorted(independent_set)}")
# Verify no two selected nodes share an edge
conflicts = [
(u, v)
for u, v in G.edges()
if u in independent_set and v in independent_set
]
print(f"Edge conflicts: {conflicts}")Output:
Feasible: True
Independent set size: 5
Selected nodes: [1, 4, 6, 9, 11]
Edge conflicts: []
Beispiel 3: 3-Färbung von Graphen ( Max-3-Cut )
Beim „Max- -Cut“-Problem werden die Knoten eines Graphen in „ “-Gruppen unterteilt, um die Anzahl der Kanten zu maximieren, deren Endpunkte zu unterschiedlichen Gruppen gehören. Für „ “ entspricht dies der Suche nach einer 3-Färbung, die die Anzahl der Kanten mit unterschiedlichen Farben maximiert.
Formell wird jedem Knoten eine der Gruppen mit den binären Variablen für die Farbe zugeordnet. Die One-Hot-Einschränkung für jeden Knoten gewährleistet eine eindeutige Zuordnung. Das Ziel maximiert die Kanten zwischen den Gruppen:
Die One-Hot-Beschränkungen eignen sich ideal für XY-Mischer, die vom Optimierer nativ verarbeitet werden.
In diesem Beispiel wird der Graph des Zachary Karate Club (34 Knoten, 78 Kanten) verwendet und das Modell mit dem Luna-Modell erstellt. Installieren Sie gegebenenfalls die erforderlichen Pakete:
# %pip install networkx matplotlib luna-modelSchritt 1: Das Problem definieren
Erstellen Sie zunächst die binären Variablen mit dem Paket luna-model . Definieren Sie anschließend das Ziel und fügen Sie die Nebenbedingungen zum Modell hinzu.
import networkx as nx
from luna_model import Model, quicksum
k = 3
G = nx.karate_club_graph()
# Instantiate the Model object
model = Model(name="Max-3-Cut")
# Add binary variables
x = model.add_variables("x", shape=(G.number_of_nodes(), k))
# Add the objective by using the numpy dot abstraction
model.objective = quicksum(x[i].dot(x[j]) for i, j in G.edges)
# Bulk-add the one-hot constraints
model.add_constraints(x.sum(axis=1) == 1)
# Encode the model to send via API
model_enc = model.encode_b64()Schritt 2: Den Optimierer ausführen
Lösen Sie das Problem mit dem Optimierer.
options = {"use_session": True}
# Dispatch the job
job_3 = optimizer.run(
problem=model_enc, backend_name=backend.name, options=options
)
print(f"Job ID: {job_3.job_id}")Output:
Job ID: df911d83-9df7-44a1-bfad-5d66e08676c3
# Monitor the job status
job_3.status()Output:
'RUNNING: WAITING_FOR_QPU'
Schritt 3: Ergebnisse abrufen und visualisieren
Die Ergebnisse abrufen und visualisieren.
result = job_3.result()
solution = result["solutions"][0]
# Map each node to its assigned color group
node_group = {}
for i in G.nodes:
for c in range(k):
if solution[f"x{i},{c}"] == 1:
node_group[i] = c
print(f"Feasible: {result['feasible']}")
print(f"Violations: {int(result['objective_value'])}")
# Visualize the partition
colors = ["tab:blue", "tab:orange", "tab:green"]
node_colors = [colors[node_group[i]] for i in G.nodes()]
nx.draw(G, nx.kamada_kawai_layout(G), node_color=node_colors, node_size=200)Output:
Feasible: True
Violations: 4
Änderungsprotokoll
[0.4.0] - 22.09.2026
Schwerwiegende Änderungen
- Der Eingabeparameter wurde
modelin umbenanntproblem. - Das Ausgabefeld wurde
obj_valuein umbenanntobjective_value. - Die Option
postprocessingwurde durch ersetztpostprocessing_level, die[0, 3]anstelle einer Zeichenkette eine Ganzzahl im Bereich akzeptiert. Die bisherigen Werte entsprechen"off"->0,"weak"->1,"medium"-> und"strong"->2``3, und der Standardwert bleibt unverändert bei3. - Umstrukturiert
metadata.circuit_metrics. Es meldet nunnum_qubits,gate_count,depth,two_qubit_gate_count,two_qubit_gate_depth, und separatoperationsfürbefore_transpilationundafter_transpilation, anstatt eines einzigen pauschalen Verzeichnisses mit gemittelten Gate-Zahlen. Das Feld ist, wennNonedas Problem während der Vorverarbeitung gelöst wurde und kein Schaltkreis durchlaufen wurde (Fehlercode4712).
Funktionen
- Es wurde die Option
seed_transpilerhinzugefügt, mit der die Schaltungssynthese und das Routing über mehrere Durchläufe hinweg reproduzierbar gemacht werden können. - Es wurde die Option
job_tagshinzugefügt, jedem von der Funktion übermittelten „ Qiskit Runtime “-Auftrag eigene Tags hinzuzufügen. - Das Ausgabefeld wurde hinzugefügt
solution_bitstrings, das dieselben Lösungen wiesolutionsin Form einer Bitfolge zurückgibt. - Es wurde hinzugefügt
metadata.solver_info.variable_mapping, wodurch jeder Variablenname seiner Zeichenposition in den Einträgen von zugeordnet wirdsolution_bitstrings.
Dokumentation
- Es wurde dokumentiert, dass kontinuierliche (reellwertige) Variablen nicht unterstützt werden und dass ganzzahlige Variablen explizite Grenzwerte erfordern. Solche Modelle schlagen mit dem Fehlercode … fehl
4710.
Unterstützung anfordern
Bei Fragen oder Problemen wenden Sie sich bitte unter Angabe Ihrer Auftrags-ID an [email protected].
Nächste Schritte
- Beantragen Sie Zugriff auf den „Constrained Quantum Optimizer“ von Aqarios.
- Die vollständige Dokumentation zu den Parametern und Ausgaben finden Sie in der API-Referenz.
- Probieren Sie das Tutorial „Find the Maximum Independent Set with the Aqarios Constrained Quantum Optimizer“ aus, um einen detaillierten Einblick in eine echte QOBLIB-Benchmark-Instanz zu erhalten.
- Lesen Sie den Artikel „Constrained Quantum Optimization via Iterative Warm-Start XY-Mixers “.
Referenzen
- Bucher et al. (2026), „Constrained Quantum Optimization via Iterative Warm-Start XY-Mixers“ 10.1088/1367-2630/ae8ea2