דלג לתוכן הראשי
פרויקט זה בשלב בטא. מצאת באג? פתח issue ב-GitHub. יש שאלה או רעיון? שאל ב-Discussions — נשמח לשמוע ממך!
מה איכות התרגום בדף זה?

SQOA Solver - Qiskit Function של JIJ

ראה את תיעוד ה-API.

הערה

Qiskit Functions הן תכונה ניסיונית הזמינה רק למשתמשי תוכנית Premium, תוכנית Flex ותוכנית On-Prem (דרך IBM Quantum Platform API) של IBM Quantum®. הן נמצאות בשלב גרסת תצוגה מקדימה ועשויות להשתנות.

סקירה כללית​

עם SQOA Solver של JIJ אתה יכול לפתור בעיות אופטימיזציה קומבינטוריות גדולות על מחשבים קוונטיים של IBM®. הפותר מבוסס על Sampling-based Quantum Optimization Algorithm with Quantum Relaxation (SQOA-QR) [1]. בניגוד לאלגוריתמים קוונטיים שמשתמשים בהתאמה חד-חד-ערכית בין משתני החלטה קלאסיים לקיוביטים, SQOA Solver יכול לטפל בבעיות אופטימיזציה עם יותר משתנים ממספר הקיוביטים הזמינים בהתקנים קוונטיים נוכחיים. התכנון מבוסס הדגימה שלו גם הופך אותו לפחות רגיש לרעש הפיזיקלי בחומרה קוונטית נוכחית. יחד, תכונות אלה הופכות את SQOA Solver למתאים היטב לבעיות אופטימיזציה בשלב הנוכחי של המחשוב הקוונטי.

הפותר מטפל בבעיות Quantum-Unconstrained Binary Optimization (QUBO) שניתנות כניסוח מתמטי קלאסי, וממפה אוטומטית את הניסוח הקלאסי להקשר הקוונטי. אפשר גם להמיר בעיות עם אילוצים לבעיות ללא אילוצים באמצעות שיטת הקנס (penalty method).

הסעיפים הבאים מתארים את ה-workflow של הפותר, תוצאות benchmark ודוגמאות מקצה לקצה שמדגימות בעיות באמצעות qiskit-addon-opt-mapper ובאופן אופציונלי Open Mathematical prograMming eXchange (OMMX). OMMX הוא פורמט נתונים פתוח ו-SDK שמפשט את החלפת בעיות האופטימיזציה בין כלי תוכנה.

תיאור​

SQOA Solver מממש את Sampling-based Quantum Optimization Algorithm with Quantum Relaxation (SQOA-QR) ועוטף אותו בעיבוד מקדים ובעיבוד מאוחר קלאסיים. סעיף זה מסביר את מסגרת SQOA ובמה היא שונה מ-Quantum Approximate Optimization Algorithm (QAOA).

האיור הבא מציג תרשים של ה-workflow של SQOA Solver. תרשים של ה-workflow של SQOA Solver, מעיבוד מקדים קלאסי דרך דגימת SQOA ועד עיבוד מאוחר וחיפוש מקומי

מסגרת SQOA​

