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

#2262 | Acquire commands on a single qubit #3574

Merged
merged 33 commits into from
Jan 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
2a03f3d
Acquire: AcquireInstruction change to sigle qbit, mem_slot, reg_slot
IceKhan13 Dec 9, 2019
eacbca2
Acquire: change usage of AcquireInstruction
IceKhan13 Dec 11, 2019
653d4e7
Tests: partial test fixing
IceKhan13 Dec 14, 2019
8f91f59
Assembler: tweak scheduler assembler to laverage new acquire + tests …
IceKhan13 Dec 17, 2019
8345e8f
Merge branch 'master' into chore/acquire-only-for-one-qubit
IceKhan13 Dec 17, 2019
29f87e8
Scheduler: fix scheduler to use acquire on single qubit + tests fix
IceKhan13 Dec 17, 2019
a535f58
Style: fix lint errors
IceKhan13 Dec 17, 2019
5dbf5a9
Acquire: remove unecessary properties
IceKhan13 Dec 18, 2019
c1b929a
Style: fix lint errors
IceKhan13 Dec 18, 2019
be2f4ca
Acuqire: back compatibility on acquire multiple qubits
IceKhan13 Jan 12, 2020
5091862
Acuqire: fix linter
IceKhan13 Jan 12, 2020
87b07ac
Acquire: refactor
IceKhan13 Jan 14, 2020
f7d6249
Acquire: fix implicit acquires; todo: revisit _validate_meas_map method
IceKhan13 Jan 17, 2020
8270c1e
Acquire: pylint fix
IceKhan13 Jan 17, 2020
35a2456
Acquire: minor fixes
IceKhan13 Jan 21, 2020
3b52da3
Acquire: fix add implicits acquires function
IceKhan13 Jan 21, 2020
5409099
Merge branch 'master' into chore/acquire-only-for-one-qubit
IceKhan13 Jan 21, 2020
95e0f80
Merge branch 'master' into chore/acquire-only-for-one-qubit
IceKhan13 Jan 22, 2020
5bc6e68
Acquire: instruction properties fix
IceKhan13 Jan 22, 2020
ee5fb0d
Acquire: remove test for validating meas map
IceKhan13 Jan 22, 2020
af8abb4
Linter: fix errors
IceKhan13 Jan 22, 2020
69a4c8b
Acquire: style fix
IceKhan13 Jan 23, 2020
fc3d2c5
Merge branch 'master' into chore/acquire-only-for-one-qubit
IceKhan13 Jan 23, 2020
5bf90b4
Merge branch 'master' into chore/acquire-only-for-one-qubit
IceKhan13 Jan 23, 2020
cdd5415
Acquire: remove deprecation in acquires property + fix positional arg…
IceKhan13 Jan 23, 2020
1b20c0b
Acquire: back and forward compatibility
IceKhan13 Jan 23, 2020
91e03ef
Acquire: remove deprecation warning (hm, I thought I removed it befor…
IceKhan13 Jan 23, 2020
2965695
Acquire: grammar fixes + split schedule acquire test
IceKhan13 Jan 24, 2020
eafd2a5
Acquire: add release note
IceKhan13 Jan 24, 2020
a011d29
Merge branch 'master' into chore/acquire-only-for-one-qubit
IceKhan13 Jan 24, 2020
2f1a2c3
Merge branch 'master' into chore/acquire-only-for-one-qubit
lcapelluto Jan 27, 2020
ce1d2fd
Acquire: release notes remove issues
IceKhan13 Jan 27, 2020
32dd418
Merge branch 'chore/acquire-only-for-one-qubit' of https://github.com…
IceKhan13 Jan 27, 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
19 changes: 14 additions & 5 deletions qiskit/assembler/assemble_schedules.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ def assemble_schedules(schedules, qobj_id, qobj_header, run_config):
# instructions
max_memory_slot = 0
qobj_instructions = []
acquire_instructions = []

# Instructions are returned as tuple of shifted time and instruction
for shift, instruction in schedule.instructions:
Expand Down Expand Up @@ -111,13 +112,16 @@ def assemble_schedules(schedules, qobj_id, qobj_header, run_config):
elif isinstance(instruction, AcquireInstruction):
max_memory_slot = max(max_memory_slot,
*[slot.index for slot in instruction.mem_slots])
if meas_map:
# verify all acquires satisfy meas_map
_validate_meas_map(instruction, meas_map)

acquire_instructions.append(instruction)

converted_instruction = instruction_converter(shift, instruction)
qobj_instructions.append(converted_instruction)

if meas_map:
# verify all acquires satisfy meas_map
_validate_meas_map(acquire_instructions, meas_map)

# memory slot size is memory slot index + 1 because index starts from zero
exp_memory_slot_size = max_memory_slot + 1
memory_slot_size = max(memory_slot_size, exp_memory_slot_size)
Expand Down Expand Up @@ -199,11 +203,16 @@ def assemble_schedules(schedules, qobj_id, qobj_header, run_config):
header=qobj_header)


