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

Command/Inst refactor: Delay #3924

Merged
merged 20 commits into from
Mar 11, 2020
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
7d7c364
Migrate Delay from a Command to an Instruction, and deprecate DelayIn…
lcapelluto Feb 18, 2020
0fdd44c
Scattering of bugfixes
lcapelluto Mar 4, 2020
dcfe20d
Remove extra line
lcapelluto Mar 4, 2020
d54e890
Add reno note update
lcapelluto Mar 4, 2020
fda68db
Add new test
lcapelluto Mar 5, 2020
2fe6f7a
Merge branch 'master' into issue-3750-delay-instruction
lcapelluto Mar 9, 2020
93e4dfe
Update qiskit/pulse/instructions/delay.py
lcapelluto Mar 9, 2020
96bb9f3
Fix up releasenote, single : to double ::
lcapelluto Mar 9, 2020
631ed1c
Merge branch 'issue-3750-delay-instruction' of github.com:lcapelluto/…
lcapelluto Mar 9, 2020
1b3122f
Give instructions a default name
lcapelluto Mar 9, 2020
0d17d5b
Merge branch 'master' into issue-3750-delay-instruction
lcapelluto Mar 9, 2020
6d26b53
Merge branch 'master' into issue-3750-delay-instruction
mergify[bot] Mar 10, 2020
c51d8b2
Merge branch 'master' into issue-3750-delay-instruction
mergify[bot] Mar 10, 2020
4ad2e1b
Merge branch 'master' into issue-3750-delay-instruction
mergify[bot] Mar 10, 2020
c633ba7
Merge branch 'master' into issue-3750-delay-instruction
mergify[bot] Mar 10, 2020
c4a0d76
Merge branch 'master' into issue-3750-delay-instruction
mergify[bot] Mar 10, 2020
5279286
Merge branch 'master' into issue-3750-delay-instruction
mergify[bot] Mar 10, 2020
85ac1f3
Merge branch 'master' into issue-3750-delay-instruction
lcapelluto Mar 11, 2020
ae8bd12
Update releasenote as a deprecation
lcapelluto Mar 11, 2020
9bc6483
Fixup release notes typo: deprecation needs to be plural
lcapelluto Mar 11, 2020
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: 2 additions & 2 deletions qiskit/assembler/assemble_schedules.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from collections import defaultdict

