Repository: Qiskit/qiskit

Issue:
Error in computing number of connected components using qc.num_connected_components()
<!-- ⚠️ 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.18.0.dev0+27e96cb
- **Python version**: 3.7

### What is the current behavior?

When we try to use `qc.num_connected_components()` on a circuit involving `c_if()`, in some cases, the function outputs `0` as the number of connected components. However, this is not possible since there has to be at least one component, the whole circuit itself.

### Steps to reproduce the problem

The error comes up when the circuit involves two or more gates with `c_if()`. For instance the following code gives an output `0` which is incorrect

```python
q = QuantumRegister(2)
c = ClassicalRegister(2)
qc = QuantumCircuit(q,c)
qc.h(0).c_if(c,0)
qc.h(1).c_if(c,1)
qc.num_connected_components()
```

while for the circuit in the code below the function outputs `2` which is correct.

```python
q = QuantumRegister(2)
c = ClassicalRegister(2)
qc = QuantumCircuit(q,c)
qc.h(0).c_if(c,0)
qc.h(1)
qc.num_connected_components()
```

The function seems to have passed the test because there is just a single test in which the test circuit contains just a single gate that is classical conditioned while the error shows up in circuits with more than one classically conditioned gates.





Discussion:

Resolving patch:
diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py
--- a/qiskit/circuit/quantumcircuit.py
+++ b/qiskit/circuit/quantumcircuit.py
@@ -1839,7 +1839,6 @@ def num_connected_components(self, unitary_only=False):
                         for k in range(num_sub_graphs):
                             if idx in sub_graphs[k]:
                                 graphs_touched.append(k)
-                                num_touched += 1
                                 break
 
                 for item in args:
@@ -1848,9 +1847,11 @@ def num_connected_components(self, unitary_only=False):
                         if reg_int in sub_graphs[k]:
                             if k not in graphs_touched:
                                 graphs_touched.append(k)
-                                num_touched += 1
                                 break
 
+                graphs_touched = list(set(graphs_touched))
+                num_touched = len(graphs_touched)
+
                 # If the gate touches more than one subgraph
                 # join those graphs together and return
                 # reduced number of subgraphs


Test patch:
diff --git a/test/python/circuit/test_circuit_properties.py b/test/python/circuit/test_circuit_properties.py
--- a/test/python/circuit/test_circuit_properties.py
+++ b/test/python/circuit/test_circuit_properties.py
@@ -542,7 +542,7 @@ def test_circuit_connected_components_with_clbits(self):
         self.assertEqual(qc.num_connected_components(), 4)
 
     def test_circuit_connected_components_with_cond(self):
-        """Test tensor components with conditional gate."""
+        """Test tensor components with one conditional gate."""
         size = 4
         q = QuantumRegister(size, "q")
         c = ClassicalRegister(size, "c")
@@ -558,6 +558,37 @@ def test_circuit_connected_components_with_cond(self):
         qc.measure(q[3], c[3])
         self.assertEqual(qc.num_connected_components(), 1)
 
+    def test_circuit_connected_components_with_cond2(self):
+        """Test tensor components with two conditional gates."""
+        size = 4
+        q = QuantumRegister(size, "q")
+        c = ClassicalRegister(2 * size, "c")
+        qc = QuantumCircuit(q, c)
+        qc.h(q[0])
+        qc.h(q[1])
+        qc.h(q[2])
+        qc.h(q[3])
+        qc.h(0).c_if(c, 0)
+        qc.cx(1, 2).c_if(c, 4)
+        self.assertEqual(qc.num_connected_components(), 2)
+
+    def test_circuit_connected_components_with_cond3(self):
+        """Test tensor components with three conditional gates and measurements."""
+        size = 4
+        q = QuantumRegister(size)
+        c = ClassicalRegister(size)
+        qc = QuantumCircuit(q, c)
+        qc.h(q[0])
+        qc.h(q[1])
+        qc.h(q[2])
+        qc.h(q[3])
+        qc.measure(q[0], c[0])
+        qc.h(q[0]).c_if(c, 0)
+        qc.cx(q[1], q[2]).c_if(c, 1)
+        qc.measure(q[2], c[2])
+        qc.x(q[3]).c_if(c, 2)
+        self.assertEqual(qc.num_connected_components(), 1)
+
     def test_circuit_unitary_factors1(self):
         """Test unitary factors empty circuit."""
         size = 4