Skip to content
129 changes: 77 additions & 52 deletions qiskit/compiler/transpile.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from qiskit.circuit.quantumcircuit import QuantumCircuit
from qiskit.providers import BaseBackend
from qiskit.providers.models import BackendProperties
from qiskit.providers.v2.backend import Backend
from qiskit.providers.models.backendproperties import Gate
from qiskit.transpiler import Layout, CouplingMap, PropertySet, PassManager
from qiskit.transpiler.basepasses import BasePass
Expand All @@ -40,7 +41,7 @@


def transpile(circuits: Union[QuantumCircuit, List[QuantumCircuit]],
backend: Optional[BaseBackend] = None,
backend: Optional[Union[BaseBackend, Backend]] = None,
basis_gates: Optional[List[str]] = None,
coupling_map: Optional[Union[CouplingMap, List[List[int]]]] = None,
backend_properties: Optional[BackendProperties] = None,
Expand Down Expand Up @@ -246,8 +247,12 @@ def _check_circuits_coupling_map(circuits, transpile_args, backend):
max_qubits = parsed_coupling_map.size()

# If coupling_map is None, the limit might be in the backend (like in 1Q devices)
elif backend is not None and not backend.configuration().simulator:
max_qubits = backend.configuration().n_qubits
elif backend is not None:
if isinstance(backend, Backend):
max_qubits = backend.target.num_qubits
else:
if not backend.configuration().simulator:
max_qubits = backend.configuration().n_qubits

if max_qubits is not None and (num_qubits > max_qubits):
raise TranspilerError('Number of qubits ({}) '.format(num_qubits) +
Expand Down Expand Up @@ -474,8 +479,11 @@ def _create_faulty_qubits_map(backend):
def _parse_basis_gates(basis_gates, backend, circuits):
# try getting basis_gates from user, else backend
if basis_gates is None:
if getattr(backend, 'configuration', None):
basis_gates = getattr(backend.configuration(), 'basis_gates', None)
if isinstance(backend, Backend):
basis_gates = backend.target.basis_gates
else:
if getattr(backend, 'configuration', None):
basis_gates = getattr(backend.configuration(), 'basis_gates', None)
# basis_gates could be None, or a list of basis, e.g. ['u3', 'cx']
if basis_gates is None or (isinstance(basis_gates, list) and
all(isinstance(i, str) for i in basis_gates)):
Expand All @@ -487,17 +495,20 @@ def _parse_basis_gates(basis_gates, backend, circuits):
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):
configuration = backend.configuration()
if hasattr(configuration, 'coupling_map') and configuration.coupling_map:
faulty_map = _create_faulty_qubits_map(backend)
if faulty_map:
coupling_map = CouplingMap()
for qubit1, qubit2 in configuration.coupling_map:
if faulty_map[qubit1] is not None and faulty_map[qubit2] is not None:
coupling_map.add_edge(faulty_map[qubit1], faulty_map[qubit2])
else:
coupling_map = CouplingMap(configuration.coupling_map)
if isinstance(backend, Backend):
coupling_map = backend.target.coupling_map
else:
if getattr(backend, 'configuration', None):
configuration = backend.configuration()
if hasattr(configuration, 'coupling_map') and configuration.coupling_map:
faulty_map = _create_faulty_qubits_map(backend)
if faulty_map:
coupling_map = CouplingMap()
for qubit1, qubit2 in configuration.coupling_map:
if faulty_map[qubit1] is not None and faulty_map[qubit2] is not None:
coupling_map.add_edge(faulty_map[qubit1], faulty_map[qubit2])
else:
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):
Expand All @@ -514,32 +525,36 @@ def _parse_coupling_map(coupling_map, backend, num_circuits):
def _parse_backend_properties(backend_properties, backend, num_circuits):
# try getting backend_properties from user, else backend
if backend_properties is None:
if getattr(backend, 'properties', None):
backend_properties = backend.properties()
if backend_properties and \
(backend_properties.faulty_qubits() or backend_properties.faulty_gates()):
faulty_qubits = sorted(backend_properties.faulty_qubits(), reverse=True)
faulty_edges = [gates.qubits for gates in backend_properties.faulty_gates()]
# remove faulty qubits in backend_properties.qubits
for faulty_qubit in faulty_qubits:
del backend_properties.qubits[faulty_qubit]

gates = []
for gate in backend_properties.gates:
# remove gates using faulty edges or with faulty qubits (and remap the
# gates in terms of faulty_qubits_map)
faulty_qubits_map = _create_faulty_qubits_map(backend)
if any([faulty_qubits_map[qubits] is not None for qubits in gate.qubits]) or \
gate.qubits in faulty_edges:
continue
gate_dict = gate.to_dict()
replacement_gate = Gate.from_dict(gate_dict)
gate_dict['qubits'] = [faulty_qubits_map[qubit] for qubit in gate.qubits]
args = '_'.join([str(qubit) for qubit in gate_dict['qubits']])
gate_dict['name'] = "%s%s" % (gate_dict['gate'], args)
gates.append(replacement_gate)

backend_properties.gates = gates
if isinstance(backend, Backend):
backend_properties = backend.properties
else:
if getattr(backend, 'properties', None):
backend_properties = backend.properties()
if backend_properties and \
(backend_properties.faulty_qubits() or backend_properties.faulty_gates()):
faulty_qubits = sorted(backend_properties.faulty_qubits(), reverse=True)
faulty_edges = [gates.qubits for gates in backend_properties.faulty_gates()]
# remove faulty qubits in backend_properties.qubits
for faulty_qubit in faulty_qubits:
del backend_properties.qubits[faulty_qubit]

