예제 #1
0
    def _1Q_frame_change_schedule(self, phi, fc_phi, total_samples, dur_drive1, dur_drive2):
        """Creates schedule for frame change test. Does a pulse w/ phase phi of duration dur_drive1,
        then frame change of phase fc_phi, then another pulse of phase phi of duration dur_drive2.
        The different durations for the pulses allow manipulation of rotation angles on Bloch sphere

        Args:
            phi (float): drive phase (phi in Hamiltonian)
            fc_phi (float): phase for frame change
            total_samples (int): length of pulses
            dur_drive1 (int): duration of first pulse
            dur_drive2 (int): duration of second pulse

        Returns:
            schedule (pulse schedule): schedule for frame change test
        """
        phase = np.exp(1j * phi)
        drive_pulse_1 = SamplePulse(phase * np.ones(dur_drive1),
                                    name='drive_pulse_1')
        drive_pulse_2 = SamplePulse(phase * np.ones(dur_drive2),
                                    name='drive_pulse_2')

        # frame change
        fc_pulse = FrameChange(phase=fc_phi, name='fc')

        # set up acquire command
        acq_cmd = pulse.Acquire(duration=total_samples)

        # add commands to schedule
        schedule = pulse.Schedule(name='fc_schedule')
        schedule |= drive_pulse_1(DriveChannel(0))
        schedule += fc_pulse(DriveChannel(0))
        schedule += drive_pulse_2(DriveChannel(0))
        schedule |= acq_cmd(AcquireChannel(0), MemorySlot(0)) << schedule.duration

        return schedule
예제 #2
0
    def _simple_1Q_schedule(self, phi, total_samples, shape="square", gauss_sigma=0):
        """Creates schedule for single pulse test
        Args:
            phi (float): drive phase (phi in Hamiltonian)
            total_samples (int): length of pulses
            shape (str): shape of the pulse; defaults to square pulse
            gauss_sigma (float): std dev for gaussian pulse if shape=="gaussian"
        Returns:
            schedule (pulse schedule): schedule for this test
        """

        # set up pulse command
        phase = np.exp(1j * phi)
        drive_pulse = None
        if shape == "square":
            const_pulse = np.ones(total_samples)
            drive_pulse = SamplePulse(phase * const_pulse, name='drive_pulse')
        if shape == "gaussian":
            times = 1.0 * np.arange(total_samples)
            gaussian = np.exp(-times**2 / 2 / gauss_sigma**2)
            drive_pulse = SamplePulse(phase * gaussian, name='drive_pulse')

        # set up acquire command
        acq_cmd = pulse.Acquire(duration=total_samples)

        # add commands into a schedule for first qubit
        schedule = pulse.Schedule(name='drive_pulse')
        schedule |= drive_pulse(DriveChannel(0))
        schedule |= acq_cmd(AcquireChannel(0), MemorySlot(0)) << schedule.duration

        return schedule
예제 #3
0
    def setUp(self):
        self.linear = SamplePulse(np.arange(0, 0.01), name='linear')
        self.pulse_library = [PulseLibraryItem(name=self.linear.name,
                                               samples=self.linear.samples.tolist())]

        self.converter = QobjToInstructionConverter(self.pulse_library, buffer=0)
        self.num_qubits = 2
예제 #4
0
    def _schedule_2Q_interaction(self, total_samples):
        """Creates schedule for testing two qubit interaction. Specifically, do a pi pulse on qub 0
        so it starts in the `1` state (drive channel) and then apply constant pulses to each
        qubit (on control channel 1). This will allow us to test a swap gate.

        Args:
            total_samples (int): length of pulses
        Returns:
            schedule (pulse schedule): schedule for 2q experiment
        """
        # set up const pulse
        const_pulse = SamplePulse(np.ones(total_samples), name='const_pulse')

        # set u channel
        uchannel = 1  # gives omega1-omega0 (we will set equal, so don't need negation)

        # add commands to schedule
        schedule = pulse.Schedule(name='2q_schedule')
        schedule |= const_pulse(DriveChannel(0))  # pi pulse drive
        schedule += const_pulse(ControlChannel(uchannel)) << schedule.duration  # u chan pulse

        acq_cmd = pulse.Acquire(duration=total_samples)
        acq_sched = acq_cmd(AcquireChannel(0), MemorySlot(0))
        acq_sched += acq_cmd(AcquireChannel(1), MemorySlot(1))

        schedule |= acq_sched << schedule.duration

        return schedule
예제 #5
0
 def test_drive_instruction(self):
     """Test converted qobj from Play."""
     converter = InstructionToQobjConverter(PulseQobjInstruction,
                                            meas_level=2)
     instruction = Play(SamplePulse(np.arange(0, 0.01), name='linear'),
                        DriveChannel(0))
     valid_qobj = PulseQobjInstruction(name='linear', ch='d0', t0=0)
     self.assertEqual(converter(0, instruction), valid_qobj)
예제 #6
0
    def setUp(self):
        self.linear = SamplePulse(np.arange(0, 0.01), name='linear')
        self.pulse_library = [PulseLibraryItem(name=self.linear.name,
                                               samples=self.linear.samples.tolist())]

        self.converter = QobjToInstructionConverter(self.pulse_library, buffer=0)

        self.device = PulseChannelSpec(n_qubits=2, n_control=0, n_registers=2)
예제 #7
0
    def test_drive_instruction(self):
        """Test converted qobj from PulseInstruction."""
        converter = PulseQobjConverter(PulseQobjInstruction, meas_level=2)
        command = SamplePulse(np.arange(0, 0.01), name='linear')
        instruction = command(self.device.q[0].drive)

        valid_qobj = PulseQobjInstruction(name='linear', ch='d0', t0=0)

        self.assertEqual(converter(0, instruction), valid_qobj)
예제 #8
0
    def test_deprecated_drive_instruction(self):
        """Test converted qobj from PulseInstruction."""
        converter = InstructionToQobjConverter(PulseQobjInstruction,
                                               meas_level=2)
        command = SamplePulse(np.arange(0, 0.01), name='linear')
        with self.assertWarns(DeprecationWarning):
            instruction = command(DriveChannel(0))

        valid_qobj = PulseQobjInstruction(name='linear', ch='d0', t0=0)

        self.assertEqual(converter(0, instruction), valid_qobj)
    def setUp(self):
        self.linear = SamplePulse(np.arange(0, 0.01), name='linear')
        self.pulse_library = [
            PulseLibraryItem(name=self.linear.name,
                             samples=self.linear.samples.tolist())
        ]

        self.converter = QobjToInstructionConverter(self.pulse_library,
                                                    buffer=0)

        self.device = DeviceSpecification(qubits=[
            Qubit(0, DriveChannel(0), MeasureChannel(0), AcquireChannel(0))
        ],
                                          registers=[RegisterSlot(0)],
                                          mem_slots=[MemorySlot(0)])
예제 #10
0
def assemble_schedules(schedules, qobj_id, qobj_header, run_config):
    """Assembles a list of schedules into a qobj which can be run on the backend.

    Args:
        schedules (list[Schedule]): schedules to assemble
        qobj_id (int): identifier for the generated qobj
        qobj_header (QobjHeader): header to pass to the results
        run_config (RunConfig): configuration of the runtime environment
    Returns:
        PulseQobj: the Qobj to be run on the backends
    Raises:
        QiskitError: when invalid schedules or configs are provided
    """
    if hasattr(run_config, 'instruction_converter'):
        instruction_converter = run_config.instruction_converter
    else:
        instruction_converter = InstructionToQobjConverter

    qobj_config = run_config.to_dict()

    qubit_lo_freq = qobj_config.get('qubit_lo_freq', None)
    if qubit_lo_freq is None:
        raise QiskitError('qubit_lo_freq must be supplied.')

    meas_lo_freq = qobj_config.get('meas_lo_freq', None)
    if meas_lo_freq is None:
        raise QiskitError('meas_lo_freq must be supplied.')

    qubit_lo_range = qobj_config.pop('qubit_lo_range', None)
    meas_lo_range = qobj_config.pop('meas_lo_range', None)
    meas_map = qobj_config.pop('meas_map', None)

    # convert enums to serialized values
    meas_return = qobj_config.get('meas_return', 'avg')
    if isinstance(meas_return, MeasReturnType):
        qobj_config['meas_return'] = meas_return.value

    meas_level = qobj_config.get('meas_return', 2)
    if isinstance(meas_level, MeasLevel):
        qobj_config['meas_level'] = meas_level.value

    instruction_converter = instruction_converter(PulseQobjInstruction, **qobj_config)

    lo_converter = LoConfigConverter(PulseQobjExperimentConfig,
                                     qubit_lo_range=qubit_lo_range,
                                     meas_lo_range=meas_lo_range,
                                     **qobj_config)

    memory_slot_size = 0

    # Pack everything into the Qobj
    qobj_schedules = []
    user_pulselib = {}
    for idx, schedule in enumerate(schedules):
        # instructions
        max_memory_slot = 0
        qobj_instructions = []

        # Instructions are returned as tuple of shifted time and instruction
        for shift, instruction in schedule.instructions:
            # TODO: support conditional gate

            if isinstance(instruction, DelayInstruction):
                # delay instructions are ignored as timing is explicit within qobj
                continue

            elif 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
            elif isinstance(instruction, AcquireInstruction):
                max_memory_slot = max(max_memory_slot,
                                      *[slot.index for slot in instruction.mem_slots])
                if meas_map:
                    # verify all acquires satisfy meas_map
                    _validate_meas_map(instruction, meas_map)

            converted_instruction = instruction_converter(shift, instruction)
            qobj_instructions.append(converted_instruction)

        # memory slot size is memory slot index + 1 because index starts from zero
        exp_memory_slot_size = max_memory_slot + 1
        memory_slot_size = max(memory_slot_size, exp_memory_slot_size)

        # experiment header
        # TODO: add other experimental header items (see circuit assembler)
        qobj_experiment_header = QobjExperimentHeader(
            memory_slots=exp_memory_slot_size,
            name=schedule.name or 'Experiment-%d' % idx
        )

        qobj_schedules.append({
            'header': qobj_experiment_header,
            'instructions': qobj_instructions
        })

    # set number of memoryslots
    qobj_config['memory_slots'] = memory_slot_size

    # setup pulse_library
    qobj_config['pulse_library'] = [PulseLibraryItem(name=pulse.name, samples=pulse.samples)
                                    for pulse in user_pulselib.values()]

    # create qobj experiment field
    experiments = []
    schedule_los = qobj_config.pop('schedule_los', [])

    if len(schedule_los) == 1:
        lo_dict = schedule_los[0]
        # update global config
        q_los = lo_converter.get_qubit_los(lo_dict)
        if q_los:
            qobj_config['qubit_lo_freq'] = q_los
        m_los = lo_converter.get_meas_los(lo_dict)
        if m_los:
            qobj_config['meas_lo_freq'] = m_los

    if schedule_los:
        # multiple frequency setups
        if len(qobj_schedules) == 1:
            # frequency sweep
            for lo_dict in schedule_los:
                experiments.append(PulseQobjExperiment(
                    instructions=qobj_schedules[0]['instructions'],
                    header=qobj_schedules[0]['header'],
                    config=lo_converter(lo_dict)
                ))
        elif len(qobj_schedules) == len(schedule_los):
            # n:n setup
            for lo_dict, schedule in zip(schedule_los, qobj_schedules):
                experiments.append(PulseQobjExperiment(
                    instructions=schedule['instructions'],
                    header=schedule['header'],
                    config=lo_converter(lo_dict)
                ))
        else:
            raise QiskitError('Invalid LO setting is specified. '
                              'The LO should be configured for each schedule, or '
                              'single setup for all schedules (unique), or '
                              'multiple setups for a single schedule (frequency sweep),'
                              'or no LO configured at all.')
    else:
        # unique frequency setup
        for schedule in qobj_schedules:
            experiments.append(PulseQobjExperiment(
                instructions=schedule['instructions'],
                header=schedule['header'],
            ))

    qobj_config = PulseQobjConfig(**qobj_config)

    return PulseQobj(qobj_id=qobj_id,
                     config=qobj_config,
                     experiments=experiments,
                     header=qobj_header)
예제 #11
0
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):
            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)):
            # 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