Skip to content

Commit

Permalink
Add pulse gate pass (#6759)
Browse files Browse the repository at this point in the history
* add publisher metadata to instmap schedule

* add pulse gate transpier pass

* use common base class

* add reno

* add reno

* lint

* fix parallel bug

* fix reno

* pulse gate pass is executed only when custom gate is added

* pulse gate pass is executed only when custom gate is added

* fix error

* mode reno

* add tests

* black&lint

* update release note

* Update qiskit/compiler/transpiler.py

Co-authored-by: Thomas Alexander <thomasalexander2718@gmail.com>

* Update qiskit/transpiler/passes/calibration/creators.py

Co-authored-by: Thomas Alexander <thomasalexander2718@gmail.com>

* Update qiskit/transpiler/passes/calibration/creators.py

Co-authored-by: Thomas Alexander <thomasalexander2718@gmail.com>

* Update releasenotes/notes/add-pulse-gate-pass-dc347177ed541bcc.yaml

Co-authored-by: Thomas Alexander <thomasalexander2718@gmail.com>

* rename to builders

* create pulse gate pass iff needed

* refactor the RZX template with Enum

* black

Co-authored-by: Thomas Alexander <thomasalexander2718@gmail.com>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Aug 31, 2021
1 parent 75e06dc commit 40deaf1
Show file tree
Hide file tree
Showing 19 changed files with 975 additions and 415 deletions.
29 changes: 27 additions & 2 deletions qiskit/compiler/transpiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,21 @@
from qiskit.providers.backend import Backend
from qiskit.providers.models import BackendProperties
from qiskit.providers.models.backendproperties import Gate
from qiskit.pulse import Schedule
from qiskit.pulse import Schedule, InstructionScheduleMap
from qiskit.tools.parallel import parallel_map
from qiskit.transpiler import Layout, CouplingMap, PropertySet, PassManager
from qiskit.transpiler.basepasses import BasePass
from qiskit.transpiler.exceptions import TranspilerError
from qiskit.transpiler.instruction_durations import InstructionDurations, InstructionDurationsType
from qiskit.transpiler.passes import ApplyLayout
from qiskit.transpiler.passmanager_config import PassManagerConfig
from qiskit.transpiler.timing_constraints import TimingConstraints
from qiskit.transpiler.preset_passmanagers import (
level_0_pass_manager,
level_1_pass_manager,
level_2_pass_manager,
level_3_pass_manager,
)
from qiskit.transpiler.timing_constraints import TimingConstraints

logger = logging.getLogger(__name__)

Expand All @@ -48,6 +48,7 @@ def transpile(
circuits: Union[QuantumCircuit, List[QuantumCircuit]],
backend: Optional[Union[Backend, BaseBackend]] = None,
basis_gates: Optional[List[str]] = None,
inst_map: Optional[List[InstructionScheduleMap]] = None,
coupling_map: Optional[Union[CouplingMap, List[List[int]]]] = None,
backend_properties: Optional[BackendProperties] = None,
initial_layout: Optional[Union[Layout, Dict, List]] = None,
Expand Down Expand Up @@ -85,6 +86,12 @@ def transpile(
circuit may be run on any backend as long as it is compatible.
basis_gates: List of basis gate names to unroll to
(e.g: ``['u1', 'u2', 'u3', 'cx']``). If ``None``, do not unroll.
inst_map: Mapping of unrolled gates to pulse schedules. If this is not provided,
transpiler tries to get from the backend. If any user defined calibration
is found in the map and this is used in a circuit, transpiler attaches
the custom gate definition to the circuit. This enables one to flexibly
override the low-level instruction implementation. This feature is available
iff the backend supports the pulse gate experiment.
coupling_map: Coupling map (perhaps custom) to target in mapping.
Multiple formats are supported:
Expand Down Expand Up @@ -270,6 +277,7 @@ def callback_func(**kwargs):
circuits,
backend,
basis_gates,
inst_map,
coupling_map,
backend_properties,
initial_layout,
Expand Down Expand Up @@ -451,6 +459,7 @@ def _parse_transpile_args(
circuits,
backend,
basis_gates,
inst_map,
coupling_map,
backend_properties,
initial_layout,
Expand Down Expand Up @@ -488,6 +497,7 @@ def _parse_transpile_args(
num_circuits = len(circuits)

basis_gates = _parse_basis_gates(basis_gates, backend, circuits)
inst_map = _parse_inst_map(inst_map, backend, num_circuits)
faulty_qubits_map = _parse_faulty_qubits_map(backend, num_circuits)
coupling_map = _parse_coupling_map(coupling_map, backend, num_circuits)
backend_properties = _parse_backend_properties(backend_properties, backend, num_circuits)
Expand All @@ -514,6 +524,7 @@ def _parse_transpile_args(
for kwargs in _zip_dict(
{
"basis_gates": basis_gates,
"inst_map": inst_map,
"coupling_map": coupling_map,
"backend_properties": backend_properties,
"initial_layout": initial_layout,
Expand All @@ -535,6 +546,7 @@ def _parse_transpile_args(
transpile_args = {
"pass_manager_config": PassManagerConfig(
basis_gates=kwargs["basis_gates"],
inst_map=kwargs["inst_map"],
coupling_map=kwargs["coupling_map"],
backend_properties=kwargs["backend_properties"],
initial_layout=kwargs["initial_layout"],
Expand Down Expand Up @@ -605,6 +617,19 @@ def _parse_basis_gates(basis_gates, backend, circuits):
return basis_gates


def _parse_inst_map(inst_map, backend, num_circuits):
# try getting inst_map from user, else backend
if inst_map is None:
if hasattr(backend, "defaults"):
inst_map = getattr(backend.defaults(), "instruction_schedule_map", None)

# inst_maps could be None, or single entry
if inst_map is None or isinstance(inst_map, InstructionScheduleMap):
inst_map = [inst_map] * num_circuits

return inst_map


def _parse_coupling_map(coupling_map, backend, num_circuits):
# try getting coupling_map from user, else backend
if coupling_map is None:
Expand Down
3 changes: 2 additions & 1 deletion qiskit/providers/models/pulsedefaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import copy
from typing import Any, Dict, List

from qiskit.pulse.instruction_schedule_map import InstructionScheduleMap
from qiskit.pulse.instruction_schedule_map import InstructionScheduleMap, CalibrationPublisher
from qiskit.pulse.schedule import Schedule
from qiskit.qobj import PulseLibraryItem, PulseQobjInstruction
from qiskit.qobj.converters import QobjToInstructionConverter
Expand Down Expand Up @@ -205,6 +205,7 @@ def __init__(
for inst in cmd_def:
pulse_insts = [self.converter(inst) for inst in inst.sequence]
schedule = Schedule(*pulse_insts, name=inst.name)
schedule.metadata["publisher"] = CalibrationPublisher.BACKEND_PROVIDER
self.instruction_schedule_map.add(inst.name, inst.qubits, schedule)

if meas_kernel is not None:
Expand Down
23 changes: 23 additions & 0 deletions qiskit/pulse/instruction_schedule_map.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import functools
import warnings
from collections import defaultdict
from enum import IntEnum
from typing import Callable, Iterable, List, Tuple, Union, Optional, NamedTuple

from qiskit.circuit.instruction import Instruction
Expand All @@ -43,6 +44,14 @@
)


class CalibrationPublisher(IntEnum):
"""Defines who defined schedule entry."""

BACKEND_PROVIDER = 0
QISKIT = 1
EXPERIMENT_SERVICE = 2


class InstructionScheduleMap:
"""Mapping from :py:class:`~qiskit.circuit.QuantumCircuit`
:py:class:`qiskit.circuit.Instruction` names and qubits to
Expand All @@ -69,6 +78,16 @@ def __init__(self):
# A backwards mapping from qubit to supported instructions
self._qubit_instructions = defaultdict(set)

def has_custom_gate(self) -> bool:
"""Return ``True`` if the map has user provided instruction."""
for qubit_inst in self._map.values():
for generator in qubit_inst.values():
metadata = getattr(generator.function, "metadata", {})
publisher = metadata.get("publisher", CalibrationPublisher.QISKIT)
if publisher != CalibrationPublisher.BACKEND_PROVIDER:
return True
return False

@property
def instructions(self) -> List[str]:
"""Return all instructions which have definitions.
Expand Down Expand Up @@ -303,6 +322,10 @@ def add(
"callable that outputs a schedule."
)

# add metadata
if hasattr(schedule, "metadata") and "publisher" not in schedule.metadata:
schedule.metadata["publisher"] = CalibrationPublisher.QISKIT

self._map[instruction][qubits] = Generator(schedule, signature)
self._qubit_instructions[qubits].add(instruction)

Expand Down
19 changes: 15 additions & 4 deletions qiskit/transpiler/passes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,16 @@
CrosstalkAdaptiveSchedule
TemplateOptimization
Calibration
=============
.. autosummary::
:toctree: ../stubs/
PulseGates
RZXCalibrationBuilder
RZXCalibrationBuilderNoEcho
Scheduling
=============
Expand All @@ -88,8 +98,6 @@
DynamicalDecoupling
AlignMeasures
ValidatePulseGates
RZXCalibrationBuilder
RZXCalibrationBuilderNoEcho
Circuit Analysis
================
Expand Down Expand Up @@ -188,12 +196,15 @@
# synthesis
from .synthesis import UnitarySynthesis

# calibration
from .calibration import PulseGates
from .calibration import RZXCalibrationBuilder
from .calibration import RZXCalibrationBuilderNoEcho

# circuit scheduling
from .scheduling import TimeUnitConversion
from .scheduling import ALAPSchedule
from .scheduling import ASAPSchedule
from .scheduling import RZXCalibrationBuilder
from .scheduling import RZXCalibrationBuilderNoEcho
from .scheduling import DynamicalDecoupling
from .scheduling import AlignMeasures
from .scheduling import ValidatePulseGates
Expand Down
15 changes: 15 additions & 0 deletions qiskit/transpiler/passes/calibration/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2021
#
# 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.

"""Module containing transpiler calibration passes."""

from .builders import RZXCalibrationBuilder, RZXCalibrationBuilderNoEcho, PulseGates
Loading

0 comments on commit 40deaf1

Please sign in to comment.