Lumaktaw sa pangunahing nilalaman
Ang proyektong ito ay nasa beta. Nakakita ng bug? Mag-bukas ng GitHub issue. May tanong o ideya? Magtanong sa Discussions — gusto naming marinig ang iyong feedback!
Gaano kaganda ang kalidad ng pagsasalin sa pahinang ito?

Optimization Solver: Isang Qiskit Function ng Q-CTRL Fire Opal

Tingnan ang API reference

tala

Ang Qiskit Functions ay isang experimental na feature na available lamang sa mga gumagamit ng IBM Quantum® Premium Plan, Flex Plan, at On-Prem (sa pamamagitan ng IBM Quantum Platform API) Plan. Nasa preview release status ang mga ito at maaaring magbago.

Package versions

Ang code sa pahinang ito ay binuo gamit ang mga sumusunod na requirement. Inirerekomenda naming gamitin ang mga bersyong ito o mas bago.

qiskit-ibm-runtime~=0.47.0
sympy~=1.14.0

Pangkalahatang-ideya​

Gamit ang Fire Opal Optimization Solver, malulutas mo ang mga utility-scale na optimization problem sa quantum hardware nang hindi kailangan ng malalim na kaalaman sa quantum computing. I-input lang ang mataas na antas na depinisyon ng problema, at ang Solver ang bahala sa lahat. Ang buong workflow ay may kamalayan sa ingay at gumagamit ng Fire Opal's Performance Management sa likod ng sistema. Patuloy na nagbibigay ang Solver ng tumpak na solusyon sa mga problemang mahirap lutasin nang klasikal, kahit sa pinakamataas na sukat ng pinakamalalaking IBM® QPU.

Flexible ang Solver at magagamit para sa mga combinatorial optimization problem na tinukoy bilang objective function o arbitrary graph. Hindi kailangang i-map ang mga problema sa device topology. Malulutas ang parehong unconstrained at constrained na mga problema, kung saan ipinapatupad ang mga constraint bilang hard Hamming-weight-1 constraint sa halip na mga penalty term. Ipinapakita ng mga halimbawa sa gabay na ito kung paano lutasin ang isang unconstrained at isang constrained na utility-scale optimization problem gamit ang iba't ibang uri ng Solver input. Ang unang halimbawa ay isang max-cut problem na tinukoy sa isang 156-node, 3-Regular na graph, habang ang pangalawa ay isang 50-node na graph partitioning problem na tinukoy ng isang cost function.

Para makakuha ng access sa Optimization Solver, makipag-ugnayan sa Q-CTRL.

Paglalarawan ng function​

Ganap na ino-optimize at ino-automate ng Solver ang buong algorithm, mula sa error suppression sa hardware level hanggang sa mahusay na problem mapping at closed-loop classical optimization. Sa likod ng sistema, binabawasan ng pipeline ng Solver ang mga error sa bawat yugto, na nagbibigay ng mas mataas na performance na kailangan para makapag-scale nang maayos. Ang pinagbabatayang workflow ay inspirado ng Quantum Approximate Optimization Algorithm (QAOA), na isang hybrid quantum-classical na algorithm. Para sa detalyadong buod ng buong Optimization Solver workflow, tingnan ang nai-publish na manuskrito.

Visualization ng Optimization Solver workflow

Para malutas ang isang pangkalahatang problema gamit ang Optimization Solver:

  1. Tukuyin ang iyong problema bilang objective function, graph, o SparsePauliOp spin chain.
  2. Kumonekta sa function sa pamamagitan ng Qiskit Functions Catalog.
  3. Patakbuhin ang problema gamit ang Solver at kunin ang mga resulta.

Tinatanggap na mga format ng problema​

  • Polynomial expression na representasyon ng isang objective function. Mas mainam na gawin ito sa Python gamit ang isang umiiral na SymPy Poly object at i-format sa string gamit ang sympy.srepr.

  • Graph representation ng isang partikular na uri ng problema. Dapat gawin ang graph gamit ang networkx library sa Python. Pagkatapos ay i-convert ito sa string gamit ang networkx function na nx.readwrite.json_graph.adjacency_data.

  • Spin chain na representasyon ng isang partikular na problema. Dapat ireprensenta ang spin chain bilang SparsePauliOp object; tingnan ang dokumentasyon para sa karagdagang detalye.

Sinusuportahan ba ng function na ito ang lahat ng IBM backend?

Kung gusto mong gumamit ng backend na hindi pa sinusuportahan ng function na ito, makipag-ugnayan sa Q-CTRL para idagdag ang suporta.

Mga Benchmark​

Paunawa

