নোট
এই পৃষ্ঠাটি tutorials/circuits_advanced/1_advanced_circuits.ipynb থেকে উৎপন্ন হয়েছে।
পালস সময়সূচী তৈরির পদ্ধতি¶
তড়িৎস্পন্দন বা পালস একটি বর্তনী (সার্কিট) যুক্তিবর্তনী (গেইট) জন্য একটি মৌলিক স্তরের, সঠিক উপস্থাপনা সংজ্ঞায়িত করে | একটি একক ক্রিয়াকলাপ (অপারেশন) একটি তড়িৎস্পন্দন বা তড়িৎস্পন্দন বা পালস নির্দেশমালার সাথে বাস্তবায়ন করা যেতে পারে, যা একাধিক মৌলিক স্তরের নির্দেশাবলী নিয়ে গঠিত। তড়িৎস্পন্দন বা তড়িৎস্পন্দন বা পালস গেট সম্পর্কে আরও জানতে, প্রদর্শক (ডকুমেন্টেশন) ফিরে যান এখানে <05_pulse_gates.ipynb> __। এই পৃষ্ঠাটি কীভাবে তড়িৎস্পন্দন বা পালস নির্দেশমালা তৈরি করতে হয় তা বিশদ করে।
টীকা: আই. বি. এম এর যন্ত্রের জন্য, তড়িৎস্পন্দন বা পালস নির্দেশমালা গেট বর্ণনা করার জন্য সাবরুটিন হিসাবে ব্যবহৃত হয়। পূর্বে, কিছু যন্ত্রের এই বিন্যাসে সম্পূর্ণ প্রোগ্রামগুলো গ্রহণ করাছিল, কিন্তু এটি 2021 সালের ডিসেম্বরে বন্ধ হচ্ছে। অন্যান্য প্রোভাইডার এখনও এই বিন্যাসে সম্পূর্ণ প্রোগ্রাম গ্রহণ করতে পারে। প্রোগ্রামটি যেভাবেই ব্যবহার করা হোক না কেন, প্রোগ্রাম তৈরির গঠন (সিনট্যাক্স) একই। কিভাবে জানতে পড়ুন!
Pulse programs, which are called Schedule
s, describe instruction sequences for the control electronics. We build Schedule
s using the Pulse Builder. It’s easy to initialize a schedule:
[20]:
from qiskit import pulse
with pulse.build(name='my_example') as my_program:
# Add instructions here
pass
my_program
[20]:
ScheduleBlock(, name="my_example", transform=AlignLeft())
আপনি দেখতে পারেন যে এখনও কোন নির্দেশনা নেই। এই পৃষ্ঠার পরবর্তী অংশটি আপনি যে সময়সূচীতে যোগ করতে পারেন তার প্রতিটি নির্দেশাবলী ব্যাখ্যা করবে এবং শেষ অংশটি বিভিন্ন alignment contexts বর্ণনা করবে, যা নির্দেশ করে কিভাবে একে অপরের আপেক্ষিক সময়ে নির্দেশাবলী স্থাপন করা হয়।
Schedule
নির্দেশনা¶
প্রতিটি নির্দেশনা ধরনের নিজস্ব অপারেন্ড গুচ্ছ আছে। আপনি উপরে দেখতে পাচ্ছেন, নির্দেশাবলী কোথায় প্রয়োগ করা হবে তা নির্দিষ্ট করার জন্য তাদের প্রতিটিতে কমপক্ষে একটি Channel
অন্তর্ভুক্ত রয়েছে।
চ্যানেল হল নিয়ন্ত্রণ যন্ত্র থেকে কোয়ান্টাম চিপ পর্যন্ত সিগন্যাল লাইনের নাম (লেবেল)।
DriveChannel
গুলি সাধারণত একক কিউবিট ঘূর্ণনের * ড্রাইভিং * এর জন্য ব্যবহৃত হয়,ControlChannel
গুলি সাধারণত মাল্টি-কিউবিট গেট বা টিউনেবল (tunable)কিউবিটগুলির অতিরিক্ত ড্রাইভ লাইনের জন্য ব্যবহৃত হয়,MeasureChannel
গুলি পালস প্রেরণের জন্য নির্দিষ্ট যা রিড-আউটকে উদ্দীপিত করে, এবংডিজিটাইজারগুলিকে ট্রিগার করতে
AcquireChannel
গুলি ব্যবহার করা হয় যা রিড-আউট সিগন্যাল সংগ্রহ করে।
DriveChannel
, ControlChannel
, এবং MeasureChannel
গুলি সব PulseChannel
; এর মানে হল যে তারা * পালস প্রেরণ * সমর্থন করে, যেখানে AcquireChannel
শুধুমাত্র একটি রিসিভ চ্যানেল এবং তরঙ্গরূপ চালাতে পারে না।
নিম্নলিখিত উদাহরণগুলির জন্য, আমরা প্রতিটি Instruction
এর জন্য একটি DriveChannel
উদাহরণ তৈরি করব যা একটি PulseChannel
গ্রহণ করে। চ্যানেলগুলি একটি পূর্ণসংখ্যা index
আর্গুমেন্ট নেয়। ControlChannel
গুলি ছাড়া, সূচকটি ট্রিভিয়ালি কিউবিট লেবেলে ম্যাপ করে।
[21]:
from qiskit.pulse import DriveChannel
channel = DriveChannel(0)
পালস Schedule
যে ব্যাকএন্ড এর উপর চলে তার থেকে স্বাধীন। যাইহোক, আমরা একটি প্রেক্ষাপটে আমাদের প্রোগ্রাম তৈরি করতে পারি যা pulse.build
এ সরবরাহ করার দ্বারা টার্গেট ব্যাকএন্ড সম্বন্ধে অবগত হয়। সম্ভব হলে আপনার একটি ব্যাকএন্ড সরবরাহ করা উচিত। চ্যানেল অ্যাক্সেসর pulse.<type>_channel(<idx>)
ব্যবহার করে আমরা নিশ্চিত করতে পারি যে আমরা কেবল উপলব্ধ ডিভাইস রিসোর্স ব্যবহার করছি।
[22]:
from qiskit.providers.fake_provider import FakeValencia
backend = FakeValencia()
with pulse.build(backend=backend, name='backend_aware') as backend_aware_program:
channel = pulse.drive_channel(0)
print(pulse.num_qubits())
# Raises an error as backend only has 5 qubits
#pulse.drive_channel(100)
5
delay
¶
অন্যতম সহজ একটি নির্দেশনা আমরা তৈরী করতে পারি যা হলো delay
। এটি একটি ব্লকিং নির্দেশ যা নির্দিষ্ট ইলেকট্রনিক্সকে নির্দিষ্ট সময়ের জন্য প্রদত্ত চ্যানেলে কোন সংকেত আউটপুট করতে বলে না। এটি অন্যান্য নির্দেশাবলীর সময় নিয়ন্ত্রণের জন্য দরকারী।
The duration here and elsewhere is in terms of the backend’s cycle time (1 / sample rate), dt
. It must take an integer value.
একটি delay
নির্দেশ যোগ করার জন্য, আমরা একটি সময়কাল এবং একটি চ্যানেল পাস করি, যেখানে channel
, AcquireChannel
সহ যেকোনো ধরনের চ্যানেল হতে পারে। আমরা একটি পালস বিল্ডার প্রসঙ্গ শুরু করতে pulse.build
ব্যবহার করি। যা স্বয়ংক্রিয়ভাবে আমাদের বিলম্বকে সময়সূচী delay_5dt
তে নির্ধারণ করে।
[23]:
with pulse.build(backend) as delay_5dt:
pulse.delay(5, channel)
That’s all there is to it. Any instruction added after this delay on the same channel will execute five timesteps later than it would have without this delay.
play
¶
The play
instruction is responsible for executing pulses. It’s straightforward to add a play instruction:
with pulse.build() as sched:
pulse.play(pulse, channel)
Let’s clarify what the pulse
argument is and explore a few different ways to build one.
তড়িৎস্পন্দন বা পালস¶
একটি Pulse
একটি ইচ্ছাধীন পালস envelope নির্দিষ্ট করে। আউটপুট ওয়েভফর্মের ফেজ এবং মড্যুলেশন ফ্রিকোয়েন্সি যথাক্রমে set_frequency
এবং shift_phase
নির্দেশাবলী দ্বারা নিয়ন্ত্রিত হয়, যা আমরা পরবর্তীতে কভার করবো।
The image below may provide some intuition for why they are specified separately. Think of the pulses which describe their envelopes as input to an arbitrary waveform generator (AWG), a common lab instrument – this is depicted in the left image. Notice the limited sample rate discritizes the signal. The signal produced by the AWG may be mixed with a continuous sine wave generator. The frequency of its output is controlled by instructions to the sine wave generator; see the middle image. Finally, the signal sent to the qubit is demonstrated by the right side of the image below.
** দ্রষ্টব্য **: হার্ডওয়্যার অন্যান্য উপায়েও প্রয়োগ করা যেতে পারে, কিন্তু যদি আমরা নির্দেশাবলী গুলি আলাদা রাখি, তাহলে আমরা স্পষ্ট তথ্য হারানো এড়াতে পারি , যেমন মড্যুলেশন ফ্রিকোয়েন্সিটির মান।
There are many methods available to us for building up pulses. Our library
within Qiskit Pulse contains helpful methods for building Pulse
s. Let’s take for example a simple Gaussian pulse – a pulse with its envelope described by a sampled Gaussian function. We arbitrarily choose an amplitude of 1, standard deviation \(\sigma\) of 10, and 128 sample points.
Note: The amplitude norm is arbitrarily limited to 1.0
. Each backend system may also impose further constraints – for instance, a minimum pulse size of 64. These additional constraints, if available, would be provided through the BackendConfiguration
which is described here.
[24]:
from qiskit.pulse import library
amp = 1
sigma = 10
num_samples = 128
পরামিতিক তড়িৎস্পন্দন বা পালস¶
Let’s build our Gaussian pulse using the Gaussian
parametric pulse. A parametric pulse sends the name of the function and its parameters to the backend, rather than every individual sample. Using parametric pulses makes the jobs you send to the backend much smaller. IBM Quantum backends limit the maximum job size that they accept, so parametric pulses may allow you to run larger programs.
library
এর অন্যান্য প্যারামেট্রিক পালসগুলির মধ্যে রয়েছে GaussianSquare
, Drag
এবং Constant
।
** দ্রষ্টব্য **: প্যারামেট্রিক তড়িৎস্পন্দন বা পালসের নমুনা ঠিক কিভাবে নিতে হবে তা নির্ধারণের জন্য ব্যাকএন্ড দায়ী। প্যারামেট্রিক তড়িৎস্পন্দন বা পালস আঁকা সম্ভব, কিন্তু প্রদর্শিত নমুনাগুলি ব্যাকএন্ডে কার্যকর হওয়াগুলির সমান হওয়ার নিশ্চয়তা দেয় না।
[25]:
gaus = pulse.library.Gaussian(num_samples, amp, sigma,
name="Parametric Gaus")
gaus.draw()
[25]:

নমুনা দ্বারা বর্ণিত পালস ওভেফর্মস¶
একটি ওয়েভফর্ম
হল একটি পালস সিগন্যাল যা সময়-নির্দেশিত জটিল পরিবর্ধন বা *নমুনা * এর একটি অ্যারে হিসাবে নির্দিষ্ট করা হয়। প্রতিটি নমুনা একটি চক্রের জন্য বাজানো হয়, একটি টাইমস্টেপ dt
, ব্যাকএন্ড দ্বারা নির্ধারিত। যদি আমরা আমাদের প্রোগ্রামের রিয়েল-টাইম গতিবিদ্যা জানতে চাই, তাহলে আমাদের dt
এর মান জানতে হবে। (শূন্য-সূচীকৃত) \(i^{th}\) নমুনাটি i*dt
সময় থেকে (i + 1)*dt
পর্যন্ত চলবে, যা কিউবিট ফ্রিকোয়েন্সি দ্বারা সংশোধন করা হবে।
[26]:
import numpy as np
times = np.arange(num_samples)
gaussian_samples = np.exp(-1/2 *((times - num_samples / 2) ** 2 / sigma**2))
gaus = library.Waveform(gaussian_samples, name="WF Gaus")
gaus.draw()
[26]:

তড়িৎস্পন্দন বা পালস লাইব্রেরি ফাংশন¶
আমাদের নিজস্ব পালস লাইব্রেরিতে সাধারণ ফাংশন থেকে Waveform
তৈরির নমুনা পদ্ধতি রয়েছে।
[27]:
gaus = library.gaussian(duration=num_samples, amp=amp, sigma=sigma, name="Lib Gaus")
gaus.draw()
[27]:

