Skip to content

Commit

Permalink
Infer cregbundle for all drawers (#9133) (#9191)
Browse files Browse the repository at this point in the history
* Infer `cregbundle` for all drawers

This swaps the default behaviour for the `cregbundle` to always bundle
if possible, but not to emit a warning if the bundles are expanded and
no concrete value was given for the parameter.  Previously, this sort of
logic was only done for the text drawer.

* Update tests for new default behaviour

Many tests use the internal `_text_circuit_drawer` function, which has
different defaults to the standard `circuit_drawer` function.  Since
this commit chain made this default the same all the way through the
tree, several tests changed their output, or needed the keyword
arguments updating.

* Fix missing warning test

* Revert unrelated expectedFailure changes

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
(cherry picked from commit 35733a5)

Co-authored-by: Jake Lishman <jake.lishman@ibm.com>
  • Loading branch information
mergify[bot] and jakelishman authored Nov 23, 2022
1 parent 01cb4f9 commit 2f33886
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 250 deletions.
35 changes: 18 additions & 17 deletions qiskit/visualization/circuit/circuit_visualization.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,9 @@ def circuit_drawer(
it is redundant.
initial_state (bool): Optional. Adds ``|0>`` in the beginning of the wire.
Default is False.
cregbundle (bool): Optional. If set True, bundle classical registers.
Default is True, except for when ``output`` is set to ``"text"``.
cregbundle (bool): Optional. If set True, bundle classical registers into a single wire.
Default is true if possible, and false if a block instruction needs to access an
individual bit from a register.
wire_order (list): Optional. A list of integers used to reorder the display
of the bits. The list must have an entry for every bit with the bits
in the range 0 to (num_qubits + num_clbits).
Expand Down Expand Up @@ -207,13 +208,14 @@ def circuit_drawer(
"wire_order list for the index of each qubit and each clbit in the circuit."
)

if circuit.clbits and cregbundle and (reverse_bits or wire_order is not None):
if circuit.clbits and (reverse_bits or wire_order is not None):
if cregbundle:
warn(
"cregbundle set to False since either reverse_bits or wire_order has been set.",
RuntimeWarning,
2,
)
cregbundle = False
warn(
"Cregbundle set to False since either reverse_bits or wire_order has been set.",
RuntimeWarning,
2,
)
if output == "text":
return _text_circuit_drawer(
circuit,
Expand Down Expand Up @@ -241,7 +243,7 @@ def circuit_drawer(
idle_wires=idle_wires,
with_layout=with_layout,
initial_state=initial_state,
cregbundle=cregbundle if cregbundle is not None else True,
cregbundle=cregbundle,
wire_order=wire_order,
)
elif output == "latex_source":
Expand All @@ -256,7 +258,7 @@ def circuit_drawer(
idle_wires=idle_wires,
with_layout=with_layout,
initial_state=initial_state,
cregbundle=cregbundle if cregbundle is not None else True,
cregbundle=cregbundle,
wire_order=wire_order,
)
elif output == "mpl":
Expand Down Expand Up @@ -391,7 +393,7 @@ def _latex_circuit_drawer(
idle_wires=True,
with_layout=True,
initial_state=False,
cregbundle=False,
cregbundle=None,
wire_order=None,
):
"""Draw a quantum circuit based on latex (Qcircuit package)
Expand All @@ -414,8 +416,8 @@ def _latex_circuit_drawer(
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``.
cregbundle (bool): Optional. If set True, bundle classical registers. On by default, if
this is possible for the given circuit, otherwise off.
wire_order (list): Optional. A list of integers used to reorder the display
of the bits. The list must have an entry for every bit with the bits
in the range 0 to (num_qubits + num_clbits).
Expand Down Expand Up @@ -510,7 +512,7 @@ def _generate_latex_source(
idle_wires=True,
with_layout=True,
initial_state=False,
cregbundle=False,
cregbundle=None,
wire_order=None,
):
"""Convert QuantumCircuit to LaTeX string.
Expand All @@ -532,7 +534,6 @@ def _generate_latex_source(
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``.
wire_order (list): Optional. A list of integers used to reorder the display
of the bits. The list must have an entry for every bit with the bits
in the range 0 to (num_qubits + num_clbits).
Expand Down Expand Up @@ -590,7 +591,7 @@ def _matplotlib_circuit_drawer(
fold=None,
ax=None,
initial_state=False,
cregbundle=True,
cregbundle=None,
wire_order=None,
):

Expand Down Expand Up @@ -652,7 +653,7 @@ def _matplotlib_circuit_drawer(
fold=fold,
ax=ax,
initial_state=initial_state,
cregbundle=cregbundle if cregbundle is not None else True,
cregbundle=cregbundle,
global_phase=None,
calibrations=None,
qregs=None,
Expand Down
23 changes: 16 additions & 7 deletions qiskit/visualization/circuit/latex.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"""latex visualization backend."""

import io
import itertools
import math
import re
from warnings import warn
Expand Down Expand Up @@ -57,7 +58,7 @@ def __init__(
plot_barriers=True,
layout=None,
initial_state=False,
cregbundle=False,
cregbundle=None,
global_phase=None,
qregs=None,
cregs=None,
Expand All @@ -78,7 +79,7 @@ def __init__(
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`.
cregbundle (bool): Optional. If set True bundle classical registers.
global_phase (float): Optional, the global phase for the circuit.
circuit (QuantumCircuit): the circuit that's being displayed
Raises:
Expand Down Expand Up @@ -183,15 +184,23 @@ def __init__(
self._layout = None

self._initial_state = initial_state
self._cregbundle = cregbundle
self._global_phase = circuit.global_phase

# If there is any custom instruction that uses classical bits
# then cregbundle is forced to be False.
for layer in self._nodes:
for node in layer:
if node.op.name not in {"measure"} and node.cargs:
self._cregbundle = False
for node in itertools.chain.from_iterable(self._nodes):
if node.cargs and node.op.name != "measure":
if cregbundle:
warn(
"Cregbundle set to False since an instruction needs to refer"
" to individual classical wire",
RuntimeWarning,
2,
)
self._cregbundle = False
break
else:
self._cregbundle = True if cregbundle is None else cregbundle

self._wire_map = get_wire_map(circuit, qubits + clbits, self._cregbundle)
self._img_width = len(self._wire_map)
Expand Down
26 changes: 16 additions & 10 deletions qiskit/visualization/circuit/matplotlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

"""mpl circuit visualization backend."""

import itertools
import re
from warnings import warn

Expand Down Expand Up @@ -76,7 +77,7 @@ def __init__(
fold=25,
ax=None,
initial_state=False,
cregbundle=True,
cregbundle=None,
global_phase=None,
qregs=None,
cregs=None,
Expand Down Expand Up @@ -194,10 +195,23 @@ def __init__(
self._ax.tick_params(labelbottom=False, labeltop=False, labelleft=False, labelright=False)

self._initial_state = initial_state
self._cregbundle = cregbundle
self._global_phase = self._circuit.global_phase
self._calibrations = self._circuit.calibrations

for node in itertools.chain.from_iterable(self._nodes):
if node.cargs and node.op.name != "measure":
if cregbundle:
warn(
"Cregbundle set to False since an instruction needs to refer"
" to individual classical wire",
RuntimeWarning,
3,
)
self._cregbundle = False
break
else:
self._cregbundle = True if cregbundle is None else cregbundle

self._fs = self._style["fs"]
self._sfs = self._style["sfs"]
self._lwidth1 = 1.0
Expand Down Expand Up @@ -407,14 +421,6 @@ def _get_layer_widths(self):
widest_box = WID
for node in layer:
op = node.op
if self._cregbundle and node.cargs and not isinstance(op, Measure):
self._cregbundle = False
warn(
"Cregbundle set to False since an instruction needs to refer"
" to individual classical wire",
RuntimeWarning,
2,
)
self._data[node] = {}
self._data[node]["width"] = WID
num_ctrl_qubits = 0 if not hasattr(op, "num_ctrl_qubits") else op.num_ctrl_qubits
Expand Down
47 changes: 16 additions & 31 deletions qiskit/visualization/circuit/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

from warnings import warn
from shutil import get_terminal_size
import itertools
import sys

from qiskit.circuit import Qubit, Clbit, ClassicalRegister, QuantumRegister, QuantumCircuit
Expand All @@ -37,13 +38,6 @@
from ..exceptions import VisualizationError


class TextDrawerCregBundle(VisualizationError):
"""The parameter "cregbundle" was set to True in an impossible situation. For example,
a node needs to refer to individual classical wires'"""

pass


class TextDrawerEncodingError(VisualizationError):
"""A problem with encoding"""

Expand Down Expand Up @@ -678,8 +672,6 @@ def __init__(
self.layout = None

self.initial_state = initial_state
self._cregbundle = cregbundle
self._default_cregbundle = False
self.global_phase = circuit.global_phase
self.plotbarriers = plotbarriers
self.reverse_bits = reverse_bits
Expand All @@ -689,6 +681,20 @@ def __init__(
self.vertical_compression = vertical_compression
self._wire_map = {}

for node in itertools.chain.from_iterable(self.nodes):
if node.cargs and node.op.name != "measure":
if cregbundle:
warn(
"Cregbundle set to False since an instruction needs to refer"
" to individual classical wire",
RuntimeWarning,
2,
)
self.cregbundle = False
break
else:
self.cregbundle = True if cregbundle is None else cregbundle

if encoding:
self.encoding = encoding
else:
Expand All @@ -697,13 +703,6 @@ def __init__(
else:
self.encoding = "utf8"

@property
def cregbundle(self):
"""cregbundle, depending if it was explicitly set or not"""
if self._cregbundle is not None:
return self._cregbundle
return self._default_cregbundle

def __str__(self):
return self.single_string()

Expand Down Expand Up @@ -769,19 +768,7 @@ def lines(self, line_length=None):

noqubits = len(self.qubits)

try:
layers = self.build_layers()
except TextDrawerCregBundle:
if self._cregbundle is not None:
self._cregbundle = False
warn(
'The parameter "cregbundle" was disabled, since an instruction needs to refer to '
"individual classical wires",
RuntimeWarning,
2,
)
layers = self.build_layers()

layers = self.build_layers()
layer_groups = [[]]
rest_of_the_line = line_length
for layerno, layer in enumerate(layers):
Expand Down Expand Up @@ -1167,8 +1154,6 @@ def add_connected_gate(node, gates, layer, current_cons):
layer.set_qu_multibox(node.qargs, gate_text, conditional=conditional)

elif node.qargs and node.cargs:
if self.cregbundle and node.cargs:
raise TextDrawerCregBundle("TODO")
layer._set_multibox(
gate_text,
qubits=node.qargs,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
fixes:
- |
The circuit drawers (:meth:`.QuantumCircuit.draw` and :func:`.circuit_drawer`) will no
longer emit a warning about the ``cregbundle`` parameter when using the default arguments,
if the content of the circuit requires all bits to be drawn individually. This was most
likely to appear when trying to draw circuits with new-style control-flow operations.
9 changes: 7 additions & 2 deletions test/python/visualization/test_circuit_drawer.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def test_wire_order_raises(self):
with self.assertRaisesRegex(VisualizationError, "cannot be set when the reverse_bits"):
visualization.circuit_drawer(circuit, wire_order=[0, 1, 2, 5, 4, 3], reverse_bits=True)

with self.assertWarnsRegex(RuntimeWarning, "Cregbundle set"):
with self.assertWarnsRegex(RuntimeWarning, "cregbundle set"):
visualization.circuit_drawer(circuit, cregbundle=True, wire_order=[0, 1, 2, 5, 4, 3])

def test_reverse_bits(self):
Expand Down Expand Up @@ -159,5 +159,10 @@ def test_no_explict_cregbundle(self):
" ",
]
)
result = visualization.circuit_drawer(circuit)
result = circuit.draw("text")
self.assertEqual(result.__str__(), expected)
# Extra tests that no cregbundle (or any other) warning is raised with the default settings
# for the other drawers, if they're available to test.
circuit.draw("latex_source")
if optionals.HAS_MATPLOTLIB and optionals.HAS_PYLATEX:
circuit.draw("mpl")
Loading

0 comments on commit 2f33886

Please sign in to comment.