def assertScheduleEqual(self, program, target):
        """Assert an error when two pulse programs are not equal.

        .. note:: Two programs are converted into standard execution format then compared.
        """
        self.assertEqual(target_qobj_transform(program),
                         target_qobj_transform(target))
    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}
        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_disassemble_single_schedule(self):
        """Test disassembling a single schedule."""
        d0 = pulse.DriveChannel(0)
        d1 = pulse.DriveChannel(1)
        with pulse.build(self.backend) as sched:
            with pulse.align_right():
                pulse.play(pulse.library.Constant(10, 1.0), d0)
                pulse.set_phase(1.0, d0)
                pulse.shift_phase(3.11, d0)
                pulse.set_frequency(1e9, d0)
                pulse.shift_frequency(1e7, d0)
                pulse.delay(20, d0)
                pulse.delay(10, d1)
                pulse.play(pulse.library.Constant(8, 0.1), d1)
                pulse.measure_all()

        qobj = assemble(sched, backend=self.backend, shots=2000)
        scheds, run_config_out, _ = disassemble(qobj)
        run_config_out = RunConfig(**run_config_out)
        self.assertEqual(run_config_out.memory_slots, 2)
        self.assertEqual(run_config_out.shots, 2000)
        self.assertEqual(run_config_out.memory, False)
        self.assertEqual(run_config_out.meas_level, 2)
        self.assertEqual(run_config_out.meas_lo_freq,
                         self.backend.defaults().meas_freq_est)
        self.assertEqual(run_config_out.qubit_lo_freq,
                         self.backend.defaults().qubit_freq_est)
        self.assertEqual(run_config_out.rep_time, 99)
        self.assertEqual(len(scheds), 1)
        self.assertEqual(scheds[0], target_qobj_transform(sched))
    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_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))
 def test_scheduler_with_params_not_bound(self):
     """Test scheduler with parameters defined but not bound"""
     x = Parameter("amp")
     qc = QuantumCircuit(2)
     qc.append(Gate("pulse_gate", 1, [x]), [0])
     with build() as expected_schedule:
         play(Gaussian(duration=160, amp=x, sigma=40), DriveChannel(0))
     qc.add_calibration(gate="pulse_gate", qubits=[0], schedule=expected_schedule, params=[x])
     sched = schedule(qc, self.backend)
     self.assertEqual(sched, transforms.target_qobj_transform(expected_schedule))
Example #7
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(target_qobj_transform(schedule).instructions), 0)
    def test_disassemble_parametric_pulses(self):
        """Test disassembling multiple schedules all should have the same config."""
        d0 = pulse.DriveChannel(0)
        with pulse.build(self.backend) as sched:
            with pulse.align_right():
                pulse.play(pulse.library.Constant(10, 1.0), d0)
                pulse.play(pulse.library.Gaussian(10, 1.0, 2.0), d0)
                pulse.play(pulse.library.GaussianSquare(10, 1.0, 2.0, 3), d0)
                pulse.play(pulse.library.Drag(10, 1.0, 2.0, 0.1), d0)

        qobj = assemble(sched, backend=self.backend, shots=2000)
        scheds, _, _ = disassemble(qobj)
        self.assertEqual(scheds[0], target_qobj_transform(sched))
    def test_disassemble_multiple_schedules(self):
        """Test disassembling multiple schedules, all should have the same config."""
        d0 = pulse.DriveChannel(0)
        d1 = pulse.DriveChannel(1)
        with pulse.build(self.backend) as sched0:
            with pulse.align_right():
                pulse.play(pulse.library.Constant(10, 1.0), d0)
                pulse.set_phase(1.0, d0)
                pulse.shift_phase(3.11, d0)
                pulse.set_frequency(1e9, d0)
                pulse.shift_frequency(1e7, d0)
                pulse.delay(20, d0)
                pulse.delay(10, d1)
                pulse.play(pulse.library.Constant(8, 0.1), d1)
                pulse.measure_all()

        with pulse.build(self.backend) as sched1:
            with pulse.align_right():
                pulse.play(pulse.library.Constant(8, 0.1), d0)
                pulse.play(pulse.library.Waveform([0.0, 1.0]), d1)
                pulse.set_phase(1.1, d0)
                pulse.shift_phase(3.5, d0)
                pulse.set_frequency(2e9, d0)
                pulse.shift_frequency(3e7, d1)
                pulse.delay(20, d1)
                pulse.delay(10, d0)
                pulse.play(pulse.library.Constant(8, 0.4), d1)
                pulse.measure_all()

        qobj = assemble([sched0, sched1], backend=self.backend, shots=2000)
        scheds, run_config_out, _ = disassemble(qobj)
        run_config_out = RunConfig(**run_config_out)
        self.assertEqual(run_config_out.memory_slots, 2)
        self.assertEqual(run_config_out.shots, 2000)
        self.assertEqual(run_config_out.memory, False)
        self.assertEqual(len(scheds), 2)
        self.assertEqual(scheds[0], target_qobj_transform(sched0))
        self.assertEqual(scheds[1], target_qobj_transform(sched1))