def _validate_meas_map(acquire, meas_map):
def _validate_meas_map(instructions, meas_map):
"""Validate all qubits tied in meas_map are to be acquired."""
meas_map_set = [set(m) for m in meas_map]
# Verify that each qubit is listed once in measurement map
measured_qubits = {acq_ch.index for acq_ch in acquire.acquires}

acquires = []
for inst in instructions:
acquires += inst.acquires
measured_qubits = {acq_ch.index for acq_ch in acquires}

tied_qubits = set()
for meas_qubit in measured_qubits:
for map_inst in meas_map_set:
Expand Down
93 changes: 67 additions & 26 deletions qiskit/pulse/commands/acquire.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
"""
Acquire.
"""
from typing import Union, List, Optional
import warnings
from typing import Optional, Union, List

from qiskit.pulse.channels import Qubit, MemorySlot, RegisterSlot, AcquireChannel
from qiskit.pulse.exceptions import PulseError
Expand Down Expand Up @@ -93,11 +94,15 @@ def __repr__(self):

# pylint: disable=arguments-differ
def to_instruction(self,
qubits: Union[Qubit, List[Qubit]],
mem_slots: Optional[Union[MemorySlot, List[MemorySlot]]] = None,
qubit: Union[AcquireChannel, List[AcquireChannel]],
mem_slot: Optional[Union[MemorySlot, List[MemorySlot]]] = None,
reg_slots: Optional[Union[RegisterSlot, List[RegisterSlot]]] = None,
mem_slots: Optional[Union[List[MemorySlot]]] = None,
reg_slot: Optional[RegisterSlot] = None,
name: Optional[str] = None) -> 'AcquireInstruction':
return AcquireInstruction(self, qubits, mem_slots, reg_slots, name=name)

return AcquireInstruction(self, qubit, mem_slot=mem_slot, reg_slot=reg_slot,
mem_slots=mem_slots, reg_slots=reg_slots, name=name)
# pylint: enable=arguments-differ


Expand All @@ -106,40 +111,72 @@ class AcquireInstruction(Instruction):

def __init__(self,
IceKhan13 marked this conversation as resolved.
Show resolved Hide resolved
command: Acquire,
acquires: Union[AcquireChannel, List[AcquireChannel]],
IceKhan13 marked this conversation as resolved.
Show resolved Hide resolved
mem_slots: Union[MemorySlot, List[MemorySlot]],
acquire: Union[AcquireChannel, List[AcquireChannel]],
mem_slot: Optional[Union[MemorySlot, List[MemorySlot]]] = None,
reg_slots: Optional[Union[RegisterSlot, List[RegisterSlot]]] = None,
mem_slots: Optional[Union[List[MemorySlot]]] = None,
reg_slot: Optional[RegisterSlot] = None,
name: Optional[str] = None):

if not isinstance(acquires, list):
acquires = [acquires]
if isinstance(acquire, list) or isinstance(mem_slot, list) or reg_slots:
warnings.warn('The AcquireInstruction no longer supports multiple qubits, '
'multiple memory slots and multiple reg slots. '
'This behavior has been deprecated. The parameter '
'"mem_slots" has been replaced by "mem_slot" and '
'"reg_slots" has been replaced by "reg_slot"', DeprecationWarning, 3)

if not isinstance(acquire, list):
acquire = [acquire]

if isinstance(acquires[0], Qubit):
if isinstance(acquire[0], Qubit):
raise PulseError("AcquireInstruction can not be instantiated with Qubits, "
"which are deprecated.")