SQOA היא מסגרת מבוססת דגימה לאופטימיזציה קומבינטורית [1]. היא משלבת שתי טכניקות: Quantum Random Access Optimization (QRAO) [2], שמקודדת את הבעיה ברילקסציה קוונטית, ו-sample-based quantum diagonalization (SQD) [3], הידועה גם בשם quantum-selected configuration interaction (QSCI) [4], שמשתמשת במחשב הקוונטי רק כדי לדגום מחרוזות ביטים ומוצאת את מצב האנרגיה הנמוכה במחשב קלאסי. SQOA היא מסגרת במובן זה שהיא קובעת את השילוב הזה אך משאירה את הפרטים לכל מימוש, כגון איך המשתנים מוקצים לקיוביטים ואילו מעגלים מייצרים את הדגימות.

  • רילקסציה קוונטית עם QRAO. QAOA וגישות אחרות מבוססות Ising מייצגות כל משתנה בינארי באמצעות האופרטור ZZ של הקיוביט שלו. QRAO משתמשת גם באופרטורים XX ו-YY. עם קוד גישה אקראית קוונטי (QRAC) מסוג (3,1), עד שלושה משתנים בינאריים חולקים קיוביט אחד, וכל משתנה מיוצג על ידי אופרטור Pauli שונה.

    ה-QUBO הופך אז להמילטוניאן מרוכך שדורש פחות קיוביטים מהמילטוניאן Ising. משתנים שמקיימים אינטראקציה ב-QUBO חייבים להיות ממוקמים על קיוביטים שונים. אילו חלקו קיוביט, המכפלה של אופרטורי Pauli שלהם הייתה מצטמצמת לאופרטור יחיד על אותו קיוביט (לדוגמה, XY=iZXY = iZ), וההמילטוניאן המרוכך כבר לא היה מייצג את האינטראקציה ביניהם.

    לכן הקצאת המשתנים לקיוביטים קובעת הן את מספר הקיוביטים והן את איכות הרילקסציה, ו-SQOA Solver מתכנן הקצאה זו בשלב העיבוד המקדים שלו.

  • Sample-based quantum diagonalization (SQD). המחשב הקוונטי מכין תחילה מצב קוונטי בעל חפיפה עם מצבי אנרגיה נמוכה של ההמילטוניאן המרוכך ואז דוגם ממנו מחרוזות ביטים. מחשב קלאסי מטיל את ההמילטוניאן המרוכך על תת-המרחב הנפרש על ידי מחרוזות הביטים שנדגמו ומבצע לו אלכסון כדי לקרב את מצב היסוד.

    מכיוון שההמילטוניאן המרוכך אינו אלכסוני, האלכסון משלב את מחרוזות הביטים שנדגמו לסופרפוזיציה. עם המילטוניאן Ising אלכסוני, כל מחרוזת ביטים היא כבר מצב עצמי, והאלכסון רק היה בוחר את הדגימה הטובה ביותר. אותה גישה יושמה על בעיות בקנה מידה גדול בכימיה קוונטית.

מצב היסוד המקורב שמתקבל מ-SQD אינו מתאים ישירות לפתרון קלאסי של הבעיה המקורית, ולכן יש לפענח ממנו את הפתרון הקלאסי. מכיוון שמצב זה מחושב במחשב קלאסי, הפענוח, הנקרא עיגול (rounding), הוא עיבוד מאוחר קלאסי. SQOA Solver משתמש בטכניקות פענוח שנועדו לקבל פתרונות קלאסיים טובים יותר באופן היוריסטי.

הטבלה הבאה משווה בין SQOA ל-QAOA, גישה וריאציונית נפוצה לאותה משפחה של בעיות.

 QAOASQOA
קיוביטים עבור nn משתנים בינארייםnnקיוביט אחד מכיל עד שלושה מהמשתנים. המספר המדויק תלוי במבנה הבעיה
שימוש ב-QPUמעריך שוב ושוב את האנרגיה של מעגלים עם פרמטרים בתוך לולאת אופטימיזציה קלאסיתרק דוגם מחרוזות ביטים. לא מאומנים פרמטרים של מעגל על ה-QPU
מדגימות לפתרוןבוחר את מחרוזת הביטים הטובה ביותר שנמדדהמבצע אלכסון להמילטוניאן המרוכך בתת-המרחב שנדגם במחשב קלאסי ומעגל את המצב המתקבל

סביב SQOA-QR, SQOA Solver מוסיף עיבוד קלאסי. העיבוד המקדים שלו מקבע משתנים שאפשר לקבוע מראש את ערכיהם האופטימליים ומתכנן את הקצאת המשתנים לקיוביטים. העיבוד המאוחר שלו משפר את הפתרון המעוגל באמצעות חיפוש מקומי, שאפשר לכבות באמצעות postprocessing_level=0.

Benchmarks​

הצהרת אחריות

הביצועים יכולים להיות תלויים הן במופע הבעיה והן בשלבי העיבוד הבאים. במקרים מסוימים, דגימות קלאסיות ודגימות שנוצרו קוונטית עשויות להשיג איכות פתרון סופית דומה לאחר עיבוד מאוחר שקול. לכן יש להעריך את כל ה-workflow של האופטימיזציה.

