Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert delays to instructions when assembling (bp #5481) #5615

Merged
merged 1 commit into from
Jan 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions qiskit/assembler/assemble_schedules.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,10 +196,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 @@ -338,6 +338,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 @@ -524,6 +524,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 @@ -812,16 +823,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