Skip to content
Open
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
37 changes: 32 additions & 5 deletions cirq-core/cirq/contrib/svg/svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,31 @@ def tdd_to_svg(
t = (
f'<svg xmlns="http://www.w3.org/2000/svg" '
f'width="{col_starts[-1]}" height="{row_starts[-1]}">'
'''
<defs>
<marker id="arrow"
viewBox="0 0 10 10"
refX="9"
refY="5"
markerUnits="strokeWidth"
markerWidth="5"
markerHeight="5"
orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" />
</marker>
<filter id="double" filterUnits="userSpaceOnUse">
<feMorphology in="SourceGraphic" result="a" operator="dilate" radius="1" />
<feComposite in="SourceGraphic" in2="a" operator="xor" />
</filter>
</defs>
'''
)

# Developers: uncomment below to draw green lines to debug
# col_starts and row_starts
# t += _debug_spacing(col_starts, row_starts)

for yi, xi1, xi2, _, _ in tdd.horizontal_lines:
for yi, xi1, xi2, _, doubled in tdd.horizontal_lines:
xi1 = cast(int, xi1)
xi2 = cast(int, xi2)
x1 = col_starts[xi1] + col_widths[xi1] / 2
Expand All @@ -203,17 +221,26 @@ def tdd_to_svg(
stroke = QBLUE
else:
stroke = 'black' # pragma: no cover
t += f'<line x1="{x1}" x2="{x2}" y1="{y}" y2="{y}" stroke="{stroke}" stroke-width="1" />'
t += f'<line x1="{x1}" x2="{x2}" y1="{y}" y2="{y}" stroke="{stroke}" stroke-width="1"'
if doubled:
t += ' filter="url(#double)"'
t += ' />'

for xi, yi1, yi2, _, _ in tdd.vertical_lines:
for xi, yi1, yi2, _, doubled in tdd.vertical_lines:
arrow = doubled and tdd.entries[int(xi), int(yi2)].text == 'V'
yi1 = yi_map[yi1]
yi2 = yi_map[yi2]
y1 = row_starts[yi1] + row_heights[yi1] / 2
y2 = row_starts[yi2] + row_heights[yi2] / 2

xi = cast(int, xi)
x = col_starts[xi] + col_widths[xi] / 2
t += f'<line x1="{x}" x2="{x}" y1="{y1}" y2="{y2}" stroke="black" stroke-width="3" />'
t += f'<line x1="{x}" x2="{x}" y1="{y1}" y2="{y2}" stroke="black" stroke-width="3"'
if doubled:
t += ' filter="url(#double)"'
if arrow:
t += ' marker-end="url(#arrow)"'
t += ' />'

for (xi, yi), v in tdd.entries.items():
yi = yi_map[yi]
Expand All @@ -238,7 +265,7 @@ def tdd_to_svg(
if v.text == '×':
t += _text(x, y + 3, '×', fontsize=40)
continue
if v.text == '':
if v.text == '' or v.text == 'V':
continue

v_text = fixup_text(v.text)
Expand Down
4 changes: 3 additions & 1 deletion cirq-core/cirq/contrib/svg/svg_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ def test_svg() -> None:
cirq.PhasedXPowGate(exponent=0.123, phase_exponent=0.456).on(c),
cirq.Z(a),
cirq.measure(a, b, c, key='z'),
cirq.MatrixGate(np.eye(2)).on(a),
cirq.MatrixGate(np.eye(2)).on(a).with_classical_controls('z'),
)
)
assert '?' in svg_text
assert '<svg' in svg_text
assert '</svg>' in svg_text
assert 'double' in svg_text
assert 'arrow' in svg_text


def test_svg_noise() -> None:
Expand Down
8 changes: 4 additions & 4 deletions cirq-core/cirq/ops/classically_controlled_operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class ClassicallyControlledOperation(raw_types.Operation):
1: ─────────────╫───X───
║ ║
control_key: ═══@═══^═══
control_key: ═══V═══@═══
>>> circuit2 = cirq.Circuit([
... cirq.measure(a, key='control_key1'),
... cirq.measure(b, key='control_key2'),
Expand All @@ -62,9 +62,9 @@ class ClassicallyControlledOperation(raw_types.Operation):
║║
2: ───────────────╫╫────X───
║║ ║
control_key1: ════@╬════^═══
control_key1: ════V╬════@═══
║ ║
control_key2: ═════@════^═══
control_key2: ═════V════@═══
└──┘
"""

Expand Down Expand Up @@ -180,7 +180,7 @@ def _circuit_diagram_info_(
control_label_count = 0
if args.label_map is not None:
control_label_count = len({k for c in self._conditions for k in c.keys})
wire_symbols = sub_info.wire_symbols + ('^',) * control_label_count
wire_symbols = sub_info.wire_symbols + ('@',) * control_label_count
if control_label_count == 0 or any(
not isinstance(c, value.KeyCondition) for c in self._conditions
):
Expand Down
Loading