خوارزمية التحسين التقريبي الكمومي
تقدير الاستخدام: 22 دقيقة على معالج Heron r3 (ملاحظة: هذا تقدير فحسب. قد يختلف وقت التشغيل الفعلي.)
الخلفية النظرية
يوضح هذا البرنامج التعليمي كيفية تنفيذ خوارزمية التحسين التقريبي الكمومي (QAOA) – وهي طريقة تكرارية هجينة (كمومية-كلاسيكية) – في سياق أنماط Qiskit. ستحل أولاً مسألة القطع الأقصى (أو Max-Cut) لرسم بياني صغير، ثم ستتعلم كيفية تنفيذه على نطاق الاستخدام العملي. ينبغي أن تُنفَّذ جميع عمليات تشغيل الأجهزة في هذا البرنامج التعليمي ضمن الحد الزمني المتاح للخطة المفتوحة المتاحة مجاناً.
مسألة القطع الأقصى هي مسألة تحسين يصعب حلها (وبصورة أدق، هي مسألة NP-hard) ولها تطبيقات عديدة في التجميع وعلم الشبكات والفيزياء الإحصائية. يأخذ هذا البرنامج التعليمي رسماً بيانياً من عقد مرتبطة بحواف، ويهدف إلى تقسيم العقد إلى مجموعتين بحيث يكون عدد الحواف التي يقطعها هذا التقسيم أقصى ما يمكن.

المتطلبات
قبل البدء في هذا البرنامج التعليمي، تأكد من تثبيت ما يلي:
- Qiskit SDK الإصدار v1.0 أو أحدث، مع دعم التصور المرئي
- Qiskit Runtime الإصدار v0.22 أو أحدث (
pip install qiskit-ibm-runtime)
بالإضافة إلى ذلك، ستحتاج إلى صلاحية الوصول إلى نسخة على IBM Quantum Platform. لاحظ أن هذا البرنامج التعليمي لا يمكن تنفيذه على الخطة المفتوحة، إذ يشغّل أحمال عمل باستخدام الجلسات، المتاحة فقط ضمن الخطة المميزة.
الإعداد
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-ibm-runtime rustworkx scipy
import matplotlib
import matplotlib.pyplot as plt
import rustworkx as rx
from rustworkx.visualization import mpl_draw as draw_graph
import numpy as np
from scipy.optimize import minimize
from collections import defaultdict
from typing import Sequence
from qiskit.quantum_info import SparsePauliOp
from qiskit.circuit.library import QAOAAnsatz
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit_ibm_runtime import Session, EstimatorV2 as Estimator
from qiskit_ibm_runtime import SamplerV2 as Sampler
الجزء الأول: QAOA على نطاق صغير
يستخدم الجزء الأول من هذا البرنامج التعليمي مسألة قطع أقصى صغيرة النطاق لتوضيح خطوات حل مسألة تحسين باستخدام حاسوب كمومي.
لإعطاء بعض السياق قبل تحويل هذه المسألة إلى خوارزمية كمومية، يمكن فهم كيفية تحوّل مسألة القطع الأقصى إلى مسألة تحسين تركيبي كلاسيكية بالنظر أولاً في تقليل دالة
حيث المدخل هو متجه تتوافق مكوناته مع كل عقدة في الرسم البياني. بعد ذلك، يُقيَّد كل مكون من هذه المكونات ليكون إما أو (يمثلان الإدراج أو عدم الإدراج في القطع). يستخدم هذا المثال الصغير رسماً بيانياً بـ عقد.
يمكن كتابة دالة لزوج من العقد تشير إلى ما إذا كان الحافة المقابلة موجودة في القطع. على سبيل المثال، الدالة تساوي 1 فقط إذا كانت إحدى القيمتين أو تساوي 1 (مما يعني أن الحافة موجودة في القطع)، وتساوي صفراً في الحالات الأخرى. يمكن صياغة مسألة تعظيم الحواف في القطع على النحو التالي
والتي يمكن إعادة كتابتها على شكل تقليل كما يلي
الحد الأدنى لـ في هذه الحالة يتحقق حين يكون عدد الحواف التي يقطعها القطع أكبر ما يمكن. كما ترى، لا يوجد حتى الآن أي ارتباط بالحوسبة الكمومية. تحتاج إلى إعادة صياغة هذه المسألة بشكل يستطيع الحاسوب الكمومي فهمه. ابدأ بتهيئة مسألتك بإنشاء رسم بياني بـ عقد.
n = 5
graph = rx.PyGraph()
graph.add_nodes_from(np.arange(0, n, 1))
edge_list = [
(0, 1, 1.0),
(0, 2, 1.0),
(0, 4, 1.0),
(1, 2, 1.0),
(2, 3, 1.0),
(3, 4, 1.0),
]
graph.add_edges_from(edge_list)
draw_graph(graph, node_size=600, with_labels=True)

