محتوای آموزشی

کدنویسی کوانتومی، مقدمه‌ای بر Cirq (بخش اول)

کدنویسی کوانتومی Cirq

Cirq یک کتابخانه در پایتون برای کدنویسی کوانتومی، به کارگیری و بهینه‌سازی مدارهای کوانتومی، و سپس اجرای آنها بر روی رایانه‌های کوانتومی و شبیه‌سازهای کوانتومی است. Cirq برداشت‌های مفیدی را برای کار با رایانه‌های کوانتومی میان‌مقیاس نوفه‌دار (noisy intermediate-scale quantum computers) امروزی ارائه می‌دهد، و این نقطه، جایی است که جزئیات سخت‌افزار برای دستیابی به نتایج پیشرفته حیاتی است. در این مقاله قصد داریم با چند مبحث پایه‌ای در Cirq آشنا شویم.

نصب Cirq بر روی رایانه‌

در ابتدا باید Cirq را نصب کنیم. نصب Cirq کار ساده ای است. کافی است کد زیر را اجرا نماییم. (شما باید از قبل پایتون را نصب کرده باشید). ابتدا pip را آپدیت می‌کنیم و سپس Cirq را نصب میکنیم:

python -m pip install --upgrade pip
python -m pip install cirq

بیایید بررسی کنیم که آیا Cirq به درستی نصب شده یا خیر. کد زیر را در command line می‌نویسیم و باید خروجی‌ای که برایمان چاپ می‌شود، مانند خروجی پایین باشد.

python -c "import cirq_google; print(cirq_google.Sycamore)"
#                                              (0, 5)───(0, 6)
#                                              │        │
#                                              │        │
#                                     (1, 4)───(1, 5)───(1, 6)───(1, 7)
#                                     │        │        │        │
#                                     │        │        │        │
#                            (2, 3)───(2, 4)───(2, 5)───(2, 6)───(2, 7)───(2, 8)
#                            │        │        │        │        │        │
#                            │        │        │        │        │        │
#                   (3, 2)───(3, 3)───(3, 4)───(3, 5)───(3, 6)───(3, 7)───(3, 8)───(3, 9)
#                   │        │        │        │        │        │        │        │
#                   │        │        │        │        │        │        │        │
#          (4, 1)───(4, 2)───(4, 3)───(4, 4)───(4, 5)───(4, 6)───(4, 7)───(4, 8)───(4, 9)
#          │        │        │        │        │        │        │        │
#          │        │        │        │        │        │        │        │
# (5, 0)───(5, 1)───(5, 2)───(5, 3)───(5, 4)───(5, 5)───(5, 6)───(5, 7)───(5, 8)
#          │        │        │        │        │        │        │
#          │        │        │        │        │        │        │
#          (6, 1)───(6, 2)───(6, 3)───(6, 4)───(6, 5)───(6, 6)───(6, 7)
#                   │        │        │        │        │
#                   │        │        │        │        │
#                   (7, 2)───(7, 3)───(7, 4)───(7, 5)───(7, 6)
#                            │        │        │
#                            │        │        │
#                            (8, 3)───(8, 4)───(8, 5)
#                                     │
#                                     │
#                                     (9, 4)

ساخت کیوبیت و مدار

قبل از انجام دادن هر چیزی، باید دقت کنیم که در ابتدای برنامه باید Cirq را وارد کنیم.

import cirq

حالا بیایید بررسی کنیم که چگونه میتوان یک کیوبیت ساخت. کدی که در ادامه نوشته شده، برای ما یک کیوبیت با نامِ «0» میسازد. اگر بخواهیم نام کیوبیت را به ۱، ۲ یا هر عدد دیگری تغییر دهیم، فقط کافی است عددی که داخل پرانتز ها قرار دارد را تغییر دهیم.

my_qubit = cirq.LineQubit(0)

راه‌های دیگری برای ساخت کیوبیت وجود دارد که بعدا در مورد آنها صحبت خواهیم کرد. فعلا بیایید یک گذرگاه (گیت) همانی (حرف آي بزرگ انگلیسی، گیتِ I یا Identity) روی کیوبیت‌مان اعمال کنیم. گذرگاه I هیچ تغییری در کیوبیت ایجاد نمی‌کند. اما وقتی یاد بگیریم آن را روی یک کیوبیت اعمال کنیم، اعمال کردن گیت‌های دیگر مثل X، Y، H و دیگر گیت‌ها مشابه اعمالِ گیتِ I خواهد بود. کدِ پایین، دستوری است که برای ما گیتِ I را روی my_qubit اعمال میکند. توجه کنید که ما آن را به هیچ مداری اضافه نکردیم. پس هنوز کاری صورت نگرفته.

