Sari la conținutul principal
Acest proiect este în versiune beta. Ai găsit o eroare? Deschide un issue pe GitHub. Ai o întrebare sau o idee? Întreabă în Discussions — ne-ar plăcea să aflăm părerea ta!
Cum este calitatea traducerii pe această pagină?

Constrained Quantum Optimizer - O funcție Qiskit de la Aqarios

Consultă referința API

notă

Qiskit Functions sunt o caracteristică experimentală disponibilă doar utilizatorilor IBM Quantum® cu plan Premium, plan Flex și plan On-Prem (prin API-ul IBM Quantum Platform). Acestea au statut de versiune preliminară (preview) și pot fi modificate.

Prezentare generală​

Cu Constrained Quantum Optimizer de la Aqarios, poți rezolva probleme de optimizare binară cu constrângeri pe hardware cuantic IBM® fără reformularea manuală a problemei și fără maparea circuitului. Este suficient să furnizezi o problemă ca fișier LP, fișier MPS sau ca Luna Model. Funcția se ocupă automat de reformulare, sinteza circuitului, transpilare și execuția pe hardware. Solverul utilizează warm-starting iterativ [1] al algoritmului FlexQAOA, o extensie a algoritmului QAOA (Quantum Approximate Optimization Algorithm) care tratează nativ constrângerile.

Optimizatorul vizează probleme binare cu constrângeri. În special, constrângerile one-hot și constrângerile set-packing pot fi impuse nativ utilizând XY-mixers. Alte tipuri de constrângeri sunt reformulate automat ca termeni de penalizare.

Tipuri de variabile acceptate

Funcția rezolvă doar probleme discrete. Fiecare variabilă de decizie trebuie să fie binară sau întreagă, cu o limită inferioară și una superioară explicite, astfel încât să poată fi codificată în qubiți. Variabilele continue (cu valori reale) nu sunt acceptate: un model care le conține este respins cu codul de eroare 4710.

Descriere​

Precizare

Performanța poate depinde atât de instanța problemei, cât și de etapele de procesare ulterioare. În unele cazuri, eșantioanele clasice și cele generate cuantic pot atinge o calitate finală similară a soluției după o post-procesare echivalentă. Evaluarea ar trebui, prin urmare, să ia în considerare întregul flux de optimizare.

Constrained Quantum Optimizer implementează Iterative warm-start XY-mixer QAOA (IWS-QAOA) [1]. Algoritmul rulează circuite QAOA cu unghi fix pe hardware cuantic și actualizează probabilitățile inițiale de warm-start ale fiecărui circuit utilizând rezultatele măsurătorilor din iterația anterioară. Nu este necesară antrenarea parametrilor variaționali; în schimb, se alege o parametrizare cu rampă liniară fixă.

Utilizând XY-mixers pentru a impune constrângeri one-hot, poți îmbunătăți drastic calitatea soluțiilor pentru problemele cu constrângeri, deoarece spațiul de căutare este redus practic la un subspațiu fezabil mai mic — iar peisajul de optimizare nu capătă complexitate suplimentară din cauza termenilor de penalizare.

Flux de lucru​

