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

البدء مع التجميع الكمي التقريبي باستخدام شبكات الموترات (AQC-Tensor)

إصدارات الحزم

تم تطوير الكود في هذه الصفحة باستخدام المتطلبات التالية. نوصي باستخدام هذه الإصدارات أو أحدث منها.

qiskit[all]~=2.3.0
qiskit-aer~=0.17
qiskit-addon-utils~=0.3.0
qiskit-addon-aqc-tensor[aer,quimb-jax]~=0.2.0; sys.platform != 'darwin'
scipy~=1.16.3

يوضّح هذا الدليل مثالاً عملياً بسيطاً للبدء مع AQC-Tensor. في هذا المثال، ستأخذ دائرة تروتر التي تحاكي تطور نموذج إيزينغ ذي المجال المستعرض، وتستخدم طريقة AQC-Tensor لتقليل عمق الدائرة الناتجة. بالإضافة إلى ذلك، يتطلب هذا المثال حزمة qiskit-addon-utils لتوليد المسألة، وqiskit-aer لمحاكاة شبكة الموترات، وscipy لتحسين المعاملات.

للبدء، تذكّر أن هاميلتوني نموذج إيزينغ ذي المجال المستعرض يأخذ الشكل

HIsing=i=1NJi,(i+1)ZiZi+1+hiXi\mathcal{H}_{Ising} = \sum_{i=1}^N J_{i,(i+1)}Z_iZ_{i+1} + h_i X_i

حيث نفترض شروط حدودية دورية تعني أنه عند i=10i=10 نحصل على i+1=111i+1=11\rightarrow 1، وJJ هي قوة الاقتران بين موقعين، وhh هي شدة المجال المغناطيسي الخارجي.

يولّد مقطع الكود التالي هاميلتوني سلسلة إيزينغ المكوّنة من 10 مواقع مع شروط حدودية دورية.

# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-addon-aqc-tensor qiskit-addon-utils qiskit-aer scipy
from qiskit.transpiler import CouplingMap
from qiskit_addon_utils.problem_generators import generate_xyz_hamiltonian
from qiskit.synthesis import SuzukiTrotter
from qiskit_addon_utils.problem_generators import (
generate_time_evolution_circuit,
)
from qiskit_addon_aqc_tensor import generate_ansatz_from_circuit
from qiskit_addon_aqc_tensor.simulation import tensornetwork_from_circuit
from qiskit_addon_aqc_tensor.simulation import compute_overlap
from qiskit_addon_aqc_tensor.objective import MaximizeStateFidelity
from qiskit_aer import AerSimulator
from scipy.optimize import OptimizeResult, minimize

# Generate some coupling map to use for this example
coupling_map = CouplingMap.from_heavy_hex(3, bidirectional=False)

# Choose a 10-qubit circle on this coupling map
reduced_coupling_map = coupling_map.reduce(
[0, 13, 1, 14, 10, 16, 4, 15, 3, 9]
)

# Get a qubit operator describing the Ising field model
hamiltonian = generate_xyz_hamiltonian(
reduced_coupling_map,
coupling_constants=(0.0, 0.0, 1.0),
ext_magnetic_field=(0.4, 0.0, 0.0),
)

تقسيم تطور الزمن إلى جزأين للتنفيذ الكلاسيكي والكمي

الهدف العام من هذا المثال هو محاكاة التطور الزمني لهاميلتوني النموذج. نقوم بذلك هنا عبر تطور تروتر، الذي سيُقسَّم إلى جزأين.

  1. جزء أولي قابل للمحاكاة باستخدام حالات حاصل ضرب المصفوفات (MPS). هذا هو الجزء الذي سيُجمَّع باستخدام AQC-Tensor.
  2. جزء لاحق سيُنفَّذ على أجهزة الكم.

سنختار تطوير النظام حتى الزمن tf=5t_f=5 واستخدام AQC-Tensor لضغط التطور الزمني حتى الزمن t=4t=4، ثم نتابع التطور باستخدام خطوات تروتر العادية حتى tft_f.

من هنا، سنولّد دائرتين: الأولى ستُضغط باستخدام AQC-Tensor والثانية ستُنفَّذ على وحدة معالجة كمومية (QPU). بالنسبة للدائرة الأولى، وبما أنها ستُحاكى كلاسيكياً باستخدام حالات حاصل ضرب المصفوفات، سنستخدم عدداً سخياً من الطبقات لتقليل خطأ تروتر. أما الدائرة الثانية التي تحاكي التطور الزمني من ti=4t_i=4 إلى tf=5t_f=5 فستستخدم طبقات أقل بكثير لتقليل العمق.

# Generate circuit to be compressed
aqc_evolution_time = 4.0
aqc_target_num_trotter_steps = 45

aqc_target_circuit = generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=aqc_target_num_trotter_steps),
time=aqc_evolution_time,
)

# Generate circuit to execute on hardware
subsequent_evolution_time = 1.0
subsequent_num_trotter_steps = 5

subsequent_circuit = generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=subsequent_num_trotter_steps),
time=subsequent_evolution_time,
)

لأغراض المقارنة، سنولّد أيضاً دائرة ثالثة؛ وهي دائرة تتطور حتى t=4t=4، لكن بنفس عدد طبقات الدائرة الثانية التي تتطور من ti=4t_i=4 إلى tf=5t_f=5. هذه هي الدائرة التي كنّا سنستخدمها لو لم نلجأ إلى تقنية AQC-Tensor. سنسميها دائرة المقارنة في الوقت الحالي.

aqc_comparison_num_trotter_steps = int(
subsequent_num_trotter_steps
/ subsequent_evolution_time
* aqc_evolution_time
)
aqc_comparison_num_trotter_steps