আপনার pulse
নির্দিষ্ট করার জন্য আপনি যে পদ্ধতিটি ব্যবহার করেন না কেন, play
আপনার সময়সূচীতে একইভাবে যোগ করা হয়:
[28]:
with pulse.build() as schedule:
pulse.play(gaus, channel)
schedule.draw()
[28]:

আপনি একটি জটিল তালিকা বা অ্যারে সরাসরি play
তে সরবরাহ করতে পারেন
[29]:
with pulse.build() as schedule:
pulse.play([0.001*i for i in range(160)], channel)
schedule.draw()
[29]:

প্লে
নির্দেশটি তার পালস
থেকে এর সময়কাল পায়: একটি প্যারামেট্রাইজড পালসের সময়কাল একটি স্পষ্ট আর্গুমেন্ট, এবং একটি ওয়েভফর্ম
এর সময়কাল ইনপুট নমুনার সংখ্যা।
set_frequency
¶
পূর্বে ব্যাখ্যা করা হয়েছে, আউটপুট পালস তরঙ্গাকৃতি আচ্ছাদন এছাড়াও একটি ফ্রিকোয়েন্সি এবং ফেজ দ্বারা সংশোধন করা হয়। প্রতিটি চ্যানেলের একটি default frequency listed in the backend.defaults() আছে।
একটি চ্যানেলের ফ্রিকোয়েন্সি set_frequency
নির্দেশ দ্বারা একটি সময়সূচী
এর মধ্যে যে কোন সময় আপডেট করা যেতে পারে। এটি একটি float ফ্রিকোয়েন্সি
এবং একটি PulseChannel
চ্যানেল
ইনপুট হিসাবে নেয়। একটি set_frequency
নির্দেশ অনুসরণ করে একটি চ্যানেলে সমস্ত তড়িৎস্পন্দন বা পালস প্রদত্ত ফ্রিকোয়েন্সি দ্বারা মড্যুলেট করা হবে যতক্ষণ না অন্য একটি set_frequency
নির্দেশনা আসে অথবা প্রোগ্রাম শেষ না হওয়া পর্যন্ত।
নির্দেশটির 0
এর একটি অন্তর্নিহিত সময়কাল রয়েছে।
দ্রষ্টব্য: যে ফ্রিকোয়েন্সিগুলি অনুরোধ করা যেতে পারে তা মোট ব্যান্ডউইথ এবং প্রতিটি হার্ডওয়্যার চ্যানেলের তাৎক্ষণিক ব্যান্ডউইথ দ্বারা সীমাবদ্ধ। ভবিষ্যতে, এগুলি ব্যাকএন্ড
দ্বারা রিপোর্ট করা হবে।
[30]:
with pulse.build(backend) as schedule:
pulse.set_frequency(4.5e9, channel)
shift_phase
¶
Shift_phase
নির্দেশ ফ্রিকোয়েন্সি মড্যুলেশন এর ফেজ phase
দ্বারা বৃদ্ধি করবে। Set_frequency
এর মত, এই ফেজ শিফট প্রোগ্রাম শেষ না হওয়া পর্যন্ত একই চ্যানেলে নিম্নলিখিত সমস্ত নির্দেশাবলীকে প্রভাবিত করবে। একটি shift_phase
এর প্রভাব পূর্বাবস্থায় ফেরানোর জন্য, negative ফেজ
একটি নতুন নির্দেশে প্রেরণ করা যেতে পারে।
Set_frequency
এর মত, নির্দেশের 0
এর অন্তর্নিহিত সময়কাল রয়েছে।
[31]:
with pulse.build(backend) as schedule:
pulse.shift_phase(np.pi, channel)
acquire
¶
acquire
নির্দেশনাটি রিডআউট এর জন্য ডেটা অধিগ্রহণকে ট্রিগার করে। এটি একটি সময় নেয়, একটি AcquireChannel
যা পরিমাপকৃত কিউবিট, এবং একটি MemorySlot
বা RegisterSlot
কে ম্যাপ করে। MemorySlot
হল ক্লাসিক্যাল মেমরি যেখানে রিডআউট ফলাফল সংরক্ষণ করা হবে। RegisterSlot
কন্ট্রোল ইলেকট্রনিক্সের একটি রেজিস্টারে ম্যাপ করে যা দ্রুত প্রতিক্রিয়া জানার জন্য রিডআউট ফলাফল সংরক্ষণ করে।
acquire
নির্দেশাবলী কাস্টম Discriminator
s এবং Kernel
s গুলিকে কীওয়ার্ড আর্গুমেন্ট হিসাবে গ্রহণ করতে পারে।
[32]:
from qiskit.pulse import Acquire, AcquireChannel, MemorySlot
with pulse.build(backend) as schedule:
pulse.acquire(1200, pulse.acquire_channel(0), MemorySlot(0))
Now that we know how to add Schedule
instructions, let’s learn how to control exactly when they’re played.
পালস বিল্ডার¶
এখানে, আমরা কিভাবে সময়সূচী তৈরি করতে হয় তা শেখার জন্য সর্বাধিক গুরুত্বপূর্ণ পালস বিল্ডার এর বৈশিষ্ট্যগুলি পুনরালোচনা করবো। এটি সম্পূর্ণ নয়; পালস বিল্ডার ব্যবহার করে আপনি কি করতে পারেন সে সম্পর্কে আরো বিস্তারিত জানার জন্য, Pulse API reference <https://qiskit.org/documentation/apidoc/pulse.html> দেখুন।
প্রান্তিককরণ প্রসঙ্গ¶
বিল্ডার এর সারিবদ্ধকরণ প্রসঙ্গ রয়েছে যা একটি সময়সূচী কীভাবে তৈরি হয় তা প্রভাবিত করে। প্রসঙ্গগুলিও বাসা বাঁধতে পারে। তাদের চেষ্টা করে দেখুন, এবং pulse গুলি কিভাবে একত্রিত হয় তা দেখতে ".draw ()" ব্যবহার করুন।
Regardless of the alignment context, the duration of the resulting schedule is as short as it can be while including every instruction and following the alignment rules. This still allows some degrees of freedom for scheduling instructions off the "longest path". The examples below illuminate this.
align_left
¶
বিল্ডার এর সারিবদ্ধকরণ প্রসঙ্গ রয়েছে যা একটি সময়সূচী কীভাবে তৈরি হয় তা প্রভাবিত করে। ডিফল্ট হল "align_left"।
[33]:
with pulse.build(backend, name='Left align example') as program:
with pulse.align_left():
gaussian_pulse = library.gaussian(100, 0.5, 20)
pulse.play(gaussian_pulse, pulse.drive_channel(0))
pulse.play(gaussian_pulse, pulse.drive_channel(1))
pulse.play(gaussian_pulse, pulse.drive_channel(1))
program.draw()
[33]:

