Skip to content

Commit 7845a22

Browse files
authored
Draw latex diagrams for bloqs using QPIC (#908)
* Draw latex diagrams for bloqs using QPIC * A bunch of improvements * Add latex type to show_bloq method and delegate to show_bloq_via_qpic
1 parent d0c5732 commit 7845a22

6 files changed

Lines changed: 522 additions & 7 deletions

File tree

qualtran/bloqs/basic_gates/global_phase.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ def adjoint(self) -> 'GlobalPhase':
5454
def pretty_name(self) -> str:
5555
return 'GPhase'
5656

57+
def __str__(self) -> str:
58+
return str(self.coefficient)
59+
5760
def _t_complexity_(self) -> 'TComplexity':
5861
return TComplexity()
5962

qualtran/cirq_interop/_cirq_to_bloq.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,20 @@ def cirq_gate(self) -> cirq.Gate:
162162
return self.gate
163163

164164

165+
def _cirq_wire_symbol_to_qualtran_wire_symbol(symbol: str, side: Side) -> 'WireSymbol':
166+
167+
from qualtran.drawing import Circle, directional_text_box, ModPlus
168+
169+
if symbol == "@":
170+
return Circle(filled=True)
171+
if symbol == "@(0)":
172+
return Circle(filled=False)
173+
if symbol == "X":
174+
return ModPlus()
175+
return directional_text_box(symbol, side=side)
176+
177+
165178
def _wire_symbol_from_gate(gate: cirq.Gate, signature: Signature, soq: 'Soquet') -> 'WireSymbol':
166-
from qualtran.drawing import directional_text_box
167179

168180
wire_symbols = cirq.circuit_diagram_info(gate).wire_symbols
169181
begin = 0
@@ -187,7 +199,7 @@ def _wire_symbol_from_gate(gate: cirq.Gate, signature: Signature, soq: 'Soquet')
187199
# bitsize = 1 and shape is non trivial, index into the array of wireshapes.
188200
symbol = np.array(wire_symbols[begin:finish]).reshape(reg.shape)[soq.idx]
189201
begin = finish
190-
return directional_text_box(text=symbol, side=soq.reg.side)
202+
return _cirq_wire_symbol_to_qualtran_wire_symbol(symbol, soq.reg.side)
191203

192204

193205
def _add_my_tensors_from_gate(

qualtran/drawing/__init__.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,11 @@
4646
format_counts_graph_markdown,
4747
)
4848

49-
from ._show_funcs import show_bloq, show_bloqs, show_call_graph, show_counts_sigma, show_flame_graph
49+
from ._show_funcs import (
50+
show_bloq,
51+
show_bloqs,
52+
show_call_graph,
53+
show_counts_sigma,
54+
show_flame_graph,
55+
show_bloq_via_qpic,
56+
)

qualtran/drawing/_show_funcs.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
"""Convenience functions for showing rich displays in Jupyter notebook."""
1616

17+
import os
1718
from typing import Dict, Sequence, TYPE_CHECKING, Union
1819

1920
import IPython.display
@@ -23,6 +24,7 @@
2324
from .flame_graph import get_flame_graph_svg_data
2425
from .graphviz import PrettyGraphDrawer, TypedGraphDrawer
2526
from .musical_score import draw_musical_score, get_musical_score_data
27+
from .qpic_diagram import qpic_diagram_for_bloq
2628

2729
if TYPE_CHECKING:
2830
import networkx as nx
@@ -36,17 +38,20 @@ def show_bloq(bloq: 'Bloq', type: str = 'graph'): # pylint: disable=redefined-b
3638
3739
Args:
3840
bloq: The bloq to show
39-
type: Either 'graph', 'dtype', or 'musical_score'. By default, display a directed acyclic
40-
graph of the bloq connectivity. If dtype then the connections are
41-
labelled with their dtypes rather than bitsizes. Otherwise, draw a
42-
musical score diagram.
41+
type: Either 'graph', 'dtype', 'musical_score' or 'latex'. By default, display
42+
a directed acyclic graph of the bloq connectivity. If dtype then the
43+
connections are labelled with their dtypes rather than bitsizes. If 'latex',
44+
then latex diagrams are drawn using `qpic`, which should be installed already
45+
and is invoked via a subprocess.run() call. Otherwise, draw a musical score diagram.
4346
"""
4447
if type.lower() == 'graph':
4548
IPython.display.display(PrettyGraphDrawer(bloq).get_svg())
4649
elif type.lower() == 'dtype':
4750
IPython.display.display(TypedGraphDrawer(bloq).get_svg())
4851
elif type.lower() == 'musical_score':
4952
draw_musical_score(get_musical_score_data(bloq))
53+
elif type.lower() == 'latex':
54+
show_bloq_via_qpic(bloq)
5055
else:
5156
raise ValueError(f"Unknown `show_bloq` type: {type}.")
5257

@@ -84,3 +89,13 @@ def show_flame_graph(*bloqs: 'Bloq', **kwargs):
8489
"""Display hiearchical decomposition and T-complexity costs as a Flame Graph."""
8590
svg_data = get_flame_graph_svg_data(*bloqs, **kwargs)
8691
IPython.display.display(IPython.display.SVG(svg_data))
92+
93+
94+
def show_bloq_via_qpic(bloq: 'Bloq', width: int = 1000, height: int = 400):
95+
"""Display latex diagram for bloq by invoking `qpic`. Assumes qpic is already installed."""
96+
output_file_path = qpic_diagram_for_bloq(bloq, output_type='png')
97+
98+
from IPython.display import Image
99+
100+
IPython.display.display(Image(output_file_path, width=width, height=height))
101+
os.remove(output_file_path)

0 commit comments

Comments
 (0)