Example #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 = target_qobj_transform(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)
Example #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 = target_qobj_transform(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)
Example #12
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 = target_qobj_transform(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 assertScheduleEqual(self, target, reference):
     """Check if two block are equal schedule representation."""
     self.assertEqual(transforms.target_qobj_transform(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 'schedule_los' setting specified. If specified, it should be "
            "either have a single entry to apply the same LOs for each schedule or "
            "have length equal to the number of schedules.")

    instruction_converter = getattr(run_config, "instruction_converter",
                                    converters.InstructionToQobjConverter)
    instruction_converter = instruction_converter(qobj.PulseQobjInstruction,
                                                  **run_config.to_dict())

    formatted_schedules = [
        transforms.target_qobj_transform(sched) for sched in schedules
    ]
    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
def _assemble_instructions(
    sched: Union[pulse.Schedule, pulse.ScheduleBlock],
    instruction_converter: converters.InstructionToQobjConverter,
    run_config: RunConfig,
    user_pulselib: Dict[str, List[complex]],
) -> Tuple[List[qobj.PulseQobjInstruction], int]:
    """Assembles the instructions in a schedule into a list of PulseQobjInstructions and returns
    related metadata that will be assembled into the Qobj configuration. Lookup table for
    pulses defined in all experiments are registered in ``user_pulselib``. This object should be
    mutable python dictionary so that items are properly updated after each instruction assemble.
    The dictionary is not returned to avoid redundancy.

    Args:
        sched: Schedule to assemble.
        instruction_converter: A converter instance which can convert PulseInstructions to
                               PulseQobjInstructions.
        run_config: Configuration of the runtime environment.
        user_pulselib: User pulse library from previous schedule.

    Returns:
        A list of converted instructions, the user pulse library dictionary (from pulse name to
        pulse samples), and the maximum number of readout memory slots used by this Schedule.
    """
    sched = transforms.target_qobj_transform(sched)

    max_memory_slot = 0
    qobj_instructions = []

    acquire_instruction_map = defaultdict(list)
    for time, instruction in sched.instructions:

        if isinstance(instruction, instructions.Play) and isinstance(
                instruction.pulse, library.ParametricPulse):
            pulse_shape = ParametricPulseShapes(type(instruction.pulse)).name
            if pulse_shape not in run_config.parametric_pulses:
                instruction = instructions.Play(
                    instruction.pulse.get_waveform(),
                    instruction.channel,
                    name=instruction.name)

        if isinstance(instruction, instructions.Play) and isinstance(
                instruction.pulse, library.Waveform):
            name = hashlib.sha256(instruction.pulse.samples).hexdigest()
            instruction = instructions.Play(
                library.Waveform(name=name, samples=instruction.pulse.samples),
                channel=instruction.channel,
                name=name,
            )
            user_pulselib[name] = instruction.pulse.samples

        # ignore explicit delay instrs on acq channels as they are invalid on IBMQ backends;
        # timing of other instrs will still be shifted appropriately
        if isinstance(instruction, instructions.Delay) and isinstance(
                instruction.channel, channels.AcquireChannel):
            continue

        if isinstance(instruction, instructions.Acquire):
            if instruction.mem_slot:
                max_memory_slot = max(max_memory_slot,
                                      instruction.mem_slot.index)
            # Acquires have a single AcquireChannel per inst, but we have to bundle them
            # together into the Qobj as one instruction with many channels
            acquire_instruction_map[(time,
                                     instruction.duration)].append(instruction)
            continue

        qobj_instructions.append(instruction_converter(time, instruction))

    if acquire_instruction_map:
        if hasattr(run_config, "meas_map"):
            _validate_meas_map(acquire_instruction_map, run_config.meas_map)
        for (time, _), instrs in acquire_instruction_map.items():
            qobj_instructions.append(
                instruction_converter.convert_bundled_acquires(time, instrs), )

    return qobj_instructions, max_memory_slot
Example #16
0
    def _schedule_loader(self, program: Union[pulse.Schedule, pulse.ScheduleBlock]):
        """Load Schedule instance.

        This function is sub-routine of py:method:`load_program`.

        Args:
            program: `Schedule` to draw.
        """
        program = target_qobj_transform(program, remove_directives=False)

        # initialize scale values
        self.chan_scales = {}
        for chan in program.channels:
            if isinstance(chan, pulse.channels.DriveChannel):
                self.chan_scales[chan] = self.formatter["channel_scaling.drive"]
            elif isinstance(chan, pulse.channels.MeasureChannel):
                self.chan_scales[chan] = self.formatter["channel_scaling.measure"]
            elif isinstance(chan, pulse.channels.ControlChannel):
                self.chan_scales[chan] = self.formatter["channel_scaling.control"]
            elif isinstance(chan, pulse.channels.AcquireChannel):
                self.chan_scales[chan] = self.formatter["channel_scaling.acquire"]
            else:
                self.chan_scales[chan] = 1.0

        # create charts
        mapper = self.layout["chart_channel_map"]
        for name, chans in mapper(
            channels=program.channels, formatter=self.formatter, device=self.device
        ):

            chart = Chart(parent=self, name=name)

            # add standard pulse instructions
            for chan in chans:
                chart.load_program(program=program, chan=chan)

            # add barriers
            barrier_sched = program.filter(
                instruction_types=[pulse.instructions.RelativeBarrier], channels=chans
            )
            for t0, _ in barrier_sched.instructions:
                inst_data = types.BarrierInstruction(t0, self.device.dt, chans)
                for gen in self.generator["barrier"]:
                    obj_generator = partial(gen, formatter=self.formatter, device=self.device)
                    for data in obj_generator(inst_data):
                        chart.add_data(data)

            # add chart axis
            chart_axis = types.ChartAxis(name=chart.name, channels=chart.channels)
            for gen in self.generator["chart"]:
                obj_generator = partial(gen, formatter=self.formatter, device=self.device)
                for data in obj_generator(chart_axis):
                    chart.add_data(data)

            self.charts.append(chart)

        # add snapshot data to global
        snapshot_sched = program.filter(instruction_types=[pulse.instructions.Snapshot])
        for t0, inst in snapshot_sched.instructions:
            inst_data = types.SnapshotInstruction(t0, self.device.dt, inst.label, inst.channels)
            for gen in self.generator["snapshot"]:
                obj_generator = partial(gen, formatter=self.formatter, device=self.device)
                for data in obj_generator(inst_data):
                    self.global_charts.add_data(data)

        # calculate axis break
        self.time_breaks = self._calculate_axis_break(program)