if not (mem_slots or reg_slots):
if mem_slot and not isinstance(mem_slot, list):
mem_slot = [mem_slot]
elif mem_slots:
mem_slot = mem_slots

if reg_slot:
reg_slot = [reg_slot]
elif reg_slots and not isinstance(reg_slots, list):
reg_slot = [reg_slots]
else:
reg_slot = reg_slots

if not (mem_slot or reg_slot):
raise PulseError('Neither memoryslots or registers were supplied')

if mem_slots:
if isinstance(mem_slots, MemorySlot):
mem_slots = [mem_slots]
elif len(acquires) != len(mem_slots):
raise PulseError("#mem_slots must be equals to #acquires")

if reg_slots:
if isinstance(reg_slots, RegisterSlot):
reg_slots = [reg_slots]
if len(acquires) != len(reg_slots):
raise PulseError("#reg_slots must be equals to #acquires")
if mem_slot and len(acquire) != len(mem_slot):
raise PulseError("The number of mem_slots must be equals to the number of acquires")

if reg_slot:
if len(acquire) != len(reg_slot):
raise PulseError("The number of reg_slots must be equals "
"to the number of acquires")
else:
reg_slots = []
reg_slot = []

super().__init__(command, *acquires, *mem_slots, *reg_slots, name=name)
super().__init__(command, *acquire, *mem_slot, *reg_slot, name=name)

self._acquires = acquires
self._mem_slots = mem_slots
self._reg_slots = reg_slots
self._acquires = acquire
self._mem_slots = mem_slot
self._reg_slots = reg_slot

@property
def acquire(self):
"""Acquire channel to be acquired on."""
return self._acquires[0] if self._acquires else None

@property
def mem_slot(self):
"""MemorySlot."""
return self._mem_slots[0] if self._mem_slots else None

@property
def reg_slot(self):
"""RegisterSlot."""
return self._reg_slots[0] if self._reg_slots else None

@property
def acquires(self):
IceKhan13 marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -149,9 +186,13 @@ def acquires(self):
@property
def mem_slots(self):
"""MemorySlots."""
warnings.warn('"mem_slots" is deprecated and being replaced by "mem_slot"',
DeprecationWarning, 3)
return self._mem_slots

@property
def reg_slots(self):
"""RegisterSlots."""
warnings.warn('"reg_slots" is deprecated and being replaced by "reg_slot"',
DeprecationWarning, 3)
return self._reg_slots
2 changes: 1 addition & 1 deletion qiskit/pulse/commands/instruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def __init__(self, command, *channels: List[Channel],
duration = command.duration

self._timeslots = TimeslotCollection(*(Timeslot(Interval(0, duration), channel)
for channel in channels))
for channel in channels if channel is not None))
lcapelluto marked this conversation as resolved.
Show resolved Hide resolved

channels = self.channels