الخطوة 1: تحويل المدخلات الكلاسيكية إلى مسألة كمومية
الخطوة الأولى في النمط هي تحويل المسألة الكلاسيكية (الرسم البياني) إلى دوائر وعوامل كمومية. لتحقيق ذلك، هناك ثلاث خطوات رئيسية:
- استخدام سلسلة من إعادات الصياغة الرياضية لتمثيل المسألة باستخدام تدوين مسائل التحسين الثنائي التربيعي غير المقيّد (QUBO).
- إعادة كتابة مسألة التحسين على شكل هاميلتوني تتوافق حالته الأساسية مع الحل الذي يقلل دالة التكلفة.
- إنشاء دائرة كمومية لتهيئة الحالة الأساسية لهذا الهاميلتوني عبر عملية مشابهة للتلدين الكمومي.
ملاحظة: في منهجية QAOA، الهدف النهائي هو الحصول على عامل (هاميلتوني) يمثل دالة التكلفة لخوارزميتنا الهجينة، فضلاً عن دائرة ذات معاملات (Ansatz) تمثل الحالات الكمومية التي تُعدّ حلولاً مرشحة للمسألة. يمكن أخذ عينات من هذه الحالات المرشحة ثم تقييمها باستخدام دالة التكلفة.
الرسم البياني → مسألة التحسين
الخطوة الأولى في التحويل هي تغيير التدوين؛ يعبّر ما يلي عن المسألة بتدوين QUBO:
حيث هي مصفوفة من الأعداد الحقيقية، و يتوافق مع عدد العقد في رسمك البياني، و هو متجه المتغيرات الثنائية المُعرَّف أعلاه، و يشير إلى منقول المتجه .
Maximize
-2*x_0*x_1 - 2*x_0*x_2 - 2*x_0*x_4 - 2*x_1*x_2 - 2*x_2*x_3 - 2*x_3*x_4 + 3*x_0
+ 2*x_1 + 3*x_2 + 2*x_3 + 2*x_4
Subject to
No constraints
Binary variables (5)
x_0 x_1 x_2 x_3 x_4
مسألة التحسين → الهاميلتوني
يمكنك بعد ذلك إعادة صياغة مسألة QUBO على شكل هاميلتوني (أي مصفوفة تمثل طاقة نظام ما):
خطوات إعادة الصياغة من مسألة QAOA إلى الهاميلتوني
لتوضيح كيفية إعادة كتابة مسألة QAOA بهذه الطريقة، استبدل أولاً المتغيرات الثنائية بمجموعة جديدة من المتغيرات عبر
يمكن هنا ملاحظة أنه إذا كانت تساوي ، فإن يجب أن تساوي . حين يُعوَّض عن في مسألة التحسين ()، يمكن الحصول على صياغة مكافئة.
الآن إذا عرّفنا ، وأسقطنا عامل الضرب المسبق والحد الثابت ، نصل إلى الصياغتين المتكافئتين لمسألة التحسين ذاتها.
هنا، يعتمد على . لاحظ أننا للحصول على أسقطنا عامل 1/4 والإزاحة الثابتة اللتين لا تؤثران على عملية التحسين.
الآن، للحصول على صياغة كمومية للمسألة، نرفع متغيرات إلى مصفوفة Pauli ، مثل مصفوفة من الشكل
حين تُعوَّض هذه المصفوفات في مسألة التحسين أعلاه، نحصل على الهاميلتوني التالي
تذكّر أيضاً أن مصفوفات مُضمَّنة في فضاء العمليات الحسابية للحاسوب الكمومي، أي فضاء هيلبرت بحجم . لذلك، ينبغي فهم المصطلحات مثل على أنها حاصل الضرب التنسوري المُضمَّن في فضاء هيلبرت . فمثلاً، في مسألة بخمسة متغيرات قرار، يُفهم الحد على أنه حيث هي مصفوفة الهوية .
يُسمى هذا الهاميلتوني هاميلتوني دالة التكلفة. ويتميز بأن حالته الأساسية تتوافق مع الحل الذي يقلل دالة التكلفة . وبالتالي، لحل مسألة التحسين تحتاج الآن إلى تهيئة الحالة الأساسية لـ (أو حالة ذات تداخل كبير معها) على الحاسوب الكمومي. ثم ستؤدي عملية أخذ العينات من هذه الحالة، باحتمالية عالية، إلى الحصول على حل لـ . الآن لنتأمل الهاميلتوني لمسألة القطع الأقصى. نربط كل قمة من الرسم البياني بكيوبت في الحالة أو ، حيث تدل القيمة على المجموعة التي تنتمي إليها القمة. الهدف من المسألة هو تعظيم عدد الحواف التي يكون فيها و، أو العكس. إذا ربطنا العامل بكل كيوبت، حيث
فإن الحافة تنتمي إلى القطع إذا كانت القيمة الذاتية لـ ؛ بمعنى آخر، يكون الكيوبتان المرتبطان بـ و مختلفين. وبالمثل، لا تنتمي إلى القطع إذا كانت القيمة الذاتية لـ . لاحظ أننا لا نهتم بالحالة الكمومية الدقيقة المرتبطة بكل قمة، بل يهمنا فقط ما إذا كانت الحالتان متماثلتين أم مختلفتين عبر كل حافة. تتطلب مسألة القطع الأقصى إيجاد توزيع للكيوبتات على القمم بحيث تُقلَّل القيمة الذاتية للهاميلتوني التالي
بعبارة أخرى، لجميع في مسألة القطع الأقصى. تمثل قيمة وزن الحافة. في هذا البرنامج التعليمي نعتبر رسماً بيانياً غير موزون، أي لجميع .
def build_max_cut_paulis(
graph: rx.PyGraph,
) -> list[tuple[str, list[int], float]]:
"""Convert the graph to Pauli list.
This function does the inverse of `build_max_cut_graph`
"""
pauli_list = []
for edge in list(graph.edge_list()):
weight = graph.get_edge_data(edge[0], edge[1])
pauli_list.append(("ZZ", [edge[0], edge[1]], weight))
return pauli_list
max_cut_paulis = build_max_cut_paulis(graph)
cost_hamiltonian = SparsePauliOp.from_sparse_list(max_cut_paulis, n)
print("Cost Function Hamiltonian:", cost_hamiltonian)
Cost Function Hamiltonian: SparsePauliOp(['IIIZZ', 'IIZIZ', 'ZIIIZ', 'IIZZI', 'IZZII', 'ZZIII'],
coeffs=[1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j, 1.+0.j])
الهاميلتوني → الدائرة الكمومية
يحتوي الهاميلتوني على التعريف الكمومي للمسألة. يمكنك الآن إنشاء دائرة كمومية تساعد في أخذ عينات جيدة من الحلول عبر الحاسوب الكمومي. تستلهم خوارزمية QAOA من التلدين الكمومي وتطبّق طبقات متناوبة من العوامل في الدائرة الكمومية.
الفكرة العامة هي البدء من الحالة الأساسية لنظام معروف، المذكور أعلاه، ثم توجيه النظام نحو الحالة الأساسية لعامل التكلفة المطلوب. يتم ذلك بتطبيق العوامل و بزوايا و.
الدائرة الكمومية التي ستنشئها ذات معاملات بـ و، مما يتيح تجربة قيم مختلفة لـ و وأخذ عينات من الحالة الناتجة.
في هذه الحالة، ستجرب مثالاً بطبقة QAOA واحدة تحتوي على معاملين: و.
circuit = QAOAAnsatz(cost_operator=cost_hamiltonian, reps=2)
circuit.measure_all()
circuit.draw("mpl")

