Repository: Qiskit/qiskit

Issue:
No good way to define pass manager for use in transpile
<!-- ⚠️ If you do not respect this template, your issue will be closed -->
<!-- ⚠️ Make sure to browse the opened and closed issues to confirm this idea does not exist. -->

### What is the expected enhancement?
Supposed I want to write a pass manager that can be used for any input circuit or backend, for example, and can be simply passed to `transpile`, e.g.

`transpile(qc, backend, pass_manager=my_pass_manager)`

I do not think that there is actually a way to do this without doing additional work in building `TranpileConfig` for initializing the PM, or just directly setting the properties upon construction.  Instead, it would be nice if `pass_manager` could take a function, for example, that uses the internally computed `TranspileConfig` to initialize a PM (just like the preset ones do).  Then a user defined pass_manager could be simply imported like any other function, and just passed to `transpile` with no additional work required.



Discussion:
You dont need `TranpileConfig` to create a custom `PassManager`. You can just:
```python 
def my_pass_manager(parameter1, parameter0):
    pm = PassManager([pass1(parameter1), pass2(parameter2)])
    return pm
```

You could import this `PassManager` as `from file import my_pass_manager`.

Am I missing something?
But now you need to define a pass manager in a different place than transpile, but still need to pass it to transpile.  Why not allow a function that works in the exact same way as the internal transpile passes to grab configuration from transpile itself.  It is much cleaner.
> but still need to pass it to transpile.

You can also run `pm.run(circuit)`. I'm not fully sure if I understand the connection between the test in #2685 and your use case. The test uses a preset pass manager.

I agree we should come up with a simpler way to build pass managers without `TranpileConfig`. I also find that object unnecessary. 
What if you want to do thousands of circuits in parallel like is possible in transpile?  

The test is simply testing that I can pass a function, e.g our preset passmanagers.  If I make my own, and look for it to match a given answer then the reference may change, giving errors for no reason.  The test shows that imputing a function gives the same as a standard preset.

I do not particularly mind the `TranspileConfig` as it is a mostly internal / advanced object.  It provides a single object from which one can basically do whatever you want for configuration.  Just needs  to be documented.
But, if you create your own passmanager function, that function needs to understand `TranspileConfig`, right?
Yep, which is why the config needs to be documented.
Gotcha! You want to pass a passmanager "constructor" to the transpiler.. makes sense. I see the problem. The next question is.. why not having a different parameter for that?
I do not care.  I just want the functionality.
Actually I remember why I thought it was a bad idea.  We run into issues with implicit priority.  Namely, is the `passmanager` kwarg higher-priority than the hypothetical `constructor` or the other way?  It becomes a bit of a mess.  
This is the problem. The `pass_manager` kwarg to `transpile()` was only included for backwards compatibility (I was close to removing it). In the docstring I included this remark:

```
        pass_manager (PassManager):
            The pass manager to use for a custom pipeline of transpiler passes.
            If this arg is present, all other args will be ignored and the
            pass manager will be used directly (Qiskit will not attempt to
            auto-select a pass manager based on transpile options).
```

So, in your example, the backend arg is actually being ignored.
```transpile(qc, backend, pass_manager=my_pass_manager)```

I think this behavior is confusing and we should remove the `pass_manager` kwarg. If you have a custom pass manager, just do `pm.run(circuits)`. I also like this syntax because it resembles `backend.run(qobj)`.

I know that this will currently not parallelize over many circuits, but let's fix that. There was an open issue for this but got closed: https://github.com/Qiskit/qiskit-terra/issues/2156

Does this make sense?
I am fine with that, although it makes switching between internal and external pass managers a bit cumbersome 
I see @nonhermitian use case. I think it makes sense to have the possibility of passing it's own passmanager constructor to `transpile`. I also agree with @ajavadia that it should not be the `pass_manager` attribute (I'm okey with removing it).

