Repository: Qiskit/qiskit

Issue:
Circuit drawers do not respect classical conditional ordering
<!-- ⚠️ 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.16.0
- **Python version**:
- **Operating system**:

### What is the current behavior?
Having gates conditioned on measurements performed earlier are moved before the measurements in the circuit drawing

eg

```
qr = QuantumRegister(3)
cr = ClassicalRegister(2)
qc = QuantumCircuit(qr,cr)
qc.reset(range(3))
qc.h(1)
qc.cx([1,0],[2,1])
qc.h(0)
qc.measure([0,1], [0,1])
qc.z(2).c_if(cr, 1)
qc.x(2).c_if(cr, 2)
```
```
                            ┌───┐┌─┐       
q6_0: ─|0>──────────────■───┤ H ├┤M├───────
           ┌───┐      ┌─┴─┐ └┬─┬┘└╥┘       
q6_1: ─|0>─┤ H ├──■───┤ X ├──┤M├──╫────────
           └───┘┌─┴─┐ ├───┤  └╥┘  ║  ┌───┐ 
q6_2: ─|0>──────┤ X ├─┤ Z ├───╫───╫──┤ X ├─
                └───┘ └─┬─┘   ║   ║  └─┬─┘ 
                     ┌──┴──┐  ║   ║ ┌──┴──┐
c9: 2/═══════════════╡ = 1 ╞══╩═══╩═╡ = 2 ╞
                     └─────┘  1   0 └─────┘

```

<img width="467" alt="Screen Shot 2020-11-11 at 19 14 01" src="https://user-images.githubusercontent.com/1249193/98878880-1305d680-2452-11eb-9d5e-2c2900babe1e.png">



### Steps to reproduce the problem



### What is the expected behavior?



### Suggested solutions





