Skip to content

Commit

Permalink
Fix SVGCircuit() for cirq.Circuit with empty moments (#4535)
Browse files Browse the repository at this point in the history
* Modified SVG Representation to include circuits with empty moments

* TODOs

* Reverted the Casting of Ints to Floats

* Consistent TODOs

* removed redundancies, added comments and improved tests

* Formatted Code

* Coverage Error

* Added tests to increase coverage

* Simplified, removed try except

Co-authored-by: Gaurav Singh <gauravsinghk03@gmail.com>
Co-authored-by: Gaurav Singh <71246220+vanhalen42@users.noreply.github.com>
Co-authored-by: Cirq Bot <craiggidney+github+cirqbot@google.com>
  • Loading branch information
4 people authored Nov 3, 2021
1 parent 3df15e3 commit 1851585
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 12 deletions.
19 changes: 10 additions & 9 deletions cirq-core/cirq/contrib/svg/svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@

QBLUE = '#1967d2'
FONT = "Arial"
EMPTY_MOMENT_COLWIDTH = float(21) # assumed default column width


def fixup_text(text: str):
if '\n' in text:
# https://github.com/quantumlib/Cirq/issues/4499
# TODO: Visualize Custom MatrixGate
return '?'
if '[<virtual>]' in text:
# https://github.com/quantumlib/Cirq/issues/2905
Expand All @@ -24,6 +27,8 @@ def fixup_text(text: str):


def _get_text_width(t: str) -> float:
if t == '': # in case of an empty moment
return EMPTY_MOMENT_COLWIDTH
t = fixup_text(t)
tp = matplotlib.textpath.TextPath((0, 0), t, size=14, prop=FONT)
bb = tp.get_extents()
Expand Down Expand Up @@ -234,6 +239,8 @@ def tdd_to_svg(
if v.text == '×':
t += _text(x, y + 3, '×', fontsize=40)
continue
if v.text == '':
continue

v_text = fixup_text(v.text)
t += _rect(boxx, boxy, boxwidth, boxheight)
Expand All @@ -247,12 +254,6 @@ def _validate_circuit(circuit: 'cirq.Circuit'):
if len(circuit) == 0:
raise ValueError("Can't draw SVG diagram for empty circuits")

if any(len(mom) == 0 for mom in circuit.moments):
raise ValueError(
"Can't draw SVG diagram for circuits with empty "
"moments. Run it through cirq.DropEmptyMoments()"
)


class SVGCircuit:
"""A wrapper around cirq.Circuit to enable rich display in a Jupyter
Expand All @@ -269,13 +270,13 @@ def __init__(self, circuit: 'cirq.Circuit'):

def _repr_svg_(self) -> str:
# coverage: ignore
_validate_circuit(self.circuit)
tdd = self.circuit.to_text_diagram_drawer(transpose=False)
return tdd_to_svg(tdd)
return circuit_to_svg(self.circuit)


def circuit_to_svg(circuit: 'cirq.Circuit') -> str:
"""Render a circuit as SVG."""
_validate_circuit(circuit)
tdd = circuit.to_text_diagram_drawer(transpose=False)
if len(tdd.horizontal_lines) == 0: # in circuits with no non-empty moments,return a blank SVG
return '<svg></svg>'
return tdd_to_svg(tdd)
23 changes: 20 additions & 3 deletions cirq-core/cirq/contrib/svg/svg_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,23 @@ def test_validation():
with pytest.raises(ValueError):
circuit_to_svg(cirq.Circuit())

q0 = cirq.LineQubit(0)
with pytest.raises(ValueError):
circuit_to_svg(cirq.Circuit([cirq.Moment([cirq.X(q0)]), cirq.Moment([])]))

def test_empty_moments():
a, b = cirq.LineQubit.range(2)
svg_1 = circuit_to_svg(
cirq.Circuit(
cirq.Moment(),
cirq.Moment(cirq.CNOT(a, b)),
cirq.Moment(),
cirq.Moment(cirq.SWAP(a, b)),
cirq.Moment(cirq.Z(a)),
cirq.Moment(cirq.measure(a, b, key='z')),
cirq.Moment(),
)
)
assert '<svg' in svg_1
assert '</svg>' in svg_1

svg_2 = circuit_to_svg(cirq.Circuit(cirq.Moment()))
assert '<svg' in svg_2
assert '</svg>' in svg_2

0 comments on commit 1851585

Please sign in to comment.