Repository: Qiskit/qiskit

Issue:
Transpiler translates CX gate which is already in the target basis - resulting in high gate count
<!-- ⚠️ If you do not respect this template, your issue will be closed -->
<!-- ⚠️ Make sure to browse the opened and closed issues -->

### Information

- **Qiskit Terra 0.16.4**:
- **Python 3.8.5**:
- **OS Ubuntu 20.04**:

### What is the current behavior?
In some cases, the transpiler translates CX gate which is in the supplied target basis `['id', 'rz', 'sx', 'x', 'cx']` using two `iSWAP` gates. Then, the iSWAPs are replaced again using 2 CX gates leading to one CX being translated into multiple single-qubit and 4 CX gates. This results in a high number of unnecessary CX gates in the transpiled circuit. For example, a SWAP includes 12 CX gates instead of only 3 due to this translation. 

### Steps to reproduce the problem
I have attached an example QASM file ([sample.txt](https://github.com/Qiskit/qiskit-terra/files/6206858/sample.txt)) which is showing this behavior. I have also included a `transpile.log` for further investigation if needed. For example, at Line # 740 of the [transpile.log](https://github.com/Qiskit/qiskit-terra/files/6206860/transpile.log), you can see how the CX gate is translated, and at Line # 1565 you can find the SWAP translation to 12 CX gates. An MWE to reproduce the problem is below:

```
import logging
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.compiler import transpile
from qiskit.test.mock import FakeAthens

logging.basicConfig(
    filename='transpile.log',
    filemode='w',
    format='%(asctime)s,%(msecs)d %(name)s %(levelname)s %(message)s',
    datefmt='%H:%M:%S',
    level=logging.DEBUG
)

circ = QuantumCircuit()
circ = circ.from_qasm_file("sample.txt")

circ_transpiled = transpile(
    circ,
    backend=FakeAthens(),
    basis_gates=['id', 'rz', 'sx', 'x', 'cx'],
    routing_method='sabre'
)
```

### What is the expected behavior?
The gates that are already in the `target basis` should not be translated in the `basis_translator.py`.


### Suggested solutions
Although a more scientific solution would be identifying why a gate in the target basis is getting translated, I can suggest 3 stop-gap solutions that will check if the gate is already in the target basis and will simply ignore the gate.

#### Solution # 1
Add a check here (https://github.com/Qiskit/qiskit-terra/blob/0950594c8d3e6aed637a47255a8a429b64c69874/qiskit/transpiler/passes/basis/basis_translator.py#L255) as following. This will skip finding equivalence for gates that are already in the target basis.
```
for gate_name, gate_num_qubits in current_basis:
        if gate_name in target_basis: # new-line
            continue # new-line
        equivs = equiv_lib._get_equivalences((gate_name, gate_num_qubits))
```

#### Solution # 2
Remove translation of gates that are already in the target basis from the return here https://github.com/Qiskit/qiskit-terra/blob/0950594c8d3e6aed637a47255a8a429b64c69874/qiskit/transpiler/passes/basis/basis_translator.py#L247
```
for idx, (gate_name, gate_num_qubits, params, equiv) in enumerate(rtn):
    if gate_name in target_basis:
        del rtn[idx]
    else:
        logger.debug('%s/%s => %s\n%s', gate_name, gate_num_qubits, params, equiv)
return rtn
```

#### Solution # 3
Add a check in the `_compose_transforms` method here https://github.com/Qiskit/qiskit-terra/blob/0950594c8d3e6aed637a47255a8a429b64c69874/qiskit/transpiler/passes/basis/basis_translator.py#L339
+ add `target_basis` as an argument in the `_compose_transforms`.
```
for node in doomed_nodes:
    if node.op.name in target_basis:
        continue
```



Discussion:
Thanks for investigating this @ashsaki ! Agree this is a bug, and your proposed Solution #1 seems like the best fix. If a gate is already in the basis, there's no need to consider it as a possible translation step (this should speed up the search somewhat as well).
@kdk @ashsaki Is anybody working on this?
> @kdk @ashsaki Is anybody working on this?

I am not working on this. I can fork and create a pull request with the proposed solution - 1. 
Sounds good. I ran some simple benchmarks on my local system. 
- Over multiple runs, I got an average depth of 613 and an average time of 24s using main. Making your solution-1 above I got an average depth of 136 in a time of 8s. That's a pretty significant improvement.
- I also remembered seeing #6122. I ran that circuit and though the output varies, I found that without the change, the transpiler found the shortest circuit of depth 4, 20% of the time in 80s. With the change it found it 33% of the time in 36s. Again a good improvement.
- In addition I ran the CI transpiler auto-tests and they passed with the change. Interestingly there was no difference in execution time with or without the change, which probably means there are no tests currently that test the problem above. I think there ought to be a couple of tests added, perhaps your circuit above and the one from #6122, modified to work in the CI environment.
Is there any update on this? I was hoping to get this bugfix backported and included in the pending 0.17.2 bugfix release (which will be released today or tomorrow, which would require a PR opened ASAP)

Resolving patch:
diff --git a/qiskit/transpiler/passes/basis/basis_translator.py b/qiskit/transpiler/passes/basis/basis_translator.py
--- a/qiskit/transpiler/passes/basis/basis_translator.py
+++ b/qiskit/transpiler/passes/basis/basis_translator.py
@@ -269,6 +269,9 @@ def _basis_search(equiv_lib, source_basis, target_basis, heuristic):
         closed_set.add(current_basis)
 
         for gate_name, gate_num_qubits in current_basis:
+            if gate_name in target_basis:
+                continue
+
             equivs = equiv_lib._get_equivalences((gate_name, gate_num_qubits))
 
             basis_remain = current_basis - {(gate_name, gate_num_qubits)}


Test patch: