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} 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)
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('amp') param_sub2 = Parameter('phase') subroutine = pulse.Schedule() subroutine += pulse.Play(waveform, DriveChannel(0)) reference = deepcopy(subroutine).assign_parameters( {param1: 0.1 * np.exp(1j * 0.5)}) main_prog = pulse.Schedule() pdict = {param1: param_sub1 * np.exp(1j * param_sub2)} main_prog += pulse.instructions.Call(subroutine, value_dict=pdict) # parameter is overwritten by parameters self.assertEqual(len(main_prog.parameters), 2) target = deepcopy(main_prog).assign_parameters({ param_sub1: 0.1, param_sub2: 0.5 }) 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("amp") param_sub2 = Parameter("phase") subroutine = pulse.Schedule() subroutine += pulse.Play(waveform, DriveChannel(0)) reference = deepcopy(subroutine).assign_parameters({param1: 0.1 * np.exp(0.5j)}) main_prog = pulse.Schedule() pdict = {param1: param_sub1 * np.exp(1j * param_sub2)} main_prog += pulse.instructions.Call(subroutine, value_dict=pdict) # parameter is overwritten by parameters self.assertEqual(len(main_prog.parameters), 2) target = deepcopy(main_prog).assign_parameters({param_sub1: 0.1, param_sub2: 0.5}) result = inline_subroutines(target) if not HAS_SYMENGINE: self.assertEqual(result, reference) else: # Because of simplification differences between sympy and symengine when # symengine is used we get 0.1*exp(0.5*I) instead of the evaluated # 0.0877582562 + 0.0479425539*I resulting in a failure. When # symengine is installed manually build the amplitude as a complex to # avoid this. reference = pulse.Schedule() waveform = pulse.library.Constant(duration=100, amp=0.1 * cmath.exp(0.5j)) reference += pulse.Play(waveform, DriveChannel(0)) self.assertEqual(result, reference)
def test_nested_assignment_partial_bind(self): """Test nested schedule with call instruction. Inline the schedule and partially bind parameters.""" context = AlignEquispaced(duration=self.context_dur) subroutine = pulse.ScheduleBlock(alignment_context=context) subroutine += pulse.Play(self.parametric_waveform1, self.d1) nested_block = pulse.ScheduleBlock() nested_block += pulse.Call(subroutine=subroutine) test_obj = pulse.ScheduleBlock() test_obj += nested_block test_obj = inline_subroutines(test_obj) value_dict = {self.context_dur: 1000, self.dur1: 200, self.ch1: 1} visitor = ParameterSetter(param_map=value_dict) assigned = visitor.visit(test_obj) ref_context = AlignEquispaced(duration=1000) ref_subroutine = pulse.ScheduleBlock(alignment_context=ref_context) ref_subroutine += pulse.Play( pulse.Gaussian(200, self.amp1_1 + self.amp1_2, 50), pulse.DriveChannel(1)) ref_nested_block = pulse.ScheduleBlock() ref_nested_block += ref_subroutine ref_obj = pulse.ScheduleBlock() ref_obj += ref_nested_block self.assertEqual(assigned, ref_obj)
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) 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) 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 filter_instructions(sched: Schedule, filters: List[Callable], negate: bool = False, recurse_subroutines: bool = True) -> Schedule: """A filtering function that takes a schedule and returns a schedule consisting of filtered instructions. Args: sched: A pulse schedule to be filtered. filters: List of callback functions that take an instruction and return boolean. negate: Set `True` to accept an instruction if a filter function returns `False`. Otherwise the instruction is accepted when the filter function returns `False`. recurse_subroutines: Set `True` to individually filter instructions inside of a subroutine defined by the :py:class:`~qiskit.pulse.instructions.Call` instruction. Returns: Filtered pulse schedule. """ from qiskit.pulse.transforms import flatten, inline_subroutines target_sched = flatten(sched) if recurse_subroutines: target_sched = inline_subroutines(target_sched) time_inst_tuples = np.array(target_sched.instructions) valid_insts = np.ones(len(time_inst_tuples), dtype=bool) for filt in filters: valid_insts = np.logical_and(valid_insts, np.array(list(map(filt, time_inst_tuples)))) if negate and len(filters) > 0: valid_insts = ~valid_insts return Schedule(*time_inst_tuples[valid_insts], name=sched.name, metadata=sched.metadata)
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, DriveChannel(0)) reference = deepcopy(program_layer0).assign_parameters({param1: 0.1}) # to call instruction program_layer1 = pulse.Schedule() program_layer1 += pulse.instructions.Call(program_layer0) target = deepcopy(program_layer1).assign_parameters({param1: 0.1}) self.assertEqual(inline_subroutines(target), reference) # to nested call instruction program_layer2 = pulse.Schedule() program_layer2 += pulse.instructions.Call(program_layer1) target = deepcopy(program_layer2).assign_parameters({param1: 0.1}) self.assertEqual(inline_subroutines(target), reference)
def test_subroutine_not_transpiled(self): """Test called circuit is frozen as a subroutine.""" subprogram = circuit.QuantumCircuit(1) subprogram.x(0) transpiler_settings = {'optimization_level': 2} with pulse.build( self.backend, default_transpiler_settings=transpiler_settings) as schedule: pulse.call(subprogram) pulse.call(subprogram) self.assertNotEqual(len(inline_subroutines(schedule).instructions), 0)
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(test_sched, ref_sched)
def test_call_with_common_parameter(self): """Test call subroutine with parameter that is defined multiple times.""" amp = circuit.Parameter('amp') with pulse.build() as subroutine: pulse.play(pulse.Gaussian(160, amp, 40), pulse.DriveChannel(0)) pulse.play(pulse.Gaussian(320, amp, 80), pulse.DriveChannel(0)) with pulse.build() as main_prog: pulse.call(subroutine, amp=0.1) assigned_sched = inline_subroutines(main_prog) play_0 = assigned_sched.instructions[0][1] play_1 = assigned_sched.instructions[1][1] self.assertEqual(play_0.pulse.amp, 0.1) self.assertEqual(play_1.pulse.amp, 0.1)
def test_call_with_parameters(self): """Test call subroutine with parameters.""" amp = circuit.Parameter('amp') with pulse.build() as subroutine: pulse.play(pulse.Gaussian(160, amp, 40), pulse.DriveChannel(0)) with pulse.build() as main_prog: pulse.call(subroutine, amp=0.1) pulse.call(subroutine, amp=0.3) self.assertEqual(main_prog.is_parameterized(), False) assigned_sched = inline_subroutines(main_prog) play_0 = assigned_sched.instructions[0][1] play_1 = assigned_sched.instructions[1][1] self.assertEqual(play_0.pulse.amp, 0.1) self.assertEqual(play_1.pulse.amp, 0.3)
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) 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)) 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(test_sched, ref_sched)
def load_program(self, program: Union[pulse.Waveform, pulse.ParametricPulse, pulse.Schedule]): """Load a program to draw. Args: program: `Waveform`, `ParametricPulse`, or `Schedule` to draw. Raises: VisualizationError: When input program is invalid data format. """ if isinstance(program, pulse.Schedule): self._schedule_loader(flatten(inline_subroutines(program))) elif isinstance(program, (pulse.Waveform, pulse.ParametricPulse)): self._waveform_loader(program) else: raise VisualizationError('Data type %s is not supported.' % type(program)) # update time range self.set_time_range(0, program.duration, seconds=False) # set title self.fig_title = self.layout['figure_title'](program=program, device=self.device)
def test_subroutine_not_transformed(self): """Test called schedule is not transformed.""" d0 = pulse.DriveChannel(0) d1 = pulse.DriveChannel(1) subprogram = pulse.Schedule() subprogram.insert(0, pulse.Delay(30, d0), inplace=True) subprogram.insert(10, pulse.Delay(10, d1), inplace=True) with pulse.build() as schedule: with pulse.align_right(): pulse.delay(10, d1) pulse.call(subprogram) reference = pulse.Schedule() reference.insert(0, pulse.Delay(10, d1), inplace=True) reference.insert(10, pulse.Delay(30, d0), inplace=True) reference.insert(20, pulse.Delay(10, d1), inplace=True) target = inline_subroutines(schedule) self.assertEqual(target, reference)
def test_call_with_parameter_name_collision(self): """Test call subroutine with duplicated parameter names.""" amp1 = circuit.Parameter('amp') amp2 = circuit.Parameter('amp') sigma = circuit.Parameter('sigma') with pulse.build() as subroutine: pulse.play(pulse.Gaussian(160, amp1, sigma), pulse.DriveChannel(0)) pulse.play(pulse.Gaussian(160, amp2, sigma), pulse.DriveChannel(0)) with pulse.build() as main_prog: pulse.call(subroutine, value_dict={amp1: 0.1, amp2: 0.2}, sigma=40) assigned_sched = inline_subroutines(main_prog) play_0 = assigned_sched.instructions[0][1] play_1 = assigned_sched.instructions[1][1] self.assertEqual(play_0.pulse.amp, 0.1) self.assertEqual(play_0.pulse.sigma, 40) self.assertEqual(play_1.pulse.amp, 0.2) self.assertEqual(play_1.pulse.sigma, 40)
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() 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)
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() 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 _assemble_experiments( schedules: List[Union['schedule.ScheduleComponent', Tuple[int, 'schedule.ScheduleComponent']]], lo_converter: converters.LoConfigConverter, run_config: RunConfig ) -> Tuple[List[qobj.PulseQobjExperiment], Dict[str, Any]]: """Assembles a list of schedules into PulseQobjExperiments, and returns related metadata that will be assembled into the Qobj configuration. Args: schedules: Schedules to assemble. lo_converter: The configured frequency converter and validator. run_config: Configuration of the runtime environment. Returns: The list of assembled experiments, and the dictionary of related experiment config. Raises: QiskitError: when frequency settings are not compatible with the experiments. """ freq_configs = [ lo_converter(lo_dict) for lo_dict in getattr(run_config, 'schedule_los', []) ] if len(schedules) > 1 and len(freq_configs) not in [0, 1, len(schedules)]: raise QiskitError( 'Invalid frequency setting is specified. If the frequency is specified, ' 'it should be configured the same for all schedules, configured for each ' 'schedule, or a list of frequencies should be provided for a single ' 'frequency sweep schedule.') instruction_converter = getattr(run_config, 'instruction_converter', converters.InstructionToQobjConverter) instruction_converter = instruction_converter(qobj.PulseQobjInstruction, **run_config.to_dict()) formatted_schedules = [] for sched in schedules: if isinstance(sched, pulse.Schedule): sched = transforms.inline_subroutines(sched) sched = transforms.flatten(sched) formatted_schedules.append(sched) else: formatted_schedules.append(pulse.Schedule(sched)) compressed_schedules = transforms.compress_pulses(formatted_schedules) user_pulselib = {} experiments = [] for idx, sched in enumerate(compressed_schedules): qobj_instructions, max_memory_slot = _assemble_instructions( sched, instruction_converter, run_config, user_pulselib) metadata = sched.metadata if metadata is None: metadata = {} # TODO: add other experimental header items (see circuit assembler) qobj_experiment_header = qobj.QobjExperimentHeader( memory_slots=max_memory_slot + 1, # Memory slots are 0 indexed name=sched.name or 'Experiment-%d' % idx, metadata=metadata) experiment = qobj.PulseQobjExperiment(header=qobj_experiment_header, instructions=qobj_instructions) if freq_configs: # This handles the cases where one frequency setting applies to all experiments and # where each experiment has a different frequency freq_idx = idx if len(freq_configs) != 1 else 0 experiment.config = freq_configs[freq_idx] experiments.append(experiment) # Frequency sweep if freq_configs and len(experiments) == 1: experiment = experiments[0] experiments = [] for freq_config in freq_configs: experiments.append( qobj.PulseQobjExperiment(header=experiment.header, instructions=experiment.instructions, config=freq_config)) # Top level Qobj configuration experiment_config = { 'pulse_library': [ qobj.PulseLibraryItem(name=name, samples=samples) for name, samples in user_pulselib.items() ], 'memory_slots': max([exp.header.memory_slots for exp in experiments]) } return experiments, experiment_config