Langkau ke kandungan utama
Projek ini dalam fasa beta. Jumpa pepijat? Buat isu GitHub. Ada soalan atau idea? Tanya dalam Discussions — kami suka dengar maklum balas anda!
Bagaimana kualiti terjemahan pada halaman ini?

Selesaikan model Sherrington-Kirkpatrick dengan ParityQC Parity Twine Optimizer

Anggaran penggunaan: 10 saat pada pemproses Nighthawk r2. (NOTA: Ini hanyalah anggaran. Masa jalan anda mungkin berbeza.)

Hasil pembelajaran​

  • Gunakan Parity Twine Optimizer untuk menyelesaikan model Sherrington-Kirkpatrick.

  • Ketahui pilihan yang tersedia untuk Parity Twine Optimizer dan hasil yang dikeluarkan.

Latar belakang​

Tutorial ini menunjukkan cara menyelesaikan model Sherrington-Kirkpatrick menggunakan ParityQC Parity Twine Optimizer.

Ia menyediakan kod untuk merumuskan masalah tersebut sepenuhnya secara tempatan dalam bentuk yang boleh berinteraksi dengan Parity Twine Optimizer.

Model Sherrington-Kirkpatrick​

Model Sherrington-Kirkpatrick (SK) ialah model asas dalam mekanik statistik, khususnya dalam kajian kaca spin. Berbeza daripada model Ising standard yang interaksinya biasanya terhad kepada jiran terdekat, model SK ialah model julat tak terhingga, bermakna setiap spin berinteraksi dengan setiap spin lain dalam sistem tersebut. Ini membawa kepada landskap tenaga yang sangat kompleks dan "bergerigi" yang dicirikan oleh banyak minimum tempatan, iaitu ciri utama tingkah laku seperti kaca (glassy).

Ciri utama model SK terletak pada frustrasi. Dalam model ini, kekuatan interaksi JijJ_{ij} antara spin diagihkan secara rawak antara nilai positif dan negatif. Ini membawa kepada situasi (contohnya, dalam susunan segi tiga) di mana spin tidak dapat disusun untuk meminimumkan semua interaksi secara serentak. Dalam model SK, kerana setiap spin berinteraksi dengan setiap spin lain, frustrasi ini berganda secara global, membawa kepada jaringan kekangan yang bercanggah.

Rumusan matematik​

Keadaan sistem ditakrifkan oleh satu set NN spin Ising, si∈{+1,−1}s_i \in \{+1, -1 \} . Tenaga bagi konfigurasi tertentu diberikan oleh Hamiltonian:

H=−∑1≤i≤j≤NJijsisjH = - \sum_{1 \leq i \leq j \leq N} J_{ij} s_i s_j

dengan JijJ_{ij} ialah kekuatan gandingan antara spin ii dan spin jj.

Dalam model SK, gandingan JijJ_{ij} ialah pemboleh ubah rawak yang tak bersandar dan teragih secara sama. Untuk memastikan tenaga kekal ekstensif (berkadar dengan NN) apabila N→∞N \rightarrow \infty, varians gandingan mesti berskala dengan bilangan zarah:

Jij∼N(0,J2N)J_{ij} \sim \mathcal{N} \left( 0, \frac{J^2}{N} \right)

Keadaan asas bagi HH yang diberikan ialah konfigurasi spin tertentu (s1,s2,...sns_1, s_2, ...s_n), yang meminimumkan tenaga. Mencari keadaan asas adalah masalah pengoptimuman NP-hard.

Keperluan​

Sebelum memulakan tutorial ini, pastikan yang berikut telah dipasang:

  • 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 kebenaran untuk mengakses fungsi ParityQC Twine Optimizer. Untuk memohon akses, lengkapkan borang ini.

Persediaan​

(Kod ini menganggap anda sudah menyimpan akaun anda ke persekitaran tempatan anda.)

Pertama, import semua pakej 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

Muatkan Parity Twine Optimizer daripada katalog Qiskit Functions:

catalog = QiskitFunctionsCatalog(channel="ibm_quantum_platform")
function = catalog.load("parityqc/parity-twine-optimizer")

Langkah 1: Takrifkan masalah sebagai fungsi objektif​

Bukannya memperoleh masalah SK daripada pustaka seperti yang kita lakukan untuk masalah Market Split, anda merumuskannya secara terus.

Fungsi generate_sk_problem merumuskan masalah SK secara terus dalam format kamus yang diperlukan. Satu-satunya input yang diperlukan ialah n, iaitu bilangan spin dalam model tersebut.

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 mengira sebutan gandingan rawak dalam model SK. Untuk kawalan lebih terhadap gandingan, anda boleh menggunakan argumen pilihan, yang diterangkan 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 di atas, anda boleh menyediakan masalah SK dan mencari penyelesaian dengan menggunakan Twine Optimizer dan backend IBM Quantum® pilihan.

Untuk menjalankan fungsi, pilih backend yang sesuai; contohnya, ibm_phoenix.

Jika perlu, gunakan options (pilihan) untuk kawalan tambahan terhadap penghantaran:

options = {
"shots": 100000,
"postprocessing_level": 1,
"transpile_only": False,
"job_tags": ["sk"],
}

dengan shots ialah integer yang menentukan bilangan pelaksanaan litar, postprocessing_level menentukan sama ada pasca-pemprosesan digunakan pada hasil, transpile_only memilih sama ada masalah hanya ditranspilasi kepada litar (dan tidak diselesaikan), dan job_tags ialah label untuk mengenal pasti job pada IBM Quantum Platform.

Saiz model SK ditakrifkan oleh NN, bilangan spin yang berinteraksi. Setelah anda memilih NN, kod di atas menjana masalah untuk n_spins.

Jalankan pengoptimum:

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

Semak status job:

# Monitor the job status
function_job.status()

Dapatkan 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},
},
}
}

dengan kamus solution sepadan dengan qubit yang ditakrifkan dalam masalah dan memberikan nilai spin yang dioptimumkan bagi Hamiltonian model SK. Jujukan spin tertentu ini dalam penyelesaian optimum mewakili konfigurasi yang meminimumkan jumlah tenaga sistem berdasarkan kekuatan interaksi rawak yang diberikan. Dalam model SK, ini boleh dianggap sebagai keadaan tenaga terendah bagi sistem magnet yang tidak teratur.

metadata memberikan maklumat tentang transpilasi (bilangan/kedalaman gate dua qubit, gate yang digunakan, qubit aktif) dan pelbagai masa jalan.

Langkah seterusnya​

Cadangan