diff --git a/qiskit/transpiler/preset_passmanagers/level1.py b/qiskit/transpiler/preset_passmanagers/level1.py index 1db056c15244..86d2de27cb9f 100644 --- a/qiskit/transpiler/preset_passmanagers/level1.py +++ b/qiskit/transpiler/preset_passmanagers/level1.py @@ -27,11 +27,13 @@ from qiskit.transpiler.passes import CheckMap from qiskit.transpiler.passes import GateDirection from qiskit.transpiler.passes import SetLayout +from qiskit.transpiler.passes import VF2Layout from qiskit.transpiler.passes import TrivialLayout from qiskit.transpiler.passes import DenseLayout from qiskit.transpiler.passes import NoiseAdaptiveLayout from qiskit.transpiler.passes import SabreLayout from qiskit.transpiler.passes import BarrierBeforeFinalMeasurements +from qiskit.transpiler.passes import Layout2qDistance from qiskit.transpiler.passes import BasicSwap from qiskit.transpiler.passes import LookaheadSwap from qiskit.transpiler.passes import StochasticSwap @@ -44,7 +46,6 @@ from qiskit.transpiler.passes import Optimize1qGatesDecomposition from qiskit.transpiler.passes import ApplyLayout from qiskit.transpiler.passes import CheckGateDirection -from qiskit.transpiler.passes import Layout2qDistance from qiskit.transpiler.passes import Collect2qBlocks from qiskit.transpiler.passes import ConsolidateBlocks from qiskit.transpiler.passes import UnitarySynthesis @@ -56,6 +57,7 @@ from qiskit.transpiler.passes import PulseGates from qiskit.transpiler.passes import Error from qiskit.transpiler.passes import ContainsInstruction +from qiskit.transpiler.passes.layout.vf2_layout import VF2LayoutStopReason from qiskit.transpiler import TranspilerError @@ -102,17 +104,58 @@ def level_1_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager: timing_constraints = pass_manager_config.timing_constraints or TimingConstraints() target = pass_manager_config.target - # 1. Use trivial layout if no layout given + # 1. Use trivial layout if no layout given if that isn't perfect use vf2 layout _given_layout = SetLayout(initial_layout) - _choose_layout_and_score = [ - TrivialLayout(coupling_map), - Layout2qDistance(coupling_map, property_name="trivial_layout_score"), - ] - def _choose_layout_condition(property_set): return not property_set["layout"] + def _trivial_not_perfect(property_set): + # Verify that a trivial layout is perfect. If trivial_layout_score > 0 + # the layout is not perfect. The layout is unconditionally set by trivial + # layout so we need to clear it before contuing. + if ( + property_set["trivial_layout_score"] is not None + and property_set["trivial_layout_score"] != 0 + ): + return True + return False + + def _vf2_match_not_found(property_set): + # If a layout hasn't been set by the time we run vf2 layout we need to + # run layout + if property_set["layout"] is None: + return True + # if VF2 layout stopped for any reason other than solution found we need + # to run layout since VF2 didn't converge. + if ( + property_set["VF2Layout_stop_reason"] is not None + and property_set["VF2Layout_stop_reason"] is not VF2LayoutStopReason.SOLUTION_FOUND + ): + return True + return False + + _choose_layout_0 = ( + [] + if pass_manager_config.layout_method + else [ + TrivialLayout(coupling_map), + Layout2qDistance(coupling_map, property_name="trivial_layout_score"), + ] + ) + + _choose_layout_1 = ( + [] + if pass_manager_config.layout_method + else VF2Layout( + coupling_map, + seed=seed_transpiler, + call_limit=int(5e4), # Set call limit to ~100ms with retworkx 0.10.2 + time_limit=0.1, + properties=backend_properties, + ) + ) + # 2. Decompose so only 1-qubit and 2-qubit gates remain _unroll3q = [ # Use unitary synthesis for basis aware decomposition of UnitaryGates @@ -138,12 +181,6 @@ def _choose_layout_condition(property_set): else: raise TranspilerError("Invalid layout method %s." % layout_method) - def _not_perfect_yet(property_set): - return ( - property_set["trivial_layout_score"] is not None - and property_set["trivial_layout_score"] != 0 - ) - # 4. Extend dag/layout with ancillas using the full coupling map _embed = [FullAncillaAllocation(coupling_map), EnlargeWithAncilla(), ApplyLayout()] @@ -279,8 +316,9 @@ def _contains_delay(property_set): if coupling_map or initial_layout: pm1.append(_given_layout) pm1.append(_unroll3q) - pm1.append(_choose_layout_and_score, condition=_choose_layout_condition) - pm1.append(_improve_layout, condition=_not_perfect_yet) + pm1.append(_choose_layout_0, condition=_choose_layout_condition) + pm1.append(_choose_layout_1, condition=_trivial_not_perfect) + pm1.append(_improve_layout, condition=_vf2_match_not_found) pm1.append(_embed) pm1.append(_swap_check) pm1.append(_swap, condition=_swap_condition) diff --git a/qiskit/transpiler/preset_passmanagers/level2.py b/qiskit/transpiler/preset_passmanagers/level2.py index 1120db671468..a091b992d851 100644 --- a/qiskit/transpiler/preset_passmanagers/level2.py +++ b/qiskit/transpiler/preset_passmanagers/level2.py @@ -27,7 +27,7 @@ from qiskit.transpiler.passes import CheckMap from qiskit.transpiler.passes import GateDirection from qiskit.transpiler.passes import SetLayout -from qiskit.transpiler.passes import CSPLayout +from qiskit.transpiler.passes import VF2Layout from qiskit.transpiler.passes import TrivialLayout from qiskit.transpiler.passes import DenseLayout from qiskit.transpiler.passes import NoiseAdaptiveLayout @@ -45,7 +45,6 @@ from qiskit.transpiler.passes import Optimize1qGatesDecomposition from qiskit.transpiler.passes import CommutativeCancellation from qiskit.transpiler.passes import ApplyLayout -from qiskit.transpiler.passes import Layout2qDistance from qiskit.transpiler.passes import CheckGateDirection from qiskit.transpiler.passes import Collect2qBlocks from qiskit.transpiler.passes import ConsolidateBlocks @@ -58,6 +57,7 @@ from qiskit.transpiler.passes import PulseGates from qiskit.transpiler.passes import Error from qiskit.transpiler.passes import ContainsInstruction +from qiskit.transpiler.passes.layout.vf2_layout import VF2LayoutStopReason from qiskit.transpiler import TranspilerError @@ -126,54 +126,42 @@ def _choose_layout_condition(property_set): # layout hasn't been set yet return not property_set["layout"] - # 1a. If layout_method is not set, first try a trivial layout - _choose_layout_0 = ( - [] - if pass_manager_config.layout_method - else [ - TrivialLayout(coupling_map), - Layout2qDistance(coupling_map, property_name="trivial_layout_score"), - ] - ) - # 2b. If a trivial layout wasn't perfect (ie no swaps are needed) then try using - # CSP layout to find a perfect layout - _choose_layout_1 = ( - [] - if pass_manager_config.layout_method - else CSPLayout(coupling_map, call_limit=1000, time_limit=10, seed=seed_transpiler) - ) - - def _trivial_not_perfect(property_set): - # Verify that a trivial layout is perfect. If trivial_layout_score > 0 - # the layout is not perfect. The layout is unconditionally set by trivial - # layout so we need to clear it before continuing. - if property_set["trivial_layout_score"] is not None: - if property_set["trivial_layout_score"] != 0: - return True - return False - - def _csp_not_found_match(property_set): - # If a layout hasn't been set by the time we run csp we need to run layout + def _vf2_match_not_found(property_set): + # If a layout hasn't been set by the time we run vf2 layout we need to + # run layout if property_set["layout"] is None: return True - # if CSP layout stopped for any reason other than solution found we need - # to run layout since CSP didn't converge. + # if VF2 layout stopped for any reason other than solution found we need + # to run layout since VF2 didn't converge. if ( - property_set["CSPLayout_stop_reason"] is not None - and property_set["CSPLayout_stop_reason"] != "solution found" + property_set["VF2Layout_stop_reason"] is not None + and property_set["VF2Layout_stop_reason"] is not VF2LayoutStopReason.SOLUTION_FOUND ): return True return False - # 2c. if CSP layout doesn't converge on a solution use layout_method (dense) to get a layout + # 2a. Try using VF2 layout to find a perfect layout + _choose_layout_0 = ( + [] + if pass_manager_config.layout_method + else VF2Layout( + coupling_map, + seed=seed_transpiler, + call_limit=int(5e6), # Set call limit to ~10 sec with retworkx 0.10.2 + time_limit=10.0, + properties=backend_properties, + ) + ) + + # 2b. if VF2 layout doesn't converge on a solution use layout_method (dense) to get a layout if layout_method == "trivial": - _choose_layout_2 = TrivialLayout(coupling_map) + _choose_layout_1 = TrivialLayout(coupling_map) elif layout_method == "dense": - _choose_layout_2 = DenseLayout(coupling_map, backend_properties) + _choose_layout_1 = DenseLayout(coupling_map, backend_properties) elif layout_method == "noise_adaptive": - _choose_layout_2 = NoiseAdaptiveLayout(backend_properties) + _choose_layout_1 = NoiseAdaptiveLayout(backend_properties) elif layout_method == "sabre": - _choose_layout_2 = SabreLayout(coupling_map, max_iterations=2, seed=seed_transpiler) + _choose_layout_1 = SabreLayout(coupling_map, max_iterations=2, seed=seed_transpiler) else: raise TranspilerError("Invalid layout method %s." % layout_method) @@ -317,8 +305,7 @@ def _contains_delay(property_set): pm2.append(_given_layout) pm2.append(_unroll3q) pm2.append(_choose_layout_0, condition=_choose_layout_condition) - pm2.append(_choose_layout_1, condition=_trivial_not_perfect) - pm2.append(_choose_layout_2, condition=_csp_not_found_match) + pm2.append(_choose_layout_1, condition=_vf2_match_not_found) pm2.append(_embed) pm2.append(_swap_check) pm2.append(_swap, condition=_swap_condition) diff --git a/qiskit/transpiler/preset_passmanagers/level3.py b/qiskit/transpiler/preset_passmanagers/level3.py index dab463e60202..d8e6a70448ba 100644 --- a/qiskit/transpiler/preset_passmanagers/level3.py +++ b/qiskit/transpiler/preset_passmanagers/level3.py @@ -28,7 +28,7 @@ from qiskit.transpiler.passes import CheckMap from qiskit.transpiler.passes import GateDirection from qiskit.transpiler.passes import SetLayout -from qiskit.transpiler.passes import CSPLayout +from qiskit.transpiler.passes import VF2Layout from qiskit.transpiler.passes import TrivialLayout from qiskit.transpiler.passes import DenseLayout from qiskit.transpiler.passes import NoiseAdaptiveLayout @@ -51,7 +51,6 @@ from qiskit.transpiler.passes import ConsolidateBlocks from qiskit.transpiler.passes import UnitarySynthesis from qiskit.transpiler.passes import ApplyLayout -from qiskit.transpiler.passes import Layout2qDistance from qiskit.transpiler.passes import CheckGateDirection from qiskit.transpiler.passes import TimeUnitConversion from qiskit.transpiler.passes import ALAPSchedule @@ -61,6 +60,7 @@ from qiskit.transpiler.passes import PulseGates from qiskit.transpiler.passes import Error from qiskit.transpiler.passes import ContainsInstruction +from qiskit.transpiler.passes.layout.vf2_layout import VF2LayoutStopReason from qiskit.transpiler import TranspilerError @@ -129,54 +129,41 @@ def _choose_layout_condition(property_set): # layout hasn't been set yet return not property_set["layout"] - def _csp_not_found_match(property_set): - # If a layout hasn't been set by the time we run csp we need to run layout + def _vf2_match_not_found(property_set): + # If a layout hasn't been set by the time we run vf2 layout we need to + # run layout if property_set["layout"] is None: return True - # if CSP layout stopped for any reason other than solution found we need - # to run layout since CSP didn't converge. + # if VF2 layout stopped for any reason other than solution found we need + # to run layout since VF2 didn't converge. if ( - property_set["CSPLayout_stop_reason"] is not None - and property_set["CSPLayout_stop_reason"] != "solution found" + property_set["VF2Layout_stop_reason"] is not None + and property_set["VF2Layout_stop_reason"] is not VF2LayoutStopReason.SOLUTION_FOUND ): return True return False - # 2a. If layout method is not set, first try a trivial layout + # 2a. If layout method is not set, first try VF2Layout _choose_layout_0 = ( [] if pass_manager_config.layout_method - else [ - TrivialLayout(coupling_map), - Layout2qDistance(coupling_map, property_name="trivial_layout_score"), - ] - ) - # 2b. If trivial layout wasn't perfect (ie no swaps are needed) then try - # using CSP layout to find a perfect layout - _choose_layout_1 = ( - [] - if pass_manager_config.layout_method - else CSPLayout(coupling_map, call_limit=10000, time_limit=60, seed=seed_transpiler) + else VF2Layout( + coupling_map, + seed=seed_transpiler, + call_limit=int(3e7), # Set call limit to ~60 sec with retworkx 0.10.2 + time_limit=60, + properties=backend_properties, + ) ) - - def _trivial_not_perfect(property_set): - # Verify that a trivial layout is perfect. If trivial_layout_score > 0 - # the layout is not perfect. The layout property set is unconditionally - # set by trivial layout so we clear that before running CSP - if property_set["trivial_layout_score"] is not None: - if property_set["trivial_layout_score"] != 0: - return True - return False - - # 2c. if CSP didn't converge on a solution use layout_method (dense). + # 2b. if VF2 didn't converge on a solution use layout_method (dense). if layout_method == "trivial": - _choose_layout_2 = TrivialLayout(coupling_map) + _choose_layout_1 = TrivialLayout(coupling_map) elif layout_method == "dense": - _choose_layout_2 = DenseLayout(coupling_map, backend_properties) + _choose_layout_1 = DenseLayout(coupling_map, backend_properties) elif layout_method == "noise_adaptive": - _choose_layout_2 = NoiseAdaptiveLayout(backend_properties) + _choose_layout_1 = NoiseAdaptiveLayout(backend_properties) elif layout_method == "sabre": - _choose_layout_2 = SabreLayout(coupling_map, max_iterations=4, seed=seed_transpiler) + _choose_layout_1 = SabreLayout(coupling_map, max_iterations=4, seed=seed_transpiler) else: raise TranspilerError("Invalid layout method %s." % layout_method) @@ -329,8 +316,7 @@ def _contains_delay(property_set): if coupling_map or initial_layout: pm3.append(_given_layout) pm3.append(_choose_layout_0, condition=_choose_layout_condition) - pm3.append(_choose_layout_1, condition=_trivial_not_perfect) - pm3.append(_choose_layout_2, condition=_csp_not_found_match) + pm3.append(_choose_layout_1, condition=_vf2_match_not_found) pm3.append(_embed) pm3.append(_swap_check) pm3.append(_swap, condition=_swap_condition) diff --git a/qiskit/visualization/pulse_v2/interface.py b/qiskit/visualization/pulse_v2/interface.py index 0ace1a2ac703..cd9b00478371 100644 --- a/qiskit/visualization/pulse_v2/interface.py +++ b/qiskit/visualization/pulse_v2/interface.py @@ -314,7 +314,7 @@ def draw( qc.h(0) qc.cx(0, 1) qc.measure_all() - qc = transpile(qc, FakeAlmaden()) + qc = transpile(qc, FakeAlmaden(), layout_method='trivial') sched = schedule(qc, FakeAlmaden()) draw(sched, backend=FakeAlmaden()) @@ -331,7 +331,7 @@ def draw( qc.h(0) qc.cx(0, 1) qc.measure_all() - qc = transpile(qc, FakeAlmaden()) + qc = transpile(qc, FakeAlmaden(), layout_method='trivial') sched = schedule(qc, FakeAlmaden()) draw(sched, style=IQXSimple(), backend=FakeAlmaden()) @@ -348,7 +348,7 @@ def draw( qc.h(0) qc.cx(0, 1) qc.measure_all() - qc = transpile(qc, FakeAlmaden()) + qc = transpile(qc, FakeAlmaden(), layout_method='trivial') sched = schedule(qc, FakeAlmaden()) draw(sched, style=IQXDebugging(), backend=FakeAlmaden()) diff --git a/qiskit/visualization/timeline/interface.py b/qiskit/visualization/timeline/interface.py index cc34feedb4cd..689757fe5f1e 100644 --- a/qiskit/visualization/timeline/interface.py +++ b/qiskit/visualization/timeline/interface.py @@ -297,7 +297,7 @@ def draw( qc.h(0) qc.cx(0,1) - qc = transpile(qc, FakeAlmaden(), scheduling_method='alap') + qc = transpile(qc, FakeAlmaden(), scheduling_method='alap', layout_method='trivial') draw(qc) Drawing with the simple stylesheet. @@ -312,7 +312,7 @@ def draw( qc.h(0) qc.cx(0,1) - qc = transpile(qc, FakeAlmaden(), scheduling_method='alap') + qc = transpile(qc, FakeAlmaden(), scheduling_method='alap', layout_method='trivial') draw(qc, style=IQXSimple()) Drawing with the stylesheet suited for program debugging. @@ -327,7 +327,7 @@ def draw( qc.h(0) qc.cx(0,1) - qc = transpile(qc, FakeAlmaden(), scheduling_method='alap') + qc = transpile(qc, FakeAlmaden(), scheduling_method='alap', layout_method='trivial') draw(qc, style=IQXDebugging()) You can partially customize a preset stylesheet when call it:: diff --git a/releasenotes/notes/0.16/delay-in-circuit-33f0d81783ac12ea.yaml b/releasenotes/notes/0.16/delay-in-circuit-33f0d81783ac12ea.yaml index 05099302afda..bc04ad96c472 100644 --- a/releasenotes/notes/0.16/delay-in-circuit-33f0d81783ac12ea.yaml +++ b/releasenotes/notes/0.16/delay-in-circuit-33f0d81783ac12ea.yaml @@ -35,7 +35,7 @@ features: qc.h(0) qc.cx(0, 1) - scheduled_circuit = transpile(qc, backend=FakeAthens(), scheduling_method="alap") + scheduled_circuit = transpile(qc, backend=FakeAthens(), scheduling_method="alap", layout_method="trivial") print("Duration in dt:", scheduled_circuit.duration) scheduled_circuit.draw(idle_wires=False) diff --git a/releasenotes/notes/0.16/timeline-drawer-1c5e9b4a7f50f8c8.yaml b/releasenotes/notes/0.16/timeline-drawer-1c5e9b4a7f50f8c8.yaml index 4624942ce105..eae7075348ab 100644 --- a/releasenotes/notes/0.16/timeline-drawer-1c5e9b4a7f50f8c8.yaml +++ b/releasenotes/notes/0.16/timeline-drawer-1c5e9b4a7f50f8c8.yaml @@ -15,4 +15,4 @@ features: qc = QuantumCircuit(2) qc.h(0) qc.cx(0,1) - timeline_drawer(transpile(qc, FakeAthens(), scheduling_method='alap')) + timeline_drawer(transpile(qc, FakeAthens(), scheduling_method='alap', layout_method="trivial")) diff --git a/releasenotes/notes/vf2layout-preset-passmanager-db46513a24e79aa9.yaml b/releasenotes/notes/vf2layout-preset-passmanager-db46513a24e79aa9.yaml new file mode 100644 index 000000000000..86e9c23612a0 --- /dev/null +++ b/releasenotes/notes/vf2layout-preset-passmanager-db46513a24e79aa9.yaml @@ -0,0 +1,34 @@ +--- +upgrade: + - | + The preset passmanagers in :mod:`qiskit.transpiler.preset_passmanagers` + for all optimization levels 2 and 3 as generated by + :func:`~qiskit.transpiler.preset_passmanagers.level_2_pass_manager` and + :func:`~qiskit.transpiler.preset_passmanagers.level_3_pass_manager` have + been changed to run the :class:`~qiskit.transpiler.passes.VF2Layout` by + default prior to the layout pass. The + :class:`~qiskit.transpiler.passes.VF2Layout` pass will quickly check if + a perfect layout can be found and supersedes what was previously + done for optimization levels 2 and 3 which were using a combination of + :class:`~qiskit.transpiler.passes.TrivialLayout` and + :class:`~qiskit.transpiler.passes.CSPLayout` to try and find a perfect + layout. This will result in potentially different behavior when + :func:`~qiskit.compiler.transpile` is called by default as it removes a + default path for all optimization levels >=2 of using a trivial layout + (where ``circuit.qubits[0]`` is mapped to physical qubit 0, + ``circuit.qubits[1]`` is mapped to physical qubit 1, etc) assuming the + trivial layout is perfect. If your use case was dependent on the + trivial layout you can explictly request it when transpiling by specifying + ``layout_method="trivial"`` when calling :func:`~qiskit.compiler.transpile`. + - | + The preset pass manager for optimization level 1 (when calling + :func:`~qiskit.compiler.transpile` with ``optimization_level=1`` or when + no ``optimization_level`` argument is set) as generated by + :func:`~qiskit.transpiler.preset_passmanagers.level_1_pass_manager` has + been changed so that :class:`~qiskit.transpiler.passes.VF2Layout` is + called by default to quickly check if a a perfect layout can be found + prior to the :class:`~qiskit.transpiler.passes.DenseLayout`. However, + unlike with optimization level 2 and 3 a trivial layout is still attempted + prior to running :class:`~qiskit.transpiler.passes.VF2Layout` and if + it's a perfect mapping the output from + :class:`~qiskit.transpiler.passes.VF2Layout` will be used. diff --git a/test/python/algorithms/test_backendv1.py b/test/python/algorithms/test_backendv1.py index 09548a303a78..484ec99d4ed4 100644 --- a/test/python/algorithms/test_backendv1.py +++ b/test/python/algorithms/test_backendv1.py @@ -75,7 +75,7 @@ def test_run_circuit_oracle(self): oracle.cz(0, 1) problem = AmplificationProblem(oracle, is_good_state=["11"]) qi = QuantumInstance( - self._provider.get_backend("fake_yorktown"), seed_simulator=12, seed_transpiler=32 + self._provider.get_backend("fake_vigo"), seed_simulator=12, seed_transpiler=32 ) grover = Grover(quantum_instance=qi) result = grover.amplify(problem) @@ -86,11 +86,9 @@ def test_run_circuit_oracle_single_experiment_backend(self): oracle = QuantumCircuit(2) oracle.cz(0, 1) problem = AmplificationProblem(oracle, is_good_state=["11"]) - backend = self._provider.get_backend("fake_yorktown") + backend = self._provider.get_backend("fake_vigo") backend._configuration.max_experiments = 1 - qi = QuantumInstance( - self._provider.get_backend("fake_yorktown"), seed_simulator=12, seed_transpiler=32 - ) + qi = QuantumInstance(backend, seed_simulator=12, seed_transpiler=32) grover = Grover(quantum_instance=qi) result = grover.amplify(problem) self.assertIn(result.top_measurement, ["11"]) diff --git a/test/python/circuit/test_scheduled_circuit.py b/test/python/circuit/test_scheduled_circuit.py index 539a5ab9f8fe..502d6899e500 100644 --- a/test/python/circuit/test_scheduled_circuit.py +++ b/test/python/circuit/test_scheduled_circuit.py @@ -43,7 +43,7 @@ def test_schedule_circuit_when_backend_tells_dt(self): qc.delay(100, 0, unit="ns") # 450[dt] qc.h(0) # 160[dt] qc.h(1) # 160[dt] - sc = transpile(qc, self.backend_with_dt, scheduling_method="alap") + sc = transpile(qc, self.backend_with_dt, scheduling_method="alap", layout_method="trivial") self.assertEqual(sc.duration, 450610) self.assertEqual(sc.unit, "dt") self.assertEqual(sc.data[1][0].name, "delay") @@ -68,7 +68,13 @@ def test_schedule_circuit_when_transpile_option_tells_dt(self): qc.delay(100, 0, unit="ns") # 450[dt] qc.h(0) qc.h(1) - sc = transpile(qc, self.backend_without_dt, scheduling_method="alap", dt=self.dt) + sc = transpile( + qc, + self.backend_without_dt, + scheduling_method="alap", + dt=self.dt, + layout_method="trivial", + ) self.assertEqual(sc.duration, 450610) self.assertEqual(sc.unit, "dt") self.assertEqual(sc.data[1][0].name, "delay") @@ -88,7 +94,9 @@ def test_schedule_circuit_in_sec_when_no_one_tells_dt(self): qc.delay(100, 0, unit="ns") qc.h(0) qc.h(1) - sc = transpile(qc, self.backend_without_dt, scheduling_method="alap") + sc = transpile( + qc, self.backend_without_dt, scheduling_method="alap", layout_method="trivial" + ) self.assertAlmostEqual(sc.duration, 450610 * self.dt) self.assertEqual(sc.unit, "s") self.assertEqual(sc.data[1][0].name, "delay") @@ -135,7 +143,9 @@ def test_transpile_delay_circuit_with_backend(self): qc.h(0) qc.delay(100, 1, unit="ns") # 450 [dt] qc.cx(0, 1) # 1760 [dt] - scheduled = transpile(qc, backend=self.backend_with_dt, scheduling_method="alap") + scheduled = transpile( + qc, backend=self.backend_with_dt, scheduling_method="alap", layout_method="trivial" + ) self.assertEqual(scheduled.duration, 2082) def test_transpile_delay_circuit_without_backend(self): @@ -222,7 +232,9 @@ def test_unit_seconds_when_using_backend_durations(self): qc.delay(500 * self.dt, 1, "s") qc.cx(0, 1) # usual case - scheduled = transpile(qc, backend=self.backend_with_dt, scheduling_method="alap") + scheduled = transpile( + qc, backend=self.backend_with_dt, scheduling_method="alap", layout_method="trivial" + ) self.assertEqual(scheduled.duration, 2132) # update durations @@ -233,6 +245,7 @@ def test_unit_seconds_when_using_backend_durations(self): backend=self.backend_with_dt, scheduling_method="alap", instruction_durations=durations, + layout_method="trivial", ) self.assertEqual(scheduled.duration, 1500) diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py index 8fad88db952c..3a6de35f49a7 100644 --- a/test/python/compiler/test_transpiler.py +++ b/test/python/compiler/test_transpiler.py @@ -1051,6 +1051,7 @@ def test_transpiled_custom_gates_calibration(self): transpiled_circuit = transpile( circ, backend=backend, + layout_method="trivial", ) self.assertEqual(transpiled_circuit.calibrations, circ.calibrations) self.assertEqual(list(transpiled_circuit.count_ops().keys()), ["mycustom"]) @@ -1089,7 +1090,7 @@ def test_transpile_calibrated_custom_gate_on_diff_qubit(self): backend = FakeAlmaden() with self.assertRaises(QiskitError): - transpile(circ, backend=backend) + transpile(circ, backend=backend, layout_method="trivial") def test_transpile_calibrated_nonbasis_gate_on_diff_qubit(self): """Test if the non-basis gates are transpiled if they are on different qubit that @@ -1128,7 +1129,7 @@ def test_transpile_subset_of_calibrated_gates(self): circ.add_calibration(x_180, [0], q0_x180) circ.add_calibration("h", [1], q0_x180) # 'h' is calibrated on qubit 1 - transpiled_circ = transpile(circ, FakeAlmaden()) + transpiled_circ = transpile(circ, FakeAlmaden(), layout_method="trivial") self.assertEqual(set(transpiled_circ.count_ops().keys()), {"u2", "mycustom", "h"}) def test_parameterized_calibrations_transpile(self): @@ -1145,10 +1146,10 @@ def q0_rxt(tau): circ.add_calibration("rxt", [0], q0_rxt(tau), [2 * 3.14 * tau]) - transpiled_circ = transpile(circ, FakeAlmaden()) + transpiled_circ = transpile(circ, FakeAlmaden(), layout_method="trivial") self.assertEqual(set(transpiled_circ.count_ops().keys()), {"rxt"}) circ = circ.assign_parameters({tau: 1}) - transpiled_circ = transpile(circ, FakeAlmaden()) + transpiled_circ = transpile(circ, FakeAlmaden(), layout_method="trivial") self.assertEqual(set(transpiled_circ.count_ops().keys()), {"rxt"}) def test_inst_durations_from_calibrations(self): @@ -1205,7 +1206,7 @@ def test_multiqubit_gates_calibrations(self, opt_level): pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.ControlChannel(4) ) circ.add_calibration("my_custom_gate", [0, 1, 2, 3, 4], my_schedule, []) - trans_circ = transpile(circ, backend, optimization_level=opt_level) + trans_circ = transpile(circ, backend, optimization_level=opt_level, layout_method="trivial") self.assertEqual({"measure": 5, "my_custom_gate": 1, "barrier": 1}, trans_circ.count_ops()) @data(0, 1, 2, 3) diff --git a/test/python/providers/test_backend_v2.py b/test/python/providers/test_backend_v2.py index b1ebe69a1d9f..0f9d0204ae47 100644 --- a/test/python/providers/test_backend_v2.py +++ b/test/python/providers/test_backend_v2.py @@ -77,7 +77,7 @@ def test_transpile(self, opt_level): "invalid output" ], ) - self.assertTrue(Operator(tqc).equiv(qc)) + self.assertTrue(Operator.from_circuit(tqc).equiv(qc)) self.assertMatchesTargetConstraints(tqc, self.backend.target) @combine( @@ -99,7 +99,8 @@ def test_5q_ghz(self, opt_level, gate, bidirectional): getattr(qc, gate)(2, 3) getattr(qc, gate)(4, 3) tqc = transpile(qc, backend, optimization_level=opt_level) - self.assertTrue(Operator(tqc).equiv(qc)) + t_op = Operator.from_circuit(tqc) + self.assertTrue(t_op.equiv(qc)) self.assertMatchesTargetConstraints(tqc, backend.target) def test_transpile_respects_arg_constraints(self): @@ -109,7 +110,7 @@ def test_transpile_respects_arg_constraints(self): qc.h(0) qc.cx(1, 0) tqc = transpile(qc, self.backend) - self.assertTrue(Operator(tqc).equiv(qc)) + self.assertTrue(Operator.from_circuit(tqc).equiv(qc)) # Below is done to check we're decomposing cx(1, 0) with extra # rotations to correct for direction. However because of fp # differences between windows and other platforms the optimization @@ -125,7 +126,7 @@ def test_transpile_respects_arg_constraints(self): qc.h(0) qc.ecr(0, 1) tqc = transpile(qc, self.backend) - self.assertTrue(Operator(tqc).equiv(qc)) + self.assertTrue(Operator.from_circuit(tqc).equiv(qc)) self.assertEqual(tqc.count_ops(), {"ecr": 1, "u": 4}) self.assertMatchesTargetConstraints(tqc, self.backend.target) @@ -141,7 +142,7 @@ def test_transpile_relies_on_gate_direction(self): expected.ecr(1, 0) expected.u(math.pi / 2, 0, -math.pi, 0) expected.u(math.pi / 2, 0, -math.pi, 1) - self.assertTrue(Operator(tqc).equiv(qc)) + self.assertTrue(Operator.from_circuit(tqc).equiv(qc)) self.assertEqual(tqc.count_ops(), {"ecr": 1, "u": 4}) self.assertMatchesTargetConstraints(tqc, self.backend.target) diff --git a/test/python/transpiler/test_preset_passmanagers.py b/test/python/transpiler/test_preset_passmanagers.py index 62430edf6f34..e8429cef7bf0 100644 --- a/test/python/transpiler/test_preset_passmanagers.py +++ b/test/python/transpiler/test_preset_passmanagers.py @@ -552,59 +552,36 @@ def test_layout_tokyo_2845(self, level): 19: Qubit(QuantumRegister(15, "ancilla"), 14), } - dense_layout = { - 2: Qubit(QuantumRegister(3, "qr1"), 0), - 6: Qubit(QuantumRegister(3, "qr1"), 1), - 1: Qubit(QuantumRegister(3, "qr1"), 2), - 5: Qubit(QuantumRegister(2, "qr2"), 0), - 0: Qubit(QuantumRegister(2, "qr2"), 1), - 3: Qubit(QuantumRegister(15, "ancilla"), 0), - 4: Qubit(QuantumRegister(15, "ancilla"), 1), - 7: Qubit(QuantumRegister(15, "ancilla"), 2), - 8: Qubit(QuantumRegister(15, "ancilla"), 3), - 9: Qubit(QuantumRegister(15, "ancilla"), 4), - 10: Qubit(QuantumRegister(15, "ancilla"), 5), - 11: Qubit(QuantumRegister(15, "ancilla"), 6), - 12: Qubit(QuantumRegister(15, "ancilla"), 7), - 13: Qubit(QuantumRegister(15, "ancilla"), 8), - 14: Qubit(QuantumRegister(15, "ancilla"), 9), - 15: Qubit(QuantumRegister(15, "ancilla"), 10), - 16: Qubit(QuantumRegister(15, "ancilla"), 11), - 17: Qubit(QuantumRegister(15, "ancilla"), 12), - 18: Qubit(QuantumRegister(15, "ancilla"), 13), - 19: Qubit(QuantumRegister(15, "ancilla"), 14), - } - - csp_layout = { - 13: Qubit(QuantumRegister(3, "qr1"), 0), - 19: Qubit(QuantumRegister(3, "qr1"), 1), - 14: Qubit(QuantumRegister(3, "qr1"), 2), - 18: Qubit(QuantumRegister(2, "qr2"), 0), - 17: Qubit(QuantumRegister(2, "qr2"), 1), + vf2_layout = { 0: Qubit(QuantumRegister(15, "ancilla"), 0), 1: Qubit(QuantumRegister(15, "ancilla"), 1), 2: Qubit(QuantumRegister(15, "ancilla"), 2), 3: Qubit(QuantumRegister(15, "ancilla"), 3), - 4: Qubit(QuantumRegister(15, "ancilla"), 4), - 5: Qubit(QuantumRegister(15, "ancilla"), 5), - 6: Qubit(QuantumRegister(15, "ancilla"), 6), - 7: Qubit(QuantumRegister(15, "ancilla"), 7), - 8: Qubit(QuantumRegister(15, "ancilla"), 8), - 9: Qubit(QuantumRegister(15, "ancilla"), 9), - 10: Qubit(QuantumRegister(15, "ancilla"), 10), - 11: Qubit(QuantumRegister(15, "ancilla"), 11), - 12: Qubit(QuantumRegister(15, "ancilla"), 12), - 15: Qubit(QuantumRegister(15, "ancilla"), 13), - 16: Qubit(QuantumRegister(15, "ancilla"), 14), + 4: Qubit(QuantumRegister(3, "qr1"), 0), + 5: Qubit(QuantumRegister(15, "ancilla"), 4), + 6: Qubit(QuantumRegister(15, "ancilla"), 5), + 7: Qubit(QuantumRegister(15, "ancilla"), 6), + 8: Qubit(QuantumRegister(3, "qr1"), 1), + 9: Qubit(QuantumRegister(15, "ancilla"), 7), + 10: Qubit(QuantumRegister(15, "ancilla"), 8), + 11: Qubit(QuantumRegister(15, "ancilla"), 9), + 12: Qubit(QuantumRegister(15, "ancilla"), 10), + 13: Qubit(QuantumRegister(3, "qr1"), 2), + 14: Qubit(QuantumRegister(2, "qr2"), 0), + 15: Qubit(QuantumRegister(15, "ancilla"), 11), + 16: Qubit(QuantumRegister(15, "ancilla"), 12), + 17: Qubit(QuantumRegister(15, "ancilla"), 13), + 18: Qubit(QuantumRegister(15, "ancilla"), 14), + 19: Qubit(QuantumRegister(2, "qr2"), 1), } # Trivial layout expected_layout_level0 = trivial_layout # Dense layout - expected_layout_level1 = dense_layout + expected_layout_level1 = vf2_layout # CSP layout - expected_layout_level2 = csp_layout - expected_layout_level3 = csp_layout + expected_layout_level2 = vf2_layout + expected_layout_level3 = vf2_layout expected_layouts = [ expected_layout_level0, @@ -751,12 +728,12 @@ def test_all_levels_use_trivial_if_perfect(self, level): 18: Qubit(QuantumRegister(20, "q"), 18), 19: Qubit(QuantumRegister(20, "q"), 19), } - trans_qc = transpile(qc, backend, optimization_level=level) + trans_qc = transpile(qc, backend, optimization_level=level, seed_transpiler=42) self.assertEqual(trans_qc._layout._p2v, expected) - @data(0, 1) + @data(0) def test_trivial_layout(self, level): - """Test that trivial layout is preferred in level 0 and 1 + """Test that trivial layout is preferred in level 0 See: https://github.com/Qiskit/qiskit-terra/pull/3657#pullrequestreview-342012465 """ qr = QuantumRegister(10, "qr") diff --git a/test/python/transpiler/test_unitary_synthesis.py b/test/python/transpiler/test_unitary_synthesis.py index cbb3ae2079fa..bf1e339d89ac 100644 --- a/test/python/transpiler/test_unitary_synthesis.py +++ b/test/python/transpiler/test_unitary_synthesis.py @@ -578,7 +578,11 @@ def test_coupling_map_unequal_durations(self, opt): circ.append(random_unitary(4, seed=1), [1, 0]) backend = FakeVigo() tqc = transpile( - circ, backend=backend, optimization_level=opt, translation_method="synthesis" + circ, + backend=backend, + optimization_level=opt, + translation_method="synthesis", + layout_method="trivial", ) tqc_index = {qubit: index for index, qubit in enumerate(tqc.qubits)} self.assertTrue(