tensor-network-visualization 1.4.1__tar.gz → 1.4.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. {tensor_network_visualization-1.4.1/src/tensor_network_visualization.egg-info → tensor_network_visualization-1.4.2}/PKG-INFO +47 -19
  2. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/README.md +44 -18
  3. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/pyproject.toml +3 -2
  4. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2/src/tensor_network_visualization.egg-info}/PKG-INFO +47 -19
  5. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_visualization.egg-info/SOURCES.txt +6 -2
  6. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_visualization.egg-info/requires.txt +2 -0
  7. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/__init__.py +5 -1
  8. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/contractions.py +122 -122
  9. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/draw/constants.py +5 -2
  10. tensor_network_visualization-1.4.2/src/tensor_network_viz/_core/draw/contraction_scheme.py +253 -0
  11. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/draw/edges.py +728 -697
  12. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/draw/graph_pipeline.py +16 -0
  13. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/draw/plotter.py +285 -285
  14. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/draw/tensors.py +198 -198
  15. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/draw/viewport_geometry.py +693 -693
  16. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/graph.py +35 -0
  17. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/layout/body.py +143 -0
  18. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/layout/force_directed.py +7 -5
  19. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/layout/parameters.py +8 -0
  20. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/layout_structure.py +506 -506
  21. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/renderer.py +444 -444
  22. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/config.py +28 -8
  23. tensor_network_visualization-1.4.2/src/tensor_network_viz/einsum_module/__init__.py +14 -0
  24. tensor_network_visualization-1.4.2/src/tensor_network_viz/einsum_module/_equation.py +332 -0
  25. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/einsum_module/_trace_state.py +72 -44
  26. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/einsum_module/_trace_types.py +15 -2
  27. tensor_network_visualization-1.4.2/src/tensor_network_viz/einsum_module/graph.py +298 -0
  28. tensor_network_visualization-1.4.2/src/tensor_network_viz/einsum_module/trace.py +148 -0
  29. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/tenpy/__init__.py +3 -0
  30. tensor_network_visualization-1.4.2/src/tensor_network_viz/tenpy/explicit.py +73 -0
  31. tensor_network_visualization-1.4.2/src/tensor_network_viz/tenpy/graph.py +184 -0
  32. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/viewer.py +93 -93
  33. tensor_network_visualization-1.4.2/tests/test_contraction_scheme.py +141 -0
  34. tensor_network_visualization-1.4.2/tests/test_demo_cli_scheme.py +45 -0
  35. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/tests/test_draw_performance.py +0 -42
  36. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/tests/test_einsum_autotrace.py +80 -19
  37. tensor_network_visualization-1.4.2/tests/test_einsum_backend.py +267 -0
  38. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/tests/test_examples.py +97 -3
  39. tensor_network_visualization-1.4.2/tests/test_examples_structure.py +38 -0
  40. tensor_network_visualization-1.4.2/tests/test_packaging_metadata.py +17 -0
  41. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/tests/test_plotting.py +0 -13
  42. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/tests/test_public_api.py +183 -183
  43. tensor_network_visualization-1.4.2/tests/test_show_tensor_network_throughput.py +57 -0
  44. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/tests/test_tenpy_backend.py +137 -1
  45. tensor_network_visualization-1.4.1/src/tensor_network_viz/einsum_module/__init__.py +0 -10
  46. tensor_network_visualization-1.4.1/src/tensor_network_viz/einsum_module/_equation.py +0 -61
  47. tensor_network_visualization-1.4.1/src/tensor_network_viz/einsum_module/graph.py +0 -175
  48. tensor_network_visualization-1.4.1/src/tensor_network_viz/einsum_module/trace.py +0 -100
  49. tensor_network_visualization-1.4.1/src/tensor_network_viz/tenpy/graph.py +0 -156
  50. tensor_network_visualization-1.4.1/tests/test_einsum_backend.py +0 -155
  51. tensor_network_visualization-1.4.1/tests/test_integration_quimb.py +0 -41
  52. tensor_network_visualization-1.4.1/tests/test_integration_tenpy.py +0 -55
  53. tensor_network_visualization-1.4.1/tests/test_show_tensor_network_throughput.py +0 -120
  54. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/LICENSE +0 -0
  55. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/setup.cfg +0 -0
  56. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_visualization.egg-info/dependency_links.txt +0 -0
  57. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_visualization.egg-info/top_level.txt +0 -0
  58. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/__init__.py +0 -0
  59. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/_draw_common.py +0 -0
  60. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/_label_format.py +0 -0
  61. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/_nodes_edges_common.py +0 -0
  62. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/axis_directions.py +0 -0
  63. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/curves.py +0 -0
  64. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/draw/__init__.py +0 -0
  65. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/draw/disk_metrics.py +0 -0
  66. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/draw/fonts_and_scale.py +0 -0
  67. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/draw/hover.py +0 -0
  68. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/draw/labels_misc.py +0 -0
  69. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/draw/pick_distance.py +0 -0
  70. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/draw/vectors.py +0 -0
  71. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/graph_cache.py +0 -0
  72. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/graph_utils.py +0 -0
  73. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/layout/__init__.py +0 -0
  74. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_core/layout/types.py +0 -0
  75. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_engine_specs.py +0 -0
  76. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/_registry.py +0 -0
  77. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/einsum_module/_backend.py +0 -0
  78. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/einsum_module/renderer.py +0 -0
  79. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/py.typed +0 -0
  80. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/quimb/__init__.py +0 -0
  81. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/quimb/graph.py +0 -0
  82. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/quimb/renderer.py +0 -0
  83. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/tenpy/renderer.py +0 -0
  84. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/tensorkrowch/__init__.py +0 -0
  85. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/tensorkrowch/graph.py +0 -0
  86. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/tensorkrowch/renderer.py +0 -0
  87. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/tensornetwork/__init__.py +0 -0
  88. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/tensornetwork/graph.py +0 -0
  89. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/src/tensor_network_viz/tensornetwork/renderer.py +0 -0
  90. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/tests/test_contraction_groups_once.py +0 -0
  91. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/tests/test_edge_index_label_2d.py +0 -0
  92. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/tests/test_edge_index_label_3d.py +0 -0
  93. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/tests/test_graph_cache.py +0 -0
  94. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/tests/test_integration_einsum.py +0 -0
  95. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/tests/test_integration_tensorkrowch.py +0 -0
  96. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/tests/test_integration_tensornetwork.py +0 -0
  97. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/tests/test_label_draw_metrics_perf.py +0 -0
  98. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/tests/test_label_format.py +0 -0
  99. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/tests/test_layout_core.py +0 -0
  100. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/tests/test_node_degrees_perf.py +0 -0
  101. {tensor_network_visualization-1.4.1 → tensor_network_visualization-1.4.2}/tests/test_quimb_backend.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tensor-network-visualization
