Optimization Solver: Qiskit Function od Q-CTRL Fire Opal
Viz referenci API
Qiskit Functions jsou experimentální funkce dostupné pouze uživatelům IBM Quantum® Premium Plan, Flex Plan a On-Prem (prostřednictvím IBM Quantum Platform API) Plan. Jsou ve stavu preview verze a mohou se měnit.
Package versions
Kód na této stránce byl vyvinut s použitím následujících požadavků. Doporučujeme používat tyto verze nebo novější.
qiskit-ibm-runtime~=0.47.0
sympy~=1.14.0
Přehled
S Fire Opal Optimization Solver můžeš řešit optimalizační problémy v utility-scale měřítku na kvantovém hardwaru bez potřeby kvantové odbornosti. Jednoduše zadej definici problému na vysoké úrovni a Solver se postará o zbytek. Celý pracovní postup je noise-aware a využívá pod pokličkou Fire Opal Performance Management. Solver konzistentně poskytuje přesná řešení klasicky náročných problémů, a to i v plném rozsahu zařízení na největších IBM® QPU.
Solver je flexibilní a lze jej použít k řešení kombinatorických optimalizačních problémů definovaných jako účelové funkce nebo libovolné grafy. Problémy nemusí být mapovány na topologii zařízení. Řešitelné jsou jak neomezené, tak omezené problémy, přičemž omezení jsou vynucena jako tvrdá Hamiltonova omezení s váhou 1 místo penalizačních členů. Příklady obsažené v tomto průvodci ukazují, jak vyřešit neomezený a omezený optimalizační problém v utility-scale měřítku pomocí různých typů vstupů Solveru. První příklad zahrnuje problém max-cut definovaný na grafu s 156 uzly a 3-regulárním uspořádáním, zatímco druhý příklad řeší problém rozdělení grafu s 50 uzly definovaný pomocí účelové funkce.
Chceš-li získat přístup k Optimization Solver, kontaktuj Q-CTRL.
Popis funkce
Solver plně optimalizuje a automatizuje celý algoritmus – od potlačování chyb na úrovni hardwaru až po efektivní mapování problému a uzavřenou smyčku klasické optimalizace. V zákulisí pipeline Solveru snižuje chyby v každé fázi, což umožňuje zvýšený výkon potřebný pro smysluplné škálování. Základní pracovní postup je inspirován algoritmem Quantum Approximate Optimization Algorithm (QAOA), který je hybridním kvantově-klasickým algoritmem. Podrobný přehled celého pracovního postupu Optimization Solver najdeš v publikovaném rukopisu.
Jak vyřešit obecný problém pomocí Optimization Solver:
- Definuj svůj problém jako účelovou funkci, graf nebo
SparsePauliOpspin chain. - Připoj se k funkci prostřednictvím katalogu Qiskit Functions.
- Spusť problém pomocí Solveru a načti výsledky.
Přijímané formáty problémů
-
Polynomiální vyjádření účelové funkce. Ideálně vytvořené v Pythonu s existujícím objektem SymPy Poly a formátované do řetězce pomocí sympy.srepr.
-
Grafová reprezentace konkrétního typu problému. Graf by měl být vytvořen pomocí knihovny networkx v Pythonu. Poté by měl být převeden na řetězec pomocí funkce networkx
nx.readwrite.json_graph.adjacency_data. -
Reprezentace spin chain konkrétního problému. Spin chain by měl být reprezentován jako objekt
SparsePauliOp; více podrobností najdeš v dokumentaci.
Pokud chceš použít Backend, který tato funkce aktuálně nepodporuje, kontaktuj Q-CTRL a přidej jeho podporu.
Benchmarky
Výkon může záviset jak na konkrétní instanci problému, tak na následných krocích zpracování. V některých případech mohou klasické vzorky a kvantově generované vzorky dosáhnout po ekvivalentním postprocessingu podobné kvality výsledného řešení. Hodnocení by proto mělo brát v úvahu celý optimalizační pracovní postup.
Publikované výsledky benchmarkingu ukazují, že Solver úspěšně řeší problémy s více než 120 qubity a dokonce překonává dříve publikované výsledky na kvantových žíhacích a trapped-ion zařízeních. Následující metriky benchmarku poskytují hrubý přehled o přesnosti a škálování typů problémů na základě několika příkladů. Skutečné metriky se mohou lišit v závislosti na různých vlastnostech problému, jako je počet členů v účelové funkci (hustota) a jejich lokalita, počet proměnných a polynomiální řád.
Uvedený „Počet qubitů" není pevným omezením, ale představuje přibližné prahové hodnoty, kde lze očekávat mimořádně konzistentní přesnost řešení. Větší velikosti problémů byly úspěšně vyřešeny a testování za těmito hranicemi je podporováno.
Libovolná konektivita qubitů je podporována napříč všemi typy problémů.
| Typ problému | Počet qubitů | Příklad | Přesnost | Celkový čas (s) | Využití Runtime (s) | Počet iterací |
|---|---|---|---|---|---|---|
| Řídce propojené kvadratické problémy | 156 | 3-regulární max-cut | 100% | 1764 | 293 | 16 |
| Binární optimalizace vyššího řádu | 156 | Ising spin-glass model | 100% | 1461 | 272 | 16 |
| Hustě propojené kvadratické problémy | 50 | Plně propojený max-cut | 100% | 1758 | 268 | 12 |
| Omezený problém s tvrdými omezeními | 50 | Vážené rozdělení grafu s hustotou hran 8 % | 100% | 1074 | 215 | 10 |
Začínáme
Nejprve se ověř pomocí svého IBM Quantum API klíče. Poté vyber Qiskit Function takto. (Tento úryvek předpokládá, že jsi již uložil/a svůj účet do svého lokálního prostředí.)
# 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")
# Verify that you have access to the function
catalog.list()
[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")
Příklad: Neomezená optimalizace
Spusť problém maximálního řezu (Max-Cut). Následující příklad ukazuje schopnosti Solveru na problému Max-Cut s 156uzlovým, 3-regulárním nevážený grafem, ale lze řešit i vážené grafové problémy.
Kromě qiskit-ibm-catalog budeš k tomuto příkladu také potřebovat následující balíčky: networkx a numpy. Tyto balíčky můžeš nainstalovat odkomentováním následující buňky, pokud spouštíš tento příklad v notebooku pomocí IPython kernelu.
# %pip install networkx numpy
1. Definuj problém
Problém Max-Cut můžeš spustit definováním grafového problému a zadáním 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
)