מדדי ה-benchmark הבאים מספקים אינדיקציה כללית לאיכות הפתרון, לדחיסת הקיוביטים ולזמן הביצוע על פני גדלים ומבנים נבחרים של בעיות. הטבלה מפרטת מבחר מופעי Maximum Independent Set מתוך Quantum Optimization Benchmarking Library (QOBLIB) ושני מופעי MaxCut 3-רגולריים. אפשר לטעון את מופעי QOBLIB כאובייקטים מסוג ommx.v1.Instance, יחד עם הפתרונות האופטימליים שלהם, באמצעות החבילה ommx-quantum-benchmarks.

כל מופע הורץ 10 פעמים על מעבד IBM Heron r2. Number of qubits סופר את הקיוביטים שנעשה בהם שימוש בפועל בחומרה לאחר העיבוד המקדים וקידוד QRAC. יחס הדחיסה תלוי במופע. Approximation ratio (AR) מדווח על איכות הפתרון הטוב ביותר שנמצא ב-10 ההרצות:

AR=CbestCopt,\mathrm{AR} = \frac{C_{\textrm{best}}}{C_{\textrm{opt}}},

כאשר CbestC_{\textrm{best}} הוא ערך המטרה הטוב ביותר שנמצא ו-CoptC_{\textrm{opt}} הוא ערך המטרה האופטימלי הידוע. כל המופעים הם בעיות מקסום עם ערך אופטימלי חיובי, ולכן AR הוא לכל היותר 100%, ו-100% בעמודה Approximation ratio מציין שהפותר מצא פתרון אופטימלי. Total time הוא הזמן הממוצע המשולב של QPU ו-CPU להרצה. QPU time הוא השימוש הממוצע ב-IBM Quantum Compute להרצה.

מופעמספר משתניםמספר קיוביטיםיחס קירובזמן כולל (שניות)זמן QPU (שניות)
maxcut_384_nodes38412998.5%62.112.0
gen200_p0-9_4420067100%38.012.0
es60fst0218642100%24.712.0
es60fst0416229100%17.912.0
maxcut_150_nodes15051100%23.112.0
sloane_1dc_1281283793.8%19.112.0
sloane_2dc_1281288100%12.311.5
C125-912543100%22.312.0
es60fst0112312100%13.612.0
es60fst0311326100%14.912.0
sloane_1dc_646416100%13.411.9
chesapeake3913100%13.112.0
football356100%12.512.0
karate342100%6.26.0
ibm323211100%12.912.0
farm174100%8.58.0

תחילת עבודה​

מידע על גישה ל-Qiskit Function זו נמצא ב-Qiskit Functions Catalog.

סעיף זה מראה כיצד לבצע אימות ולטעון את הפונקציה, וכיצד להכין בעיה בפורמט המילון ש-SQOA Solver מקבל באמצעות OptimizationProblem מתוך qiskit-addon-opt-mapper. הדוגמאות שלאחר מכן מריצות את הפונקציה וקוראות את התוצאה.

אימות וטעינת הפונקציה​

תחילה, בצע אימות עם מפתח ה-API של IBM Quantum שלך. (הקוד הבא מניח שכבר שמרת את החשבון שלך בסביבה המקומית שלך.) לאחר מכן צור לקוח קטלוג כך:

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

_needed = {"jijmodeling": "jijmodeling", "networkx": "networkx", "ommx": "ommx", "qiskit_addon_opt_mapper": "qiskit-addon-opt-mapper", "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")
from qiskit_ibm_catalog import QiskitFunctionsCatalog

catalog = QiskitFunctionsCatalog(channel="ibm_quantum_platform")

# verify that you have access to the function
catalog.list()
[QiskitFunction(jij/sqoa-solver)]
solver = catalog.load("jij/sqoa-solver")

הכנת הקלט עם qiskit-addon-opt-mapper​

מדריך זה מדגים בעיות באמצעות המחלקה OptimizationProblem של qiskit-addon-opt-mapper. SQOA Solver מקבל בעיית QUBO כמילון מקדמים בפורמט tuple-string שבו משתמשות פונקציות האופטימיזציה של IBM, ולכן כל דוגמה במדריך זה עוקבת אחר אותו דפוס הכנה בצד הלקוח:

  1. כתוב את המודל. צור OptimizationProblem, הוסף משתני החלטה בינאריים, וקבע את פונקציית המטרה ואת האילוצים, אם יש.

  2. המר ל-QUBO. המר את הבעיה באמצעות OptimizationProblemToQubo, שמוסיף כל אילוץ לפונקציית המטרה כאיברי קנס ומחזיר בעיית מינימיזציה שקולה ללא אילוצים.

  3. המר למילון. העבר את ה-QUBO לפונקציית העזר to_problem_dict() שמוגדרת בסעיף הבא, והעבר את התוצאה ל-solver.run() בתור problem, יחד עם variable_type="binary".

