Repository: Qiskit/qiskit

Issue:
GraphState circuit depth excedingly high using optimization_levels 2 & 3
<!-- ⚠️ If you do not respect this template, your issue will be closed -->
<!-- ⚠️ Make sure to browse the opened and closed issues -->

### Information

- **Qiskit Terra version**: latest
- **Python version**:
- **Operating system**:

### What is the current behavior?
The following graph state fits exactly on the device (72 CX), but `optimization_level` 2 or 3 transpiles it to ~950 CX gates:

```python

backend = pro.get_backend('ibmq_manhattan')
config = backend.configuration()

rows = [x[0] for x in config.coupling_map]
cols = [x[1] for x in config.coupling_map]

A = np.zeros((65, 65))
A[rows, cols] = 1

qc = qiskit.circuit.library.GraphState(A)
qc.measure_all()

trans_qc = transpile(qc, backend, optimization_level=3)
```

### Steps to reproduce the problem



### What is the expected behavior?



### Suggested solutions





Discussion:
I added a callback to your script and printed the depth after each pass. Basically:

```
def callback(**kwargs):
    print(kwargs['pass_'])
    print(kwargs['dag'].depth())

trans_qc = transpile(qc, backend, optimization_level=3, callback=callback)
```

The issue here is the `CSPLayout` is not able to realize the graph state circuit matches a trivial layout and it chooses a suboptimal initial layout and causes stochastic swap to run greatly increasing the number of CX gates. While level 1 tries a trivial layout realizes it's a matches and skips DenseLayout and stochastic swap. I'm not sure the best path to go about fixing this, but maybe to add trying a trivial layout first to level2 and level3's passmanagers before using the CSP layout.

The raw output I got was:

```
Level 3
<qiskit.transpiler.passes.basis.unroll_3q_or_more.Unroll3qOrMore object at 0x7fb538416a00>
28
<qiskit.transpiler.passes.optimization.remove_reset_in_zero_state.RemoveResetInZeroState object at 0x7fb51f116eb0>
28
<qiskit.transpiler.passes.optimization.optimize_swap_before_measure.OptimizeSwapBeforeMeasure object at 0x7fb51f116f70>
28
<qiskit.transpiler.passes.optimization.remove_diagonal_gates_before_measure.RemoveDiagonalGatesBeforeMeasure object at 0x7fb51f116fa0>
28
<qiskit.transpiler.passes.layout.set_layout.SetLayout object at 0x7fb538416af0>
28
<qiskit.transpiler.passes.layout.csp_layout.CSPLayout object at 0x7fb538416b50>
28
<qiskit.transpiler.passes.layout.dense_layout.DenseLayout object at 0x7fb538416be0>
28
<qiskit.transpiler.passes.layout.full_ancilla_allocation.FullAncillaAllocation object at 0x7fb538416d00>
28
<qiskit.transpiler.passes.layout.enlarge_with_ancilla.EnlargeWithAncilla object at 0x7fb538416d60>
28
<qiskit.transpiler.passes.layout.apply_layout.ApplyLayout object at 0x7fb538416df0>
28
<qiskit.transpiler.passes.utils.check_map.CheckMap object at 0x7fb538416e80>
28
<qiskit.transpiler.passes.utils.barrier_before_final_measurements.BarrierBeforeFinalMeasurements object at 0x7fb538416ee0>
28
<qiskit.transpiler.passes.routing.stochastic_swap.StochasticSwap object at 0x7fb538416f40>
89
<qiskit.transpiler.passes.basis.unroll_custom_definitions.UnrollCustomDefinitions object at 0x7fb538416eb0>
89
<qiskit.transpiler.passes.basis.basis_translator.BasisTranslator object at 0x7fb538416fd0>
543
<qiskit.transpiler.passes.analysis.depth.Depth object at 0x7fb51f116d30>
543
<qiskit.transpiler.passes.utils.fixed_point.FixedPoint object at 0x7fb51f116d90>
543
<qiskit.transpiler.passes.optimization.collect_2q_blocks.Collect2qBlocks object at 0x7fb51f0a00d0>
543
<qiskit.transpiler.passes.optimization.consolidate_blocks.ConsolidateBlocks object at 0x7fb51f0a0160>
391
<qiskit.transpiler.passes.synthesis.unitary_synthesis.UnitarySynthesis object at 0x7fb51f0a0190>
477
<qiskit.transpiler.passes.optimization.optimize_1q_decomposition.Optimize1qGatesDecomposition object at 0x7fb51f0a0370>
344
<qiskit.transpiler.passes.optimization.commutation_analysis.CommutationAnalysis object at 0x7fb51f0a04c0>
344
<qiskit.transpiler.passes.optimization.commutative_cancellation.CommutativeCancellation object at 0x7fb51f0a0460>
335
<qiskit.transpiler.passes.basis.unroll_custom_definitions.UnrollCustomDefinitions object at 0x7fb538416eb0>
335
<qiskit.transpiler.passes.basis.basis_translator.BasisTranslator object at 0x7fb538416fd0>
370
<qiskit.transpiler.passes.analysis.depth.Depth object at 0x7fb51f116d30>
370
<qiskit.transpiler.passes.utils.fixed_point.FixedPoint object at 0x7fb51f116d90>
370
<qiskit.transpiler.passes.optimization.collect_2q_blocks.Collect2qBlocks object at 0x7fb51f0a00d0>
370
<qiskit.transpiler.passes.optimization.consolidate_blocks.ConsolidateBlocks object at 0x7fb51f0a0160>
357
<qiskit.transpiler.passes.synthesis.unitary_synthesis.UnitarySynthesis object at 0x7fb51f0a0190>
366
<qiskit.transpiler.passes.optimization.optimize_1q_decomposition.Optimize1qGatesDecomposition object at 0x7fb51f0a0370>
335
<qiskit.transpiler.passes.optimization.commutation_analysis.CommutationAnalysis object at 0x7fb51f0a04c0>
335
<qiskit.transpiler.passes.optimization.commutative_cancellation.CommutativeCancellation object at 0x7fb51f0a0460>
332
<qiskit.transpiler.passes.basis.unroll_custom_definitions.UnrollCustomDefinitions object at 0x7fb538416eb0>
332
<qiskit.transpiler.passes.basis.basis_translator.BasisTranslator object at 0x7fb538416fd0>
340
<qiskit.transpiler.passes.analysis.depth.Depth object at 0x7fb51f116d30>
340
<qiskit.transpiler.passes.utils.fixed_point.FixedPoint object at 0x7fb51f116d90>
340
<qiskit.transpiler.passes.optimization.collect_2q_blocks.Collect2qBlocks object at 0x7fb51f0a00d0>
340
<qiskit.transpiler.passes.optimization.consolidate_blocks.ConsolidateBlocks object at 0x7fb51f0a0160>
336
<qiskit.transpiler.passes.synthesis.unitary_synthesis.UnitarySynthesis object at 0x7fb51f0a0190>
336
<qiskit.transpiler.passes.optimization.optimize_1q_decomposition.Optimize1qGatesDecomposition object at 0x7fb51f0a0370>
336
<qiskit.transpiler.passes.optimization.commutation_analysis.CommutationAnalysis object at 0x7fb51f0a04c0>
336
<qiskit.transpiler.passes.optimization.commutative_cancellation.CommutativeCancellation object at 0x7fb51f0a0460>
333
<qiskit.transpiler.passes.basis.unroll_custom_definitions.UnrollCustomDefinitions object at 0x7fb538416eb0>
333
<qiskit.transpiler.passes.basis.basis_translator.BasisTranslator object at 0x7fb538416fd0>
333
<qiskit.transpiler.passes.analysis.depth.Depth object at 0x7fb51f116d30>
333
<qiskit.transpiler.passes.utils.fixed_point.FixedPoint object at 0x7fb51f116d90>
333
<qiskit.transpiler.passes.optimization.collect_2q_blocks.Collect2qBlocks object at 0x7fb51f0a00d0>
333
<qiskit.transpiler.passes.optimization.consolidate_blocks.ConsolidateBlocks object at 0x7fb51f0a0160>
333
<qiskit.transpiler.passes.synthesis.unitary_synthesis.UnitarySynthesis object at 0x7fb51f0a0190>
333
<qiskit.transpiler.passes.optimization.optimize_1q_decomposition.Optimize1qGatesDecomposition object at 0x7fb51f0a0370>
333
<qiskit.transpiler.passes.optimization.commutation_analysis.CommutationAnalysis object at 0x7fb51f0a04c0>
333
<qiskit.transpiler.passes.optimization.commutative_cancellation.CommutativeCancellation object at 0x7fb51f0a0460>
333
<qiskit.transpiler.passes.basis.unroll_custom_definitions.UnrollCustomDefinitions object at 0x7fb538416eb0>
333
<qiskit.transpiler.passes.basis.basis_translator.BasisTranslator object at 0x7fb538416fd0>
333
<qiskit.transpiler.passes.analysis.depth.Depth object at 0x7fb51f116d30>
333
<qiskit.transpiler.passes.utils.fixed_point.FixedPoint object at 0x7fb51f116d90>
333
<qiskit.transpiler.passes.optimization.collect_2q_blocks.Collect2qBlocks object at 0x7fb51f0a00d0>
333
<qiskit.transpiler.passes.optimization.consolidate_blocks.ConsolidateBlocks object at 0x7fb51f0a0160>
333
<qiskit.transpiler.passes.synthesis.unitary_synthesis.UnitarySynthesis object at 0x7fb51f0a0190>
333
<qiskit.transpiler.passes.optimization.optimize_1q_decomposition.Optimize1qGatesDecomposition object at 0x7fb51f0a0370>
333
<qiskit.transpiler.passes.optimization.commutation_analysis.CommutationAnalysis object at 0x7fb51f0a04c0>
333
<qiskit.transpiler.passes.optimization.commutative_cancellation.CommutativeCancellation object at 0x7fb51f0a0460>
333
<qiskit.transpiler.passes.basis.unroll_custom_definitions.UnrollCustomDefinitions object at 0x7fb538416eb0>
333
<qiskit.transpiler.passes.basis.basis_translator.BasisTranslator object at 0x7fb538416fd0>
333
<qiskit.transpiler.passes.optimization.remove_reset_in_zero_state.RemoveResetInZeroState object at 0x7fb51f116eb0>
333

Level 2
<qiskit.transpiler.passes.layout.set_layout.SetLayout object at 0x7fb538507ee0>
28
<qiskit.transpiler.passes.layout.csp_layout.CSPLayout object at 0x7fb538507e50>
28
<qiskit.transpiler.passes.layout.dense_layout.DenseLayout object at 0x7fb538507e20>
28
<qiskit.transpiler.passes.layout.full_ancilla_allocation.FullAncillaAllocation object at 0x7fb538507d30>
28
<qiskit.transpiler.passes.layout.enlarge_with_ancilla.EnlargeWithAncilla object at 0x7fb538507d00>
28
<qiskit.transpiler.passes.layout.apply_layout.ApplyLayout object at 0x7fb51ec42550>
28
<qiskit.transpiler.passes.basis.unroll_3q_or_more.Unroll3qOrMore object at 0x7fb51ec42610>
28
<qiskit.transpiler.passes.utils.check_map.CheckMap object at 0x7fb51f13d490>
28
<qiskit.transpiler.passes.utils.barrier_before_final_measurements.BarrierBeforeFinalMeasurements object at 0x7fb51f26c640>
28
<qiskit.transpiler.passes.routing.stochastic_swap.StochasticSwap object at 0x7fb51ed9ee50>
96
<qiskit.transpiler.passes.basis.unroll_custom_definitions.UnrollCustomDefinitions object at 0x7fb51ed9edf0>
96
<qiskit.transpiler.passes.basis.basis_translator.BasisTranslator object at 0x7fb51ed9e610>
592
<qiskit.transpiler.passes.optimization.remove_reset_in_zero_state.RemoveResetInZeroState object at 0x7fb51ed9ebe0>
592
<qiskit.transpiler.passes.analysis.depth.Depth object at 0x7fb51ed9edc0>
592
<qiskit.transpiler.passes.utils.fixed_point.FixedPoint object at 0x7fb51ed9e8e0>
592
<qiskit.transpiler.passes.optimization.optimize_1q_decomposition.Optimize1qGatesDecomposition object at 0x7fb51ed9e370>
320
<qiskit.transpiler.passes.optimization.commutation_analysis.CommutationAnalysis object at 0x7fb51ed9ecd0>
320
<qiskit.transpiler.passes.optimization.commutative_cancellation.CommutativeCancellation object at 0x7fb51ed9e9a0>
320
<qiskit.transpiler.passes.basis.unroll_custom_definitions.UnrollCustomDefinitions object at 0x7fb51ed9edf0>
320
<qiskit.transpiler.passes.basis.basis_translator.BasisTranslator object at 0x7fb51ed9e610>
320
<qiskit.transpiler.passes.analysis.depth.Depth object at 0x7fb51ed9edc0>
320
<qiskit.transpiler.passes.utils.fixed_point.FixedPoint object at 0x7fb51ed9e8e0>
320
<qiskit.transpiler.passes.optimization.optimize_1q_decomposition.Optimize1qGatesDecomposition object at 0x7fb51ed9e370>
320
<qiskit.transpiler.passes.optimization.commutation_analysis.CommutationAnalysis object at 0x7fb51ed9ecd0>
320
<qiskit.transpiler.passes.optimization.commutative_cancellation.CommutativeCancellation object at 0x7fb51ed9e9a0>
320
<qiskit.transpiler.passes.basis.unroll_custom_definitions.UnrollCustomDefinitions object at 0x7fb51ed9edf0>
320
<qiskit.transpiler.passes.basis.basis_translator.BasisTranslator object at 0x7fb51ed9e610>
320
<qiskit.transpiler.passes.analysis.depth.Depth object at 0x7fb51ed9edc0>
320
<qiskit.transpiler.passes.utils.fixed_point.FixedPoint object at 0x7fb51ed9e8e0>
320
<qiskit.transpiler.passes.optimization.optimize_1q_decomposition.Optimize1qGatesDecomposition object at 0x7fb51ed9e370>
320
<qiskit.transpiler.passes.optimization.commutation_analysis.CommutationAnalysis object at 0x7fb51ed9ecd0>
320
<qiskit.transpiler.passes.optimization.commutative_cancellation.CommutativeCancellation object at 0x7fb51ed9e9a0>
320
<qiskit.transpiler.passes.basis.unroll_custom_definitions.UnrollCustomDefinitions object at 0x7fb51ed9edf0>
320
<qiskit.transpiler.passes.basis.basis_translator.BasisTranslator object at 0x7fb51ed9e610>
320

Level 1
<qiskit.transpiler.passes.layout.set_layout.SetLayout object at 0x7fb51ee50ca0>
28
<qiskit.transpiler.passes.layout.trivial_layout.TrivialLayout object at 0x7fb51edf7700>
28
<qiskit.transpiler.passes.layout.layout_2q_distance.Layout2qDistance object at 0x7fb51ebffb20>
28
<qiskit.transpiler.passes.layout.full_ancilla_allocation.FullAncillaAllocation object at 0x7fb51ee162e0>
28
<qiskit.transpiler.passes.layout.enlarge_with_ancilla.EnlargeWithAncilla object at 0x7fb51ee16760>
28
<qiskit.transpiler.passes.layout.apply_layout.ApplyLayout object at 0x7fb51f049a60>
28
<qiskit.transpiler.passes.basis.unroll_3q_or_more.Unroll3qOrMore object at 0x7fb51eef1cd0>
28
<qiskit.transpiler.passes.utils.check_map.CheckMap object at 0x7fb51ee95100>
28
<qiskit.transpiler.passes.basis.unroll_custom_definitions.UnrollCustomDefinitions object at 0x7fb51ef01190>
28
<qiskit.transpiler.passes.basis.basis_translator.BasisTranslator object at 0x7fb51f102190>
335
<qiskit.transpiler.passes.optimization.remove_reset_in_zero_state.RemoveResetInZeroState object at 0x7fb51f06b0a0>
335
<qiskit.transpiler.passes.analysis.depth.Depth object at 0x7fb51ecae790>
335
<qiskit.transpiler.passes.utils.fixed_point.FixedPoint object at 0x7fb51ecae5b0>
335
<qiskit.transpiler.passes.optimization.optimize_1q_decomposition.Optimize1qGatesDecomposition object at 0x7fb51eef92e0>
84
<qiskit.transpiler.passes.optimization.cx_cancellation.CXCancellation object at 0x7fb51eef98b0>
84
<qiskit.transpiler.passes.analysis.depth.Depth object at 0x7fb51ecae790>
84
<qiskit.transpiler.passes.utils.fixed_point.FixedPoint object at 0x7fb51ecae5b0>
84
<qiskit.transpiler.passes.optimization.optimize_1q_decomposition.Optimize1qGatesDecomposition object at 0x7fb51eef92e0>
84
<qiskit.transpiler.passes.optimization.cx_cancellation.CXCancellation object at 0x7fb51eef98b0>
84
<qiskit.transpiler.passes.analysis.depth.Depth object at 0x7fb51ecae790>
84
<qiskit.transpiler.passes.utils.fixed_point.FixedPoint object at 0x7fb51ecae5b0>
84
<qiskit.transpiler.passes.optimization.optimize_1q_decomposition.Optimize1qGatesDecomposition object at 0x7fb51eef92e0>
84
<qiskit.transpiler.passes.optimization.cx_cancellation.CXCancellation object at 0x7fb51eef98b0>
84
```