Solver přijímá řetězec jako vstup definice problému.
# Convert graph to string
problem_as_str = nx.readwrite.json_graph.adjacency_data(maxcut_graph)
2. Spusť problém
Při použití vstupní metody na základě grafu zadej typ problému.
# 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"
)
Zkontroluj stav své pracovní zátěže Qiskit Function nebo načti výsledky takto:
# Print the ID so you can use it later, if necessary
print(maxcut_job.job_id)
# Get job status
print(maxcut_job.status())
34b53970-d95a-4e24-8763-fc6f3d112843
QUEUED
3. Načti výsledek
Načti optimální hodnotu řezu ze slovníku výsledků.
Mapování proměnných na bitstring se mohlo změnit. Výstupní slovník obsahuje podslovník variables_to_bitstring_index_map, který pomáhá ověřit pořadí.
# 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
Přesnost výsledku můžeš ověřit klasickým řešením problému pomocí open-source solverů jako PuLP, pokud graf není hustě propojený. Problémy s vysokou hustotou mohou pro ověření řešení vyžadovat pokročilé klasické solvery.
Příklad: Omezená optimalizace
Předchozí příklad max-cut je běžný problém kvadratické neomezené binární optimalizace. Optimization Solver od Q-CTRL dokáže řešit i omezené optimalizační problémy tím, že tvrdá omezení předá přímo Solveru prostřednictvím vstupu constraint, místo aby je kódoval jako penalizační termy v účelové funkci. Solver v současnosti podporuje omezení typu Hammingova váha 1: každé omezení určuje skupinu proměnných, kde přesně jedna proměnná musí být rovna 1 a zbytek musí být roven 0.
Následující příklad ukazuje, jak sestavit účelovou funkci a sadu tvrdých omezení pro omezený optimalizační problém, rozdělení grafu, přiřazením každého uzlu v grafu právě do jedné z několika skupin při minimalizaci celkové váhy hran, jejichž koncové body leží ve stejné skupině.
Kromě balíčků qiskit-ibm-catalog a qiskit budeš k tomuto příkladu také potřebovat: numpy, networkx a sympy. Tyto balíčky můžeš nainstalovat odkomentováním následující buňky, pokud spouštíš tento příklad v notebooku pomocí IPython kernelu.
# %pip install numpy networkx sympy
1. Definuj problém
Definuj náhodný problém rozdělení grafu vygenerováním grafu s náhodně váženými uzly.
import networkx as nx
from sympy import Symbol, 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
graph = nx.erdos_renyi_graph(
node_count, edge_probability, seed=rng_seed, directed=False
)
# add node weights
min_weight = -1.0
max_weight = 1.0
for i in graph.nodes:
weight = (max_weight - min_weight) * _rng.random() + min_weight
graph.add_node(i, weight=weight)
# Optionally, visualize the graph
nx.draw_networkx(graph, nx.kamada_kawai_layout(graph), node_size=200)

