supertensor: shape-aware tensor figure toolkit
Extracted from the tensor-formula-viz skill and rebuilt around the idea that the geometry rules should be enforced by construction rather than restated as prose an agent has to remember. - assets/supertensor.sty: faces, stacks, index faces, shared caption lanes, meaning box, signature. Macros take a declared axis and a declared role, so equal shapes get equal edges, a x a is square, a transpose swaps the face, and contracted axes share an edge length -- without any manual alignment. - scripts/preflight.sh: decide the TikZ/CJK path before drawing. - scripts/build.sh: compile and fail on silent corruption (missing CJK glyphs, overfull boxes, undeclared roles), then export pdf/svg/png/thumb. - scripts/test.sh: build every figure as a regression test for the package. - examples/: three golden figures (TP-FFN, causal MHA, MoE top-k gather) plus an anti-pattern gallery of figures that compile cleanly and still lie. - SKILL.md + references/: lean entry point, details loaded on demand.
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
# Anti-patterns
|
||||
|
||||
Every figure below compiles cleanly. `build.sh` is happy with all of them. They are still
|
||||
wrong, because the compiler checks TeX syntax and not whether the picture is true.
|
||||
|
||||
Render `examples/antipatterns.tex` and look at
|
||||
`examples/build/antipatterns.png` once before your first figure.
|
||||
|
||||
## 1. The transpose that only changed its label
|
||||
|
||||
A face captioned `Kᵀ` that is still `T × d_h`. The reader looks for the contracted axis,
|
||||
finds two faces of the same height, and concludes the contraction runs along the wrong
|
||||
dimension. **Fix:** swap the arguments — `\ststack{KT}{...}{dh}{T}{3}`. See `geometry.md` §3.
|
||||
|
||||
## 2. Shards that do not tile their parent
|
||||
|
||||
Two shards drawn with a gap, or stretched to fill a parent whose other shards were elided.
|
||||
Both assert a width that the tensor does not have. **Fix:** place each shard from the
|
||||
previous one's edge (`($(W1a.east)+(2*\stunit,0)$)`), and draw an ellipsis for anything
|
||||
omitted. See `geometry.md` §5–6.
|
||||
|
||||
## 3. An index drawn as a heatmap
|
||||
|
||||
Expert ids or token positions rendered with a lightness ramp. The ramp is a magnitude
|
||||
channel, so it says `expert 3 > expert 0`, which is meaningless. **Fix:** `\stindexface`.
|
||||
See `semantics.md`.
|
||||
|
||||
Same family: a Boolean mask drawn with graded cells (it has one level, not three), and a
|
||||
score matrix drawn as flat blocks (it has magnitude, and hiding it wastes the figure).
|
||||
|
||||
## 4. One pale level everywhere
|
||||
|
||||
A whole tensor in `role!10`. At full size it looks tasteful; at thumbnail size — which is
|
||||
how it will be seen on a slide — it is a blank rectangle. **Fix:** three separated levels,
|
||||
`role!30 / role!55 / role!80`. Contrast comes from lightness, not saturation.
|
||||
See `style.md`.
|
||||
|
||||
## Not in the gallery, but just as common
|
||||
|
||||
- **Periodic texture.** A polynomial hash reduced mod 3 repeats every 3 rows, and the eye
|
||||
reads the resulting stripe as real structure. `pattern=dense` avoids it; if you write
|
||||
your own filler, check that rows 1, 2, 4, 5 of a tall face are not identical.
|
||||
- **A label wider than its connector.** The white underlay then covers the target tensor.
|
||||
Shorten the label or widen the gap — never let it sit on a face. See `layout.md`.
|
||||
- **A new hue for a regrouped view of the same data.** `X` and the per-expert buffers
|
||||
gathered out of `X` are the same object in a different order; a second hue claims they
|
||||
are different tensors.
|
||||
- **Captions hanging at different depths** because the faces in a row have different
|
||||
heights. Use `\stlane`.
|
||||
- **A floating commentary card between two operands.** If it is not a real operation, it
|
||||
belongs in the stage subtitle or the bottom box.
|
||||
- **A meaning box that repeats the shapes.** The shapes are already under every block. The
|
||||
box is for what the axes *mean* and what the operation *does*.
|
||||
- **Solving crowding by shrinking type.** The type hierarchy is a hard floor; move the
|
||||
stage to another row instead.
|
||||
@@ -0,0 +1,103 @@
|
||||
# supertensor.sty API
|
||||
|
||||
```tex
|
||||
\documentclass[border=10pt]{standalone}
|
||||
\usepackage[cjk]{supertensor} % cjk: ctex + fandol (XeLaTeX). en: English rail labels.
|
||||
```
|
||||
|
||||
Build with `./scripts/build.sh fig.tex` — it puts `assets/` on `TEXINPUTS`, so the package
|
||||
does not need to be installed into your texmf tree.
|
||||
|
||||
## Ledgers
|
||||
|
||||
```tex
|
||||
\stsetrole{q}{stTeal} % role -> color. Macros take a ROLE, never a color.
|
||||
\stdim{T}{6} % symbolic axis -> physical edge length in cells
|
||||
\stsetauthor{...} % default 五道口纳什
|
||||
\stsetlabels{A}{O}{M} % override the three meaning-box rail labels
|
||||
\stsetrail{3.2em} % width of the bold label rail
|
||||
```
|
||||
|
||||
Colors: `stTeal stOrange stCoral stViolet stGray stInk`. An unknown role falls back to gray
|
||||
**and emits a package warning**, which `build.sh` turns into a failed build.
|
||||
|
||||
Lengths: `\stunit` (one cell, 4.6 mm) and `\sttilegap` (white gutter, 0.5 mm).
|
||||
|
||||
## Faces
|
||||
|
||||
```tex
|
||||
\stface[keys]{name}{(coord)}{rows}{cols}
|
||||
\ststack[keys]{name}{(coord)}{rows}{cols}{sheets}
|
||||
\stindexface[keys]{name}{(coord)}{rows}{cols}{entries}
|
||||
```
|
||||
|
||||
`rows`/`cols` accept a declared axis name or a raw integer. `(coord)` must include its own
|
||||
parentheses — `{(0,0)}`, `{($(A.east)+(1.5,0)$)}`. `name` becomes a TikZ node you can
|
||||
anchor against; `\ststack` also defines `name-front`.
|
||||
|
||||
Keys:
|
||||
|
||||
| key | default | meaning |
|
||||
|---|---|---|
|
||||
| `role=` | `neutral` | hue, via `\stsetrole` |
|
||||
| `pattern=` | `dense` | `solid dense diag band lower upper causal empty data` |
|
||||
| `data=` | — | with `pattern=data`: comma-separated rows, one digit per cell, `0`–`3` = level |
|
||||
| `level=` | `2` | level for `pattern=solid` and the flat level of a mask |
|
||||
| `bracket=` | `false` | thin neutral matrix brackets |
|
||||
| `border=` | `true` | outer `black!60` border |
|
||||
| `tiles=` | `true` | `false` = one flat filled rectangle |
|
||||
|
||||
`\stindexface` entries are row-major, `rows*cols` of them; `.` leaves a cell blank.
|
||||
It deliberately has no lightness ramp — see `semantics.md`.
|
||||
|
||||
```tex
|
||||
\stface[role=w, pattern=data, level=3,
|
||||
data={3300,0330,0033,3003,3030,0303}]{D}{(0,0)}{T}{E}
|
||||
\stindexface[role=idx]{I}{(b)}{T}{k}{0,1, 1,2, 2,3, 3,0, 0,2, 1,3}
|
||||
```
|
||||
|
||||
## Captions
|
||||
|
||||
```tex
|
||||
\node[inner sep=0pt, fit=(A)(B)(C)] (rowA) {};
|
||||
\stlane{rowA}
|
||||
\stcaption{A}{$\mathbf A$}{$T\times d$} % symbol lane, shape lane
|
||||
\stnolane
|
||||
\stcaptiontop{A}{\stshapefont{token}} % occasional label above a face
|
||||
```
|
||||
|
||||
`\stcaption` defines `name-sym` and `name-shape` nodes; anchor the next stage heading
|
||||
against `name-shape.south`.
|
||||
|
||||
## Operators, connectors, nodes
|
||||
|
||||
```tex
|
||||
\node[st op, right=6mm of A] (m) {$\times$};
|
||||
\node[st comm, right=9mm of P] (ar) {All-Reduce};
|
||||
\starrow{P.east}{ar.west}
|
||||
\starrowlabel{M.east}{A.west}{softmax}
|
||||
```
|
||||
|
||||
Styles: `st sym st shape st stage st op st note st arrow st comm st brace`.
|
||||
Text helpers: `\stformula \ststagelabel \stoperator \stsymfont \stshapefont \stprose`.
|
||||
Connectors route on the background layer automatically.
|
||||
|
||||
## Bottom
|
||||
|
||||
```tex
|
||||
\node[inner sep=0pt, fit=(F)(rowA)(rowB)(Y-shape)] (all) {};
|
||||
\stmeaningbox{mb}{16.6cm}{all}{axes text}{objects text}{mechanism text}
|
||||
\stsignature{因果多头注意力(掩码 + 拼接投影)}{mb}
|
||||
```
|
||||
|
||||
Arg 2 is the total box width; arg 3 is the node it hangs below — include every caption and
|
||||
top label in that `fit` or the box will overlap them. An empty `{}` row is dropped.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- `\ststack` never re-enters `\stface`; if you extend the package, do not pass
|
||||
`role=\st@role` back through pgfkeys — it defines the macro in terms of itself and hangs.
|
||||
- A coordinate expression inside `fit=` needs braces: `fit={(a) ($(b)+(1,0)$)}`.
|
||||
- `\foreach {\macro,...,1}` cannot infer its direction from an unexpanded macro.
|
||||
- `\strole` is expandable on purpose (it is used inside `\edef`); the warning lives in
|
||||
`\stcheckrole`.
|
||||
@@ -0,0 +1,59 @@
|
||||
# Pre-delivery checklist
|
||||
|
||||
A clean `build.sh` proves only that TeX was happy. Nothing below is checked by the compiler.
|
||||
Work through it against the rendered PNG. Any mandatory violation means redraw, not patch.
|
||||
|
||||
## 1. Math (before looking at the picture)
|
||||
|
||||
- [ ] Every shape recomputed independently from the source formula or code.
|
||||
- [ ] Block multiplication, broadcasting, reductions and sharding algebra verified.
|
||||
- [ ] Axis identities that the figure asserts actually hold in the numbers drawn
|
||||
(`d = h·d_h`, `Σ_e n_e = T·k`, shards summing to the parent).
|
||||
|
||||
## 2. Semantics ledger
|
||||
|
||||
- [ ] Every discrete or overloaded symbol has one type, domain and range.
|
||||
- [ ] Score, index and mask are three distinct objects in three distinct grammars.
|
||||
- [ ] Producer-to-consumer chain closed: scores → indices → gather/mask → values.
|
||||
- [ ] Shared selectors drawn once, with the reuse axis marked.
|
||||
|
||||
## 3. Geometry ledger
|
||||
|
||||
- [ ] Equal shapes have identical faces everywhere.
|
||||
- [ ] `a×a` is square; every transpose physically swaps the face.
|
||||
- [ ] Both occurrences of each contracted axis have the same edge length.
|
||||
- [ ] Shards tile their parent exactly; concat reverses split; elisions use an ellipsis.
|
||||
|
||||
## 4. Full-size visual audit
|
||||
|
||||
Open the PNG at 100 %.
|
||||
|
||||
- [ ] No forbidden intersection, tangency, clipping or occlusion — including stack offset
|
||||
sheets, brackets, arrow labels and the meaning box.
|
||||
- [ ] Every connector's white label underlay covers only its own connector.
|
||||
- [ ] No connector crosses a box that is not its endpoint.
|
||||
- [ ] Symbols and shapes sit on two flat lanes per row; stage headings share a left rail.
|
||||
- [ ] Top zone compact (≤2 formula lines, no shape underbraces).
|
||||
- [ ] Bottom box: one column, ≤3 rows, no overflow, no shrunken type.
|
||||
- [ ] Signature outside the box, one line, names what the figure actually shows, not clipped
|
||||
and not visually dominant.
|
||||
- [ ] Structural support exact: known zeros unfilled, masks and diagonals exactly right.
|
||||
|
||||
## 5. Thumbnail audit
|
||||
|
||||
Open `*-thumb.png` (360 px).
|
||||
|
||||
- [ ] ≤4 active hue families per row plus gray; each role keeps one hue across stages.
|
||||
- [ ] Base colors still muted, not saturated.
|
||||
- [ ] Three visibly separated lightness levels where values vary; nothing is uniform pastel.
|
||||
- [ ] Borders neutral, not tensor-colored.
|
||||
- [ ] Dense texture reads as noise, not as stripes, checkerboard or a symmetric motif.
|
||||
- [ ] The main structural claim of the figure is still legible at this size.
|
||||
|
||||
## 6. Delivery
|
||||
|
||||
- [ ] PNG preview shown.
|
||||
- [ ] Short mechanism explanation in prose.
|
||||
- [ ] `.tex` source and vector artifact (PDF/SVG) linked.
|
||||
- [ ] Any degraded path stated explicitly — no CJK font, no `pdftocairo`, fallback renderer,
|
||||
inferred shapes or conventions.
|
||||
@@ -0,0 +1,77 @@
|
||||
# Geometry invariants
|
||||
|
||||
A figure that is drawn to the wrong geometry is not a stylistic problem — it teaches the
|
||||
reader a false fact about the computation. These invariants are mandatory. Most of them
|
||||
are automatic if you declare the geometry ledger and never pass a raw number.
|
||||
|
||||
## The ledger
|
||||
|
||||
```tex
|
||||
\stdim{T}{6} % sequence length -> 6 cells, everywhere in the figure
|
||||
\stdim{d}{9} % model width -> 9 cells, everywhere
|
||||
\stdim{dh}{3} % head width -> 3 cells, and 3*dh = d holds visually
|
||||
```
|
||||
|
||||
`\stface{...}{T}{dh}` resolves the names through the ledger, so **one symbolic axis maps
|
||||
to exactly one physical edge length across the whole figure**. Equal shapes therefore form
|
||||
an equivalence class automatically: `Q` and `V` at `T×d_h` come out identical without you
|
||||
lining anything up by hand.
|
||||
|
||||
Raw integers are accepted (`\stface{A}{(0,0)}{4}{4}`) but they opt out of the guarantee.
|
||||
Use them only for a face whose axis appears nowhere else.
|
||||
|
||||
## The rules
|
||||
|
||||
1. **Face orientation.** A matrix face `a×b` is height `a`, width `b`. Always. For batched
|
||||
or stacked tensors, the *last two* axes make the face; leading axes become depth
|
||||
(`\ststack`) or repeated panels — never a wider rectangle.
|
||||
2. **Squares.** `a×a` renders as a square. Automatic when both arguments resolve to the
|
||||
same declared axis.
|
||||
3. **Transpose.** Draw `K^T` by physically swapping height and width:
|
||||
`\ststack{KT}{...}{dh}{T}{3}` against `\ststack{K}{...}{T}{dh}{3}`. Relabelling a face
|
||||
`K^T` while leaving its shape alone is invalid — it is the single most common lie in
|
||||
attention figures.
|
||||
4. **Contraction.** In `(m×k)(k×n)`, both occurrences of `k` get the same edge length.
|
||||
With the ledger this is free: pass the same axis name to the width of the left face and
|
||||
the height of the right one. The same applies to `einsum` and attention axes.
|
||||
5. **Partition.** Explicit shards tile their parent exactly along the split axis, equal
|
||||
shards are equal in size, and concatenation reverses the split. Place shards from the
|
||||
previous face's edge so no gap can creep in:
|
||||
|
||||
```tex
|
||||
\stface[role=r1]{W1a}{(...)}{d}{dffl}
|
||||
\stface[role=r2]{W1b}{($(W1a.east)+(2*\stunit,0)$)}{d}{dffl}
|
||||
```
|
||||
|
||||
The offset is `half-width of the next face` in `\stunit`, so the two faces are exactly
|
||||
adjacent. Size concatenated parts from their *declared* shapes — Q/K/V are equal
|
||||
segments only when their output shapes are equal.
|
||||
6. **Elision.** If intermediate shards are omitted, draw an ellipsis. Never stretch the
|
||||
visible shards to impersonate the full parent.
|
||||
7. **Axis changes.** Geometry may change only at an explicit reshape, flatten, transpose,
|
||||
split, or concat operator, and the axis identity must be stated — e.g. `(h/p)·d_h = d/p`.
|
||||
Do not silently reuse one generic rectangle on both sides of an axis change.
|
||||
8. **Illustrative counts.** Cell counts need not equal real dimensions. Choosing `d=9`
|
||||
to stand for 4096 is fine. It never waives rules 1–7: the *ratios* you draw are read as
|
||||
facts. If `d = h·d_h`, pick numbers where that arithmetic actually holds.
|
||||
|
||||
## Sharded matmul
|
||||
|
||||
When a matmul is sharded, expand the block algebra in the top formula as well as in the
|
||||
middle row, otherwise the reader cannot check the figure:
|
||||
|
||||
```
|
||||
XW = [XW^(1) | ... | XW^(p)] = [H^(1) | ... | H^(p)]
|
||||
|
||||
[H^(1) | ... | H^(p)] [W^(1); ...; W^(p)] = Σ_r H^(r) W^(r) = Σ_r P^(r)
|
||||
```
|
||||
|
||||
Column sharding splits the *output* axis (shards sit side by side); row sharding splits the
|
||||
*contracted* axis (shards stack vertically and require a reduction). `examples/tp-ffn-allreduce.tex`
|
||||
draws both in one figure.
|
||||
|
||||
## Distinguish global from local
|
||||
|
||||
Per-rank shapes and global shapes are different objects. Label them differently
|
||||
(`d_ff/p` vs `d_ff`) and, when both appear, say in the **Axes** row which one the figure
|
||||
is drawing.
|
||||
@@ -0,0 +1,89 @@
|
||||
# Layout invariants
|
||||
|
||||
Everything on the canvas is a bounding box: tensors, full offset stacks, brackets,
|
||||
operators, arrow labels, annotations, symbols, shape labels, stage headings, the meaning
|
||||
box, the signature. **Tangency counts as collision.**
|
||||
|
||||
## Gutters
|
||||
|
||||
Define one base gutter `g ≥ 1 em`. Unrelated boxes stay at least `g` apart; stage bands at
|
||||
least `1.5g`. In practice: `right=5mm–9mm` between an operator and its operands, `7mm–9mm`
|
||||
between the last caption of one row and the next stage heading.
|
||||
|
||||
Overlap is allowed only inside one declared composite:
|
||||
|
||||
- tiles inside their own face,
|
||||
- shards tiling a parent,
|
||||
- outline sheets in one `\ststack`,
|
||||
- a bracket around its own tensor,
|
||||
- a connector endpoint touching its source/target border.
|
||||
|
||||
Every other intersection or occlusion is forbidden.
|
||||
|
||||
## Lanes
|
||||
|
||||
Reserve separate vertical lanes and never put anything else in them:
|
||||
|
||||
```
|
||||
stage heading
|
||||
(connector annotations)
|
||||
tensor / operator row
|
||||
symbols <- \stcaption arg 2
|
||||
shapes <- \stcaption arg 3
|
||||
```
|
||||
|
||||
Faces of different heights would otherwise hang their captions at different depths. Fix it
|
||||
with a shared baseline:
|
||||
|
||||
```tex
|
||||
\node[inner sep=0pt, fit=(Q)(KT)(S)] (rowA) {};
|
||||
\stlane{rowA}
|
||||
\stcaption{Q}{$\mathbf Q^{(i)}$}{$h\times T\times d_h$}
|
||||
...
|
||||
\stnolane
|
||||
```
|
||||
|
||||
Every `\stcaption` between `\stlane` and `\stnolane` hangs from the bottom of `rowA`, so
|
||||
symbols and shapes form two flat lanes.
|
||||
|
||||
Stage headings share one left rail. Anchor each heading below the previous row but at the
|
||||
previous *heading's* x, not at the previous row's content:
|
||||
|
||||
```tex
|
||||
\coordinate (cy) at ($(I-shape.south)+(0,-9mm)$);
|
||||
\node[st stage, anchor=north west] (SC) at (SB.west |- cy) {...};
|
||||
```
|
||||
|
||||
Explanatory prose belongs in the stage subtitle, the bottom box, or above its own
|
||||
connector. Never drop a floating commentary card between two operands unless it is a real
|
||||
operation node (`st comm`).
|
||||
|
||||
## Layers
|
||||
|
||||
The package declares three: `stbg` (connectors), `main` (tensors, operators), `stfg`
|
||||
(text). `\starrow` and `\starrowlabel` route on `stbg` automatically, so a connector can
|
||||
never cover a face. Two consequences you still own:
|
||||
|
||||
- A connector may not cross a box that is not one of its endpoints. Move the row, don't
|
||||
route over.
|
||||
- A label's white underlay may cover only its own connector — never a tensor, never
|
||||
another label. If the label is wider than the arrow, shorten the label or widen the gap.
|
||||
This is the single most common failure after a first draft.
|
||||
|
||||
## Stacks
|
||||
|
||||
`\ststack` includes its offset sheets in the bounding box, so neighbours can be spaced
|
||||
against the real extent. Back sheets are outline-only and must carry no semantic content
|
||||
of their own. If individual slices need to be read, use separate panels instead of overlap.
|
||||
|
||||
## When it does not fit
|
||||
|
||||
In this order:
|
||||
|
||||
1. shorten or remove secondary annotation,
|
||||
2. widen the natural crop,
|
||||
3. increase row spacing,
|
||||
4. move the whole stage to another row.
|
||||
|
||||
Never solve crowding by shrinking below the type hierarchy, closing the gutter, or covering
|
||||
another object.
|
||||
@@ -0,0 +1,67 @@
|
||||
# Symbol semantics
|
||||
|
||||
Shape is not meaning. Two tensors of shape `T×k` can be a score matrix, a list of token
|
||||
positions, or a Boolean support, and drawing all three the same way is the fastest way to
|
||||
mislead a reader who is trying to follow the mechanism.
|
||||
|
||||
## Classify every non-obvious symbol
|
||||
|
||||
For each symbol record: **semantic kind**, **dtype/domain**, **what one entry means**, and
|
||||
its **range** when meaningful. Kinds worth separating:
|
||||
|
||||
| kind | example | domain |
|
||||
|---|---|---|
|
||||
| value / activation | `X`, `H` | ℝ |
|
||||
| score / logit | `S = QKᵀ/√d_h` | ℝ |
|
||||
| probability | `A = softmax(S)` | [0,1], rows sum to 1 |
|
||||
| index / coordinate | `I = TopKIndices(G)` | {0,…,E−1} |
|
||||
| rank / order | selected-slot axis `r` | {1,…,k} |
|
||||
| count | `n_e` tokens per expert | ℕ |
|
||||
| id | token id, device id | opaque |
|
||||
| mask / support | `D`, causal `M` | {0,1} or {0,−∞} |
|
||||
| permutation | gather order | bijection |
|
||||
| shape parameter | `p`, `h` | ℕ, not drawn as a tensor |
|
||||
|
||||
## One block, one object
|
||||
|
||||
Never merge a score, an index list and a mask under a label like `M/S`. Each conversion
|
||||
gets an explicit operator and arrow. For selection or routing, close the entire chain:
|
||||
|
||||
```
|
||||
continuous scores → discrete indices/ids → gather / scatter / mask / route → selected values
|
||||
```
|
||||
|
||||
`TopKValues` and `TopKIndices` are different tensors; if both are used, show both.
|
||||
|
||||
## Three grammars, deliberately different
|
||||
|
||||
| object | grammar | package |
|
||||
|---|---|---|
|
||||
| value / score / probability | magnitude — three separated lightness levels | `\stface[pattern=dense]` |
|
||||
| index / id | discrete symbols in outlined cells, **no** lightness ramp | `\stindexface{...}{entries}` |
|
||||
| mask / support | one flat level, exact structure, zeros unfilled | `\stface[pattern=causal, level=3]` or `pattern=data` |
|
||||
|
||||
`examples/moe-topk-gather.tex` puts all three in one figure on purpose. The reason indices
|
||||
get no ramp: a ramp invites the reader to compare `expert 3 > expert 0` as if the number
|
||||
were a size.
|
||||
|
||||
## Notation duties
|
||||
|
||||
- Define index notation and range at first use:
|
||||
`S_t = (s_{t,1},…,s_{t,k})`, `s_{t,r} ∈ {0,…,t}`.
|
||||
- Distinguish the *source-position* axis `s` from the *selected-slot* axis `r`, and say
|
||||
whether ordering, duplicates, padding or variable cardinality matter.
|
||||
- Show the address mapping once: `G[b,t,r,:] = X[b, S[b,t,r], :]`.
|
||||
- If a mask is shown alongside the index tensor, state `M[b,t,s] = 1[s ∈ S_{b,t}]` — do not
|
||||
let the figure imply they are the same object.
|
||||
- When one selector is shared across heads, ranks or branches, draw it **once** and mark
|
||||
the broadcast/reuse axis. A per-head copy of a shared mask is a false claim about memory
|
||||
and about the computation (`examples/mha-causal.tex`: `M` is a single face while `A` is a
|
||||
three-sheet stack).
|
||||
|
||||
## Colors carry semantics too
|
||||
|
||||
One tensor role keeps one hue for the whole figure — that is what `\stsetrole` is for. A
|
||||
gathered, resharded or regrouped view of the same data keeps the *same* role color; a new
|
||||
hue means a new object. Derived tensors may reuse their parent's family rather than
|
||||
spending a hue (`V → O → Y` in the MHA example are all violet).
|
||||
@@ -0,0 +1,94 @@
|
||||
# House style
|
||||
|
||||
The package ships these defaults; this file explains what you must still decide and what
|
||||
you must not undo.
|
||||
|
||||
## Canvas
|
||||
|
||||
White background, natural `standalone` crop. No forced 16:9. No title by default. The top
|
||||
holds at most two compact formula lines: the primary chain and, only if essential, one
|
||||
companion definition.
|
||||
|
||||
Each stage is one horizontal algebraic row with a shared visual baseline. Use the fewest
|
||||
stages that preserve the primary path. No unrelated branches, no dashboard panels.
|
||||
|
||||
## Type hierarchy
|
||||
|
||||
| element | size | macro / style |
|
||||
|---|---|---|
|
||||
| formula | `\large` | `\stformula` |
|
||||
| stage label | `\small\bfseries`, muted | `st stage` |
|
||||
| operator | `\Large` | `st op` |
|
||||
| symbol | `\small` | `\stcaption` arg 2 |
|
||||
| shape | `\scriptsize`, muted | `\stcaption` arg 3 |
|
||||
| bottom prose | `\small` | `\stmeaningbox` |
|
||||
| signature | `\scriptsize`, low contrast | `\stsignature` |
|
||||
|
||||
Never shrink below this to make something fit — see `layout.md`.
|
||||
|
||||
## Faces
|
||||
|
||||
Separate tiles with a small white gutter and 0.5–1 pt corner rounding (`\st@tile` does
|
||||
this). Thin neutral brackets, `black!55`–`black!70` outer borders. No saturated
|
||||
tensor-colored outlines, no continuous spreadsheet grid.
|
||||
|
||||
**Encode support before magnitude.** Every known zero stays white/unfilled; every shown
|
||||
nonzero gets color. A diagonal matrix must read instantly as colored diagonal cells on a
|
||||
white field. `pattern=diag/band/lower/upper/causal/data` fill exactly the structural
|
||||
support.
|
||||
|
||||
## Color
|
||||
|
||||
Palette (already defined): `stTeal #4F8FA5`, `stOrange #EE995B`, `stCoral #C95B5B`,
|
||||
`stViolet #8A74B5`, `stGray #85898F`. Muted, mid-chroma, paper-like. Do not add saturated
|
||||
primaries.
|
||||
|
||||
- One semantic color per tensor role, held across every stage: `\stsetrole{q}{stTeal}`.
|
||||
Macros take a **role**, never a color.
|
||||
- At most four active hue families per algebraic row, plus neutral gray. Vary lightness or
|
||||
reuse the related input/output family before spending a new hue.
|
||||
- If sign matters: hue for sign, intensity for magnitude.
|
||||
- Contrast comes from **lightness separation, not saturation**. Levels are `role!30`,
|
||||
`role!55`, `role!80` (`\stlevelpct`); white is reserved for zero/absence. Do not render
|
||||
a whole tensor in `role!5`–`role!15` pastel.
|
||||
- Illustrative dense tensors use two or three **non-periodic** levels. `pattern=dense`
|
||||
composes coprime moduli to avoid this; a polynomial hash mod 3 makes rows 1, 2, 4, 5
|
||||
identical and the eye reads that stripe as structure in the data. No checkerboards, no
|
||||
regular stripes, no symmetric motifs unless they encode real structure.
|
||||
|
||||
## Bottom box
|
||||
|
||||
One full-width, low-contrast box, one reading column, three fixed-label rows:
|
||||
|
||||
- **Axes** — what each dimension means.
|
||||
- **Objects** — semantic kind / domain / range (see `semantics.md`).
|
||||
- **Mechanism** — at most two essential mappings, contractions, broadcasts or boundaries.
|
||||
|
||||
Narrow bold label rail, left-aligned ragged-right `\small` content, 8–10 pt inner padding,
|
||||
0.4–0.6 em row gaps. Rail labels localize with the package option (`zh` default, `en`).
|
||||
Keep each row compact: prefer symbol semantics over numeric configuration. When it is too
|
||||
long, **remove content** — never add cards, columns or smaller type. Pass `{}` to omit a row.
|
||||
|
||||
## Signature
|
||||
|
||||
One centered line below the box, outside it, low-contrast gray, `\scriptsize` or smaller:
|
||||
`\stsignature{<subject>}{<fit node>}` renders `<subject>@五道口纳什`. The subject must name
|
||||
what this figure actually visualizes. Keep it on one line, with a small but visible gap.
|
||||
|
||||
## Never
|
||||
|
||||
Charts or metric insets not present in the primary formula. Decorative pills, banners,
|
||||
shadows, repeated separators, explanatory cards.
|
||||
|
||||
## Reference image
|
||||
|
||||
`assets/kimi-matrix-style-reference.png` — inspect it with an image viewer before drawing
|
||||
when entry-level matrix blocks are central or Kimi-like styling is requested. Use it only
|
||||
to calibrate tile spacing, rounding, neutral brackets, restrained hue, lightness separation
|
||||
and structural whitespace. Do not copy its content, and do not embed it in the output.
|
||||
|
||||
## Language
|
||||
|
||||
Chinese figures use concise Chinese labels with standard English terms where helpful
|
||||
(`softmax`, `All-Reduce`, `gather` stay in English). Switch the whole figure at once —
|
||||
`\usepackage[en]{supertensor}` plus English stage headings and box text — never mix.
|
||||
Reference in New Issue
Block a user