Discussion:
This is interesting. I believe the problem is in `_get_layered_instructions` which builds the list of layers for the drawers to use. There are apparently several problems here. Using simplified circuits, I get these different results. So I'm working on it.
![image](https://user-images.githubusercontent.com/16268251/98965695-33b84580-24bf-11eb-9eaa-13bc1c62815f.png)
![image](https://user-images.githubusercontent.com/16268251/98966034-9f9aae00-24bf-11eb-9a70-f71ee0785a1d.png)
![image](https://user-images.githubusercontent.com/16268251/98965827-5ba7a900-24bf-11eb-9a03-1b24b0b6e5bc.png)


Resolving patch:
diff --git a/qiskit/visualization/utils.py b/qiskit/visualization/utils.py
--- a/qiskit/visualization/utils.py
+++ b/qiskit/visualization/utils.py
@@ -15,12 +15,14 @@
 """Common visualization utilities."""
 
 import re
+from collections import OrderedDict
 
 import numpy as np
 from qiskit.converters import circuit_to_dag
 from qiskit.quantum_info.states import DensityMatrix
 from qiskit.quantum_info.operators import PauliTable, SparsePauliOp
 from qiskit.visualization.exceptions import VisualizationError
+from qiskit.circuit import Measure
 
 try:
     import PIL
@@ -99,16 +101,21 @@ def _get_layered_instructions(circuit, reverse_bits=False,
     justify = justify if justify in ('right', 'none') else 'left'
 
     dag = circuit_to_dag(circuit)
+
     ops = []
     qregs = dag.qubits
     cregs = dag.clbits
 
+    # Create a mapping of each register to the max layer number for all measure ops
+    # with that register as the target. Then when a node with condition is seen,
+    # it will be placed to the right of the measure op if the register matches.
+    measure_map = OrderedDict([(c, -1) for c in circuit.cregs])
+
     if justify == 'none':
         for node in dag.topological_op_nodes():
             ops.append([node])
-
     else:
-        ops = _LayerSpooler(dag, justify)
+        ops = _LayerSpooler(dag, justify, measure_map)
 
     if reverse_bits:
         qregs.reverse()
@@ -169,24 +176,22 @@ def _any_crossover(qregs, node, nodes):
 class _LayerSpooler(list):
     """Manipulate list of layer dicts for _get_layered_instructions."""
 
-    def __init__(self, dag, justification):
+    def __init__(self, dag, justification, measure_map):
         """Create spool"""
         super().__init__()
         self.dag = dag
         self.qregs = dag.qubits
         self.justification = justification
+        self.measure_map = measure_map
 
         if self.justification == 'left':
-
             for dag_layer in dag.layers():
                 current_index = len(self) - 1
                 dag_nodes = _sorted_nodes(dag_layer)
                 for node in dag_nodes:
                     self.add(node, current_index)
-
         else:
             dag_layers = []
-
             for dag_layer in dag.layers():
                 dag_layers.append(dag_layer)
 
@@ -213,32 +218,36 @@ def insertable(self, node, nodes):
 
     def slide_from_left(self, node, index):
         """Insert node into first layer where there is no conflict going l > r"""
+        measure_layer = None
+        if isinstance(node.op, Measure):
+            measure_reg = node.cargs[0].register
+
         if not self:
-            self.append([node])
             inserted = True
-
+            self.append([node])
         else:
             inserted = False
             curr_index = index
-            last_insertable_index = None
-
-            while curr_index > -1:
+            index_stop = -1 if not node.condition else self.measure_map[node.condition[0]]
+            last_insertable_index = -1
+            while curr_index > index_stop:
                 if self.is_found_in(node, self[curr_index]):
                     break
                 if self.insertable(node, self[curr_index]):
                     last_insertable_index = curr_index
                 curr_index = curr_index - 1
 
-            if last_insertable_index:
-                self[last_insertable_index].append(node)
+            if last_insertable_index >= 0:
                 inserted = True
-
+                self[last_insertable_index].append(node)
+                measure_layer = last_insertable_index
             else:
                 inserted = False
                 curr_index = index
                 while curr_index < len(self):
                     if self.insertable(node, self[curr_index]):
                         self[curr_index].append(node)
+                        measure_layer = curr_index
                         inserted = True
                         break
                     curr_index = curr_index + 1
@@ -246,12 +255,17 @@ def slide_from_left(self, node, index):
         if not inserted:
             self.append([node])
 
+        if isinstance(node.op, Measure):
+            if not measure_layer:
+                measure_layer = len(self) - 1
+            if measure_layer > self.measure_map[measure_reg]:
+                self.measure_map[measure_reg] = measure_layer
+
     def slide_from_right(self, node, index):
         """Insert node into rightmost layer as long there is no conflict."""
         if not self:
             self.insert(0, [node])
             inserted = True
-
         else:
             inserted = False
             curr_index = index
@@ -267,7 +281,6 @@ def slide_from_right(self, node, index):
             if last_insertable_index:
                 self[last_insertable_index].append(node)
                 inserted = True
-
             else:
                 curr_index = index
                 while curr_index > -1:


Test patch:
diff --git a/test/ipynb/mpl/references/meas_condition.png b/test/ipynb/mpl/references/meas_condition.png
new file mode 100644
Binary files /dev/null and b/test/ipynb/mpl/references/meas_condition.png differ
diff --git a/test/ipynb/mpl/test_circuit_matplotlib_drawer.py b/test/ipynb/mpl/test_circuit_matplotlib_drawer.py
--- a/test/ipynb/mpl/test_circuit_matplotlib_drawer.py
+++ b/test/ipynb/mpl/test_circuit_matplotlib_drawer.py
@@ -471,6 +471,17 @@ def test_subfont_change(self):
         self.circuit_drawer(circuit, style={'name': 'iqx', 'subfontsize': 11},
                             filename='subfont.png')
 
+    def test_meas_condition(self):
+        """Tests measure with a condition"""
+
+        qr = QuantumRegister(2, 'qr')
+        cr = ClassicalRegister(2, 'cr')
+        circuit = QuantumCircuit(qr, cr)
+        circuit.h(qr[0])
+        circuit.measure(qr[0], cr[0])
+        circuit.h(qr[1]).c_if(cr, 1)
+        self.circuit_drawer(circuit, filename='meas_condition.png')
+
 
 if __name__ == '__main__':
     unittest.main(verbosity=1)
diff --git a/test/python/visualization/references/test_teleport.tex b/test/python/visualization/references/test_teleport.tex
--- a/test/python/visualization/references/test_teleport.tex
+++ b/test/python/visualization/references/test_teleport.tex
@@ -1,8 +1,8 @@
 % \documentclass[preview]{standalone}
 % If the image is too large to fit on this documentclass use
 \documentclass[draft]{beamer}
-% img_width = 4, img_depth = 10
-\usepackage[size=custom,height=10,width=25,scale=0.7]{beamerposter}
+% img_width = 4, img_depth = 11
+\usepackage[size=custom,height=10,width=27,scale=0.7]{beamerposter}
 % instead and customize the height and width (in cm) to fit.
 % Large images may run out of memory quickly.
 % To fix this use the LuaLaTeX compiler, which dynamically
@@ -16,10 +16,10 @@
 
 \begin{equation*}
     \Qcircuit @C=1.0em @R=0.0em @!R {
-	 	\lstick{ {q}_{0} :  } & \gate{U_3(0.3,0.2,0.1)} & \qw \barrier[0em]{2} & \qw & \ctrl{1} & \gate{H} & \meter & \qw & \qw & \qw & \qw\\
-	 	\lstick{ {q}_{1} :  } & \gate{H} & \ctrl{1} & \qw & \targ & \meter & \qw & \qw & \qw & \qw & \qw\\
-	 	\lstick{ {q}_{2} :  } & \qw & \targ & \qw & \gate{Z} & \qw & \qw & \gate{X} & \meter & \qw & \qw\\
-	 	\lstick{c:} & {/_{_{3}}} \cw & \cw & \cw & \control \cw \cwx[-1] & \dstick{1} \cw \cwx[-2] & \dstick{0} \cw \cwx[-3] & \control \cw \cwx[-1] & \dstick{2} \cw \cwx[-1] & \cw & \cw\\
+	 	\lstick{ {q}_{0} :  } & \gate{U_3(0.3,0.2,0.1)} & \qw \barrier[0em]{2} & \qw & \ctrl{1} & \gate{H} & \meter & \qw & \qw & \qw & \qw & \qw\\
+	 	\lstick{ {q}_{1} :  } & \gate{H} & \ctrl{1} & \qw & \targ & \meter & \qw & \qw & \qw & \qw & \qw & \qw\\
+	 	\lstick{ {q}_{2} :  } & \qw & \targ & \qw & \qw & \qw & \qw & \gate{Z} & \gate{X} & \meter & \qw & \qw\\
+	 	\lstick{c:} & {/_{_{3}}} \cw & \cw & \cw & \cw & \dstick{1} \cw \cwx[-2] & \dstick{0} \cw \cwx[-3] & \control \cw \cwx[-1] & \control \cw \cwx[-1] & \dstick{2} \cw \cwx[-1] & \cw & \cw\\
 	 }
 \end{equation*}
 
diff --git a/test/python/visualization/test_circuit_text_drawer.py b/test/python/visualization/test_circuit_text_drawer.py
--- a/test/python/visualization/test_circuit_text_drawer.py
+++ b/test/python/visualization/test_circuit_text_drawer.py
@@ -1829,6 +1829,27 @@ def test_conditional_multiplexer(self):
 
         self.assertEqual(str(_text_circuit_drawer(qc)), expected)
 
+    def test_text_conditional_measure(self):
+        """Conditional with measure on same clbit"""
+        qr = QuantumRegister(2, 'qr')
+        cr = ClassicalRegister(2, 'cr')
+        circuit = QuantumCircuit(qr, cr)
+        circuit.h(qr[0])
+        circuit.measure(qr[0], cr[0])
+        circuit.h(qr[1]).c_if(cr, 1)
+
+        expected = '\n'.join(["         ┌───┐┌─┐       ",
+                              "qr_0: |0>┤ H ├┤M├───────",
+                              "         └───┘└╥┘ ┌───┐ ",
+                              "qr_1: |0>──────╫──┤ H ├─",
+                              "               ║ ┌┴─╨─┴┐",
+                              " cr_0: 0 ══════╩═╡     ╞",
+                              "                 │ = 1 │",
+                              " cr_1: 0 ════════╡     ╞",
+                              "                 └─────┘"])
+
+        self.assertEqual(str(_text_circuit_drawer(circuit)), expected)
+
 
 class TestTextIdleWires(QiskitTestCase):
     """The idle_wires option"""