Lewati ke konten utama

Optimization Solver: Qiskit Function oleh Q-CTRL Fire Opal

Lihat referensi API

catatan

Qiskit Functions adalah fitur eksperimental yang hanya tersedia untuk pengguna IBM Quantum® Premium Plan, Flex Plan, dan On-Prem (melalui IBM Quantum Platform API) Plan. Fitur ini dalam status rilis pratinjau dan bisa berubah sewaktu-waktu.

Versi paket

Kode di halaman ini dikembangkan menggunakan persyaratan berikut. Kami merekomendasikan menggunakan versi ini atau yang lebih baru.

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

Ikhtisar

Dengan Fire Opal Optimization Solver, kamu bisa memecahkan masalah optimasi skala utilitas di perangkat keras kuantum tanpa perlu keahlian kuantum. Cukup masukkan definisi masalah tingkat tinggi, dan Solver akan menangani sisanya. Seluruh alur kerja bersifat noise-aware dan memanfaatkan Fire Opal's Performance Management di balik layar. Solver secara konsisten menghasilkan solusi yang akurat untuk masalah yang menantang secara klasik, bahkan pada skala perangkat penuh di QPU IBM® terbesar.

Solver bersifat fleksibel dan dapat digunakan untuk memecahkan masalah optimasi kombinatorial yang didefinisikan sebagai fungsi objektif atau graf sembarang. Masalah tidak perlu dipetakan ke topologi perangkat. Baik masalah tidak terkendali maupun terkendali dapat diselesaikan, dengan kendala dipaksakan sebagai hard Hamming-weight-1 constraints daripada suku penalti. Contoh-contoh yang disertakan dalam panduan ini menunjukkan cara memecahkan masalah optimasi skala utilitas yang tidak terkendali dan terkendali menggunakan berbagai tipe input Solver. Contoh pertama melibatkan masalah Max-Cut yang didefinisikan pada graf 3-Regular dengan 156 simpul, sementara contoh kedua menangani masalah graph partitioning 50 simpul yang didefinisikan oleh fungsi biaya.

Untuk mendapatkan akses ke Optimization Solver, hubungi Q-CTRL.

Deskripsi fungsi

Solver sepenuhnya mengoptimalkan dan mengotomatiskan seluruh algoritma, mulai dari supresi kesalahan di tingkat perangkat keras hingga pemetaan masalah yang efisien dan optimasi klasik loop tertutup. Di balik layar, pipeline Solver mengurangi kesalahan di setiap tahap, memungkinkan peningkatan performa yang dibutuhkan untuk penskalaan yang bermakna. Alur kerja yang mendasarinya terinspirasi dari Quantum Approximate Optimization Algorithm (QAOA), yang merupakan algoritma hibrida kuantum-klasik. Untuk ringkasan lengkap alur kerja Optimization Solver, lihat manuskrip yang dipublikasikan.

Visualisasi alur kerja Optimization Solver

Untuk memecahkan masalah umum dengan Optimization Solver:

  1. Definisikan masalahmu sebagai fungsi objektif, graf, atau rantai spin SparsePauliOp.
  2. Hubungkan ke fungsi melalui Qiskit Functions Catalog.
  3. Jalankan masalah dengan Solver dan ambil hasilnya.

Format masalah yang diterima

  • Representasi ekspresi polinomial dari fungsi objektif. Idealnya dibuat di Python dengan objek SymPy Poly yang sudah ada dan diformat menjadi string menggunakan sympy.srepr.

  • Representasi graf dari tipe masalah tertentu. Graf harus dibuat menggunakan library networkx di Python. Kemudian dikonversi ke string menggunakan fungsi networkx nx.readwrite.json_graph.adjacency_data.

  • Representasi rantai spin dari masalah tertentu. Rantai spin harus direpresentasikan sebagai objek SparsePauliOp; lihat dokumentasi untuk detail lebih lanjut.

Apakah fungsi ini mendukung semua Backend IBM?

Jika kamu ingin menggunakan Backend yang belum didukung oleh fungsi ini, hubungi Q-CTRL untuk menambahkan dukungan.

Tolok ukur

Hasil tolok ukur yang dipublikasikan menunjukkan bahwa Solver berhasil memecahkan masalah dengan lebih dari 120 qubit, bahkan mengungguli hasil yang sebelumnya dipublikasikan pada anil kuantum dan perangkat ion terjebak. Metrik tolok ukur berikut memberikan indikasi kasar tentang akurasi dan penskalaan tipe masalah berdasarkan beberapa contoh. Metrik aktual bisa berbeda berdasarkan berbagai fitur masalah, seperti jumlah suku dalam fungsi objektif (kepadatan) dan lokalitasnya, jumlah variabel, dan orde polinomial.

"Jumlah qubit" yang ditunjukkan bukanlah batasan keras tetapi merepresentasikan ambang batas kasar di mana kamu dapat mengharapkan akurasi solusi yang sangat konsisten. Ukuran masalah yang lebih besar telah berhasil dipecahkan, dan pengujian di luar batas ini sangat dianjurkan.

Konektivitas qubit sembarang didukung di semua tipe masalah.

Tipe masalahJumlah qubitContohAkurasiTotal waktu (s)Penggunaan runtime (s)Jumlah iterasi
Masalah kuadratik dengan koneksi jarang1563-regular Max-Cut100%176429316
Optimasi biner orde tinggi156Model spin-glass Ising100%146127216
Masalah kuadratik dengan koneksi padat50Max-Cut penuh terkoneksi100%175826812
Masalah terkendali dengan hard constraints50Weighted graph partitioning dengan kepadatan tepi 8%100%107421510

Mulai