SQOA Solver תמיד ממזער בעיית מילון, מה שתואם את בעיית המינימיזציה ש-OptimizationProblemToQubo מחזיר. לכן, עבור בעיית מקסום, ה-objective_value המוחזר הוא ההפך של פונקציית המטרה המקורית. כדי לקרוא את התוצאה במונחי הבעיה המקורית, הערך את ההשמה המוחזרת באמצעות OptimizationProblem, כפי שהדוגמאות מראות. לפרטי פורמט המילון, ראה Accepted problem formats במדריך ה-API.

# %pip install qiskit-addon-opt-mapper

הגדר את פונקציית העזר הבאה פעם אחת והשתמש בה בכל דוגמה. היא ממירה את ה-QUBO ש-OptimizationProblemToQubo מחזיר לפורמט המילון. המפתחות משתמשים באינדקסים של המשתנים של ה-QUBO, ולכן מפתחות הפתרון x_0, x_1 וכן הלאה בתוצאה מתאימים לאינדקסים אלה. כל משתנה מקבל איבר לינארי, גם עם מקדם אפס, כדי שהפתרון המוחזר יכסה את כל המשתנים.

from qiskit_addon_opt_mapper import OptimizationProblem
from qiskit_addon_opt_mapper.converters import OptimizationProblemToQubo

def to_problem_dict(qubo: OptimizationProblem) -> dict[str, float]:
"""Convert a QUBO from OptimizationProblemToQubo to the SQOA Solver dictionary format."""
objective = qubo.objective
payload = {"()": objective.constant}
# Keep every variable in the problem, even with a zero linear coefficient.
payload.update({f"({i},)": 0.0 for i in range(qubo.get_num_vars())})
for i, coefficient in objective.linear.to_dict().items():
payload[f"({i},)"] += coefficient
for (i, j), coefficient in objective.quadratic.to_dict().items():
# Fold a binary diagonal term x_i * x_i = x_i into the linear term.
key = f"({i},)" if i == j else f"({i}, {j})"
payload[key] = payload.get(key, 0.0) + coefficient
return {key: float(value) for key, value in payload.items()}

דוגמה 1: MaxCut על גרף 3-רגולרי​

בעיות גרף רבות, כגון MaxCut, הן NP-קשות ומועמדות טבעיות לאופטימיזציה קוונטית. התקן את networkx כתלות נוספת כדי להריץ דוגמה זו:

# %pip install networkx

1. כתיבת המודל​

הקצה משתנה בינארי xv∈{0,1}x_v \in \{0, 1\} לכל קודקוד של גרף G=(V,E)G = (V, E) כדי לציין את הצד שלו בחתך. צלע נחתכת כאשר קצותיה בצדדים שונים, ולכן גודל החתך הוא:

Cut(x)=∑(u,v)∈E(xu+xv−2xuxv).\mathrm{Cut}(x) = \sum_{(u,v) \in E} \left(x_u + x_v - 2 x_u x_v\right).

פונקציית מטרה זו היא כבר QUBO ללא אילוצים, ולכן OptimizationProblemToQubo רק הופך את המקסום למינימיזציה שקולה ומשאיר את המשתנים ללא שינוי. מחלקת היישום Maxcut ב-qiskit_addon_opt_mapper.applications בונה את אותו מודל באמצעות Maxcut(G).to_optimization_problem().

import networkx as nx

G = nx.random_regular_graph(3, 40, seed=42)

linear = {v: 0 for v in G.nodes}
quadratic = {}
for u, v in G.edges:
linear[u] += 1
linear[v] += 1
quadratic[(u, v)] = -2

maxcut = OptimizationProblem("MaxCut")
maxcut.binary_var_list(G.number_of_nodes(), name="x")
maxcut.maximize(linear=linear, quadratic=quadratic)

2. הרצת הפותר​