Resolving patch:
diff --git a/qiskit/transpiler/preset_passmanagers/level2.py b/qiskit/transpiler/preset_passmanagers/level2.py
--- a/qiskit/transpiler/preset_passmanagers/level2.py
+++ b/qiskit/transpiler/preset_passmanagers/level2.py
@@ -44,6 +44,7 @@
 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
@@ -99,10 +100,41 @@ def level_2_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager:
     _given_layout = SetLayout(initial_layout)
 
     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')]
+    # 1b. 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 contuing.
+        if property_set['trivial_layout_score'] is not None:
+            if property_set['trivial_layout_score'] != 0:
+                property_set['layout']._wrapped = None
+                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
+        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 property_set['CSPLayout_stop_reason'] is not None \
+                and property_set['CSPLayout_stop_reason'] != "solution found":
+            return True
+        return False
+
+    # 1c. if CSP 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)
     elif layout_method == 'dense':
@@ -193,8 +225,9 @@ def _opt_control(property_set):
     pm2 = PassManager()
     if coupling_map or initial_layout:
         pm2.append(_given_layout)
-        pm2.append(_choose_layout_1, condition=_choose_layout_condition)
-        pm2.append(_choose_layout_2, condition=_choose_layout_condition)
+        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(_embed)
         pm2.append(_unroll3q)
         pm2.append(_swap_check)
