Repository: Qiskit/qiskit

Issue:
Transpiler doesn't produce differing circuit layouts when backend.properties object is updated with custom calibration data (cnot and readout)

### Information

- **Qiskit Terra version**: 0.16.0
- **Python version**: 3.7.4
- **Operating system**: Windows, conda env

### What is the current behavior?
After manually measuring the CNOT and Readout error measurements and updating these values in the backend.properties() object, the transpiler fails to produce differing circuit layouts in the following qiskit version:
`{'qiskit-terra': '0.16.0', 'qiskit-aer': '0.7.0', 'qiskit-ignis': '0.5.0', 'qiskit-ibmq-provider': '0.11.0', 'qiskit-aqua': '0.8.0', 'qiskit': '0.23.0'}`

This is not the case with an older qiskit version `{'qiskit-terra': '0.12.0', 'qiskit-aer': '0.4.0', 'qiskit-ignis': '0.2.0', 'qiskit-ibmq-provider': '0.4.6', 'qiskit-aqua': '0.6.4', 'qiskit': '0.15.0'}` where the transpiler produces differing circuit layouts with the exact same custom error measurement data as noted above.

On checking, it looks like this pull request (https://github.com/Qiskit/qiskit-terra/pull/5146 ) has made changes to neighbor discovery inside noise-adaptive layout which seems to be sensitive to our workflow. 

Could someone please look at this and check if the above change has affected the functionality of the noise-adaptive transpilation procedure?

### Steps to reproduce the problem
1. Manually change backend.properties() object by replacing `readout_error` and `gate_error` (CNOT) with custom values.
2. Call transpile with optimization level 3 (to use noise adaptive layout) and pass this updated backend properties object to force the transpiler to use custom error measurement data to create differing layouts.


### What is the expected behavior?
Circuit layouts produced with default backend.properties() object and those with manually updated object should be different.

### Suggested solutions
Could this change (https://github.com/Qiskit/qiskit-terra/pull/5146) be implemented in the form of a switchable parameter in the transpiler? 




Discussion:
#5146 should not have changed any behavior in the noise adaptive layout pass, all it did was cache the neighbors list for nodes in the internal graph for performance.

I actually think what is going on is that you're not using the noise adaptive layout pass anymore. In qiskit-terra 0.13.0 (metapackage 0.18.0) the default layout pass for optimization level 3 was changed to [CSPLayout](https://qiskit.org/documentation/stubs/qiskit.transpiler.passes.CSPLayout.html#qiskit.transpiler.passes.CSPLayout). You should change your transpile call to be
`transpile(circuit, backend, layout_method='noise_adaptive')` which will explicitly set the layout pass to be the noise adaptive layout pass (at any optimization level).

This was documented in the release notes at the time: https://qiskit.org/documentation/release_notes.html#notable-change (you have to search for it unfortunately a recent docs theme change is breaking links to the release note directly :/) Although it's not the best upgrade note there, it didn't mention what the old behavior was or how to retain it just that it was changed and a new dependency was added because of that.

Can you confirm that you still get the incorrect behavior when explicitly setting the layout method to the noise adaptive layout pass? If that doesn't fix the issue for you I can dig into the issue more (but will need example inputs for the noise properties you're using and a circuit).
@mtreinish Thanks, I tried your suggestion but the behavior is still the same. Setting `layout_method='noise_adaptive'` in `transpile` call didn't seem to help. 

Sure, can I share the files with you here? Also, I have the error data from `ibmq_boeblingen`, is that fine?
@mtreinish Were there any updates on this thread?
Currently, setting `layout_method='noise_adaptive'` will not prevent `CSPLayout` from running (and setting a layout if it finds one which does not require routing). This is noted in the `transpile` docstring, but might not be obvious behavior and might be worth changing. Thoughts @1ucian0 ?

@sudhakarsingh27 Feel free to post your code for building and transpiling your circuit here.

(Also, FYI, CSPLayout is being made aware of device noise characteristics in #5075 .)



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
@@ -101,7 +101,8 @@ def level_2_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager:
     def _choose_layout_condition(property_set):
         return not property_set['layout']
 
-    _choose_layout_1 = CSPLayout(coupling_map, call_limit=1000, time_limit=10)
+    _choose_layout_1 = [] if pass_manager_config.layout_method \
+        else CSPLayout(coupling_map, call_limit=1000, time_limit=10)
     if layout_method == 'trivial':
         _choose_layout_2 = TrivialLayout(coupling_map)
     elif layout_method == 'dense':
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
@@ -107,7 +107,8 @@ def level_3_pass_manager(pass_manager_config: PassManagerConfig) -> PassManager:
     def _choose_layout_condition(property_set):
         return not property_set['layout']
 
-    _choose_layout_1 = CSPLayout(coupling_map, call_limit=10000, time_limit=60)
+    _choose_layout_1 = [] if pass_manager_config.layout_method \
+        else CSPLayout(coupling_map, call_limit=10000, time_limit=60)
     if layout_method == 'trivial':
         _choose_layout_2 = TrivialLayout(coupling_map)
     elif layout_method == 'dense':


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
@@ -147,6 +147,23 @@ def test_backend(self, level):
         self.assertIn('ApplyLayout', self.passes)
         self.assertIn('CheckCXDirection', self.passes)
 
+    @data(0, 1, 2, 3)
+    def test_5409(self, level):
+        """The parameter layout_method='noise_adaptive' should be honored
+        See: https://github.com/Qiskit/qiskit-terra/issues/5409
+        """
+        qr = QuantumRegister(5, 'q')
+        qc = QuantumCircuit(qr)
+        qc.cx(qr[2], qr[4])
+        backend = FakeMelbourne()
+
+        _ = transpile(qc, backend, layout_method='noise_adaptive',
+                      optimization_level=level, callback=self.callback)
+
+        self.assertIn('SetLayout', self.passes)
+        self.assertIn('ApplyLayout', self.passes)
+        self.assertIn('NoiseAdaptiveLayout', self.passes)
+
     @data(0, 1, 2, 3)
     def test_symmetric_coupling_map(self, level):
         """Symmetric coupling map does not run CheckCXDirection