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

[WIP] Dynamical decoupling #11

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 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
1 change: 1 addition & 0 deletions how_tos/data/graph_hardware_native_127nodes_001.json

Large diffs are not rendered by default.

442 changes: 442 additions & 0 deletions how_tos/how_to_add_dynamical_decoupling.ipynb

Large diffs are not rendered by default.

148 changes: 148 additions & 0 deletions qopt_best_practices/data/edge_coloring/eagle.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
{
"edge colors": [
{"key": [2, 1], "value": 0},
{"key": [33, 39], "value": 0},
{"key": [59, 60], "value": 0},
{"key": [66, 67], "value": 0},
{"key": [72, 81], "value": 0},
{"key": [118, 119], "value": 0},
{"key": [21, 20], "value": 0},
{"key": [26, 25], "value": 0},
{"key": [13, 12], "value": 0},
{"key": [31, 32], "value": 0},
{"key": [70, 74], "value": 0},
{"key": [122, 123], "value": 0},
{"key": [97, 96], "value": 0},
{"key": [57, 56], "value": 0},
{"key": [63, 64], "value": 0},
{"key": [107, 108], "value": 0},
{"key": [103, 104], "value": 0},
{"key": [46, 45], "value": 0},
{"key": [28, 35], "value": 0},
{"key": [7, 6], "value": 0},
{"key": [79, 78], "value": 0},
{"key": [5, 4], "value": 0},
{"key": [109, 114], "value": 0},
{"key": [62, 61], "value": 0},
{"key": [58, 71], "value": 0},
{"key": [37, 52], "value": 0},
{"key": [76, 77], "value": 0},
{"key": [0, 14], "value": 0},
{"key": [36, 51], "value": 0},
{"key": [106, 105], "value": 0},
{"key": [73, 85], "value": 0},
{"key": [88, 87], "value": 0},
{"key": [68, 55], "value": 0},
{"key": [116, 115], "value": 0},
{"key": [94, 95], "value": 0},
{"key": [100, 110], "value": 0},
{"key": [17, 30], "value": 0},
{"key": [92, 102], "value": 0},
{"key": [50, 49], "value": 0},
{"key": [83, 84], "value": 0},
{"key": [48, 47], "value": 0},
{"key": [98, 99], "value": 0},
{"key": [8, 9], "value": 0},
{"key": [121, 120], "value": 0},
{"key": [23, 24], "value": 0},
{"key": [44, 43], "value": 0},
{"key": [22, 15], "value": 0},
{"key": [53, 41], "value": 0},
{"key": [53, 60], "value": 1},
{"key": [123, 124], "value": 1},
{"key": [21, 22], "value": 1},
{"key": [11, 12], "value": 1},
{"key": [67, 68], "value": 1},
{"key": [2, 3], "value": 1},
{"key": [66, 65], "value": 1},
{"key": [122, 121], "value": 1},
{"key": [110, 118], "value": 1},
{"key": [6, 5], "value": 1},
{"key": [94, 90], "value": 1},
{"key": [28, 29], "value": 1},
{"key": [14, 18], "value": 1},
{"key": [62, 63], "value": 1},
{"key": [111, 104], "value": 1},
{"key": [100, 99], "value": 1},
{"key": [45, 44], "value": 1},
{"key": [4, 15], "value": 1},
{"key": [20, 19], "value": 1},
{"key": [57, 58], "value": 1},
{"key": [77, 71], "value": 1},
{"key": [76, 75], "value": 1},
{"key": [26, 27], "value": 1},
{"key": [16, 8], "value": 1},
{"key": [35, 47], "value": 1},
{"key": [31, 30], "value": 1},
{"key": [48, 49], "value": 1},
{"key": [69, 70], "value": 1},
{"key": [125, 126], "value": 1},
{"key": [89, 74], "value": 1},
{"key": [80, 79], "value": 1},
{"key": [116, 117], "value": 1},
{"key": [114, 113], "value": 1},
{"key": [10, 9], "value": 1},
{"key": [106, 93], "value": 1},
{"key": [101, 102], "value": 1},
{"key": [92, 83], "value": 1},
{"key": [98, 91], "value": 1},
{"key": [82, 81], "value": 1},
{"key": [54, 64], "value": 1},
{"key": [96, 109], "value": 1},
{"key": [85, 84], "value": 1},
{"key": [87, 86], "value": 1},
{"key": [108, 112], "value": 1},
{"key": [34, 24], "value": 1},
{"key": [42, 43], "value": 1},
{"key": [40, 41], "value": 1},
{"key": [39, 38], "value": 1},
{"key": [10, 11], "value": 2},
{"key": [54, 45], "value": 2},
{"key": [111, 122], "value": 2},
{"key": [64, 65], "value": 2},
{"key": [60, 61], "value": 2},
{"key": [103, 102], "value": 2},
{"key": [72, 62], "value": 2},
{"key": [4, 3], "value": 2},
{"key": [33, 20], "value": 2},
{"key": [58, 59], "value": 2},
{"key": [26, 16], "value": 2},
{"key": [28, 27], "value": 2},
{"key": [8, 7], "value": 2},
{"key": [104, 105], "value": 2},
{"key": [66, 73], "value": 2},
{"key": [87, 93], "value": 2},
{"key": [85, 86], "value": 2},
{"key": [55, 49], "value": 2},
{"key": [68, 69], "value": 2},
{"key": [89, 88], "value": 2},
{"key": [80, 81], "value": 2},
{"key": [117, 118], "value": 2},
{"key": [101, 100], "value": 2},
{"key": [114, 115], "value": 2},
{"key": [96, 95], "value": 2},
{"key": [29, 30], "value": 2},
{"key": [106, 107], "value": 2},
{"key": [83, 82], "value": 2},
{"key": [91, 79], "value": 2},
{"key": [0, 1], "value": 2},
{"key": [56, 52], "value": 2},
{"key": [90, 75], "value": 2},
{"key": [126, 112], "value": 2},
{"key": [36, 32], "value": 2},
{"key": [46, 47], "value": 2},
{"key": [77, 78], "value": 2},
{"key": [97, 98], "value": 2},
{"key": [17, 12], "value": 2},
{"key": [119, 120], "value": 2},
{"key": [22, 23], "value": 2},
{"key": [24, 25], "value": 2},
{"key": [43, 34], "value": 2},
{"key": [42, 41], "value": 2},
{"key": [40, 39], "value": 2},
{"key": [37, 38], "value": 2},
{"key": [125, 124], "value": 2},
{"key": [50, 51], "value": 2},
{"key": [18, 19], "value": 2}
]
}
1 change: 1 addition & 0 deletions qopt_best_practices/transpilation/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .dynamical_decoupling import dd_pass_manager
87 changes: 87 additions & 0 deletions qopt_best_practices/transpilation/dynamical_decoupling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@

from typing import Dict, Optional

from qiskit.transpiler import PassManager
from qiskit.circuit.library import XGate, YGate

from qiskit_ibm_provider.transpiler.passes.scheduling import (
DynamicCircuitInstructionDurations,
ALAPScheduleAnalysis,
PadDynamicalDecoupling,
PadDelay,
)


PASSES = {
"staggered_XY4": {
"spacings": [0.125, 0.25, 0.25, 0.25, 0.125],
"alt_spacings": [0.25, 0.25, 0.25, 0.25, 0],
"dd_sequences": [XGate(), YGate(), XGate(), YGate()],
},
"staggered_XX": {
"spacings": [0.25, 0.5, 0.25],
"alt_spacings": [0.25, 0.25, 0.25, 0.25, 0],
"dd_sequences": [XGate(), XGate()],
},
"XY4": {
"spacings": [0.125, 0.25, 0.25, 0.25, 0.125],
"alt_spacings": None, # TODO Check
"dd_sequences": [XGate(), YGate(), XGate(), YGate()],
},
"XX": {
"spacings": [0.25, 0.5, 0.25],
"alt_spacings": None, # TODO Check
"dd_sequences": [XGate(), XGate()],
},
}


def dd_pass_manager(
backend,
dd_sequence: Optional[str] = None,
dd_config: Optional[Dict] = None,
):
"""Make a pass-manager that inserts a Dynamical Decoupling sequence into a circuit.

This is a helper function to make a dynamical decoupling PassManager.

Args:
backend: The backend for which to generate the DD sequence. This is needed
because we need to know the duration of the instructions.
dd_sequence: A string to specify the DD sequence to use. This corresponds to preset
values for the gates to insert, the spacings between the gates, as well as the
`alt_spacings` that can be leveraged for staggered DD.
dd_config: If users do not want to use a preset DD configuration then they can
specify the arguments to `PadDynamicalDecoupling` themselves. The config should
include the arguments `dd_sequences`, `spacings`, and `alt_spacings`.
"""
min_seq_ratio = 1

durations = DynamicCircuitInstructionDurations.from_backend(backend)

# Some backends do not report the duration of the Y gate.
phys_qs = list(range(backend.num_qubits))
durations.update(DynamicCircuitInstructionDurations(
[("y", i, durations.get('x', i)) for i in phys_qs])
)

if dd_config is None:
dd_config = PASSES.get(dd_sequence, None)

if dd_config is None:
raise ValueError(f"Unknown DD sequence. Options for `dd_sequence` are {PASSES.keys()}.")

return PassManager(
[
ALAPScheduleAnalysis(durations),
PadDynamicalDecoupling(
durations,
dd_sequences=dd_config["dd_sequences"],
coupling_map=backend.coupling_map,
spacings=dd_config["spacings"],
alt_spacings=dd_config["alt_spacings"],
sequence_min_length_ratios=min_seq_ratio,
)
]
)

1 change: 1 addition & 0 deletions qopt_best_practices/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@


from .graph_utils import build_max_cut_graph, build_max_cut_paulis
from .edge_coloring import load_edge_coloring

__all__ = ["build_max_cut_graph", "build_max_cut_paulis"]
32 changes: 32 additions & 0 deletions qopt_best_practices/utils/edge_coloring.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import json
import os
from typing import Dict


def load_edge_coloring(device: str = "eagle", symmetric: bool = True) -> Dict[tuple, int]:
"""Load an edge coloring.

Args:
device: The type of device to use. For now, the supported device in `eagle` only.
symmetric: A boolean. If this is set to True then if edge `(i, j)` is in the coloring
we will also add edge `(j, i)`.

Returns:
An edge coloring of the coupling map of the given type of device. The edge coloring
is a mapping between an edge, specified as a tuple, and a number.
"""

edge_file = os.path.join(os.path.dirname(__file__), f"../data/edge_coloring/{device}.json")

with open(edge_file, "r") as fin:
data = json.load(fin)

edge_coloring = {}
for edge_data in data["edge colors"]:
edge = tuple(edge_data["key"])
edge_coloring[edge] = edge_data["value"]

if symmetric:
edge_coloring[edge[::-1]] = edge_data["value"]

return edge_coloring
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ networkx
# preventively pinning qiskit in anticipation of
# breaking changes in 1.0
qiskit>=0.44,<1.0
qiskit-ibm-provider
Loading