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

Remove list argument broadcasting and simplify transpile() #10291

Merged
merged 21 commits into from
Jul 19, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
611 changes: 157 additions & 454 deletions qiskit/compiler/transpiler.py

Large diffs are not rendered by default.

8 changes: 0 additions & 8 deletions qiskit/providers/fake_provider/fake_1q.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,3 @@ def __init__(self):
general=[],
)
super().__init__(configuration)

def defaults(self):
"""defaults == configuration"""
return self._configuration

def properties(self):
"""properties == configuration"""
return self._configuration
6 changes: 5 additions & 1 deletion qiskit/providers/fake_provider/fake_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,11 @@ def _setup_sim(self):
def properties(self):
"""Return backend properties"""
coupling_map = self.configuration().coupling_map
unique_qubits = list(set().union(*coupling_map))
unique_qubits = []
if coupling_map is not None:
unique_qubits = list(set().union(*coupling_map))
else:
return None
mtreinish marked this conversation as resolved.
Show resolved Hide resolved

properties = {
"backend_name": self.name(),
Expand Down
8 changes: 7 additions & 1 deletion qiskit/transpiler/passes/layout/set_layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@


from qiskit.transpiler.basepasses import AnalysisPass
from qiskit.transpiler.layout import Layout


class SetLayout(AnalysisPass):
Expand Down Expand Up @@ -41,5 +42,10 @@ def run(self, dag):
Returns:
DAGCircuit: the original DAG.
"""
self.property_set["layout"] = None if self.layout is None else self.layout.copy()
if isinstance(self.layout, list):
layout = Layout({dag.qubits[i]: phys for i, phys in enumerate(self.layout)})
else:
layout = self.layout

self.property_set["layout"] = None if layout is None else layout.copy()
return dag
5 changes: 2 additions & 3 deletions qiskit/transpiler/passmanager_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def __init__(
self.hls_config = hls_config

@classmethod
def from_backend(cls, backend, **pass_manager_options):
def from_backend(cls, backend, _skip_target=False, **pass_manager_options):
"""Construct a configuration based on a backend and user input.

This method automatically gererates a PassManagerConfig object based on the backend's
Expand All @@ -128,7 +128,6 @@ def from_backend(cls, backend, **pass_manager_options):
backend_version = 0
if backend_version < 2:
config = backend.configuration()

if res.basis_gates is None:
if backend_version < 2:
res.basis_gates = getattr(config, "basis_gates", None)
Expand Down Expand Up @@ -156,7 +155,7 @@ def from_backend(cls, backend, **pass_manager_options):
res.instruction_durations = backend.instruction_durations
if res.backend_properties is None and backend_version < 2:
res.backend_properties = backend.properties()
if res.target is None:
if res.target is None and not _skip_target:
if backend_version >= 2:
res.target = backend.target
if res.scheduling_method is None and hasattr(backend, "get_scheduling_stage_plugin"):
Expand Down
4 changes: 3 additions & 1 deletion qiskit/transpiler/preset_passmanagers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ def generate_preset_pass_manager(
hls_config=None,
init_method=None,
optimization_method=None,
*,
_skip_target=False,
):
"""Generate a preset :class:`~.PassManager`

Expand Down Expand Up @@ -241,10 +243,10 @@ def generate_preset_pass_manager(
}

if backend is not None:
pm_options["_skip_target"] = _skip_target
pm_config = PassManagerConfig.from_backend(backend, **pm_options)
else:
pm_config = PassManagerConfig(**pm_options)

if optimization_level == 0:
pm = level_0_pass_manager(pm_config)
elif optimization_level == 1:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
upgrade:
- |
Support for passing in lists of argument values to the :func:`~.transpile`
function is removed. This functionality was deprecated as part of the
0.23.0 release and is now being removed. Removing this functionality was
necessary to greatly reduce the overhead for parallel execution for
transpiling multiple circuits at once. If you’re using this functionality
currently you can call :func:`~.transpile` multiple times instead. For
example if you were previously doing something like::
mtreinish marked this conversation as resolved.
Show resolved Hide resolved

from qiskit.transpiler import CouplingMap
from qiskit import QuantumCircuit
from qiskit import transpile

qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.measure_all()

cmaps = [CouplingMap.from_heavy_hex(d) for d in range(3, 15, 2)]
results = transpile([qc] * 6, coupling_map=cmaps)

instead you should now run something like::

from itertools import cycle

from qiskit.transpiler import CouplingMap
from qiskit import QuantumCircuit
from qiskit import transpile

qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.measure_all()

cmaps = [CouplingMap.from_heavy_hex(d) for d in range(3, 15, 2)]
results = []
for qc, cmap in zip(cycle([qc]), cmaps):
results.append(transpile(qc, coupling_map=cmap))
mtreinish marked this conversation as resolved.
Show resolved Hide resolved

You can also leverage :func:`~.parallel_map` or ``multiprocessing`` from
the Python standard library if you want to run this in parallel.
14 changes: 3 additions & 11 deletions test/python/compiler/test_transpiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -635,7 +635,7 @@ def test_wrong_initial_layout(self):
QuantumRegister(3, "q")[2],
]

with self.assertRaisesRegex(TranspilerError, "different numbers of qubits"):
with self.assertRaises(TranspilerError):
transpile(qc, backend, initial_layout=bad_initial_layout)
Comment on lines -638 to 639
Copy link
Member

Choose a reason for hiding this comment

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

Is the new error message significantly worse?

Copy link
Member Author

Choose a reason for hiding this comment

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

It was when I modified this test, but @1ucian0 added a real error message in SetLayout as part of #10344 so it'll say:

The length of the layout is different than the size of the circuit 1024 <> 2

now. (I glossed over <> in my review we should change that to actually say 1024 qubits in the layout != 2 qubits in the circuit or something more explicit instead)

Copy link
Member

Choose a reason for hiding this comment

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

or just stick from __future__ import barry_as_FLUFL at the top of the file lol


def test_parameterized_circuit_for_simulator(self):
Expand Down Expand Up @@ -2071,24 +2071,16 @@ def test_transpile_with_multiple_coupling_maps(self):
cmap = CouplingMap.from_line(7)
cmap.add_edge(0, 2)

with self.assertWarnsRegex(
DeprecationWarning, "Passing in a list of arguments for coupling_map is deprecated"
):
with self.assertRaisesRegex(TranspilerError, "Only a single input coupling"):
# Initial layout needed to prevent transpiler from relabeling
# qubits to avoid doing the swap
tqc = transpile(
transpile(
[qc] * 2,
backend,
coupling_map=[backend.coupling_map, cmap],
initial_layout=(0, 1, 2),
)

# Check that the two coupling maps were used. The default should
# require swapping (extra cx's) and the second one should not (just the
# original cx).
self.assertEqual(tqc[0].count_ops()["cx"], 4)
self.assertEqual(tqc[1].count_ops()["cx"], 1)

@data(0, 1, 2, 3)
def test_backend_and_custom_gate(self, opt_level):
"""Test transpile() with BackendV2, custom basis pulse gate."""
Expand Down
7 changes: 0 additions & 7 deletions test/python/providers/test_backend_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@

from qiskit.circuit import QuantumCircuit, ClassicalRegister, QuantumRegister
from qiskit.compiler import transpile
from qiskit.compiler.transpiler import _parse_inst_map
from qiskit.pulse.instruction_schedule_map import InstructionScheduleMap
from qiskit.test.base import QiskitTestCase
from qiskit.providers.fake_provider import FakeMumbaiFractionalCX
from qiskit.providers.fake_provider.fake_backend_v2 import (
Expand Down Expand Up @@ -178,11 +176,6 @@ def test_transpile_mumbai_target(self):
expected.measure(qr[1], cr[1])
self.assertEqual(expected, tqc)

def test_transpile_parse_inst_map(self):
"""Test that transpiler._parse_inst_map() supports BackendV2."""
inst_map = _parse_inst_map(inst_map=None, backend=self.backend)
self.assertIsInstance(inst_map, InstructionScheduleMap)

@data(0, 1, 2, 3, 4)
def test_drive_channel(self, qubit):
"""Test getting drive channel with qubit index."""
Expand Down