Standardní optimalizační model pro vážené rozdělení grafu lze formulovat následovně. Rozděl uzly grafu do tří skupin a nech , pokud je uzel přiřazen do skupiny , a jinak. Cílem je minimalizovat celkovou váhu hran, jejichž koncové body jsou přiřazeny do stejné skupiny, kde váha hrany je kombinovaná váha jejích dvou koncových bodů, :
# Construct the cost function.
group_count = 3
variables = [
Symbol(f"n[{i},{g}]")
for i in range(node_count)
for g in range(group_count)
]
node_group_var = {
(i, g): variables[i * group_count + g]
for i in range(node_count)
for g in range(group_count)
}
cost_function = Poly(0, *variables)
for i, j in graph.edges():
edge_weight = graph.nodes[i]["weight"] + graph.nodes[j]["weight"]
for g in range(group_count):
cost_function += (
edge_weight * node_group_var[(i, g)] * node_group_var[(j, g)]
)
Každý uzel musí být přiřazen přesně do jedné ze tří skupin. Toto je omezení typu Hammingova váha 1: pro každý uzel musí být přesně jedna z hodnot rovna 1 a zbytek musí být roven 0:
Místo toho, aby byl tento požadavek kódován jako penalizační term v účelové funkci, předej ho Solveru přímo jako tvrdé omezení pomocí vstupu constraint.
# Build the hard constraint: exactly one group per node.
constraint_dict = {
str(tuple(f"n[{i},{g}]" for g in range(group_count))): 1
for i in range(node_count)
}
print(f"Problem constraints: {constraint_dict}")
Problem constraints: {"('n[0,0]', 'n[0,1]', 'n[0,2]')": 1, "('n[1,0]', 'n[1,1]', 'n[1,2]')": 1, "('n[2,0]', 'n[2,1]', 'n[2,2]')": 1, "('n[3,0]', 'n[3,1]', 'n[3,2]')": 1, "('n[4,0]', 'n[4,1]', 'n[4,2]')": 1, "('n[5,0]', 'n[5,1]', 'n[5,2]')": 1, "('n[6,0]', 'n[6,1]', 'n[6,2]')": 1, "('n[7,0]', 'n[7,1]', 'n[7,2]')": 1, "('n[8,0]', 'n[8,1]', 'n[8,2]')": 1, "('n[9,0]', 'n[9,1]', 'n[9,2]')": 1, "('n[10,0]', 'n[10,1]', 'n[10,2]')": 1, "('n[11,0]', 'n[11,1]', 'n[11,2]')": 1, "('n[12,0]', 'n[12,1]', 'n[12,2]')": 1, "('n[13,0]', 'n[13,1]', 'n[13,2]')": 1, "('n[14,0]', 'n[14,1]', 'n[14,2]')": 1, "('n[15,0]', 'n[15,1]', 'n[15,2]')": 1, "('n[16,0]', 'n[16,1]', 'n[16,2]')": 1, "('n[17,0]', 'n[17,1]', 'n[17,2]')": 1, "('n[18,0]', 'n[18,1]', 'n[18,2]')": 1, "('n[19,0]', 'n[19,1]', 'n[19,2]')": 1, "('n[20,0]', 'n[20,1]', 'n[20,2]')": 1, "('n[21,0]', 'n[21,1]', 'n[21,2]')": 1, "('n[22,0]', 'n[22,1]', 'n[22,2]')": 1, "('n[23,0]', 'n[23,1]', 'n[23,2]')": 1, "('n[24,0]', 'n[24,1]', 'n[24,2]')": 1, "('n[25,0]', 'n[25,1]', 'n[25,2]')": 1, "('n[26,0]', 'n[26,1]', 'n[26,2]')": 1, "('n[27,0]', 'n[27,1]', 'n[27,2]')": 1, "('n[28,0]', 'n[28,1]', 'n[28,2]')": 1, "('n[29,0]', 'n[29,1]', 'n[29,2]')": 1, "('n[30,0]', 'n[30,1]', 'n[30,2]')": 1, "('n[31,0]', 'n[31,1]', 'n[31,2]')": 1, "('n[32,0]', 'n[32,1]', 'n[32,2]')": 1, "('n[33,0]', 'n[33,1]', 'n[33,2]')": 1, "('n[34,0]', 'n[34,1]', 'n[34,2]')": 1, "('n[35,0]', 'n[35,1]', 'n[35,2]')": 1, "('n[36,0]', 'n[36,1]', 'n[36,2]')": 1, "('n[37,0]', 'n[37,1]', 'n[37,2]')": 1, "('n[38,0]', 'n[38,1]', 'n[38,2]')": 1, "('n[39,0]', 'n[39,1]', 'n[39,2]')": 1, "('n[40,0]', 'n[40,1]', 'n[40,2]')": 1, "('n[41,0]', 'n[41,1]', 'n[41,2]')": 1, "('n[42,0]', 'n[42,1]', 'n[42,2]')": 1, "('n[43,0]', 'n[43,1]', 'n[43,2]')": 1, "('n[44,0]', 'n[44,1]', 'n[44,2]')": 1, "('n[45,0]', 'n[45,1]', 'n[45,2]')": 1, "('n[46,0]', 'n[46,1]', 'n[46,2]')": 1, "('n[47,0]', 'n[47,1]', 'n[47,2]')": 1, "('n[48,0]', 'n[48,1]', 'n[48,2]')": 1, "('n[49,0]', 'n[49,1]', 'n[49,2]')": 1}
Nemusíš přidat každou proměnnou do constraint. Jakákoli proměnná, která ve slovníku chybí, zůstává neomezená, takže můžeš v rámci stejného problému kombinovat skupiny proměnných s tvrdým omezením a volné proměnné.
2. Spusť problém
# Solve the problem
partition_job = solver.run(
problem=srepr(cost_function),
constraint=constraint_dict,
backend_name="ibm_marrakesh", # E.g. "ibm_marrakesh"
)
Zkontroluj stav své pracovní zátěže Qiskit Function nebo načti výsledky takto:
# Print the ID so you can use it later, if necessary
print(partition_job.job_id)
# Get job status
print(partition_job.status())
b8085944-f313-444e-be39-ea61b1b47ebd
QUEUED
3. Získej výsledek
Získej řešení a analyzuj výsledky. Cena řešení představuje celkovou váhu hran, jejichž koncové body skončily ve stejné skupině, takže nižší cena znamená lepší rozdělení grafu.
partition_result = partition_job.result()
qctrl_cost = partition_result["solution_bitstring_cost"]
solution_bitstring = partition_result["solution_bitstring"]
# Print results
print(f"Total weight of same-group edges: {qctrl_cost}")
print(f"Solution bitstring: {solution_bitstring}")
Total weight of same-group edges: -36.5539
Solution bitstring: 100100100100100001100100100100100100100100100100100001010100010100100100100010001001100100100001100001100001010001001010100100100100100010100100100100
Získej podporu
Máš-li jakékoli dotazy nebo problémy, kontaktuj Q-CTRL.
Changelog
-
2026-08-10: Přidána podpora tvrdých omezení (Hammingova váha 1) prostřednictvím vstupu
constrainta aktualizován příklad omezené optimalizace tak, aby je používal. -
2026-02-11: Nyní je podporováno
ibm_miami
Další kroky
-
Požádej o přístup k Q-CTRL Optimization Solver.
-
Viz referenci API pro tuto Qiskit Function.
-
Vyzkoušej tutoriál Řešení binárních optimalizačních problémů vyššího řádu pomocí Optimization Solver od Q-CTRL.
-
Přečti si případovou studii Mazda.
-
Přečti si případovou studii Network Rail.
-
Přečti si případovou studii Australian Army.
-
Přečti si případovou studii Transport for New South Wales.