লক্ষ্য করুন কিভাবে "D1" এ পালস গুলির জন্য কোন নির্ধারিত স্বাধীনতা নেই। প্রথম তরঙ্গের পরপরই দ্বিতীয় তরঙ্গরূপ শুরু হয়। সামগ্রিক সময়সূচির সময়কাল পরিবর্তন না করে "D0" এর পালসটি "t = 0" এবং "t = 100" এর মধ্যে যেকোনো সময় শুরু হতে পারে। "Align_left" প্রসঙ্গ এই পালসটির শুরুর সময়কে "t = 0" এ সেট করে। আপনি এটিকে একটি টেক্সট ডকুমেন্টের বাম-ন্যায্যতার মতো ভাবতে পারেন।
align_right
¶
Unsurprisingly, align_right
does the opposite of align_left
. It will choose t=100
in the above example to begin the gaussian pulse on D0
. Left and right are also sometimes called "as soon as possible" and "as late as possible" scheduling, respectively.
[34]:
with pulse.build(backend, name='Right align example') as program:
with pulse.align_right():
gaussian_pulse = library.gaussian(100, 0.5, 20)
pulse.play(gaussian_pulse, pulse.drive_channel(0))
pulse.play(gaussian_pulse, pulse.drive_channel(1))
pulse.play(gaussian_pulse, pulse.drive_channel(1))
program.draw()
[34]:

align_equispaced(duration)
¶
যদি একটি নির্দিষ্ট ব্লকের সময়কাল জানা থাকে, আপনি প্রতিটি নির্দেশের মধ্যে একই সময়কাল বিলম্ব যুক্ত করতে align_equispaced
ব্যবহার করতে পারেন।
[35]:
with pulse.build(backend, name='example') as program:
gaussian_pulse = library.gaussian(100, 0.5, 20)
with pulse.align_equispaced(2*gaussian_pulse.duration):
pulse.play(gaussian_pulse, pulse.drive_channel(0))
pulse.play(gaussian_pulse, pulse.drive_channel(1))
pulse.play(gaussian_pulse, pulse.drive_channel(1))
program.draw()
[35]:

align_sequential
¶
এই প্রান্তিককরণ প্রসঙ্গ সমান্তরাল নির্দেশাবলী নির্ধারণ করে না। প্রতিটি নির্দেশ পূর্বে যোগ করা নির্দেশের শেষে শুরু হবে।
[36]:
with pulse.build(backend, name='example') as program:
with pulse.align_sequential():
gaussian_pulse = library.gaussian(100, 0.5, 20)
pulse.play(gaussian_pulse, pulse.drive_channel(0))
pulse.play(gaussian_pulse, pulse.drive_channel(1))
pulse.play(gaussian_pulse, pulse.drive_channel(1))
program.draw()
[36]:

