Repository: Qiskit/qiskit

Issue:
latex drawer support for cregbundle
In the spirit of https://github.com/Qiskit/qiskit-terra/issues/2797 it would be great if latex drawer add support for `cregbundle`.

Take the following example:
```python
from qiskit import *
qr = QuantumRegister(3, 'q')
cr = ClassicalRegister(3, 'c')
circuit = QuantumCircuit(qr, cr)
circuit.measure(qr, cr)
circuit.draw('latex')
```
<img width="427" alt="Screen Shot 2020-04-27 at 3 10 31 PM" src="https://user-images.githubusercontent.com/766693/80410889-43f93200-8899-11ea-9bed-558804fa26c6.png">

I suggest something like this:
```
circuit.draw('latex', cregbundle=True)
```
<img width="451" alt="Screen Shot 2020-04-27 at 3 11 26 PM" src="https://user-images.githubusercontent.com/766693/80410958-612e0080-8899-11ea-9cce-5005f5ef43b1.png">

The latex code for that figure is:
```latex
\begin{equation*}
    \Qcircuit @C=1.0em @R=1.0em @!R {
	 	\lstick{ {q}_{0} :  } & \qw & \meter & \qw & \qw & \qw & \qw\\
	 	\lstick{ {q}_{1} :  } & \qw & \qw & \meter & \qw & \qw & \qw\\
	 	\lstick{ {q}_{2} :  } & \qw & \qw & \qw & \meter & \qw & \qw\\
	 	\lstick{c:} & {/_{_3}} \cw & \dstick{0} \cw \cwx[-3] & \dstick{1} \cw \cwx[-2] & \dstick{2} \cw \cwx[-1] & \cw & \cw\\
	 }
\end{equation*}
```


Discussion:
Hello! I haven't contributed to any open-source software but I want to try my hand at this.
Sure! Go ahead. Let me know if I can help!

