Skip to content
This repository has been archived by the owner on Jul 24, 2024. It is now read-only.

Add dynamic circuits scheduling pass #365

Merged
merged 65 commits into from
Aug 24, 2022
Merged
Changes from 1 commit
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
450922b
Fix lint for Qiskit main branch.
taalexander Jul 6, 2022
5c61448
Fix sphinx language configuration.
taalexander Jul 6, 2022
0658c7a
Add initial scaffolding for dynamic_circuits module.
taalexander Jun 17, 2022
4dbe92a
Add a dummy test.
taalexander Jun 17, 2022
44a7afb
Add reno.
taalexander Jun 17, 2022
8aa3365
Add initial qiskit DynamicalDecoupling scheduling scaffolding and tests.
taalexander Jun 17, 2022
06f9d86
Refactor scheduler with visitor pattern.
taalexander Jun 19, 2022
a518281
Refactor nodes to no longer return. Remove special handling for class…
taalexander Jun 19, 2022
bfcfe2e
Add block based scheduling and updated tests for dynamic circuits typ…
taalexander Jun 27, 2022
9a0955c
Refactor padder class.
taalexander Jul 5, 2022
1744ae4
Base padding is working.
taalexander Jul 5, 2022
4340be0
Remove debug statements.
taalexander Jul 5, 2022
9e2d5ae
Update non conditional tests to pass.
taalexander Jul 5, 2022
3cd3859
c_if scheduling tests are working.
taalexander Jul 5, 2022
b48951d
All tests passing.
taalexander Jul 5, 2022
3efa7da
All dynamic circuits tests passing.
taalexander Jul 6, 2022
96e02fb
Black formatting.
taalexander Jul 6, 2022
9dddf1e
Move the dynamic_circuits module to a generic transpiler module.
taalexander Jul 6, 2022
2442d1e
Blackify
taalexander Jul 6, 2022
7e144e9
Linting.
taalexander Jul 6, 2022
42c8bc8
Blackify.
taalexander Jul 6, 2022
615f03c
Reach black and pylint fixed point.
taalexander Jul 6, 2022
70ae09d
Mypyify the code.
taalexander Jul 6, 2022
36c611e
Merge branch 'main' into add-scheduling-pass
rathishcholarajan Jul 6, 2022
b4f8f9b
Add initial scaffolding for dynamic_circuits module.
taalexander Jun 17, 2022
af86472
Add a dummy test.
taalexander Jun 17, 2022
b42cf0c
Add reno.
taalexander Jun 17, 2022
0bef47b
Add initial qiskit DynamicalDecoupling scheduling scaffolding and tests.
taalexander Jun 17, 2022
f97fa79
Refactor scheduler with visitor pattern.
taalexander Jun 19, 2022
e9db084
Refactor nodes to no longer return. Remove special handling for class…
taalexander Jun 19, 2022
eab1fdb
Add block based scheduling and updated tests for dynamic circuits typ…
taalexander Jun 27, 2022
dc4ea34
Refactor padder class.
taalexander Jul 5, 2022
6e173a5
Base padding is working.
taalexander Jul 5, 2022
f490053
Remove debug statements.
taalexander Jul 5, 2022
ccbad76
Update non conditional tests to pass.
taalexander Jul 5, 2022
25bba97
c_if scheduling tests are working.
taalexander Jul 5, 2022
65760f3
All tests passing.
taalexander Jul 5, 2022
d7cbdd5
All dynamic circuits tests passing.
taalexander Jul 6, 2022
2be8de8
Black formatting.
taalexander Jul 6, 2022
eb33397
Move the dynamic_circuits module to a generic transpiler module.
taalexander Jul 6, 2022
8deed38
Blackify
taalexander Jul 6, 2022
bf0807b
Linting.
taalexander Jul 6, 2022
8b4a602
Blackify.
taalexander Jul 6, 2022
5ac8693
Reach black and pylint fixed point.
taalexander Jul 6, 2022
8f49cb1
Mypyify the code.
taalexander Jul 6, 2022
53ad4b4
Merge remote-tracking branch 'origin/add-scheduling-pass' into add-sc…
taalexander Jul 6, 2022
209cc8e
Rename BasePadding to BlockBasePadder.
taalexander Jul 6, 2022
89e7fba
Fix broken tests by Qiskit upgrade.
taalexander Jul 6, 2022
ee823a5
Move tests into unit.
taalexander Jul 6, 2022
4c33ca7
linting.
taalexander Jul 6, 2022
aea5473
Update documentation.
taalexander Jul 6, 2022
ea37d66
Fix requirements dev for matplotlib drawer./
taalexander Jul 6, 2022
69cbab4
Chain qargs and cargs.
taalexander Jul 6, 2022
b1943a6
Update pulse block comment.
taalexander Jul 6, 2022
2b971b3
Update measurement comment.
taalexander Jul 6, 2022
44a1905
Add t0 comment.
taalexander Jul 6, 2022
2d995df
Move scheduler unit tests.
taalexander Jul 6, 2022
931fe00
Make scheduler idempotent.
taalexander Jul 7, 2022
783d608
Operations on qubits already measured trigger block termination.
taalexander Jul 7, 2022
b777249
Black.
taalexander Jul 7, 2022
81596b1
Update comment on _visit_measure qargs.
taalexander Aug 11, 2022
d50b28b
Update comment typo.
taalexander Aug 11, 2022
97e5bcd
Update comment on neighbor ordering.
taalexander Aug 11, 2022
b5d9e31
Add comments.
taalexander Aug 11, 2022
ff25a88
Merge branch 'main' into add-scheduling-pass
kt474 Aug 24, 2022
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
Prev Previous commit
Next Next commit
Add initial qiskit DynamicalDecoupling scheduling scaffolding and tests.
taalexander committed Jul 6, 2022
commit 0bef47b099ce46264a868ad3df1388cfcf5bf5dd
2 changes: 0 additions & 2 deletions qiskit_ibm_provider/dynamic_circuits/__init__.py
Original file line number Diff line number Diff line change
@@ -49,5 +49,3 @@


