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

ترميز البيانات

المقدمة والترميز

لاستخدام خوارزمية كمومية، يجب إدخال البيانات الكلاسيكية بطريقة ما إلى دائرة كمومية. يُشار إلى هذا عادةً بـترميز البيانات، وقد يُسمى أيضاً تحميل البيانات. تذكّر من الدروس السابقة مفهوم تعيين الميزات (feature mapping)، وهو تعيين ميزات البيانات من فضاء إلى آخر. مجرد نقل البيانات الكلاسيكية إلى حاسوب كمومي هو نوع من التعيين، ويمكن تسميته تعيين ميزات. من الناحية العملية، تتضمن تعيينات الميزات المدمجة في Qiskit (مثل z_Feature Map وZZ Feature Map) عادةً طبقات دوران وطبقات تشابك تمتد بالحالة إلى أبعاد عديدة في فضاء هيلبرت. تُعدّ عملية الترميز هذه جزءاً محورياً من خوارزميات تعلّم الآلة الكمومي وتؤثر مباشرةً في قدراتها الحسابية.

بعض أساليب الترميز التالية يمكن محاكاتها كلاسيكياً بكفاءة؛ ويتضح ذلك جلياً في أساليب الترميز التي تُنتج حالات جداء (أي أنها لا تُشابك الكيوبتات). وتذكّر أن الفائدة الكمومية تكمن على الأرجح في المواضع التي يتطابق فيها التعقيد الكمومي للبيانات مع أسلوب الترميز. لذا من المرجح جداً أن تنتهي إلى كتابة دوائر ترميز خاصة بك. نعرض هنا مجموعة واسعة من استراتيجيات الترميز الممكنة لمقارنتها وفهم الفوارق بينها، والاطلاع على ما هو متاح. ثمة تصريحات عامة يمكن إطلاقها حول مدى فائدة أساليب الترميز. مثلاً، efficient_su2 (انظر أدناه) مع مخطط تشابك كامل أكثر احتمالاً لالتقاط الميزات الكمومية للبيانات مقارنةً بالأساليب التي تُنتج حالات جداء (مثل z_feature_map). لكن هذا لا يعني أن efficient_su2 كافٍ أو متلاءم بما يكفي مع بياناتك لتحقيق تسريع كمومي، إذ يستلزم ذلك دراسة متأنية لبنية البيانات المُنمذَجة أو المُصنَّفة. كما أن ثمة موازنة مع عمق الدائرة، فكثير من تعيينات الميزات التي تُشابك الكيوبتات بالكامل تُنتج دوائر عميقة جداً يتعذّر الحصول منها على نتائج قابلة للاستخدام على أجهزة الكمبيوتر الكمومية الحالية.

الترميز الرياضي

مجموعة البيانات هي مجموعة من MM متجهات بيانات: X={x(j)j[M]}\text{X} = \{\vec{x}^{(j)}\,|\,j\in [M]\}، حيث كل متجه ذو NN بُعداً، أي x(j)=(x1(j),,xN(j))RN\vec{x}^{(j)}=(\vec{x}^{(j)}_1,\ldots,\vec{x}^{(j)}_N)\in\mathbb{R}^N. يمكن تعميم هذا ليشمل ميزات البيانات المركّبة. في هذا الدرس، قد نستخدم أحياناً هذه الرموز للمجموعة الكاملة (X)(\text{X}) وعناصرها المحددة مثل x(j)\vec{x}^{(j)}. لكننا سنتحدث في معظم الأحيان عن تحميل متجه واحد من مجموعة البيانات في كل مرة، وكثيراً ما سنشير فقط إلى متجه واحد مؤلف من NN ميزة على شكل x\vec{x}.

علاوةً على ذلك، يشيع استخدام الرمز Φ(x)\Phi(\vec{x}) للإشارة إلى تعيين الميزات Φ\Phi للمتجه x\vec{x}. وفي الحوسبة الكمومية تحديداً، يشيع الإشارة إلى التعيينات باستخدام U(x)U(\vec{x})، وهو ترميز يُبرز الطابع الأحادي لهذه العمليات. يمكن استخدام الرمز نفسه لكليهما بصورة صحيحة؛ فكلاهما تعيين ميزات. في هذه الدورة، نميل إلى استخدام:

  • Φ(x)\Phi(\vec{x}) عند الحديث عن تعيينات الميزات في تعلّم الآلة بشكل عام، و
  • U(x)U(\vec{x}) عند الحديث عن التطبيقات الدائرية لتعيينات الميزات.

التوحيد القياسي وفقدان المعلومات

في تعلّم الآلة الكلاسيكي، كثيراً ما تُوحَّد قياسياً ميزات بيانات التدريب أو تُعاد ضبطها، مما يُحسّن أداء النموذج في الغالب. من أشيع طرق ذلك التوحيد القياسي بالحد الأدنى والأقصى (min-max normalization) أو التوحيد القياسي الإحصائي (standardization). في التوحيد بالحد الأدنى والأقصى، تُوحَّد أعمدة الميزات في مصفوفة البيانات X\text{X} (مثلاً الميزة kk) على النحو التالي:

