Skip to content

Commit

Permalink
Merge branch 'master' into add-catalina-job
Browse files Browse the repository at this point in the history
  • Loading branch information
mtreinish authored Feb 15, 2020
2 parents 5c6662a + ce6b231 commit d5029e3
Show file tree
Hide file tree
Showing 75 changed files with 1,770 additions and 1,251 deletions.
4 changes: 2 additions & 2 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ extensions/ @ajavadia @kdk @ewinston @1ucian0 @mtreinish
dagcircuit/ @ajavadia @kdk @1ucian0 @maddy-tod
providers/ @ajavadia @mtreinish @diego-plan9
basicaer/ @chriseclectic @ajavadia
pulse/ @lcapelluto @taalexander @eggerdj @nkanazawa1989
scheduler/ @lcapelluto @taalexander @eggerdj @nkanazawa1989
pulse/ @lcapelluto @taalexander @eggerdj @nkanazawa1989 @danpuzzuoli
scheduler/ @lcapelluto @taalexander @eggerdj @nkanazawa1989 @danpuzzuoli
quantum_info/ @chriseclectic @ajavadia
qi/ @chriseclectic @ajavadia
result/ @diego-plan9 @jyu00 @taalexander @mtreinish @ajavadia
Expand Down
6 changes: 3 additions & 3 deletions docs/apidocs/qiskit.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
.. module:: qiskit

=============
API Reference
=============
==========================
Qiskit Terra API Reference
==========================

.. toctree::
:maxdepth: 1
Expand Down
6 changes: 5 additions & 1 deletion qiskit/circuit/quantumcircuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,8 +334,12 @@ def extend(self, rhs):
if element not in self.cregs:
self.cregs.append(element)

# Copy the circuit data if rhs and self are the same, otherwise the data of rhs is
# appended to both self and rhs resulting in an infinite loop
data = rhs.data.copy() if rhs is self else rhs.data

# Add new gates
for instruction_context in rhs.data:
for instruction_context in data:
self._append(*instruction_context)
return self

Expand Down
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
30 changes: 29 additions & 1 deletion qiskit/execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
.. autofunction:: execute
"""
from qiskit.compiler import transpile, assemble
from qiskit.compiler import transpile, assemble, schedule
from qiskit.qobj.utils import MeasLevel, MeasReturnType
from qiskit.pulse import Schedule
from qiskit.exceptions import QiskitError


def execute(experiments, backend,
Expand All @@ -35,6 +37,7 @@ def execute(experiments, backend,
schedule_los=None, meas_level=MeasLevel.CLASSIFIED,
meas_return=MeasReturnType.AVERAGE,
memory_slots=None, memory_slot_size=100, rep_time=None, parameter_binds=None,
schedule_circuit=False, inst_map=None, meas_map=None, scheduling_method=None,
**run_config):
"""Execute a list of :class:`qiskit.circuit.QuantumCircuit` or
:class:`qiskit.pulse.Schedule` on a backend.
Expand Down Expand Up @@ -179,6 +182,21 @@ def execute(experiments, backend,
length-n list, and there are m experiments, a total of m x n
experiments will be run (one for each experiment/bind pair).
schedule_circuit (bool):
If ``True``, ``experiments`` will be converted to ``Schedule``s prior to
execution.
inst_map (InstructionScheduleMap):
Mapping of circuit operations to pulse schedules. If None, defaults to the
``instruction_schedule_map`` of ``backend``.
meas_map (list(list(int))):
List of sets of qubits that must be measured together. If None, defaults to
the ``meas_map`` of ``backend``.
scheduling_method (str or list(str)):
Optionally specify a particular scheduling method.
run_config (dict):
Extra arguments used to configure the run (e.g. for Aer configurable backends).
Refer to the backend documentation for details on these arguments.
Expand Down Expand Up @@ -220,6 +238,16 @@ def execute(experiments, backend,
pass_manager=pass_manager,
)

if schedule_circuit:
if isinstance(experiments, Schedule) or isinstance(experiments[0], Schedule):
raise QiskitError("Must supply QuantumCircuit to schedule circuit.")
experiments = schedule(circuits=experiments,
backend=backend,
inst_map=inst_map,
meas_map=meas_map,
method=scheduling_method
)

# assembling the circuits into a qobj to be run on the backend
qobj = assemble(experiments,
qobj_id=qobj_id,
Expand Down
2 changes: 2 additions & 0 deletions qiskit/extensions/standard/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
from .iden import IdGate
from .ms import MSGate
from .r import RGate
from .rccx import RCCXGate
from .rcccx import RCCCXGate
from .rx import RXGate, CrxGate
from .rxx import RXXGate
from .ry import RYGate, CryGate
Expand Down
2 changes: 0 additions & 2 deletions qiskit/extensions/standard/multi_control_toffoli_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@
from qiskit.circuit import QuantumCircuit, QuantumRegister, Qubit

from qiskit import QiskitError
# pylint: disable=unused-import
from .relative_phase_toffoli import rccx

logger = logging.getLogger(__name__)

Expand Down
Loading

0 comments on commit d5029e3

Please sign in to comment.