mirror of https://github.com/Qiskit/qiskit.git
Add ShiftFrequency instruction to pulse (#4390)
* Add ShiftFrequency * Review suggestions * Lint * remove unwanted newlines * lint * add newline * Review suggestions and bugfix * Reno * Hz -> GHz conversion for ShiftFrequency -> PulseQobjInstruction * Logic fixes * review suggestion * review suggestions Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
parent
6dbf9dd06b
commit
d4bbaf605c
|
@ -137,7 +137,8 @@ from .commands import AcquireInstruction, FrameChange, PersistentValue
|
|||
from .configuration import LoConfig, LoRange, Kernel, Discriminator
|
||||
from .exceptions import PulseError
|
||||
from .instruction_schedule_map import InstructionScheduleMap
|
||||
from .instructions import Acquire, Instruction, Delay, Play, ShiftPhase, Snapshot, SetFrequency
|
||||
from .instructions import (Acquire, Instruction, Delay, Play, ShiftPhase, Snapshot,
|
||||
SetFrequency, ShiftFrequency)
|
||||
from .interfaces import ScheduleComponent
|
||||
from .pulse_lib import (SamplePulse, Gaussian, GaussianSquare, Drag,
|
||||
Constant, ConstantPulse, ParametricPulse)
|
||||
|
|
|
@ -39,6 +39,7 @@ sequence of scheduled Pulse ``Instruction`` s over many channels. ``Instruction`
|
|||
Delay
|
||||
Play
|
||||
SetFrequency
|
||||
ShiftFrequency
|
||||
ShiftPhase
|
||||
Snapshot
|
||||
|
||||
|
@ -53,7 +54,7 @@ Abstract Classes
|
|||
from .acquire import Acquire
|
||||
from .delay import Delay
|
||||
from .instruction import Instruction
|
||||
from .frequency import SetFrequency
|
||||
from .frequency import SetFrequency, ShiftFrequency
|
||||
from .phase import ShiftPhase
|
||||
from .play import Play
|
||||
from .snapshot import Snapshot
|
||||
|
|
|
@ -60,3 +60,34 @@ class SetFrequency(Instruction):
|
|||
scheduled on.
|
||||
"""
|
||||
return self._channel
|
||||
|
||||
|
||||
class ShiftFrequency(Instruction):
|
||||
"""Shift the channel frequency away from the current frequency."""
|
||||
|
||||
def __init__(self,
|
||||
frequency: float,
|
||||
channel: PulseChannel,
|
||||
name: Optional[str] = None):
|
||||
"""Creates a new shift frequency instruction.
|
||||
|
||||
Args:
|
||||
frequency: Frequency shift of the channel in Hz.
|
||||
channel: The channel this instruction operates on.
|
||||
name: Name of this set channel frequency command.
|
||||
"""
|
||||
self._frequency = float(frequency)
|
||||
self._channel = channel
|
||||
super().__init__((frequency, channel), 0, (channel,), name=name)
|
||||
|
||||
@property
|
||||
def frequency(self) -> float:
|
||||
"""Frequency shift from the set frequency."""
|
||||
return self._frequency
|
||||
|
||||
@property
|
||||
def channel(self) -> PulseChannel:
|
||||
"""Return the :py:class:`~qiskit.pulse.channels.Channel` that this instruction is
|
||||
scheduled on.
|
||||
"""
|
||||
return self._channel
|
||||
|
|
|
@ -273,6 +273,25 @@ class InstructionToQobjConverter:
|
|||
}
|
||||
return self._qobj_model(**command_dict)
|
||||
|
||||
@bind_instruction(instructions.ShiftFrequency)
|
||||
def convert_shift_frequency(self, shift, instruction):
|
||||
"""Return converted `ShiftFrequency`.
|
||||
|
||||
Args:
|
||||
shift (int): Offset time.
|
||||
instruction (ShiftFrequency): Shift frequency instruction.
|
||||
|
||||
Returns:
|
||||
dict: Dictionary of required parameters.
|
||||
"""
|
||||
command_dict = {
|
||||
'name': 'shiftf',
|
||||
't0': shift+instruction.start_time,
|
||||
'ch': instruction.channel.name,
|
||||
'frequency': instruction.frequency / 1e9
|
||||
}
|
||||
return self._qobj_model(**command_dict)
|
||||
|
||||
@bind_instruction(instructions.ShiftPhase)
|
||||
def convert_shift_phase(self, shift, instruction):
|
||||
"""Return converted `ShiftPhase`.
|
||||
|
@ -545,6 +564,31 @@ class QobjToInstructionConverter:
|
|||
|
||||
return instructions.SetFrequency(frequency, channel) << t0
|
||||
|
||||
@bind_name('shiftf')
|
||||
def convert_shift_frequency(self, instruction):
|
||||
"""Return converted `ShiftFrequency`.
|
||||
|
||||
Args:
|
||||
instruction (PulseQobjInstruction): Shift frequency qobj instruction.
|
||||
|
||||
Returns:
|
||||
Schedule: Converted and scheduled Instruction
|
||||
"""
|
||||
t0 = instruction.t0
|
||||
channel = self.get_channel(instruction.ch)
|
||||
frequency = instruction.frequency * 1e9
|
||||
|
||||
if isinstance(frequency, str):
|
||||
frequency_expr = parse_string_expr(frequency, partial_binding=False)
|
||||
|
||||
def gen_sf_schedule(*args, **kwargs):
|
||||
_frequency = frequency_expr(*args, **kwargs)
|
||||
return instructions.ShiftFrequency(_frequency, channel) << t0
|
||||
|
||||
return ParameterizedSchedule(gen_sf_schedule, parameters=frequency_expr.params)
|
||||
|
||||
return instructions.ShiftFrequency(frequency, channel) << t0
|
||||
|
||||
@bind_name('delay')
|
||||
def convert_delay(self, instruction):
|
||||
"""Return converted `Delay`.
|
||||
|
|
|
@ -36,7 +36,7 @@ from qiskit.pulse.channels import (DriveChannel, ControlChannel,
|
|||
from qiskit.pulse.commands import FrameChangeInstruction
|
||||
from qiskit.pulse import (SamplePulse, FrameChange, PersistentValue, Snapshot, Play,
|
||||
Acquire, PulseError, ParametricPulse, SetFrequency, ShiftPhase,
|
||||
Instruction, ScheduleComponent)
|
||||
Instruction, ScheduleComponent, ShiftFrequency)
|
||||
|
||||
|
||||
class EventsOutputChannels:
|
||||
|
@ -105,6 +105,14 @@ class EventsOutputChannels:
|
|||
|
||||
return self._trim(self._frequencychanges)
|
||||
|
||||
@property
|
||||
def frequencyshift(self) -> Dict[int, ShiftFrequency]:
|
||||
"""Set the frequency changes."""
|
||||
if self._frequencychanges is None:
|
||||
self._build_waveform()
|
||||
|
||||
return self._trim(self._frequencychanges)
|
||||
|
||||
@property
|
||||
def conditionals(self) -> Dict[int, str]:
|
||||
"""Get conditionals."""
|
||||
|
@ -194,6 +202,8 @@ class EventsOutputChannels:
|
|||
pv[time:] = 0
|
||||
elif isinstance(command, SetFrequency):
|
||||
tmp_sf = command.frequency
|
||||
elif isinstance(command, ShiftFrequency):
|
||||
tmp_sf = command.frequency
|
||||
elif isinstance(command, Snapshot):
|
||||
self._snapshots[time] = command.name
|
||||
if tmp_fc != 0:
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
The :py:class:`~qiskit.pulse.instructions.ShiftFrequency` instruction allows users
|
||||
to shift the frequency from the set frequency. For example::
|
||||
|
||||
sched += ShiftFrequency(-340e6, DriveChannel(0))
|
||||
|
||||
In this example, all the pulses applied to ``DriveChannel(0)`` after the
|
||||
``ShiftFrequency`` command will have the envelope a frequency decremented by 340MHz.
|
|
@ -20,7 +20,7 @@ import numpy as np
|
|||
|
||||
from qiskit.pulse import (Play, SamplePulse, ShiftPhase, Instruction, SetFrequency, Acquire,
|
||||
pulse_lib, Snapshot, Delay, Gaussian, Drag, GaussianSquare, Constant,
|
||||
functional_pulse)
|
||||
functional_pulse, ShiftFrequency)
|
||||
from qiskit.pulse.channels import (MemorySlot, RegisterSlot, DriveChannel, AcquireChannel,
|
||||
SnapshotChannel, MeasureChannel)
|
||||
from qiskit.pulse.commands import PersistentValue, PulseInstruction
|
||||
|
@ -665,6 +665,7 @@ class TestScheduleFilter(BaseTestSchedule):
|
|||
sched = sched.insert(10, Play(lp0, self.config.drive(1)))
|
||||
sched = sched.insert(30, ShiftPhase(-1.57, self.config.drive(0)))
|
||||
sched = sched.insert(40, SetFrequency(8.0, self.config.drive(0)))
|
||||
sched = sched.insert(50, ShiftFrequency(4.0e6, self.config.drive(0)))
|
||||
for i in range(2):
|
||||
sched = sched.insert(60, Acquire(5, self.config.acquire(i), MemorySlot(i)))
|
||||
sched = sched.insert(90, Play(lp0, self.config.drive(0)))
|
||||
|
@ -686,22 +687,30 @@ class TestScheduleFilter(BaseTestSchedule):
|
|||
for _, inst in no_pulse_and_fc.instructions:
|
||||
self.assertFalse(isinstance(inst, (Play, ShiftPhase)))
|
||||
self.assertEqual(len(only_pulse_and_fc.instructions), 4)
|
||||
self.assertEqual(len(no_pulse_and_fc.instructions), 3)
|
||||
self.assertEqual(len(no_pulse_and_fc.instructions), 4)
|
||||
|
||||
# test on ShiftPhase
|
||||
only_fc, no_fc = \
|
||||
self._filter_and_test_consistency(sched, instruction_types={ShiftPhase})
|
||||
self.assertEqual(len(only_fc.instructions), 1)
|
||||
self.assertEqual(len(no_fc.instructions), 6)
|
||||
self.assertEqual(len(no_fc.instructions), 7)
|
||||
|
||||
# test on SetFrequency
|
||||
only_sf, no_sf = \
|
||||
self._filter_and_test_consistency(sched,
|
||||
instruction_types=[SetFrequency])
|
||||
for _, inst in only_sf.instructions:
|
||||
only_setf, no_setf = self._filter_and_test_consistency(
|
||||
sched, instruction_types=[SetFrequency])
|
||||
for _, inst in only_setf.instructions:
|
||||
self.assertTrue(isinstance(inst, SetFrequency))
|
||||
self.assertEqual(len(only_sf.instructions), 1)
|
||||
self.assertEqual(len(no_sf.instructions), 6)
|
||||
self.assertEqual(len(only_setf.instructions), 1)
|
||||
self.assertEqual(len(no_setf.instructions), 7)
|
||||
|
||||
# test on ShiftFrequency
|
||||
only_shiftf, no_shiftf = \
|
||||
self._filter_and_test_consistency(sched,
|
||||
instruction_types=[ShiftFrequency])
|
||||
for _, inst in only_shiftf.instructions:
|
||||
self.assertTrue(isinstance(inst, ShiftFrequency))
|
||||
self.assertEqual(len(only_shiftf.instructions), 1)
|
||||
self.assertEqual(len(no_shiftf.instructions), 7)
|
||||
|
||||
def test_filter_intervals(self):
|
||||
"""Test filtering on intervals."""
|
||||
|
|
|
@ -23,7 +23,7 @@ from qiskit.qobj.converters import (InstructionToQobjConverter, QobjToInstructio
|
|||
LoConfigConverter)
|
||||
from qiskit.pulse.commands import (SamplePulse, FrameChange, PersistentValue, Snapshot, Acquire,
|
||||
Gaussian, GaussianSquare, Constant, Drag)
|
||||
from qiskit.pulse.instructions import ShiftPhase, SetFrequency, Play, Delay
|
||||
from qiskit.pulse.instructions import ShiftPhase, SetFrequency, Play, Delay, ShiftFrequency
|
||||
from qiskit.pulse.channels import (DriveChannel, ControlChannel, MeasureChannel, AcquireChannel,
|
||||
MemorySlot, RegisterSlot)
|
||||
from qiskit.pulse.schedule import ParameterizedSchedule, Schedule
|
||||
|
@ -157,6 +157,20 @@ class TestInstructionToQobjConverter(QiskitTestCase):
|
|||
|
||||
self.assertEqual(converter(0, instruction), valid_qobj)
|
||||
|
||||
def test_shift_frequency(self):
|
||||
"""Test converted qobj from ShiftFrequency."""
|
||||
converter = InstructionToQobjConverter(PulseQobjInstruction, meas_level=2)
|
||||
instruction = ShiftFrequency(8.0e9, DriveChannel(0))
|
||||
|
||||
valid_qobj = PulseQobjInstruction(
|
||||
name='shiftf',
|
||||
ch='d0',
|
||||
t0=0,
|
||||
frequency=8.0
|
||||
)
|
||||
|
||||
self.assertEqual(converter(0, instruction), valid_qobj)
|
||||
|
||||
def test_persistent_value(self):
|
||||
"""Test converted qobj from PersistentValueInstruction."""
|
||||
converter = InstructionToQobjConverter(PulseQobjInstruction, meas_level=2)
|
||||
|
@ -301,7 +315,7 @@ class TestQobjToInstructionConverter(QiskitTestCase):
|
|||
self.assertEqual(converted_instruction.instructions[0][-1], instruction)
|
||||
|
||||
def test_set_frequency(self):
|
||||
"""Test converted qobj from FrameChangeInstruction."""
|
||||
"""Test converted qobj from SetFrequency."""
|
||||
instruction = SetFrequency(8.0e9, DriveChannel(0))
|
||||
|
||||
qobj = PulseQobjInstruction(name='setf', ch='d0', t0=0, frequency=8.0)
|
||||
|
@ -312,6 +326,18 @@ class TestQobjToInstructionConverter(QiskitTestCase):
|
|||
self.assertEqual(converted_instruction.instructions[0][-1], instruction)
|
||||
self.assertTrue('frequency' in qobj.to_dict())
|
||||
|
||||
def test_shift_frequency(self):
|
||||
"""Test converted qobj from ShiftFrequency."""
|
||||
instruction = ShiftFrequency(8.0e9, DriveChannel(0))
|
||||
|
||||
qobj = PulseQobjInstruction(name='shiftf', ch='d0', t0=0, frequency=8.0)
|
||||
converted_instruction = self.converter(qobj)
|
||||
|
||||
self.assertEqual(converted_instruction.start_time, 0)
|
||||
self.assertEqual(converted_instruction.duration, 0)
|
||||
self.assertEqual(converted_instruction.instructions[0][-1], instruction)
|
||||
self.assertTrue('frequency' in qobj.to_dict())
|
||||
|
||||
def test_delay(self):
|
||||
"""Test converted qobj from Delay."""
|
||||
instruction = Delay(10, DriveChannel(0))
|
||||
|
|
|
@ -232,6 +232,7 @@ class TestPulseQobj(QiskitTestCase):
|
|||
PulseQobjInstruction(name='pv', t0=10, ch='d0', val=0.1 + 0.0j),
|
||||
PulseQobjInstruction(name='pv', t0=10, ch='d0', val='P1'),
|
||||
PulseQobjInstruction(name='setf', t0=10, ch='d0', frequency=8.0),
|
||||
PulseQobjInstruction(name='shiftf', t0=10, ch='d0', frequency=4.0),
|
||||
PulseQobjInstruction(name='acquire', t0=15, duration=5,
|
||||
qubits=[0], memory_slot=[0],
|
||||
kernels=[
|
||||
|
@ -266,6 +267,7 @@ class TestPulseQobj(QiskitTestCase):
|
|||
{'name': 'pv', 't0': 10, 'ch': 'd0', 'val': 0.1+0j},
|
||||
{'name': 'pv', 't0': 10, 'ch': 'd0', 'val': 'P1'},
|
||||
{'name': 'setf', 't0': 10, 'ch': 'd0', 'frequency': 8.0},
|
||||
{'name': 'shiftf', 't0': 10, 'ch': 'd0', 'frequency': 4.0},
|
||||
{'name': 'acquire', 't0': 15, 'duration': 5,
|
||||
'qubits': [0], 'memory_slot': [0],
|
||||
'kernels': [{'name': 'boxcar',
|
||||
|
|
|
@ -23,7 +23,7 @@ from qiskit.pulse import pulse_lib
|
|||
from qiskit.pulse.channels import (DriveChannel, MeasureChannel, ControlChannel, AcquireChannel,
|
||||
MemorySlot, RegisterSlot)
|
||||
from qiskit.pulse.commands import FrameChange
|
||||
from qiskit.pulse.instructions import SetFrequency, Play, Acquire, Delay, Snapshot
|
||||
from qiskit.pulse.instructions import SetFrequency, Play, Acquire, Delay, Snapshot, ShiftFrequency
|
||||
from qiskit.pulse.schedule import Schedule
|
||||
from qiskit.tools.visualization import HAS_MATPLOTLIB
|
||||
from qiskit.visualization import pulse_drawer
|
||||
|
@ -68,6 +68,7 @@ class TestPulseVisualizationImplementation(QiskitVisualizationTestCase):
|
|||
ControlChannel(0)))
|
||||
sched = sched.insert(60, FrameChange(phase=-1.57)(DriveChannel(0)))
|
||||
sched = sched.insert(60, SetFrequency(8.0, DriveChannel(0)))
|
||||
sched = sched.insert(70, ShiftFrequency(4.0e6, DriveChannel(0)))
|
||||
sched = sched.insert(30, gp1(DriveChannel(1)))
|
||||
sched = sched.insert(60, gp0(ControlChannel(0)))
|
||||
sched = sched.insert(60, gs0(MeasureChannel(0)))
|
||||
|
|
Loading…
Reference in New Issue