Resolving patch:
diff --git a/qiskit/circuit/quantumcircuit.py b/qiskit/circuit/quantumcircuit.py
--- a/qiskit/circuit/quantumcircuit.py
+++ b/qiskit/circuit/quantumcircuit.py
@@ -839,8 +839,8 @@ def draw(self, output=None, scale=0.7, filename=None, style=None,
             initial_state (bool): Optional. Adds ``|0>`` in the beginning of the wire.
                 Only used by the ``text``, ``latex`` and ``latex_source`` outputs.
                 Default: ``False``.
-            cregbundle (bool): Optional. If set True bundle classical registers. Only used by
-                the ``text`` output. Default: ``False``.
+            cregbundle (bool): Optional. If set True bundle classical registers. Not used by
+                the ``matplotlib`` output. Default: ``False``.
 
         Returns:
             :class:`PIL.Image` or :class:`matplotlib.figure` or :class:`str` or
diff --git a/qiskit/visualization/circuit_visualization.py b/qiskit/visualization/circuit_visualization.py
--- a/qiskit/visualization/circuit_visualization.py
+++ b/qiskit/visualization/circuit_visualization.py
@@ -139,8 +139,8 @@ def circuit_drawer(circuit,
         initial_state (bool): Optional. Adds ``|0>`` in the beginning of the wire.
             Only used by the ``text``, ``latex`` and ``latex_source`` outputs.
             Default: ``False``.
-        cregbundle (bool): Optional. If set True bundle classical registers. Only used by
-            the ``text`` output. Default: ``False``.
+        cregbundle (bool): Optional. If set True bundle classical registers. Not used by
+            the ``matplotlib`` output. Default: ``False``.
     Returns:
         :class:`PIL.Image` or :class:`matplotlib.figure` or :class:`str` or
         :class:`TextDrawing`:
@@ -300,7 +300,8 @@ def circuit_drawer(circuit,
                                       justify=justify,
                                       idle_wires=idle_wires,
                                       with_layout=with_layout,
-                                      initial_state=initial_state)
+                                      initial_state=initial_state,
+                                      cregbundle=cregbundle)
     elif output == 'latex_source':
         return _generate_latex_source(circuit,
                                       filename=filename, scale=scale,
@@ -310,7 +311,8 @@ def circuit_drawer(circuit,
                                       justify=justify,
                                       idle_wires=idle_wires,
                                       with_layout=with_layout,
-                                      initial_state=initial_state)
+                                      initial_state=initial_state,
+                                      cregbundle=cregbundle)
     elif output == 'mpl':
         image = _matplotlib_circuit_drawer(circuit, scale=scale,
                                            filename=filename, style=style,
@@ -475,7 +477,8 @@ def _latex_circuit_drawer(circuit,
                           justify=None,
                           idle_wires=True,
                           with_layout=True,
-                          initial_state=False):
+                          initial_state=False,
+                          cregbundle=False):
     """Draw a quantum circuit based on latex (Qcircuit package)
 
     Requires version >=2.6.0 of the qcircuit LaTeX package.
@@ -495,6 +498,8 @@ def _latex_circuit_drawer(circuit,
         with_layout (bool): Include layout information, with labels on the physical
             layout. Default: True
         initial_state (bool): Optional. Adds |0> in the beginning of the line. Default: `False`.
+        cregbundle (bool): Optional. If set True bundle classical registers.
+            Default: ``False``.
 
     Returns:
         PIL.Image: an in-memory representation of the circuit diagram
@@ -513,7 +518,8 @@ def _latex_circuit_drawer(circuit,
                                plot_barriers=plot_barriers,
                                reverse_bits=reverse_bits, justify=justify,
                                idle_wires=idle_wires, with_layout=with_layout,
-                               initial_state=initial_state)
+                               initial_state=initial_state,
+                               cregbundle=cregbundle)
         try:
 
             subprocess.run(["pdflatex", "-halt-on-error",
@@ -559,7 +565,7 @@ def _latex_circuit_drawer(circuit,
 def _generate_latex_source(circuit, filename=None,
                            scale=0.7, style=None, reverse_bits=False,
                            plot_barriers=True, justify=None, idle_wires=True,
-                           with_layout=True, initial_state=False):
+                           with_layout=True, initial_state=False, cregbundle=False):
     """Convert QuantumCircuit to LaTeX string.
 
     Args:
@@ -577,6 +583,8 @@ def _generate_latex_source(circuit, filename=None,
         with_layout (bool): Include layout information, with labels on the physical
             layout. Default: True
         initial_state (bool): Optional. Adds |0> in the beginning of the line. Default: `False`.
+        cregbundle (bool): Optional. If set True bundle classical registers.
+            Default: ``False``.
 
     Returns:
         str: Latex string appropriate for writing to file.
@@ -592,7 +600,8 @@ def _generate_latex_source(circuit, filename=None,
     qcimg = _latex.QCircuitImage(qregs, cregs, ops, scale, style=style,
                                  plot_barriers=plot_barriers,
                                  reverse_bits=reverse_bits, layout=layout,
-                                 initial_state=initial_state)
+                                 initial_state=initial_state,
+                                 cregbundle=cregbundle)
     latex = qcimg.latex()
     if filename:
         with open(filename, 'w') as latex_file:
diff --git a/qiskit/visualization/latex.py b/qiskit/visualization/latex.py
--- a/qiskit/visualization/latex.py
+++ b/qiskit/visualization/latex.py
@@ -41,7 +41,8 @@ class QCircuitImage:
     """
 
     def __init__(self, qubits, clbits, ops, scale, style=None,
-                 plot_barriers=True, reverse_bits=False, layout=None, initial_state=False):
+                 plot_barriers=True, reverse_bits=False, layout=None, initial_state=False,
+                 cregbundle=False):
         """QCircuitImage initializer.
 
         Args:
@@ -57,6 +58,7 @@ def __init__(self, qubits, clbits, ops, scale, style=None,
             layout (Layout or None): If present, the layout information will be
                included.
             initial_state (bool): Optional. Adds |0> in the beginning of the line. Default: `False`.
+            cregbundle (bool): Optional. If set True bundle classical registers. Default: `False`.
         Raises:
             ImportError: If pylatexenc is not installed
         """
@@ -125,10 +127,14 @@ def __init__(self, qubits, clbits, ops, scale, style=None,
         self.clbit_list = clbits
         self.img_regs = {bit: ind for ind, bit in
                          enumerate(self.ordered_regs)}
-        self.img_width = len(self.img_regs)
+        if cregbundle:
+            self.img_width = len(qubits) + len(self.cregs)
+        else:
+            self.img_width = len(self.img_regs)
         self.wire_type = {}
         for bit in self.ordered_regs:
             self.wire_type[bit] = bit.register in self.cregs.keys()
+        self.cregbundle = cregbundle
 
     def latex(self, aliases=None):
         """Return LaTeX string representation of circuit.
@@ -208,10 +214,19 @@ def _initialize_latex_array(self, aliases=None):
              else "\\qw" for _ in range(self.img_depth + 1)]
             for j in range(self.img_width)]
         self._latex.append([" "] * (self.img_depth + 1))
+        if self.cregbundle:
+            offset = 0
         for i in range(self.img_width):
             if self.wire_type[self.ordered_regs[i]]:
-                self._latex[i][0] = "\\lstick{" + self.ordered_regs[i].register.name + \
-                                    "_{" + str(self.ordered_regs[i].index) + "}" + ": "
+                if self.cregbundle:
+                    self._latex[i][0] = \
+                        "\\lstick{" + self.ordered_regs[i + offset].register.name + ":"
+                    clbitsize = self.cregs[self.ordered_regs[i + offset].register]
+                    self._latex[i][1] = "{/_{_{" + str(clbitsize) + "}}} \\cw"
+                    offset += clbitsize - 1
+                else:
+                    self._latex[i][0] = "\\lstick{" + self.ordered_regs[i].register.name + \
+                                            "_{" + str(self.ordered_regs[i].index) + "}:"
                 if self.initial_state:
                     self._latex[i][0] += "0"
                 self._latex[i][0] += "}"
@@ -277,6 +292,10 @@ def _get_image_depth(self):
         # wires in the beginning and end
         columns = 2
 
+        # add extra column if needed
+        if self.cregbundle and self.ops[0][0].name == "measure":
+            columns += 1
+
         # all gates take up 1 column except from those with labels (ie cu1)
         # which take 2 columns
         for layer in self.ops:
@@ -368,6 +387,9 @@ def _build_latex_array(self, aliases=None):
             qregdata = self.qregs
 
         column = 1
+        # Leave a column to display number of classical registers if needed
+        if self.cregbundle and self.ops[0][0].name == "measure":
+            column += 1
         for layer in self.ops:
             num_cols_used = 1
 
@@ -917,12 +939,27 @@ def _build_latex_array(self, aliases=None):
                         qindex = newq[1]
 
                     pos_1 = self.img_regs[op.qargs[0]]
-                    pos_2 = self.img_regs[op.cargs[0]]
+                    if self.cregbundle:
+                        pos_2 = self.img_regs[self.clbit_list[0]]
+                        cregindex = self.img_regs[op.cargs[0]] - pos_2
+                        for creg_size in self.cregs.values():
+                            if cregindex >= creg_size:
+                                cregindex -= creg_size
+                                pos_2 += 1
+                            else:
+                                break
+                    else:
+                        pos_2 = self.img_regs[op.cargs[0]]
 
                     try:
                         self._latex[pos_1][column] = "\\meter"
-                        self._latex[pos_2][column] = \
-                            "\\cw \\cwx[-" + str(pos_2 - pos_1) + "]"
+                        if self.cregbundle:
+                            self._latex[pos_2][column] = \
+                                "\\dstick{" + str(cregindex) + "} " + \
+                                "\\cw \\cwx[-" + str(pos_2 - pos_1) + "]"
+                        else:
+                            self._latex[pos_2][column] = \
+                                "\\cw \\cwx[-" + str(pos_2 - pos_1) + "]"
                     except Exception as e:
                         raise exceptions.VisualizationError(
                             'Error during Latex building: %s' % str(e))


Test patch: