Sari la conținutul principal

Optimization Solver: O Funcție Qiskit de Q-CTRL Fire Opal

Consultă referința API

notă

Funcțiile Qiskit sunt o funcționalitate experimentală disponibilă doar utilizatorilor IBM Quantum® cu abonament Premium Plan, Flex Plan și On-Prem (prin IBM Quantum Platform API) Plan. Acestea se află în stadiu de previzualizare și pot fi modificate.

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

Prezentare generală

Cu Fire Opal Optimization Solver, poți rezolva probleme de optimizare la scară utilă pe hardware cuantic fără a necesita expertiză în domeniul cuantic. Pur și simplu introduci definiția problemei la nivel înalt, iar Solver-ul se ocupă de restul. Întregul flux de lucru este conștient de zgomot și utilizează Fire Opal's Performance Management în fundal. Solver-ul oferă în mod constant soluții precise pentru probleme dificil de rezolvat clasic, chiar și la scara completă a dispozitivului, pe cele mai mari QPU-uri IBM®.

Solver-ul este flexibil și poate fi utilizat pentru a rezolva probleme de optimizare combinatorie definite ca funcții obiectiv sau grafuri arbitrare. Problemele nu trebuie să fie mapate la topologia dispozitivului. Atât problemele neconstrânse, cât și cele constrânse pot fi rezolvate, cu condiția că restricțiile pot fi formulate ca termeni de penalizare. Exemplele incluse în acest ghid demonstrează cum să rezolvi o problemă de optimizare neconstrânsă și una constrânsă la scară utilă, folosind diferite tipuri de intrări ale Solver-ului. Primul exemplu implică o problemă max-cut definită pe un graf 3-regulat cu 156 de noduri, în timp ce al doilea exemplu abordează o problemă de Acoperire Minimă a Vârfurilor cu 50 de noduri, definită printr-o funcție cost.

Pentru a obține acces la Optimization Solver, contactează Q-CTRL.

Descrierea funcției

Solver-ul optimizează și automatizează complet întregul algoritm, de la suprimarea erorilor la nivel hardware până la maparea eficientă a problemei și optimizarea clasică în buclă închisă. În fundal, pipeline-ul Solver-ului reduce erorile la fiecare etapă, permițând performanța îmbunătățită necesară pentru o scalare semnificativă. Fluxul de lucru de bază este inspirat de Quantum Approximate Optimization Algorithm (QAOA), care este un algoritm hibrid cuantic-clasic. Pentru un rezumat detaliat al fluxului complet de lucru al Optimization Solver, consultă manuscrisul publicat.

Vizualizarea fluxului de lucru al Optimization Solver

Pentru a rezolva o problemă generică cu Optimization Solver:

  1. Definește problema ta ca o funcție obiectiv, un graf sau un lanț de spin SparsePauliOp.
  2. Conectează-te la funcție prin Catalogul de Funcții Qiskit.
  3. Rulează problema cu Solver-ul și recuperează rezultatele.