ফেজ এবং ফ্রিকোয়েন্সি অফসেট¶
আমরা একটি চ্যানেলে আমাদের ফ্রিকোয়েন্সি বা পালস এর পর্যায়কে অস্থায়ীভাবে অফসেট করতে বিল্ডার এর সহায়তা নিতে পারি।
[37]:
with pulse.build(backend, name='Offset example') as program:
with pulse.phase_offset(3.14, pulse.drive_channel(0)):
pulse.play(gaussian_pulse, pulse.drive_channel(0))
with pulse.frequency_offset(10e6, pulse.drive_channel(0)):
pulse.play(gaussian_pulse, pulse.drive_channel(0))
program.draw()
[37]:

আরো জানার জন্য আমরা আপনাকে Pulse API reference দেখার জন্য উৎসাহিত করছি।
[38]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright
Version Information
Qiskit Software | Version |
---|---|
qiskit-terra | 0.22.3 |
qiskit-aer | 0.11.2 |
qiskit-ignis | 0.7.0 |
qiskit-ibmq-provider | 0.19.2 |
qiskit | 0.39.4 |
System information | |
Python version | 3.10.6 |
Python compiler | GCC 11.3.0 |
Python build | main, Nov 14 2022 16:10:14 |
OS | Linux |
CPUs | 4 |
Memory (Gb) | 3.7695083618164062 |
Thu Dec 22 18:42:20 2022 JST |
This code is a part of Qiskit
© Copyright IBM 2017, 2022.
This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.