diff --git a/qiskit/transpiler/preset_passmanagers/level3.py b/qiskit/transpiler/preset_passmanagers/level3.py
--- a/qiskit/transpiler/preset_passmanagers/level3.py
+++ b/qiskit/transpiler/preset_passmanagers/level3.py
@@ -50,6 +50,7 @@
 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
@@ -105,10 +106,41 @@ def level_3_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager:
     _given_layout = SetLayout(initial_layout)
 
     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
+        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 property_set['CSPLayout_stop_reason'] is not None \
+                and property_set['CSPLayout_stop_reason'] != "solution found":
+            return True
+        return False
+
+    # 2a. 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 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)
+
+    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:
+                property_set['layout']._wrapped = None
+                return True
+        return False
+
+    # 2c. if CSP didn't converge on a solution use layout_method (dense).
     if layout_method == 'trivial':
         _choose_layout_2 = TrivialLayout(coupling_map)
     elif layout_method == 'dense':
@@ -205,8 +237,9 @@ def _opt_control(property_set):
     pm3.append(_reset + _meas)
     if coupling_map or initial_layout:
         pm3.append(_given_layout)
-        pm3.append(_choose_layout_1, condition=_choose_layout_condition)
-        pm3.append(_choose_layout_2, condition=_choose_layout_condition)
+        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(_embed)
         pm3.append(_swap_check)
         pm3.append(_swap, condition=_swap_condition)