Expand Down
14 changes: 10 additions & 4 deletions qiskit/pulse/reschedule.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,14 @@ def add_implicit_acquires(schedule: ScheduleComponent, meas_map: List[List[int]]
Schedule
"""
new_schedule = Schedule(name=schedule.name)
acquire_map = dict()

for time, inst in schedule.instructions:
if isinstance(inst, AcquireInstruction):
if any([acq.index != mem.index for acq, mem in zip(inst.acquires, inst.mem_slots)]):
IceKhan13 marked this conversation as resolved.
Show resolved Hide resolved
warnings.warn("One of your acquires was mapped to a memory slot which didn't match"
" the qubit index. I'm relabeling them to match.")

cmd = Acquire(inst.duration, inst.command.discriminator, inst.command.kernel)
# Get the label of all qubits that are measured with the qubit(s) in this instruction
existing_qubits = {chan.index for chan in inst.acquires}
Expand All @@ -155,10 +157,14 @@ def add_implicit_acquires(schedule: ScheduleComponent, meas_map: List[List[int]]
all_qubits.extend(sublist)
# Replace the old acquire instruction by a new one explicitly acquiring all qubits in
# the measurement group.
new_schedule |= AcquireInstruction(
IceKhan13 marked this conversation as resolved.
Show resolved Hide resolved
cmd,
[AcquireChannel(i) for i in all_qubits],
[MemorySlot(i) for i in all_qubits]) << time
for i in all_qubits:
explicit_inst = AcquireInstruction(cmd, AcquireChannel(i), MemorySlot(i)) << time
if time not in acquire_map:
new_schedule |= explicit_inst
acquire_map = {time: {i}}
elif i not in acquire_map[time]:
new_schedule |= explicit_inst
acquire_map[time].add(i)
else:
new_schedule |= inst << time

Expand Down
9 changes: 5 additions & 4 deletions qiskit/qobj/converters/pulse_instruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,15 +321,15 @@ def convert_acquire(self, instruction):
t0 = instruction.t0
duration = instruction.duration
qubits = instruction.qubits
qubit_channels = [channels.AcquireChannel(qubit) for qubit in qubits]
acquire_channels = [channels.AcquireChannel(qubit) for qubit in qubits]

mem_slots = [channels.MemorySlot(instruction.memory_slot[i]) for i in range(len(qubits))]

if hasattr(instruction, 'register_slot'):
register_slots = [channels.RegisterSlot(instruction.register_slot[i])
for i in range(len(qubits))]
else:
register_slots = None
register_slots = [None] * len(qubits)

discriminators = (instruction.discriminators
if hasattr(instruction, 'discriminators') else None)
Expand All @@ -356,8 +356,9 @@ def convert_acquire(self, instruction):

cmd = commands.Acquire(duration, discriminator=discriminator, kernel=kernel)
schedule = Schedule()
schedule |= commands.AcquireInstruction(cmd, qubit_channels, mem_slots,
register_slots) << t0

for acquire_channel, mem_slot, reg_slot in zip(acquire_channels, mem_slots, register_slots):
IceKhan13 marked this conversation as resolved.
Show resolved Hide resolved
schedule |= commands.AcquireInstruction(cmd, acquire_channel, mem_slot, reg_slot) << t0

return schedule

Expand Down
13 changes: 6 additions & 7 deletions qiskit/scheduler/methods/basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,16 +157,15 @@ def get_measure_schedule() -> CircuitPulseDef:
default_sched = inst_map.get('measure', qubits)
for time, inst in default_sched.instructions:
IceKhan13 marked this conversation as resolved.
Show resolved Hide resolved
if isinstance(inst, AcquireInstruction):
mem_slots = []
for channel in inst.acquires:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

acquires is deprecated now, so this causes a ton of deprecation warnings to be printed. We can either wait to deprecate acquires, use the private attribute (probably not the best idea), or suppress warnings around this line of code. The first might be the simplest and easiest to do.

if channel.index in qubit_mem_slots.keys():
mem_slots.append(MemorySlot(qubit_mem_slots[channel.index]))
mem_slot = MemorySlot(qubit_mem_slots[channel.index])
else:
mem_slots.append(MemorySlot(unused_mem_slots.pop()))
new_acquire = AcquireInstruction(command=inst.command,
acquires=inst.acquires,
mem_slots=mem_slots)
sched._union((time, new_acquire))
mem_slot = MemorySlot(unused_mem_slots.pop())
sched._union((time, AcquireInstruction(command=inst.command,
acquire=channel,
mem_slot=mem_slot)))

# Measurement pulses should only be added if its qubit was measured by the user
elif inst.channels[0].index in qubit_mem_slots.keys():
sched._union((time, inst))
Expand Down
20 changes: 20 additions & 0 deletions releasenotes/notes/acquire-single-channel-ea83cef8d991f945.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
prelude: >
Acquire and AcquireInstruction now can be applied to a single channel
features:
- |
Within the terra API allow acquires be applied to a single qubit.
This makes pulse programming more consistent and easier to reason
about as all operations in pulse would then be for single channels.
For example:

acquire = Acquire(duration=10)
schedule = Schedule()
schedule.insert(60, acquire(AcquireChannel(0), MemorySlot(0), RegisterSlot(0)))
schedule.insert(60, acquire(AcquireChannel(1), MemorySlot(1), RegisterSlot(1)))

deprecations:
- |
Acquire on multiple qubits has been deprecated.
``AcquireInstruction`` parameters ``mem_slots``, ``reg_slots`` has been deprecated,
use ``reg_slot``, ``mem_slot`` instead.
Loading