Fluxul de lucru al funcției este descris mai jos:

  1. Preprocesare: Înainte de sinteza circuitului, optimizatorul analizează structura constrângerilor problemei de intrare:

    • Preprocesarea grafului: Atunci când este aplicabil problemei, aceasta este analizată ca un graf, în care muchiile determină relația dintre variabile. Această analiză a grafului permite două îmbunătățiri de preprocesare a problemei. În primul rând, constrângerile individuale pot fi agregate într-o singură constrângere mare prin combinarea de clici (clique merging), astfel încât să fie reprezentate printr-un singur XY-mixer. În al doilea rând, variabilele care au un singur vecin pot fi fixate în mod determinist, reducând dimensiunea și complexitatea problemei.

    • Rezolvarea constrângerilor: Preprocesorul tratează fiecare constrângere separat: dacă constrângerea este de tip one-hot, aceasta poate fi impusă prin XY-mixers. Dacă este o constrângere de tip set-packing, aceasta este mai întâi transformată într-o constrângere one-hot. Constrângerile de egalitate sunt tratate prin penalizări pătratice, iar cele de inegalitate prin penalizare dezechilibrată.

    • Derivarea penalizării: Constrângerile care nu pot fi exprimate ca constrângeri de egalitate one-hot sunt convertite în termeni de penalizare. Optimizatorul derivă automat intensitatea penalizării din structura problemei.

  2. Warm-starting iterativ: Optimizatorul rulează mai multe lanțuri de warm-start paralele. Fiecare lanț deține o distribuție de probabilitate peste atribuirile variabilelor, care este utilizată ca probabilitate de pornire a circuitului QAOA (starea de warm-start). La fiecare iterație, un lanț eșantionează din circuitul cuantic, aplică post-procesare clasică și își actualizează distribuția pe baza apariției eșantioanelor. De-a lungul iterațiilor, aceasta concentrează căutarea pe soluții de înaltă calitate fără o buclă de optimizare variațională.

Numărul de lanțuri (num_parallel), bugetul total de shot-uri per lanț (total_shots) și numărul de repetiții QAOA (reps) sunt principalele controale pentru a echilibra calitatea soluției cu timpul de execuție.

Workflow diagram of the Constrained Quantum Optimizer

Benchmark-uri​

Benchmark-urile de mai jos arată că funcția Qiskit Constrained Quantum Optimizer este capabilă să găsească soluții fezabile, de înaltă calitate, pentru probleme de optimizare cu constrângeri cu mult peste 100 de variabile binare. Acuratețea este raportul dintre valoarea obiectiv găsită și optimul cunoscut. Timpul de execuție este timpul real (wall-clock) de la invocarea funcției până la livrarea rezultatului. Utilizarea QPU este timpul de calcul cuantic facturabil.

Au fost examinate două probleme: problema Maximum Independent Set (MIS) și Max-kk-Cut, care este o extensie a binecunoscutei probleme MaxCut la mai mult de două categorii. Max-kk-Cut este, de asemenea, varianta de optimizare echivalentă a problemei de decizie a colorării grafurilor (atunci când toate muchiile sunt tăiate, graful este kk-colorabil).

ProblemăVariabileConstrângeriQubițiAcuratețeFezabilitateTimp total de execuție (s)Utilizare QPU (s)Total shot-uri
MIS es60fst02186280124100.0%True940.2147.025.0k
MIS sloane_2dc_128128517374100.0%True347.6106.012.5k
Max-3-Cut Karate Club99339998.7%True279.5166.025.0k
Max-4-Cut Karate Club13233132100.0%True258.3200.025.0k

Note privind benchmark-urile​

  • Rezultatele de mai sus au fost obținute pe procesorul Heron r2 ibm_marrakesh cu opțiunile implicite și use_session activat. Pentru instanța sloane_2dc_128, a fost utilizat total_shots=12500.

  • Numărul redus de qubiți pentru instanțele MIS (74 și 124 față de 128 și 186 de variabile) reflectă fixarea variabilelor în etapa de preprocesare.

  • Instanțele problemei pentru MIS sunt preluate din Quantum Optimization Benchmarking Library. - Instanța pentru problema Max-kk-Cut este graful Zachary Karate Club, care are un număr cromatic de 5.

Primii pași​

Acest ghid demonstrează utilizarea de bază a Constrained Quantum Optimizer, arătând cum se încarcă funcția și cum se execută probleme simple. Pentru un tutorial mai amplu, consultă Find the Maximum Independent Set with the Aqarios Constrained Quantum Optimizer.

Autentifică-te cu cheia API IBM Quantum și CRN-ul instanței, apoi încarcă funcția din catalog.

notă