המר את המודל ל-QUBO ולאחר מכן למילון, ושלח אותו. problem ו-variable_type הם חובה. backend_name הוא אופציונלי. כשהוא מושמט או שערכו None, הפונקציה בוחרת את ה-QPU התפעולי הכי פחות עמוס שזמין למופע שלך.

מילון options מקבל את shots, seed, session, postprocessing_level ו-job_tags. לתיאורים ולערכי ברירת מחדל, ראה את מדריך ה-API.

qubo = OptimizationProblemToQubo().convert(maxcut)

job = solver.run(
problem=to_problem_dict(qubo),
variable_type="binary",
backend_name="ibm_fez",
options={
"shots": 4096,
"seed": 42,
},
)

3. אחזור התוצאה​

job.result() מחזיר מילון עם ארבעה מפתחות:

  • solution היא ההשמה המלאה של המשתנים, עם מפתחות מהצורה x_i, כאשר i הוא אינדקס המשתנה (לדוגמה, x_3).

  • objective_value ו-feasible הם ערך המטרה והאפשריות של אותה השמה, שהוערכו על המילון שנשלח.

  • metadata מכיל את solver_info ו-resource_usage.

מכיוון ש-QUBO הוא צורת המינימיזציה של MaxCut, objective_value הוא ההפך של גודל החתך. הערך את ההשמה על OptimizationProblem המקורי כדי לקרוא ישירות את גודל החתך.

result = job.result()

x = [result["solution"][f"x_{i}"] for i in range(maxcut.get_num_vars())]
print(f"Cut value: {maxcut.objective.evaluate(x)}")
print(f"Nodes on side 1: {[v for v, value in enumerate(x) if value > 0.5]}")
Cut value: 55.0
Nodes on side 1: [5, 7, 9, 11, 14, 16, 17, 19, 21, 23, 24, 26, 30, 31, 33, 34, 36, 37, 38]

4. בדיקת השימוש במשאבים​

result["metadata"]["resource_usage"] מדווח על הזמן שהושקע בכל שלב ביצוע. שלבים שאינם RUNNING: EXECUTING_QPU מדווחים על CPU_TIME, זמן השעון של השלב בשניות, כאשר הוא זמין.

השלב RUNNING: EXECUTING_QPU מדווח על QPU_TIME, השימוש ב-QPU של כל משימות Quantum Compute בהרצה, אם השימוש הסופי זמין לכל משימה. לפרטים, ראה את מדריך ה-API.

for phase, metrics in result["metadata"]["resource_usage"].items():
line = f"{phase:36s}"
if "CPU_TIME" in metrics:
line += f" CPU {metrics['CPU_TIME']:8.1f} s"
if "QPU_TIME" in metrics:
line += f" QPU {metrics['QPU_TIME']:8.1f} s"
print(line)
RUNNING: MAPPING CPU 3.2 s
RUNNING: OPTIMIZING_FOR_HARDWARE CPU 5.0 s
RUNNING: WAITING_FOR_QPU CPU 1.1 s
RUNNING: EXECUTING_QPU QPU 3.0 s
RUNNING: POST_PROCESSING CPU 0.9 s

דוגמה 2: המרת בעיה עם אילוצים ל-QUBO​

SQOA Solver מקבל בעיות ללא אילוצים. דוגמה זו מראה כיצד להמיר בעיה עם אילוצים ל-QUBO באמצעות OptimizationProblemToQubo ולמפות את התוצאה בחזרה למשתני הבעיה המקורית.

selection = OptimizationProblem("ConstrainedExample")
selection.binary_var_list(2, name="x")
selection.maximize(linear={"x0": 1, "x1": 1})
selection.linear_constraint({"x0": 1, "x1": 1}, "<=", 1, name="at_most_one")

print(selection.prettyprint())
Problem name: ConstrainedExample

Maximize
x0 + x1

Subject to
Linear constraints (1)
x0 + x1 <= 1 'at_most_one'

Binary variables (2)
x0 x1

OptimizationProblemToQubo מוסיף את האילוצים לפונקציית המטרה כאיברי קנס וממיר את הבעיה למינימיזציה. משקל הקנס המתאים תלוי בבעיה.

לאחר ההרצה, interpret() ממפה את ההשמה של ה-QUBO בחזרה למשתני הבעיה המקורית.