circuit.parameters
ParameterView([ParameterVectorElement(β[0]), ParameterVectorElement(β[1]), ParameterVectorElement(γ[0]), ParameterVectorElement(γ[1])])
الخطوة 2: تحسين المسألة لتنفيذها على الأجهزة الكمومية
تحتوي الدائرة أعلاه على سلسلة من التجريدات المفيدة للتفكير في الخوارزميات الكمومية، غير أنه لا يمكن تشغيلها مباشرةً على الأجهزة. لتتمكن من التشغيل على وحدة معالجة كمومية QPU، يجب أن تخضع الدائرة لسلسلة من العمليات التي تشكّل خطوة التحويل البرمجي أو تحسين الدائرة في النمط.
توفر مكتبة Qiskit سلسلة من ممرات التحويل البرمجي التي تلبي نطاقاً واسعاً من تحويلات الدوائر. تحتاج إلى التأكد من أن دائرتك محسَّ نة لغرضك المحدد.
قد ينطوي التحويل البرمجي على عدة خطوات، منها:
- التعيين الأولي للكيوبتات في الدائرة (كمتغيرات القرار) على الكيوبتات المادية في الجهاز.
- فك التسلسل للتعليمات في الدائرة الكمومية إلى تعليمات أصيلة للأجهزة يستطيع المعالج تنفيذها.
- التوجيه لأي كيوبتات في الدائرة تتفاعل مع كيوبتات مادية متجاورة.
- قمع الأخطاء بإضافة بوابات أحادية الكيوبت لقمع الضوضاء باستخدام فك الإقران الديناميكي.
مزيد من المعلومات حول التحويل البرمجي متاح في التوثيق.
يحوّل الكود التالي الدائرة المجردة ويحسّنها إلى صيغة جاهزة للتنفيذ على أحد الأجهزة المتاحة عبر السحابة باستخدام خدمة Qiskit IBM Runtime.
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)
print(backend)
# Create pass manager for transpilation
pm = generate_preset_pass_manager(optimization_level=3, backend=backend)
candidate_circuit = pm.run(circuit)
candidate_circuit.draw("mpl", fold=False, idle_wires=False)
<IBMBackend('test_heron_pok_1')>

