Skip to content

Commit

Permalink
Defaults in TranspileConfig (now called PassManagerConfig) (Qiskit#3035)
Browse files Browse the repository at this point in the history
* TranspileConfig defaults

* defatuls for TranspileConfig

* explicit kwargs

* remove __getattr__ None

* move cm checks to _parse_coupling_map

* transpile_config as a dict

* pass manager config

* circuit is yet another transpiler param

* TranspileConfigSchema -> PassManagerConfigSchema

* removing unsed parameters in PassManagerConfig

* no need for _transpile_circuit anymore

* pass manager callback at construction time

* docstring

* changelog

* deprecate callback from construction time

* _parse_output_name creates Nones instead of circuit.name

* transpile_config -> transpile_args

* CouplingMap(backend.configuration().coupling_map)

* reformat

* fixing test/python/transpiler/test_passmanager_run.py

* run(..., output_name=None, callback=None)

* basis

* kwargs

* transpile_args[pass_manager_config].basis_gates

* callback at run time

* lint

* release note

* docstring

* other -> upgrade

* release note

* style

* fix

* line too long

* reverse the changes in about parallel

* rollback transpile_circuit

* lint

* release note

* expanding the parameters

* remove optimization level

* remove pass_manager_config as a transpile_circuit arg

* output_name and callback are optional

* Update qiskit/compiler/transpile.py

Co-Authored-By: Ali Javadi-Abhari <[email protected]>

* documentation

* parse callback

* remove circuit from transpile_args

* Update qiskit/transpiler/transpile_circuit.py

Co-Authored-By: Ali Javadi-Abhari <[email protected]>

* rename transpile_args_circuits to list_transpile_args.append

* new path for passes

* back to old _parse_coupling_map

* undoing _parse_output_name

* comments on the transpiler configuration

* docstring

* remove transpile_circuit

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Co-authored-by: Kevin Krsulich <[email protected]>
Co-authored-by: Ali Javadi-Abhari <[email protected]>
  • Loading branch information
4 people authored Feb 9, 2020
1 parent aeeef37 commit db613ea
Show file tree
Hide file tree
Showing 16 changed files with 296 additions and 289 deletions.
127 changes: 90 additions & 37 deletions qiskit/compiler/transpile.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@
"""Circuit transpile function"""
from qiskit.transpiler import Layout, CouplingMap
from qiskit.tools.parallel import parallel_map
from qiskit.transpiler.transpile_config import TranspileConfig
from qiskit.transpiler.transpile_circuit import transpile_circuit
from qiskit.transpiler.pass_manager_config import PassManagerConfig
from qiskit.pulse import Schedule
from qiskit.circuit.quantumregister import Qubit
from qiskit import user_config
from qiskit.transpiler.exceptions import TranspilerError
from qiskit.converters import isinstanceint, isinstancelist
from qiskit.transpiler.passes.basis.ms_basis_decomposer import MSBasisDecomposer
from qiskit.transpiler.preset_passmanagers import (level_0_pass_manager,
level_1_pass_manager,
level_2_pass_manager,
level_3_pass_manager)


def transpile(circuits,
Expand Down Expand Up @@ -176,14 +180,15 @@ def callback_func(**kwargs):
config = user_config.get_config()
optimization_level = config.get('transpile_optimization_level', None)

# Get TranspileConfig(s) to configure the circuit transpilation job(s)
# Get transpile_args to configure the circuit transpilation job(s)
circuits = circuits if isinstance(circuits, list) else [circuits]
transpile_configs = _parse_transpile_args(circuits, backend, basis_gates, coupling_map,
backend_properties, initial_layout,
seed_transpiler, optimization_level,
pass_manager, callback, output_name)
transpile_args = _parse_transpile_args(circuits, backend, basis_gates, coupling_map,
backend_properties, initial_layout,
seed_transpiler, optimization_level,
pass_manager, callback, output_name)
# Check circuit width against number of qubits in coupling_map(s)
coupling_maps_list = list(config.coupling_map for config in transpile_configs)
coupling_maps_list = list(config['pass_manager_config'].coupling_map for config in
transpile_args)
for circuit, parsed_coupling_map in zip(circuits, coupling_maps_list):
# If coupling_map is not None or n_qubits == 1
n_qubits = len(circuit.qubits)
Expand All @@ -201,28 +206,72 @@ def callback_func(**kwargs):
'is greater than maximum ({}) '.format(max_qubits) +
'in the coupling_map')
# Transpile circuits in parallel
circuits = parallel_map(_transpile_circuit, list(zip(circuits, transpile_configs)))
circuits = parallel_map(_transpile_circuit, list(zip(circuits, transpile_args)))

if len(circuits) == 1:
return circuits[0]
return circuits


# FIXME: This is a helper function because of parallel tools.
def _transpile_circuit(circuit_config_tuple):
"""Select a PassManager and run a single circuit through it.
Args:
circuit_config_tuple (tuple):
circuit (QuantumCircuit): circuit to transpile
transpile_config (TranspileConfig): configuration dictating how to transpile
transpile_config (dict): configuration dictating how to transpile. The
dictionary has the following format:
{'optimization_level': int,
'pass_manager': PassManager,
'output_name': string,
'callback': callable,
'pass_manager_config': PassManagerConfig}
Returns:
QuantumCircuit: transpiled circuit
Raises:
TranspilerError: if transpile_config is not valid or transpilation incurs error
"""
circuit, transpile_config = circuit_config_tuple

return transpile_circuit(circuit, transpile_config)
pass_manager_config = transpile_config['pass_manager_config']

# Workaround for ion trap support: If basis gates includes
# Mølmer-Sørensen (rxx) and the circuit includes gates outside the basis,
# first unroll to u3, cx, then run MSBasisDecomposer to target basis.
basic_insts = ['measure', 'reset', 'barrier', 'snapshot']
device_insts = set(pass_manager_config.basis_gates).union(basic_insts)
ms_basis_swap = None
if 'rxx' in pass_manager_config.basis_gates and \
not device_insts >= circuit.count_ops().keys():
ms_basis_swap = pass_manager_config.basis_gates
pass_manager_config.basis_gates = list(
set(['u3', 'cx']).union(pass_manager_config.basis_gates))

if transpile_config['pass_manager'] is not None:
# either the pass manager is already selected...
pass_manager = transpile_config['pass_manager']
else:
# or we choose an appropriate one based on desired optimization level (default: level 1)
if transpile_config['optimization_level'] is not None:
level = transpile_config['optimization_level']
else:
level = 1

if level == 0:
pass_manager = level_0_pass_manager(pass_manager_config)
elif level == 1:
pass_manager = level_1_pass_manager(pass_manager_config)
elif level == 2:
pass_manager = level_2_pass_manager(pass_manager_config)
elif level == 3:
pass_manager = level_3_pass_manager(pass_manager_config)
else:
raise TranspilerError("optimization_level can range from 0 to 3.")

if ms_basis_swap is not None:
pass_manager.append(MSBasisDecomposer(ms_basis_swap))

return pass_manager.run(circuit, callback=transpile_config['callback'],
output_name=transpile_config['output_name'])


def _parse_transpile_args(circuits, backend,
Expand All @@ -238,45 +287,38 @@ def _parse_transpile_args(circuits, backend,
arg has more priority than the arg set by backend).
Returns:
list[TranspileConfig]: a transpile config for each circuit, which is a standardized
object that configures the transpiler and determines the pass manager to use.
list[dicts]: a list of transpile parameters.
"""
# Each arg could be single or a list. If list, it must be the same size as
# number of circuits. If single, duplicate to create a list of that size.
num_circuits = len(circuits)

basis_gates = _parse_basis_gates(basis_gates, backend, circuits)

coupling_map = _parse_coupling_map(coupling_map, backend, num_circuits)

backend_properties = _parse_backend_properties(backend_properties, backend, num_circuits)

initial_layout = _parse_initial_layout(initial_layout, circuits)

seed_transpiler = _parse_seed_transpiler(seed_transpiler, num_circuits)

optimization_level = _parse_optimization_level(optimization_level, num_circuits)

pass_manager = _parse_pass_manager(pass_manager, num_circuits)

output_name = _parse_output_name(output_name, circuits)
callback = _parse_callback(callback, num_circuits)

transpile_configs = []
list_transpile_args = []
for args in zip(basis_gates, coupling_map, backend_properties,
initial_layout, seed_transpiler, optimization_level,
pass_manager, output_name):
transpile_config = TranspileConfig(basis_gates=args[0],
coupling_map=args[1],
backend_properties=args[2],
initial_layout=args[3],
seed_transpiler=args[4],
optimization_level=args[5],
pass_manager=args[6],
callback=callback,
output_name=args[7])
transpile_configs.append(transpile_config)
pass_manager, output_name, callback):
transpile_args = {'pass_manager_config': PassManagerConfig(basis_gates=args[0],
coupling_map=args[1],
backend_properties=args[2],
initial_layout=args[3],
seed_transpiler=args[4]),
'optimization_level': args[5],
'pass_manager': args[6],
'output_name': args[7],
'callback': args[8]}
list_transpile_args.append(transpile_args)

return transpile_configs
return list_transpile_args


def _parse_basis_gates(basis_gates, backend, circuits):
Expand All @@ -303,14 +345,19 @@ def _parse_coupling_map(coupling_map, backend, num_circuits):
# try getting coupling_map from user, else backend
if coupling_map is None:
if getattr(backend, 'configuration', None):
coupling_map = getattr(backend.configuration(), 'coupling_map', None)
configuration = backend.configuration()
if hasattr(configuration, 'coupling_map') and configuration.coupling_map:
coupling_map = CouplingMap(configuration.coupling_map)

# coupling_map could be None, or a list of lists, e.g. [[0, 1], [2, 1]]
if coupling_map is None or isinstance(coupling_map, CouplingMap):
coupling_map = [coupling_map] * num_circuits
elif isinstance(coupling_map, list) and all(isinstance(i, list) and len(i) == 2
for i in coupling_map):
coupling_map = [coupling_map] * num_circuits

coupling_map = [CouplingMap(cm) if isinstance(cm, list) else cm for cm in coupling_map]

return coupling_map


Expand Down Expand Up @@ -372,6 +419,12 @@ def _parse_pass_manager(pass_manager, num_circuits):
return pass_manager


def _parse_callback(callback, num_circuits):
if not isinstance(callback, list):
callback = [callback] * num_circuits
return callback


def _parse_output_name(output_name, circuits):
# naming and returning circuits
# output_name could be either a string or a list
Expand Down
9 changes: 0 additions & 9 deletions qiskit/transpiler/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,6 @@
.. currentmodule:: qiskit.transpiler
Circuit Transpilation
=====================
.. autosummary::
:toctree: ../stubs/
transpile_circuit
Pass Managment
==============
Expand Down Expand Up @@ -73,4 +65,3 @@
from .basepasses import AnalysisPass, TransformationPass
from .coupling import CouplingMap
from .layout import Layout
from .transpile_circuit import transpile_circuit
6 changes: 3 additions & 3 deletions qiskit/transpiler/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""Models for TranspileConfig and RunConfig."""
"""Models for PassManagerConfig and RunConfig."""

from qiskit.validation import BaseSchema


class TranspileConfigSchema(BaseSchema):
"""Schema for TranspileConfig."""
class PassManagerConfigSchema(BaseSchema):
"""Schema for PassManagerConfig."""

# Required properties.

Expand Down
49 changes: 49 additions & 0 deletions qiskit/transpiler/pass_manager_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# -*- coding: utf-8 -*-

# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2019.
#
# 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.

"""Models for PassManagerConfig and its related components."""

from qiskit.transpiler.models import PassManagerConfigSchema
from qiskit.validation import BaseModel, bind_schema


@bind_schema(PassManagerConfigSchema)
class PassManagerConfig(BaseModel):
"""Model for PassManagerConfig.
Please note that this class only describes the required fields. For the
full description of the model, please check ``PassManagerConfigSchema``.
Attributes:
initial_layout (Layout): Initial position of virtual qubits on physical qubits.
basis_gates (list): List of basis gate names to unroll to.
coupling_map (CouplingMap): Directed graph represented a coupling map.
backend_properties (BackendProperties): Properties returned by a backend, including
information on gate errors, readout errors, qubit coherence times, etc.
seed_transpiler (int): Sets random seed for the stochastic parts of the transpiler.
"""

def __init__(self,
initial_layout=None,
basis_gates=None,
coupling_map=None,
backend_properties=None,
seed_transpiler=None,
**kwargs):
super().__init__(initial_layout=initial_layout,
basis_gates=basis_gates,
coupling_map=coupling_map,
backend_properties=backend_properties,
seed_transpiler=seed_transpiler,
**kwargs)
Loading

0 comments on commit db613ea

Please sign in to comment.