Repository: Qiskit/qiskit

Issue:
Preset pass managers doesn't work with default Aer backend
### Environment

- **Qiskit Terra version**: 0.24
- **Python version**: 3.9
- **Operating system**: MacOs


### What is happening?

- Trying to use the preset pass manager to transpile a circuit doesn't work with AerBackend and gives an error at trivial layout stage that `"number of qubit greater than device"`

### How can we reproduce the issue?

```python
from qiskit import QuantumCircuit
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit_aer import AerSimulator

qc = QuantumCircuit(1)
pm = generate_preset_pass_manager(1, backend=AerSimulator())
pm.run(qc)
```

results in

```
---------------------------------------------------------------------------
TranspilerError                           Traceback (most recent call last)
Cell In [31], line 8
      6 pm = generate_staged_pass_manager(backend=AerSimulator())
      7 qc = RealAmplitudes(2)
----> 8 tqc = pm.run(qc)
      9 tqc.draw()

File ~/git/qiskit/pec-runtime/pec_runtime/transpiler/pass_manager.py:152, in StagedPassManager.run(self, circuits, output_name, callback)
    146 def run(
    147     self,
    148     circuits,
    149     output_name=None,
    150     callback=None,
    151 ):
--> 152     return self._run_converter(
    153         super().run, circuits, output_name=output_name, callback=callback
    154     )

File ~/git/qiskit/pec-runtime/pec_runtime/transpiler/pass_manager.py:48, in _TwirledMixin._run_converter(self, run_fn, circuits, **kwargs)
     45             circuit.metadata = {}
     47 # Run the regular staged pass manager
---> 48 transpiled = run_fn(circuits, **kwargs)
     49 if not self._return_twirled_circuit:
     50     return transpiled

File ~/mambaforge/envs/pec/lib/python3.9/site-packages/qiskit/transpiler/passmanager.py:537, in StagedPassManager.run(self, circuits, output_name, callback)
    530 def run(
    531     self,
    532     circuits: _CircuitsT,
    533     output_name: Optional[str] = None,
    534     callback: Optional[Callable] = None,
    535 ) -> _CircuitsT:
    536     self._update_passmanager()
--> 537     return super().run(circuits, output_name, callback)

File ~/mambaforge/envs/pec/lib/python3.9/site-packages/qiskit/transpiler/passmanager.py:231, in PassManager.run(self, circuits, output_name, callback)
    229     return circuits
    230 if isinstance(circuits, QuantumCircuit):
--> 231     return self._run_single_circuit(circuits, output_name, callback)
    232 if len(circuits) == 1:
    233     return [self._run_single_circuit(circuits[0], output_name, callback)]

File ~/mambaforge/envs/pec/lib/python3.9/site-packages/qiskit/transpiler/passmanager.py:292, in PassManager._run_single_circuit(self, circuit, output_name, callback)
    280 """Run all the passes on a ``circuit``.
    281 
    282 Args:
   (...)
    289     The transformed circuit.
    290 """
    291 running_passmanager = self._create_running_passmanager()
--> 292 result = running_passmanager.run(circuit, output_name=output_name, callback=callback)
    293 self.property_set = running_passmanager.property_set
    294 return result

File ~/git/qiskit/pec-runtime/pec_runtime/transpiler/running_pass_manager.py:33, in RunningPassManager.run(***failed resolving arguments***)
     31 next_dags = []
     32 for dag in current_dags:
---> 33     ret = self._do_pass(pass_, dag, passset.options)
     34     if isinstance(ret, DAGCircuit):
     35         next_dags.append(ret)

File ~/mambaforge/envs/pec/lib/python3.9/site-packages/qiskit/transpiler/runningpassmanager.py:173, in RunningPassManager._do_pass(self, pass_, dag, options)
    171 # Run the pass itself, if not already run
    172 if pass_ not in self.valid_passes:
--> 173     dag = self._run_this_pass(pass_, dag)
    175     # update the valid_passes property
    176     self._update_valid_passes(pass_)

File ~/git/qiskit/pec-runtime/pec_runtime/transpiler/running_pass_manager.py:108, in RunningPassManager._run_this_pass(self, pass_, dag)
    106     return new_dags
    107 else:
--> 108     return super()._run_this_pass(pass_, dag)

File ~/mambaforge/envs/pec/lib/python3.9/site-packages/qiskit/transpiler/runningpassmanager.py:227, in RunningPassManager._run_this_pass(self, pass_, dag)
    224 elif pass_.is_analysis_pass:
    225     # Measure time if we have a callback or logging set
    226     start_time = time()
--> 227     pass_.run(FencedDAGCircuit(dag))
    228     end_time = time()
    229     run_time = end_time - start_time

File ~/mambaforge/envs/pec/lib/python3.9/site-packages/qiskit/transpiler/passes/layout/trivial_layout.py:63, in TrivialLayout.run(self, dag)
     61         raise TranspilerError("Number of qubits greater than device.")
     62 elif dag.num_qubits() > self.coupling_map.size():
---> 63     raise TranspilerError("Number of qubits greater than device.")
     64 self.property_set["layout"] = Layout.generate_trivial_layout(
     65     *(dag.qubits + list(dag.qregs.values()))
     66 )

TranspilerError: 'Number of qubits greater than device.'
```

### What should happen?

Transpilation should work normally like for a real backend with coupling_map=None and an arbitrary number of qubits.

### Any suggestions?

No idea. But the trace log seems to indicate the issue is with the TrivialLayout pass when coupling map = None. Though that setting `coupling_map=None` without specifying a backend with the default pm function does work.


Discussion:
I think the issue is the pass manager is initializing a coupling map as `CouplingMap(None)`, and this has size 0, when it should have infinite size.

Resolving patch:
diff --git a/qiskit/transpiler/passmanager_config.py b/qiskit/transpiler/passmanager_config.py
--- a/qiskit/transpiler/passmanager_config.py
+++ b/qiskit/transpiler/passmanager_config.py
@@ -144,7 +144,9 @@ def from_backend(cls, backend, **pass_manager_options):
                 res.inst_map = backend.instruction_schedule_map
         if res.coupling_map is None:
             if backend_version < 2:
-                res.coupling_map = CouplingMap(getattr(config, "coupling_map", None))
+                cmap_edge_list = getattr(config, "coupling_map", None)
+                if cmap_edge_list is not None:
+                    res.coupling_map = CouplingMap(cmap_edge_list)
             else:
                 res.coupling_map = backend.coupling_map
         if res.instruction_durations is None:


Test patch:
diff --git a/test/python/transpiler/test_passmanager_config.py b/test/python/transpiler/test_passmanager_config.py
--- a/test/python/transpiler/test_passmanager_config.py
+++ b/test/python/transpiler/test_passmanager_config.py
@@ -86,6 +86,7 @@ def test_simulator_backend_v1(self):
         config = PassManagerConfig.from_backend(backend)
         self.assertIsInstance(config, PassManagerConfig)
         self.assertIsNone(config.inst_map)
+        self.assertIsNone(config.coupling_map)
 
     def test_invalid_user_option(self):
         """Test from_backend() with an invalid user option."""
@@ -103,7 +104,7 @@ def test_str(self):
 	initial_layout: None
 	basis_gates: ['id', 'rz', 'sx', 'x']
 	inst_map: None
-	coupling_map: 
+	coupling_map: None
 	layout_method: None
 	routing_method: None
 	translation_method: None