diff --git a/qiskit/pulse/__init__.py b/qiskit/pulse/__init__.py index f8938aa075f8..58f13cda060e 100644 --- a/qiskit/pulse/__init__.py +++ b/qiskit/pulse/__init__.py @@ -126,7 +126,6 @@ from qiskit.pulse.instruction_schedule_map import InstructionScheduleMap from qiskit.pulse.instructions import ( Acquire, - Call, Delay, Instruction, Play, diff --git a/qiskit/pulse/instructions/__init__.py b/qiskit/pulse/instructions/__init__.py index 3e0de5ab6f29..e97ac27fc62f 100644 --- a/qiskit/pulse/instructions/__init__.py +++ b/qiskit/pulse/instructions/__init__.py @@ -41,7 +41,6 @@ :toctree: ../stubs/ Acquire - Call Reference Delay Play @@ -60,7 +59,6 @@ from .acquire import Acquire from .delay import Delay from .directives import Directive, RelativeBarrier, TimeBlockade -from .call import Call from .instruction import Instruction from .frequency import SetFrequency, ShiftFrequency from .phase import ShiftPhase, SetPhase diff --git a/qiskit/pulse/instructions/call.py b/qiskit/pulse/instructions/call.py deleted file mode 100644 index 8a5416f57e1c..000000000000 --- a/qiskit/pulse/instructions/call.py +++ /dev/null @@ -1,177 +0,0 @@ -# This code is part of Qiskit. -# -# (C) Copyright IBM 2020, 2021, 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. - -"""Call instruction that represents calling a schedule as a subroutine.""" -from __future__ import annotations - -from qiskit.circuit.parameterexpression import ParameterExpression, ParameterValueType -from qiskit.pulse.channels import Channel -from qiskit.pulse.exceptions import PulseError -from qiskit.pulse.instructions import instruction -from qiskit.utils.deprecation import deprecate_func - - -class Call(instruction.Instruction): - """Pulse ``Call`` instruction. - - The ``Call`` instruction represents the calling of a referenced subroutine (schedule). - It enables code reuse both within the pulse representation and hardware (if supported). - """ - - # Prefix to use for auto naming. - prefix = "call" - - @deprecate_func( - since="0.25.0", - package_name="qiskit-terra", - additional_msg="Instead, use the pulse builder function " - "qiskit.pulse.builder.call(subroutine) within an active building context.", - ) - def __init__( - self, - subroutine, - value_dict: dict[ParameterExpression, ParameterValueType] | None = None, - name: str | None = None, - ): - """Define new subroutine. - - .. note:: Inline subroutine is mutable. This requires special care for modification. - - Args: - subroutine (Union[Schedule, ScheduleBlock]): A program subroutine to be referred to. - value_dict: Mapping of parameter object to assigned value. - name: Unique ID of this subroutine. If not provided, this is generated based on - the subroutine name. - - Raises: - PulseError: If subroutine is not valid data format. - """ - from qiskit.pulse.schedule import Schedule, ScheduleBlock - - if not isinstance(subroutine, (Schedule, ScheduleBlock)): - raise PulseError(f"Subroutine type {subroutine.__class__.__name__} cannot be called.") - - value_dict = value_dict or {} - - # initialize parameter template - if subroutine.is_parameterized(): - self._arguments: dict[ParameterExpression, ParameterValueType] = { - par: value_dict.get(par, par) for par in subroutine.parameters - } - assigned_subroutine = subroutine.assign_parameters( - value_dict=self.arguments, inplace=False - ) - else: - self._arguments = {} - assigned_subroutine = subroutine - - # create cache data of parameter-assigned subroutine - self._assigned_cache = (self._get_arg_hash(), assigned_subroutine) - - super().__init__(operands=(subroutine,), name=name or f"{self.prefix}_{subroutine.name}") - - @property - def duration(self) -> int | ParameterExpression: - """Duration of this instruction.""" - return self.subroutine.duration - - @property - def channels(self) -> tuple[Channel]: - """Returns the channels that this schedule uses.""" - return self.assigned_subroutine().channels - - @property - def subroutine(self): - """Return attached subroutine. - - Returns: - program (Union[Schedule, ScheduleBlock]): The program referenced by the call. - """ - return self.operands[0] - - def assigned_subroutine(self): - """Returns this subroutine with the parameters assigned. - - .. note:: This function may be often called internally for class equality check - despite its overhead of parameter assignment. - The subroutine with parameter assigned is cached based on ``.argument`` hash. - Once this argument is updated, new assigned instance will be returned. - Note that this update is not mutable operation. - - Returns: - program (Union[Schedule, ScheduleBlock]): Attached program. - """ - if self._get_arg_hash() != self._assigned_cache[0]: - subroutine = self.subroutine.assign_parameters(value_dict=self.arguments, inplace=False) - # update cache data - self._assigned_cache = (self._get_arg_hash(), subroutine) - else: - subroutine = self._assigned_cache[1] - - return subroutine - - @property - def parameters(self) -> set: - """Unassigned parameters which determine the instruction behavior.""" - params = set() - for value in self._arguments.values(): - if isinstance(value, ParameterExpression): - params |= value.parameters - return params - - @property - def arguments(self) -> dict[ParameterExpression, ParameterValueType]: - """Parameters dictionary to be assigned to subroutine.""" - return self._arguments - - @arguments.setter - def arguments(self, new_arguments: dict[ParameterExpression, ParameterValueType]): - """Set new arguments. - - Args: - new_arguments: Dictionary of new parameter value mapping to update. - - Raises: - PulseError: When new arguments doesn't match with existing arguments. - """ - # validation - if new_arguments.keys() != self._arguments.keys(): - new_arg_names = ", ".join(map(repr, new_arguments.keys())) - old_arg_names = ", ".join(map(repr, self.arguments.keys())) - raise PulseError( - "Key mismatch between new arguments and existing arguments. " - f"{new_arg_names} != {old_arg_names}" - ) - - self._arguments = new_arguments - - def _get_arg_hash(self): - """A helper function to generate hash of parameters.""" - return hash(tuple(self.arguments.items())) - - def __eq__(self, other: object) -> bool: - """Check if this instruction is equal to the `other` instruction. - - Instructions are equal if they share the same type, operands, and channels. - """ - # type check - if not isinstance(other, self.__class__): - return False - - # compare subroutine. assign parameter values before comparison - if self.assigned_subroutine() != other.assigned_subroutine(): - return False - - return True - - def __repr__(self) -> str: - return f"{self.__class__.__name__}({self.assigned_subroutine()}, name='{self.name}')" diff --git a/qiskit/pulse/parameter_manager.py b/qiskit/pulse/parameter_manager.py index e9e3cfbb9967..5c8163cb10fe 100644 --- a/qiskit/pulse/parameter_manager.py +++ b/qiskit/pulse/parameter_manager.py @@ -162,24 +162,6 @@ def visit_AlignmentKind(self, node: AlignmentKind): # Mid layer: Assign parameters to instructions - def visit_Call(self, node: instructions.Call): - """Assign parameters to ``Call`` instruction. - - .. note:: ``Call`` instruction has a special parameter handling logic. - This instruction separately keeps program, i.e. parametrized schedule, - and bound parameters until execution. The parameter assignment operation doesn't - immediately override its operand data. - """ - if node.is_parameterized(): - new_table = copy(node.arguments) - - for parameter, value in new_table.items(): - if isinstance(value, ParameterExpression): - new_table[parameter] = self._assign_parameter_expression(value) - node.arguments = new_table - - return node - def visit_Instruction(self, node: instructions.Instruction): """Assign parameters to general pulse instruction. @@ -300,14 +282,6 @@ def visit_AlignmentKind(self, node: AlignmentKind): # Mid layer: Get parameters from instructions - def visit_Call(self, node: instructions.Call): - """Get parameters from ``Call`` instruction. - - .. note:: ``Call`` instruction has a special parameter handling logic. - This instruction separately keeps parameters and program. - """ - self.parameters |= node.parameters - def visit_Instruction(self, node: instructions.Instruction): """Get parameters from general pulse instruction. diff --git a/qiskit/pulse/transforms/canonicalization.py b/qiskit/pulse/transforms/canonicalization.py index 931bf36ef7a9..9bda5907c2fe 100644 --- a/qiskit/pulse/transforms/canonicalization.py +++ b/qiskit/pulse/transforms/canonicalization.py @@ -171,16 +171,7 @@ def _inline_schedule(schedule: Schedule) -> Schedule: for t0, inst in schedule.children: # note that schedule.instructions unintentionally flatten the nested schedule. # this should be performed by another transformer node. - if isinstance(inst, instructions.Call): - # bind parameter - subroutine = inst.assigned_subroutine() - # convert into schedule if block is given - if isinstance(subroutine, ScheduleBlock): - subroutine = block_to_schedule(subroutine) - # recursively inline the program - inline_schedule = _inline_schedule(subroutine) - ret_schedule.insert(t0, inline_schedule, inplace=True) - elif isinstance(inst, Schedule): + if isinstance(inst, Schedule): # recursively inline the program inline_schedule = _inline_schedule(inst) ret_schedule.insert(t0, inline_schedule, inplace=True) @@ -196,19 +187,7 @@ def _inline_block(block: ScheduleBlock) -> ScheduleBlock: """ ret_block = ScheduleBlock.initialize_from(block) for inst in block.blocks: - if isinstance(inst, instructions.Call): - # bind parameter - subroutine = inst.assigned_subroutine() - if isinstance(subroutine, Schedule): - raise PulseError( - f"A subroutine {subroutine.name} is a pulse Schedule. " - "This program cannot be inserted into ScheduleBlock because " - "t0 associated with instruction will be lost." - ) - # recursively inline the program - inline_block = _inline_block(subroutine) - ret_block.append(inline_block, inplace=True) - elif isinstance(inst, ScheduleBlock): + if isinstance(inst, ScheduleBlock): # recursively inline the program inline_block = _inline_block(inst) ret_block.append(inline_block, inplace=True) diff --git a/releasenotes/notes/deprecate-pulse-instruction-call-52dca0dd26e1c768.yaml b/releasenotes/notes/deprecate-pulse-instruction-call-52dca0dd26e1c768.yaml new file mode 100644 index 000000000000..bb6d2ce66357 --- /dev/null +++ b/releasenotes/notes/deprecate-pulse-instruction-call-52dca0dd26e1c768.yaml @@ -0,0 +1,5 @@ +--- +upgrade: + - | + Removed the deprecated class :class:`qiskit.pulse.instructions.Call`. + No alternative pulse instruction is provided. diff --git a/test/python/pulse/test_block.py b/test/python/pulse/test_block.py index 11c71027645d..0ddd645d8bcf 100644 --- a/test/python/pulse/test_block.py +++ b/test/python/pulse/test_block.py @@ -657,26 +657,6 @@ def test_get_assigend_duration(self): self.assertEqual(block.duration, 400) - def test_nested_parametrized_instructions(self): - """Test parameters of nested schedule can be assigned.""" - test_waveform = pulse.Constant(100, self.amp0) - - param_sched = pulse.Schedule(pulse.Play(test_waveform, self.d0)) - with self.assertWarns(DeprecationWarning): - call_inst = pulse.instructions.Call(param_sched) - - sub_block = pulse.ScheduleBlock() - sub_block += call_inst - - block = pulse.ScheduleBlock() - block += sub_block - - self.assertTrue(block.is_parameterized()) - - # assign durations - block = block.assign_parameters({self.amp0: 0.1}) - self.assertFalse(block.is_parameterized()) - def test_equality_of_parametrized_channels(self): """Test check equality of blocks involving parametrized channels.""" par_ch = circuit.Parameter("ch") diff --git a/test/python/pulse/test_builder.py b/test/python/pulse/test_builder.py index f888182f490b..67f34607444c 100644 --- a/test/python/pulse/test_builder.py +++ b/test/python/pulse/test_builder.py @@ -821,8 +821,7 @@ def test_call(self): reference += instructions.Delay(20, d1) ref_sched = pulse.Schedule() - with self.assertWarns(DeprecationWarning): - ref_sched += pulse.instructions.Call(reference) + ref_sched += reference with pulse.build() as schedule: with pulse.align_right(): diff --git a/test/python/pulse/test_instructions.py b/test/python/pulse/test_instructions.py index 6699892ee2d7..480972ef0fd0 100644 --- a/test/python/pulse/test_instructions.py +++ b/test/python/pulse/test_instructions.py @@ -14,9 +14,8 @@ import numpy as np -from qiskit import pulse, circuit +from qiskit import circuit from qiskit.pulse import channels, configuration, instructions, library, exceptions -from qiskit.pulse.transforms import inline_subroutines, target_qobj_transform from qiskit.test import QiskitTestCase @@ -324,89 +323,3 @@ def test_relative_barrier(self): self.assertEqual(barrier.duration, 0) self.assertEqual(barrier.channels, chans) self.assertEqual(barrier.operands, chans) - - -class TestCall(QiskitTestCase): - """Test call instruction.""" - - def setUp(self): - super().setUp() - - with pulse.build() as _subroutine: - pulse.delay(10, pulse.DriveChannel(0)) - self.subroutine = _subroutine - - self.param1 = circuit.Parameter("amp1") - self.param2 = circuit.Parameter("amp2") - with pulse.build() as _function: - pulse.play(pulse.Gaussian(160, self.param1, 40), pulse.DriveChannel(0)) - pulse.play(pulse.Gaussian(160, self.param2, 40), pulse.DriveChannel(0)) - pulse.play(pulse.Gaussian(160, self.param1, 40), pulse.DriveChannel(0)) - self.function = _function - - def test_call(self): - """Test basic call instruction.""" - with self.assertWarns(DeprecationWarning): - call = instructions.Call(subroutine=self.subroutine) - - self.assertEqual(call.duration, 10) - self.assertEqual(call.subroutine, self.subroutine) - - def test_parameterized_call(self): - """Test call instruction with parameterized subroutine.""" - with self.assertWarns(DeprecationWarning): - call = instructions.Call(subroutine=self.function) - - self.assertTrue(call.is_parameterized()) - self.assertEqual(len(call.parameters), 2) - - def test_assign_parameters_to_call(self): - """Test create schedule by calling subroutine and assign parameters to it.""" - init_dict = {self.param1: 0.1, self.param2: 0.5} - - with pulse.build() as test_sched: - pulse.call(self.function) - - test_sched = test_sched.assign_parameters(value_dict=init_dict) - test_sched = inline_subroutines(test_sched) - - with pulse.build() as ref_sched: - pulse.play(pulse.Gaussian(160, 0.1, 40), pulse.DriveChannel(0)) - pulse.play(pulse.Gaussian(160, 0.5, 40), pulse.DriveChannel(0)) - pulse.play(pulse.Gaussian(160, 0.1, 40), pulse.DriveChannel(0)) - - self.assertEqual(target_qobj_transform(test_sched), target_qobj_transform(ref_sched)) - - def test_call_initialize_with_parameter(self): - """Test call instruction with parameterized subroutine with initial dict.""" - init_dict = {self.param1: 0.1, self.param2: 0.5} - with self.assertWarns(DeprecationWarning): - call = instructions.Call(subroutine=self.function, value_dict=init_dict) - - with pulse.build() as ref_sched: - pulse.play(pulse.Gaussian(160, 0.1, 40), pulse.DriveChannel(0)) - pulse.play(pulse.Gaussian(160, 0.5, 40), pulse.DriveChannel(0)) - pulse.play(pulse.Gaussian(160, 0.1, 40), pulse.DriveChannel(0)) - - self.assertEqual( - target_qobj_transform(call.assigned_subroutine()), target_qobj_transform(ref_sched) - ) - - def test_call_subroutine_with_different_parameters(self): - """Test call subroutines with different parameters in the same schedule.""" - init_dict1 = {self.param1: 0.1, self.param2: 0.5} - init_dict2 = {self.param1: 0.3, self.param2: 0.7} - - with pulse.build() as test_sched: - pulse.call(self.function, value_dict=init_dict1) - pulse.call(self.function, value_dict=init_dict2) - - with pulse.build() as ref_sched: - pulse.play(pulse.Gaussian(160, 0.1, 40), pulse.DriveChannel(0)) - pulse.play(pulse.Gaussian(160, 0.5, 40), pulse.DriveChannel(0)) - pulse.play(pulse.Gaussian(160, 0.1, 40), pulse.DriveChannel(0)) - pulse.play(pulse.Gaussian(160, 0.3, 40), pulse.DriveChannel(0)) - pulse.play(pulse.Gaussian(160, 0.7, 40), pulse.DriveChannel(0)) - pulse.play(pulse.Gaussian(160, 0.3, 40), pulse.DriveChannel(0)) - - self.assertEqual(target_qobj_transform(test_sched), target_qobj_transform(ref_sched)) diff --git a/test/python/pulse/test_parameter_manager.py b/test/python/pulse/test_parameter_manager.py index a44bc3d2ed63..5f180c035600 100644 --- a/test/python/pulse/test_parameter_manager.py +++ b/test/python/pulse/test_parameter_manager.py @@ -78,9 +78,6 @@ def setUp(self): subroutine += pulse.ShiftPhase(self.phi1, self.d1) subroutine += pulse.Play(self.parametric_waveform1, self.d1) - sched = pulse.Schedule() - sched += pulse.ShiftPhase(self.phi3, self.d3) - long_schedule = pulse.ScheduleBlock( alignment_context=AlignEquispaced(self.context_dur), name="long_schedule" ) @@ -88,8 +85,7 @@ def setUp(self): long_schedule += subroutine long_schedule += pulse.ShiftPhase(self.phi2, self.d2) long_schedule += pulse.Play(self.parametric_waveform2, self.d2) - with self.assertWarns(DeprecationWarning): - long_schedule += pulse.Call(sched) + long_schedule += pulse.ShiftPhase(self.phi3, self.d3) long_schedule += pulse.Play(self.parametric_waveform3, self.d3) long_schedule += pulse.Acquire( @@ -149,21 +145,6 @@ def test_get_parameter_from_inst(self): self.assertSetEqual(visitor.parameters, ref_params) - def test_get_parameter_from_call(self): - """Test get parameters from instruction.""" - sched = pulse.Schedule() - sched += pulse.ShiftPhase(self.phi1, self.d1) - - with self.assertWarns(DeprecationWarning): - test_obj = pulse.Call(subroutine=sched) - - visitor = ParameterGetter() - visitor.visit(test_obj) - - ref_params = {self.phi1, self.ch1} - - self.assertSetEqual(visitor.parameters, ref_params) - def test_with_function(self): """Test ParameterExpressions formed trivially in a function.""" @@ -255,27 +236,6 @@ def test_set_parameter_to_inst(self): self.assertEqual(assigned, ref_obj) - def test_set_parameter_to_call(self): - """Test get parameters from instruction.""" - sched = pulse.Schedule() - sched += pulse.ShiftPhase(self.phi1, self.d1) - - with self.assertWarns(DeprecationWarning): - test_obj = pulse.Call(subroutine=sched) - - value_dict = {self.phi1: 1.57, self.ch1: 2} - - visitor = ParameterSetter(param_map=value_dict) - assigned = visitor.visit(test_obj) - - ref_sched = pulse.Schedule() - ref_sched += pulse.ShiftPhase(1.57, pulse.DriveChannel(2)) - - with self.assertWarns(DeprecationWarning): - ref_obj = pulse.Call(subroutine=ref_sched) - - self.assertEqual(assigned, ref_obj) - def test_with_function(self): """Test ParameterExpressions formed trivially in a function.""" @@ -314,8 +274,8 @@ def test_nested_assignment_partial_bind(self): subroutine += pulse.Play(self.parametric_waveform1, self.d1) nested_block = pulse.ScheduleBlock() - with self.assertWarns(DeprecationWarning): - nested_block += pulse.Call(subroutine=subroutine) + + nested_block += subroutine test_obj = pulse.ScheduleBlock() test_obj += nested_block @@ -480,16 +440,12 @@ def test_set_parameter_to_complex_schedule(self): subroutine += pulse.ShiftPhase(1.0, pulse.DriveChannel(0)) subroutine += pulse.Play(pulse.Gaussian(100, 0.3, 25), pulse.DriveChannel(0)) - sched = pulse.Schedule() - sched += pulse.ShiftPhase(3.0, pulse.DriveChannel(4)) - ref_obj = pulse.ScheduleBlock(alignment_context=AlignEquispaced(1000), name="long_schedule") ref_obj += subroutine ref_obj += pulse.ShiftPhase(2.0, pulse.DriveChannel(2)) ref_obj += pulse.Play(pulse.Gaussian(125, 0.3, 25), pulse.DriveChannel(2)) - with self.assertWarns(DeprecationWarning): - ref_obj += pulse.Call(sched) + ref_obj += pulse.ShiftPhase(3.0, pulse.DriveChannel(4)) ref_obj += pulse.Play(pulse.Gaussian(150, 0.4, 25), pulse.DriveChannel(4)) ref_obj += pulse.Acquire( @@ -531,73 +487,6 @@ def test_parametric_pulses(self): self.assertEqual(block.blocks[0].pulse.amp, 0.2) self.assertEqual(block.blocks[0].pulse.sigma, 4.0) - def test_parameters_from_subroutine(self): - """Test that get parameter objects from subroutines.""" - param1 = Parameter("amp") - waveform = pulse.library.Constant(duration=100, amp=param1) - - program_layer0 = pulse.Schedule() - program_layer0 += pulse.Play(waveform, pulse.DriveChannel(0)) - - # from call instruction - program_layer1 = pulse.Schedule() - with self.assertWarns(DeprecationWarning): - program_layer1 += pulse.instructions.Call(program_layer0) - self.assertEqual(program_layer1.get_parameters("amp")[0], param1) - - # from nested call instruction - program_layer2 = pulse.Schedule() - with self.assertWarns(DeprecationWarning): - program_layer2 += pulse.instructions.Call(program_layer1) - self.assertEqual(program_layer2.get_parameters("amp")[0], param1) - - def test_assign_parameter_to_subroutine(self): - """Test that assign parameter objects to subroutines.""" - param1 = Parameter("amp") - waveform = pulse.library.Constant(duration=100, amp=param1) - - program_layer0 = pulse.Schedule() - program_layer0 += pulse.Play(waveform, pulse.DriveChannel(0)) - reference = program_layer0.assign_parameters({param1: 0.1}, inplace=False) - - # to call instruction - program_layer1 = pulse.Schedule() - with self.assertWarns(DeprecationWarning): - program_layer1 += pulse.instructions.Call(program_layer0) - target = program_layer1.assign_parameters({param1: 0.1}, inplace=False) - self.assertEqual(inline_subroutines(target), reference) - - # to nested call instruction - program_layer2 = pulse.Schedule() - with self.assertWarns(DeprecationWarning): - program_layer2 += pulse.instructions.Call(program_layer1) - target = program_layer2.assign_parameters({param1: 0.1}, inplace=False) - self.assertEqual(inline_subroutines(target), reference) - - def test_assign_parameter_to_subroutine_parameter(self): - """Test that assign parameter objects to parameter of subroutine.""" - param1 = Parameter("amp") - waveform = pulse.library.Constant(duration=100, amp=param1) - - param_sub1 = Parameter("p1") - param_sub2 = Parameter("p2") - - subroutine = pulse.Schedule() - subroutine += pulse.Play(waveform, pulse.DriveChannel(0)) - reference = subroutine.assign_parameters({param1: 0.6}, inplace=False) - - main_prog = pulse.Schedule() - pdict = {param1: param_sub1 + param_sub2} - with self.assertWarns(DeprecationWarning): - main_prog += pulse.instructions.Call(subroutine, value_dict=pdict) - - # parameter is overwritten by parameters - self.assertEqual(len(main_prog.parameters), 2) - target = main_prog.assign_parameters({param_sub1: 0.1, param_sub2: 0.5}, inplace=False) - result = inline_subroutines(target) - - self.assertEqual(result, reference) - class TestScheduleTimeslots(QiskitTestCase): """Test for edge cases of timing overlap on parametrized channels. diff --git a/test/python/pulse/test_transforms.py b/test/python/pulse/test_transforms.py index 8bb66631b3e4..5cbf4ac9cd4b 100644 --- a/test/python/pulse/test_transforms.py +++ b/test/python/pulse/test_transforms.py @@ -895,87 +895,5 @@ def test_remove_trivial_barriers(self): self.assertEqual(schedule, reference) -class TestRemoveSubroutines(QiskitTestCase): - """Test removing of subroutines.""" - - def test_remove_subroutines(self): - """Test that nested subroutiens are removed.""" - d0 = pulse.DriveChannel(0) - - nested_routine = pulse.Schedule() - nested_routine.insert(10, pulse.Delay(10, d0), inplace=True) - - subroutine = pulse.Schedule() - subroutine.insert(0, pulse.Delay(20, d0), inplace=True) - with self.assertWarns(DeprecationWarning): - subroutine.insert(20, pulse.instructions.Call(nested_routine), inplace=True) - subroutine.insert(50, pulse.Delay(10, d0), inplace=True) - - main_program = pulse.Schedule() - main_program.insert(0, pulse.Delay(10, d0), inplace=True) - with self.assertWarns(DeprecationWarning): - main_program.insert(30, pulse.instructions.Call(subroutine), inplace=True) - - target = transforms.inline_subroutines(main_program) - - reference = pulse.Schedule() - reference.insert(0, pulse.Delay(10, d0), inplace=True) - reference.insert(30, pulse.Delay(20, d0), inplace=True) - reference.insert(60, pulse.Delay(10, d0), inplace=True) - reference.insert(80, pulse.Delay(10, d0), inplace=True) - - self.assertEqual(target, reference) - - def test_call_in_nested_schedule(self): - """Test that subroutines in nested schedule.""" - d0 = pulse.DriveChannel(0) - - subroutine = pulse.Schedule() - subroutine.insert(10, pulse.Delay(10, d0), inplace=True) - - nested_sched = pulse.Schedule() - with self.assertWarns(DeprecationWarning): - nested_sched.insert(0, pulse.instructions.Call(subroutine), inplace=True) - - main_sched = pulse.Schedule() - main_sched.insert(0, nested_sched, inplace=True) - - target = transforms.inline_subroutines(main_sched) - - # no call instruction - reference_nested = pulse.Schedule() - reference_nested.insert(0, subroutine, inplace=True) - - reference = pulse.Schedule() - reference.insert(0, reference_nested, inplace=True) - - self.assertEqual(target, reference) - - def test_call_in_nested_block(self): - """Test that subroutines in nested schedule.""" - d0 = pulse.DriveChannel(0) - - subroutine = pulse.ScheduleBlock() - subroutine.append(pulse.Delay(10, d0), inplace=True) - - nested_block = pulse.ScheduleBlock() - with self.assertWarns(DeprecationWarning): - nested_block.append(pulse.instructions.Call(subroutine), inplace=True) - - main_block = pulse.ScheduleBlock() - main_block.append(nested_block, inplace=True) - - target = transforms.inline_subroutines(main_block) - - # no call instruction - reference_nested = pulse.ScheduleBlock() - reference_nested.append(subroutine, inplace=True) - - reference = pulse.ScheduleBlock() - reference.append(reference_nested, inplace=True) - - self.assertEqual(target, reference) - - if __name__ == "__main__": unittest.main()