gates = []
for gate in backend_properties.gates:
# remove gates using faulty edges or with faulty qubits (and remap the
# gates in terms of faulty_qubits_map)
faulty_qubits_map = _create_faulty_qubits_map(backend)
any_faulty_qubits = any(
[faulty_qubits_map[qubits] is not None for qubits in gate.qubits])
if any_faulty_qubits or gate.qubits in faulty_edges:
continue
gate_dict = gate.to_dict()
replacement_gate = Gate.from_dict(gate_dict)
gate_dict['qubits'] = [faulty_qubits_map[qubit] for qubit in gate.qubits]
args = '_'.join([str(qubit) for qubit in gate_dict['qubits']])
gate_dict['name'] = "%s%s" % (gate_dict['gate'], args)
gates.append(replacement_gate)

backend_properties.gates = gates
if not isinstance(backend_properties, list):
backend_properties = [backend_properties] * num_circuits
return backend_properties
Expand All @@ -548,11 +563,18 @@ def _parse_backend_properties(backend_properties, backend, num_circuits):
def _parse_backend_num_qubits(backend, num_circuits):
if backend is None:
return [None] * num_circuits
if not isinstance(backend, list):
return [backend.configuration().n_qubits] * num_circuits
backend_num_qubits = []
for a_backend in backend:
backend_num_qubits.append(a_backend.configuration().n_qubits)
if isinstance(backend, Backend):
if not isinstance(backend, list):
return [backend.target.num_qubits] * num_circuits
backend_num_qubits = []
for a_backend in backend:
backend_num_qubits.append(a_backend.target.num_qubits)
else:
if not isinstance(backend, list):
return [backend.configuration().n_qubits] * num_circuits
backend_num_qubits = []
for a_backend in backend:
backend_num_qubits.append(a_backend.configuration().n_qubits)
return backend_num_qubits


Expand Down Expand Up @@ -633,11 +655,14 @@ def _parse_callback(callback, num_circuits):
def _parse_faulty_qubits_map(backend, num_circuits):
if backend is None:
return [None] * num_circuits
if not isinstance(backend, list):
return [_create_faulty_qubits_map(backend)] * num_circuits
faulty_qubits_map = []
for a_backend in backend:
faulty_qubits_map.append(_create_faulty_qubits_map(a_backend))
elif isinstance(backend, Backend):
return [None] * num_circuits
else:
if not isinstance(backend, list):
return [_create_faulty_qubits_map(backend)] * num_circuits
faulty_qubits_map = []
for a_backend in backend:
faulty_qubits_map.append(_create_faulty_qubits_map(a_backend))
return faulty_qubits_map


Expand Down
70 changes: 41 additions & 29 deletions qiskit/execute.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from time import time
from qiskit.compiler import transpile, assemble, schedule
from qiskit.qobj.utils import MeasLevel, MeasReturnType
from qiskit.providers.v2.backend import Backend
from qiskit.pulse import Schedule
from qiskit.exceptions import QiskitError

Expand Down Expand Up @@ -57,7 +58,7 @@ def execute(experiments, backend,
experiments (QuantumCircuit or list[QuantumCircuit] or Schedule or list[Schedule]):
Circuit(s) or pulse schedule(s) to execute

backend (BaseBackend):
backend (BaseBackend|Backend):
Backend to execute circuits on.
Transpiler options are automatically grabbed from
backend.configuration() and backend.properties().
Expand Down Expand Up @@ -263,34 +264,45 @@ def execute(experiments, backend,
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,
qobj_header=qobj_header,
shots=shots,
memory=memory,
max_credits=max_credits,
seed_simulator=seed_simulator,
default_qubit_los=default_qubit_los,
default_meas_los=default_meas_los,
schedule_los=schedule_los,
meas_level=meas_level,
meas_return=meas_return,
memory_slots=memory_slots,
memory_slot_size=memory_slot_size,
rep_time=rep_time,
rep_delay=rep_delay,
parameter_binds=parameter_binds,
backend=backend,
init_qubits=init_qubits,
**run_config)

# executing the circuits on the backend and returning the job
start_time = time()
job = backend.run(qobj, **run_config)
end_time = time()
_log_submission_time(start_time, end_time)
return job
# v2 Providers Backend
if isinstance(backend, Backend):
start_time = time()
backend.set_options(shots=shots, **run_config)
job = backend.run(experiments)
end_time = time()
_log_submission_time(start_time, end_time)
return job

# v1 Providers Backend
else:
# assembling the circuits into a qobj to be run on the backend
qobj = assemble(experiments,
qobj_id=qobj_id,
qobj_header=qobj_header,
shots=shots,
memory=memory,
max_credits=max_credits,
seed_simulator=seed_simulator,
default_qubit_los=default_qubit_los,
default_meas_los=default_meas_los,
schedule_los=schedule_los,
meas_level=meas_level,
meas_return=meas_return,
memory_slots=memory_slots,
memory_slot_size=memory_slot_size,
rep_time=rep_time,
rep_delay=rep_delay,
parameter_binds=parameter_binds,
backend=backend,
init_qubits=init_qubits,
**run_config)

# executing the circuits on the backend and returning the job
start_time = time()
job = backend.run(qobj, **run_config)
end_time = time()
_log_submission_time(start_time, end_time)
return job


def _check_conflicting_argument(**kargs):
Expand Down
Loading