Repository: Qiskit/qiskit

Issue:
Ability to remove passes from PassManager 
### What is the expected behavior?

We would like to be able to remove passes from a `PassManager`, analogous to how one can append passes.

For instance, suppose you want to use `optimization_level=1`, but don't want to use the pass `RemoveResetInZeroState`. 

You get the passes from level 1 with
```
from qiskit.transpiler.passmanager_config import PassManagerConfig
from qiskit.transpiler import PassManager
from qiskit.transpiler.preset_passmanagers import level_1_pass_manager
pm = level_1_pass_manager(PassManagerConfig())
```

I would like, now to be able to do something like
```
from qiskit.transpiler.passes import RemoveResetInZeroState
pm.remove(RemoveResetInZeroState())
```


Discussion:
@1ucian0 see here.
A workaround
```
from qiskit.transpiler.passmanager_config import PassManagerConfig
from qiskit.transpiler.preset_passmanagers import level_1_pass_manager
pm = level_1_pass_manager(PassManagerConfig())
pm.draw()
```
![antes](https://user-images.githubusercontent.com/766693/92146128-42abb900-ede7-11ea-9d99-66a4c7be4ea6.png)

Check the index of the pass to remove, 1 in this case:
```
pm.replace(1,[])
pm.draw()
``` 
![despues](https://user-images.githubusercontent.com/766693/92146143-47706d00-ede7-11ea-82a1-13acd6f8a34f.png)


Resolving patch:
diff --git a/qiskit/transpiler/passmanager.py b/qiskit/transpiler/passmanager.py
--- a/qiskit/transpiler/passmanager.py
+++ b/qiskit/transpiler/passmanager.py
@@ -109,7 +109,7 @@ def replace(
             flow_controller_conditions: control flow plugins.
 
         Raises:
-            TranspilerError: if a pass in passes is not a proper pass.
+            TranspilerError: if a pass in passes is not a proper pass or index not found.
 
         See Also:
             ``RunningPassManager.add_flow_controller()`` for more information about the control
@@ -127,6 +127,20 @@ def replace(
         except IndexError:
             raise TranspilerError('Index to replace %s does not exists' % index)
 
+    def remove(self, index: int) -> None:
+        """Removes a particular pass in the scheduler.
+
+        Args:
+            index: Pass index to replace, based on the position in passes().
+
+        Raises:
+            TranspilerError: if the index is not found.
+        """
+        try:
+            del self._pass_sets[index]
+        except IndexError:
+            raise TranspilerError('Index to replace %s does not exists' % index)
+
     def __setitem__(self, index, item):
         self.replace(index, item)
 
@@ -161,7 +175,6 @@ def __add__(self, other):
     def _normalize_passes(passes: Union[BasePass, List[BasePass]]) -> List[BasePass]:
         if isinstance(passes, BasePass):
             passes = [passes]
-
         for pass_ in passes:
             if not isinstance(pass_, BasePass):
                 raise TranspilerError('%s is not a pass instance' % pass_.__class__)


Test patch:
diff --git a/test/python/transpiler/test_pass_scheduler.py b/test/python/transpiler/test_pass_scheduler.py
--- a/test/python/transpiler/test_pass_scheduler.py
+++ b/test/python/transpiler/test_pass_scheduler.py
@@ -695,8 +695,8 @@ def test_fixed_point_twice(self):
         self.assertScheduler(self.circuit, self.passmanager, expected)
 
 
-class TestPassManagerReplace(SchedulerTestCase):
-    """Test PassManager.replace"""
+class TestPassManagerChanges(SchedulerTestCase):
+    """Test PassManager manipulation with changes"""
 
     def setUp(self):
         self.passmanager = PassManager()
@@ -724,6 +724,38 @@ def test_replace1(self):
                     'run transformation pass PassC_TP_RA_PA']
         self.assertScheduler(self.circuit, self.passmanager, expected)
 
+    def test_remove0(self):
+        """ Test passmanager.remove(0)."""
+        self.passmanager.append(PassC_TP_RA_PA())  # Request: PassA / Preserves: PassA
+        self.passmanager.append(PassB_TP_RA_PA())  # Request: PassA / Preserves: PassA
+
+        self.passmanager.remove(0)
+
+        expected = ['run transformation pass PassA_TP_NR_NP',
+                    'run transformation pass PassB_TP_RA_PA']
+        self.assertScheduler(self.circuit, self.passmanager, expected)
+
+    def test_remove1(self):
+        """ Test passmanager.remove(1)."""
+        self.passmanager.append(PassC_TP_RA_PA())  # Request: PassA / Preserves: PassA
+        self.passmanager.append(PassB_TP_RA_PA())  # Request: PassA / Preserves: PassA
+
+        self.passmanager.remove(1)
+
+        expected = ['run transformation pass PassA_TP_NR_NP',
+                    'run transformation pass PassC_TP_RA_PA']
+        self.assertScheduler(self.circuit, self.passmanager, expected)
+
+    def test_remove_minus_1(self):
+        """ Test passmanager.remove(-1)."""
+        self.passmanager.append(PassA_TP_NR_NP())
+        self.passmanager.append(PassB_TP_RA_PA())  # Request: PassA / Preserves: PassA
+
+        self.passmanager.remove(-1)
+
+        expected = ['run transformation pass PassA_TP_NR_NP']
+        self.assertScheduler(self.circuit, self.passmanager, expected)
+
     def test_setitem(self):
         """ Test passmanager[1] = ..."""
         self.passmanager.append(PassC_TP_RA_PA())  # Request: PassA / Preserves: PassA