Formate de problemă acceptate

  • Reprezentarea expresiei polinomiale a unei funcții obiectiv. Ideal creată în Python cu un obiect SymPy Poly existent și formatată într-un șir folosind sympy.srepr.
  • Reprezentarea grafului unui tip specific de problemă. Graful trebuie creat folosind biblioteca networkx în Python. Apoi trebuie convertit într-un șir folosind funcția networkx [nx.readwrite.json_graph.adjacency_data](http://nx.readwrite.json_graph.adjacency_data.).
  • Reprezentarea lanțului de spin a unei probleme specifice. Lanțul de spin trebuie reprezentat ca obiect SparsePauliOp; consultă documentația pentru mai multe detalii.
Această funcție suportă toate Backend-urile IBM?

Dacă vrei să folosești un Backend pe care această funcție nu îl suportă în prezent, contactează Q-CTRL pentru a adăuga suport.

Benchmark-uri

Rezultatele de benchmark publicate arată că Solver-ul rezolvă cu succes probleme cu peste 120 de Qubiți, depășind chiar rezultatele publicate anterior pe dispozitivele de tip quantum annealing și trapped-ion. Următoarele metrici de benchmark oferă o indicație aproximativă a acurateței și scalabilității tipurilor de probleme, bazate pe câteva exemple. Metricile reale pot diferi în funcție de diverse caracteristici ale problemei, cum ar fi numărul de termeni din funcția obiectiv (densitate) și localitatea lor, numărul de variabile și ordinul polinomului.

„Numărul de Qubiți" indicat nu este o limitare strictă, ci reprezintă praguri aproximative unde poți anticipa o acuratețe a soluției extrem de consistentă. Dimensiunile mai mari ale problemelor au fost rezolvate cu succes, iar testarea dincolo de aceste limite este încurajată.

Conectivitatea arbitrară a Qubiților este suportată pentru toate tipurile de probleme.

Tip de problemăNumăr de QubițiExempluAcuratețeTimp total (s)Utilizare Runtime (s)Număr de iterații
Probleme pătratice cu conectivitate redusă156max-cut 3-regulat100%176429316
Optimizare binară de ordin superior156Model Ising spin-glass100%146127216
Probleme pătratice cu conectivitate densă50max-cut complet conectat100%175826812
Problemă constrânsă cu termeni de penalizare50Acoperire Minimă Ponderată a Vârfurilor cu densitate de 8% a muchiilor100%107421510

Începe

Mai întâi, autentifică-te folosind cheia API IBM Quantum. Apoi, selectează Funcția Qiskit după cum urmează. (Acest fragment de cod presupune că ai salvat deja contul în mediul tău local.)

# Added by doQumentation — required packages for this notebook
!pip install -q networkx numpy qiskit-ibm-catalog qiskit-ibm-runtime sympy
from qiskit_ibm_catalog import QiskitFunctionsCatalog

catalog = QiskitFunctionsCatalog(channel="ibm_quantum_platform")

# Access Function
solver = catalog.load("q-ctrl/optimization-solver")
# %pip install networkx numpy

Exemplu: Optimizare neconstrânsă

Rulează problema tăieturii maxime (Max-Cut). Următorul exemplu demonstrează capacitățile Solver-ului pe o problemă Max-Cut pe un graf 3-regulat neponderat cu 156 de noduri, dar poți rezolva și probleme pe grafuri ponderate. Pe lângă qiskit-ibm-catalog, vei folosi și următoarele pachete pentru a rula acest exemplu: networkx și numpy. Poți instala aceste pachete decomentând celula de mai jos dacă rulezi acest exemplu într-un notebook folosind kernelul IPython.

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)

1. Definește problema

Poți rula o problemă Max-Cut definind o problemă pe bază de graf și specificând problem_type='maxcut'.

# Optionally, visualize the graph
nx.draw_networkx(
maxcut_graph, nx.kamada_kawai_layout(maxcut_graph), node_size=100
)
# Convert graph to string
problem_as_str = nx.readwrite.json_graph.adjacency_data(maxcut_graph)

Rezultatul celulei de cod anterioare

Solver-ul acceptă un șir ca intrare pentru definiția problemei.

# This cell is hidden from users
from qiskit_ibm_runtime import QiskitRuntimeService

service = QiskitRuntimeService()
backend_name = service.least_busy(n_qubits=156).name

2. Rulează problema

Când folosești metoda de intrare bazată pe graf, specifică tipul problemei.

# Solve the problem
maxcut_job = solver.run(
problem=problem_as_str,
problem_type="maxcut",
backend_name=backend_name, # E.g. "ibm_fez"
)
# Get job status
print(maxcut_job.status())

Verifică starea sarcinii din Funcția Qiskit sau recuperează rezultatele după cum urmează:

QUEUED
# 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}")

3. Recuperează rezultatul

Recuperează valoarea tăieturii optime din dicționarul de rezultate.

notă

Maparea variabilelor la șirul de biți poate fi modificată. Dicționarul de ieșire conține un sub-dicționar variables_to_bitstring_index_map, care ajută la verificarea ordinii.

Optimal cut value: 210.0
# %pip install numpy networkx sympy

