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

Defaults in TranspileConfig (now called PassManagerConfig) #3035

Merged
merged 87 commits into from
Feb 9, 2020
Merged
Show file tree
Hide file tree
Changes from 68 commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
efd1aa8
TranspileConfig defaults
Aug 23, 2019
4527a17
defatuls for TranspileConfig
Aug 23, 2019
76befce
Merge branch 'master' into defaults_TranspileConfig
Sep 5, 2019
e95a102
explicit kwargs
Sep 5, 2019
75ca2cd
remove __getattr__ None
Sep 5, 2019
ca3e1d2
move cm checks to _parse_coupling_map
Sep 8, 2019
ba39d87
transpile_config as a dict
Sep 8, 2019
203280f
pass manager config
Sep 8, 2019
eccfd27
circuit is yet another transpiler param
Sep 8, 2019
ea8d6a2
TranspileConfigSchema -> PassManagerConfigSchema
Sep 8, 2019
cc393d1
removing unsed parameters in PassManagerConfig
Sep 8, 2019
24ce889
no need for _transpile_circuit anymore
Sep 8, 2019
fc488b8
pass manager callback at construction time
Sep 8, 2019
44677ce
Merge branch 'master' of github.com:Qiskit/qiskit-terra into defaults…
Sep 8, 2019
b5ee757
docstring
Sep 9, 2019
01de59b
changelog
Sep 10, 2019
fe54db6
deprecate callback from construction time
Sep 10, 2019
26b379e
_parse_output_name creates Nones instead of circuit.name
Sep 10, 2019
4aeb87e
transpile_config -> transpile_args
Sep 10, 2019
117d813
merge
Sep 10, 2019
948b3d4
CouplingMap(backend.configuration().coupling_map)
Sep 10, 2019
a909c5f
reformat
Sep 10, 2019
83a79d1
merge
Sep 23, 2019
2f1e60e
Merge branch 'master' into defaults_TranspileConfig
Sep 30, 2019
23d1742
merge
Oct 30, 2019
26d19e2
Merge branch 'master' into defaults_TranspileConfig
Oct 30, 2019
73b21c2
fixing test/python/transpiler/test_passmanager_run.py
Oct 31, 2019
bbb1c45
run(..., output_name=None, callback=None)
Oct 31, 2019
142e298
basis
Oct 31, 2019
321b906
Merge branch 'master' of github.com:Qiskit/qiskit-terra into defaults…
Oct 31, 2019
4c98cc5
kwargs
Oct 31, 2019
38f7c56
transpile_args[pass_manager_config].basis_gates
Oct 31, 2019
af9a914
callback at run time
Oct 31, 2019
5627f46
lint
Oct 31, 2019
1ad6b25
Merge branch 'master' of github.com:Qiskit/qiskit-terra into defaults…
Nov 1, 2019
1c91111
Merge branch 'master' of github.com:Qiskit/qiskit-terra into defaults…
Nov 2, 2019
6b0b4be
release note
Nov 3, 2019
cc7ddc1
Merge branch 'master' into defaults_TranspileConfig
mergify[bot] Nov 5, 2019
187a58e
Merge branch 'master' into defaults_TranspileConfig
mergify[bot] Nov 6, 2019
d261510
Merge branch 'master' into defaults_TranspileConfig
mergify[bot] Nov 6, 2019
d4af0f8
Merge branch 'master' of github.com:Qiskit/qiskit-terra into defaults…
Nov 7, 2019
3037240
Merge branch 'master' into defaults_TranspileConfig
Nov 7, 2019
2a99885
Merge branch 'master' into defaults_TranspileConfig
mergify[bot] Nov 7, 2019
009238d
Merge branch 'master' of github.com:Qiskit/qiskit-terra into defaults…
Nov 8, 2019
ad5bb3a
docstring
Nov 8, 2019
b21e0b3
other -> upgrade
Nov 8, 2019
70aaf6c
release note
Nov 8, 2019
6dbac3b
Merge branch 'master' of github.com:Qiskit/qiskit-terra into defaults…
Nov 8, 2019
8c5faba
Merge branch 'master' into defaults_TranspileConfig
Nov 26, 2019
a3582cc
Merge branch 'master' into defaults_TranspileConfig
Dec 3, 2019
1efe02f
Merge branch 'master' into defaults_TranspileConfig
kdk Dec 3, 2019
58ecc5d
Merge branch 'master' into defaults_TranspileConfig
Dec 11, 2019
dacb8be
style
Dec 11, 2019
5ae9f13
fix
Dec 11, 2019
a0b1755
Merge branch 'master' of github.com:Qiskit/qiskit-terra into defaults…
Dec 17, 2019
0c13b16
line too long
Dec 17, 2019
cf28d29
Merge branch 'master' of github.com:Qiskit/qiskit-terra into defaults…
Dec 23, 2019
571375f
Merge branch 'master' of github.com:Qiskit/qiskit-terra into defaults…
Dec 23, 2019
09d0c90
reverse the changes in about parallel
Dec 23, 2019
9ec8679
rollback transpile_circuit
Dec 23, 2019
095c0cc
lint
Dec 23, 2019
34aec1e
release note
Dec 23, 2019
a31a190
Merge branch 'master' of github.com:Qiskit/qiskit-terra into defaults…
Dec 24, 2019
be7314a
merge
Dec 30, 2019
66d838a
expanding the parameters
Dec 30, 2019
63e3e68
remove optimization level
Dec 30, 2019
078979a
remove pass_manager_config as a transpile_circuit arg
Dec 30, 2019
570c1f1
output_name and callback are optional
Dec 30, 2019
15f4dd4
Update qiskit/compiler/transpile.py
Dec 30, 2019
fa007a0
documentation
Jan 13, 2020
6ed9677
parse callback
Jan 13, 2020
7ec5ceb
remove circuit from transpile_args
Jan 13, 2020
08b68ea
Update qiskit/transpiler/transpile_circuit.py
Jan 13, 2020
4c87790
rename transpile_args_circuits to list_transpile_args.append
Jan 13, 2020
cef86d3
conflict
Jan 13, 2020
c50cf29
Merge branch 'defaults_TranspileConfig' of github.com:1ucian0/qiskit-…
Jan 13, 2020
7d811ef
new path for passes
Jan 13, 2020
b57b28d
merge
Jan 22, 2020
e1d7f10
back to old _parse_coupling_map
Jan 24, 2020
7ad1521
undoing _parse_output_name
Jan 24, 2020
b84e270
comments on the transpiler configuration
Jan 24, 2020
346b8ea
docstring
Jan 24, 2020
edc9184
Merge branch 'master' into defaults_TranspileConfig
Jan 24, 2020
ce06242
Merge branch 'master' of github.com:Qiskit/qiskit-terra into defaults…
Feb 3, 2020
1c219ed
Merge branch 'defaults_TranspileConfig' of github.com:1ucian0/qiskit-…
Feb 3, 2020
8d935be
remove transpile_circuit
Feb 3, 2020
a9e6825
Merge branch 'master' into defaults_TranspileConfig
Feb 9, 2020
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
158 changes: 107 additions & 51 deletions qiskit/compiler/transpile.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,18 @@
"""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.pass_manager_config import PassManagerConfig
from qiskit.transpiler.transpile_circuit import transpile_circuit
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.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 +181,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 +207,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):
1ucian0 marked this conversation as resolved.
Show resolved Hide resolved
"""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 format of the
1ucian0 marked this conversation as resolved.
Show resolved Hide resolved
dictionary has the following format:
{'optimization_level': int,
'pass_manager': PassManager,
'output_name': string,
'callback': callable,
'pass_manager_config': PassManagerConfig}
ajavadia marked this conversation as resolved.
Show resolved Hide resolved
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:
ajavadia marked this conversation as resolved.
Show resolved Hide resolved
pass_manager = transpile_config['pass_manager']
else:
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 transpile_circuit(circuit,
pass_manager,
transpile_config['output_name'],
transpile_config['callback'])


