انتقل إلى المحتوى الرئيسي

محلّل التحسين: دالة Qiskit من Q-CTRL Fire Opal

ملاحظة

دوال Qiskit ميزة تجريبية متاحة فقط لمستخدمي IBM Quantum® Premium Plan وFlex Plan وOn-Prem (عبر IBM Quantum Platform API) Plan. هي في مرحلة إصدار معاينة وقابلة للتغيير.

نظرة عامة

مع محلّل التحسين Fire Opal، يمكنك حلّ مسائل التحسين على النطاق الاستخدامي على الأجهزة الكمومية دون الحاجة إلى خبرة كمومية. ما عليك سوى إدخال تعريف المسألة رفيع المستوى، ويتولى المحلّل الباقي. سير العمل بالكامل يدرك الضجيج ويستفيد من إدارة أداء Fire Opal في الخلفية. يقدّم المحلّل باستمرار حلولاً دقيقة للمسائل الصعبة كلاسيكيًا، حتى على نطاق الجهاز الكامل لأكبر أجهزة IBM® QPU.

المحلّل مرن ويمكن استخدامه لحلّ مسائل التحسين التوافقية المعرَّفة كدوال هدف أو رسوم بيانية عشوائية. لا يجب ربط المسائل بطبولوجيا الجهاز. المسائل غير المقيدة والمقيدة قابلة للحلّ، بشرط أن تُصاغ القيود كحدود عقوبة. الأمثلة المضمّنة في هذا الدليل توضّح كيفية حلّ مسألة تحسين غير مقيدة ومسألة مقيدة على النطاق الاستخدامي باستخدام أنواع مدخلات مختلفة للمحلّل. المثال الأول يتضمن مسألة Max-Cut معرَّفة على رسم بياني منتظم ثلاثي 156 عقدة، بينما يعالج المثال الثاني مسألة Minimum Vertex Cover من 50 عقدة معرَّفة بدالة تكلفة.

للحصول على إمكانية الوصول إلى محلّل التحسين، تواصل مع Q-CTRL.

وصف الدالة

يحسّن المحلّل الخوارزمية بالكامل ويؤتمتها، من قمع الأخطاء على مستوى الأجهزة إلى تعيين المسائل بكفاءة والتحسين الكلاسيكي في حلقة مغلقة. خلف الكواليس، تقلّل خطوط أنابيب المحلّل الأخطاء في كل مرحلة، مما يُمكّن الأداء المحسّن المطلوب للتوسع الفعلي. سير العمل الأساسي مستوحى من خوارزمية التحسين الكمومي التقريبي (QAOA)، وهي خوارزمية هجينة كمومية-كلاسيكية. للاطلاع على ملخص تفصيلي لسير عمل محلّل التحسين الكامل، راجع المخطوطة المنشورة.

تصوّر لسير عمل محلّل التحسين

لحلّ مسألة عامة مع محلّل التحسين:

  1. عرِّف مسألتك كدالة هدف، أو رسم بياني، أو سلسلة دوران SparsePauliOp.
  2. اتصل بالدالة عبر كتالوج دوال Qiskit.
  3. شغّل المسألة مع المحلّل واسترجع النتائج.

المدخلات والمخرجات

المدخلات

الاسمالنوعالوصفمطلوبالافتراضيمثال
problemstr أو SparsePauliOpأحد التمثيلات المدرجة ضمن "صيغ المسائل المقبولة"نعمغير متاحPoly(2.0*n[0]*n[1] + 2.0*n[0]*n[2] - 3.13520241298341*n[0] + 2.0*n[1]*n[2] - 3.14469748506794*n[1] - 3.18897660121566*n[2] + 6.0, n[0], n[1], n[2], domain='RR')
problem_typestrاسم فئة المسألة؛ يُستخدم فقط لتعريفات مسائل الرسم البياني وسلسلة الدوران، المحدودة بـ"maxcut" أو "spin_chain"؛ غير مطلوب لتعريفات مسائل دالة الهدف العشوائيةلاNone"maxcut"
backend_namestrاسم الخلفية المراد استخدامهالاأقل الخلفيات ازدحامًا التي يمكن لمثيلك الوصول إليها"ibm_fez"
optionsdictخيارات الإدخال، بما في ذلك: (اختياري) session_id: str؛ السلوك الافتراضي ينشئ جلسة جديدةلاNone{"session_id": "cw2q70c79ws0008z6g4g"}