Resolving patch:
diff --git a/qiskit/transpiler/passmanager.py b/qiskit/transpiler/passmanager.py
--- a/qiskit/transpiler/passmanager.py
+++ b/qiskit/transpiler/passmanager.py
@@ -14,7 +14,11 @@
 
 """PassManager class for the transpiler."""
 
+import dill
+
 from qiskit.visualization import pass_manager_drawer
+from qiskit.tools.parallel import parallel_map
+from qiskit.circuit import QuantumCircuit
 from .basepasses import BasePass
 from .exceptions import TranspilerError
 from .runningpassmanager import RunningPassManager
@@ -143,19 +147,56 @@ def _normalize_passes(passes):
                 raise TranspilerError('%s is not a pass instance' % pass_.__class__)
         return passes
 
-    def run(self, circuit):
-        """Run all the passes on a QuantumCircuit
+    def run(self, circuits):
+        """Run all the passes on circuit or circuits
 
         Args:
-            circuit (QuantumCircuit): circuit to transform via all the registered passes
+            circuits (QuantumCircuit or list[QuantumCircuit]): circuit(s) to
+            transform via all the registered passes.
 
         Returns:
-            QuantumCircuit: Transformed circuit.
+            QuantumCircuit or list[QuantumCircuit]: Transformed circuit(s).
         """
+        if isinstance(circuits, QuantumCircuit):
+            return self._run_single_circuit(circuits)
+        else:
+            return self._run_several_circuits(circuits)
+
+    def _create_running_passmanager(self):
         running_passmanager = RunningPassManager(self.max_iteration, self.callback)
         for pass_set in self._pass_sets:
             running_passmanager.append(pass_set['passes'], **pass_set['flow_controllers'])
+        return running_passmanager
+
+    @staticmethod
+    def _in_parallel(circuit, pm_dill=None):
+        """ Used by _run_several_circuits. """
+        running_passmanager = dill.loads(pm_dill)._create_running_passmanager()
+        result = running_passmanager.run(circuit)
+        return result
+
+    def _run_several_circuits(self, circuits):
+        """Run all the passes on each of the circuits in the circuits list
+
+        Args:
+            circuits (list[QuantumCircuit]): circuit to transform via all the registered passes
 
