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)
예제 #4
0
    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)
예제 #6
0
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)
예제 #8
0
    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)
예제 #9
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)
예제 #10
0
    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)
예제 #11
0
    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)
예제 #12
0
    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)
예제 #13
0
    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)
예제 #14
0
    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)
예제 #15
0
    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)
예제 #16
0
    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)
예제 #17
0
    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)
예제 #18
0
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