def _assemble_instructions(
    schedule: Schedule, instruction_converter: InstructionToQobjConverter,
    run_config: RunConfig,
    user_pulselib: Dict[str,
                        Command]) -> Tuple[List[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:
        schedule: 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 command), and the maximum number of readout memory slots used by this Schedule.
    """
    max_memory_slot = 0
    qobj_instructions = []

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

        if isinstance(instruction, ParametricInstruction):  # deprecated
            instruction = Play(instruction.command,
                               instruction.channels[0],
                               name=instruction.name)

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

        if isinstance(instruction, PulseInstruction):  # deprecated
            instruction = Play(SamplePulse(
                name=name, samples=instruction.command.samples),
                               instruction.channels[0],
                               name=name)

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

        if isinstance(instruction, (AcquireInstruction, Acquire)):
            max_memory_slot = max(
                max_memory_slot,
                *[slot.index for slot in instruction.mem_slots])
            # 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.command)].append(instruction)
            continue

        if isinstance(instruction, (DelayInstruction, Delay)):
            # delay instructions are ignored as timing is explicit within qobj
            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, _), instructions in acquire_instruction_map.items():
            qubits, mem_slots, reg_slots = _bundle_channel_indices(
                instructions)
            qobj_instructions.append(
                instruction_converter.convert_single_acquires(
                    time,
                    instructions[0],
                    qubits=qubits,
                    memory_slot=mem_slots,
                    register_slot=reg_slots))

    return qobj_instructions, max_memory_slot
Ejemplo n.º 2
0
def _assemble_instructions(
    schedule: Schedule, instruction_converter: InstructionToQobjConverter,
    run_config: RunConfig
) -> Tuple[List[PulseQobjInstruction], Dict[str, Command], int]:
    """Assembles the instructions in a schedule into a list of PulseQobjInstructions and returns
    related metadata that will be assembled into the Qobj configuration.

    Args:
        schedule: Schedule to assemble.
        instruction_converter: A converter instance which can convert PulseInstructions to
                               PulseQobjInstructions.
        run_config: Configuration of the runtime environment.

    Returns:
        A list of converted instructions, the user pulse library dictionary (from pulse name to
        pulse command), and the maximum number of readout memory slots used by this Schedule.
    """
    max_memory_slot = 0
    qobj_instructions = []
    user_pulselib = {}

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

        if isinstance(instruction, ParametricInstruction):
            pulse_shape = ParametricPulseShapes(type(instruction.command)).name
            if pulse_shape not in run_config.parametric_pulses:
                # Convert to SamplePulse if the backend does not support it
                instruction = PulseInstruction(
                    instruction.command.get_sample_pulse(),
                    instruction.channels[0],
                    name=instruction.name)

        if isinstance(instruction, PulseInstruction):
            name = instruction.command.name
            if name in user_pulselib and instruction.command != user_pulselib[
                    name]:
                name = "{0}-{1:x}".format(
                    name, hash(instruction.command.samples.tostring()))
                instruction = PulseInstruction(command=SamplePulse(
                    name=name, samples=instruction.command.samples),
                                               name=instruction.name,
                                               channel=instruction.channels[0])
            # add samples to pulse library
            user_pulselib[name] = instruction.command

        if isinstance(instruction, AcquireInstruction):
            max_memory_slot = max(
                max_memory_slot,
                *[slot.index for slot in instruction.mem_slots])
            # 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.command)].append(instruction)
            continue

        if isinstance(instruction, DelayInstruction):
            # delay instructions are ignored as timing is explicit within qobj
            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, _), instructions in acquire_instruction_map.items():
            qubits, mem_slots, reg_slots = _bundle_channel_indices(
                instructions)
            qobj_instructions.append(
                instruction_converter.convert_single_acquires(
                    time,
                    instructions[0],
                    qubits=qubits,
                    memory_slot=mem_slots,
                    register_slot=reg_slots))

    return qobj_instructions, user_pulselib, max_memory_slot