I am trying to run exercise 4 from the recent IBM Quantum Challenge using a PulseSimulator since the device used in the challenge is not available for public use. A snippet of what I am trying to run is the following:
from qiskit import pulse, IBMQ, assemble
from qiskit.pulse import Play, Schedule, DriveChannel, Gaussian, AcquireChannel
from qiskit.providers.aer import PulseSimulator
from qiskit.tools.monitor import job_monitor
import numpy as np
# Constants and units
job_params = {
'meas_level': 1,
'meas_return': 'avg',
'shots': 512
}
spec_range = 0.300 # GHz
num_spec01_freqs = 71
GHz = 1.0e9 # Gigahertz
# Helper functions
def get_exc_chans(gv):
return [AcquireChannel(i) for i in range(gv['backend_config'].n_qubits)]
def get_spec01_freqs(center_freqs, qubit):
center_freq = round(center_freqs[qubit], -8) # 2 significant digits
return np.linspace(center_freq/GHz - spec_range/2,
center_freq/GHz + spec_range/2, num_spec01_freqs)
# Set up backend and config
provider = IBMQ.load_account()
backend_name = 'ibmq_armonk'
backend_real = provider.get_backend(backend_name)
backend = PulseSimulator.from_backend(backend_real)
qubit = 0
backend_config = backend.configuration()
exc_chans = get_exc_chans(globals())
dt = backend_config.dt
backend_defaults = backend.defaults()
center_frequency = backend_defaults.qubit_freq_est
inst_sched_map = backend_defaults.instruction_schedule_map
# |0⟩ -> |1⟩ pulse
# Retrieve calibrated measurement pulse from backend
meas = inst_sched_map.get('measure', qubits=[qubit])
# The same spec pulse for both 01 and 12 spec
drive_amp = 0.25
drive_duration = inst_sched_map.get('x', qubits=[qubit]).duration
# Calibrated backend pulse use advanced DRAG pulse to reduce leakage to the |2> state.
# Here we will use simple Gaussian pulse
drive_sigma = drive_duration // 4 # DRAG pulses typically 4*sigma long.
spec_pulse = Gaussian(duration=drive_duration, amp=drive_amp,
sigma=drive_sigma, name=f"Spec drive amplitude = {drive_amp}")
# Construct an np array of the frequencies for our experiment
spec_freqs_GHz = get_spec01_freqs(center_frequency, qubit)
# Create the base schedule
# Start with drive pulse acting on the drive channel
spec01_scheds = []
for freq in spec_freqs_GHz:
with pulse.build(name="Spec Pulse at %.3f GHz" % freq) as spec01_sched:
with pulse.align_sequential():
# Pay close attention to this part to solve the problem at the end
pulse.set_frequency(freq*GHz, DriveChannel(qubit))
pulse.play(spec_pulse, DriveChannel(qubit))
pulse.call(meas)
spec01_scheds.append(spec01_sched)
qobj = assemble(spec01_scheds, backend=backend, **job_params)
spec01_job = backend.run(qobj)
job_monitor(spec01_job)
However, everytime I run this I get the following (not very helpful) error message:
Job Status: job incurred error
I opened an issue about this in the Qiskit Aer GitHub repository (issue #1264) and got a response. They told me that "the set/shift frequency instructions are not supported by the pulse simulator". And they suggested the following workaround:
A way to bypass this issue as a user is to manually add an oscillation to the pulse envelopes. E.g. if the channel's LO frequency is $w$, but you want to set it to $v$ for a given pulse (or pulses), convert the pulse to an explicit WaveForm specified in terms of a sample list, then multiply the sample array $exp(i(v-w)t)$, where $t$ is the array of associated times. I may be missing some book keeping here but some version of this should work.
As simple as this sounds, I don't quite understand how to do this. Can anyone explain to me, with code, how to do this? Or point me to somewhere where this is done?