ScheduleBlock
class ScheduleBlock(name=None, metadata=None, alignment_context=None)
Bases: object
Time-ordered sequence of instructions with alignment context.
ScheduleBlock
supports lazy scheduling of context instructions, i.e. their timeslots is always generated at runtime. This indicates we can parametrize instruction durations as well as other parameters. In contrast to Schedule
being somewhat static, ScheduleBlock
is a dynamic representation of a pulse program.
Pulse Builder
The Qiskit pulse builder is a domain specific language that is developed on top of the schedule block. Use of the builder syntax will improve the workflow of pulse programming. See Pulse Builder for a user guide.
Alignment contexts
A schedule block is always relatively scheduled. Instead of taking individual instructions with absolute execution time t0
, the schedule block defines a context of scheduling and instructions under the same context are scheduled in the same manner (alignment). Several contexts are available in Alignments. A schedule block is instantiated with one of these alignment contexts. The default context is AlignLeft
, for which all instructions are left-justified, in other words, meaning they use as-soon-as-possible scheduling.
If you need an absolute-time interval in between instructions, you can explicitly insert Delay
instructions.
Nested blocks
A schedule block can contain other nested blocks with different alignment contexts. This enables advanced scheduling, where a subset of instructions is locally scheduled in a different manner. Note that a Schedule
instance cannot be directly added to a schedule block. To add a Schedule
instance, wrap it in a Call
instruction. This is implicitly performed when a schedule is added through the Pulse Builder.
Unsupported operations
Because the schedule block representation lacks timeslots, it cannot perform particular Schedule
operations such as insert()
or shift()
that require instruction start time t0
. In addition, exclude()
and filter()
methods are not supported because these operations may identify the target instruction with t0
. Except for these operations, ScheduleBlock
provides full compatibility with Schedule
.
Subroutine
The timeslots-free representation offers much greater flexibility for writing pulse programs. Because ScheduleBlock
only cares about the ordering of the child blocks we can add an undefined pulse sequence as a subroutine of the main program. If your program contains the same sequence multiple times, this representation may reduce the memory footprint required by the program construction. Such a subroutine is realized by the special compiler directive Reference
that is defined by a unique set of reference key strings to the subroutine. The (executable) subroutine is separately stored in the main program. Appended reference directives are resolved when the main program is executed. Subroutines must be assigned through assign_references()
before execution.
Program Scoping
When you call a subroutine from another subroutine, or append a schedule block to another schedule block, the management of references and parameters can be a hard task. Schedule block offers a convenient feature to help with this by automatically scoping the parameters and subroutines.
from qiskit import pulse
from qiskit.circuit.parameter import Parameter
amp1 = Parameter("amp")
with pulse.build() as sched1:
pulse.play(pulse.Constant(100, amp1), pulse.DriveChannel(0))
print(sched1.scoped_parameters())
(Parameter(root::amp),)
The scoped_parameters()
method returns all Parameter
objects defined in the schedule block. The parameter name is updated to reflect its scope information, i.e. where it is defined. The outer scope is called “root”. Since the “amp” parameter is directly used in the current builder context, it is prefixed with “root”. Note that the Parameter
object returned by scoped_parameters()
preserves the hidden UUID key, and thus the scoped name doesn’t break references to the original Parameter
.
You may want to call this program from another program. In this example, the program is called with the reference key “grand_child”. You can call a subroutine without specifying a substantial program (like sched1
above which we will assign later).
amp2 = Parameter("amp")
with pulse.build() as sched2:
with pulse.align_right():
pulse.reference("grand_child")
pulse.play(pulse.Constant(200, amp2), pulse.DriveChannel(0))
print(sched2.scoped_parameters())
(Parameter(root::amp),)
This only returns “root::amp” because the “grand_child” reference is unknown. Now you assign the actual pulse program to this reference.
sched2.assign_references({("grand_child", ): sched1})
print(sched2.scoped_parameters())
(Parameter(root::amp), Parameter(root::grand_child::amp))
Now you get two parameters “root::amp” and “root::grand_child::amp”. The second parameter name indicates it is defined within the referred program “grand_child”. The program calling the “grand_child” has a reference program description which is accessed through ScheduleBlock.references
.
print(sched2.references)
ReferenceManager:
- ('grand_child',): ScheduleBlock(Play(Constant(duration=100, amp=amp,...
Finally, you may want to call this program from another program. Here we try a different approach to define subroutine. Namely, we call a subroutine from the root program with the actual program sched2
.
amp3 = Parameter("amp")
with pulse.build() as main:
pulse.play(pulse.Constant(300, amp3), pulse.DriveChannel(0))
pulse.call(sched2, name="child")
print(main.scoped_parameters())
(Parameter(root::amp), Parameter(root::child::amp), Parameter(root::child::grand_child::amp))
This implicitly creates a reference named “child” within the root program and assigns sched2
to it. You get three parameters “root::amp”, “root::child::amp”, and “root::child::grand_child::amp”. As you can see, each parameter name reflects the layer of calls from the root program. If you know the scope of a parameter, you can directly get the parameter object using ScheduleBlock.search_parameters()
as follows.
main.search_parameters("root::child::grand_child::amp")
You can use a regular expression to specify the scope. The following returns the parameters defined within the scope of “ground_child” regardless of its parent scope. This is sometimes convenient if you want to extract parameters from a deeply nested program.
main.search_parameters("\S::grand_child::amp")
Note that the root program is only aware of its direct references.
print(main.references)
ReferenceManager:
- ('child',): ScheduleBlock(ScheduleBlock(ScheduleBlock(Play(Con...
As you can see the main program cannot directly assign a subroutine to the “grand_child” because this subroutine is not called within the root program, i.e. it is indirectly called by “child”. However, the returned ReferenceManager
is a dict-like object, and you can still reach to “grand_child” via the “child” program with the following chained dict access.
main.references[("child", )].references[("grand_child", )]
Note that ScheduleBlock.parameters
and ScheduleBlock.scoped_parameters()
still collect all parameters also from the subroutine once it’s assigned.
Create an empty schedule block.
Parameters
- name (
Optional
[str
]) – Name of this schedule. Defaults to an autogenerated string if not provided. - metadata (
Optional
[dict
]) – Arbitrary key value metadata to associate with the schedule. This gets stored as free-form data in a dict in themetadata
attribute. It will not be directly used in the schedule. - alignment_context (AlignmentKind) –
AlignmentKind
instance that manages scheduling of instructions in this block.
Raises
TypeError – if metadata is not a dict.
Methods
append
ScheduleBlock.append(block, name=None, inplace=True)
Return a new schedule block with block
appended to the context block. The execution time is automatically assigned when the block is converted into schedule.
Parameters
- block (
Union
[ScheduleBlock
,Instruction
]) – ScheduleBlock to be appended. - name (
Optional
[str
]) – Name of the newSchedule
. Defaults to name ofself
. - inplace (
bool
) – Perform operation inplace on this schedule. Otherwise, return a newSchedule
.
Return type
Returns
Schedule block with appended schedule.
Raises
PulseError – When invalid schedule type is specified.
assign_parameters
ScheduleBlock.assign_parameters(value_dict, inplace=True)
Assign the parameters in this schedule according to the input.
Parameters
- value_dict (
Dict
[ParameterExpression
,Union
[ParameterExpression
,float
]]) – A mapping from Parameters to either numeric values or another Parameter expression. - inplace (
bool
) – SetTrue
to override this instance with new parameter.
Return type
Returns
Schedule with updated parameters.
Raises
PulseError – When the block is nested into another block.
assign_references
ScheduleBlock.assign_references(subroutine_dict, inplace=True)
Assign schedules to references.
It is only capable of assigning a schedule block to immediate references which are directly referred within the current scope. Let’s see following example:
from qiskit import pulse
with pulse.build() as subroutine:
pulse.delay(10, pulse.DriveChannel(0))
with pulse.build() as sub_prog:
pulse.reference("A")
with pulse.build() as main_prog:
pulse.reference("B")
In above example, the main_prog
can refer to the subroutine “root::B” and the reference of “B” to program “A”, i.e., “B::A”, is not defined in the root namespace. This prevents breaking the reference “root::B::A” by the assignment of “root::B”. For example, if a user could indirectly assign “root::B::A” from the root program, one can later assign another program to “root::B” that doesn’t contain “A” within it. In this situation, a reference “root::B::A” would still live in the reference manager of the root. However, the subroutine “root::B::A” would no longer be used in the actual pulse program. To assign subroutine “A” to nested_prog
as a nested subprogram of main_prog
, you must first assign “A” of the sub_prog
, and then assign the sub_prog
to the main_prog
.
sub_prog.assign_references({("A", ): nested_prog}, inplace=True)
main_prog.assign_references({("B", ): sub_prog}, inplace=True)
Alternatively, you can also write
main_prog.assign_references({("B", ): sub_prog}, inplace=True)
main_prog.references[("B", )].assign_references({"A": nested_prog}, inplace=True)
Here references
returns a dict-like object, and you can mutably update the nested reference of the particular subroutine.
Assigned programs are deep-copied to prevent an unexpected update.
Parameters
- subroutine_dict (
Dict
[Union
[str
,Tuple
[str
,...
]],ScheduleBlock
]) – A mapping from reference key to schedule block of the subroutine. - inplace (
bool
) – SetTrue
to override this instance with new subroutine.
Return type
Returns
Schedule block with assigned subroutine.
Raises
PulseError – When reference key is not defined in the current scope.
ch_duration
ScheduleBlock.ch_duration(*channels)
Return the time of the end of the last instruction over the supplied channels.
Parameters
*channels – Channels within self
to include.
Return type
int
draw
ScheduleBlock.draw(style=None, backend=None, time_range=None, time_unit='dt', disable_channels=None, show_snapshot=True, show_framechange=True, show_waveform_info=True, show_barrier=True, plotter='mpl2d', axis=None)
Plot the schedule.
Parameters
-
style (
Optional
[Dict
[str
,Any
]]) – Stylesheet options. This can be dictionary or preset stylesheet classes. SeeIQXStandard
,IQXSimple
, andIQXDebugging
for details of preset stylesheets. -
backend (Optional[BaseBackend]) – Backend object to play the input pulse program. If provided, the plotter may use to make the visualization hardware aware.
-
time_range (
Optional
[Tuple
[int
,int
]]) – Set horizontal axis limit. Tuple (tmin, tmax). -
time_unit (
str
) – The unit of specified time range either dt or ns. The unit of ns is available only when backend object is provided. -
disable_channels (
Optional
[List
[Channel
]]) – A control property to show specific pulse channel. Pulse channel instances provided as a list are not shown in the output image. -
show_snapshot (
bool
) – Show snapshot instructions. -
show_framechange (
bool
) – Show frame change instructions. The frame change represents instructions that modulate phase or frequency of pulse channels. -
show_waveform_info (
bool
) – Show additional information about waveforms such as their name. -
show_barrier (
bool
) – Show barrier lines. -
plotter (
str
) –Name of plotter API to generate an output image. One of following APIs should be specified:
mpl2d: Matplotlib API for 2D image generation. Matplotlib API to generate 2D image. Charts are placed along y axis with vertical offset. This API takes matplotlib.axes.Axes as ``axis`` input.
axis
andstyle
kwargs may depend on the plotter. -
axis (
Optional
[Any
]) – Arbitrary object passed to the plotter. If this object is provided, the plotters use a givenaxis
instead of internally initializing a figure object. This object format depends on the plotter. See plotter argument for details.
Returns
Visualization output data. The returned data type depends on the plotter
. If matplotlib family is specified, this will be a matplotlib.pyplot.Figure
data.
exclude
ScheduleBlock.exclude(*filter_funcs, channels=None, instruction_types=None, time_ranges=None, intervals=None, check_subroutine=True)
Return a Schedule
with only the instructions from this Schedule failing at least one of the provided filters. This method is the complement of py:meth:~self.filter, so that:
self.filter(args) | self.exclude(args) == self
This method is currently not supported. Support will be soon added please create an issue if you believe this must be prioritized.
Parameters
- filter_funcs (
List
[Callable
]) – A list of Callables which take a (int, Union[‘Schedule’, Instruction]) tuple and return a bool. - channels (
Optional
[Iterable
[Channel
]]) – For example,[DriveChannel(0), AcquireChannel(0)]
. - instruction_types (
Union
[Iterable
[ABCMeta
],ABCMeta
,None
]) – For example,[PulseInstruction, AcquireInstruction]
. - time_ranges (
Optional
[Iterable
[Tuple
[int
,int
]]]) – For example,[(0, 5), (6, 10)]
. - intervals (
Optional
[Iterable
[Tuple
[int
,int
]]]) – For example,[(0, 5), (6, 10)]
. - check_subroutine (
bool
) – Set True to individually filter instructions inside of a subroutine defined by theCall
instruction.
Returns
Schedule
consisting of instructions that are not match with filtering condition.
Raises
PulseError – When this method is called. This method will be supported soon.
filter
ScheduleBlock.filter(*filter_funcs, channels=None, instruction_types=None, time_ranges=None, intervals=None, check_subroutine=True)
Return a new Schedule
with only the instructions from this ScheduleBlock
which pass though the provided filters; i.e. an instruction will be retained iff every function in filter_funcs
returns True
, the instruction occurs on a channel type contained in channels
, the instruction type is contained in instruction_types
, and the period over which the instruction operates is fully contained in one specified in time_ranges
or intervals
.
If no arguments are provided, self
is returned.
This method is currently not supported. Support will be soon added please create an issue if you believe this must be prioritized.
Parameters
- filter_funcs (
List
[Callable
]) – A list of Callables which take a (int, Union[‘Schedule’, Instruction]) tuple and return a bool. - channels (
Optional
[Iterable
[Channel
]]) – For example,[DriveChannel(0), AcquireChannel(0)]
. - instruction_types (
Union
[Iterable
[ABCMeta
],ABCMeta
,None
]) – For example,[PulseInstruction, AcquireInstruction]
. - time_ranges (
Optional
[Iterable
[Tuple
[int
,int
]]]) – For example,[(0, 5), (6, 10)]
. - intervals (
Optional
[Iterable
[Tuple
[int
,int
]]]) – For example,[(0, 5), (6, 10)]
. - check_subroutine (
bool
) – Set True to individually filter instructions inside a subroutine defined by theCall
instruction.
Returns
Schedule
consisting of instructions that matches with filtering condition.
Raises
PulseError – When this method is called. This method will be supported soon.
get_parameters
ScheduleBlock.get_parameters(parameter_name)
Get parameter object bound to this schedule by string name.
Note that we can define different parameter objects with the same name, because these different objects are identified by their unique uuid. For example,
from qiskit import pulse, circuit
amp1 = circuit.Parameter("amp")
amp2 = circuit.Parameter("amp")
with pulse.build() as sub_prog:
pulse.play(pulse.Constant(100, amp1), pulse.DriveChannel(0))
with pulse.build() as main_prog:
pulse.call(sub_prog, name="sub")
pulse.play(pulse.Constant(100, amp2), pulse.DriveChannel(0))
main_prog.get_parameters("amp")
This returns a list of two parameters amp1
and amp2
.
Parameters
parameter_name (str
) – Name of parameter.
Return type
List
[Parameter
]
Returns
Parameter objects that have corresponding name.
initialize_from
classmethod ScheduleBlock.initialize_from(other_program, name=None)
Create new schedule object with metadata of another schedule object.
Parameters
- other_program (
Any
) – Qiskit program that provides metadata to new object. - name (
Optional
[str
]) – Name of new schedule. Name ofblock
is used by default.
Return type
Returns
New block object with name and metadata.
Raises
PulseError – When other_program
does not provide necessary information.
is_parameterized
ScheduleBlock.is_parameterized()
Return True iff the instruction is parameterized.
Return type
bool
is_referenced
ScheduleBlock.is_referenced()
Return True iff the current schedule block contains reference to subroutine.
Return type
bool
is_schedulable
ScheduleBlock.is_schedulable()
Return True
if all durations are assigned.
Return type
bool
replace
ScheduleBlock.replace(old, new, inplace=True)
Return a ScheduleBlock
with the old
component replaced with a new
component.
Parameters
- old (
Union
[ScheduleBlock
,Instruction
]) – Schedule block component to replace. - new (
Union
[ScheduleBlock
,Instruction
]) – Schedule block component to replace with. - inplace (
bool
) – Replace instruction by mutably modifying thisScheduleBlock
.
Return type
Returns
The modified schedule block with old
replaced by new
.
scoped_parameters
ScheduleBlock.scoped_parameters()
Return unassigned parameters with scoped names.
If a parameter is defined within a nested scope, it is prefixed with all parent-scope names with the delimiter string, which is “::”. If a reference key of the scope consists of multiple key strings, it will be represented by a single string joined with “,”. For example, “root::xgate,q0::amp” for the parameter “amp” defined in the reference specified by the key strings (“xgate”, “q0”).
Return type
Tuple
[Parameter
]
search_parameters
ScheduleBlock.search_parameters(parameter_regex)
Search parameter with regular expression.
This method looks for the scope-aware parameters. For example,
from qiskit import pulse, circuit
amp1 = circuit.Parameter("amp")
amp2 = circuit.Parameter("amp")
with pulse.build() as sub_prog:
pulse.play(pulse.Constant(100, amp1), pulse.DriveChannel(0))
with pulse.build() as main_prog:
pulse.call(sub_prog, name="sub")
pulse.play(pulse.Constant(100, amp2), pulse.DriveChannel(0))
main_prog.search_parameters("root::sub::amp")
This finds amp1
with scoped name “root::sub::amp”.
Parameters
parameter_regex (str
) – Regular expression for scoped parameter name.
Return type
List
[Parameter
]
Returns
Parameter objects that have corresponding name.
Attributes
alignment_context
Return alignment instance that allocates block component to generate schedule.
blocks
Get the block elements added to self.
The sequence of elements is returned in order of addition. Because the first element is schedule first, e.g. FIFO, the returned sequence is roughly time-ordered. However, in the parallel alignment context, especially in the as-late-as-possible scheduling, or AlignRight
context, the actual timing of when the instructions are issued is unknown until the ScheduleBlock
is scheduled and converted into a Schedule
.
Return type
Tuple
[Union
[ScheduleBlock
, Instruction
], ...
]
channels
duration
Duration of this schedule block.
Return type
int
instances_counter
Default value: count(9)
instructions
metadata
The user provided metadata associated with the schedule.
User provided dict
of metadata for the schedule. The metadata contents do not affect the semantics of the program but are used to influence the execution of the schedule. It is expected to be passed between all transforms of the schedule and that providers will associate any schedule metadata with the results it returns from the execution of that schedule.
Return type
Dict
[str
, Any
]
name
Return name of this schedule
Return type
str
parameters
prefix
Default value: 'block'
references
Return a reference manager of the current scope.
Return type
ReferenceManager