def _parse_transpile_args(circuits, backend,
Expand All @@ -238,45 +288,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)

coupling_map = _parse_coupling_map(coupling_map, backend, 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, num_circuits)

output_name = _parse_output_name(output_name, circuits)

transpile_configs = []
transpile_args_circuits = []
1ucian0 marked this conversation as resolved.
Show resolved Hide resolved
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)

return transpile_configs
pass_manager, output_name, circuits):
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],
'circuit': args[8],
1ucian0 marked this conversation as resolved.
Show resolved Hide resolved
'callback': callback}
1ucian0 marked this conversation as resolved.
Show resolved Hide resolved
transpile_args_circuits.append(transpile_args)

return transpile_args_circuits


def _parse_basis_gates(basis_gates, backend, circuits):
Expand All @@ -299,18 +342,31 @@ def _parse_basis_gates(basis_gates, backend, circuits):
return basis_gates


def _parse_coupling_map(coupling_map, backend, num_circuits):
def _parse_coupling_map(coupling_map, backend, circuits):
1ucian0 marked this conversation as resolved.
Show resolved Hide resolved
num_circuits = len(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)
# 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]
configuration = backend.configuration()
if hasattr(configuration, 'coupling_map') and configuration.coupling_map:
coupling_map = CouplingMap(configuration.coupling_map)