Poți verifica acuratețea rezultatului rezolvând problema clasic cu solvere open-source precum PuLP, dacă graful nu este dens conectat. Problemele cu densitate ridicată pot necesita solvere clasice avansate pentru a valida soluția.

Exemplu: Optimizare constrânsă

Exemplul anterior max-cut este o problemă de optimizare binară pătratică neconstrânsă frecventă. Optimization Solver de la Q-CTRL poate fi utilizat pentru diverse tipuri de probleme, inclusiv optimizare constrânsă. Poți rezolva tipuri arbitrare de probleme introducând definiția problemei reprezentată ca un polinom, unde restricțiile sunt modelate ca termeni de penalizare.

Următorul exemplu demonstrează cum să construiești o funcție cost pentru o problemă de optimizare constrânsă, acoperirea minimă a vârfurilor (MVC). Pe lângă pachetele qiskit-ibm-catalog și qiskit, vei folosi și următoarele pachete pentru a rula acest exemplu: numpy, networkx și sympy. Poți instala aceste pachete decomentând celula de mai jos dacă rulezi acest exemplu într-un notebook folosind kernelul IPython.

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)

1. Definește problema

Definește o problemă MVC aleatoare generând un graf cu noduri ponderate aleator.

# 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] * weight

Rezultatul celulei de cod anterioare

Un model de optimizare standard pentru MVC ponderat poate fi formulat după cum urmează. Mai întâi, trebuie adăugată o penalizare pentru orice caz în care o muchie nu este conectată la un vârf din submulțime. Prin urmare, fie ni=1n_i = 1 dacă vârful ii se află în acoperiș (adică în submulțime) și ni=0n_i = 0 altfel. În al doilea rând, scopul este de a minimiza numărul total de vârfuri din submulțime, ceea ce poate fi reprezentat prin următoarea funcție:

Minimizey=iVωini\textbf{Minimize}\qquad y = \sum_{i\in V} \omega_i n_i

# 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]
)

Acum, fiecare muchie din graf trebuie să includă cel puțin un capăt din acoperiș, ceea ce poate fi exprimat ca inegalitate:

ni+nj1 for all (i,j)En_i + n_j \ge 1 \texttt{ for all } (i,j)\in E

Orice caz în care o muchie nu este conectată la vârful acoperirii trebuie penalizat. Aceasta poate fi reprezentată în funcția cost prin adăugarea unei penalizări de forma P(1ninj+ninj)P(1-n_i-n_j+n_i n_j) unde PP este o constantă de penalizare pozitivă. Astfel, o alternativă neconstrânsă la inegalitatea constrânsă pentru MVC ponderat este:

Minimizey=iVωini+P((i,j)E(1ninj+ninj))\textbf{Minimize}\qquad y = \sum_{i\in V}\omega_i n_i + P(\sum_{(i,j)\in E}(1 - n_i - n_j + n_i n_j))

# Solve the problem
mvc_job = solver.run(
problem=srepr(cost_function),
backend_name=backend_name, # E.g. "ibm_fez"
)

2. Rulează problema

print(mvc_job.status())

Verifică starea sarcinii din Funcția Qiskit sau recuperează rezultatele după cum urmează:

QUEUED

3. Obține rezultatul

Recuperează soluția și analizează rezultatele. Deoarece această problemă are noduri ponderate, soluția nu este pur și simplu numărul minim de noduri acoperite. În schimb, costul soluției reprezintă suma ponderilor vârfurilor incluse în acoperirea vârfurilor. Acesta reprezintă „costul" sau „greutatea" totală a acoperirii tuturor muchiilor din graf folosind vârfurile selectate.

mvc_result = mvc_job.result()
qctrl_cost = mvc_result["solution_bitstring_cost"]

# Print results
print(f"Solution cost: {qctrl_cost}")
Solution cost: 10.248198273708624

Obține suport

Pentru orice întrebări sau probleme, contactează Q-CTRL.

Jurnal de modificări

  • 2026-02-11: Acum avem suport pentru ibm_miami

Pași următori