Test patch:
diff --git a/test/python/transpiler/test_preset_passmanagers.py b/test/python/transpiler/test_preset_passmanagers.py
--- a/test/python/transpiler/test_preset_passmanagers.py
+++ b/test/python/transpiler/test_preset_passmanagers.py
@@ -25,6 +25,7 @@
 from qiskit.test.mock import (FakeTenerife, FakeMelbourne, FakeJohannesburg,
                               FakeRueschlikon, FakeTokyo, FakePoughkeepsie)
 from qiskit.converters import circuit_to_dag
+from qiskit.circuit.library import GraphState
 
 
 def emptycircuit():
@@ -482,6 +483,48 @@ def test_layout_tokyo_fully_connected_cx(self, level):
         result = transpile(qc, backend, optimization_level=level, seed_transpiler=42)
         self.assertEqual(result._layout._p2v, expected_layouts[level])
 
+    @data(0, 1, 2, 3)
+    def test_all_levels_use_trivial_if_perfect(self, level):
+        """Test that we always use trivial if it's a perfect match.
+
+        See: https://github.com/Qiskit/qiskit-terra/issues/5694 for more
+        details
+        """
+        backend = FakeTokyo()
+        config = backend.configuration()
+
+        rows = [x[0] for x in config.coupling_map]
+        cols = [x[1] for x in config.coupling_map]
+
+        adjacency_matrix = np.zeros((20, 20))
+        adjacency_matrix[rows, cols] = 1
+        qc = GraphState(adjacency_matrix)
+        qc.measure_all()
+        expected = {
+            0: Qubit(QuantumRegister(20, 'q'), 0),
+            1: Qubit(QuantumRegister(20, 'q'), 1),
+            2: Qubit(QuantumRegister(20, 'q'), 2),
+            3: Qubit(QuantumRegister(20, 'q'), 3),
+            4: Qubit(QuantumRegister(20, 'q'), 4),
+            5: Qubit(QuantumRegister(20, 'q'), 5),
+            6: Qubit(QuantumRegister(20, 'q'), 6),
+            7: Qubit(QuantumRegister(20, 'q'), 7),
+            8: Qubit(QuantumRegister(20, 'q'), 8),
+            9: Qubit(QuantumRegister(20, 'q'), 9),
+            10: Qubit(QuantumRegister(20, 'q'), 10),
+            11: Qubit(QuantumRegister(20, 'q'), 11),
+            12: Qubit(QuantumRegister(20, 'q'), 12),
+            13: Qubit(QuantumRegister(20, 'q'), 13),
+            14: Qubit(QuantumRegister(20, 'q'), 14),
+            15: Qubit(QuantumRegister(20, 'q'), 15),
+            16: Qubit(QuantumRegister(20, 'q'), 16),
+            17: Qubit(QuantumRegister(20, 'q'), 17),
+            18: Qubit(QuantumRegister(20, 'q'), 18),
+            19: Qubit(QuantumRegister(20, 'q'), 19)
+        }
+        trans_qc = transpile(qc, backend, optimization_level=level)
+        self.assertEqual(trans_qc._layout._p2v, expected)
+
     @data(0, 1)
     def test_trivial_layout(self, level):
         """Test that trivial layout is preferred in level 0 and 1