Pertama, autentikasi menggunakan kunci API IBM Quantum-mu. Kemudian, pilih Qiskit Function sebagai berikut. (Cuplikan ini mengasumsikan kamu sudah menyimpan akunmu ke lingkungan lokalmu.)

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

Contoh: Optimasi tidak terkendali

Jalankan masalah maximum cut (Max-Cut). Contoh berikut mendemonstrasikan kemampuan Solver pada masalah Max-Cut graf tidak berbobot 3-regular dengan 156 simpul, tapi kamu juga bisa memecahkan masalah graf berbobot. Selain qiskit-ibm-catalog, kamu juga akan menggunakan paket berikut untuk menjalankan contoh ini: networkx dan numpy. Kamu bisa menginstal paket-paket ini dengan membatalkan komentar sel berikut jika kamu menjalankan contoh ini di notebook menggunakan kernel IPython.

# %pip install networkx numpy

1. Definisikan masalah

Kamu bisa menjalankan masalah Max-Cut dengan mendefinisikan masalah graf dan menentukan 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

Solver menerima string sebagai input definisi masalah.

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

2. Jalankan masalah

Saat menggunakan metode input berbasis graf, tentukan tipe masalah.

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

Periksa status workload Qiskit Function-mu atau ambil hasil sebagai berikut:

# 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. Ambil hasilnya

Ambil nilai potongan optimal dari kamus hasil.

catatan

Pemetaan variabel ke bitstring mungkin telah berubah. Kamus output berisi sub-kamus variables_to_bitstring_index_map, yang membantu memverifikasi urutannya.

# 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

Kamu bisa memverifikasi akurasi hasil dengan memecahkan masalah secara klasik menggunakan solver open-source seperti PuLP jika graf tidak terhubung padat. Masalah dengan kepadatan tinggi mungkin memerlukan solver klasik tingkat lanjut untuk memvalidasi solusinya.

Contoh: Optimasi terkendali

Contoh max-cut sebelumnya adalah masalah quadratic unconstrained binary optimization yang umum. Optimization Solver dari Q-CTRL juga bisa menyelesaikan masalah optimasi terkendali dengan meneruskan hard constraint secara langsung ke Solver melalui input constraint, alih-alih mengkodekannya sebagai penalty term dalam fungsi objektif. Solver saat ini mendukung constraint Hamming-weight-1: setiap constraint menentukan sekelompok variabel di mana tepat satu variabel harus sama dengan 1 dan sisanya harus sama dengan 0.

Contoh berikut mendemonstrasikan cara membangun fungsi biaya dan sekumpulan hard constraint untuk masalah optimasi terkendali, graph partitioning, dengan menetapkan setiap node dalam graf ke tepat satu dari beberapa kelompok sambil meminimalkan total bobot edge yang kedua ujungnya berada dalam kelompok yang sama. Selain paket qiskit-ibm-catalog dan qiskit, kamu juga akan menggunakan paket berikut untuk menjalankan contoh ini: numpy, networkx, dan sympy. Kamu bisa menginstal paket-paket ini dengan membatalkan komentar sel berikut jika kamu menjalankan contoh ini di notebook menggunakan kernel IPython.

# %pip install numpy networkx sympy

1. Definisikan masalah

Definisikan masalah graph partitioning acak dengan membuat graf dengan simpul berbobot acak.

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

Model optimasi standar untuk weighted graph partitioning dapat diformulasikan sebagai berikut. Bagi node-node dari graf menjadi tiga kelompok g{0,1,2}g \in \{0, 1, 2\}, dan biarkan ni,g=1n_{i,g} = 1 jika node ii ditetapkan ke kelompok gg, dan ni,g=0n_{i,g} = 0 jika tidak. Tujuannya adalah untuk meminimalkan total bobot edge yang kedua ujungnya ditetapkan ke kelompok yang sama, di mana bobot dari edge (i,j)(i,j) adalah gabungan bobot dari kedua ujungnya, ωi,j=ωi+ωj\omega_{i,j} = \omega_i + \omega_j:

Minimizey=(i,j)Eωi,jgni,gnj,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)]
)

Setiap node harus ditetapkan ke tepat satu dari tiga kelompok. Ini adalah constraint Hamming-weight-1: untuk setiap node ii, tepat satu dari ni,0,ni,1,ni,2n_{i,0}, n_{i,1}, n_{i,2} harus sama dengan 1, dan sisanya harus sama dengan 0:

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

Daripada mengkodekan persyaratan ini sebagai penalty term dalam fungsi biaya, teruskan langsung ke Solver sebagai hard constraint menggunakan input 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}
Masalah yang sebagian terkendala

Kamu tidak perlu menambahkan setiap variabel ke constraint. Variabel apa pun yang tidak dimasukkan dalam dictionary tetap tidak terkendala, sehingga kamu bisa mencampur kelompok variabel yang hard-constrained dengan variabel bebas dalam masalah yang sama.

2. Jalankan masalah

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

Periksa status workload Qiskit Function-mu atau ambil hasil sebagai berikut:

# 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. Dapatkan hasilnya

Ambil solusinya dan analisis hasilnya. Biaya solusi merepresentasikan total bobot edge yang kedua ujungnya berakhir dalam kelompok yang sama, sehingga biaya yang lebih rendah menunjukkan partisi graf yang lebih baik.

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

Dapatkan dukungan

Untuk pertanyaan atau masalah apa pun, hubungi Q-CTRL.

Changelog

  • 2026-08-10: Menambahkan dukungan untuk hard constraint (Hamming weight 1) melalui input constraint, dan memperbarui contoh optimasi terkendala untuk menggunakannya.

  • 2026-02-11: Kami sekarang mendukung ibm_miami

Langkah selanjutnya