Selesaikan model Sherrington-Kirkpatrick dengan ParityQC Parity Twine Optimizer
Estimasi penggunaan: 10 detik pada prosesor Nighthawk r2. (CATATAN: Ini hanya perkiraan. Runtime Anda mungkin bervariasi.)
Hasil pembelajaran
-
Gunakan Parity Twine Optimizer untuk menyelesaikan model Sherrington-Kirkpatrick.
-
Pelajari opsi apa saja yang tersedia untuk Parity Twine Optimizer dan hasil apa yang dikeluarkan.
Latar belakang
Tutorial ini mendemonstrasikan cara menyelesaikan model Sherrington-Kirkpatrick menggunakan ParityQC Parity Twine Optimizer.
Tutorial ini menyediakan kode untuk merumuskan masalah sepenuhnya secara lokal dalam bentuk yang dapat berinteraksi dengan Parity Twine Optimizer.
Model Sherrington-Kirkpatrick
Model Sherrington-Kirkpatrick (SK) adalah model dasar dalam mekanika statistik, khususnya dalam studi tentang spin glass. Berbeda dengan model Ising standar, di mana interaksi biasanya terbatas pada tetangga terdekat, model SK adalah model jangkauan tak-hingga, yang berarti setiap spin berinteraksi dengan setiap spin lain dalam sistem. Hal ini menghasilkan lanskap energi yang sangat kompleks dan "terjal" (berbukit-bukit), yang ditandai dengan banyak minima lokal, yang merupakan ciri khas perilaku mirip kaca (glassy).
Fitur inti dari model SK terletak pada frustrasi. Dalam model ini, kekuatan interaksi antar spin didistribusikan secara acak antara nilai positif dan negatif. Hal ini menghasilkan situasi (misalnya, dalam susunan segitiga) di mana spin tidak dapat disusun untuk meminimalkan semua interaksi secara bersamaan. Dalam model SK, karena setiap spin berinteraksi dengan setiap spin lain, frustrasi ini diperparah secara global, sehingga menghasilkan jaringan batasan yang saling bertentangan.
Formulasi matematis
Keadaan sistem didefinisikan oleh sekumpulan spin Ising, . Energi dari konfigurasi tertentu diberikan oleh Hamiltonian:
di mana adalah kekuatan kopling antara spin dan spin .
Dalam model SK, kopling adalah variabel acak yang independen dan terdistribusi identik. Untuk memastikan bahwa energi tetap ekstensif (proporsional dengan ) saat , varians kopling harus berskala dengan jumlah partikel:
Keadaan dasar untuk tertentu adalah konfigurasi spin tertentu (), yang meminimalkan energi. Menemukan keadaan dasar adalah masalah optimasi NP-hard.
Persyaratan
Sebelum memulai tutorial ini, pastikan hal berikut telah terinstal:
-
Qiskit Functions Catalog IBM Client (
pip install qiskit-ibm-catalog) -
Qiskit addon Optimization Mapper (
pip install qiskit_addon_opt_mapper) -
NumPy (
pip install numpy)
Anda juga memerlukan izin untuk mengakses fungsi ParityQC Twine Optimizer. Untuk meminta akses, isi formulir ini.
Pengaturan
(Kode ini mengasumsikan Anda sudah menyimpan akun Anda ke lingkungan lokal Anda.)
Pertama, impor semua paket yang diperlukan untuk tutorial ini.
# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util
_needed = {"numpy": "numpy", "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")
import numpy as np
from qiskit_ibm_catalog import QiskitFunctionsCatalog
Muat Parity Twine Optimizer dari katalog Qiskit Functions:
catalog = QiskitFunctionsCatalog(channel="ibm_quantum_platform")
function = catalog.load("parityqc/parity-twine-optimizer")
Langkah 1: Definisikan masalah sebagai fungsi objektif
Alih-alih memperoleh masalah SK dari library seperti yang kita lakukan untuk masalah Market Split, Anda merumuskannya secara langsung.
Fungsi generate_sk_problem merumuskan masalah SK secara langsung dalam format dictionary yang diperlukan. Satu-satunya input yang diperlukan adalah n, jumlah spin dalam model.
def generate_sk_problem(
n: int,
coupling_mean: float = 0.0,
coupling_std: float = 1.0,
local_fields_mean: float = 0.0,
local_fields_std: float = 0.0,
edge_density: float = 1.0,
ensure_extensivity: bool = False,
seed: int | None = None,
) -> dict:
"""Generate the Sherrington-Kirkpatrick (SK) model with varying
edge density.
Samples couplings and local fields via ``generate_couplings_sk_model``
and assembles the corresponding Ising Hamiltonian
H = -∑_{i<j} J_ij z_i z_j - ∑_i h_i z_i,
where z_i ∈ {-1, +1}.
Args:
n: Number of spins (>= 2).
coupling_mean: Mean coupling before optional SK scaling.
coupling_std: Coupling std before optional SK scaling.
local_fields_mean: Mean longitudinal field.
local_fields_std: Std of the longitudinal fields.
edge_density: Fraction of non-zero couplings, in ``[2/n, 1]``.
ensure_extensivity: Whether to apply the SK 1/n scaling.
seed: random number generator seed.
Returns:
An encoding the SK Hamiltonian.
Raises:
ValueError: If ``n < 2``, ``coupling_std < 0``, ``local_fields_std < 0``,
or ``edge_density`` is outside ``[2/n, 1]``.
"""
couplings, local_fields = _generate_couplings_sk_model(
n=n,
coupling_mean=coupling_mean,
coupling_std=coupling_std,
local_fields_mean=local_fields_mean,
local_fields_std=local_fields_std,
edge_density=edge_density,
ensure_extensivity=ensure_extensivity,
seed=seed,
)
# Handle quadratic terms: coupling[i, j] * zj[i] * zj[j]
# Only iterate over the upper triangle (i < j)
sk_problem = {
str((i, j)): float(couplings[i, j])
for i in range(n)
for j in range(i + 1, n)
if couplings[i, j] != 0
}
# Handle linear terms: local_fields[i] * zj[i]
sk_problem.update(
{
str((i,)): float(local_fields[i])
for i in range(n)
if local_fields[i] != 0
}
)
return sk_problem
Gunakan fungsi _generate_couplings_sk_model untuk menghitung suku kopling acak dalam model SK. Untuk kontrol lebih lanjut atas kopling, Anda dapat menggunakan argumen opsional, yang dijelaskan dalam docstring fungsi tersebut.
def _generate_couplings_sk_model(
n: int,
coupling_mean: float = 0.0,
coupling_std: float = 1.0,
local_fields_mean: float = 0.0,
local_fields_std: float = 0.0,
edge_density: float = 1.0,
ensure_extensivity: bool = False,
seed: int | None = None,
) -> tuple[np.ndarray, np.ndarray]:
"""Generate random couplings and local fields for an Ising / SK model.
Couplings are Gaussian. With ``ensure_extensivity=True`` they follow the
Sherrington-Kirkpatrick scaling ``J_ij ~ N(coupling_mean/n, coupling_std^2/n)``
(extensive energy, O(n)); otherwise ``J_ij ~ N(coupling_mean, coupling_std^2)``
(energy O(n^2)). Fields are ``h_i ~ N(local_fields_mean, local_fields_std^2)``.
``edge_density`` sets the fraction of the ``n*(n-1)/2`` possible couplings that
are non-zero (1 = fully dense). The kept edges always include a random spanning
tree, so the interaction graph is guaranteed connected. This requires at least
``n-1`` edges, so ``edge_density`` must be at least ``2/n``.
Args:
n: Number of spins (>= 2).
coupling_mean: Mean coupling before optional SK scaling.
coupling_std: Coupling std before optional SK scaling.
local_fields_mean: Mean longitudinal field.
local_fields_std: Std of the longitudinal fields.
edge_density: Fraction of non-zero couplings, in ``[2/n, 1]``.
ensure_extensivity: Whether to apply the SK 1/n scaling.
seed: random number generator seed.
Returns:
Tuple ``(couplings, fields)``: a symmetric ``(n, n)`` matrix with zero
diagonal, and an ``(n,)`` field vector.
Raises:
ValueError: If ``n < 2``, ``coupling_std < 0``, ``local_fields_std < 0``,
or ``edge_density`` is outside ``[2/n, 1]``.
"""
if n < 2:
raise ValueError(f"n must be >= 2, got {n}")
if coupling_std < 0 or local_fields_std < 0:
raise ValueError(
"coupling_std and local_fields_std must be non-negative"
)
# A connected graph on n nodes needs at least n-1 of the n*(n-1)/2 possible
# edges, so edge_density has a hard lower bound of 2/n.
min_edge_density = 2.0 / n
if not min_edge_density <= edge_density <= 1.0:
raise ValueError(
f"edge_density must be in [{min_edge_density:.4g}, 1] for n={n} "
f"(at least n-1 edges are needed to keep the graph connected), "
f"got {edge_density}"
)
rng = np.random.default_rng(seed)
j_loc, j_scale = (
(coupling_mean / n, coupling_std / np.sqrt(n))
if ensure_extensivity
else (coupling_mean, coupling_std)
)
upper_idx = np.triu_indices(n, k=1)
n_edges = len(upper_idx[0])
# Select which edges are present.
if edge_density < 1.0:
n_keep = int(round(edge_density * n_edges))
# Map each (i, j) node pair to its position in the flat upper-triangle list.
pair_to_flat = {
(int(i), int(j)): idx
for idx, (i, j) in enumerate(
zip(upper_idx[0], upper_idx[1], strict=False)
)
}
# Random spanning tree: node perm[k] links to a random earlier node.
perm = rng.permutation(n)
keep = np.zeros(n_edges, dtype=bool)
for k in range(1, n):
child, parent = perm[k], perm[rng.integers(0, k)]
i, j = min(child, parent), max(child, parent)
keep[pair_to_flat[(int(i), int(j))]] = True
# Fill the remaining budget with random non-tree edges.
remaining = n_keep - (n - 1)
if remaining > 0:
keep[
rng.choice(
np.flatnonzero(~keep), size=remaining, replace=False
)
] = True
else:
keep = np.ones(n_edges, dtype=bool)
n_present = int(keep.sum())
if j_scale == 0.0:
vals = np.full(n_present, j_loc)
else:
vals = rng.normal(loc=j_loc, scale=j_scale, size=n_present)
couplings = np.zeros((n, n))
couplings[upper_idx[0][keep], upper_idx[1][keep]] = vals
couplings += couplings.T # symmetrize; diagonal stays zero
fields = (
np.full(n, local_fields_mean)
if local_fields_std == 0.0
else rng.normal(loc=local_fields_mean, scale=local_fields_std, size=n)
)
return couplings, fields
Langkah 2: Selesaikan masalah menggunakan Parity Twine Optimizer
Dengan fungsi-fungsi di atas, Anda dapat menyiapkan masalah SK dan menemukan solusi dengan menggunakan Twine Optimizer dan backend IBM Quantum® pilihan Anda.
Untuk menjalankan fungsi tersebut, pilih backend yang sesuai; misalnya, ibm_phoenix.
Jika perlu, gunakan opsi berikut untuk kontrol tambahan atas pengiriman job:
options = {
"shots": 100000,
"postprocessing_level": 1,
"transpile_only": False,
"job_tags": ["sk"],
}
di mana shots adalah bilangan bulat yang menentukan jumlah eksekusi circuit, postprocessing_level menentukan apakah post-processing diterapkan pada hasil,
transpile_only memilih apakah masalah hanya ditranspilasi menjadi circuit (dan tidak diselesaikan), dan job_tags adalah label untuk mengidentifikasi job pada IBM Quantum Platform.
Ukuran model SK didefinisikan oleh , jumlah spin yang berinteraksi. Setelah Anda memilih , kode di atas menghasilkan masalah untuk n_spins.
Jalankan optimizer:
n_spins = 50
sk_problem = generate_sk_problem(n_spins)
function_job = function.run(
problem=sk_problem,
variable_type="spin",
backend_name="ibm_phoenix",
options=options,
)
print(f"Job ID: {function_job.job_id}")
Periksa status job:
# Monitor the job status
function_job.status()
Ambil hasil:
result = function_job.result()
result
Hasilnya berbentuk:
{
'solution': {'0': 1, '1': 1, '10': 1, '11': 1, ... },
'objective_value': -240.5425312543882,
'solution_bitstring': '00001101110100100111001110101001101111111011001110',
'metadata': {
'circuit_metrics': {
'depth': 523,
'gate_count': 10118,
'two_qubit_gate_depth': 196,
'two_qubit_gate_count': 2499,
'num_qubits': 50,
'operations': {'sx': 3353, 'rz': 3320, 'cz': 2499, 'delay': 894, 'measure': 50, 'x': 2},
},
'solver_info': {
'variable_mapping': {'0': 0, '1': 1, '10': 2, '11': 3, ... },
'bitstring_distributions': {
'before_postprocessing': {'011101110010110111001110011000': 1, ... },
'after_postprocessing': {'011011110000110101001111011000': 1, ... }
},
'best_parameters': {
'beta': [-0.4602084830507902],
'gamma': [1.8500357096574955]
}
},
'resource_usage': {
'RUNNING: MAPPING': {'CPU_TIME': 290.272},
'RUNNING: OPTIMIZING_FOR_HARDWARE': {'CPU_TIME': 0.494},
'RUNNING: WAITING_FOR_QPU': {'CPU_TIME': 8.775},
'RUNNING: EXECUTING_QPU': {'QPU_TIME': 31.0},
'RUNNING: POST_PROCESSING': {'CPU_TIME': 162.96},
},
}
}
di mana dictionary solution berkorespondensi dengan qubit yang didefinisikan dalam masalah dan memberikan nilai spin yang dioptimalkan untuk Hamiltonian model SK.
Urutan spin tertentu dalam solusi optimal ini merepresentasikan konfigurasi yang meminimalkan total energi sistem berdasarkan kekuatan interaksi acak yang diberikan.
Dalam model SK, ini dapat dianggap sebagai keadaan energi terendah dari sistem magnetik yang tidak teratur.
metadata memberikan informasi tentang transpilasi (jumlah/kedalaman gate dua qubit, gate yang digunakan, qubit aktif) dan berbagai runtime.
Langkah selanjutnya
- Minta akses ke fungsi ini dengan mengisi formulir ini.
- Kunjungi referensi API untuk Qiskit Function ini.
- Baca panduannya.
- Coba tutorial untuk menerapkan Parity Twine Optimizer pada masalah Market Split.
- Tinjau preprint ArXiv Connectivity-aware Synthesis of Quantum Algorithms, Drier et al. (2025).