+        Returns:
+            list[QuantumCircuit]: Transformed circuits.
+        """
+        return parallel_map(PassManager._in_parallel, circuits,
+                            task_kwargs={'pm_dill': dill.dumps(self)})
+
+    def _run_single_circuit(self, circuit):
+        """Run all the passes on a QuantumCircuit
+
+        Args:
+            circuit (QuantumCircuit): circuit to transform via all the registered passes
+
+        Returns:
+            QuantumCircuit: Transformed circuit.
+        """
+        running_passmanager = self._create_running_passmanager()
         result = running_passmanager.run(circuit)
         self.property_set = running_passmanager.property_set
         return result
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -33,7 +33,8 @@
     "ply>=3.10",
     "psutil>=5",
     "scipy>=1.0",
-    "sympy>=1.3"
+    "sympy>=1.3",
+    "dill>=0.3",
 ]
 
 # Add Cython extensions here


Test patch:
diff --git a/test/python/transpiler/test_passmanager_run.py b/test/python/transpiler/test_passmanager_run.py
new file mode 100644
--- /dev/null
+++ b/test/python/transpiler/test_passmanager_run.py
@@ -0,0 +1,117 @@
+# -*- coding: utf-8 -*-
+
+# This code is part of Qiskit.
+#
+# (C) Copyright IBM 2017, 2019.
+#
+# This code is licensed under the Apache License, Version 2.0. You may
+# obtain a copy of this license in the LICENSE.txt file in the root directory
+# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
+#
+# Any modifications or derivative works of this code must retain this
+# copyright notice, and modified files need to carry a notice indicating
+# that they have been altered from the originals.
+
+"""Tests PassManager.run()"""
+
+from qiskit import QuantumRegister, QuantumCircuit
+from qiskit.extensions.standard import CnotGate
+from qiskit.transpiler.preset_passmanagers import level_1_pass_manager
+from qiskit.test import QiskitTestCase
+from qiskit.test.mock import FakeMelbourne
+from qiskit.transpiler import Layout, CouplingMap
+from qiskit.transpiler.transpile_config import TranspileConfig
+
+
+class TestPassManagerRun(QiskitTestCase):
+    """Test default_pass_manager.run(circuit(s))."""
+
+    def test_default_pass_manager_single(self):
+        """Test default_pass_manager.run(circuit).
+
+        circuit:
+        qr0:-[H]--.------------  -> 1
+                  |
+        qr1:-----(+)--.--------  -> 2
+                      |
+        qr2:---------(+)--.----  -> 3
+                          |
+        qr3:-------------(+)---  -> 5
+
+        device:
+        0  -  1  -  2  -  3  -  4  -  5  -  6
+
+              |     |     |     |     |     |
+
+              13 -  12  - 11 -  10 -  9  -  8  -   7
+        """
+        qr = QuantumRegister(4, 'qr')
+        circuit = QuantumCircuit(qr)
+        circuit.h(qr[0])
+        circuit.cx(qr[0], qr[1])
+        circuit.cx(qr[1], qr[2])
+        circuit.cx(qr[2], qr[3])
+
+        coupling_map = FakeMelbourne().configuration().coupling_map
+        basis_gates = FakeMelbourne().configuration().basis_gates
+        initial_layout = [None, qr[0], qr[1], qr[2], None, qr[3]]
+
+        pass_manager = level_1_pass_manager(TranspileConfig(
+            basis_gates=basis_gates,
+            coupling_map=CouplingMap(coupling_map),
+            initial_layout=Layout.from_qubit_list(initial_layout),
+            seed_transpiler=42,
+            optimization_level=1))
+        new_circuit = pass_manager.run(circuit)
+
+        for gate, qargs, _ in new_circuit.data:
+            if isinstance(gate, CnotGate):
+                self.assertIn([x.index for x in qargs], coupling_map)
+
+    def test_default_pass_manager_two(self):
+        """Test default_pass_manager.run(circuitS).
+
+        circuit1 and circuit2:
+        qr0:-[H]--.------------  -> 1
+                  |
+        qr1:-----(+)--.--------  -> 2
+                      |
+        qr2:---------(+)--.----  -> 3
+                          |
+        qr3:-------------(+)---  -> 5
+
+        device:
+        0  -  1  -  2  -  3  -  4  -  5  -  6
+
+              |     |     |     |     |     |
+
+              13 -  12  - 11 -  10 -  9  -  8  -   7
+        """
+        qr = QuantumRegister(4, 'qr')
+        circuit1 = QuantumCircuit(qr)
+        circuit1.h(qr[0])
+        circuit1.cx(qr[0], qr[1])
+        circuit1.cx(qr[1], qr[2])
+        circuit1.cx(qr[2], qr[3])
+
+        circuit2 = QuantumCircuit(qr)
+        circuit2.cx(qr[1], qr[2])
+        circuit2.cx(qr[0], qr[1])
+        circuit2.cx(qr[2], qr[3])
+
+        coupling_map = FakeMelbourne().configuration().coupling_map
+        basis_gates = FakeMelbourne().configuration().basis_gates
+        initial_layout = [None, qr[0], qr[1], qr[2], None, qr[3]]
+
+        pass_manager = level_1_pass_manager(TranspileConfig(
+            basis_gates=basis_gates,
+            coupling_map=CouplingMap(coupling_map),
+            initial_layout=Layout.from_qubit_list(initial_layout),
+            seed_transpiler=42,
+            optimization_level=1))
+        new_circuits = pass_manager.run([circuit1, circuit2])
+
+        for new_circuit in new_circuits:
+            for gate, qargs, _ in new_circuit.data:
+                if isinstance(gate, CnotGate):
+                    self.assertIn([x.index for x in qargs], coupling_map)