Codul următor presupune că ai salvat deja acreditările. Pentru a le configura, urmează instrucțiunile din Salvează acreditările contului tău IBM Cloud.

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"luna_model": "luna-model", "networkx": "networkx", "qiskit_addon_opt_mapper": "qiskit-addon-opt-mapper", "qiskit_ibm_catalog": "qiskit-ibm-catalog"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
from qiskit_ibm_catalog import QiskitFunctionsCatalog

catalog = QiskitFunctionsCatalog(channel="ibm_quantum_platform")

# Verify that you have access to the function
catalog.list()
[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()
[<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")

Exemplul 1: O problemă simplă cu constrângeri​

Primul exemplu arată cum se utilizează funcția cu fișiere LP, o specificație obișnuită pentru probleme de optimizare utilizată în cercetarea operațională. Vei formula următoarea problemă de optimizare arbitrară cu cinci variabile binare xi∈{0,1}x_i \in \{0,1\} supuse la două constrângeri:

min⁡x1x2+2x2x3−x3x4−2x4x5−2x1x3−4x2x5s.t.x1+x2+x3≤1x3−x4+x5=0 \min x_1 x_2 + 2 x_2 x_3 - x_3 x_4 - 2 x_4 x_5 - 2 x_1 x_3 - 4 x_2 x_5 \\ \text{s.t.}\quad x_1 + x_2 + x_3 \leq 1 \\ \quad x_3 - x_4 + x_5 = 0

1. Formulează problema​

Exprimă direct expresia matematică în următorul format de șir LP:

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
"""

Reține că [ ... ] / 2 este o notație necesară pentru obiectivele pătratice conform standardului LP.

2. Rulează optimizatorul​

Rezolvă problema cu optimizatorul.

# 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}")
Job ID: 2e06a3a8-7c29-4c76-94d7-194293363f4a
# Monitor the job status
job_1.status()
'RUNNING: WAITING_FOR_QPU'

3. Preia rezultatul​

Soluția, care mapează numele variabilelor la atribuirile asociate, este furnizată de rezultat.

result = job_1.result()

result
{'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}}}}

Câmpul solutions din dicționarul returnat conține toate cele mai bune soluții degenerate găsite, sub formă de dicționare care asociază fiecare nume de variabilă cu valoarea sa atribuită. Aceleași soluții sunt returnate și ca șiruri de biți în solution_bitstrings; metadata.solver_info.variable_mapping îți spune ce poziție de caracter dintr-un șir de biți aparține cărei variabile. Pe lângă datele soluției, sunt furnizate objective_value, un indicator feasible și metadata suplimentare.

Exemplul 2: Maximum Independent Set​

Problema Maximum Independent Set (MIS) cere cel mai mare subset de vârfuri dintr-un graf astfel încât niciun vârf din subset să nu fie conectat prin muchie cu un alt vârf din subset. Acest exemplu rezolvă MIS pe un graf regulat cu 12 noduri. Pentru mai multe informații despre problemă și un exemplu mai amplu, consultă tutorialul.

Problema este construită cu qiskit-addon-opt-mapper. Instalează pachetele necesare dacă este cazul:

# %pip install networkx qiskit-addon-opt-mapper

Pasul 1: Definește problema​

Construiește un graf regulat aleatoriu de gradul 3 și creează problema de optimizare MIS. Fiecare nod al grafului devine o variabilă binară, iar fiecare muchie introduce o constrângere care asigură că cel mult unul dintre capete este selectat.

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)
\ 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

Pasul 2: Rulează optimizatorul​

Rezolvă problema cu optimizatorul.

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}")
Job ID: f041431c-b42e-4627-afe5-522fea61faf6
# Monitor the job status
job_2.status()
'QUEUED'

Pasul 3: Preia și interpretează rezultatele​

În cele din urmă, preluăm soluția și verificăm corectitudinea acesteia.

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}")
Feasible: True
Independent set size: 5
Selected nodes: [1, 4, 6, 9, 11]
Edge conflicts: []

Exemplul 3: Colorarea grafului cu 3 culori (Max-3-Cut)​

Problema Max-kk-Cut împarte vârfurile unui graf în kk grupuri pentru a maximiza numărul de muchii ale căror capete aparțin unor grupuri diferite. Pentru k=3k = 3, aceasta este echivalentă cu găsirea unei colorări cu 3 culori care maximizează muchiile dintre culori diferite.

Formal, se atribuie fiecărui nod i∈Vi \in V unul dintre cele kk grupuri, folosind variabile binare xi,cx_{i,c} pentru culoarea c∈{1,…,k}c \in \{1, \ldots, k\}. Constrângerea one-hot ∑cxi,c=1\sum_c x_{i,c} = 1 pentru fiecare nod impune o atribuire unică. Obiectivul maximizează muchiile dintre grupuri diferite:

min⁡∑(u,v)∈E∑cxu,c xv,cs.t.∑cxi,c=1∀i∈V\min \sum_{(u,v) \in E} \sum_c x_{u,c} \, x_{v,c}\\ \text{s.t.} \sum_{c} x_{i,c} = 1 \quad \forall i \in V

Constrângerile one-hot sunt ideale pentru XY-mixers, pe care optimizatorul le gestionează nativ.

Acest exemplu utilizează graful Zachary Karate Club (34 de noduri, 78 de muchii) și construiește modelul cu Luna Model. Instalează pachetele necesare dacă este cazul:

# %pip install networkx matplotlib luna-model

Pasul 1: Definește problema​

Mai întâi, generează variabilele binare cu pachetul luna-model. Apoi, definește obiectivul și adaugă constrângerile la model.

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()

Pasul 2: Rulează optimizatorul​

Rezolvă problema cu optimizatorul.

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}")
Job ID: df911d83-9df7-44a1-bfad-5d66e08676c3
# Monitor the job status
job_3.status()
'RUNNING: WAITING_FOR_QPU'

Pasul 3: Preia și vizualizează rezultatele​

Preia și vizualizează rezultatele.

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)
Feasible: True
Violations: 4

Output of the previous code cell

Jurnal de modificări​

[0.4.0] - 2026-09-22​

Modificări incompatibile

  • Parametrul de intrare model a fost redenumit în problem.
  • Câmpul de ieșire obj_value a fost redenumit în objective_value.
  • Opțiunea postprocessing a fost înlocuită cu postprocessing_level, care primește un număr întreg în intervalul [0, 3] în loc de un șir de caractere. Valorile anterioare se asociază astfel: "off" -> 0, "weak" -> 1, "medium" -> 2 și "strong" -> 3, iar valoarea implicită rămâne neschimbată la 3.
  • metadata.circuit_metrics a fost restructurat. Acum raportează num_qubits, gate_count, depth, two_qubit_gate_count, two_qubit_gate_depth și operations separat pentru before_transpilation și after_transpilation, în loc de un singur dicționar plat cu numere medii de porți. Câmpul este None când problema a fost rezolvată în timpul preprocesării și nu a fost rulat niciun circuit (codul de eroare 4712).

Funcționalități

  • A fost adăugată opțiunea seed_transpiler pentru a face sinteza și rutarea circuitului reproductibile între rulări.
  • A fost adăugată opțiunea job_tags pentru a atașa propriile etichete fiecărui job Qiskit Runtime trimis de funcție.
  • A fost adăugat câmpul de ieșire solution_bitstrings, care returnează aceleași soluții ca solutions, sub formă de șiruri de biți.
  • A fost adăugat metadata.solver_info.variable_mapping, care asociază fiecare nume de variabilă cu poziția sa de caracter în intrările din solution_bitstrings.

Documentație

  • S-a documentat că variabilele continue (cu valori reale) nu sunt acceptate și că variabilele întregi necesită limite explicite. Astfel de modele eșuează cu codul de eroare 4710.

Obține asistență​

Pentru întrebări sau probleme, contactează support@aqarios.com menționând ID-ul jobului tău.

Pași următori​

Recomandări

Referințe​

  1. Bucher et al. (2026), Constrained Quantum Optimization via Iterative Warm-Start XY-Mixers 10.1088/1367-2630/ae8ea2