3
- Version: 1.4.1
3
+ Version: 1.4.2
4
4
  Summary: Minimal Matplotlib visualizations for TensorKrowch, TensorNetwork, Quimb, TeNPy, and traced PyTorch/NumPy einsum tensor networks.
5
5
  Author: Alejandro Mata Ali
6
6
  License: MIT
@@ -19,11 +19,13 @@ Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
20
  Requires-Dist: matplotlib>=3.7
21
21
  Requires-Dist: networkx>=3.0
22
+ Requires-Dist: numpy
22
23
  Provides-Extra: dev
23
24
  Requires-Dist: pytest; extra == "dev"
24
25
  Requires-Dist: ruff; extra == "dev"
25
26
  Requires-Dist: pyright; extra == "dev"
26
27
  Requires-Dist: ipython; extra == "dev"
28
+ Requires-Dist: tomli>=2.0.1; extra == "dev"
27
29
  Requires-Dist: tensorkrowch; extra == "dev"
28
30
  Requires-Dist: tensornetwork; extra == "dev"
29
31
  Requires-Dist: quimb; extra == "dev"
@@ -78,8 +80,11 @@ PyPI package name: `tensor-network-visualization`. Import module: `tensor_networ
78
80
  python -m pip install tensor-network-visualization
79
81
  ```
80
82
 
81
- Depends on `matplotlib` and `networkx` only. You can render **`einsum`** traces built from ordered
82
- `pair_tensor` entries without installing PyTorch.
83
+ Base runtime dependencies are `numpy`, `matplotlib`, and `networkx` only. You can **build and
84
+ render** rich **`einsum`** graphs from ordered **`pair_tensor`** / **`einsum_trace_step`** entries
85
+ (ellipsis and repeated indices need shapes in metadata); **`tensor-network-visualization[einsum]`**
86
+ (PyTorch) is only needed to **execute** `tensor_network_viz.einsum(..., trace=...)` and record
87
+ those rows automatically.
83
88
 
84
89
  ### Optional backends (extras)
85
90
 
@@ -89,7 +94,7 @@ Depends on `matplotlib` and `networkx` only. You can render **`einsum`** traces
89
94
  | TensorNetwork | `tensornetwork` | `pip install "tensor-network-visualization[tensornetwork]"` |
90
95
  | Quimb | `quimb` | `pip install "tensor-network-visualization[quimb]"` |
91
96
  | TeNPy | `tenpy` | Resolves to PyPI package **`physics-tenpy`**. |
92
- | Einsum tracing | `einsum` | Adds **PyTorch** for the traced `einsum` helper. |
97
+ | Einsum tracing | `einsum` | Adds **PyTorch** for auto-traced `einsum(..., trace=...)` (layout from `pair_tensor` / `einsum_trace_step` lists with metadata as needed). |
93
98
  | Jupyter widgets| `jupyter` | `ipympl`, widgets, JupyterLab / Notebook 7+ for interactive figures. |
94
99
 
95
100
  Combine extras, for example:
@@ -148,7 +153,8 @@ Everything below maps to real parameters—there are no hidden mode switches.
148
153
  | **Display mode** | `show=True` / `False` | If `True`: Jupyter **kernel** uses `IPython.display.display(fig)`; otherwise `plt.show()`. If `False`: neither runs—use for `savefig` / batch. |
149
154
  | **Label policy** | `PlotConfig` + overrides | Defaults: `show_tensor_labels`, `show_index_labels`. Per-call: `show_tensor_network(..., show_tensor_labels=..., show_index_labels=...)`. |
150
155
  | **Hover labels** | `PlotConfig(hover_labels=True)` | Tensor names and bond labels appear on pointer hover (2D axes hit-test; 3D screen-space distance). Needs an **interactive** Matplotlib window. |
151
- | **Einsum workflow** | `engine="einsum"` | **Auto:** `EinsumTrace` + `tensor_network_viz.einsum`. **Manual:** ordered list of `pair_tensor(...)`. |
156
+ | **Contraction scheme** | `PlotConfig(show_contraction_scheme=True)` | **Einsum:** cumulative per-step highlights from the trace. **Other engines:** set **`contraction_scheme_by_name`**. **2D:** rounded boxes (AABB + pad); colored borders (no fill by default). **3D:** wireframe box. See **`docs/guide.md`**. |
157
+ | **Einsum workflow** | `engine="einsum"` | **Auto:** `EinsumTrace` + `einsum` (binary `pair_tensor`, unary/ternary+ `einsum_trace_step`; implicit `->`, `out=`). **Manual:** `pair_tensor` / `einsum_trace_step` (ellipsis needs `metadata` shapes). See **`examples/einsum_general.py`**. |
152
158
 
153
159
  ## Minimal examples
154
160
 