הערך את פונקציית המטרה ואת האפשריות על הבעיה המקורית. בבעיית מילון, השדה feasible בתוצאה מתייחס רק לתחום המשתנים, כי למילון אין אילוצים.

converter = OptimizationProblemToQubo(penalty=4.0)
qubo = converter.convert(selection)

job = solver.run(
problem=to_problem_dict(qubo),
variable_type="binary",
backend_name="ibm_fez",
)
result = job.result()

x_qubo = [result["solution"][f"x_{i}"] for i in range(qubo.get_num_vars())]
x = converter.interpret(x_qubo)
print("Objective:", selection.objective.evaluate(x))
print("Feasible:", selection.is_feasible(x))
print("x values:", x)
Objective: 1.0
Feasible: True
x values: [1. 0.]

דוגמה 3: שליחת מופע OMMX​

SQOA Solver מקבל גם ommx.v1.Instance מה-SDK של OMMX, ששומר יחד עם הבעיה את שמות המשתנים, האינדקסים ומטא-נתוני ההמרה. בהשוואה למילון, לקלט OMMX יש את היתרונות הבאים:

  • התוצאה מכילה גם את ה-ommx.v1.Solution הקנוני ב-solver_info["ommx_solution"].

  • objective_value מוערך במובן של המופע, ולכן פונקציית המטרה של בעיית מקסום אינה מנוגדת בסימן.

  • עבור מופע שהומר במקום באמצעות Instance.to_qubo(), feasible מוערך מול האילוצים המקוריים.

דוגמה זו בונה את מודל MaxCut מדוגמה 1 באמצעות JijModeling, כלי מידול לאופטימיזציה מתמטית שמהדר מודלים למופעי OMMX. התקן את JijModeling, שמתקין גם את החבילה ommx:

# %pip install "jijmodeling~=2.8.0"

SQOA Solver מחליף נתוני OMMX כמחרוזות Base64 סטנדרטיות עם ריפוד. הגדר את פונקציות העזר הבאות להמרה זו:

  • to_problem_payload() מבצע סריאליזציה של ommx.v1.Instance למחרוזת שאתה מעביר בתור problem.

  • to_ommx_solution() מפענח את ה-ommx.v1.Solution הקנוני מהתוצאה.

import base64

from ommx.v1 import Instance, Solution

def to_problem_payload(instance: Instance) -> str:
"""Serialize an OMMX instance into the `problem` string for SQOA Solver."""
return base64.b64encode(instance.to_bytes()).decode()

def to_ommx_solution(result: dict) -> Solution:
"""Decode the canonical OMMX solution from a SQOA Solver result."""
payload = result["metadata"]["solver_info"]["ommx_solution"]
return Solution.from_bytes(base64.b64decode(payload, validate=True))

1. כתיבת המודל עם JijModeling​

הניסוח הרגיל של MaxCut בספינים על גרף G=(V,E)G = (V, E) מקצה sv∈{−1,+1}s_v \in \{-1, +1\} לכל קודקוד. צלע נחתכת כאשר susv=−1s_u s_v = -1, ולכן גודל החתך הוא:

Cut⁡(s)=∑(u,v)∈E1−susv2.\operatorname{Cut}(s) = \sum_{(u,v) \in E} \frac{1 - s_u s_v}{2}.

JijModeling אינו מספק משתנה החלטה מקורי מסוג ספין, ו-SQOA Solver מקבל משתני QUBO בינאריים. לכן הצהר על bv∈{0,1}b_v \in \{0, 1\} והגדר בתוך המודל את הביטוי בערכי ספין sv=1−2bvs_v = 1 - 2b_v. עם ביטוי זה, פונקציית המטרה נשארת בצורת הספין הסטנדרטית, והמופע המהודר נשאר QUBO בינארי.

import jijmodeling as jm

@jm.Problem.define("MaxCut", sense=jm.ProblemSense.MAXIMIZE)
def maxcut_model(problem: jm.DecoratedProblem):
V = problem.Natural() # number of nodes
E = problem.Graph(dtype=V) # edge list
b = problem.BinaryVar(shape=(V,))
s = 1 - 2 * b # spin-valued expression

problem += jm.sum((1 - s[u] * s[v]) / 2 for u, v in E)

אם תציג את maxcut_model במחברת, הוא יציג את הניסוח הבא:

