Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix dag visualization for DAGCircuits without registers #7923

Merged
merged 6 commits into from
Apr 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions qiskit/visualization/dag_visualization.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import tempfile

from qiskit.dagcircuit.dagnode import DAGOpNode, DAGInNode, DAGOutNode
from qiskit.circuit import Qubit
from qiskit.utils import optionals as _optionals
from qiskit.exceptions import InvalidFileError
from .exceptions import VisualizationError
Expand Down Expand Up @@ -173,7 +174,9 @@ def node_attr_func(node):
edge_attr_func = None

else:
bit_labels = {
qubit_indices = {bit: index for index, bit in enumerate(dag.qubits)}
clbit_indices = {bit: index for index, bit in enumerate(dag.clbits)}
register_bit_labels = {
bit: f"{reg.name}[{idx}]"
for reg in list(dag.qregs.values()) + list(dag.cregs.values())
for (idx, bit) in enumerate(reg)
Expand All @@ -192,12 +195,20 @@ def node_attr_func(node):
n["style"] = "filled"
n["fillcolor"] = "lightblue"
if isinstance(node, DAGInNode):
n["label"] = bit_labels[node.wire]
if isinstance(node.wire, Qubit):
label = register_bit_labels.get(node.wire, f"q_{qubit_indices[node.wire]}")
else:
label = register_bit_labels.get(node.wire, f"c_{clbit_indices[node.wire]}")
n["label"] = label
n["color"] = "black"
n["style"] = "filled"
n["fillcolor"] = "green"
if isinstance(node, DAGOutNode):
n["label"] = bit_labels[node.wire]
if isinstance(node.wire, Qubit):
label = register_bit_labels.get(node.wire, f"q[{qubit_indices[node.wire]}]")
else:
label = register_bit_labels.get(node.wire, f"c[{clbit_indices[node.wire]}]")
n["label"] = label
n["color"] = "black"
n["style"] = "filled"
n["fillcolor"] = "red"
Expand All @@ -207,7 +218,11 @@ def node_attr_func(node):

def edge_attr_func(edge):
e = {}
e["label"] = bit_labels[edge]
if isinstance(edge, Qubit):
label = register_bit_labels.get(edge, f"q_{qubit_indices[edge]}")
else:
label = register_bit_labels.get(edge, f"c_{clbit_indices[edge]}")
e["label"] = label
return e

dot_str = dag._multi_graph.to_dot(node_attr_func, edge_attr_func, graph_attrs)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
fixes:
- |
Fixed an issue with the visualization function :func:`~.dag_drawer` and the
:meth:`.DAGCircuit.draw` method where previously the drawer would fail
when attempting to generate a visualization for a :class:`~.DAGCircuit`
object that contained a :class:`~.Qubit` or :class:`~.Clbit` which wasn't
part of a :class:`~QuantumRegister` or :class:`~ClassicalRegister`.
Fixed `#7915 <https://github.com/Qiskit/qiskit-terra/issues/7915>`__
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 24 additions & 3 deletions test/python/visualization/test_dag_drawer.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,22 @@

"""Tests for DAG visualization tool."""

import os
import tempfile
import unittest

from qiskit import QuantumRegister, QuantumCircuit
from qiskit.test import QiskitTestCase
from PIL import Image

from qiskit.circuit import QuantumRegister, QuantumCircuit, Qubit, Clbit
from qiskit.tools.visualization import dag_drawer
from qiskit.exceptions import InvalidFileError
from qiskit.visualization.exceptions import VisualizationError
from qiskit.converters import circuit_to_dag
from qiskit.utils import optionals as _optionals
from .visualization import path_to_diagram_reference, QiskitVisualizationTestCase


class TestDagDrawer(QiskitTestCase):
class TestDagDrawer(QiskitVisualizationTestCase):
"""Qiskit DAG drawer tests."""

def setUp(self):
Expand All @@ -49,6 +54,22 @@ def test_dag_drawer_checks_filename_extension(self):
with self.assertRaisesRegex(InvalidFileError, "Filename extension must be one of: .*"):
dag_drawer(self.dag, filename="aa.abc")

@unittest.skipUnless(_optionals.HAS_GRAPHVIZ, "Graphviz not installed")
def test_dag_drawer_no_register(self):
"""Test dag visualization with a circuit with no registers."""
qubit = Qubit()
clbit = Clbit()
qc = QuantumCircuit([qubit, clbit])
qc.h(0)
qc.measure(0, 0)
dag = circuit_to_dag(qc)
with tempfile.TemporaryDirectory() as tmpdirname:
tmp_path = os.path.join(tmpdirname, "dag.png")
dag_drawer(dag, filename=tmp_path)
image_ref = path_to_diagram_reference("dag_no_reg.png")
image = Image.open(tmp_path)
self.assertImagesAreEqual(image, image_ref, 0.2)


if __name__ == "__main__":
unittest.main(verbosity=2)