comparison_circuit = generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=aqc_comparison_num_trotter_steps),
time=aqc_evolution_time,
)

توليد الأنساتز وبناء محاكاة MPS

بعد ذلك سنولّد الأنساتز الذي سنحسّنه. سيتطور حتى نفس زمن التطور للدائرة الأولى (من ti=0t_i=0 إلى tf=4t_f=4)، لكن بعدد أقل من خطوات تروتر.

بمجرد توليد الدائرة، نمرّرها إلى دالة generate_ansatz_from_circuit() في AQC-Tensor، التي تحلّل ترابط الكيوبتات ثنائية وتُرجع شيئين: أولاً دائرة أنساتز مولَّدة بنفس ترابط الكيوبتات ثنائية، وثانياً مجموعة من المعاملات التي عند إدخالها في الأنساتز تُنتج الدائرة المُدخلة.

aqc_ansatz_num_trotter_steps = 5

aqc_good_circuit = generate_time_evolution_circuit(
hamiltonian,
synthesis=SuzukiTrotter(reps=aqc_ansatz_num_trotter_steps),
time=aqc_evolution_time,
)

aqc_ansatz, aqc_initial_parameters = generate_ansatz_from_circuit(
aqc_good_circuit, qubits_initially_zero=True
)
aqc_ansatz.draw("mpl", fold=-1)

Output of the previous code cell

بعد ذلك سنبني تمثيل MPS للحالة التي سيقرّبها AQC. كما سنحسب الإخلاص ψ1ψ22|\langle\psi_1 | \psi_2 \rangle |^2 بين الحالة التي تُعدّها دائرة المقارنة والدائرة التي تولّد الحالة المستهدفة (التي استخدمت خطوات تروتر أكثر).

# Generate MPS simulator settings and obtain the MPS representation of the target state
simulator_settings = AerSimulator(
method="matrix_product_state",
matrix_product_state_max_bond_dimension=100,
)
aqc_target_mps = tensornetwork_from_circuit(
aqc_target_circuit, simulator_settings
)

# Compute the fidelity between the MPS representation of the target state and the state produced by the comparison circuit
comparison_mps = tensornetwork_from_circuit(
comparison_circuit, simulator_settings
)
comparison_fidelity = (
abs(compute_overlap(comparison_mps, aqc_target_mps)) ** 2
)
print(f"Comparison fidelity: {comparison_fidelity}")
Comparison fidelity: 0.9997111919739693

تحسين معاملات الأنساتز باستخدام MPS

أخيراً، سنحسّن دائرة الأنساتز بحيث تُنتج الحالة المستهدفة بإخلاص أعلى مما ستُنتجه comparison_fidelity. دالة التكلفة التي سنقلّلها هي MaximizeStateFidelity وسيتم تحسينها باستخدام محسّن L-BFGS من scipy.

objective = MaximizeStateFidelity(
aqc_target_mps, aqc_ansatz, simulator_settings
)

stopping_point = 1 - comparison_fidelity

def callback(intermediate_result: OptimizeResult):
print(f"Intermediate result: Fidelity {1 - intermediate_result.fun:.8}")
if intermediate_result.fun < stopping_point:
# Good enough for now
raise StopIteration

result = minimize(
objective,
aqc_initial_parameters,
method="L-BFGS-B",
jac=True,
options={"maxiter": 100},
callback=callback,
)
if (
result.status
not in (
0,
1,
99,
)
): # 0 => success; 1 => max iterations reached; 99 => early termination via StopIteration
raise RuntimeError(
f"Optimization failed: {result.message} (status={result.status})"
)

print(f"Done after {result.nit} iterations.")
aqc_final_parameters = result.x
Intermediate result: Fidelity 0.95084365
Intermediate result: Fidelity 0.98409893
Intermediate result: Fidelity 0.99142033
Intermediate result: Fidelity 0.99521405
Intermediate result: Fidelity 0.99566673
Intermediate result: Fidelity 0.99650054
Intermediate result: Fidelity 0.99683487
Intermediate result: Fidelity 0.99720426
Intermediate result: Fidelity 0.99761726
Intermediate result: Fidelity 0.99809073
Intermediate result: Fidelity 0.99838244
Intermediate result: Fidelity 0.99861841
Intermediate result: Fidelity 0.99874617
Intermediate result: Fidelity 0.99892696
Intermediate result: Fidelity 0.99908129
Intermediate result: Fidelity 0.99917737
Intermediate result: Fidelity 0.99925456
Intermediate result: Fidelity 0.99933134
Intermediate result: Fidelity 0.99947173
Intermediate result: Fidelity 0.99956469
Intermediate result: Fidelity 0.99964488
Intermediate result: Fidelity 0.99967419
Intermediate result: Fidelity 0.99968821
Intermediate result: Fidelity 0.9997448
Done after 24 iterations.

عند هذه النقطة، لدينا مجموعة من المعاملات التي تولّد الحالة المستهدفة بإخلاص أعلى مما كانت ستُنتجه دائرة المقارنة دون استخدام AQC. بهذه المعاملات المثلى، تمتلك الدائرة المضغوطة الآن خطأ تروتر أقل وعمقاً أقل من الدائرة الأصلية.

كخطوة أخيرة، يبني مقطع الكود التالي دائرة التطور الزمني الكاملة التي يمكن تمريرها إلى خط أنابيب المحوّل وتنفيذها على أجهزة الكم.

final_circuit = aqc_ansatz.assign_parameters(aqc_final_parameters)
final_circuit.compose(subsequent_circuit, inplace=True)
final_circuit.draw("mpl", fold=-1)

Output of the previous code cell

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