صيغ المسائل المقبولة:

  • تمثيل التعبير متعدد الحدود لدالة هدف. يُنصح بإنشائه في Python بكائن SymPy Poly موجود وتنسيقه كسلسلة نصية باستخدام sympy.srepr.
  • تمثيل رسم بياني لنوع مسألة محدد. يجب إنشاء الرسم البياني باستخدام مكتبة networkx في Python، ثم تحويله إلى سلسلة نصية باستخدام دالة networkx [nx.readwrite.json_graph.adjacency_data](http://nx.readwrite.json_graph.adjacency_data.).
  • تمثيل سلسلة الدوران لمسألة محددة. يجب تمثيل سلسلة الدوران ككائن SparsePauliOp؛ راجع التوثيق لمزيد من التفاصيل.

الخلفيات المدعومة: شغّل الكود التالي لرؤية قائمة الخلفيات المدعومة حاليًا. إذا لم تكن جهازك مدرجًا، تواصل مع Q-CTRL لإضافة الدعم.

# Added by doQumentation — required packages for this notebook
!pip install -q networkx numpy qiskit-ibm-catalog qiskit-ibm-runtime sympy
from qiskit_ibm_runtime import QiskitRuntimeService

service = QiskitRuntimeService()

service.backends()
[<IBMBackend('ibm_fez')>,
<IBMBackend('ibm_brisbane')>,
<IBMBackend('ibm_pittsburgh')>,
<IBMBackend('ibm_kingston')>,
<IBMBackend('ibm_torino')>,
<IBMBackend('ibm_marrakesh')>]

الخيارات:

الاسمالنوعالوصفالافتراضي
session_idstrمعرّف جلسة Qiskit Runtime موجودة"cw4r3je6f0t010870y3g"
job_tagslist[str]قائمة بوسوم الوظائف[]

المخرجات

الاسمالنوعالوصفمثال
resultdict[str, Any]الحلّ والبيانات الوصفية المدرجة ضمن "محتويات قاموس النتيجة"{'solution_bitstring_cost': 3.0, 'final_bitstring_distribution': {'000001': 100, '000011': 2}, 'iteration_count': 3, 'solution_bitstring': '000001', 'variables_to_bitstring_index_map': {n[1]': 5, 'n[2]': 4, 'n[3]': 3, 'n[4]': 2, 'n[5]': 1}, 'best_parameters': [0.19628831763697097, -1.047052334523102], 'warnings': []}

محتويات قاموس النتيجة:

الاسمالنوعالوصف
solution_bitstring_costfloatأفضل تكلفة دنيا عبر جميع التكرارات
final_bitstring_distributionCountsDictقاموس أعداد السلسلة الثنائية المرتبط بالتكلفة الدنيا
solution_bitstringstrالسلسلة الثنائية ذات أفضل تكلفة في التوزيع النهائي
iteration_countintالعدد الكلي لتكرارات QAOA التي أجراها المحلّل
variables_to_bitstring_index_mapfloatالربط بين المتغيرات والبت المقابل في السلسلة الثنائية
best_parameterslist[float]معاملات beta وgamma المحسّنة عبر جميع التكرارات
warningslist[str]التحذيرات الصادرة أثناء تجميع QAOA أو تشغيله (تعود افتراضيًا بـNone)

المعايير المرجعية

تُظهر نتائج المعايير المرجعية المنشورة أن المحلّل ينجح في حلّ مسائل تتجاوز 120 كيوبت، متفوقًا حتى على النتائج المنشورة سابقًا على أجهزة التليين الكمومي والأيونات المحاصرة. مقاييس المعايير المرجعية التالية تعطي مؤشرًا تقريبيًا على دقة أنواع المسائل وقابليتها للتوسع بناءً على بعض الأمثلة. قد تختلف المقاييس الفعلية بناءً على خصائص المسألة المختلفة، مثل عدد الحدود في دالة الهدف (الكثافة) وموقعها، وعدد المتغيرات، والرتبة متعددة الحدود.

"عدد الكيوبتات" المشار إليه ليس حدًا صارمًا بل يمثّل عتبات تقريبية حيث يمكن توقع دقة حلول عالية الاتساق. مسائل أكبر حجمًا تمّ حلّها بنجاح، ويُشجّع الاختبار خارج هذه الحدود.

الاتصالية العشوائية بين الكيوبتات مدعومة عبر جميع أنواع المسائل.

نوع المسألةعدد الكيوبتاتمثالالدقةالوقت الكلي (ث)استخدام وقت التشغيل (ث)عدد التكرارات
مسائل تربيعية متفرقة الاتصال156Max-Cut ثلاثي منتظم100%176429316
تحسين ثنائي ذو رتبة عليا156نموذج Ising spin-glass100%146127216
مسائل تربيعية كثيفة الاتصال50Max-Cut متكامل الاتصال100%175826812
مسألة مقيدة بحدود عقوبة50Minimum Vertex Cover موزون بكثافة حواف 8%100%107421510

البدء

أولًا، سجّل الدخول باستخدام مفتاح IBM Quantum API. ثم اختر دالة Qiskit كما يلي. (هذا المقتطف يفترض أنك حفظت حسابك في بيئتك المحلية مسبقًا.)

from qiskit_ibm_catalog import QiskitFunctionsCatalog

catalog = QiskitFunctionsCatalog(channel="ibm_quantum_platform")

# Access Function
solver = catalog.load("q-ctrl/optimization-solver")

مثال: تحسين غير مقيد

شغّل مسألة القطع الأقصى (Max-Cut). يوضّح المثال التالي قدرات المحلّل على مسألة Max-Cut لرسم بياني غير موزون منتظم ثلاثي من 156 عقدة، لكن يمكنك أيضًا حلّ مسائل الرسم البياني الموزون. بالإضافة إلى qiskit-ibm-catalog، ستحتاج أيضًا إلى الحزم التالية لتشغيل هذا المثال: networkx وnumpy. يمكنك تثبيت هذه الحزم بإلغاء تعليق الخلية التالية إذا كنت تشغّل هذا المثال في notebook باستخدام نواة IPython.

# %pip install networkx numpy

1. تعريف المسألة

يمكنك تشغيل مسألة Max-Cut بتعريف مسألة رسم بياني وتحديد 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

يقبل المحلّل سلسلة نصية كمدخل لتعريف المسألة.

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

2. تشغيل المسألة

عند استخدام طريقة الإدخال القائمة على الرسم البياني، حدّد نوع المسألة.

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

تحقق من حالة حمل عمل دالة Qiskit أو استرجع النتائج كما يلي:

# Get job status
print(maxcut_job.status())
QUEUED

3. استرجاع النتيجة

استرجع قيمة القطع المثلى من قاموس النتائج.

ملاحظة
ربما تغيّر تعيين المتغيرات إلى السلسلة الثنائية. يحتوي قاموس الإخراج على قاموس فرعي variables_to_bitstring_index_map يساعد في التحقق من الترتيب.
# 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: 209.0

يمكنك التحقق من دقة النتيجة بحلّ المسألة كلاسيكيًا باستخدام محلّلات مفتوحة المصدر مثل PuLP إذا لم يكن الرسم البياني كثيف الاتصال. قد تتطلب مسائل الكثافة العالية محلّلات كلاسيكية متقدمة للتحقق من صحة الحلّ.

مثال: تحسين مقيد

مثال Max-Cut السابق هو مسألة تحسين ثنائي تربيعي غير مقيد شائعة. يمكن استخدام محلّل التحسين من Q-CTRL لأنواع مسائل متعددة، بما في ذلك التحسين المقيد. يمكنك حلّ أنواع مسائل عشوائية بإدخال تعريف المسألة ممثَّلًا كمتعدد حدود حيث تُنمذَج القيود كحدود عقوبة.

يوضّح المثال التالي كيفية بناء دالة تكلفة لمسألة تحسين مقيدة، الغطاء الأدنى للرؤوس (MVC). بالإضافة إلى حزمتي qiskit-ibm-catalog وqiskit، ستحتاج أيضًا إلى الحزم التالية لتشغيل هذا المثال: numpy وnetworkx وsympy. يمكنك تثبيت هذه الحزم بإلغاء تعليق الخلية التالية إذا كنت تشغّل هذا المثال في notebook باستخدام نواة IPython.

# %pip install numpy networkx sympy

1. تعريف المسألة

عرِّف مسألة MVC عشوائية بتوليد رسم بياني بعقد موزونة عشوائيًا.

import networkx as nx
from sympy import symbols, 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
mvc_graph = nx.erdos_renyi_graph(
node_count, edge_probability, seed=rng_seed, directed=False
)

# add node weights
for i in mvc_graph.nodes:
mvc_graph.add_node(i, weight=_rng.random())

# Optionally, visualize the graph
nx.draw_networkx(mvc_graph, nx.kamada_kawai_layout(mvc_graph), node_size=200)

Output of the previous code cell

يمكن صياغة نموذج التحسين القياسي للـMVC الموزون كما يلي. أولًا، يجب إضافة عقوبة لأي حالة لا تكون فيها حافة متصلة برأس في المجموعة الفرعية. لذا، ليكن ni=1n_i = 1 إذا كان الرأس ii في الغطاء (أي في المجموعة الفرعية) وni=0n_i = 0 في الحالة المعاكسة. ثانيًا، الهدف هو تقليل العدد الكلي للرؤوس في المجموعة الفرعية، ويمكن تمثيله بالدالة التالية:

Minimizey=iVωini\textbf{Minimize}\qquad y = \sum_{i\in V} \omega_i n_i

# Construct the cost function.
variables = symbols([f"n[{i}]" for i in range(node_count)])
cost_function = Poly(0, variables)

for i in mvc_graph.nodes():
weight = mvc_graph.nodes[i].get("weight", 0)
cost_function += variables[i] * weight

الآن يجب أن تشمل كل حافة في الرسم البياني على الأقل نقطة نهاية واحدة من الغطاء، ويمكن التعبير عن ذلك بالمتراجحة:

ni+nj1 for all (i,j)En_i + n_j \ge 1 \texttt{ for all } (i,j)\in E

يجب معاقبة أي حالة لا تكون فيها الحافة متصلة برأس من الغطاء. يمكن تمثيل ذلك في دالة التكلفة بإضافة عقوبة من الشكل P(1ninj+ninj)P(1-n_i-n_j+n_i n_j) حيث PP ثابت عقوبة موجب. وبذلك، البديل غير المقيد للمتراجحة المقيدة للـMVC الموزون هو:

Minimizey=iVωini+P((i,j)E(1ninj+ninj))\textbf{Minimize}\qquad y = \sum_{i\in V}\omega_i n_i + P(\sum_{(i,j)\in E}(1 - n_i - n_j + n_i n_j))

# Add penalty term.
penalty_constant = 2
for i, j in mvc_graph.edges():
cost_function += penalty_constant * (
1 - variables[i] - variables[j] + variables[i] * variables[j]
)

2. تشغيل المسألة

# Solve the problem
mvc_job = solver.run(
problem=srepr(cost_function),
backend_name=backend_name, # E.g. "ibm_fez"
)

تحقق من حالة حمل عمل دالة Qiskit أو استرجع النتائج كما يلي:

print(mvc_job.status())

3. الحصول على النتيجة

استرجع الحلّ وحلّل النتائج. بما أن هذه المسألة تحتوي على عقد موزونة، فالحلّ ليس مجرد الحد الأدنى من عدد العقد المغطاة. بدلًا من ذلك، تمثّل تكلفة الحلّ مجموع أوزان الرؤوس المضمّنة في غطاء الرأس. وهي تمثّل "التكلفة" أو "الوزن" الكلي لتغطية جميع الحواف في الرسم البياني باستخدام الرؤوس المختارة.

mvc_result = mvc_job.result()
qctrl_cost = mvc_result["solution_bitstring_cost"]

# Print results
print(f"Solution cost: {qctrl_cost}")
Solution cost: 10.248198273708624

الدعم

لأي أسئلة أو مشكلات، تواصل مع Q-CTRL.

الخطوات التالية