Constrained Quantum Optimizer - פונקציית Qiskit מבית Aqarios
ראו את הפניית ה-API
Qiskit Functions הן תכונה ניסיונית הזמינה רק למשתמשי התוכניות IBM Quantum® Premium Plan, Flex Plan ו-On-Prem (דרך IBM Quantum Platform API). הן נמצאות במעמד גרסה מקדימה (preview) וכפופות לשינויים.
סקירה כללית
בעזרת Constrained Quantum Optimizer מבית Aqarios, ניתן לפתור בעיות אופטימיזציה בינארית עם אילוצים על גבי חומרת קוונטים של IBM® ללא צורך בניסוח מחדש ידני ובמיפוי מעגלים. פשוט ספקו בעיה כקובץ LP, קובץ MPS, או מודל Luna. הפונקציה מטפלת בניסוח מחדש, בסינתזת מעגלים, בטרנספילציה (transpilation) ובביצוע על החומרה באופן אוטומטי. הפותר משתמש בהתחלה חמה איטרטיבית [1] של אלגוריתם FlexQAOA, הרחבה של Quantum Approximate Optimization Algorithm (QAOA) שתומכת באילוצים באופן מובנה (constraint-native).
האופטימייזר מיועד לבעיות בינאריות עם אילוצים. בפרט, ניתן לאכוף באופן טבעי אילוצי one-hot ואילוצי set-packing באמצעות מערבלי XY. סוגי אילוצים אחרים מנוסחים מחדש באופן אוטומטי כאיברי קנס (penalty terms).
הפונקציה פותרת בעיות דיסקרטיות בלבד. כל משתנה החלטה חייב להיות בינארי, או שלם עם חסם תחתון ועליון מפורשים, כדי שאפשר יהיה לקודד אותו לקיוביטים. משתנים רציפים (בעלי ערכים ממשיים) אינם נתמכים: מודל שמכיל אותם נדחה עם קוד השגיאה 4710.
תיאור
הביצועים עשויים להיות תלויים הן במופע הבעיה והן בשלבי העיבוד שלאחר מכן. במקרים מסוימים, דגימות קלאסיות ודגימות שנוצרו קוונטית עשויות להשיג איכות פתרון סופית דומה לאחר עיבוד שווה-ערך. לכן, יש להעריך את זרימת העבודה המלאה של האופטימיזציה.
Constrained Quantum Optimizer מממש את Iterative warm-start XY-mixer QAOA (IWS-QAOA) [1]. האלגוריתם מריץ מעגלי QAOA עם זוויות קבועות על חומרת קוונטים, ומעדכן את הסתברויות ההתחלה החמה הראשוניות של כל מעגל באמצעות תוצאות המדידה מהאיטרציה הקודמת. אין צורך באימון פרמטרים וריאציוני; במקום זאת, נבחרת פרמטריזציה של רמפה לינארית קבועה.
באמצעות שימוש במערבלי XY לאכיפת אילוצי one-hot, ניתן לשפר באופן דרמטי את איכות הפתרון עבור בעיות עם אילוצים, מכיוון שמרחב החיפוש מצטמצם הלכה למעשה לתת-מרחב ישים קטן יותר — וזאת מבלי להוסיף לנוף האופטימיזציה מורכבות הנובעת מאיברי קנס.
זרימת עבודה
זרימת העבודה של הפונקציה מתוארת להלן:
-
עיבוד מקדים: לפני סינתזת המעגל, האופטימייזר מנתח את מבנה האילוצים של בעיית הקלט:
-
עיבוד מקדים של גרף: כאשר רלוונטי לבעיה, היא מנותחת כגרף, שבו קשתות קובעות את הקשר בין המשתנים. ניתוח גרף זה מאפשר שני שיפורי עיבוד מקדים לבעיה. ראשית, ניתן לאחד אילוצים בודדים לאילוץ גדול אחד באמצעות מיזוג קליקות (clique merging), כך שהם יוצגו על ידי מערבל XY יחיד. שנית, ניתן לקבע באופן דטרמיניסטי משתנים בעלי שכן יחיד בלבד, מה שמצמצם את גודל הבעיה ואת מורכבותה.
-
פתרון אילוצים: מעבד הקדם מטפל בכל אילוץ בנפרד: אם האילוץ הוא אילוץ one-hot, ניתן לאכוף אותו באמצעות מערבלי XY. אם מדובר באילוץ set-packing, הוא יומר תחילה לאילוץ one-hot. אילוצי שוויון מטופלים באמצעות קנסות ריבועיים, ואילוצי אי-שוויון באמצעות ענישה לא-מאוזנת.
-
גזירת קנס: אילוצים שלא ניתן לבטא כאילוצי שוויון one-hot מומרים לאיברי קנס. האופטימייזר גוזר את עוצמת הקנס באופן אוטומטי ממבנה הבעיה.
-
-
התחלה חמה איטרטיבית: האופטימייזר מריץ מספר שרשראות התחלה חמה מקבילות. כל שרשרת מחזיקה התפלגות הסתברות על פני השמות של ערכים למשתנים, המשמשת כהסתברות ההתחלה של מעגל ה-QAOA (מצב התחלה חמה). בכל איטרציה, השרשרת דוגמת מהמעגל הקוונטי, מיישמת עיבוד קלאסי לאחר-דגימה, ומעדכנת את ההתפלגות שלה בהתבסס על שכיחות הדגימות. לאורך האיטרציות, הדבר ממקד את החיפוש בפתרונות באיכות גבוהה ללא לולאת אופטימיזציה וריאציונית.
מספר השרשראות (num_parallel), תקציב היריות (shots) הכולל לכל שרשרת (total_shots), ומספר החזרות של QAOA (reps) הם אמצעי הבקרה העיקריים לאיזון בין איכות הפתרון לזמן הריצה.
בנצ'מרקים
הבנצ'מרקים שלהלן מראים שפונקציית Qiskit של Constrained Quantum Optimizer מסוגלת למצוא פתרונות ישימים באיכות גבוהה לבעיות אופטימיזציה עם אילוצים הכוללות הרבה מעל 100 משתנים בינאריים. הדיוק (Accuracy) הוא היחס בין ערך פונקציית המטרה שנמצא לבין האופטימום הידוע. זמן הריצה (Runtime) הוא הזמן הכולל שחלף (wall-clock) מקריאת הפונקציה ועד למסירת התוצאה. שימוש ה-QPU הוא זמן ה-Quantum Compute שניתן לחיוב.
שתי בעיות נבחנו: בעיית Maximum Independent Set (MIS) ו-Max--Cut, שהיא הרחבה של בעיית MaxCut הידועה ליותר משתי קטגוריות. Max--Cut היא גם בעיית האופטימיזציה המקבילה לבעיית ההכרעה של צביעת גרפים (graph coloring) (כאשר כל הקשתות נחתכות, הגרף הוא -צביע).
| בעיה | משתנים | אילוצים | Qubits | דיוק | ישימות | זמן ריצה כולל (שניות) | שימוש ב-QPU (שניות) | סה"כ יריות |
|---|---|---|---|---|---|---|---|---|
| MIS es60fst02 | 186 | 280 | 124 | 100.0% | True | 940.2 | 147.0 | 25.0k |
| MIS sloane_2dc_128 | 128 | 5173 | 74 | 100.0% | True | 347.6 | 106.0 | 12.5k |
| Max-3-Cut Karate Club | 99 | 33 | 99 | 98.7% | True | 279.5 | 166.0 | 25.0k |
| Max-4-Cut Karate Club | 132 | 33 | 132 | 100.0% | True | 258.3 | 200.0 | 25.0k |
הערות לבנצ'מרק
-
התוצאות שלעיל התקבלו על המעבד
ibm_marrakeshמסוג Heron r2, עם אפשרויות ברירת המחדל ו-use_sessionמופעל. עבור המופעsloane_2dc_128, נעשה שימוש ב-total_shots=12500. -
מספר ה-Qubits המופחת עבור מופעי MIS (74 ו-124 לעומת 128 ו-186 משתנים) משקף קיבוע משתנים בעיבוד המקדים.
-
מופעי הבעיה עבור MIS נלקחים מתוך Quantum Optimization Benchmarking Library. - המופע עבור בעיית Max--Cut הוא גרף Zachary Karate Club, שמספר הצביעה (chromatic number) שלו הוא 5.
התחלת העבודה
מדריך זה מדגים שימוש בסיסי ב-Constrained Quantum Optimizer, על ידי הצגת אופן טעינת הפונקציה והרצת בעיות פשוטות. למדריך מפורט יותר, ראו Find the Maximum Independent Set with the Aqarios Constrained Quantum Optimizer.
התאמתו (authenticate) באמצעות מפתח ה-API שלכם ב-IBM Quantum ו-CRN של המופע, ולאחר מכן טענו את הפונקציה מהקטלוג.
הקוד הבא מניח שכבר שמרתם את פרטי ההתחברות שלכם. כדי להגדיר אותם, פעלו לפי ההוראות במאמר שמירת פרטי חשבון IBM Cloud שלכם.
# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util
_needed = {"luna_model": "luna-model", "networkx": "networkx", "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(aqarios/constrained-quantum-optimizer)]
# Load the function
optimizer = catalog.load("aqarios/constrained-quantum-optimizer")
# Check the list of backends you have access to
catalog.backends()
[<IBMBackend('ibm_pittsburgh')>,
<IBMBackend('ibm_boston')>,
<IBMBackend('ibm_phoenix')>,
<IBMBackend('ibm_fez')>,
<IBMBackend('ibm_miami')>,
<IBMBackend('ibm_marrakesh')>,
<IBMBackend('ibm_kingston')>]
# Select the backend you want to use
backend = catalog.backend("ibm_phoenix")
דוגמה 1: בעיה פשוטה עם אילוצים
הדוגמה הראשונה מראה כיצד להשתמש בפונקציה עם קובצי LP, פורמט נפוץ בחקר ביצועים לתיאור בעיות אופטימיזציה. תנסחו את בעיית האופטימיזציה השרירותית הבאה עם חמישה משתנים בינאריים הכפופה לשני אילוצים:
1. ניסוח הבעיה
רשמו ישירות את הביטוי המתמטי בפורמט מחרוזת ה-LP הבא:
lp_str = """\\Problem name: Example
Minimize
obj: [ 2 x_1 x_2 + 4 x_2 x_3 - 2 x_3 x_4 - 4 x_4 x_5 - 4 x_1 x_3 - 8 x_2 x_5 ] / 2
Subject To
c1: x_1 + x_2 + x_3 <= 1
c2: x_3 - x_4 + x_5 = 0
Binaries
x_1 x_2 x_3 x_4 x_5
End
"""
שימו לב ש-[ ... ] / 2 הוא סימון נדרש עבור פונקציות מטרה ריבועיות בתקן ה-LP.
2. הרצת האופטימייזר
פתרו את הבעיה באמצעות האופטימייזר.
# Set up low-resource options for the simple problem
options = {"total_shots": 2000, "num_parallel": 5, "use_session": True}
# Dispatch the job
job_1 = optimizer.run(
problem=lp_str, backend_name=backend.name, options=options
)
print(f"Job ID: {job_1.job_id}")
Job ID: 2e06a3a8-7c29-4c76-94d7-194293363f4a
# Monitor the job status
job_1.status()
'RUNNING: WAITING_FOR_QPU'
3. אחזור התוצאה
הפתרון, הממפה את שמות המשתנים להשמות המשויכות להם, מסופק על ידי התוצאה.
result = job_1.result()
result
{'solutions': [{'x_1': 0, 'x_2': 1, 'x_3': 0, 'x_4': 1, 'x_5': 1}],
'solution_bitstrings': ['01011'],
'raw_energy': -6.0,
'objective_value': -6.0,
'feasible': True,
'metadata': {'resource_usage': {'RUNNING: MAPPING': {'CPU': 5.405},
'RUNNING: OPTIMIZING_FOR_HARDWARE': {'CPU': 9.902},
'RUNNING: WAITING_FOR_QPU': {'CPU': 25.456},
'RUNNING: EXECUTING_QPU': {'CPU': 25.202},
'RUNNING: POST_PROCESSING': {'CPU': 6.481}},
'circuit_metrics': {'before_transpilation': {'num_qubits': 6,
'gate_count': 42,
'depth': 15,
'two_qubit_gate_count': 12,
'two_qubit_gate_depth': 7,
'operations': {'rz': 12,
'p': 8,
'ry': 7,
'rzz': 4,
'cx': 3,
'xx_plus_yy': 3,
'global_phase': 2,
'cry': 2,
'x': 1}},
'after_transpilation': {'num_qubits': 6,
'gate_count': 254,
'depth': 100,
'two_qubit_gate_count': 48,
'two_qubit_gate_depth': 33,
'operations': {'rz': 78, 'sx': 122, 'cz': 48, 'measure': 6, 'x': 0}}},
'solver_info': {'variable_mapping': {'x_1': 0,
'x_2': 1,
'x_3': 2,
'x_4': 3,
'x_5': 4}}}}
השדה solutions במילון המוחזר מכיל את כל הפתרונות האופטימליים (המנוונים) שנמצאו, כמילונים שממפים כל שם משתנה להשמה שלו. אותם פתרונות מוחזרים גם כמחרוזות ביטים ב-solution_bitstrings; metadata.solver_info.variable_mapping מציין איזה מיקום תו במחרוזת הביטים שייך לאיזה משתנה. לצד נתוני הפתרון מסופקים גם objective_value, דגל feasible ו-metadata נוסף.
דוגמה 2: Maximum Independent Set
בעיית Maximum Independent Set (MIS) מבקשת את תת-הקבוצה הגדולה ביותר של קודקודים בגרף, כך שאין שני קודקודים בתת-הקבוצה החולקים קשת משותפת. דוגמה זו פותרת MIS על גרף רגולרי בן 12 צמתים. למידע נוסף על הבעיה ולדוגמה גדולה יותר, ראו את המדריך.
הבעיה נבנית באמצעות qiskit-addon-opt-mapper. התקינו את החבילות הנדרשות במידת הצורך:
# %pip install networkx qiskit-addon-opt-mapper
שלב 1: הגדרת הבעיה
בנו גרף 3-רגולרי אקראי וצרו את בעיית האופטימיזציה של MIS. כל צומת בגרף הופך למשתנה בינארי, וכל קשת מציגה אילוץ המבטיח שלכל היותר נקודת קצה אחת שלה תיבחר.
import networkx as nx
from qiskit_addon_opt_mapper.applications import IndependentSet
from qiskit_addon_opt_mapper.translators import to_docplex_mp
# 12-node random 3-regular graph
G = nx.random_regular_graph(3, 12, seed=7)
# Build MIS problem and export as LP string
mis = IndependentSet(G)
mis_problem = mis.to_optimization_problem()
lp_str = to_docplex_mp(mis_problem).export_as_lp_string()
print(lp_str)
\ This file has been generated by DOcplex
\ ENCODING=ISO-8859-1
\Problem name: Independent set
Maximize
obj: x_0 + x_1 + x_2 + x_3 + x_4 + x_5 + x_6 + x_7 + x_8 + x_9 + x_10 + x_11
Subject To
c0: x_0 + x_4 <= 1
c1: x_0 + x_9 <= 1
c2: x_0 + x_8 <= 1
c3: x_1 + x_2 <= 1
c4: x_1 + x_7 <= 1
c5: x_1 + x_3 <= 1
c6: x_2 + x_4 <= 1
c7: x_2 + x_11 <= 1
c8: x_3 + x_10 <= 1
c9: x_3 + x_11 <= 1
c10: x_4 + x_5 <= 1
c11: x_5 + x_10 <= 1
c12: x_5 + x_6 <= 1
c13: x_6 + x_8 <= 1
c14: x_6 + x_7 <= 1
c15: x_7 + x_9 <= 1
c16: x_8 + x_11 <= 1
c17: x_9 + x_10 <= 1
Bounds
0 <= x_0 <= 1
0 <= x_1 <= 1
0 <= x_2 <= 1
0 <= x_3 <= 1
0 <= x_4 <= 1
0 <= x_5 <= 1
0 <= x_6 <= 1
0 <= x_7 <= 1
0 <= x_8 <= 1
0 <= x_9 <= 1
0 <= x_10 <= 1
0 <= x_11 <= 1
Binaries
x_0 x_1 x_2 x_3 x_4 x_5 x_6 x_7 x_8 x_9 x_10 x_11
End
שלב 2: הרצת האופטימייזר
פתרו את הבעיה באמצעות האופטימייזר.
options = {"total_shots": 2000, "use_session": True}
# Dispatch the job
job_2 = optimizer.run(
problem=lp_str, backend_name=backend.name, options=options
)
print(f"Job ID: {job_2.job_id}")
Job ID: f041431c-b42e-4627-afe5-522fea61faf6
# Monitor the job status
job_2.status()
'QUEUED'
שלב 3: אחזור התוצאות ופירושן
לבסוף, נאחזר את הפתרון ונוודא את נכונותו.
result = job_2.result()
print(f"Feasible: {result['feasible']}")
print(f"Independent set size: {int(result['objective_value'])}")
# Extract the selected nodes
solution = result["solutions"][0]
independent_set = [
int(k.split("_")[1]) for k, v in solution.items() if v == 1
]
print(f"Selected nodes: {sorted(independent_set)}")
# Verify no two selected nodes share an edge
conflicts = [
(u, v)
for u, v in G.edges()
if u in independent_set and v in independent_set
]
print(f"Edge conflicts: {conflicts}")
Feasible: True
Independent set size: 5
Selected nodes: [1, 4, 6, 9, 11]
Edge conflicts: []
דוגמה 3: צביעת גרף ב-3 צבעים (Max-3-Cut)
בעיית Max--Cut מחלקת את קודקודי הגרף ל- קבוצות במטרה למקסם את מספר הקשתות שנקודות הקצה שלהן שייכות לקבוצות שונות. עבור הדבר שקול למציאת צביעה ב-3 צבעים הממקסמת קשתות בין-צבעוניות.
באופן פורמלי, מייחסים כל צומת לאחת מתוך קבוצות באמצעות משתנים בינאריים עבור צבע . אילוץ ה-one-hot עבור כל צומת אוכף השמה ייחודית. פונקציית המטרה ממקסמת קשתות בין-קבוצתיות:
אילוצי ה-one-hot אידיאליים עבור מערבלי XY, שבהם האופטימייזר מטפל באופן טבעי.
דוגמה זו משתמשת ב-גרף Zachary Karate Club (34 צמתים, 78 קשתות) ובונה את המודל באמצעות Luna Model. התקינו את החבילות הנדרשות במידת הצורך:
# %pip install networkx matplotlib luna-model
שלב 1: הגדרת הבעיה
ראשית, צרו את המשתנים הבינאריים באמצעות החבילה luna-model. לאחר מכן, הגדירו את פונקציית המטרה והוסיפו את האילוצים למודל.
import networkx as nx
from luna_model import Model, quicksum
k = 3
G = nx.karate_club_graph()
# Instantiate the Model object
model = Model(name="Max-3-Cut")
# Add binary variables
x = model.add_variables("x", shape=(G.number_of_nodes(), k))
# Add the objective by using the numpy dot abstraction
model.objective = quicksum(x[i].dot(x[j]) for i, j in G.edges)
# Bulk-add the one-hot constraints
model.add_constraints(x.sum(axis=1) == 1)
# Encode the model to send via API
model_enc = model.encode_b64()
שלב 2: הרצת האופטימייזר
פתרו את הבעיה באמצעות האופטימייזר.
options = {"use_session": True}
# Dispatch the job
job_3 = optimizer.run(
problem=model_enc, backend_name=backend.name, options=options
)
print(f"Job ID: {job_3.job_id}")
Job ID: df911d83-9df7-44a1-bfad-5d66e08676c3
# Monitor the job status
job_3.status()
'RUNNING: WAITING_FOR_QPU'
שלב 3: אחזור התוצאות והצגתן
אחזרו את התוצאות והציגו אותן.
result = job_3.result()
solution = result["solutions"][0]
# Map each node to its assigned color group
node_group = {}
for i in G.nodes:
for c in range(k):
if solution[f"x{i},{c}"] == 1:
node_group[i] = c
print(f"Feasible: {result['feasible']}")
print(f"Violations: {int(result['objective_value'])}")
# Visualize the partition
colors = ["tab:blue", "tab:orange", "tab:green"]
node_colors = [colors[node_group[i]] for i in G.nodes()]
nx.draw(G, nx.kamada_kawai_layout(G), node_color=node_colors, node_size=200)
Feasible: True
Violations: 4

יומן שינויים
[0.4.0] - 2026-09-22
שינויים שוברי תאימות
- שם פרמטר הקלט
modelשונה ל-problem. - שם שדה הפלט
obj_valueשונה ל-objective_value. - האפשרות
postprocessingהוחלפה ב-postprocessing_level, שמקבלת מספר שלם בטווח[0, 3]במקום מחרוזת. הערכים הקודמים ממופים כך:"off"->0,"weak"->1,"medium"->2ו-"strong"->3, וברירת המחדל לא השתנתה ונשארה3. - המבנה של
metadata.circuit_metricsשונה. כעת הוא מדווח עלnum_qubits,gate_count,depth,two_qubit_gate_count,two_qubit_gate_depthו-operationsבנפרד עבורbefore_transpilationו-after_transpilation, במקום מילון שטוח יחיד של ממוצעי ספירות שערים. השדה הואNoneכשהבעיה נפתרה במהלך העיבוד המקדים ולא הורץ שום מעגל (קוד שגיאה4712).
תכונות
- נוספה האפשרות
seed_transpilerכדי להפוך את סינתזת המעגל והניתוב לניתנים לשחזור בין הרצות. - נוספה האפשרות
job_tagsכדי לצרף תגיות משלכם לכל עבודת Qiskit Runtime שהפונקציה שולחת. - נוסף שדה הפלט
solution_bitstrings, שמחזיר את אותם פתרונות כמוsolutionsבצורת מחרוזות ביטים. - נוסף
metadata.solver_info.variable_mapping, שממפה כל שם משתנה למיקום התו שלו במחרוזות שב-solution_bitstrings.
תיעוד
- תועד שמשתנים רציפים (בעלי ערכים ממשיים) אינם נתמכים ושמשתנים שלמים דורשים חסמים מפורשים. מודלים כאלה נכשלים עם קוד השגיאה
4710.
קבלת תמיכה
לשאלות או בעיות, פנו אל support@aqarios.com עם מזהה העבודה (job ID) שלכם.
הצעדים הבאים
- בקשת גישה ל-Constrained Quantum Optimizer מבית Aqarios.
- בקרו בהפניית ה-API לתיעוד המלא של הפרמטרים והפלט.
- נסו את מדריך Find the Maximum Independent Set with the Aqarios Constrained Quantum Optimizer לצלילה מעמיקה לתוך מופע בנצ'מרק אמיתי של QOBLIB.
- עיינו בפרסום Constrained Quantum Optimization via Iterative Warm-Start XY-Mixers.
מקורות
- Bucher et al. (2026), Constrained Quantum Optimization via Iterative Warm-Start XY-Mixers 10.1088/1367-2630/ae8ea2