"""

foo = 1
142 changes: 142 additions & 0 deletions qiskit_ibm_provider/dynamic_circuits/schedule.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2022.
#
# 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.

"""Scheduler for dynamic circuit backends."""

from qiskit.circuit import Measure
from qiskit.transpiler.exceptions import TranspilerError

from qiskit.transpiler.passes.scheduling.scheduling.base_scheduler import BaseScheduler


class DynamicCircuitScheduleAnalysis(BaseScheduler):
"""Dynamic circuits scheduling analysis pass.

This is a scheduler designed to work for the unique scheduling constraints of the dynamic circuits
backends due to the limitations imposed by hardware. This is expected to evolve overtime as the
dynamic circuit backends also change.

In its current form this is slow to Qiskit's ASAP scheduler in which instructions start asas early as possible.

The primary differences are that:

* Measurements currently trigger the end of a "quantum block". The period between the end of the block and the next is *indeterministic*
ie., we do not know when the next block will begin (as we could be evaluating a classical function of indeterministic length) and
therefore the next block starts at a *relative* t=0.
* It is possible to apply gates during a measurement.
* Measurements on disjoint qubits happen simulataneously and are part of the same block. Measurements that are not lexigraphically
neighbors in the generated QASM3 will happen in separate blocks.

"""

def run(self, dag):
"""Run the ASAPSchedule pass on `dag`.
Args:
dag (DAGCircuit): DAG to schedule.
Returns:
DAGCircuit: A scheduled DAG.
Raises:
TranspilerError: if the circuit is not mapped on physical qubits.
TranspilerError: if conditional bit is added to non-supported instruction.
"""
if len(dag.qregs) != 1 or dag.qregs.get("q", None) is None:
raise TranspilerError("ASAP schedule runs on physical circuits only")

conditional_latency = self.property_set.get("conditional_latency", 0)
clbit_write_latency = self.property_set.get("clbit_write_latency", 0)

node_start_time = dict()
idle_after = {q: 0 for q in dag.qubits + dag.clbits}
bit_indices = {q: index for index, q in enumerate(dag.qubits)}
for node in dag.topological_op_nodes():
op_duration = self._get_node_duration(node, bit_indices, dag)

# compute t0, t1: instruction interval, note that
# t0: start time of instruction
# t1: end time of instruction
if isinstance(node.op, self.CONDITIONAL_SUPPORTED):
t0q = max(idle_after[q] for q in node.qargs)
if node.op.condition_bits:
# conditional is bit tricky due to conditional_latency
t0c = max(idle_after[bit] for bit in node.op.condition_bits)
if t0q > t0c:
# This is situation something like below
#
# |t0q
# Q ▒▒▒▒▒▒▒▒▒░░
# C ▒▒▒░░░░░░░░
# |t0c
#
# In this case, you can insert readout access before tq0
#
# |t0q
# Q ▒▒▒▒▒▒▒▒▒▒▒
# C ▒▒▒░░░▒▒░░░
# |t0q - conditional_latency
#
t0c = max(t0q - conditional_latency, t0c)
t1c = t0c + conditional_latency
for bit in node.op.condition_bits:
# Lock clbit until state is read
idle_after[bit] = t1c
# It starts after register read access
t0 = max(t0q, t1c)
else:
t0 = t0q
t1 = t0 + op_duration
else:
if node.op.condition_bits:
raise TranspilerError(
f"Conditional instruction {node.op.name} is not supported in ASAP scheduler."
)

if isinstance(node.op, Measure):
# measure instruction handling is bit tricky due to clbit_write_latency
t0q = max(idle_after[q] for q in node.qargs)
t0c = max(idle_after[c] for c in node.cargs)
# Assume following case (t0c > t0q)
#
# |t0q
# Q ▒▒▒▒░░░░░░░░░░░░
# C ▒▒▒▒▒▒▒▒░░░░░░░░
# |t0c
#
# In this case, there is no actual clbit access until clbit_write_latency.
# The node t0 can be push backward by this amount.
#
# |t0q' = t0c - clbit_write_latency
# Q ▒▒▒▒░░▒▒▒▒▒▒▒▒▒▒
# C ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
# |t0c' = t0c
#
# rather than naively doing
#
# |t0q' = t0c
# Q ▒▒▒▒░░░░▒▒▒▒▒▒▒▒
# C ▒▒▒▒▒▒▒▒░░░▒▒▒▒▒
# |t0c' = t0c + clbit_write_latency
#
t0 = max(t0q, t0c - clbit_write_latency)
t1 = t0 + op_duration
for clbit in node.cargs:
idle_after[clbit] = t1
else:
# It happens to be directives such as barrier
t0 = max(idle_after[bit] for bit in node.qargs + node.cargs)
t1 = t0 + op_duration

for bit in node.qargs:
idle_after[bit] = t1

node_start_time[node] = t0

self.property_set["node_start_time"] = node_start_time
1 change: 1 addition & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -25,3 +25,4 @@ websockets>=8
black==22.3.0
coverage>=6.3
scikit-learn>=0.20.0
ddt>=1.2.0,!=1.4.0,!=1.4.3
626 changes: 626 additions & 0 deletions test/dynamic_circuits/test_schedule.py

Large diffs are not rendered by default.