coupling_map = [coupling_map] * num_circuits

for index, parsed_coupling_map in enumerate(coupling_map):
if isinstance(parsed_coupling_map, list):
1ucian0 marked this conversation as resolved.
Show resolved Hide resolved
parsed_coupling_map = CouplingMap(parsed_coupling_map)
# If coupling_map is not None
if isinstance(parsed_coupling_map, CouplingMap):
n_qubits = len(circuits[index].qubits)
max_qubits = parsed_coupling_map.size()
if n_qubits > max_qubits:
raise TranspilerError('Number of qubits ({}) '.format(n_qubits) +
'in {} '.format(circuits[index].name) +
'is greater than maximum ({}) '.format(max_qubits) +
'in the coupling_map')
coupling_map[index] = parsed_coupling_map

return coupling_map


Expand Down Expand Up @@ -372,21 +428,21 @@ def _parse_pass_manager(pass_manager, num_circuits):
return pass_manager


def _parse_output_name(output_name, circuits):
def _parse_output_name(output_name, num_circuits):
# naming and returning circuits
# output_name could be either a string or a list
if output_name is not None:
if isinstance(output_name, str):
# single circuit
if len(circuits) == 1:
if num_circuits == 1:
return [output_name]
# multiple circuits
else:
raise TranspilerError("Expected a list object of length equal " +
"to that of the number of circuits " +
"being transpiled")
elif isinstance(output_name, list):
if len(circuits) == len(output_name) and \
if num_circuits == len(output_name) and \
all(isinstance(name, str) for name in output_name):
return output_name
else:
Expand All @@ -398,4 +454,4 @@ def _parse_output_name(output_name, circuits):
raise TranspilerError("The parameter output_name should be a string or a"
"list of strings: %s was used." % type(output_name))
else:
return [circuit.name for circuit in circuits]
return [None] * num_circuits
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
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,35 @@
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

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

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


@bind_schema(TranspileConfigSchema)
class TranspileConfig(BaseModel):
"""Model for TranspileConfig.
@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 ``TranspileConfigSchema``.
full description of the model, please check ``PassManagerConfigSchema``.

Attributes:
optimization_level (int): a non-negative integer indicating the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Attributes documentation should be updated. Also, would there be value in having an object for both the TranspileArgs and PassManagerConfig, or is transpile_args better left as adict?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

transpile_args is a dict because is only used for calling the parallelization code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

attributes documentation should be updated.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make sure the module docstring has all the right info about what this new class contains.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is still not addressed. docstrings are not up to date

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in fa007a0

optimization level. 0 means no transformation on the circuit. Higher
levels may produce more optimized circuits, but may take longer.
"""
def __init__(self, optimization_level, **kwargs):
self.optimization_level = optimization_level
super().__init__(**kwargs)

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