الخطوة 3: التنفيذ باستخدام عوامل Qiskit الأولية
في سير عمل QAOA، تُحدَّد معاملات QAOA المثلى في حلقة تحسين تكرارية، تُشغّل سلسلة من تقييمات الدائرة وتستخدم محسّناً كلاسيكياً للعثور على المعاملات المثلى و. تُنفَّذ هذه الحلقة التنفيذية عبر الخطوات التالية:
- تحديد المعاملات الأولية
- إنشاء
Sessionجديدة تحتوي على حلقة التحسين والعامل الأولي المستخدم لأخذ عينات من الدائرة - بعد العثور على المجموعة المثلى من المعاملات، تنفيذ الدائرة مرة نهائية للحصول على التوزيع الأخير الذي سيُستخدم في خطوة ما بعد المعالجة.
تحديد الدائرة بالمعاملات الأولية
نبدأ بمعاملات مختارة بشكل اعتباطي.
initial_gamma = np.pi
initial_beta = np.pi / 2
init_params = [initial_beta, initial_beta, initial_gamma, initial_gamma]
تحديد المعالج الخلفي وعامل التنفيذ الأولي
استخدم عوامل Qiskit Runtime الأولية للتفاعل مع معالجات IBM®. العاملان الأوليان هما Sampler وEstimator، ويعتمد الاختيار بينهما على نوع القياس الذي تريد إجراءه على الحاسوب الكمومي. لتقليل ، استخدم Estimator إذ إن قياس دالة التكلفة ي عادل ببساطة القيمة المتوقعة لـ .
التشغيل
يوفر العاملان الأوليان مجموعة متنوعة من أوضاع التنفيذ لجدولة أحمال العمل على الأجهزة الكمومية، ويعمل سير عمل QAOA بشكل تكراري ضمن جلسة.

يمكنك توصيل دالة التكلفة المبنية على Sampler بروتين التقليل الخاص بـ SciPy للعثور على المعاملات المثلى.
def cost_func_estimator(params, ansatz, hamiltonian, estimator):
# transform the observable defined on virtual qubits to
# an observable defined on all physical qubits
isa_hamiltonian = hamiltonian.apply_layout(ansatz.layout)
pub = (ansatz, isa_hamiltonian, params)
job = estimator.run([pub])
results = job.result()[0]
cost = results.data.evs
objective_func_vals.append(cost)
return cost
objective_func_vals = [] # Global variable
with Session(backend=backend) as session:
# If using qiskit-ibm-runtime<0.24.0, change `mode=` to `session=`
estimator = Estimator(mode=session)
estimator.options.default_shots = 1000
# Set simple error suppression/mitigation options
estimator.options.dynamical_decoupling.enable = True
estimator.options.dynamical_decoupling.sequence_type = "XY4"
estimator.options.twirling.enable_gates = True
estimator.options.twirling.num_randomizations = "auto"
result = minimize(
cost_func_estimator,
init_params,
args=(candidate_circuit, cost_hamiltonian, estimator),
method="COBYLA",
tol=1e-2,
)
print(result)
message: Return from COBYLA because the trust region radius reaches its lower bound.
success: True
status: 0
fun: -1.6295230263157894
x: [ 1.530e+00 1.439e+00 4.071e+00 4.434e+00]
nfev: 26
maxcv: 0.0
تمكّن المحسّن من تقليل التكلفة والعثور على معاملات أفضل للدائرة.
plt.figure(figsize=(12, 6))
plt.plot(objective_func_vals)
plt.xlabel("Iteration")
plt.ylabel("Cost")
plt.show()