from qiskit.exceptions import QiskitError
from qiskit.pulse import Schedule
from qiskit.pulse import Schedule, Delay
from qiskit.pulse.commands import (Command, PulseInstruction, Acquire, AcquireInstruction,
DelayInstruction, SamplePulse, ParametricInstruction)
from qiskit.qobj import (PulseQobj, QobjHeader, QobjExperimentHeader,
Expand Down Expand Up @@ -193,7 +193,7 @@ def _assemble_instructions(
acquire_instruction_map[(time, instruction.command)].append(instruction)
continue

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

Expand Down
4 changes: 2 additions & 2 deletions qiskit/pulse/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,12 @@
from .cmd_def import CmdDef
from .commands import (Acquire, AcquireInstruction, FrameChange,
PersistentValue, SamplePulse, Snapshot, Kernel,
Discriminator, Delay, ParametricPulse,
Discriminator, ParametricPulse,
ParametricInstruction, Gaussian,
GaussianSquare, Drag, ConstantPulse, functional_pulse)
from .configuration import LoConfig, LoRange
from .exceptions import PulseError
from .instruction_schedule_map import InstructionScheduleMap
from .instructions import Instruction
from .instructions import Instruction, Delay
from .interfaces import ScheduleComponent
from .schedule import Schedule
62 changes: 8 additions & 54 deletions qiskit/pulse/commands/delay.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,65 +12,15 @@
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""
Delay instruction.
"""
from typing import Optional
"""Delay instruction. Deprecated path."""
import warnings

from qiskit.pulse.channels import Channel
from ..instructions import Delay
from ..instructions import Instruction
from .command import Command


class Delay(Command):
"""Delay command."""

prefix = 'delay'

def __init__(self, duration: int, name: Optional[str] = None):
"""Create a new delay command.

No other command may be scheduled within a delay command.

Delays that exist as the last instruction on a channel will be removed.

Note: Delays are not explicitly sent to backends with the current Qobj
transport layer. They are only used to enforce the correct offset in time
for instructions that will be submitted directly to the backend.

Args:
duration: Length of time of the delay in terms of dt.
name: Name of delay command for display purposes.
"""
super().__init__(duration=duration)
self._name = Delay.create_name(name)

# pylint: disable=arguments-differ
def to_instruction(self, channel: Channel, name: str = None) -> 'DelayInstruction':
"""Create a delay instruction on the given channel.

Args:
channel: Channel for delay instruction to be created.
name: Name of delay instruction for display purposes.

Returns:
DelayInstruction
"""
return DelayInstruction(self, channel, name=name)
# pylint: enable=arguments-differ


class DelayInstruction(Instruction):
"""Instruction to add a blocking delay on a `Channel`.

No other may be scheduled within a delay command.

Delays that exist as the last instruction on a channel will be removed.

Note: Delay's are not explicitly sent to backends with the current Qobj
transport layer. They are only used to enforce the correct offset in time
for instructions that will be submitted directly to the backend.
"""
"""Deprecated."""

def __init__(self, command: Delay, channel: Delay, name: str = None):
"""Create a delay instruction from a delay command.
Expand All @@ -80,4 +30,8 @@ def __init__(self, command: Delay, channel: Delay, name: str = None):
channel: Channel for delay instruction to be created.
name: Name of delay instruction for display purposes.
"""
warnings.warn("The DelayInstruction is deprecated. Use Delay, instead, with channels. "
"For example: DelayInstruction(Delay(5), DriveChannel(0)) -> "
"Delay(5, DriveChannel(0)).",
DeprecationWarning)
super().__init__(command, channel, name=name)
1 change: 1 addition & 0 deletions qiskit/pulse/instructions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@
An instruction can be added to a :py:class:`~qiskit.pulse.Schedule`, which is a
sequence of scheduled Pulse ``Instruction`` s over many channels.
"""
from .delay import Delay
from .instruction import Instruction
93 changes: 93 additions & 0 deletions qiskit/pulse/instructions/delay.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# -*- coding: utf-8 -*-

# This code is part of Qiskit.
#
# (C) Copyright IBM 2020.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""An instruction for blocking time on a channel; useful for scheduling alignment."""
import warnings

from typing import List, Optional, Union

from qiskit.pulse.channels import PulseChannel
from qiskit.pulse.exceptions import PulseError
from .instruction import Instruction


class Delay(Instruction):
"""A blocking instruction with no other effect. The delay is used for aligning and scheduling
other instructions.

Example:

To schedule an instruction at time = 10, on a channel assigned to the variable ``channel``,
the following could be used::

sched = Schedule(name="Delay instruction example")
sched += Delay(10, channel)
sched += Gaussian(duration, amp, sigma, channel)

The ``channel`` will output no signal from time=0 up until time=10.
"""

def __init__(self, duration: int,
channel: Optional[PulseChannel] = None,
name: Optional[str] = None):
"""Create a new delay instruction.

No other instruction may be scheduled within a ``Delay``.

Args:
duration: Length of time of the delay in terms of dt.
channel: The channel that will have the delay.
name: Name of the delay for display purposes.
"""
if channel is None:
warnings.warn("Usage of Delay without specifying a channel is deprecated. For "
"example, Delay(5)(DriveChannel(0)) should be replaced by "
"Delay(5, DriveChannel(0)).", DeprecationWarning)
self._channel = channel
super().__init__(duration, channel, name=name)

@property
def operands(self) -> List[Union[int, PulseChannel]]:
"""Return a list of instruction operands."""
return [self.duration, self.channel]

@property
def channel(self) -> PulseChannel:
"""Return the :py:class:`~qiskit.pulse.channels.Channel` that this instruction is
scheduled on.
"""
return self._channel

def __call__(self, channel: PulseChannel) -> 'Delay':
"""Return new ``Delay`` that is fully instantiated with both ``duration`` and a ``channel``.

Args:
channel: The channel that will have the delay.

Return:
Complete and ready to schedule ``Delay``.

Raises:
PulseError: If ``channel`` has already been set.
"""
warnings.warn("Calling Delay with a channel is deprecated. Instantiate the delay with "
"a channel instead.", DeprecationWarning)
if self._channel is not None:
raise PulseError("The channel has already been assigned as {}.".format(self.channel))
return Delay(self.duration, channel)

def __repr__(self):
return "{}({}, {})".format(self.__class__.__name__,
self.duration,
self.channel)
15 changes: 9 additions & 6 deletions qiskit/pulse/instructions/instruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,22 @@ def __init__(self, duration: Union['commands.Command', int],
*channels: List of pulse channels that this instruction operates on.
name: Display name for this instruction.
"""
self._name = name

self._command = None
if not isinstance(duration, int):
# TODO: Add deprecation warning once all instructions are migrated
self._command = duration
if name is None:
self._name = self.command.name
name = self.command.name
duration = self.command.duration
self._duration = duration

self._timeslots = TimeslotCollection(*(Timeslot(Interval(0, duration), channel)
for channel in channels if channel is not None))

if name is None:
name = "{}{}".format(self.__class__.__name__.lower(), str(hex(self.__hash__()))[3:8])
self._name = name

@property
def name(self) -> str:
"""Name of this instruction."""
Expand Down Expand Up @@ -101,7 +104,7 @@ def stop_time(self) -> int:
@property
def duration(self) -> int:
"""Duration of this instruction."""
return self.timeslots.duration
return self._duration

@property
def _children(self) -> Tuple[ScheduleComponent]:
Expand Down Expand Up @@ -270,8 +273,8 @@ def __eq__(self, other: 'Instruction'):
def __hash__(self):
if self.command:
# Backwards compatibility for Instructions with Commands
return hash((hash(tuple(self.command)), self.channels.__hash__()))
return hash((hash(tuple(self.duration)), self.channels.__hash__()))
return hash(((tuple(self.command)), self.channels.__hash__()))
return hash((self.duration, self.channels.__hash__()))

def __add__(self, other: ScheduleComponent) -> Schedule:
"""Return a new schedule with `other` inserted within `self` at `start_time`."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,18 @@ features:

sched += Delay(5, DriveChannel(0))
sched += ShiftPhase(np.pi, DriveChannel(0))
upgrade:
- |
``DelayInstruction`` has been deprecated and replaced by
:py:class:`~qiskit.pulse.instruction.Delay`. The migration pattern is::

Delay(<duration>)(<channel>) -> Delay(<duration>, <channel>)
DelayInstruction(Delay(<duration>), <channel>)
-> Delay(<duration>, <channel>)

Until the deprecation period is over, the previous ``Delay`` syntax of
calling a command on a channel will also be supported::

Delay(<phase>)(<channel>)

The new ``Delay`` instruction does not support a ``command`` attribute.
32 changes: 32 additions & 0 deletions test/python/pulse/test_instructions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-

# This code is part of Qiskit.
#
# (C) Copyright IBM 2020.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

# pylint: disable=invalid-name,unexpected-keyword-arg

"""Unit tests for pulse instructions."""

from qiskit.pulse import Delay, DriveChannel
from qiskit.test import QiskitTestCase


class TestDelayCommand(QiskitTestCase):
"""Delay tests."""

def test_delay(self):
"""Test delay."""
delay = Delay(10, DriveChannel(0), name='test_name')

self.assertEqual(delay.name, "test_name")
self.assertEqual(delay.duration, 10)
self.assertEqual(delay.operands, [10, DriveChannel(0)])