@@ -255,14 +261,14 @@ Numeric fields with **`None`** use the corresponding `DEFAULT_*` on the class (s
255
261
 
256
262
  | Field | Default | Role |
257
263
  |-------|---------|------|
258
- | `node_color` | `"#E8E8E8"` | Tensor node fill. |
259
- | `node_edge_color` | `"#2D3748"` | Tensor node outline. |
260
- | `node_color_degree_one` | `"#E8D6D6"` | Fill for tensors with total graph degree 1. |
261
- | `node_edge_color_degree_one` | `"#4A3436"` | Outline for degree-1 tensors. |
262
- | `tensor_label_color` | `"#1A202C"` | Tensor name text. |
263
- | `label_color` | `"#0C1319"` | Index / bond label text. |
264
- | `bond_edge_color` | `"#00008B"` | Contraction edges. |
265
- | `dangling_edge_color` | `"#8B0000"` | Dangling (open) legs. |
264
+ | `node_color` | `"#E8EEF5"` | Tensor node fill. |
265
+ | `node_edge_color` | `"#1E293B"` | Tensor node outline. |
266
+ | `node_color_degree_one` | `"#FEE2E2"` | Fill for tensors with total graph degree 1. |
267
+ | `node_edge_color_degree_one` | `"#7F1D1D"` | Outline for degree-1 tensors. |
268
+ | `tensor_label_color` | `"#0F172A"` | Tensor name text. |
269
+ | `label_color` | `"#334155"` | Index / bond label text. |
270
+ | `bond_edge_color` | `"#0369A1"` | Contraction edges. |
271
+ | `dangling_edge_color` | `"#BE123C"` | Dangling (open) legs. |
266
272
  | `figsize` | `(8, 6)` | `inches`; `None` uses Matplotlib fallback `(14, 10)` when the renderer creates a new figure. |
267
273
  | `show_tensor_labels` | `True` | Draw tensor names on nodes. |
268
274
  | `show_index_labels` | `True` | Draw axis names on bonds / stubs. |
@@ -290,6 +296,7 @@ from tensor_network_viz import (
290
296
  PlotConfig,
291
297
  ViewName,
292
298
  einsum,
299
+ einsum_trace_step,
293
300
  pair_tensor,
294
301
  show_tensor_network,
295
302
  )
@@ -301,10 +308,21 @@ Per-backend plotters (optional; same as `show_tensor_network` internals):
301
308
  from tensor_network_viz.tensorkrowch import plot_tensorkrowch_network_2d, plot_tensorkrowch_network_3d
302
309
  from tensor_network_viz.tensornetwork import plot_tensornetwork_network_2d, plot_tensornetwork_network_3d
303
310
  from tensor_network_viz.quimb import plot_quimb_network_2d, plot_quimb_network_3d
304
- from tensor_network_viz.tenpy import plot_tenpy_network_2d, plot_tenpy_network_3d
305
- from tensor_network_viz.einsum_module import plot_einsum_network_2d, plot_einsum_network_3d
311
+ from tensor_network_viz.tenpy import (
312
+ make_tenpy_tensor_network,
313
+ plot_tenpy_network_2d,
314
+ plot_tenpy_network_3d,
315
+ )
316
+ from tensor_network_viz.einsum_module import (
317
+ parse_einsum_equation,
318
+ parse_equation_for_shapes,
319
+ plot_einsum_network_2d,
320
+ plot_einsum_network_3d,
321
+ )
306
322
  ```
307
323
 
324
+ (`parse_equation_for_shapes` — binary only; `parse_einsum_equation` — any arity, NumPy-validated.)
325
+
308
326
  ## Accepted inputs (summary)
309
327
 
310
328
  | Backend | Input |
@@ -312,8 +330,8 @@ from tensor_network_viz.einsum_module import plot_einsum_network_2d, plot_einsum
312
330
  | tensorkrowch | Network with `nodes` / `leaf_nodes`, or iterable of nodes |
313
331
  | tensornetwork | Iterable of `tensornetwork.Node` |
314
332
  | quimb | `TensorNetwork` or iterable of `Tensor` |
315
- | tenpy | Finite/segment/infinite `MPS`, finite/infinite `MPO` |
316
- | einsum | `EinsumTrace` or ordered iterable of `pair_tensor` |
333
+ | tenpy | `TenPyTensorNetwork` / `make_tenpy_tensor_network` (`npc.Array` + bonds); `MPS`, `MPO`, `MomentumMPS`-like; no stable TeNPy PEPS class (hand-built TN ok) |
334
+ | einsum | `EinsumTrace` or ordered iterable of `pair_tensor` / `einsum_trace_step` (ellipsis / hyperedges in the normalized graph) |
317
335
 
318
336
  Details, subgraph behavior, and Quimb hyperindex hubs are in **[docs/guide.md](docs/guide.md)**.
319
337
 
@@ -329,8 +347,10 @@ Runnable demos live under **`examples/`**. From the repo root with the right ext
329
347
  | `mera_tree_demo.py` | Large MERA + binary TTN stress test. |
330
348
  | `cubic_peps_demo.py` | 3D cubic PEPS lattice. |
331
349
  | `quimb_demo.py` | Includes hyper-index example; `--from-list`. |
332
- | `tenpy_demo.py` | Finite and infinite MPS/MPO. |
350
+ | `tenpy_demo.py` | MPS/MPO, purification, uniform, excitation chain (duck-typed like `MomentumMPS`). |
351
+ | `tenpy_explicit_tn_demo.py` | Explicit `TenPyTensorNetwork`: open chain or 3-way hub ([examples/README](examples/README.md)). |
333
352
  | `einsum_demo.py` | Auto trace vs manual `pair_tensor`. |
353
+ | `einsum_general.py` | Ellipsis, batch hubs, multi-step fusion, traces, short MPS, implicit/`out=`, unary, ternary (auto-trace). |
334
354
  | `tn_tsp.py` | Larger TensorKrowch TSP construction. |
335
355
 
336
356
  Catalog and one-liner commands: **[examples/README.md](examples/README.md)**.
@@ -340,7 +360,14 @@ Catalog and one-liner commands: **[examples/README.md](examples/README.md)**.
340
360
  - Quimb **hyper-indices** (three or more tensors) are drawn via internal virtual hubs.
341
361
  - Infinite TeNPy **MPS/MPO** use one periodic unit cell.
342
362
  - The **einsum** backend visualizes the **fundamental** tensor network, not each intermediate
343
- contraction tensor.
363
+ contraction tensor. Pairwise summed indices are drawn as ordinary bonds; repeated or
364
+ output-carrying indices use **virtual hubs** (layout separates colocated hubs, nudges **2D**
365
+ hubs that attach to **one** tensor only—e.g. **`ii->i`**—off that tensor, and offsets hubs on a
366
+ tensor–tensor chord when a **direct** bond also links that pair).
367
+ - Optional **`contraction_steps`** from **einsum**: **running union** of operand physical lineages
368
+ (each step is a superset of the previous); **`PlotConfig`** draws per-step **AABB** highlights
369
+ (**2D:** rounded rectangles; **3D:** wireframe), colored borders (no fill by default), extra
370
+ padding as steps advance, and later steps underneath.
344
371
  - Passing a **subset** of nodes/tensors shows connections outside the subset as **dangling** legs.
345
372
 
346
373
  ## Quick verification (reviewers)
@@ -362,6 +389,7 @@ Expect `quimb_mps.png` and all tests passing.
362
389
  | Blank or double figure in Jupyter | Assign `fig, ax = show_tensor_network(...)`; avoid bare tuple as last line; try `%matplotlib widget` or inline. |
363
390
  | Hover labels do nothing | Requires interactive backend and `show` path that runs a GUI or widget event loop; not for `--no-show` PNG only. |
364
391
  | Huge graphs are slow | `PlotConfig(refine_tensor_labels=False)`; lower `layout_iterations` or pass `positions`. Force layout samples repulsion when node count is large (about 72+; see [guide](docs/guide.md#layout-and-draw-scale)). |
392
+ | Einsum unary trace (`ii->i`) looks odd in 2D | Layout offsets the virtual hub off the tensor in 2D; try `view="3d"` or read [Einsum unary / same-tensor trace in 2D](docs/guide.md#toc-einsum-unary-2d-layout) in the guide. |
365
393
 
366
394
  **Full troubleshooting:** [docs/guide.md — Troubleshooting](docs/guide.md#troubleshooting).
367
395
 
@@ -31,8 +31,11 @@ PyPI package name: `tensor-network-visualization`. Import module: `tensor_networ
31
31
  python -m pip install tensor-network-visualization
32
32
  ```
33
33
 
34
- Depends on `matplotlib` and `networkx` only. You can render **`einsum`** traces built from ordered
35
- `pair_tensor` entries without installing PyTorch.
34
+ Base runtime dependencies are `numpy`, `matplotlib`, and `networkx` only. You can **build and
35
+ render** rich **`einsum`** graphs from ordered **`pair_tensor`** / **`einsum_trace_step`** entries
36
+ (ellipsis and repeated indices need shapes in metadata); **`tensor-network-visualization[einsum]`**
37
+ (PyTorch) is only needed to **execute** `tensor_network_viz.einsum(..., trace=...)` and record
38
+ those rows automatically.
36
39
 
37
40
  ### Optional backends (extras)
38
41
 
@@ -42,7 +45,7 @@ Depends on `matplotlib` and `networkx` only. You can render **`einsum`** traces
42
45
  | TensorNetwork | `tensornetwork` | `pip install "tensor-network-visualization[tensornetwork]"` |
43
46
  | Quimb | `quimb` | `pip install "tensor-network-visualization[quimb]"` |
44
47
  | TeNPy | `tenpy` | Resolves to PyPI package **`physics-tenpy`**. |
45
- | Einsum tracing | `einsum` | Adds **PyTorch** for the traced `einsum` helper. |
48
+ | Einsum tracing | `einsum` | Adds **PyTorch** for auto-traced `einsum(..., trace=...)` (layout from `pair_tensor` / `einsum_trace_step` lists with metadata as needed). |
46
49
  | Jupyter widgets| `jupyter` | `ipympl`, widgets, JupyterLab / Notebook 7+ for interactive figures. |
47
50
 
48
51
  Combine extras, for example:
@@ -101,7 +104,8 @@ Everything below maps to real parameters—there are no hidden mode switches.
101
104
  | **Display mode** | `show=True` / `False` | If `True`: Jupyter **kernel** uses `IPython.display.display(fig)`; otherwise `plt.show()`. If `False`: neither runs—use for `savefig` / batch. |
102
105
  | **Label policy** | `PlotConfig` + overrides | Defaults: `show_tensor_labels`, `show_index_labels`. Per-call: `show_tensor_network(..., show_tensor_labels=..., show_index_labels=...)`. |
103
106
  | **Hover labels** | `PlotConfig(hover_labels=True)` | Tensor names and bond labels appear on pointer hover (2D axes hit-test; 3D screen-space distance). Needs an **interactive** Matplotlib window. |
104
- | **Einsum workflow** | `engine="einsum"` | **Auto:** `EinsumTrace` + `tensor_network_viz.einsum`. **Manual:** ordered list of `pair_tensor(...)`. |
107
+ | **Contraction scheme** | `PlotConfig(show_contraction_scheme=True)` | **Einsum:** cumulative per-step highlights from the trace. **Other engines:** set **`contraction_scheme_by_name`**. **2D:** rounded boxes (AABB + pad); colored borders (no fill by default). **3D:** wireframe box. See **`docs/guide.md`**. |
108
+ | **Einsum workflow** | `engine="einsum"` | **Auto:** `EinsumTrace` + `einsum` (binary `pair_tensor`, unary/ternary+ `einsum_trace_step`; implicit `->`, `out=`). **Manual:** `pair_tensor` / `einsum_trace_step` (ellipsis needs `metadata` shapes). See **`examples/einsum_general.py`**. |
105
109
 
106
110
  ## Minimal examples
107
111
 
@@ -208,14 +212,14 @@ Numeric fields with **`None`** use the corresponding `DEFAULT_*` on the class (s
208
212
 
209
213
  | Field | Default | Role |
210
214
  |-------|---------|------|
211
- | `node_color` | `"#E8E8E8"` | Tensor node fill. |
212
- | `node_edge_color` | `"#2D3748"` | Tensor node outline. |
213
- | `node_color_degree_one` | `"#E8D6D6"` | Fill for tensors with total graph degree 1. |
214
- | `node_edge_color_degree_one` | `"#4A3436"` | Outline for degree-1 tensors. |
215
- | `tensor_label_color` | `"#1A202C"` | Tensor name text. |
216
- | `label_color` | `"#0C1319"` | Index / bond label text. |
217
- | `bond_edge_color` | `"#00008B"` | Contraction edges. |
218
- | `dangling_edge_color` | `"#8B0000"` | Dangling (open) legs. |
215
+ | `node_color` | `"#E8EEF5"` | Tensor node fill. |
216
+ | `node_edge_color` | `"#1E293B"` | Tensor node outline. |
217
+ | `node_color_degree_one` | `"#FEE2E2"` | Fill for tensors with total graph degree 1. |
218
+ | `node_edge_color_degree_one` | `"#7F1D1D"` | Outline for degree-1 tensors. |
219
+ | `tensor_label_color` | `"#0F172A"` | Tensor name text. |
220
+ | `label_color` | `"#334155"` | Index / bond label text. |
221
+ | `bond_edge_color` | `"#0369A1"` | Contraction edges. |
222
+ | `dangling_edge_color` | `"#BE123C"` | Dangling (open) legs. |
219
223
  | `figsize` | `(8, 6)` | `inches`; `None` uses Matplotlib fallback `(14, 10)` when the renderer creates a new figure. |
220
224
  | `show_tensor_labels` | `True` | Draw tensor names on nodes. |
221
225
  | `show_index_labels` | `True` | Draw axis names on bonds / stubs. |
@@ -243,6 +247,7 @@ from tensor_network_viz import (
243
247
  PlotConfig,
244
248
  ViewName,
245
249
  einsum,
250
+ einsum_trace_step,
246
251
  pair_tensor,
247
252
  show_tensor_network,
248
253
  )
@@ -254,10 +259,21 @@ Per-backend plotters (optional; same as `show_tensor_network` internals):
254
259
  from tensor_network_viz.tensorkrowch import plot_tensorkrowch_network_2d, plot_tensorkrowch_network_3d
255
260
  from tensor_network_viz.tensornetwork import plot_tensornetwork_network_2d, plot_tensornetwork_network_3d
256
261
  from tensor_network_viz.quimb import plot_quimb_network_2d, plot_quimb_network_3d
257
- from tensor_network_viz.tenpy import plot_tenpy_network_2d, plot_tenpy_network_3d
258
- from tensor_network_viz.einsum_module import plot_einsum_network_2d, plot_einsum_network_3d
262
+ from tensor_network_viz.tenpy import (
263
+ make_tenpy_tensor_network,
264
+ plot_tenpy_network_2d,
265
+ plot_tenpy_network_3d,
266
+ )
267
+ from tensor_network_viz.einsum_module import (
268
+ parse_einsum_equation,
269
+ parse_equation_for_shapes,
270
+ plot_einsum_network_2d,
271
+ plot_einsum_network_3d,
272
+ )
259
273
  ```
260
274
 
275
+ (`parse_equation_for_shapes` — binary only; `parse_einsum_equation` — any arity, NumPy-validated.)
276
+
261
277
  ## Accepted inputs (summary)
262
278
 
263
279
  | Backend | Input |
@@ -265,8 +281,8 @@ from tensor_network_viz.einsum_module import plot_einsum_network_2d, plot_einsum
265
281
  | tensorkrowch | Network with `nodes` / `leaf_nodes`, or iterable of nodes |
266
282
  | tensornetwork | Iterable of `tensornetwork.Node` |
267
283
  | quimb | `TensorNetwork` or iterable of `Tensor` |
268
- | tenpy | Finite/segment/infinite `MPS`, finite/infinite `MPO` |
269
- | einsum | `EinsumTrace` or ordered iterable of `pair_tensor` |
284
+ | tenpy | `TenPyTensorNetwork` / `make_tenpy_tensor_network` (`npc.Array` + bonds); `MPS`, `MPO`, `MomentumMPS`-like; no stable TeNPy PEPS class (hand-built TN ok) |
285
+ | einsum | `EinsumTrace` or ordered iterable of `pair_tensor` / `einsum_trace_step` (ellipsis / hyperedges in the normalized graph) |
270
286
 
271
287
  Details, subgraph behavior, and Quimb hyperindex hubs are in **[docs/guide.md](docs/guide.md)**.
272
288
 
@@ -282,8 +298,10 @@ Runnable demos live under **`examples/`**. From the repo root with the right ext
282
298
  | `mera_tree_demo.py` | Large MERA + binary TTN stress test. |
283
299
  | `cubic_peps_demo.py` | 3D cubic PEPS lattice. |
284
300
  | `quimb_demo.py` | Includes hyper-index example; `--from-list`. |
285
- | `tenpy_demo.py` | Finite and infinite MPS/MPO. |
301
+ | `tenpy_demo.py` | MPS/MPO, purification, uniform, excitation chain (duck-typed like `MomentumMPS`). |
302
+ | `tenpy_explicit_tn_demo.py` | Explicit `TenPyTensorNetwork`: open chain or 3-way hub ([examples/README](examples/README.md)). |
286
303
  | `einsum_demo.py` | Auto trace vs manual `pair_tensor`. |
304
+ | `einsum_general.py` | Ellipsis, batch hubs, multi-step fusion, traces, short MPS, implicit/`out=`, unary, ternary (auto-trace). |
287
305
  | `tn_tsp.py` | Larger TensorKrowch TSP construction. |
288
306
 
289
307
  Catalog and one-liner commands: **[examples/README.md](examples/README.md)**.
@@ -293,7 +311,14 @@ Catalog and one-liner commands: **[examples/README.md](examples/README.md)**.
293
311
  - Quimb **hyper-indices** (three or more tensors) are drawn via internal virtual hubs.
294
312
  - Infinite TeNPy **MPS/MPO** use one periodic unit cell.
295
313
  - The **einsum** backend visualizes the **fundamental** tensor network, not each intermediate
296
- contraction tensor.
314
+ contraction tensor. Pairwise summed indices are drawn as ordinary bonds; repeated or
315
+ output-carrying indices use **virtual hubs** (layout separates colocated hubs, nudges **2D**
316
+ hubs that attach to **one** tensor only—e.g. **`ii->i`**—off that tensor, and offsets hubs on a
317
+ tensor–tensor chord when a **direct** bond also links that pair).
318
+ - Optional **`contraction_steps`** from **einsum**: **running union** of operand physical lineages
319
+ (each step is a superset of the previous); **`PlotConfig`** draws per-step **AABB** highlights
320
+ (**2D:** rounded rectangles; **3D:** wireframe), colored borders (no fill by default), extra
321
+ padding as steps advance, and later steps underneath.
297
322
  - Passing a **subset** of nodes/tensors shows connections outside the subset as **dangling** legs.
298
323
 
299
324
  ## Quick verification (reviewers)
@@ -315,6 +340,7 @@ Expect `quimb_mps.png` and all tests passing.
315
340
  | Blank or double figure in Jupyter | Assign `fig, ax = show_tensor_network(...)`; avoid bare tuple as last line; try `%matplotlib widget` or inline. |
316
341
  | Hover labels do nothing | Requires interactive backend and `show` path that runs a GUI or widget event loop; not for `--no-show` PNG only. |
317
342
  | Huge graphs are slow | `PlotConfig(refine_tensor_labels=False)`; lower `layout_iterations` or pass `positions`. Force layout samples repulsion when node count is large (about 72+; see [guide](docs/guide.md#layout-and-draw-scale)). |
343
+ | Einsum unary trace (`ii->i`) looks odd in 2D | Layout offsets the virtual hub off the tensor in 2D; try `view="3d"` or read [Einsum unary / same-tensor trace in 2D](docs/guide.md#toc-einsum-unary-2d-layout) in the guide. |
318
344
 
319
345
  **Full troubleshooting:** [docs/guide.md — Troubleshooting](docs/guide.md#troubleshooting).
320
346
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "tensor-network-visualization"
7
- version = "1.4.1"
7
+ version = "1.4.2"
8
8
  description = "Minimal Matplotlib visualizations for TensorKrowch, TensorNetwork, Quimb, TeNPy, and traced PyTorch/NumPy einsum tensor networks."
9
9
  authors = [{ name = "Alejandro Mata Ali" }]
10
10
  readme = "README.md"
@@ -14,6 +14,7 @@ keywords = ["tensor-network", "visualization", "pytorch", "numpy", "tensorkrowch
14
14
  dependencies = [
15
15
  "matplotlib>=3.7",
16
16
  "networkx>=3.0",
17
+ "numpy",
17
18
  ]
18
19
  classifiers = [
19
20
  "License :: OSI Approved :: MIT License",
@@ -30,7 +31,7 @@ Repository = "https://github.com/DOKOS-TAYOS/Tensor-Network-Visualization"
30
31
  Issues = "https://github.com/DOKOS-TAYOS/Tensor-Network-Visualization/issues"
31
32
 
32
33
  [project.optional-dependencies]
33
- dev = ["pytest", "ruff", "pyright", "ipython", "tensorkrowch", "tensornetwork", "quimb", "physics-tenpy"]
34
+ dev = ["pytest", "ruff", "pyright", "ipython", "tomli>=2.0.1", "tensorkrowch", "tensornetwork", "quimb", "physics-tenpy"]
34
35
  jupyter = ["ipympl>=0.9.0", "ipywidgets>=8.0", "jupyterlab>=4.0", "notebook>=7.0"]
35
36
  tensorkrowch = ["tensorkrowch"]
36
37
  tensornetwork = ["tensornetwork"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tensor-network-visualization
3
- Version: 1.4.1
3
+ Version: 1.4.2
4
4
  Summary: Minimal Matplotlib visualizations for TensorKrowch, TensorNetwork, Quimb, TeNPy, and traced PyTorch/NumPy einsum tensor networks.
5
5
  Author: Alejandro Mata Ali
6
6
  License: MIT
@@ -19,11 +19,13 @@ Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
20
  Requires-Dist: matplotlib>=3.7
21
21
  Requires-Dist: networkx>=3.0
22
+ Requires-Dist: numpy
22
23
  Provides-Extra: dev
23
24
  Requires-Dist: pytest; extra == "dev"
24
25
  Requires-Dist: ruff; extra == "dev"
25
26
  Requires-Dist: pyright; extra == "dev"
26
27
  Requires-Dist: ipython; extra == "dev"
28
+ Requires-Dist: tomli>=2.0.1; extra == "dev"
27
29
  Requires-Dist: tensorkrowch; extra == "dev"
28
30
  Requires-Dist: tensornetwork; extra == "dev"
29
31
  Requires-Dist: quimb; extra == "dev"
@@ -78,8 +80,11 @@ PyPI package name: `tensor-network-visualization`. Import module: `tensor_networ
78
80
  python -m pip install tensor-network-visualization
79
81
  ```
80
82
 
81
- Depends on `matplotlib` and `networkx` only. You can render **`einsum`** traces built from ordered
82
- `pair_tensor` entries without installing PyTorch.
83
+ Base runtime dependencies are `numpy`, `matplotlib`, and `networkx` only. You can **build and
84
+ render** rich **`einsum`** graphs from ordered **`pair_tensor`** / **`einsum_trace_step`** entries
85
+ (ellipsis and repeated indices need shapes in metadata); **`tensor-network-visualization[einsum]`**
86
+ (PyTorch) is only needed to **execute** `tensor_network_viz.einsum(..., trace=...)` and record
87
+ those rows automatically.
83
88
 
84
89
  ### Optional backends (extras)
85
90
 
@@ -89,7 +94,7 @@ Depends on `matplotlib` and `networkx` only. You can render **`einsum`** traces
89
94
  | TensorNetwork | `tensornetwork` | `pip install "tensor-network-visualization[tensornetwork]"` |
90
95
  | Quimb | `quimb` | `pip install "tensor-network-visualization[quimb]"` |
91
96
  | TeNPy | `tenpy` | Resolves to PyPI package **`physics-tenpy`**. |
92
- | Einsum tracing | `einsum` | Adds **PyTorch** for the traced `einsum` helper. |
97
+ | Einsum tracing | `einsum` | Adds **PyTorch** for auto-traced `einsum(..., trace=...)` (layout from `pair_tensor` / `einsum_trace_step` lists with metadata as needed). |
93
98
  | Jupyter widgets| `jupyter` | `ipympl`, widgets, JupyterLab / Notebook 7+ for interactive figures. |
94
99
 
95
100
  Combine extras, for example:
@@ -148,7 +153,8 @@ Everything below maps to real parameters—there are no hidden mode switches.
148
153
  | **Display mode** | `show=True` / `False` | If `True`: Jupyter **kernel** uses `IPython.display.display(fig)`; otherwise `plt.show()`. If `False`: neither runs—use for `savefig` / batch. |
149
154
  | **Label policy** | `PlotConfig` + overrides | Defaults: `show_tensor_labels`, `show_index_labels`. Per-call: `show_tensor_network(..., show_tensor_labels=..., show_index_labels=...)`. |
150
155
  | **Hover labels** | `PlotConfig(hover_labels=True)` | Tensor names and bond labels appear on pointer hover (2D axes hit-test; 3D screen-space distance). Needs an **interactive** Matplotlib window. |
151
- | **Einsum workflow** | `engine="einsum"` | **Auto:** `EinsumTrace` + `tensor_network_viz.einsum`. **Manual:** ordered list of `pair_tensor(...)`. |
156
+ | **Contraction scheme** | `PlotConfig(show_contraction_scheme=True)` | **Einsum:** cumulative per-step highlights from the trace. **Other engines:** set **`contraction_scheme_by_name`**. **2D:** rounded boxes (AABB + pad); colored borders (no fill by default). **3D:** wireframe box. See **`docs/guide.md`**. |
157
+ | **Einsum workflow** | `engine="einsum"` | **Auto:** `EinsumTrace` + `einsum` (binary `pair_tensor`, unary/ternary+ `einsum_trace_step`; implicit `->`, `out=`). **Manual:** `pair_tensor` / `einsum_trace_step` (ellipsis needs `metadata` shapes). See **`examples/einsum_general.py`**. |
152
158
 
153
159
  ## Minimal examples
154
160
 
@@ -255,14 +261,14 @@ Numeric fields with **`None`** use the corresponding `DEFAULT_*` on the class (s
255
261
 
256
262
  | Field | Default | Role |
257
263
  |-------|---------|------|
258
- | `node_color` | `"#E8E8E8"` | Tensor node fill. |
259
- | `node_edge_color` | `"#2D3748"` | Tensor node outline. |
260
- | `node_color_degree_one` | `"#E8D6D6"` | Fill for tensors with total graph degree 1. |
261
- | `node_edge_color_degree_one` | `"#4A3436"` | Outline for degree-1 tensors. |
262
- | `tensor_label_color` | `"#1A202C"` | Tensor name text. |
263
- | `label_color` | `"#0C1319"` | Index / bond label text. |
264
- | `bond_edge_color` | `"#00008B"` | Contraction edges. |
265
- | `dangling_edge_color` | `"#8B0000"` | Dangling (open) legs. |
264
+ | `node_color` | `"#E8EEF5"` | Tensor node fill. |
265
+ | `node_edge_color` | `"#1E293B"` | Tensor node outline. |
266
+ | `node_color_degree_one` | `"#FEE2E2"` | Fill for tensors with total graph degree 1. |
267
+ | `node_edge_color_degree_one` | `"#7F1D1D"` | Outline for degree-1 tensors. |
268
+ | `tensor_label_color` | `"#0F172A"` | Tensor name text. |
269
+ | `label_color` | `"#334155"` | Index / bond label text. |
270
+ | `bond_edge_color` | `"#0369A1"` | Contraction edges. |
271
+ | `dangling_edge_color` | `"#BE123C"` | Dangling (open) legs. |
266
272
  | `figsize` | `(8, 6)` | `inches`; `None` uses Matplotlib fallback `(14, 10)` when the renderer creates a new figure. |
267
273
  | `show_tensor_labels` | `True` | Draw tensor names on nodes. |
268
274
  | `show_index_labels` | `True` | Draw axis names on bonds / stubs. |
@@ -290,6 +296,7 @@ from tensor_network_viz import (
290
296
  PlotConfig,
291
297
  ViewName,
292
298
  einsum,
299
+ einsum_trace_step,
293
300
  pair_tensor,
294
301
  show_tensor_network,
295
302
  )
@@ -301,10 +308,21 @@ Per-backend plotters (optional; same as `show_tensor_network` internals):
301
308
  from tensor_network_viz.tensorkrowch import plot_tensorkrowch_network_2d, plot_tensorkrowch_network_3d
302
309
  from tensor_network_viz.tensornetwork import plot_tensornetwork_network_2d, plot_tensornetwork_network_3d
303
310
  from tensor_network_viz.quimb import plot_quimb_network_2d, plot_quimb_network_3d
304
- from tensor_network_viz.tenpy import plot_tenpy_network_2d, plot_tenpy_network_3d
305
- from tensor_network_viz.einsum_module import plot_einsum_network_2d, plot_einsum_network_3d
311
+ from tensor_network_viz.tenpy import (
312
+ make_tenpy_tensor_network,
313
+ plot_tenpy_network_2d,
314
+ plot_tenpy_network_3d,
315
+ )
316
+ from tensor_network_viz.einsum_module import (
317
+ parse_einsum_equation,
318
+ parse_equation_for_shapes,
319
+ plot_einsum_network_2d,
320
+ plot_einsum_network_3d,
321
+ )
306
322
  ```
307
323
 
324
+ (`parse_equation_for_shapes` — binary only; `parse_einsum_equation` — any arity, NumPy-validated.)
325
+
308
326
  ## Accepted inputs (summary)
309
327
 
310
328
  | Backend | Input |
@@ -312,8 +330,8 @@ from tensor_network_viz.einsum_module import plot_einsum_network_2d, plot_einsum
312
330
  | tensorkrowch | Network with `nodes` / `leaf_nodes`, or iterable of nodes |
313
331
  | tensornetwork | Iterable of `tensornetwork.Node` |
314
332
  | quimb | `TensorNetwork` or iterable of `Tensor` |
315
- | tenpy | Finite/segment/infinite `MPS`, finite/infinite `MPO` |
316
- | einsum | `EinsumTrace` or ordered iterable of `pair_tensor` |
333
+ | tenpy | `TenPyTensorNetwork` / `make_tenpy_tensor_network` (`npc.Array` + bonds); `MPS`, `MPO`, `MomentumMPS`-like; no stable TeNPy PEPS class (hand-built TN ok) |
334
+ | einsum | `EinsumTrace` or ordered iterable of `pair_tensor` / `einsum_trace_step` (ellipsis / hyperedges in the normalized graph) |
317
335
 
318
336
  Details, subgraph behavior, and Quimb hyperindex hubs are in **[docs/guide.md](docs/guide.md)**.
319
337
 
@@ -329,8 +347,10 @@ Runnable demos live under **`examples/`**. From the repo root with the right ext
329
347
  | `mera_tree_demo.py` | Large MERA + binary TTN stress test. |
330
348
  | `cubic_peps_demo.py` | 3D cubic PEPS lattice. |
331
349
  | `quimb_demo.py` | Includes hyper-index example; `--from-list`. |
332
- | `tenpy_demo.py` | Finite and infinite MPS/MPO. |
350
+ | `tenpy_demo.py` | MPS/MPO, purification, uniform, excitation chain (duck-typed like `MomentumMPS`). |
351
+ | `tenpy_explicit_tn_demo.py` | Explicit `TenPyTensorNetwork`: open chain or 3-way hub ([examples/README](examples/README.md)). |
333
352
  | `einsum_demo.py` | Auto trace vs manual `pair_tensor`. |
353
+ | `einsum_general.py` | Ellipsis, batch hubs, multi-step fusion, traces, short MPS, implicit/`out=`, unary, ternary (auto-trace). |
334
354
  | `tn_tsp.py` | Larger TensorKrowch TSP construction. |
335
355
 
336
356
  Catalog and one-liner commands: **[examples/README.md](examples/README.md)**.
@@ -340,7 +360,14 @@ Catalog and one-liner commands: **[examples/README.md](examples/README.md)**.
340
360
  - Quimb **hyper-indices** (three or more tensors) are drawn via internal virtual hubs.
341
361
  - Infinite TeNPy **MPS/MPO** use one periodic unit cell.
342
362
  - The **einsum** backend visualizes the **fundamental** tensor network, not each intermediate
343
- contraction tensor.
363
+ contraction tensor. Pairwise summed indices are drawn as ordinary bonds; repeated or
364
+ output-carrying indices use **virtual hubs** (layout separates colocated hubs, nudges **2D**
365
+ hubs that attach to **one** tensor only—e.g. **`ii->i`**—off that tensor, and offsets hubs on a
366
+ tensor–tensor chord when a **direct** bond also links that pair).
367
+ - Optional **`contraction_steps`** from **einsum**: **running union** of operand physical lineages
368
+ (each step is a superset of the previous); **`PlotConfig`** draws per-step **AABB** highlights
369
+ (**2D:** rounded rectangles; **3D:** wireframe), colored borders (no fill by default), extra
370
+ padding as steps advance, and later steps underneath.
344
371
  - Passing a **subset** of nodes/tensors shows connections outside the subset as **dangling** legs.
345
372
 
346
373
  ## Quick verification (reviewers)
@@ -362,6 +389,7 @@ Expect `quimb_mps.png` and all tests passing.
362
389
  | Blank or double figure in Jupyter | Assign `fig, ax = show_tensor_network(...)`; avoid bare tuple as last line; try `%matplotlib widget` or inline. |
363
390
  | Hover labels do nothing | Requires interactive backend and `show` path that runs a GUI or widget event loop; not for `--no-show` PNG only. |
364
391
  | Huge graphs are slow | `PlotConfig(refine_tensor_labels=False)`; lower `layout_iterations` or pass `positions`. Force layout samples repulsion when node count is large (about 72+; see [guide](docs/guide.md#layout-and-draw-scale)). |
392
+ | Einsum unary trace (`ii->i`) looks odd in 2D | Layout offsets the virtual hub off the tensor in 2D; try `view="3d"` or read [Einsum unary / same-tensor trace in 2D](docs/guide.md#toc-einsum-unary-2d-layout) in the guide. |
365
393
 
366
394
  **Full troubleshooting:** [docs/guide.md — Troubleshooting](docs/guide.md#troubleshooting).
367
395
 
@@ -26,6 +26,7 @@ src/tensor_network_viz/_core/layout_structure.py
26
26
  src/tensor_network_viz/_core/renderer.py
27
27
  src/tensor_network_viz/_core/draw/__init__.py
28
28
  src/tensor_network_viz/_core/draw/constants.py
29
+ src/tensor_network_viz/_core/draw/contraction_scheme.py
29
30
  src/tensor_network_viz/_core/draw/disk_metrics.py
30
31
  src/tensor_network_viz/_core/draw/edges.py
31
32
  src/tensor_network_viz/_core/draw/fonts_and_scale.py
@@ -54,6 +55,7 @@ src/tensor_network_viz/quimb/__init__.py
54
55
  src/tensor_network_viz/quimb/graph.py
55
56
  src/tensor_network_viz/quimb/renderer.py
56
57
  src/tensor_network_viz/tenpy/__init__.py
58
+ src/tensor_network_viz/tenpy/explicit.py
57
59
  src/tensor_network_viz/tenpy/graph.py
58
60
  src/tensor_network_viz/tenpy/renderer.py
59
61
  src/tensor_network_viz/tensorkrowch/__init__.py
@@ -63,22 +65,24 @@ src/tensor_network_viz/tensornetwork/__init__.py
63
65
  src/tensor_network_viz/tensornetwork/graph.py
64
66
  src/tensor_network_viz/tensornetwork/renderer.py
65
67
  tests/test_contraction_groups_once.py
68
+ tests/test_contraction_scheme.py
69
+ tests/test_demo_cli_scheme.py
66
70
  tests/test_draw_performance.py
67
71
  tests/test_edge_index_label_2d.py
68
72
  tests/test_edge_index_label_3d.py
69
73
  tests/test_einsum_autotrace.py
70
74
  tests/test_einsum_backend.py
71
75
  tests/test_examples.py
76
+ tests/test_examples_structure.py
72
77
  tests/test_graph_cache.py
73
78
  tests/test_integration_einsum.py
74
- tests/test_integration_quimb.py
75
- tests/test_integration_tenpy.py
76
79
  tests/test_integration_tensorkrowch.py
77
80
  tests/test_integration_tensornetwork.py
78
81
  tests/test_label_draw_metrics_perf.py
79
82
  tests/test_label_format.py
80
83
  tests/test_layout_core.py
81
84
  tests/test_node_degrees_perf.py
85
+ tests/test_packaging_metadata.py
82
86
  tests/test_plotting.py
83
87
  tests/test_public_api.py
84
88
  tests/test_quimb_backend.py
@@ -1,11 +1,13 @@
1
1
  matplotlib>=3.7
2
2
  networkx>=3.0
3
+ numpy
3
4
 
4
5
  [dev]
5
6
  pytest
6
7
  ruff
7
8
  pyright
8
9
  ipython
10
+ tomli>=2.0.1
9
11
  tensorkrowch
10
12
  tensornetwork
11
13
  quimb
@@ -2,7 +2,8 @@ from typing import TYPE_CHECKING, Any
2
2
 
3
3
  from ._core.graph_cache import clear_tensor_network_graph_cache
4
4
  from .config import EngineName, PlotConfig, ViewName
5
- from .einsum_module.trace import EinsumTrace, einsum, pair_tensor
5
+ from .einsum_module.trace import EinsumTrace, einsum, einsum_trace_step, pair_tensor
6
+ from .tenpy.explicit import TenPyTensorNetwork, make_tenpy_tensor_network
6
7
 
7
8
  if TYPE_CHECKING:
8
9
  from .viewer import show_tensor_network
@@ -18,9 +19,12 @@ __all__ = [
18
19
  "EngineName",
19
20
  "EinsumTrace",
20
21
  "PlotConfig",
22
+ "TenPyTensorNetwork",
21
23
  "ViewName",
22
24
  "clear_tensor_network_graph_cache",
23
25
  "einsum",
26
+ "einsum_trace_step",
27
+ "make_tenpy_tensor_network",
24
28
  "pair_tensor",
25
29
  "show_tensor_network",
26
30
  ]