Problem ⁣:MaxCutmax⁡∑⟨u,v⟩∈E1−(1−2⋅b)u⋅(1−2⋅b)v2whereDecision Variables:bi∈{0,1}a 1-dim array of binary decision variables∀i∈{0,…,V−1}Placeholders:Ei∈V×Va 1-dim array of placeholders with elements in V×V∀i∈{0,…,len_at(E,0)−1}V∈Na scalar placeholder in N\begin{array}{rl} \text{Problem}\colon &\text{MaxCut}\\ \displaystyle \max &\displaystyle \sum _{\left\langle u,v\right\rangle \in E}{\frac{1-{\left(1-2\cdot b\right)}_{u}\cdot {\left(1-2\cdot b\right)}_{v}}{2}}\\ &\\ \text{where}&\\ &\text{Decision Variables:}\\ &\qquad \begin{alignedat}{2}{b}_{i}&\in \left\{0,1\right\}&\qquad &\text{a }1\text{-dim array of }\text{binary}\text{ decision variables}\\ &\forall i\in \left\{0,\ldots ,V-1\right\}&&\\ \end{alignedat}\\ &\\ &\text{Placeholders:}\\ &\qquad \begin{alignedat}{2}{E}_{i}&\in V\times V&\qquad &\text{a }1\text{-dim array of placeholders with elements in }V\times V\\ &\forall i\in \left\{0,\ldots ,\mathop{\mathtt{len\_{}at}}\left(E,0\right)-1\right\}&&\\ &&&\\ V&\in \mathbb{N}&\qquad &\text{a scalar placeholder in }\mathbb{N}\\ \end{alignedat}\end{array}

2. הידור המופע והרצת הפותר​

קשור את הגרף מדוגמה 1 כדי להדר ommx.v1.Instance, ושלח אותו עם variable_type="binary". מופע OMMX נשלח תמיד כבעיה בינארית.

instance = maxcut_model.eval(
{"V": G.number_of_nodes(), "E": [list(edge) for edge in G.edges]}
)

job = solver.run(
problem=to_problem_payload(instance),
variable_type="binary",
backend_name="ibm_fez",
)

3. אחזור התוצאה​

בקלט OMMX, objective_value הוא גודל החתך, ו-to_ommx_solution() מפענח את הפתרון הקנוני כך שאפשר לקרוא את ההשמה לפי שם המשתנה.

result = job.result()
print(f"Cut value: {result['objective_value']}")

solution = to_ommx_solution(result)
b_values = solution.extract_decision_variables("b")
print(
f"Nodes on side 1: {sorted(v for (v,), value in b_values.items() if value > 0.5)}"
)
Cut value: 55.0
Nodes on side 1: [5, 7, 9, 11, 14, 16, 17, 19, 21, 23, 24, 26, 30, 31, 33, 34, 36, 37, 38]

קבלת תמיכה​

לתמיכה, שלח דוא"ל אל info@j-ij.com.

השלבים הבאים​

המלצות

מקורות​

[1] Matsuyama, H., & Yamashiro, Y. (2025). Sampling-based quantum optimization algorithm with quantum relaxation. 2025 IEEE International Conference on Quantum Computing and Engineering (QCE), 1, 2323–2333. DOI, arXiv:2504.12629

[2] Fuller, B., Hadfield, C., Glick, J. R., Imamichi, T., Itoko, T., Thompson, R. J., Jiao, Y., Kagele, M. M., Blom-Schieber, A. W., Raymond, R., et al. (2024). Approximate solutions of combinatorial problems via quantum relaxations. IEEE Transactions on Quantum Engineering, 5, 1–15. DOI, arXiv:2111.03167

[3] Robledo-Moreno, J., Motta, M., Haas, H., Javadi-Abhari, A., Jurcevic, P., Kirby, W., et al. (2025). Chemistry beyond the scale of exact diagonalization on a quantum-centric supercomputer. Science Advances, 11(25), eadu9991. DOI, arXiv:2405.05068

[4] Kanno, K., Kohda, M., Imai, R., Koh, S., Mitarai, K., Mizukami, W., & Nakagawa, Y. O. (2026). Quantum-selected configuration interaction: Classical diagonalization of Hamiltonians in subspaces selected by quantum computers. Physical Review Research, 8(2), 023268. DOI, arXiv:2302.11320