cirq.I(my_qubit)

حالا بیایید یک مدار بسازیم. کدِ پایین برای ما یک مدار به نام my_circuit می‌سازد:

my_circuit = cirq.Circuit()

اکنون میتوانیم عملیاتِ اعمالِ گیتِ I بر روی کیوبیتِ my_qubit را به مدارمان اضافه کنیم:

my_circuit.append(cirq.I(my_qubit))

کار تمام است. بیایید خروجی مدار را نگاه کنیم. با این دستور میتوانیم مدار را چاپ کنیم:

print(my_circuit)

خروجی بدین شکل خواهد بود. (همانطور که میبینید، نام، کیوبیت‌مان را «۰» گذاشته بودیم و روی آن گیتِ I را اعمال کردیم. در شکل پایین هم این مورد قابل مشاهده است.)

0: ───I───

حالا شما یک ایده‌ی کلی از اینکه چه اتفاقی در Cirq می‌افتد، دارید. پس حالا میتوانیم کمی عمیق تر با هم جلو برویم.

راه های ساخت کیوبیت

در قسمت قبل دیدیم که چطور یک کیوبیت که با عدد نام گذاری شده ساخته میشود. حالا اگر بخواهیم یک اسم به جای نامِ یک کیوبیت قرار دهیم، و نه یک عدد، در این حالت باید چه کنیم.

ساخت کیوبیت با نام

کد پایین نشان می‌دهد که چگونه یک کیوبیت با نامِ source می‌سازیم. الان my_qubit یک متغییر است که دارای یک کیوبیت است که نامِ آن کیوبیت به جای عددی مثل ۰ یا ۱، یک کلمه مثل source است.

my_qubit = cirq.NamedQubit("source")

بیایید بررسی کنیم وقتی از روش بالا استفاده کنیم، خروجی به چه صورت خواهد بود:

my_circuit = cirq.Circuit()
my_circuit.append(cirq.I(my_qubit))
print(my_circuit)

خروجی بدین صورت خواهد بود:

source: ───I───

همانطور که می‌بینید، نامِ کیوبیت به source تغییر کرده است.

ساخت LineQubit

همانطور که در قسمتی قبلی دیدیم، کدِ پایین روشی است که ما یک کیوبیت با نام ۰ میسازیم:

my_qubit = cirq.LineQubit(0)

فرض کنیم که میخواهیم یک آرایه به طول ۱۰، حاویِ ۱۰ تا کیوبیت داشته باشیم که از ۰ تا ۹ نامگذاری شده اند. چون این نیاز، نیازِ متداولی است، برای این کار دستوری وجود دارد. با نوشتنِ کد پایین، آرایه‌ای به نام qubits_array خواهیم داشت که ۱۰ تا عضو دارد. هر عضو یک LineQubit است که از ۰ تا ۹ نامگذاری شده اند.

qubits_array = cirq.LineQubit.range(10)

فرض کنیم میخواهیم روی هر کدام از کیوبیت های آرایه‌ی qubits_array، یک گیتِ I اعمال کنیم. کدِ پایین این کار را برای ما انجام می‌دهد.

circuit = cirq.Circuit()
circuit.append(cirq.I.on_each(qubits_array))

حالا اگر مدار را پرینت کنیم، همچین خروجی ای خواهد داشت: (چاپ کردن مدار را قبلا آموزش دادیم)

0: ───I───
1: ───I───
2: ───I───
3: ───I───
4: ───I───
5: ───I───
6: ───I───
7: ───I───
8: ───I───
9: ───I───

دیگر گیت ها

در بخش های قبل دیدیم که چطور میتوانیم گیتِ I را روی کیوبیت ها اعمال کنیم. گیتِ I هیچ کار خاصی انجام نمی‌دهد. گیت های دیگر را می‌توانیم به این صورت پیاده سازی کنیم:

import cirq
qubits = cirq.LineQubit.range(6)
circuit = cirq.Circuit()

# apply X gate
circuit.append(cirq.X(qubits[0]))

# apply Y gate
circuit.append(cirq.Y(qubits[1]))

# apply Z gate
circuit.append(cirq.Z(qubits[2]))

# apply CNOT gate. the syntax would be like this: cirq.CNOT(cotrol_qubit, target_qubit)
circuit.append(cirq.CNOT(qubits[3], qubits[4]))

# appply H gate
circuit.append(cirq.X(qubits[5]))

# print the circuit to see the result:
print(circuit)

خروجی بدین شکل خواهد بود:

$ python3 main.py
0: ───X───
1: ───Y───
2: ───Z───
3: ───@───
      │
4: ───X───
5: ───X───

لینک های مفید مرتبط با این موضوع:

https://quantumai.google/cirq/start/basics