xk(i)=xk(i)min{xk(j)x(j)[X]}max{xk(j)x(j)[X]}min{xk(j)x(j)[X]}x^{'(i)}_k = \frac{x^{(i)}_k - \text{min}\{x^{(j)}_k\,|\,\vec{x}^{(j)}\in [\text{X}]\}}{\text{max}\{x^{(j)}_k\,|\,\vec{x}^{(j)}\in [\text{X}]\}-\text{min}\{x^{(j)}_k\,|\,\vec{x}^{(j)}\in [\text{X}]\}}

حيث تشير min وmax إلى الحد الأدنى والأقصى للميزة kk عبر MM متجهات البيانات في مجموعة البيانات X\text{X}. تقع جميع قيم الميزات بعدها في الفترة الوحدوية: xk(i)[0,1]x^{'(i)}_k \in [0,1] لكل i[M]i\in [M], k[N]k\in[N].

التوحيد القياسي مفهوم أساسي أيضاً في ميكانيكا الكم والحوسبة الكمومية، لكنه يختلف قليلاً عن التوحيد بالحد الأدنى والأقصى. يشترط التوحيد في ميكانيكا الكم أن يكون طول (في سياق الحوسبة الكمومية، المعيار-2) متجه الحالة ψ|\psi\rangle مساوياً للوحدة: ψ=ψψ=1\|\psi\|=\sqrt{\langle\psi|\psi\rangle} = 1، مما يضمن أن مجموع احتمالات القياس يساوي 1. تُوحَّد الحالة بالقسمة على المعيار-2، أي بإعادة الضبط:

ψψ1ψ|\psi\rangle\rightarrow\|\psi\|^{-1}|\psi\rangle

في الحوسبة الكمومية وميكانيكا الكم، هذا ليس توحيداً يفرضه الناس على البيانات، بل خاصية أساسية لحالات الكم. اعتماداً على مخطط الترميز لديك، قد يؤثر هذا القيد على طريقة إعادة ضبط بياناتك. مثلاً، في الترميز بالسعة (انظر أدناه)، يُوحَّد متجه البيانات x(j)=1\vert\vec{x}^{(j)}\vert = 1 كما تقتضي ميكانيكا الكم، وهذا يؤثر في ضبط البيانات المُرمَّزة. أما في الترميز بالطور، فيُوصى بإعادة ضبط قيم الميزات بحيث xi(j)(0,2π]\vec{x}^{(j)}_i \in (0,2\pi] لتجنب فقدان المعلومات الناجم عن تأثير modulo-2π2\pi عند الترميز على زاوية طور الكيوبت[1,2].

أساليب الترميز

في الأقسام القليلة التالية، سنشير إلى مجموعة بيانات كلاسيكية مثالية صغيرة Xex\text{X}_\text{ex} تتألف من M=5M=5 متجهات بيانات، لكل منها N=3N=3 ميزات:

Xex={(4,8,5),(9,8,6),(2,9,2),(5,7,0),(3,7,5)}\text{X}_{\text{ex}}=\{(4,8,5),(9,8,6),(2,9,2),(5,7,0),(3,7,5)\}

بالترميز المقدَّم أعلاه، نقول مثلاً إن الميزة 1st1^\text{st} للمتجه الرابع 4th4^\text{th} في مجموعتنا Xex\text{X}_{\text{ex}} هي x1(4)=5\vec{x}^{(4)}_1 = 5.

الترميز بالأساس

يُرمَّز في الترميز بالأساس سلسلة بتات كلاسيكية مؤلفة من PP بت في حالة أساس حسابية لنظام مؤلف من PP كيوبت. خذ مثلاً x3(1)=5=0(23)+1(22)+0(21)+1(20)\vec{x}^{(1)}_3 = 5 = 0(2^3)+1(2^2)+0(2^1)+1(2^0). يمكن تمثيل هذا كسلسلة مؤلفة من 44 بتات على النحو (0101)(0101)، وبنظام مؤلف من 44 كيوبتات كحالة كمومية 0101|0101\rangle. بشكل عام، لسلسلة بتات مؤلفة من PP بت: xk(j)=(b1,b2,...,bP)\vec{x}^{(j)}_k = (b_1, b_2, ... , b_P)، تكون الحالة المقابلة لـPP كيوبت هي xk(j)=b1,b2,...,bP|x^{(j)}_k\rangle = | b_1, b_2, ... , b_P \rangle مع bn{0,1}b_n \in \{0,1\} لـn=1,,Pn = 1 , \dots , P. لاحظ أن هذا لميزة واحدة فقط.

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

كمثال، لنرمّز المتجه (5, 7, 0).

لنفترض أن جميع الميزات مخزَّنة في أربعة بتات (أكثر مما نحتاج، لكن كافٍ لتمثيل أي عدد صحيح أحادي الرقم بالأساس 10):

5 → binary 0101

7 → binary 0111

0 → binary 0000

تُعيَّن سلاسل البتات هذه إلى ثلاث مجموعات من أربعة كيوبتات، فتكون حالة الأساس الكلية لـ12 كيوبتاً:

010101110000∣0101 0111 0000⟩

هنا، تمثّل الكيوبتات الأربع الأولى الميزة الأولى، والأربع التالية الميزة الثانية، والأربع الأخيرة الميزة الثالثة. يُحوِّل الكود التالي متجه البيانات (5,7,0) إلى حالة كمومية، وهو مُعمَّم للقيام بذلك مع ميزات أحادية الرقم أخرى.

# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit
from qiskit import QuantumCircuit

# Data point to encode
x = 5 # binary: 0101
y = 7 # binary: 0111
z = 0 # binary: 0000

# Convert each to 4-bit binary list
x_bits = [int(b) for b in format(x, "04b")] # [0,1,0,1]
y_bits = [int(b) for b in format(y, "04b")] # [0,1,1,1]
z_bits = [int(b) for b in format(z, "04b")] # [0,0,0,0]

# Combine all bits
all_bits = x_bits + y_bits + z_bits # [0,1,0,1,0,1,1,1,0,0,0,0]

# Initialize a 12-qubit quantum circuit
qc = QuantumCircuit(12)

# Apply x-gates where the bit is 1
for idx, bit in enumerate(all_bits):
if bit == 1:
qc.x(idx)

qc.draw("mpl")
import math
from qiskit import QuantumCircuit

# Data point to encode
x = 4 # binary: 0100
y = 8 # binary: 1000
z = 5 # binary: 0101

# Convert each to 4-bit binary list
x_bits = [int(b) for b in format(x, '04b')] # [0,1,0,0]
y_bits = [int(b) for b in format(y, '04b')] # [1,0,0,0]
z_bits = [int(b) for b in format(z, '04b')] # [0,1,0,1]

# Combine all bits
all_bits = x_bits + y_bits + z_bits # [0,1,0,0,1,0,0,0,0,1,0,1]

# Initialize a 12-qubit quantum circuit
qc = QuantumCircuit(12)

# Apply x-gates where the bit is 1
for idx, bit in enumerate(all_bits):
if bit == 1:
qc.x(idx)

qc.draw('mpl')

Output of the previous code cell

تحقق من فهمك

اقرأ السؤال أدناه، فكّر في إجابتك، ثم انقر على المثلث للكشف عن الحل.

اكتب كوداً لترميز المتجه الأول في مجموعة البيانات المثالية Xex\text{X}_{\text{ex}}:

x(1)=(4,8,5)\vec{x}^{(1)}=(4,8,5)

باستخدام الترميز بالأساس.

الإجابة:

import math

desired_state = [
1 / math.sqrt(105) * 4,
1 / math.sqrt(105) * 8,
1 / math.sqrt(105) * 5,
1 / math.sqrt(105) * 0,
]

qc = QuantumCircuit(2)
qc.initialize(desired_state, [0, 1])

qc.decompose(reps=5).draw(output="mpl")

الترميز بالسعة

الترميز بالسعة يُشفِّر البيانات في سعات (amplitudes) الحالة الكمومية. فهو يُمثِّل متجهَ بيانات كلاسيكيًا مُعيَّنًا بُعده NN، وهو x(j)\vec{x}^{(j)}، على شكل سعات لحالة كمومية مكوَّنة من nn كيوبت، ψx|\psi_x\rangle:

ψx(j)=1αi=1Nxi(j)i|\psi^{(j)}_x\rangle = \frac{1}{\alpha}\sum_{i=1}^N x^{(j)}_i |i\rangle

حيث NN هو نفس بُعد متجهات البيانات المذكورة سابقًا، وxi(j)\vec{x}^{(j)}_i هو العنصر ithi^{th} في x(j)\vec{x}^{(j)}، وi|i\rangle هو حالة الأساس الحسابية ithi^{th}. أما α\alpha فهو ثابت التسوية (normalization constant) الذي يُحدَّد من البيانات المُشفَّرة. وهذا هو شرط التسوية الذي تفرضه ميكانيكا الكم:

i=1Nxi(j)2=α2.\sum_{i=1}^N \left|x^{(j)}_i\right|^2 = \left|\alpha\right|^2.

بشكل عام، هذا الشرط يختلف عن تسوية min/max المُستخدمة لكل ميزة عبر جميع متجهات البيانات. وكيفية التعامل مع هذا الاختلاف تعتمد على المسألة التي تعمل عليها، لكن لا مفر من شرط التسوية الكمومية أعلاه.

في الترميز بالسعة، كل ميزة في متجه البيانات تُخزَّن كسعة لحالة كمومية مختلفة. وبما أن نظامًا من nn كيوبت يوفر 2n2^n سعة، فإن ترميز NN ميزة بالسعة يتطلب nlog2(N)n \ge \mathrm{log}_2(N) كيوبت.

كمثال، لنُشفِّر المتجه الأول في مجموعة بياناتنا Xex\text{X}_\text{ex}، وهو x(1)=(4,8,5)\vec{x}^{(1)} = (4,8,5)، باستخدام الترميز بالسعة. بعد تسوية المتجه الناتج، نحصل على:

i=1Nxi(1)2=42+82+52=105=α2α=105\sum_{i=1}^N \left|x^{(1)}_i\right|^2 = 4^2+8^2+5^2 = 105 = \left|\alpha\right|^2 \rightarrow \alpha = \sqrt{105}

والحالة الكمومية المكوَّنة من كيوبتين الناتجة ستكون:

ψ(x(1))=1105(400+801+510+011)|\psi(\vec{x}^{(1)})\rangle = \frac{1}{\sqrt{105}}(4|00\rangle+8|01\rangle+5|10\rangle+0|11\rangle)

في المثال أعلاه، عدد الميزات في المتجه N=3N=3 ليس قوة للعدد 2. حين لا يكون NN قوة للعدد 2، نختار ببساطة قيمة لعدد الكيوبتات nn بحيث 2nN2^n\geq N، ونملأ متجه السعة بثوابت غير معلوماتية (هنا، صفر).

كما في الترميز الأساسي، بمجرد حساب الحالة التي ستُشفِّر مجموعة بياناتنا، يمكننا في Qiskit استخدام دالة initialize لتهيئتها:

desired_state = [
9 / math.sqrt(270),
8 / math.sqrt(270),
6 / math.sqrt(270),
2 / math.sqrt(270),
9 / math.sqrt(270),
2 / math.sqrt(270),
0,
0,
]

print(desired_state)

qc = QuantumCircuit(3)
qc.initialize(desired_state, [0, 1, 2])
qc.decompose(reps=8).draw(output="mpl")

Output of the previous code cell

ميزة الترميز بالسعة هي الاكتفاء بـlog2(N)\mathrm{log}_2(N) كيوبت فقط كما ذُكر سابقًا. غير أن الخوارزميات اللاحقة يجب أن تعمل على سعات الحالة الكمومية، وطرق تهيئة الحالات الكمومية وقياسها لا تكون عادةً ذات كفاءة عالية.

اختبر فهمك

اقرأ الأسئلة أدناه، فكِّر في إجاباتك، ثم اضغط على المثلثات للكشف عن الحلول.

اكتب الحالة المُسوَّاة لترميز المتجه التالي (المكوَّن من متجهين من مجموعة بياناتنا):

x=(9,8,6,2,9,2)\vec{x}=(9,8,6,2,9,2)

باستخدام الترميز بالسعة.

الإجابة:

لترميز 6 أعداد، نحتاج إلى امتلاك 6 حالات على الأقل يمكننا ترميز السعات عليها. وهذا يتطلب 3 كيوبتات. باستخدام عامل تسوية غير معروف α\alpha، يمكننا كتابة ذلك على النحو التالي:

ψ=α(9000+8001+6010+2011+9100+2101+0110+0111)|\psi\rangle = \alpha(9|000\rangle+8|001\rangle+6|010\rangle+2|011\rangle+9|100\rangle+2|101\rangle+0|110\rangle+0|111\rangle)

لاحظ أن

ψψ=α2×(92+82+62+22+92+22+02+02)=α2×(270)=1α=1270\langle \psi|\psi\rangle = |\alpha|^2\times(9^2+8^2+6^2+2^2+9^2+2^2+0^2+0^2) = |\alpha|^2\times(270)=1 \rightarrow \alpha = \frac{1}{\sqrt{270}}

وأخيرًا،

ψ=1270(9000+8001+6010+2011+9100+2101+0110+0111)|\psi\rangle = \frac{1}{\sqrt{270}}(9|000\rangle+8|001\rangle+6|010\rangle+2|011\rangle+9|100\rangle+2|101\rangle+0|110\rangle+0|111\rangle)

لنفس متجه البيانات x=(9,8,6,2,9,2),\vec{x}=(9,8,6,2,9,2), اكتب كودًا لإنشاء دائرة تُحمِّل هذه الميزات باستخدام الترميز بالسعة.

الإجابة:

import numpy as np
from math import sqrt

init_list = [4, 8, 5, 9, 8, 6, 2, 9, 2, 5, 7, 0, 3, 7, 5]
qubits = round(np.log(len(init_list)) / np.log(2) + 0.4999999999)
need_length = 2**qubits
pad = need_length - len(init_list)
for i in range(0, pad):
init_list.append(0)

init_array = np.array(init_list) # Unnormalized data vector
length = sqrt(
sum(init_array[i] ** 2 for i in range(0, len(init_array)))
) # Vector length
norm_array = init_array / length # Normalized array
print("Normalized array:")
print(norm_array)
print()

qubit_numbers = []
for i in range(0, qubits):
qubit_numbers.append(i)
print(qubit_numbers)

qc = QuantumCircuit(qubits)
qc.initialize(norm_array, qubit_numbers)
qc.decompose(reps=7).draw(output="mpl")

[0.5477225575051662, 0.48686449556014766, 0.36514837167011077, 0.12171612389003691, 0.5477225575051662, 0.12171612389003691, 0, 0]

"Output of the previous code cell"

قد تحتاج إلى التعامل مع متّجهات بيانات كبيرة جدًا. تأمّل المتّجه التالي:

x=(4,8,5,9,8,6,2,9,2,5,7,0,3,7,5).\vec{x}=(4,8,5,9,8,6,2,9,2,5,7,0,3,7,5).

اكتب كودًا لأتمتة عملية التطبيع، وأنشئ دائرة كمومية لترميز السّعة.

الجواب:

هناك إجابات عديدة محتملة. إليك كودًا يطبع بعض الخطوات الوسيطة:

from qiskit.quantum_info import Statevector
from math import pi

qc = QuantumCircuit(1)
state1 = Statevector.from_instruction(qc)
qc.ry(pi / 2, 0) # Phase gate rotates by an angle pi/2
state2 = Statevector.from_instruction(qc)
states = state1, state2

المصفوفة بعد التطبيع: [0.17342199 0.34684399 0.21677749 0.39019949 0.34684399 0.26013299 0.086711 0.39019949 0.086711 0.21677749 0.30348849 0. 0.1300665 0.30348849 0.21677749 0. ]

[0, 1, 2, 3]

"Output of the previous code cell"

هل ترى مزايا لترميز السّعة مقارنةً بترميز الأساس؟ إن كان الأمر كذلك، فاشرح.

الجواب:

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

من مزايا ترميز السّعة أنّه لا يتطلّب سوى log2(N)\log_2(N) كيوبت لمتّجه بيانات ذي NN بُعدًا (NN ميزة) xx\vec{x}\rightarrow|\vec{x}\rangle. غير أنّ ترميز السّعة هو بشكل عام إجراءٌ غير كفء يستلزم تحضير حالة اعتباطية، وهو ما يكون أسيًّا في عدد بوابات CNOT. بعبارة أخرى، تتمتّع عملية تحضير الحالة بتعقيد زمني متعدّد الحدود يُقدَّر بـ O(N)\mathcal O(N) بالنسبة إلى عدد الأبعاد، حيث N=2nN = 2^n، وnn هو عدد الكيوبتات. يُتيح ترميز السّعة "توفيرًا أسيًّا في الفضاء على حساب زيادة أسيّة في الزمن"[3]؛ بيد أنّ تحقيق تعقيد زمني بمرتبة O(logN)\mathcal O(\log N) ممكن في حالات معيّنة[4]. ولتحقيق تسريع كمومي شامل من البداية حتى النهاية، يجب أخذ تعقيد زمن تحميل البيانات بعين الاعتبار.

ترميز الزاوية

يحظى ترميز الزاوية باهتمام واسع في كثير من نماذج QML التي تستخدم خرائط ميزات باولي، كآلات المتّجهات الداعمة الكمومية (QSVMs) والدوائر الكمومية التغايرية (VQCs) وغيرها. ويرتبط ترميز الزاوية ارتباطًا وثيقًا بترميز الطور وترميز الزاوية الكثيف اللذين سنعرضهما لاحقًا. سنستخدم هنا مصطلح "ترميز الزاوية" للإشارة إلى دوران في θ\theta، أي دوران بعيدًا عن محور zz، يتحقّق مثلًا ببوابة RXR_X أو بوابة RYR_Y[1,3]. في الواقع، يمكن ترميز البيانات في أيّ دوران أو مزيج من الدورانات، إلّا أنّ RYR_Y هي الأكثر شيوعًا في الأدبيات، لذا سنُركّز عليها هنا.

عند تطبيق ترميز الزاوية على كيوبت واحد، فإنّه يُضفي دورانًا حول محور Y يتناسب مع قيمة البيانات. تأمّل ترميز ميزة واحدة (الميزة رقم kk) من متّجه البيانات jj في مجموعة البيانات، xk(j)\vec{x}^{(j)}_k:

xk(j)=RY(θ=xk(j))0=cos(xk(j)2)0+sin(xk(j)2)1.|\vec{x}^{(j)}_k\rangle = R_Y(\theta=\vec{x}^{(j)}_k)|0\rangle = \textstyle\cos\left(\frac{\vec{x}^{(j)}_k}{2}\right)|0\rangle + \sin\left(\frac{\vec{x}^{(j)}_k}{2}\right)|1\rangle.

بدلًا من ذلك، يمكن إجراء ترميز الزاوية باستخدام بوابات RX(θ)R_X(\theta)، وإن كانت الحالة المُرمَّزة ستمتلك عندئذٍ طورًا نسبيًّا مركّبًا مقارنةً بـ RY(θ)R_Y(\theta).

يختلف ترميز الزاوية عن الطريقتين السابقتين من عدّة نواحٍ. في ترميز الزاوية:

  • تُربَط كل قيمة ميزة بكيوبت مقابل لها، xk(j)Qk\vec{x}^{(j)}_k \rightarrow Q_k، ممّا يُبقي الكيوبتات في حالة جداء.
  • يُرمَّز قيمة عددية واحدة في كل مرة، بدلًا من مجموعة ميزات كاملة من نقطة بيانات.
  • يتطلّب ترميز NN ميزة بيانات nn كيوبت، حيث nNn\leq N. وفي الغالب يتحقّق التساوي هنا. سنرى كيف يمكن أن يكون n<Nn<N في الأقسام القليلة التالية.
  • الدائرة الكمومية الناتجة تمتلك عمقًا ثابتًا (عادةً يكون العمق 1 قبل عملية التحويل).

تجعل الدائرة الكمومية ذات العمق الثابت ترميزَ الزاوية مناسبًا بشكل خاص للأجهزة الكمومية الحالية. ميزة إضافية أخرى لترميز بياناتنا باستخدام θ\theta (وتحديدًا، اختيارنا لترميز الزاوية حول محور Y) هي أنّه يُنشئ حالات كمومية ذات قيم حقيقية قد تكون مفيدة في بعض التطبيقات. في دوران محور Y، يُعيَّن ترميز البيانات بوّابة دوران حول محور Y مُعطاة بـ RY(θ)R_Y(\theta) بزاوية حقيقية θ(0,2π]\theta \in (0, 2\pi] (Qiskit RYGate). وكما هو الحال مع ترميز الطور (انظر أدناه)، نوصي بإعادة قياس البيانات بحيث xk(j)(0,2π]\vec{x}^{(j)}_k \in (0,2\pi]، تفاديًا لفقدان المعلومات وغيره من التأثيرات غير المرغوبة.

يُدوِّر كود Qiskit التالي كيوبتًا واحدًا من حالته الابتدائية 0|0\rangle لترميز قيمة البيانات xk(j)=12π\vec{x}^{(j)}_k=\frac{1}{2}\pi.

import numpy as np
from qiskit.visualization.bloch import Bloch
from qiskit.visualization.state_visualization import _bloch_multivector_data

def plot_Nstates(states, axis, plot_trace_points=True):
"""This function plots N states to 1 Bloch sphere"""
bloch_vecs = [_bloch_multivector_data(s)[0] for s in states]

if axis is None:
bloch_plot = Bloch()
else:
bloch_plot = Bloch(axes=axis)

bloch_plot.add_vectors(bloch_vecs)

if len(states) > 1:

def rgba_map(x, num):
g = (0.95 - 0.05) / (num - 1)
i = 0.95 - g * num
y = g * x + i
return (0.0, y, 0.0, 0.7)

num = len(states)
bloch_plot.vector_color = [rgba_map(x, num) for x in range(1, num + 1)]

bloch_plot.vector_width = 3
bloch_plot.vector_style = "simple"

if plot_trace_points:

def trace_points(bloch_vec1, bloch_vec2):
# bloch_vec = (x,y,z)
n_points = 15
thetas = np.arccos([bloch_vec1[2], bloch_vec2[2]])
phis = np.arctan2(
[bloch_vec1[1], bloch_vec2[1]], [bloch_vec1[0], bloch_vec2[0]]
)
if phis[1] < 0:
phis[1] = phis[1] + 2 * pi
angles0 = np.linspace(phis[0], phis[1], n_points)
angles1 = np.linspace(thetas[0], thetas[1], n_points)

xp = np.cos(angles0) * np.sin(angles1)
yp = np.sin(angles0) * np.sin(angles1)
zp = np.cos(angles1)
pnts = [xp, yp, zp]
bloch_plot.add_points(pnts)
bloch_plot.point_color = "k"
bloch_plot.point_size = [4] * len(bloch_plot.points)
bloch_plot.point_marker = ["o"]

for i in range(len(bloch_vecs) - 1):
trace_points(bloch_vecs[i], bloch_vecs[i + 1])

bloch_plot.sphere_alpha = 0.05
bloch_plot.frame_alpha = 0.15
bloch_plot.figsize = [4, 4]

bloch_plot.render()

plot_Nstates(states, axis=None, plot_trace_points=True)

سنُعرِّف دالة لتصوير تأثير العملية على متّجه الحالة. تفاصيل تعريف الدالة ليست مهمة، لكنّ القدرة على تصوير متّجهات الحالة وتغيّراتها أمرٌ بالغ الأهمية.

qc = QuantumCircuit(3)
qc.ry(0, 0)
qc.ry(2 * math.pi / 4, 1)
qc.ry(2 * math.pi / 2, 2)
qc.draw(output="mpl")

مخرجات خلية الكود السابقة

هذا كان مجرد ميزة واحدة من متجه بيانات واحد. عند ترميز NN ميزة في زوايا الدوران لـ nn كيوبت، لنقل للمتجه الـ jthj^\text{th} من البيانات x(j)=(x1,...,xN),\vec{x}^{(j)} = (x_1,...,x_N), سيبدو حالة الجداء المُرمَّزة هكذا:

x(j)=k=1Ncos(xk(j))0+sin(xk(j))1|\vec{x}^{(j)}\rangle = \bigotimes^N_{k=1} \cos(\vec{x}^{(j)}_k)|0\rangle + \sin(\vec{x}^{(j)}_k)|1\rangle

نلاحظ أن هذا مكافئ لـ

x(j)=k=1NRY(2xk(j))0.|\vec{x}^{(j)}\rangle = \bigotimes^N_{k=1} R_Y(2\vec{x}^{(j)}_k)|0\rangle.

تحقق من فهمك

اقرأ الأسئلة أدناه، فكّر في إجاباتك، ثم انقر على المثلثات للكشف عن الحلول.

رمّز متجه البيانات x=(0,π/4,π/2)\vec{x} = (0, \pi/4, \pi/2) باستخدام الترميز الزاوي كما هو موضح أعلاه.

الجواب:

qc = QuantumCircuit(1)
qc.h(0) # Hadamard gate rotates state down to Bloch equator
state1 = Statevector.from_instruction(qc)

qc.p(pi / 2, 0) # Phase gate rotates by an angle pi/2
state2 = Statevector.from_instruction(qc)

states = state1, state2

qc.draw("mpl", scale=1)

&quot;مخرجات خلية الكود السابقة&quot;

باستخدام الترميز الزاوي كما هو موضح أعلاه، كم عدد الكيوبتات المطلوبة لترميز 5 ميزات؟

الجواب: 5

الترميز بالطور

الترميز بالطور مشابه جداً للترميز الزاوي الموضح أعلاه. زاوية طور الكيوبت هي زاوية حقيقية القيمة ϕ\phi حول المحور zz من المحور +x+x. تُعيَّن البيانات باستخدام دوران الطور، P(ϕ)=eiϕ/2RZ(ϕ)P(\phi) = e^{i\phi/2}R_Z(\phi)، حيث ϕ(0,2π]\phi \in (0,2\pi] (راجع Qiskit PhaseGate لمزيد من المعلومات). يُنصح بإعادة تحجيم البيانات بحيث يكون xk(j)(0,2π]\vec{x}^{(j)}_k \in (0,2\pi]. هذا يمنع فقدان المعلومات وتأثيرات أخرى غير مرغوب فيها[1,2].

عادةً ما يُهيَّأ الكيوبت في الحالة 0|0\rangle، وهي حالة ذاتية لمؤثر دوران الطور، مما يعني أن حالة الكيوبت تحتاج أولاً إلى التدوير حتى يمكن تطبيق الترميز بالطور. لذلك من المنطقي تهيئة الحالة ببوابة هادامار: H0=+=12(0+1)H|0\rangle = |+\rangle = \textstyle\frac{1}{\sqrt{2}}(|0\rangle + |1\rangle). الترميز بالطور على كيوبت واحد يعني إضافة طور نسبي يتناسب مع قيمة البيانات:

xk(j)=P(ϕ=xk(j))+=12(0+eixk(j)1).|\vec{x}^{(j)}_k\rangle = P(\phi=\vec{x}^{(j)}_k)|+\rangle = \textstyle\frac{1}{\sqrt{2}}\big(|0\rangle + e^{i\vec{x}^{(j)}_k}|1\rangle\big).

تعيّن إجراءات الترميز بالطور كل قيمة ميزة إلى طور الكيوبت المقابل، xk(j)Qk\vec{x}^{(j)}_k \rightarrow Q_k. في المجمل، يمتلك الترميز بالطور عمق دائرة مقداره 2، بما في ذلك طبقة هادامار، مما يجعله مخطط ترميز فعّال. الحالة متعددة الكيوبتات المُرمَّزة بالطور (nn كيوبت لـ N=nN=n ميزة) هي حالة جداء:

x(j)=k=1NPk(ϕ=xk(j))+N=12Nk=1N(0+eixk(j)1).|\vec{x}^{(j)}\rangle = \bigotimes_{k=1}^{N} P_k(\phi = \vec{x}^{(j)}_k)|+\rangle^{\otimes N} = {\textstyle\frac{1}{\sqrt{2^N}}} \bigotimes_{k=1}^{N}\big(|0\rangle + e^{i\vec{x}^{(j)}_k}|1\rangle\big).

كود Qiskit التالي يُهيِّئ أولاً الحالة الابتدائية لكيوبت واحد بتدويره ببوابة هادامار، ثم يدوّره مجدداً باستخدام بوابة الطور لترميز ميزة البيانات xk(j)=12π\vec{x}^{(j)}_k=\frac{1}{2}\pi.

plot_Nstates(states, axis=None, plot_trace_points=True)

Output of the previous code cell

يمكننا تصور الدوران في ϕ\phi باستخدام دالة plot_Nstates التي عرّفناها.

phase_data = [4, 8, 5, 9, 8, 6, 2, 9, 2, 5, 7, 0]
qc = QuantumCircuit(len(phase_data))
for i in range(0, len(phase_data)):
qc.h(i)
qc.rz(phase_data[i] * 2 * math.pi / float(max(phase_data)), i)
qc.draw(output="mpl")

Output of the previous code cell

مخطط كرة بلوخ يُظهر دوران المحور Z على الشكل +P(12π)+|+\rangle \rightarrow P(\frac{1}{2}\pi)|+\rangle حيث xk(j)=12π\vec{x}^{(j)}_k=\frac{1}{2}\pi. يُشير السهم الأخضر الفاتح إلى الحالة النهائية.

يُستخدم الترميز الطوري في كثير من خرائط الميزات الكمومية، خاصةً خرائط الميزات ZZ وZZZZ، وخرائط ميزات باولي العامة، وغيرها.

تحقق من فهمك

اقرأ الأسئلة أدناه، فكّر في إجاباتك، ثم انقر على المثلثات لعرض الحلول.

كم عدد الكيوبتات المطلوبة لاستخدام الترميز الطوري كما هو موضح أعلاه لتخزين 8 ميزات؟

الجواب: 8

اكتب كوداً لترميز المتجه x(1)=(4,8,5,9,8,6,2,9,2,5,7,0)\vec{x}^{(1)}=(4,8,5,9,8,6,2,9,2,5,7,0) باستخدام الترميز الطوري.

الجواب:

قد تكون هناك إجابات متعددة. إليك مثال واحد:

qc = QuantumCircuit(1)
state1 = Statevector.from_instruction(qc)
qc.ry(3 * pi / 8, 0)
state2 = Statevector.from_instruction(qc)
qc.rz(7 * pi / 4, 0)
state3 = Statevector.from_instruction(qc)
states = state1, state2, state3

plot_Nstates(states, axis=None, plot_trace_points=True)

&quot;Output of the previous code cell&quot;

الترميز بالزاوية الكثيف

الترميز بالزاوية الكثيف (DAE) هو مزيج من الترميز بالزاوية والترميز الطوري. يتيح الترميز بالزاوية الكثيف ترميز قيمتَي ميزتين في كيوبت واحد: زاوية واحدة بدوران حول المحور Y، والأخرى بدوران حول المحور zz: xk(j),\vec{x}^{(j)}_k, x(j)θ,ϕ\vec{x}^{(j)}_\ell \rightarrow \theta, \phi. يُرمِّز الميزتين على النحو التالي:

xk(j),x(j)=RZ(ϕ=x(j))RY(θ=xk(j))0=cos(xk(j)2)0+eix(j)sin(xk(j)2)1.|\vec{x}^{(j)}_k,\vec{x}^{(j)}_\ell\rangle = R_Z(\phi=\vec{x}^{(j)}_\ell) R_Y(\theta=\vec{x}^{(j)}_k)|0\rangle = \cos\left(\frac{\vec{x}^{(j)}_k}{2}\right)|0\rangle + e^{i\vec{x}^{(j)}_\ell} \sin\left(\frac{\vec{x}^{(j)}_k}{2}\right)|1\rangle.

ترميز ميزتَين في كيوبت واحد يؤدي إلى تقليل عدد الكيوبتات المطلوبة للترميز بمقدار 2×2\times. وبتوسيع هذا ليشمل ميزات أكثر، يمكن ترميز متجه البيانات x=(x1,...,xN)\vec{x} = (x_1,...,x_N) على النحو التالي:

x=k=1N/2cos(x2k1)0+eix2ksin(x2k1)1|\vec{x}\rangle = \bigotimes_{k=1}^{N/2} \cos(x_{2k-1})|0\rangle + e^{i x_{2k}}\sin(x_{2k-1})|1\rangle

يمكن تعميم الترميز بالزاوية الكثيف ليشمل دوال عشوائية للميزتين بدلاً من الدوال المثلثية المستخدمة هنا، وهذا ما يُعرف بالترميز العام للكيوبت[7].

كمثال على الترميز بالزاوية الكثيف، يُرمِّز الكود أدناه ويُصوِّر ترميز الميزتين x1=θ=3π/8x_1=\theta = 3\pi/8 وx2=ϕ=7π/4x_2=\phi = 7\pi/4.

dense_data = [4, 8, 5, 9, 8, 6, 2, 9, 2, 5, 7, 0, 3, 7, 5, 0]
qc = QuantumCircuit(int(len(dense_data) / 2))
entry = 0
for i in range(0, int(len(dense_data) / 2)):
qc.ry(dense_data[entry] * 2 * math.pi / float(max(dense_data)), i)
entry = entry + 1
qc.rz(dense_data[entry] * 2 * math.pi / float(max(dense_data)), i)
entry = entry + 1
qc.draw(output="mpl")

Output of the previous code cell

تحقق من فهمك

اقرأ الأسئلة أدناه، فكّر في إجاباتك، ثم انقر على المثلثات لعرض الحلول.

بناءً على ما سبق، كم عدد الكيوبتات اللازمة لترميز 6 ميزات باستخدام الترميز الكثيف؟

الجواب: 3

اكتب كوداً لتحميل المتجه x(1)=(4,8,5,9,8,6,2,9,2,5,7,0,3,7,5)\vec{x}^{(1)}=(4,8,5,9,8,6,2,9,2,5,7,0,3,7,5) باستخدام الترميز بالزاوية الكثيف.

الجواب:

لاحظ أننا أضفنا "0" إلى القائمة لتجنب مشكلة وجود معامل غير مستخدم في مخطط الترميز الخاص بنا.

from qiskit.circuit.library import efficient_su2

circuit = efficient_su2(num_qubits=2, reps=1, insert_barriers=True)
circuit.decompose().draw(output="mpl")

&quot;Output of the previous code cell&quot;

الترميز باستخدام خرائط الميزات المدمجة

الترميز عند نقاط عشوائية

يُعِدّ الترميز بالزاوية، والترميز الطوري، والترميز الكثيف حالات حاصل ضرب مع ترميز ميزة على كل كيوبت (أو ميزتين لكل كيوبت). وهذا يختلف عن الترميز الأساسي والترميز بالسعة، إذ تستخدم هذه الطرق حالات متشابكة، ولا توجد علاقة 1:1 بين ميزة البيانات والكيوبت. في الترميز بالسعة مثلاً، قد تكون إحدى الميزات هي سعة الحالة 01|01\rangle وأخرى هي سعة الحالة 10|10\rangle. بشكل عام، الطرق التي تُرمِّز في حالات حاصل الضرب تُنتج دوائر أكثر ضحالة ويمكنها تخزين ميزة واحدة أو ميزتين على كل كيوبت. أما الطرق التي تستخدم التشابك وتربط ميزة بحالة بدلاً من كيوبت فتُنتج دوائر أعمق، ويمكنها تخزين ميزات أكثر لكل كيوبت في المتوسط.

لكن لا يجب أن يكون الترميز كاملاً في حالات حاصل الضرب أو كاملاً في الحالات المتشابكة كما في الترميز بالسعة. بل إن كثيراً من مخططات الترميز المدمجة في Qiskit تتيح الترميز قبل طبقة التشابك وبعدها، بدلاً من الاقتصار على البداية فقط. يُعرف هذا بـ"إعادة رفع البيانات". للاطلاع على أعمال ذات صلة، راجع المراجع [5] و[6].

في هذا القسم، سنستخدم ونُصوِّر بعض مخططات الترميز المدمجة. جميع الطرق في هذا القسم تُرمِّز NN ميزة على شكل دورانات على NN بوابة ذات معاملات على nn كيوبت، حيث nNn \leq N. لاحظ أن تعظيم تحميل البيانات لعدد معين من الكيوبتات ليس الاعتبار الوحيد؛ ففي كثير من الحالات قد يكون عمق الدائرة اعتباراً أهم من عدد الكيوبتات.

Efficient SU2

مثال شائع ومفيد على الترميز مع التشابك الكمي هو دائرة efficient_su2 في Qiskit. والمثير للإعجاب أن هذه الدائرة تستطيع، على سبيل المثال، ترميز 8 خصائص على 2 كيوبت فقط. دعنا نشاهد ذلك ثم نحاول أن نفهم كيف يكون هذا ممكنًا.

x = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2]
circuit = efficient_su2(num_qubits=3, reps=1, insert_barriers=True)
encode = circuit.assign_parameters(x)
encode.decompose().draw(output="mpl")

Output of the previous code cell

حين نكتب الحالة، سنتبع اصطلاح Qiskit الذي يرتّب الكيوبتات الأقل أهمية في أقصى اليمين، كما في q2,q1,q0|q_2,q_1,q_0\rangle أو q2q1q0.|q_2\rangle\otimes|q_1\rangle\otimes|q_0\rangle. قد تصبح هذه الحالات معقدة جدًا بسرعة كبيرة، وهذا المثال النادر قد يفسّر لماذا نادرًا ما تُكتب مثل هذه الحالات بصورة صريحة.

يبدأ نظامنا في الحالة 00.|00\rangle. وحتى الحاجز الأول (النقطة التي نسمّيها b1b1)، تكون حالاتنا:

ψb1=(cos(θ12)0+sin(θ12)eiθ31)(cos(θ02)0+sin(θ02)eiθ21)|\psi\rangle_{b1} = \left(\cos\left(\frac{\theta_1}{2}\right)|0\rangle+\sin\left(\frac{\theta_1}{2}\right)e^{i\theta_3}|1\rangle\right)\otimes\left(\cos\left(\frac{\theta_0}{2}\right)|0\rangle+\sin\left(\frac{\theta_0}{2}\right)e^{i\theta_2}|1\rangle\right)

هذا مجرد ترميز كثيف رأيناه من قبل. الآن بعد بوابة CNOT، عند الحاجز الثاني (b2b2)، تكون حالتنا:

ψb2=cos(θ12)cos(θ02)00+cos(θ12)sin(θ02)eiθ211+sin(θ12)cos(θ02)eiθ310+sin(θ12)sin(θ02)eiθ2eiθ301\begin{aligned} |\psi\rangle_{b2} = & \cos\left(\frac{\theta_1}{2}\right)\cos\left(\frac{\theta_0}{2}\right)|00\rangle+\cos\left(\frac{\theta_1}{2}\right)\sin\left(\frac{\theta_0}{2}\right)e^{i\theta_2}|11\rangle\\ + & \sin\left(\frac{\theta_1}{2}\right)\cos\left(\frac{\theta_0}{2}\right)e^{i\theta_3}|10\rangle+\sin\left(\frac{\theta_1}{2}\right)\sin\left(\frac{\theta_0}{2}\right)e^{i\theta_2}e^{i\theta_3}|01\rangle \end{aligned}

الآن نطبّق المجموعة الأخيرة من دورانات الكيوبت الواحد ونجمع الحالات المتشابهة للحصول على:

ψfinal=[cos(θ02)(cos(θ12)cos(θ52)sin(θ12)sin(θ52)eiθ3)cos(θ42)+sin(θ02)(cos(θ12)sin(θ52)sin(θ12)cos(θ52)eiθ3)sin(θ42)eiθ2]00+[cos(θ02)(cos(θ12)cos(θ52)sin(θ12)sin(θ52)eiθ3)sin(θ42)+sin(θ02)(cos(θ12)sin(θ52)+sin(θ12)cos(θ52)eiθ3)cos(θ42)eiθ2]eiθ601+[cos(θ02)(cos(θ12)sin(θ52)+sin(θ12)cos(θ52)eiθ3)cos(θ42)sin(θ02)(cos(θ12)cos(θ52)+sin(θ12)sin(θ52)eiθ3)sin(θ42)eiθ2]eiθ710+[cos(θ02)(cos(θ12)sin(θ52)+sin(θ12)cos(θ52)eiθ3)sin(θ42)+sin(θ02)(cos(θ12)cos(θ52)+sin(θ12)sin(θ52)eiθ3)cos(θ42)eiθ2]eiθ6eiθ711\begin{align*} |\psi\rangle_{\text{final}} = & \left[\cos\left(\frac{\theta_0}{2}\right)\left(\cos\left(\frac{\theta_1}{2}\right)\cos\left(\frac{\theta_5}{2}\right)-\sin\left(\frac{\theta_1}{2}\right)\sin\left(\frac{\theta_5}{2}\right)e^{i\theta_3}\right)\cos\left(\frac{\theta_4}{2}\right)\right.\\ + & \left.\sin\left(\frac{\theta_0}{2}\right)\left(\cos\left(\frac{\theta_1}{2}\right)\sin\left(\frac{\theta_5}{2}\right)-\sin\left(\frac{\theta_1}{2}\right)\cos\left(\frac{\theta_5}{2}\right)e^{i\theta_3}\right)\sin\left(\frac{\theta_4}{2}\right)e^{i\theta_2}\right] |00\rangle\\ + & \left[\cos\left(\frac{\theta_0}{2}\right)\left(\cos\left(\frac{\theta_1}{2}\right)\cos\left(\frac{\theta_5}{2}\right)-\sin\left(\frac{\theta_1}{2}\right)\sin\left(\frac{\theta_5}{2}\right)e^{i\theta_3}\right)\sin\left(\frac{\theta_4}{2}\right)\right.\\ + & \left.\sin\left(\frac{\theta_0}{2}\right)\left(-\cos\left(\frac{\theta_1}{2}\right)\sin\left(\frac{\theta_5}{2}\right)+\sin\left(\frac{\theta_1}{2}\right)\cos\left(\frac{\theta_5}{2}\right)e^{i\theta_3}\right)\cos\left(\frac{\theta_4}{2}\right)e^{i\theta_2}\right] e^{i\theta_6}|01\rangle\\ + & \left[\cos\left(\frac{\theta_0}{2}\right)\left(\cos\left(\frac{\theta_1}{2}\right)\sin\left(\frac{\theta_5}{2}\right)+\sin\left(\frac{\theta_1}{2}\right)\cos\left(\frac{\theta_5}{2}\right)e^{i\theta_3}\right)\cos\left(\frac{\theta_4}{2}\right)\right.\\ - & \left.\sin\left(\frac{\theta_0}{2}\right)\left(\cos\left(\frac{\theta_1}{2}\right)\cos\left(\frac{\theta_5}{2}\right)+\sin\left(\frac{\theta_1}{2}\right)\sin\left(\frac{\theta_5}{2}\right)e^{i\theta_3}\right)\sin\left(\frac{\theta_4}{2}\right)e^{i\theta_2}\right] e^{i\theta_7}|10\rangle\\ + & \left[\cos\left(\frac{\theta_0}{2}\right)\left(\cos\left(\frac{\theta_1}{2}\right)\sin\left(\frac{\theta_5}{2}\right)+\sin\left(\frac{\theta_1}{2}\right)\cos\left(\frac{\theta_5}{2}\right)e^{i\theta_3}\right)\sin\left(\frac{\theta_4}{2}\right)\right.\\ + & \left.\sin\left(\frac{\theta_0}{2}\right)\left(\cos\left(\frac{\theta_1}{2}\right)\cos\left(\frac{\theta_5}{2}\right)+\sin\left(\frac{\theta_1}{2}\right)\sin\left(\frac{\theta_5}{2}\right)e^{i\theta_3}\right)\cos\left(\frac{\theta_4}{2}\right)e^{i\theta_2}\right] e^{i\theta_6}e^{i\theta_7}|11\rangle \end{align*}

هذه المعادلة على الأرجح معقدة جدًا لتحليلها. بدلًا من ذلك، تراجع خطوة للوراء وفكّر في عدد المعاملات التي حمّلناها على الحالة: ثمانية. لكننا لدينا فقط أربع حالات أساسية حسابية. قد يبدو للوهلة الأولى أننا حمّلنا معاملات أكثر مما هو منطقي، إذ يمكن كتابة الحالة النهائية على النحو ψfinal=c000+c101+c210+c311\psi_\text{final} = c_0|00\rangle+c_1|01\rangle+c_2|10\rangle+c_3|11\rangle. لاحظ مع ذلك أن كل معامل مسبق هو عدد مركّب! وإذا كُتب على هذا الشكل:

ψfinal=(a0+ib0)00+(a1+ib1)01+(a2+ib2)10+(a3+ib3)11\psi_\text{final} = (a_0+ib_0)|00\rangle+(a_1+ib_1)|01\rangle+(a_2+ib_2)|10\rangle+(a_3+ib_3)|11\rangle

يتضح أن لدينا فعلًا ثمانية معاملات على الحالة يمكننا ترميز ثماني خصائص عليها.

بزيادة عدد الكيوبتات وزيادة عدد تكرارات طبقات التشابك والدوران، يمكن ترميز كميات أكبر بكثير من البيانات. كتابة دوال الموجة يصبح سريعًا أمرًا غير قابل للتطبيق. لكن لا يزال بإمكاننا مشاهدة الترميز في العمل. نرمّز هنا متجه البيانات x\vec{x} ذا 12 خاصية على دائرة efficient_su2 ذات 3 كيوبتات، مستخدمين كل بوابة معلمة لترميز خاصية مختلفة.

x=(0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,1.1,1.2)\vec{x} = (0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0,1.1,1.2)

في متجه البيانات هذا، تظهر الخصائص بترتيب معين. بمعزل عن السياق، لا يهم إن رُمّزت بهذا الترتيب أو بالعكس. المهم هو تتبّع الترتيب والتناسق فيه. لاحظ في مخطط الدائرة أن efficient_su2 يفترض ترتيبًا معينًا للترميز، وتحديدًا يملأ طبقة البوابات المعلمة الأولى من الكيوبت 0 إلى الكيوبت 2، ثم ينتقل إلى الطبقة التالية. هذا لا يتعارض ولا يتوافق بالضرورة مع ترميز little-endian، إذ لا يمكن دائمًا ترتيب خصائص البيانات حسب الكيوبت مسبقًا قبل تحديد دائرة الترميز.

qc0 = QuantumCircuit(1)
qc1 = QuantumCircuit(1)

qc0.h(0)
qc0.p(pi / 2, 0)

qc1.h(0)
qc1.p(pi / 3, 0)

# Combine circuits qc0 and qc1 into 1 circuit
qc = QuantumCircuit(2)
qc.compose(qc0, [0], inplace=True)
qc.compose(qc1, [1], inplace=True)

qc.draw("mpl", scale=1)

Output of the previous code cell

بدلًا من زيادة عدد الكيوبتات، قد تختار زيادة عدد تكرارات طبقات التشابك والدوران. لكن هناك حدود لعدد التكرارات المفيدة. كما أُشير سابقًا، ثمة مقايضة: الدوائر التي تحتوي على كيوبتات أكثر أو تكرارات أكثر لطبقات التشابك والدوران قد تخزّن معاملات أكثر، لكنها تفعل ذلك بعمق دائرة أكبر. سنعود إلى أعماق بعض خرائط الخصائص المدمجة لاحقًا. طرق الترميز التالية المدمجة في Qiskit تتضمن "feature map" في أسمائها. دعنا نؤكد من جديد أن ترميز البيانات في دائرة كمومية هو في حد ذاته تعيين للخصائص، بمعنى أنه ينقل البيانات إلى فضاء جديد: فضاء هيلبرت للكيوبتات المعنية. العلاقة بين بُعد فضاء الخصائص الأصلي وبُعد فضاء هيلبرت ستعتمد على الدائرة المستخدمة في الترميز.

خريطة الخصائص ZZ

يمكن تفسير خريطة الخصائص ZZ (ZFM) باعتبارها امتدادًا طبيعيًا لترميز الطور. تتكوّن ZFM من طبقات متناوبة من بوابات الكيوبت الواحد: طبقات بوابة هادامار وطبقات بوابة الطور. ليكن متجه البيانات x\vec{x} يحتوي على NN خاصية. تُمثَّل الدائرة الكمومية التي تنفّذ تعيين الخصائص كمؤثر أحادي يعمل على الحالة الابتدائية:

UZFM(x)0N=ϕ(x)\mathscr{U}_{\text{ZFM}}(\vec{x})|0\rangle^{\otimes N}=|\phi(\vec{x})\rangle

حيث 0N|0\rangle^{\otimes N} هي الحالة الأرضية لـ NN كيوبت. يُستخدم هذا الترميز للتناسق مع المرجع [4] لـ Havlicek et al. تُعيَّن خصائص البيانات xix_i بصورة واحد-لواحد مع الكيوبتات المقابلة. على سبيل المثال، إن كانت لديك 8 خصائص في متجه بيانات، فستستخدم 8 كيوبتات. تتكوّن دائرة ZFM من rr تكرار لدائرة فرعية مؤلفة من طبقات بوابة هادامار وطبقات بوابة الطور. طبقة هادامار تتألف من بوابة هادامار تعمل على كل كيوبت في سجلّ nn-كيوبت، HHH=HnH \otimes H \otimes \dots \otimes H = H^{\otimes n}، ضمن المرحلة ذاتها من الخوارزمية. ينطبق هذا الوصف أيضًا على طبقة بوابة الطور حيث يتأثر الكيوبت ii بـ P(xi)P(\vec{x}_i). كل بوابة PP لها خاصية واحدة كمعطى، لكن طبقة بوابة الطور (P(x1)P(xk)P(xN)P(\vec{x}_1)\otimes\ldots P(\vec{x}_k)\otimes\ldots P(\vec{x}_N)) هي دالة لمتجه البيانات. المؤثر الأحادي الكامل لدائرة ZFM بتكرار واحد هو:

UZFM=(P(x1)P(xk)P(xN)HN)=(k=1NP(xk))HN\mathscr{U}_{\text{ZFM}}=\big(P(\vec{x}_1)\otimes\ldots P(\vec{x}_k)\otimes\ldots P(\vec{x}_N)H^{\otimes N}\big)=\left(\bigotimes_{k = 1}^N P(\vec{x}_k)\right)H^{\otimes N}

ثم rr تكرارات من هذا المؤثر الأحادي تكون:

UZFM(r)(x)=s=1r[(k=1NP(xk))HN]\mathscr{U}^{(r)}_{\text{ZFM}}\left(\vec{x}\right)=\prod_{s=1}^{r}\left[\left(\bigotimes_{k = 1}^N P(\vec{x}_k)\right)H^{\otimes N}\right]

خصائص البيانات، xkx_k، تُعيَّن إلى بوابات الطور بالطريقة ذاتها في جميع التكرارات الـ rr. حالة خريطة خصائص ZFM هي حالة ضرب تنسيقي وهي فعّالة للمحاكاة الكلاسيكية[4].

للبدء بمثال صغير، نبرمج دائرة ZFM ذات كيوبتين في Qiskit ونرسمها لإظهار البنية البسيطة للدائرة. في هذا المثال، يُنفَّذ تكرار واحد، r=1r=1، مع متجه البيانات x=(12π,13π)\vec{x} = \left(\textstyle\frac{1}{2}\pi, \textstyle\frac{1}{3}\pi\right). لاحظ أن هذا مكتوب بالترتيب المعياري لمتجه في Python، أي أن العنصر 00 هو 12π.\textstyle\frac{1}{2}\pi. لنا حرية ترميز هذه الخاصية 00 على الكيوبت 00، أو على الكيوبت NN. مجددًا، لا يمكن دائمًا وجود تعيين 1:1 واحد من ترتيب الخصائص إلى ترتيب الكيوبتات، إذ تُرمَّد أعداد مختلفة من الخصائص على كل كيوبت في خرائط خصائص مختلفة. ومجددًا ما يهم هو أن نكون واعين بمكان ترميز كل خاصية. عند تقديم قائمة معاملات لخريطة خصائص ZZ، ستُرمَّز الخاصية 0 من القائمة على الكيوبت الأقل أهمية الذي يحتوي بوابة معلمة، أي الكيوبت 0. لذا سنتبع هذا الاصطلاح حين نفعل ذلك يدويًا. سنرمّز 12π\textstyle\frac{1}{2}\pi على الكيوبت 00، و13π\textstyle\frac{1}{3}\pi على الكيوبت 11.

يعمل مؤثر الدائرة الأحادي لـ ZFM على الحالة الابتدائية بالطريقة التالية:

UZFM(xˉ)00=P(xˉ)2H200=(P(13π)H0)(P(12π)H0).\mathscr{U}_{\text{ZFM}}(\bar{x})|00\rangle = P(\bar{x})^{\otimes 2} H^{\otimes 2}|00\rangle = \left( P\left(\textstyle\frac{1}{3}\pi\right)H|0\rangle \right) \otimes \left(P\left(\textstyle\frac{1}{2}\pi\right)H|0\rangle\right).

أُعيدت صياغة المعادلة حول حاصل الضرب التنسيقي للتأكيد على العمليات على كل كيوبت. يستخدم كود Qiskit التالي بوابات هادامار والطور بصورة صريحة لإظهار بنية ZFM:

from qiskit.circuit.library import z_feature_map

zfeature_map = z_feature_map(feature_dimension=2, reps=3)
zfeature_map = zfeature_map.assign_parameters([(1 / 2) * pi / 2, (1 / 2) * pi / 3])
zfeature_map.decompose().draw("mpl")

Output of the previous code cell

نرمّز الآن متجه البيانات ذاته x=(12π,13π)\vec{x} = \left(\textstyle\frac{1}{2}\pi, \textstyle\frac{1}{3}\pi\right) على دائرة ZFM بثلاثة تكرارات، r=3r=3، باستخدام صنف z_feature_map في Qiskit، مما يعطينا في المجمل خريطة الخصائص الكمومية UZFM(x)\mathscr{U}_{\text{ZFM}}(\vec{x}). بشكل افتراضي في صنف z_feature_map، تُضرب المعاملات β\beta في 2 قبل تعيينها على بوابة الطور βP(θ=2β)\beta \rightarrow P(\theta = 2\beta). للحصول على الترميزات ذاتها كما في الأعلى، نقسم على 2.

qc = QuantumCircuit(2)
qc.rzz(pi, 0, 1)
qc.draw("mpl", scale=1)

Output of the previous code cell

من الواضح أن هذا تعيين مختلف عن الذي أجريناه يدويًا أعلاه، لكن لاحظ الاتساق في ترتيب المعاملات: تم تشفير 12π\textstyle\frac{1}{2}\pi مجددًا على الكيوبت 0th0^\text{th}.

يمكنك استخدام ZFM عبر فئة ZFM في Qiskit؛ كما يمكنك الاستلهام من هذا الهيكل لبناء تعيين الميزات الخاص بك.

خريطة ميزات ZZZZ

تمتد خريطة ميزات ZZZZ (ZZFM) على خريطة ZFM بإضافة بوابات تشابك ثنائية الكيوبت، وتحديدًا بوابة دوران ZZZZ وهي RZZ(θ)R_{ZZ}(\theta). يُعتقد أن ZZFM يصعب حسابها بشكل عام على الحاسوب الكلاسيكي، على عكس ZFM.

تُنفّذ RZZ(θ)R_{ZZ}(\theta) تفاعلًا من نوع ZZZZ وتكون أقصى تشابكًا عند θ=12π\theta = \textstyle{\frac{1}{2}}\pi. يمكن تحليل RZZ(θ)R_{ZZ}(\theta) إلى سلسلة من البوابات على كيوبتَين، كما هو موضح في كود Qiskit التالي باستخدام بوابة RZZ وأسلوب الفئة QuantumCircuit المسمى decompose. نقوم بتشفير ميزة واحدة من متجه البيانات x\vec{x}: xk=π.\vec{x}_k=\pi.

qc.decompose().draw("mpl", scale=1)

Output of the previous code cell

كما هو الحال في الغالب، نرى هذا ممثلًا كوحدة تشبه بوابة واحدة، حتى نستخدم ‎.decompose()‎ لرؤية جميع البوابات المكوِّنة لها.

from qiskit.circuit.library import zz_feature_map

feature_dim = 2
zzfeature_map = zz_feature_map(
feature_dimension=feature_dim, entanglement="linear", reps=1
)
zzfeature_map.decompose(reps=1).draw("mpl", scale=1)

Output of the previous code cell

يتم تعيين البيانات بدوران طوري P(θ)=eiθ/2RZ(θ)P(\theta) = e^{i\theta/2}R_Z(\theta) على الكيوبت الثاني. تقوم بوابة RZZ(θ)R_{ZZ}(\theta) بتشابك الكيوبتَين اللذَين تعمل عليهما بدرجة تشابك تحددها قيمة الميزة المُشفَّرة.

تتكوّن دائرة ZZFM الكاملة من بوابة هادامار وبوابة طور، كما في ZFM، يعقبها التشابك الموصوف أعلاه. تكرار واحد لدائرة ZZFM هو:

UZZFM(x)=UZZ(x)(P(x1)P(xk)P(xN)HN)=UZZ(x)(k=1NP(xk))HN,\mathscr{U}_{\text{ZZFM}}(\vec{x}) = U_{ZZ}(\vec{x})\big(P(\vec{x}_1)\otimes\ldots P(\vec{x}_k)\otimes\ldots P(\vec{x}_N)H^{\otimes N}\big)=U_{ZZ}(\vec{x})\left(\bigotimes_{k = 1}^N P(\vec{x}_k)\right)H^{\otimes N},

حيث تحتوي UZZ(x)U_{ZZ}(\vec{x}) على طبقة بوابات ZZ منظَّمة وفق مخطط تشابك معين. يُعرض عدة مخططات تشابك في كتل الكود أدناه. يتضمن هيكل UZZ(x)U_{ZZ}(\vec{x}) أيضًا دالة تجمع ميزات البيانات من الكيوبتات المتشابكة على النحو التالي. لنفترض أن بوابة RZZR_{ZZ} ستُطبَّق على الكيوبتَين pp وqq. في طبقة الطور، تحتوي هذه الكيوبتات على بوابات طور تُشفّر xp\vec{x}_p وxq\vec{x}_q عليها على التوالي. الوسيط θq,p\theta_{q,p} لـ RZZ,q,p(θq,p)R_{ZZ,q,p}(\theta_{q,p}) لن يكون مجرد إحدى هذه الميزات أو الأخرى، بل دالة تُشار إليها في الغالب بـ ϕ\phi (لا يجب الخلط بينها وبين الزاوية الاستوائية):

θq,pϕ(xq,xp)=2(πxq)(πxp).\theta_{q,p} \rightarrow \phi(\vec{x}_q, \vec{x}_p) = 2(\pi-\vec{x}_q)(\pi-\vec{x}_p).

سنرى هذا في أمثلة عدة أدناه. امتداد التكرارات المتعددة هو نفسه كما في حالة z_feature_map:

UZZFM(r)(x)=s=1r[UZZ(x)(k=1NP(xk))HN].\mathscr{U}^{(r)}_{\text{ZZFM}}\left(\vec{x}\right)=\prod_{s=1}^{r}\left[U_{ZZ}(\vec{x})\left(\bigotimes_{k = 1}^N P(\vec{x}_k)\right)H^{\otimes N}\right].

بما أن العوامل قد ازدادت تعقيدًا، فلنبدأ بتشفير متجه بيانات x=(x0,x1)\vec{x} = (x_0, x_1) باستخدام ZZFM ثنائي الكيوبت وتكرار واحد بالكود التالي:

feature_dim = 4
zzfeature_map = zz_feature_map(
feature_dimension=feature_dim, entanglement="linear", reps=1
)
zzfeature_map.decompose().draw("mpl", scale=1)

Output of the previous code cell

افتراضيًا في Qiskit، يتم تعيين الميزتَين (x1,x2)(\vec{x}_1, \vec{x}_2) معًا إلى RZZ(θ)R_{ZZ}(\theta) بواسطة دالة التعيين هذه θ1,2=ϕ(x1,x2)=2(πx1)(πx2)\theta_{1,2} = \phi(\vec{x}_1, \vec{x}_2) = 2(\pi-\vec{x}_1)(\pi-\vec{x}_2). يتيح Qiskit للمستخدم تخصيص الدالة ϕ\phi (أو ϕS\phi_S حيث SS هي مجموعة أزواج الكيوبتات المقترنة عبر بوابات RZZR_{ZZ}) كخطوة معالجة مسبقة.

بالانتقال إلى متجه بيانات رباعي الأبعاد x=(x1,x2,x3,x4)\vec{x} = (\vec{x}_1, \vec{x}_2, \vec{x}_3, \vec{x}_4) وتعيينه إلى ZZFM رباعي الكيوبتات مع تكرار واحد، يمكننا البدء في رؤية التعيين ϕ\phi لأزواج الكيوبتات المختلفة. كما يمكننا أن نرى معنى التشابك "الخطي":

from qiskit.circuit.library import pauli_feature_map

feature_dim = 3
pfmap = pauli_feature_map(
feature_dimension=feature_dim, entanglement="linear", reps=1, paulis=["Y", "XX"]
)

pfmap.decompose().draw("mpl", scale=1.5)

Output of the previous code cell

في مخطط التشابك الخطي، يتم تشابك أزواج الكيوبتات المتجاورة (المرقَّمة) في هذه الدائرة. ثمة مخططات تشابك مدمجة أخرى في Qiskit، منها circular وfull.

خريطة ميزات باولي

خريطة ميزات باولي (PFM) هي تعميم لـ ZFM وZZFM لاستخدام بوابات باولي اعتباطية. تأخذ خريطة ميزات باولي شكلًا مشابهًا جدًا لخريطتَي الميزات السابقتَين. لـ rr تكرار لتشفير الـ NN ميزة لمتجه x,\vec{x},

UPFM(x)=s=1rU(x)Hn.\mathscr{U}_{\text{PFM}}(\vec{x}) = \prod_{s=1}^{r} U(\vec{x}) H^{\otimes n}.

بالنسبة لـ PFM، يتم تعميم U(x)U(\vec{x}) إلى معامل أحادي لتوسعة باولي. نقدم هنا صيغة أكثر عمومية لخرائط الميزات التي درسناها حتى الآن:

U(x)=exp(iSIϕS(x)iSσi),U(\vec{x}) = \exp\left(i \sum_{S \in\mathcal{I}} \phi_S(\vec{x}) \prod_{i \in S} \sigma_i \right),

حيث σi\sigma_i هو معامل باولي، σiI,X,Y,Z\sigma_i \in {I,X,Y,Z}. هنا I\mathcal{I} هي مجموعة جميع ترابطات الكيوبتات كما تحددها خريطة الميزات، بما في ذلك مجموعة الكيوبتات التي تعمل عليها البوابات أحادية الكيوبت. أي أنه في خريطة ميزات يُعمل فيها على الكيوبت 0 ببوابة طور، وعلى الكيوبتَين 2 و3 ببوابة RZZR_{ZZ}، ستتضمن المجموعة I\mathcal{I} العنصرَين {{0},{2,3}}\{\{0\},\{2,3\}\}. يمر SS عبر جميع عناصر تلك المجموعة. في خرائط الميزات السابقة، كانت الدالة ϕS(x)\phi_S(\vec{x}) تتعامل إما حصرًا مع البوابات أحادية الكيوبت أو حصرًا مع البوابات ثنائية الكيوبت. نعرّفها هنا بشكل عام:

ϕS(x)={xiif S={i} (single-qubit)jS(πxj)if S2 (multi-qubit)\phi_S(\vec{x})= \begin{cases} x_i & \text{if } S= \{i\} \text{ (single-qubit)}\\ \prod_{j\in{S}}(\pi-x_j) & \text{if } |S|\ge2 \text{ (multi-qubit)}\\ \end{cases}

للاطلاع على التوثيق، راجع توثيق فئة Pauli feature map في Qiskit). في ZZFM، يُقيَّد المعامل σi\sigma_i بـ ZiZ_i.

أحد أوجه فهم المعامل الأحادي أعلاه هو القياس بالمنتشر في نظام فيزيائي. المعامل الأحادي أعلاه هو معامل تطور أحادي، exp(itH)\exp(it\mathcal{H})، لهاميلتوني H\mathcal{H} مشابه لنموذج إيزينغ، حيث يُستبدل معامل الزمن tt بقيم البيانات لدفع التطور. توسعة هذا المعامل الأحادي تعطينا دائرة PFM. يمكن تفسير ترابطات التشابك في SS كاقترانات إيزينغ في شبكة دورانية. لنأخذ مثالًا على معاملَي باولي YY وXXXX يمثلان تفاعلات من نوع إيزينغ. يوفر Qiskit فئة pauli_feature_map لإنشاء PFM باختيار بوابات أحادية وnn-كيوبت، والتي ستُمرَّر في هذا المثال كسلاسل باولي 'Y' و'XX'. عادةً ما يكون nn هو 1 أو 2 للتفاعلات أحادية وثنائية الكيوبت على التوالي. مخطط التشابك هو "linear"، أي أنه يتم اقتران الكيوبتات المتجاورة فقط في الدائرة الكمومية. لاحظ أن هذا لا يتوافق بالضرورة مع الكيوبتات المتجاورة على الحاسوب الكمومي نفسه، إذ إن هذه الدائرة الكمومية هي طبقة تجريدية.

from qiskit.visualization import circuit_drawer
import matplotlib.pyplot as plt

feature_dim = 2
fig, axs = plt.subplots(9, 2)
i_plot = 0
for paulis in [
["I"],
["X"],
["Y"],
["Z"],
["XX"],
["XY"],
["XZ"],
["YY"],
["YZ"],
["ZZ"],
["X", "ZZ"],
["Y", "ZZ"],
["Z", "ZZ"],
["X", "YZ"],
["Y", "YZ"],
["Z", "YZ"],
["YY", "ZZ"],
["XY", "ZZ"],
]:
pfmap = pauli_feature_map(feature_dimension=feature_dim, paulis=paulis, reps=1)
circuit_drawer(
pfmap.decompose(),
output="mpl",
style={"backgroundcolor": "#EEEEEE"},
ax=axs[int((i_plot - i_plot % 2) / 2), i_plot % 2],
)
axs[int((i_plot - i_plot % 2) / 2), i_plot % 2].title.set_text(paulis)
i_plot += 1

fig.set_figheight(16)
fig.set_figwidth(16)

Output of the previous code cell

يوفر Qiskit معاملًا α\alpha في خرائط ميزات باولي للتحكم في مقياس دورانات باولي.

U(xˉ)=exp(iαS[n]ϕS(xˉ)iSσi)U(\bar{x}) = \exp\left(i \alpha \sum_{S\subseteq[n]} \phi_S(\bar{x}) \prod_{i \in S} \sigma_i \right)

القيمة الافتراضية لـ α\alpha هي 22. بتحسين قيمته في النطاق، مثلًا [0,4],[0,4], يمكن محاذاة نواة كمومية مع البيانات بشكل أفضل.

هنا نُصوِّر خرائط ميزات باولي المتنوعة لدوائر ثنائية الكيوبت للحصول على صورة أوضح عن نطاق الاحتمالات.

# Initializing parameters and empty lists for depths
x = [0.1, 0.2]
n_data = []
zz2gates = []
su22gates = []
z2gates = []
p2gates = []

# Generating feature maps
for n in range(3, 10):
x.append(n / 10)
zzcircuit = zz_feature_map(n, reps=1, insert_barriers=True)
zcircuit = z_feature_map(n, reps=1, insert_barriers=True)
su2circuit = efficient_su2(n, reps=1, insert_barriers=True)
pcircuit = pauli_feature_map(n, reps=1, paulis=["XX"], insert_barriers=True)
# Getting the cx depths
zzcx = zzcircuit.decompose().count_ops().get("cx")
zcx = zcircuit.decompose().count_ops().get("cx")
su2cx = su2circuit.decompose().count_ops().get("cx")
pcx = pcircuit.decompose().count_ops().get("cx")

# Appending the cx gate counts to the lists. We shift the zz and pauli data points, because they overlap.
n_data.append(n)
zz2gates.append(zzcx - 0.5)
z2gates.append(0)
su22gates.append(su2cx)
p2gates.append(pcx + 0.5)

# Plot the output
plt.plot(n_data, p2gates, "bo")
plt.plot(n_data, zz2gates, "ro")
plt.plot(n_data, su22gates, "yo")
plt.plot(n_data, z2gates, "go")
plt.ylabel("CX Gates")
plt.xlabel("Data elements")
plt.legend(["Pauli", "ZZ", "SU2", "Z"])
# plt.suptitle('zz_feature_map(n)')
plt.show()

Output of the previous code cell

يمكن بالطبع توسيع ما سبق ليشمل تباديل وتكرارات أخرى لمصفوفات باولي. نشجع المتعلمين على تجربة تلك الخيارات.

مراجعة خرائط الميزات المدمجة

رأيت عدة مخططات لترميز البيانات في دائرة كمومية:

  • الترميز الأساسي
  • ترميز السعة
  • ترميز الزاوية
  • ترميز الطور
  • الترميز الكثيف

ورأيت كيف تبني خرائط ميزاتك الخاصة باستخدام هذه المخططات، فضلاً عن أربع خرائط ميزات مدمجة تستفيد من ترميز الزاوية والطور:

  • Efficient SU2
  • خريطة ميزات Z
  • خريطة ميزات ZZ
  • خريطة ميزات باولي

تختلف هذه الخرائط المدمجة عن بعضها من عدة نواحٍ:

  • العمق لعدد معيّن من الميزات المرمّزة
  • عدد الكيوبتات المطلوبة لعدد معيّن من الميزات
  • درجة التشابك (وهي مرتبطة بالاختلافات الأخرى بطبيعة الحال)

الكود أدناه يطبّق هذه الخرائط الأربع المدمجة على ترميز مجموعة ميزات، ويرسم عمق بوابتين كيوبت في الدائرة الناتجة. بما أن معدلات أخطاء بوابات الكيوبتين أعلى بكثير من معدلات أخطاء بوابات الكيوبت الواحد، فقد يكون الأكثر أهمية هو عمق بوابات الكيوبتين. في الكود أدناه، نحصل على أعداد جميع البوابات في الدائرة بتحليلها أولاً ثم استخدام count_ops()، كما هو موضح أدناه. بوابات الكيوبتين التي نهتم بها هنا هي بوابات cx:

import qiskit

qiskit.version.get_version_info()

بشكل عام، ستؤدي خرائط ميزات باولي وZZ إلى عمق دائرة أكبر وعدد أعلى من بوابات الكيوبتين مقارنةً بـ efficient_su2 وخرائط ميزات Z.

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

  1. الأجهزة الحديثة: وجود الضوضاء والتكلفة الكبيرة لكود تصحيح الأخطاء يعني أن التطبيقات الحالية ستحتاج إلى مراعاة أمور مثل كفاءة الأجهزة وتقليل عمق بوابات الكيوبتين.

  2. الخرائط التي تناسب المشكلة المطروحة: شيء واحد أن نقول إن zz_feature_map مثلاً يصعب محاكاتها كلاسيكياً وبالتالي هي مثيرة للاهتمام، وشيء آخر تماماً أن تكون zz_feature_map مناسبة بشكل مثالي لمهمة تعلم الآلة أو مجموعة البيانات الخاصة بك. أداء الدوائر الكمومية ذات المعاملات المختلفة على أنواع مختلفة من البيانات هو مجال بحث نشط.

نختتم بملاحظة حول كفاءة الأجهزة.

ترميز الميزات المتوافق مع الأجهزة

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

التحويل (Transpilation) هو عملية تحويل الدائرة الكمومية من تجريد عالي المستوى إلى دائرة جاهزة للتشغيل على حاسوب كمومي حقيقي، مع مراعاة قيود الأجهزة. للحاسوب الكمومي مجموعة أصلية من بوابات الكيوبت الواحد والكيوبتين، مما يعني أن جميع البوابات في كود Qiskit يجب تحويلها إلى مجموعة البوابات الأصلية للأجهزة. على سبيل المثال، في ibm_torino، وهو معالج كمومي يعمل بمعالج Heron r1 واكتمل عام 2023، البوابات الأصلية أو الأساسية هي \{CZ, ID, RZ, SX, X\}. وهذه هي بوابة CZ ذات الكيوبتين المتحكَّم بها، وبوابات كيوبت واحد تُسمى الهوية، ودوران ZZ، والجذر التربيعي لـ NOT، وNOT على التوالي، مما يوفر مجموعة شاملة. عند تنفيذ بوابات متعددة الكيوبتات كدائرة فرعية مكافئة، تكون بوابات CZCZ الفيزيائية ذات الكيوبتين ضرورية، إلى جانب بوابات كيوبت واحد أخرى متاحة في الأجهزة. علاوة على ذلك، لإجراء بوابة كيوبتين على زوج من الكيوبتات غير المترابطة فيزيائياً، تُضاف بوابات SWAP لنقل حالات الكيوبت بين الكيوبتات لتمكين الاقتران، مما يؤدي إلى امتداد حتمي للدائرة. باستخدام وسيط optimization الذي يمكن ضبطه من 0 حتى أعلى مستوى وهو 3. للتحكم الأكبر وإمكانية التخصيص، يمكن إدارة مسار المحوّل باستخدام Qiskit Pass Manager. راجع توثيق Qiskit Transpiler لمزيد من المعلومات حول التحويل.

في Havlicek وآخرين 2019 [2]، إحدى الطرق التي حقق بها المؤلفون كفاءة الأجهزة هي استخدام خريطة ميزات ZZZZ لأنها توسع من الرتبة الثانية (انظر قسم "خريطة ميزات ZZZZ" أعلاه). التوسع من الرتبة NN يحتوي على بوابات NN-كيوبت. الحواسيب الكمومية من IBM® لا تمتلك بوابات NN-كيوبت أصلية حيث N>2N>2، لذا فإن تنفيذها يتطلب التحليل إلى بوابات CNOT ذات الكيوبتين المتاحة في الأجهزة. الطريقة الثانية التي يقلل بها المؤلفون العمق هي اختيار طوبولوجيا اقتران ZZZZ تتوافق مباشرة مع اقترانات البنية. تحسين إضافي يقومون به هو استهداف دائرة فرعية أجهزة عالية الأداء ذات اتصال مناسب. أشياء إضافية تستحق المراعاة هي تقليل عدد تكرارات خريطة الميزات واختيار مخطط تشابك منخفض العمق أو "خطي" مخصص بدلاً من المخطط "الكامل" الذي يشابك جميع الكيوبتات.

Data encoding image

يُظهر الرسم البياني أعلاه شبكة من العقد والحواف التي تمثل الكيوبتات الفيزيائية واقترانات الأجهزة على التوالي. تُعرض خريطة الاقتران وأداء ibm_torino مع جميع بوابات اقتران CZ ذات الكيوبتين الممكنة. الكيوبتات مُرمَّزة بالألوان على مقياس مبني على وقت الاسترخاء T1 بالميكروثانية (μs)، حيث تكون أوقات T1 الأطول أفضل وذات ظل فاتح. حواف الاقتران مُرمَّزة بالألوان حسب خطأ CZ، حيث تكون الظلال الأغمق أفضل. يمكن الوصول إلى معلومات مواصفات الأجهزة في مخطط تكوين الواجهة الخلفية للأجهزة IBMQBackend.configuration().

المراجع

  1. Maria Schuld and Francesco Petruccione, Supervised Learning with Quantum Computers, Springer 2018, doi:10.1007/978-3-319-96424-9.
  2. Vojtech Havlicek et al., "Supervised Learning with Quantum Enhanced Feature Spaces." Nature, vol. 567 (2019): 209–212. https://arxiv.org/abs/1804.11326.
  3. Ryan LaRose and Brian Coyle, "Robust data encodings for quantum classifiers", Physical Review A 102, 032420 (2020), doi:10.1103/PhysRevA.102.032420, arXiv:2003.01695.
  4. Lou Grover and Terry Rudolph. "Creating Superpositions That Correspond to Efficiently Integrable Probability Distributions." arXiv:quant-ph/0208112, August 15, 2002, https://arxiv.org/abs/quant-ph/0208112.
  5. Adrián Pérez-Salinas, Alba Cervera-Lierta, Elies Gil-Fuster, José I. Latorre, "Data re-uploading for a universal quantum classifier", Quantum 4, 226 (2020), ArXiv.org/abs/1907.02085.
  6. Maria Schuld, Ryan Sweke, Johannes Jakob Meyer, "The effect of data encoding on the expressive power of variational quantum machine learning models", Phys. Rev. A 103, 032430 (2021), arxiv.org/abs/2008.08605
import qiskit

qiskit.version.get_version_info()