Repository: Qiskit/qiskit

Issue:
Cannot transpile custom pulse gate over 5 qubits
<!-- ⚠️ If you do not respect this template, your issue will be closed -->
<!-- ⚠️ Make sure to browse the opened and closed issues -->

### Information

- **Qiskit Terra version**: latest 
- **Python version**:
- **Operating system**:

### What is the current behavior?
```python

from qiskit import *
from qiskit.circuit import Gate
from qiskit import pulse
from qiskit.pulse.library import Gaussian

circ = QuantumCircuit(5)
custom_gate = Gate('my_custom_gate', 5, [])
circ.append(custom_gate, [0,1,2,3,4])
circ.measure_all()

with pulse.build(backend, name='custom') as my_schedule:
    pulse.play(Gaussian(duration=128, amp=0.1, sigma=16), pulse.drive_channel(0))
    pulse.play(Gaussian(duration=128, amp=0.1, sigma=16), pulse.drive_channel(1))
    pulse.play(Gaussian(duration=128, amp=0.1, sigma=16), pulse.drive_channel(2))
    pulse.play(Gaussian(duration=128, amp=0.1, sigma=16), pulse.drive_channel(3))
    pulse.play(Gaussian(duration=128, amp=0.1, sigma=16), pulse.drive_channel(4))
    pulse.play(Gaussian(duration=128, amp=0.1, sigma=16), pulse.ControlChannel(1))
    pulse.play(Gaussian(duration=128, amp=0.1, sigma=16), pulse.ControlChannel(2))
    pulse.play(Gaussian(duration=128, amp=0.1, sigma=16), pulse.ControlChannel(3))
    pulse.play(Gaussian(duration=128, amp=0.1, sigma=16), pulse.ControlChannel(4))

circ.add_calibration('my_custom_gate', [0,1,2,3,4], my_schedule, [])

trans_circ = transpile(circ, backend)
```

gives:

```python

AttributeError: 'NoneType' object has no attribute 'data'
```

The docs say it should do this if a calibration is not provided:

> Normally, if we tried to transpile our circ, we would get an error. There was no functional definition provided for "my_custom_gate", so the transpiler can’t unroll it to the basis gate set of the target device. We can show this by trying to add "my_custom_gate" to another qubit which hasn’t been calibrated.

But here I have explicitly done so.

### Steps to reproduce the problem



### What is the expected behavior?



### Suggested solutions





Discussion:
`add_calibration` says that it takes a tuple. What happens when you change that line to:
```python
circ.add_calibration('my_custom_gate', (0,1,2,3,4), my_schedule, [])
```
?
The error still persists.  Also note that the tutorial uses lists:

https://qiskit.org/documentation/tutorials/circuits_advanced/05_pulse_gates.html
I already see this problem when reducing it to 3 qubits rather than 5.
Is there any more of the traceback available?
ger.py", line 165, in _run_this_pass
    new_dag = pass_.run(dag)
  File "/opt/conda/lib/python3.8/site-packages/qiskit/transpiler/passes/basis/unroll_3q_or_more.py", line 35, in run
    rule = node.op.definition.data
AttributeError: 'NoneType' object has no attribute 'data'
The `unroll_custom` file has:

```
if dag.has_calibration_for(node):
                continue
```

which is missing in the 3Q unroller.  
Likewise for `CheckMap`.
Is anyone working on this?

Resolving patch:
diff --git a/qiskit/transpiler/passes/basis/unroll_3q_or_more.py b/qiskit/transpiler/passes/basis/unroll_3q_or_more.py
--- a/qiskit/transpiler/passes/basis/unroll_3q_or_more.py
+++ b/qiskit/transpiler/passes/basis/unroll_3q_or_more.py
@@ -31,6 +31,8 @@ def run(self, dag):
             QiskitError: if a 3q+ gate is not decomposable
         """
         for node in dag.multi_qubit_ops():
+            if dag.has_calibration_for(node):
+                continue
             # TODO: allow choosing other possible decompositions
             rule = node.op.definition.data
             if not rule:
diff --git a/qiskit/transpiler/passes/utils/check_map.py b/qiskit/transpiler/passes/utils/check_map.py
--- a/qiskit/transpiler/passes/utils/check_map.py
+++ b/qiskit/transpiler/passes/utils/check_map.py
@@ -49,6 +49,8 @@ def run(self, dag):
         qubit_indices = {bit: index for index, bit in enumerate(dag.qubits)}
 
         for gate in dag.two_qubit_ops():
+            if dag.has_calibration_for(gate):
+                continue
             physical_q0 = qubit_indices[gate.qargs[0]]
             physical_q1 = qubit_indices[gate.qargs[1]]
 


Test patch:
diff --git a/test/python/compiler/test_transpiler.py b/test/python/compiler/test_transpiler.py
--- a/test/python/compiler/test_transpiler.py
+++ b/test/python/compiler/test_transpiler.py
@@ -1122,6 +1122,49 @@ def test_inst_durations_from_calibrations(self):
         out = transpile(qc, scheduling_method="alap")
         self.assertEqual(out.duration, cal.duration)
 
+    @data(0, 1, 2, 3)
+    def test_multiqubit_gates_calibrations(self, opt_level):
+        """Test multiqubit gate > 2q with calibrations works
+
+        Adapted from issue description in https://github.com/Qiskit/qiskit-terra/issues/6572
+        """
+        circ = QuantumCircuit(5)
+        custom_gate = Gate("my_custom_gate", 5, [])
+        circ.append(custom_gate, [0, 1, 2, 3, 4])
+        circ.measure_all()
+        backend = FakeAlmaden()
+        with pulse.build(backend, name="custom") as my_schedule:
+            pulse.play(
+                pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.drive_channel(0)
+            )
+            pulse.play(
+                pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.drive_channel(1)
+            )
+            pulse.play(
+                pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.drive_channel(2)
+            )
+            pulse.play(
+                pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.drive_channel(3)
+            )
+            pulse.play(
+                pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.drive_channel(4)
+            )
+            pulse.play(
+                pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.ControlChannel(1)
+            )
+            pulse.play(
+                pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.ControlChannel(2)
+            )
+            pulse.play(
+                pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.ControlChannel(3)
+            )
+            pulse.play(
+                pulse.library.Gaussian(duration=128, amp=0.1, sigma=16), pulse.ControlChannel(4)
+            )
+        circ.add_calibration("my_custom_gate", [0, 1, 2, 3, 4], my_schedule, [])
+        trans_circ = transpile(circ, backend, optimization_level=opt_level)
+        self.assertEqual({"measure": 5, "my_custom_gate": 1, "barrier": 1}, trans_circ.count_ops())
+
     @data(0, 1, 2, 3)
     def test_circuit_with_delay(self, optimization_level):
         """Verify a circuit with delay can transpile to a scheduled circuit."""