Skip to content

Commit

Permalink
changed cost functions to average error from vf2_utils and removed ma…
Browse files Browse the repository at this point in the history
…pomatic dependency
  • Loading branch information
nbronn committed Aug 7, 2024
1 parent 19c6eea commit b0f6dce
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 207 deletions.
3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ classifiers = [
requires-python = ">=3.8"

dependencies = [
"mapomatic==0.9",
"qiskit==0.46.0",
"qiskit==1.1.1",
"qiskit-aer",
"qiskit-ibm-runtime",
]
Expand Down
25 changes: 23 additions & 2 deletions qiskit_research/utils/cost_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,33 @@
from typing import List, Tuple

from qiskit.circuit import QuantumCircuit
from qiskit.converters import circuit_to_dag
from qiskit.providers.backend import Backend
from qiskit.qasm import pi

from qiskit.transpiler import Target
from qiskit.transpiler.passes.layout.vf2_utils import (
build_average_error_map,
build_interaction_graph,
score_layout,
)

from math import pi
import numpy as np


def avg_error_score(qc_isa: QuantumCircuit, target: Target) -> float:
init_layout = qc_isa.layout.final_index_layout()
dag = circuit_to_dag(qc_isa)

layout = {idx: init_layout[idx] for idx in range(len(init_layout))}
avg_error_map = build_average_error_map(target, None, None)
im_graph, im_graph_node_map, reverse_im_graph_node_map, _ = build_interaction_graph(
dag, strict_direction=False
)
return score_layout(
avg_error_map, layout, im_graph_node_map, reverse_im_graph_node_map, im_graph
)


def cost_func_scaled_cr(
circ: QuantumCircuit,
layouts: List[List[int]],
Expand Down
90 changes: 48 additions & 42 deletions qiskit_research/utils/dynamical_decoupling.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
from qiskit.dagcircuit import DAGCircuit, DAGInNode, DAGNode, DAGOpNode
from qiskit.providers.backend import Backend
from qiskit.pulse import Drag, Waveform
from qiskit.qasm import pi
from qiskit.synthesis import OneQubitEulerDecomposer
from qiskit.transpiler import InstructionDurations
from qiskit.transpiler.basepasses import BasePass
Expand All @@ -40,6 +39,8 @@
PeriodicDynamicalDecoupling,
)

from math import pi

X = XGate()
Xp = XpGate()
Xm = XmGate()
Expand Down Expand Up @@ -86,18 +87,18 @@ def dynamical_decoupling_passes(
Yields:
Iterator[Iterable[BasePass]]: Transpiler passes used for adding DD sequences.
"""
durations = get_instruction_durations(backend)
pulse_alignment = backend.configuration().timing_constraints["pulse_alignment"]
target = backend.target
for new_gate in [Xp, Xm, Yp, Ym]:
target.add_instruction(new_gate, target["x"])
durations = target.durations()

if dd_str in DD_SEQUENCE:
sequence = DD_SEQUENCE[dd_str]
elif dd_str == "URDD":
phis = get_urdd_angles(urdd_pulse_num)
sequence = tuple(PiPhiGate(phi) for phi in phis)
yield scheduler(durations)
yield PadDynamicalDecoupling(
durations, list(sequence), pulse_alignment=pulse_alignment
)
yield PadDynamicalDecoupling(durations, list(sequence))


def periodic_dynamical_decoupling(
Expand Down Expand Up @@ -126,42 +127,47 @@ def periodic_dynamical_decoupling(
)


# TODO this should take instruction schedule map instead of backend
def get_instruction_durations(backend: Backend) -> InstructionDurations:
"""
Retrieves gate timing information for the backend from the instruction
schedule map, and returns the type InstructionDurations for use by
Qiskit's scheduler (i.e., ALAP) and DynamicalDecoupling passes.
This method relies on IBM backend knowledge such as
- all single qubit gates durations are the same
- the 'x' gate, used for echoed cross resonance, is also the basis for
all othe dynamical decoupling gates (currently)
"""
inst_durs: InstructionDurationsType = []
inst_sched_map = backend.defaults().instruction_schedule_map
num_qubits = backend.configuration().num_qubits

# single qubit gates
for qubit in range(num_qubits):
for inst_str in inst_sched_map.qubit_instructions(qubits=[qubit]):
inst = inst_sched_map.get(inst_str, qubits=[qubit])
inst_durs.append((inst_str, qubit, inst.duration))

# create DD pulses from CR echo 'x' pulse
if inst_str == "x":
for new_gate in ["xp", "xm", "y", "yp", "ym", "pi_phi"]:
inst_durs.append((new_gate, qubit, inst.duration))

# two qubit gates
for qc in range(num_qubits):
for qt in range(num_qubits):
for inst_str in inst_sched_map.qubit_instructions(qubits=[qc, qt]):
inst = inst_sched_map.get(inst_str, qubits=[qc, qt])
inst_durs.append((inst_str, [qc, qt], inst.duration))

return InstructionDurations(inst_durs)
# # TODO this should take instruction schedule map instead of backend
# def get_instruction_durations(backend: Backend) -> InstructionDurations:
# """
# Retrieves gate timing information for the backend from the instruction
# schedule map, and returns the type InstructionDurations for use by
# Qiskit's scheduler (i.e., ALAP) and DynamicalDecoupling passes.

# This method relies on IBM backend knowledge such as

# - all single qubit gates durations are the same
# - the 'x' gate, used for echoed cross resonance, is also the basis for
# all othe dynamical decoupling gates (currently)
# """
# inst_durs: InstructionDurationsType = []
# # inst_sched_map = backend.defaults().instruction_schedule_map
# target = backend.target
# inst_sched_map = target.instruction_schedule_map()
# num_qubits = target.num_qubits

# # for new_gate in ["xp", "xm", "y", "yp", "ym", "pi_phi"]:
# # target.add_instruction(new_gate, target["x"])

# # single qubit gates
# for qubit in range(num_qubits):
# for inst_str in inst_sched_map.qubit_instructions(qubits=[qubit]):
# inst = inst_sched_map.get(inst_str, qubits=[qubit])
# inst_durs.append((inst_str, qubit, inst.duration))

# # create DD pulses from CR echo 'x' pulse
# if inst_str == "x":
# for new_gate in ["xp", "xm", "y", "yp", "ym", "pi_phi"]:
# inst_durs.append((new_gate, qubit, inst.duration))

# # two qubit gates
# for qc in range(num_qubits):
# for qt in range(num_qubits):
# for inst_str in inst_sched_map.qubit_instructions(qubits=[qc, qt]):
# inst = inst_sched_map.get(inst_str, qubits=[qc, qt])
# inst_durs.append((inst_str, [qc, qt], inst.duration))

# return InstructionDurations(inst_durs)


# TODO refactor this as a CalibrationBuilder transpilation pass
Expand Down
3 changes: 2 additions & 1 deletion qiskit_research/utils/gate_decompositions.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@
from qiskit.exceptions import QiskitError
from qiskit.providers.backend import Backend
from qiskit.pulse import ControlChannel, InstructionScheduleMap, Play
from qiskit.qasm import pi
from qiskit.transpiler.basepasses import TransformationPass

from .gates import SECRGate

from math import pi


def cr_forward_direction(
control: int,
Expand Down
3 changes: 2 additions & 1 deletion qiskit_research/utils/gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
from qiskit.circuit.gate import Gate
from qiskit.circuit.library import RZXGate, RZGate, U3Gate, XGate
from qiskit.circuit.parameterexpression import ParameterValueType
from qiskit.qasm import pi

from math import pi


class XpGate(Gate):
Expand Down
14 changes: 9 additions & 5 deletions qiskit_research/utils/pulse_scaling.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
Schedule,
ScheduleBlock,
)
from qiskit.qasm import pi
from qiskit.transpiler.basepasses import BasePass, TransformationPass
from qiskit.transpiler.passes import (
CXCancellation,
Expand All @@ -41,6 +40,8 @@
)
from qiskit_research.utils.gates import SECRGate

from math import pi

BASIS_GATES = ["sx", "rz", "rzx", "cx"]


Expand Down Expand Up @@ -71,14 +72,17 @@ def pulse_attaching_passes(
param_bind: dict,
) -> Iterable[BasePass]:
"""Yields transpilation passes for attaching pulse schedules."""
inst_sched_map = backend.defaults().instruction_schedule_map
channel_map = backend.configuration().qubit_channel_mapping
# inst_sched_map = backend.defaults().instruction_schedule_map
# channel_map = backend.configuration().qubit_channel_mapping
target = backend.target

yield BindParameters(param_bind)
yield Optimize1qGatesDecomposition(BASIS_GATES)
yield CXCancellation()
yield SECRCalibrationBuilder(inst_sched_map, channel_map)
yield RZXCalibrationBuilder(inst_sched_map, channel_map)
# yield SECRCalibrationBuilder(inst_sched_map, channel_map)
# yield RZXCalibrationBuilder(inst_sched_map, channel_map)
yield SECRCalibrationBuilder(target=target)
yield RZXCalibrationBuilder(target=target)


class CombineRuns(TransformationPass):
Expand Down
Loading

0 comments on commit b0f6dce

Please sign in to comment.