Repository: Qiskit/qiskit

Issue:
Cannot compose circuits with different numbers of measurements
<!-- ⚠️ 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**: 0.17.4
- **Python version**:
- **Operating system**:

### What is the current behavior?
Compose fails when combining circuits with no measurements together with those that do, e.g.

```python
ansatz = TwoLocal(2, rotation_blocks='ry',
                  entanglement_blocks='cx')  

qc = QuantumCircuit(2)
qc.measure_all()

ansatz.compose(qc)
```

gives:

CircuitError: "Trying to compose with another QuantumCircuit which has more 'in' edges."

while `+` works, but is deprecated in favor of `compose`.



### Steps to reproduce the problem



### What is the expected behavior?



### Suggested solutions





Discussion:
I believe this behavior is by design, though I agree the error message could be more helpful in leading users to the correct behavior. `compose` requires `self` to be wider than `other` (so that the `qubits` and `clbits` arguments can always unambiguously index onto the bits in `self`), so in this case, the call would need to be `qc.compose(ansatz, front=True)`.
Ok, it makes sense although a bit confusing.  Namely, I cannot add a measurement circuit onto an ansatz, but rather I must append the needed measurement rotation gates to the ansatz itself before adding the measurements to it.  It would be nice if this could work if `self` has no cregs given that there is no ambiguity in that case and it is a common situation to be in.
I agree with Paul. Adding a measurement circuit onto the end of a non-measurement circuit is something I do quite often.

For my own purposes, I just construct the non-measurement circuit with a classical register so that it works. But when writing educational materials, it wouldn't be great to say "here we put in a classical register just so Qiskit doesn't complain".
Yeah, I do not see any reason why this cannot be done, and it seems like a common situation to be in. I will do a PR for it. 

Resolving patch:
diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py
--- a/qiskit/circuit/quantumcircuit.py
+++ b/qiskit/circuit/quantumcircuit.py
@@ -874,6 +874,14 @@ def compose(
         else:
             dest = self.copy()
 
+        # If self does not have any cregs but other does then we allow
+        # that and add the registers to the output dest
+        if isinstance(other, QuantumCircuit):
+            if not self.clbits and other.clbits:
+                dest.add_bits(other.clbits)
+                for reg in other.cregs:
+                    dest.add_register(reg)
+
         if wrap:
             try:
                 other = other.to_gate()
@@ -898,15 +906,14 @@ def compose(
 
         instrs = other.data
 
-        if other.num_qubits > self.num_qubits or other.num_clbits > self.num_clbits:
+        if other.num_qubits > dest.num_qubits or other.num_clbits > dest.num_clbits:
             raise CircuitError(
                 "Trying to compose with another QuantumCircuit which has more 'in' edges."
             )
 
         # number of qubits and clbits must match number in circuit or None
-        identity_qubit_map = dict(zip(other.qubits, self.qubits))
-        identity_clbit_map = dict(zip(other.clbits, self.clbits))
-
+        identity_qubit_map = dict(zip(other.qubits, dest.qubits))
+        identity_clbit_map = dict(zip(other.clbits, dest.clbits))
         if qubits is None:
             qubit_map = identity_qubit_map
         elif len(qubits) != len(other.qubits):


Test patch:
diff --git a/test/python/circuit/test_compose.py b/test/python/circuit/test_compose.py
--- a/test/python/circuit/test_compose.py
+++ b/test/python/circuit/test_compose.py
@@ -23,11 +23,12 @@
     ClassicalRegister,
     Clbit,
     QuantumCircuit,
+    Qubit,
     Parameter,
     Gate,
     Instruction,
 )
-from qiskit.circuit.library import HGate, RZGate, CXGate, CCXGate
+from qiskit.circuit.library import HGate, RZGate, CXGate, CCXGate, TwoLocal
 from qiskit.test import QiskitTestCase
 
 
@@ -651,6 +652,46 @@ def test_condition_mapping_whileloopop(self):
         self.assertIs(reg_instruction.condition[0], test_creg)
         self.assertEqual(reg_instruction.condition, (test_creg, 3))
 
+    def test_compose_no_clbits_in_one(self):
+        """Test combining a circuit with cregs to one without"""
+        ansatz = TwoLocal(2, rotation_blocks="ry", entanglement_blocks="cx")
+
+        qc = QuantumCircuit(2)
+        qc.measure_all()
+        out = ansatz.compose(qc)
+        self.assertEqual(out.clbits, qc.clbits)
+
+    def test_compose_no_clbits_in_one_inplace(self):
+        """Test combining a circuit with cregs to one without inplace"""
+        ansatz = TwoLocal(2, rotation_blocks="ry", entanglement_blocks="cx")
+
+        qc = QuantumCircuit(2)
+        qc.measure_all()
+        ansatz.compose(qc, inplace=True)
+        self.assertEqual(ansatz.clbits, qc.clbits)
+
+    def test_compose_no_clbits_in_one_multireg(self):
+        """Test combining a circuit with cregs to one without, multi cregs"""
+        ansatz = TwoLocal(2, rotation_blocks="ry", entanglement_blocks="cx")
+
+        qa = QuantumRegister(2, "q")
+        ca = ClassicalRegister(2, "a")
+        cb = ClassicalRegister(2, "b")
+        qc = QuantumCircuit(qa, ca, cb)
+        qc.measure(0, cb[1])
+        out = ansatz.compose(qc)
+        self.assertEqual(out.clbits, qc.clbits)
+        self.assertEqual(out.cregs, qc.cregs)
+
+    def test_compose_noclbits_registerless(self):
+        """Combining a circuit with cregs to one without, registerless case"""
+        inner = QuantumCircuit([Qubit(), Qubit()], [Clbit(), Clbit()])
+        inner.measure([0, 1], [0, 1])
+        outer = QuantumCircuit(2)
+        outer.compose(inner, inplace=True)
+        self.assertEqual(outer.clbits, inner.clbits)
+        self.assertEqual(outer.cregs, [])
+
 
 if __name__ == "__main__":
     unittest.main()