Maaaring depende ang performance sa parehong problem instance at kasunod na mga hakbang sa pagproseso. Sa ilang kaso, maaaring umabot sa magkatulad na huling kalidad ng solusyon ang mga classical sample at ang mga quantum-generated sample matapos ang katumbas na post-processing. Kaya dapat isaalang-alang sa ebalwasyon ang kumpletong optimization workflow.

Ipinapakita ng mga nai-publish na resulta ng benchmarking na matagumpay na nireresulba ng Solver ang mga problema na may mahigit 120 qubit, at kahit pa nakakalampas sa mga dating nai-publish na resulta sa quantum annealing at trapped-ion na mga device. Ang mga sumusunod na benchmark metric ay nagbibigay ng magaspang na indikasyon ng katumpakan at scaling ng mga uri ng problema batay sa ilang halimbawa. Maaaring mag-iba ang aktwal na mga metric batay sa iba't ibang katangian ng problema, tulad ng bilang ng mga term sa objective function (density) at ang kanilang locality, bilang ng mga variable, at polynomial order.

Ang "Bilang ng mga qubit" na nakaindika ay hindi isang mahigpit na limitasyon kundi kumakatawan sa mga magaspang na threshold kung saan maaari kang umasa ng lubhang pare-pareho na katumpakan ng solusyon. Matagumpay nang nalutas ang mga mas malalaking sukat ng problema, at hinihikayat ang pagsubok na lagpas sa mga limitasyong ito.

Sinusuportahan ang arbitrary qubit connectivity sa lahat ng uri ng problema.

Uri ng problemaBilang ng mga qubitHalimbawaKatumpakanKabuuang oras (s)Paggamit ng runtime (s)Bilang ng mga iteration
Sparsely-connected na mga quadratic problem1563-regular max-cut100%176429316
Higher-order binary optimization156Ising spin-glass model100%146127216
Densely-connected na mga quadratic problem50Fully-connected max-cut100%175826812
Constrained na problema with hard constraints50Weighted graph partitioning with 8% edge density100%107421510

Magsimula​

Una, mag-authenticate gamit ang iyong IBM Quantum API key. Pagkatapos, piliin ang Qiskit Function tulad ng sumusunod. (Ipinapalagay ng snippet na ito na na-save mo na ang iyong account sa iyong lokal na kapaligiran.)

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

_needed = {"networkx": "networkx", "numpy": "numpy", "qiskit_ibm_catalog": "qiskit-ibm-catalog", "qiskit_ibm_runtime": "qiskit-ibm-runtime", "sympy": "sympy"}
_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(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")

Halimbawa: Unconstrained na optimization​

Patakbuhin ang maximum cut (Max-Cut) na problema. Ipinapakita ng sumusunod na halimbawa ang kakayahan ng Solver sa isang 156-node, 3-regular na unweighted graph Max-Cut problem, ngunit maaari ka ring lumutas ng mga weighted graph problem. Bukod sa qiskit-ibm-catalog, gagamitin mo rin ang mga sumusunod na package para patakbuhin ang halimbawang ito: networkx at numpy. Maaari mong i-install ang mga package na ito sa pamamagitan ng pag-uncomment ng sumusunod na cell kung pinapatakbo mo ang halimbawang ito sa isang notebook gamit ang IPython kernel.

# %pip install networkx numpy

1. Tukuyin ang problema​

Maaari kang magpatakbo ng Max-Cut problem sa pamamagitan ng pagde-define ng graph problem at pagtukoy ng 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 of the previous code cell

Tumatanggap ang Solver ng string bilang input ng depinisyon ng problema.

# Convert graph to string
problem_as_str = nx.readwrite.json_graph.adjacency_data(maxcut_graph)

2. Patakbuhin ang problema​

Kapag gumagamit ng graph-based na paraan ng input, tukuyin ang uri ng problema.

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

Suriin ang status ng iyong Qiskit Function workload o kunin ang mga resulta tulad ng sumusunod:

# 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. Kunin ang resulta​

Kunin ang pinakamainam na halaga ng cut mula sa results dictionary.

tala

Maaaring nagbago ang pagma-map ng mga variable sa bitstring. Ang output dictionary ay naglalaman ng variables_to_bitstring_index_map sub-dictionary, na tumutulong sa pag-verify ng pagkakasunod-sunod.

# 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

Maaari mong ma-verify ang katumpakan ng resulta sa pamamagitan ng paglutas ng problema nang klasikal gamit ang mga open-source solver tulad ng PuLP kung hindi masyadong siksik ang koneksyon ng graph. Para sa mga problemang may mataas na density, maaaring kailangan ng mas advanced na classical solver para ma-validate ang solusyon.

Halimbawa: Constrained na optimization​

Ang naunang halimbawa ng max-cut ay isang karaniwang quadratic unconstrained binary optimization problem. Kaya ring lutasin ng Q-CTRL's Optimization Solver ang mga constrained optimization problem sa pamamagitan ng pagpasa ng mga hard constraint nang direkta sa Solver sa pamamagitan ng constraint input, imbes na i-encode ang mga ito bilang mga penalty term sa objective function. Kasalukuyang sinusuportahan ng Solver ang mga Hamming-weight-1 constraint: bawat constraint ay tumutukoy ng isang grupo ng mga variable kung saan eksaktong isang variable lang ang dapat maging 1 at ang natitira ay dapat maging 0.

Ipinapakita ng sumusunod na halimbawa kung paano bumuo ng cost function at isang set ng mga hard constraint para sa isang constrained optimization problem, graph partitioning, sa pamamagitan ng pagtatalaga ng bawat node sa isang graph sa eksaktong isa sa ilang mga grupo habang mini-minimize ang kabuuang timbang ng mga edge kung saan ang mga endpoint ay napapadpad sa parehong grupo. Bukod sa mga package na qiskit-ibm-catalog at qiskit, gagamitin mo rin ang mga sumusunod na package para patakbuhin ang halimbawang ito: numpy, networkx, at sympy. Maaari mong i-install ang mga package na ito sa pamamagitan ng pag-uncomment ng sumusunod na cell kung pinapatakbo mo ang halimbawang ito sa isang notebook gamit ang IPython kernel.

# %pip install numpy networkx sympy

1. Tukuyin ang problema​

Tukuyin ang isang random na graph partitioning problem sa pamamagitan ng paglikha ng graph na may mga node na may random na timbang.

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)

Output of the previous code cell

Ang isang standard optimization model para sa weighted graph partitioning ay maaaring i-formulate gaya ng sumusunod. Hatiin ang mga node ng graph sa tatlong grupo g∈{0,1,2}g \in \{0, 1, 2\}, at hayaang ni,g=1n_{i,g} = 1 kung ang node ii ay itinalaga sa grupo gg, at ni,g=0n_{i,g} = 0 kung hindi. Ang layunin ay i-minimize ang kabuuang timbang ng mga edge kung saan ang mga endpoint ay itinalaga sa parehong grupo, kung saan ang timbang ng isang edge (i,j)(i,j) ay ang pinagsamang timbang ng dalawa nitong endpoint, ωi,j=ωi+ωj\omega_{i,j} = \omega_i + \omega_j:

Minimizey=∑(i,j)∈Eωi,j∑gni,g nj,g\textbf{Minimize}\qquad y = \sum_{(i,j)\in E} \omega_{i,j} \sum_{g} n_{i,g}\, n_{j,g}

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

Dapat maitalaga ang bawat node sa eksaktong isa sa tatlong grupo. Ito ay isang Hamming-weight-1 constraint: para sa bawat node ii, eksaktong isa sa ni,0,ni,1,ni,2n_{i,0}, n_{i,1}, n_{i,2} ang dapat maging 1, at ang natitira ay dapat maging 0:

ni,0+ni,1+ni,2=1 for all i∈Vn_{i,0} + n_{i,1} + n_{i,2} = 1 \texttt{ for all } i \in V

Sa halip na i-encode ang requirement na ito bilang isang penalty term sa cost function, ipasa ito nang direkta sa Solver bilang isang hard constraint gamit ang constraint input.

# 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}
Mga bahagyang constrained na problema

Hindi mo kailangang idagdag ang bawat variable sa constraint. Ang anumang variable na hindi kasama sa dictionary ay mananatiling unconstrained, kaya maaari mong pagsamahin ang mga hard-constrained na grupo ng mga variable kasama ang mga malayang variable sa parehong problema.

2. Patakbuhin ang problema​

# Solve the problem
partition_job = solver.run(
problem=srepr(cost_function),
constraint=constraint_dict,
backend_name="ibm_marrakesh", # E.g. "ibm_marrakesh"
)

Suriin ang status ng iyong Qiskit Function workload o kunin ang mga resulta tulad ng sumusunod:

# 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. Kunin ang resulta​

Kunin ang solusyon at suriin ang mga resulta. Ang cost ng solusyon ay kumakatawan sa kabuuang timbang ng mga edge kung saan ang mga endpoint ay napunta sa parehong grupo, kaya ang mas mababang cost ay nagpapahiwatig ng mas mahusay na partitioning ng graph.

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

Makakuha ng suporta​

Para sa anumang katanungan o isyu, makipag-ugnayan sa Q-CTRL.

Talaan ng mga Pagbabago​

  • 2026-08-10: Idinagdag ang suporta para sa mga hard (Hamming weight 1) constraint sa pamamagitan ng constraint input, at na-update ang halimbawa ng constrained optimization para gamitin ang mga ito.

  • 2026-02-11: Mayroon na kaming suporta para sa ibm_miami

Mga susunod na hakbang​