Skip to content

Add capability to generate diagram: Goldstone diagrams from SeQuant term strings - #582

Open
zhihao-deng wants to merge 1 commit into
masterfrom
zhihao/feature/draw_diagrams
Open

Add capability to generate diagram: Goldstone diagrams from SeQuant term strings#582
zhihao-deng wants to merge 1 commit into
masterfrom
zhihao/feature/draw_diagrams

Conversation

@zhihao-deng

Copy link
Copy Markdown

Adds utilities/diagram_gen/, a standalone Python tool that turns a SeQuant
coupled-cluster term string into a Goldstone diagram PNG.

The term string SeQuant prints is the only input — paste it in, get a diagram out:

python3 csv_diagram.py '2 (f{i_1;μ̃_1} * C{μ̃_1;a_1<i_1>}) * t{a_1<i_1>;i_1}' bubble.png

The renderer understands the CSV/PNO–DF flavour of those strings (PAO→PNO transforms
C, PAO overlaps s, density-fitting auxiliary index Κ) and draws them as overlay
annotations. --no-csv drops every annotation, leaving the textbook CC Goldstone
skeleton.

Python renderer that turns a SeQuant CC term string into a
Goldstone diagram PNG, with the CSV/PNO-DF overlay
(C / CsC boxes, domain superscripts, DF auxiliary label) toggleable
down to the canonical CC skeleton. Includes a batch driver and examples
```

Everything is driven by the **term string** that SeQuant prints — you paste it in, you
get a diagram out. The renderer understands the CSV/PNO–DF flavour of those strings

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

flavour -> flavor

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new standalone Python utility under utilities/diagram_gen/ to parse SeQuant coupled-cluster term strings and render publication-style Goldstone diagrams (PNG), with optional CSV/DF overlay annotations (domains, C/CsC bridges, DF auxiliary K) and a canonical “skeleton-only” mode.

Changes:

  • Introduces csv_diagram.py renderer with CLI + reusable parsing/graph/layout APIs.
  • Adds batch rendering (render_all.py) and automated cleanliness checks (audit_diagrams.py) for large equation files.
  • Documents the term-string format, rendering options, and diagram conventions (plus sample inputs).

Reviewed changes

Copilot reviewed 6 out of 11 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
utilities/diagram_gen/sample_terms.txt Sample SeQuant terms for quick manual testing.
utilities/diagram_gen/render_all.py Batch driver to render full equation markdown sections into PNG sets + index.
utilities/diagram_gen/README.md Usage, options, input format description, and Python API examples.
utilities/diagram_gen/csv-cc-diagram-rules.md Formalized diagram conventions and the “overlay invariance” rule set.
utilities/diagram_gen/csv_diagram.py Core parser/graph builder/layout engine + matplotlib renderer and CLI.
utilities/diagram_gen/audit_diagrams.py Automated audit to detect overlaps/collisions in rendered output.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +79 to +82
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
Comment on lines +313 to +317
hv_pair = None
if len(hvs) == 2:
hv_pair = (hvs[0], hvs[1])
elif len(hvs) > 2:
raise ValueError(">2 interaction half-vertices not supported")
@bimalgaudel

bimalgaudel commented Jul 30, 2026

Copy link
Copy Markdown
Member

I found the following with the help of Claude. (Removed the slop.)


Blocking 1: an ordinary 4-index g is drawn as a one-body vertex

build_graph creates one half-vertex per g tensor (csv_diagram.py:261-263) and never looks
at rank. That's right for DF three-centre factors, but for a normal four-index integral draw
sees len(hvs) == 1, takes the Fock branch (:904-921) and draws a dashed line to an ×.

dg csv_diagram.py '8 * Ŝ{i_1,i_2;a_1,a_2}:N-C-S * g{i_3,a_1;a_3,i_1}:N-S-S * t{a_2,a_3;i_2,i_3}:N-N-S' /tmp/textbook.png

That term is verbatim from tests/unit/test_canonicalize.cpp:271 (spin-free CCSD, already in
the slot convention this tool prefers). You get one dot with four legs joined to an × and a
legend calling it a one-body vertex, no error. It contradicts rules A2 and A3 in your own rules
doc ("each individual half-vertex will have one incoming and one outgoing line"), and since this
is what stock SeQuant emits, it also undercuts the README's claim that --no-csv leaves "the
plain textbook CC Goldstone skeleton".

A2 quotes S&B p.111, "electron 1 ↔ left half-vertex; electron 2 ↔ right half-vertex", so the fix
is to emit two half-vertex nodes for a rank-2 g{p,q;r,s} and route column k to half-vertex
k, roughly 15 lines in build_graph. If that's out of scope for this PR, then rank-2 g has
to raise and the README has to say DF-factorized terms only.

Blocking 2: the opposite bra/ket slot convention reverses every arrow

Hole/particle character comes from the index name (kind_of, :131-141), but flow direction
comes from slot position (build_graph, :301-310). SeQuant doesn't impose one convention, it
round-trips whatever the user built, and both orderings show up as expected canonicalize()
output in a single test file.

dg csv_diagram.py 'Ŝ{a1,a2;i1,i2} f{a3;i3} t{i3;a2} t{i1,i2;a1,a3}' /tmp/flip.png

Verbatim from tests/unit/test_canonicalize.cpp:124. It renders happily: red particle lines
point down, blue hole lines point up, the legend still says "particle line (up) / hole line
(down)", and amplitudes come out as t̂^{i3}_{a2} with occupieds as superscripts. Every Part-A
convention inverted, no error.

Both conventions are self-consistent bra/ket bipartitions, so inference can't tell them apart.
It needs an explicit check: each t should have an all-virtual bra and an all-occupied ket,
Ŝ the reverse. On violation, either raise or transpose everything and re-run.

Major 3: half-vertex pairing ignores the auxiliary index

:313-315 does if len(hvs) == 2: hv_pair = (hvs[0], hvs[1]), pairing on count alone even
though the comment right above says pairing is by shared aux index. Two gs carrying different
aux indices collapse into one dashed vertex:

dg csv_diagram.py 'g{i_1;μ̃_1;Κ_1} * C{μ̃_1;a_1<i_1>} * t{a_1<i_1>;i_1} * g{i_2;μ̃_2;Κ_2} * C{μ̃_2;a_2<i_2>} * t{a_2<i_2>;i_2}' /tmp/two.png

Two disconnected sub-diagrams, joined by a single dashed line. The label on that line is also
the hard-coded string "$K$" (:886, :892); aux is read at :884 but only as a truthiness
test, so Κ_1 and Κ_5 render identically. Copilot flagged the pairing half on :317 already;
this is the empirical confirmation plus the label problem.

Fix: compare the aux indices, raise on mismatch, render _sub(aux) instead of the literal.

One question

Is the intended scope CSV/PNO–DF terms only? That's a perfectly good scope, but then the tool
should reject everything else rather than draw it, and the README and PR title should say so.
The answer decides whether blocking 1 is "implement the split" or "raise and document".

@evaleev

evaleev commented Aug 4, 2026

Copy link
Copy Markdown
Member

@bimalgaudel does this work for unitary CC?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants