Skip to content

Commit

Permalink
Convert delays to instructions when assembling (#5481)
Browse files Browse the repository at this point in the history
* Convert delays to instructions when assembling

* Add reno

* Fixup copy paste error

* Remove failing test

* Add test for regular delay inst

* Respond to feedback

* Update disassembler tests

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
lcapelluto and mergify[bot] authored Dec 8, 2020
1 parent 75e600e commit 5fb8100
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 15 deletions.
4 changes: 0 additions & 4 deletions qiskit/assembler/assemble_schedules.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,10 +198,6 @@ def _assemble_instructions(
acquire_instruction_map[(time, instruction.duration)].append(instruction)
continue

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

qobj_instructions.append(instruction_converter(time, instruction))

if acquire_instruction_map:
Expand Down
18 changes: 18 additions & 0 deletions qiskit/qobj/converters/pulse_instruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,24 @@ def convert_shift_phase(self, shift, instruction):
}
return self._qobj_model(**command_dict)

@bind_instruction(instructions.Delay)
def convert_delay(self, shift, instruction):
"""Return converted `Delay`.
Args:
shift(int): Offset time.
instruction (Delay): Delay instruction.
Returns:
dict: Dictionary of required parameters.
"""
command_dict = {
'name': 'delay',
't0': shift + instruction.start_time,
'ch': instruction.channel.name,
'duration': instruction.duration
}
return self._qobj_model(**command_dict)

@bind_instruction(instructions.Play)
def convert_play(self, shift, instruction):
"""Return the converted `Play`.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
fixes:
- |
Pulse :py:class:`~qiskit.pulse.instructions.Delay` is now explicitly
assembled as qobj instructions.
Previously, we could ignore delays rather than assembling them. Now, with
pulse gates, there are times that we want to schedule ONLY a delay, and not
including the delay itself would remove the delay.
24 changes: 16 additions & 8 deletions test/python/compiler/test_assembler.py
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,17 @@ def test_pulse_gates_common_cals(self):
self.assertEqual(len(qobj.experiments[0].config.calibrations.gates), 1)
self.assertFalse(hasattr(qobj.experiments[1].config, 'calibrations'))

def test_pulse_gates_delay_only(self):
"""Test that a single delay gate is translated to an instruction."""
circ = QuantumCircuit(2)
circ.append(Gate('test', 1, []), [0])
test_sched = pulse.Delay(64, DriveChannel(0)) + pulse.Delay(160, DriveChannel(0))
circ.add_calibration('test', [0], test_sched)
qobj = assemble(circ, FakeOpenPulse2Q())
self.assertEqual(len(qobj.config.calibrations.gates[0].instructions), 2)
self.assertEqual(qobj.config.calibrations.gates[0].instructions[1].to_dict(),
{"name": "delay", "t0": 64, "ch": "d0", "duration": 160})


class TestPulseAssembler(QiskitTestCase):
"""Tests for assembling schedules to qobj."""
Expand Down Expand Up @@ -836,16 +847,13 @@ def test_pulse_name_conflicts_in_other_schedule(self):

def test_assemble_with_delay(self):
"""Test that delay instruction is ignored in assembly."""
orig_schedule = self.schedule
delay_schedule = orig_schedule + pulse.Delay(10, self.backend_config.drive(0))

orig_qobj = assemble(orig_schedule, self.backend)
validate_qobj_against_schema(orig_qobj)
delay_schedule = pulse.Delay(10, self.backend_config.drive(0))
delay_schedule += self.schedule
delay_qobj = assemble(delay_schedule, self.backend)
validate_qobj_against_schema(delay_qobj)

self.assertEqual(orig_qobj.experiments[0].to_dict(),
delay_qobj.experiments[0].to_dict())
validate_qobj_against_schema(delay_qobj)
self.assertEqual(delay_qobj.experiments[0].instructions[0].name, "delay")
self.assertEqual(delay_qobj.experiments[0].instructions[0].duration, 10)

def test_assemble_schedule_enum(self):
"""Test assembling a schedule with enum input values to assemble."""
Expand Down
6 changes: 3 additions & 3 deletions test/python/compiler/test_disassembler.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ def test_disassemble_single_schedule(self):
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], sched.exclude(instruction_types=[pulse.Delay]))
self.assertEqual(scheds[0], sched)

def test_disassemble_multiple_schedules(self):
"""Test disassembling multiple schedules, all should have the same config.
Expand Down Expand Up @@ -290,8 +290,8 @@ def test_disassemble_multiple_schedules(self):
self.assertEqual(run_config_out.shots, 2000)
self.assertEqual(run_config_out.memory, False)
self.assertEqual(len(scheds), 2)
self.assertEqual(scheds[0], sched0.exclude(instruction_types=[pulse.Delay]))
self.assertEqual(scheds[1], sched1.exclude(instruction_types=[pulse.Delay]))
self.assertEqual(scheds[0], sched0)
self.assertEqual(scheds[1], sched1)

def test_disassemble_parametric_pulses(self):
"""Test disassembling multiple schedules all should have the same config.
Expand Down

0 comments on commit 5fb8100

Please sign in to comment.