Skip to content

Commit 6ea290e

Browse files
committed
Add charge_in_node option to draw_symmray_peps
Render each tensor's charge q and total particle number N centered inside the node circle (enlarged to fit), dropping the duplicate q label above. Add a focused test exercising charge_in_node=True.
1 parent f5949f9 commit 6ea290e

2 files changed

Lines changed: 43 additions & 4 deletions

File tree

‎src/pepsy/tensors/symmetric.py‎

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,18 @@ def _format_shape(shape):
193193
return "x".join(str(int(dim)) for dim in shape) or "scalar"
194194

195195

196+
def _charge_particle_number(charge):
197+
"""Total particle number carried by a tensor charge (sum of components)."""
198+
if charge is None:
199+
return None
200+
if isinstance(charge, tuple):
201+
return sum(int(x) for x in charge)
202+
try:
203+
return int(charge)
204+
except (TypeError, ValueError):
205+
return None
206+
207+
196208
def _add_charges(a, b):
197209
if isinstance(a, tuple) or isinstance(b, tuple):
198210
a_t = a if isinstance(a, tuple) else (a,) * len(b)
@@ -1426,6 +1438,7 @@ def draw_symmray_peps(
14261438
show_diagnostics=False,
14271439
show_blocks=False,
14281440
show_block_labels=False,
1441+
charge_in_node=False,
14291442
max_blocks_per_site=4,
14301443
node_shape="circle",
14311444
node_radius=0.22,
@@ -1437,6 +1450,10 @@ def draw_symmray_peps(
14371450
The schematic follows the compact :mod:`quimb.schematic` style with a PEPS
14381451
lattice, virtual-bond arrows, physical legs, and optional Symmray block and
14391452
dimension labels.
1453+
1454+
Set ``charge_in_node=True`` to print each tensor's charge ``q`` and total
1455+
particle number ``N`` (the sum of the charge components) centered inside its
1456+
node circle; the node is enlarged automatically so the text fits.
14401457
"""
14411458
summary = symmray_peps_summary(peps)
14421459
max_blocks_per_site = int(max_blocks_per_site)
@@ -1564,18 +1581,37 @@ def draw_symmray_peps(
15641581
)
15651582

15661583
show_block_labels = bool(show_block_labels)
1584+
charge_in_node = bool(charge_in_node)
1585+
node_text_radius = node_radius
1586+
if charge_in_node and node_shape == "circle":
1587+
node_text_radius = max(node_radius, 0.32)
15671588
for tensor in shown_tensors:
15681589
site = tensor["site"]
15691590
x_pos, y_pos = xy_by_site[site]
15701591
preset = "center" if site == center_site else ("site_a" if sum(site) % 2 == 0 else "site_b")
15711592

15721593
if node_shape == "circle":
1573-
drawing.circle((x_pos, y_pos), radius=node_radius, preset=preset, zorder=3)
1594+
drawing.circle((x_pos, y_pos), radius=node_text_radius, preset=preset, zorder=3)
15741595
elif node_shape == "cube":
15751596
drawing.cube((x_pos, y_pos, 0.0), preset=preset, zorder=3)
15761597
else:
15771598
raise ValueError("node_shape must be 'circle' or 'cube'.")
15781599

1600+
if charge_in_node and tensor["charge"] is not None:
1601+
node_lines = [rf"$q={_format_charge(tensor['charge'])}$"]
1602+
particle = _charge_particle_number(tensor["charge"])
1603+
if particle is not None:
1604+
node_lines.append(rf"$N={particle}$")
1605+
drawing.text(
1606+
(x_pos, y_pos),
1607+
"\n".join(node_lines),
1608+
fontsize=6.4,
1609+
ha="center",
1610+
va="center",
1611+
color=(1.0, 1.0, 1.0, 1.0),
1612+
zorder=4,
1613+
)
1614+
15791615
phys_xy = (x_pos - 0.30, y_pos - 0.42)
15801616
drawing.line((x_pos, y_pos), phys_xy, preset="phys", zorder=1)
15811617
if show_arrows:
@@ -1589,7 +1625,7 @@ def draw_symmray_peps(
15891625

15901626
if show_tensor_labels:
15911627
label_lines = [rf"$T_{{({site[0]},{site[1]})}}$"]
1592-
if tensor["charge"] is not None:
1628+
if tensor["charge"] is not None and not charge_in_node:
15931629
label_lines.append(rf"$q={_format_charge(tensor['charge'])}$")
15941630
if not show_blocks:
15951631
label_lines.append(rf"$B={tensor['num_blocks']}$")
@@ -1600,7 +1636,7 @@ def draw_symmray_peps(
16001636
else (0.06, 0.20, 0.30, 1.0)
16011637
)
16021638
drawing.text(
1603-
(x_pos, y_pos + 0.34),
1639+
(x_pos, y_pos + node_text_radius + 0.12),
16041640
label,
16051641
fontsize=7.5,
16061642
ha="center",
@@ -1632,7 +1668,7 @@ def draw_symmray_peps(
16321668
gap = 0.032
16331669
total_width = len(blocks) * block_width + (len(blocks) - 1) * gap
16341670
start = x_pos - 0.5 * total_width
1635-
block_y = y_pos - 0.34
1671+
block_y = y_pos - node_text_radius - 0.12
16361672
for block_pos, block in enumerate(blocks):
16371673
bx = start + block_pos * (block_width + gap)
16381674
color = schematic.hash_to_color(str(block["sector"]))

‎tests/test_symmetric_tensors.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ def test_symmray_peps_summary_and_schematic_for_z2_grid():
146146
assert hasattr(drawing, "ax")
147147
assert drawn_summary["bonds"] == summary["bonds"]
148148

149+
node_drawing = draw_symmray_peps(state, charge_in_node=True)
150+
assert hasattr(node_drawing, "fig")
151+
149152

150153
def test_symmetric_state_uses_psi_with_network_compatibility_alias():
151154
"""SymMPS should prefer psi/mps naming while keeping network compatibility."""

0 commit comments

Comments
 (0)