# tikz-tensor-networks 0.8.0 — 2026-09-05 ## CTAN package rename (2026-09-17) Renamed the package from `tenkz` to `tikz-tensor-networks` at the CTAN team's request, before the first accepted release. Documents now load `\usepackage{tikz-tensor-networks}`. The `tenkz` and `tenkzeq` environments, body commands, internal modules, and event format are unchanged. The upload archive, manual, and citation metadata use the new package name. ## Drawing corrections (2026-09-06) Plane physical legs remain local to their tensor instead of stretching to the containing region. Bare glyphless sites now attach their physical ports at the site, and saved trace paths retain the existing rounded-corner style. These corrections add no public options. Source-backed benchmark redraws correct the normal-form and gauge routes, project the MPO ring into its plane, and restore the renormalization plaquette's plain crossings and eight virtual openings. Compact MPDO trace capsules, the condensation diagram's layer and crossing order, and braid-four's labelled four-port resolvers now close the remaining three cosmetic gaps. Fresh source comparison also restores braid-four's two inter-resolver branches and upper return arch. Flat physical traces use the existing trace clearance for their height and bound their rounded caps by the available width. ## Unreleased development history The version numbers and removed spellings below describe internal development, not earlier public releases. The manual documents the current language. ### Repository split (2026-08-25) The package, corpus, manual, and tooling now live in [LionSR/tenkz](https://github.com/LionSR/tenkz), extracted with history from TNLean `85a12e6b5`. At the split, the TeX package version remained 0.7. Historical tenkz issues stay on TNLean; new work opens here. 0.7 drew pictures through four front ends. Five environments, seven picture commands, and four separate key ledgers each said the same few things in a private dialect: a cell, a wire, a mark, a frame. 0.8.0 has one environment and one ledger. Every picture is a kernel picture, the package binds the kernel at load, and the front ends are gone — 3,154 lines of commutative-diagram stage, 4,393 of free stage, 10,500 of lattice stage, 17,340 of grid stage, retired in four changes that deleted 35,387 lines against 2,764 added. The registry census fell from 201 public rows to 86 and the parser-path count from 228 to 75; the escape ledger, which prices every occurrence of a spelling the core grammar cannot say, reached zero. The spellings below are removed outright, with one stated exception. 0.8.0 is a first release candidate and keeps no alias, compatibility reader, or dual writer for any of them: an old spelling stops the run with an unknown-key or unknown-command error naming the vocabulary, and nothing is silently reinterpreted. Every documented replacement was applied to the blueprint corpus and the 130-case benchmark before its front end was deleted, and each deletion carried the fixtures whose language died — the regression corpus went from 264 sources to 9. The exception is `\tenkzkernel`. It is not removed: it is inert for the whole 0.8 series and carries a registry sunset, because the kernel it used to switch on is now bound at package load, so a document that still writes it asks for what it already has. Delete it at leisure. Every other row below is an error from 0.8.0 onward. ## Retired environments | Old | New | |---|---| | `tenkzcd` | plain `tikz-cd`; commutative diagrams are not this language | | `tenkzfree` | `tenkz` with addressed `\tn`, `\tnwire`, and `\tnmark` records | | `tenkzlattice` | `tenkz` with `lattice={RxC}`, or a declared `frame={..., basis={...}}` | | `tenkzplanes` | `tenkz` with the `planes` sugar row | | `tenkz` (0.7 grid meaning) | `tenkz` — the name survives, the meaning is the kernel picture | ## Retired commands | Old | New | |---|---| | `\tnpic[k]{body}` | `\begin{tenkz}[k] body \end{tenkz}` | | `\tnarrow` | `\tnwire[dir=to]` | | `\tnput` | `\tn[at=
]` | | `\tnjoin` | `\tnwire` | | `\tnedge` | `\tnwire` | | `\tnsite` | `\tn[at=(r,c)]` | | `\tnregion` | `\tnmark[form=enclosure]` | | `\tncut` | `\tnmark[form=enclosure]` or `\tnmark[form=bracket]` | | `\tnspan[form]{k}{m}` | `\tnmark[form=...]{(r,c) .. (r,c+k-1)}{m}` | | `\tnX{m}` | `\tn[skin=ring]{m}` | | `\tndots` | `\tn[skin=dots]{}` | | `\tnskip` | `\tn[void=open]{}` | | `\tnghost{m}` | nothing; an address may name an empty cell | ## Retired keys Commutative-diagram front end: | Old | New | |---|---| | `maps` | — | | `polygon=`, `radius=` | — | | `column sep=`, `row sep=` | — | | `from=`, `to=` | `\tnwire{}{}` | | `poly=k` | — | Free front end: | Old | New | |---|---| | `out=`, `in=` | `route=arc` | | `route=hv`, `route=vh` | `route=orth` | | `route=curve` | `route=arc` | | `drop`, `hug` | `route=orth`, `route={ of }` | | `ports=` (free object row) | `\tn[ports=...]`, the typed-port list | | `ring`, `circle`, `boundary` | `skin=ring`, `skin=circle`, `skin=boundary` | | `fused` | — | | `none` (connection flag) | omit the record, or `void=sealed` to remove the site | | `group=` | an address set | Lattice front end: | Old | New | |---|---| | `site=` | — | | `sheets=`, `sheet sep=` | `frame={plane, basis={...}}` | | `col vector=`, `row vector=`, `sheet vector=` | `frame=plane` with basis members | | `plane rise=`, `plane slant=`, `plane lean=` | `frame=plane` subkeys | | `pairing` | `pairings=` on the declared skin | | `outer legs=`, `boundary legs` | the side policy | | `label=` (object) | `\tnmark[form=label]` | | `size=` (object) | `size=`, the size class | | `removed=` | `void=sealed` | | `style=` (edge pass-through) | `stroke=`, or the port type | | `label at=` (region) | `label pos=` | Grid front end: | Old | New | |---|---| | `tensor style=` | `skin=` | | `up=`, `down=` | `ports=` | | `up at=`, `down at=`, `west at=`, `east at=`, `combined=` | the `ports=` angle and slot grammar | | `span=` | `wires=` | | `mpo` | `skin=mpo` | | `bond dir=` | `dir=` on the wire | | `bond label={$D$ at 1-2}` | `\tnmark[form=label]{}{$D$}` | | `label shift=` | `label pos=` | | `box` | `\tnmark[form=enclosure]` | | `brace above` | `\tnmark[form=bracket]`; the side a bracket speaks from is the side its label sits on, so `label pos=` names it and the south is the default | | `label pos` (annotation) | `label pos=` on the mark record | | `layer sep=` | the metric size classes | | `trace style=racetrack` | — | | `inline`, `compact` | math-style sensing and `size=`; `metrics=compact` for a page-constrained picture | | `wiring=` | `pairings=` on the skin | | `weight=string` | `kind=string` | | `cluster` (as a skin) | `cluster={RxC}`, a basis sugar | | `enclosure` (as a skin) | `\tnmark[form=enclosure]`; a boundary operator is a wide atom | | `chain axis`, `legs at`, `rows`, `periodic` | `frame=`, `ports=`, `wires=`, `west=trace, east=trace` | | `leg of `, ` outside` | the generated leg's own name | | `(r,c)-(r,c)` | `(r,c) .. (r,c)` | Spellings inside the kernel tier itself: | Old | New | |---|---| | `outline` (mark flag) | `tint` | | `physical=` as a picture-wide row topology | `physical=` as a per-cell port policy | | `\tnset{pitch=...}` in the body | `metrics=compact` | | hand-written leave and enter angles on a route | `crossing=` for the habit, `cross=` for the exception | | `\tenkzkernel` | nothing; the kernel is bound at package load. Retained, inert, sunset — the one row above that is not an error | ## Why the front ends died - **One picture, one language.** The four dialects disagreed about nothing that mattered. A cell was a `site`, a `tensor`, or an object with `ports`; a wire was an `edge`, a `join`, an `arrow`, or a `bond`; a mark was a `region`, a `cut`, a `span`, or a `box`. Each dialect then needed its own parser, its own defaults, and its own renderer, and a picture that wanted two of them could not be written at all. The kernel has one record for each of the three, and the dialects became presets over it. - **An address, not a cursor.** `\tnput` placed a tensor where the last one left off; `\tnsite` placed one at a lattice coordinate; `\tnpic` placed one wherever the body's row and column separators had got to. Three ways to say where. In 0.8.0 a picture declares a frame, the frame mints addresses, and every record names its addresses. `\tnghost` existed only to advance a cursor past an empty cell, so it has nothing to do. - **A port has a type; a route has ends.** `out=` and `in=` set the raw departure and arrival angles of a curve, which meant that moving a tensor broke every wire touching it. An arc now leaves and enters along the faces of its ends, and the ends are the wire's two arguments rather than `from=` and `to=` keys. `fused` and `weight=` chose ink from the author's intent; the port type chooses it from the picture. - **A sheet is a basis member.** `sheets=`, `sheet sep=`, `col vector=`, `row vector=`, and `sheet vector=` described a three-dimensional lattice by listing its layers and then its lattice vectors separately, so the two could disagree. `frame={plane, basis={...}}` states the basis once and the layers are members of it. The doubled-plane pictures the lattice front end existed for are the `planes` sugar row over that frame. - **A hyphen is not a range.** `(r,c)-(r,c)` could not be told from a generated name containing a hyphen, so a selector was ambiguous exactly where selectors are used most. The range operator is `..`. - **Contour is the default, so paper says so.** The mark flag was `outline`, and its absence meant a filled mark. Filled marks are rare, unfilled marks are the common case, and a flag should name the exception. The flag is now `tint` and its absence means contour only. ## Migration Per spelling, one substitution each: ``` \tnpic[K]{BODY} -> \begin{tenkz}[K] BODY \end{tenkz} \tnarrow -> \tnwire[dir=to] \tnjoin -> \tnwire \tnedge -> \tnwire \tnX{M} -> \tn[skin=ring]{M} \tndots -> \tn[skin=dots]{} \tnskip -> \tn[void=open]{} \tncut -> \tnmark[form=enclosure] \tnregion -> \tnmark[form=enclosure] tensor style= -> skin= route=curve -> route=arc route=hv | route=vh -> route=orth span= -> wires= bond dir= -> dir= label shift= -> label pos= label at= -> label pos= removed= -> void=sealed outline -> tint (r,c)-(r,c) -> (r,c) .. (r,c) ``` `\tnghost` and the `none` connection flag are deleted, not rewritten. The rest read better by hand: - `\tnput{M}` becomes `\tn[at=
]{M}` once the picture declares a frame; a free picture that relied on placement order must first say where its tensors are. - `\tnsite`, `\tnedge`, and `\tnregion` bodies become `\tn`, `\tnwire`, and `\tnmark` records over the same coordinates, with `lattice={RxC}` supplying the frame the environment used to supply. - `out=`/`in=` angle pairs become `route=arc`, and a crossing that the arcs no longer resolve is named once with `crossing=` or per wire with `cross=`. - `up=`/`down=` row topology becomes a `ports=` list per cell. - A `bond label={$D$ at 1-2}` becomes a `\tnmark[form=label]` record naming the wire. - `\tenkzkernel` may be deleted from a document body: the meanings it bound are the package's meanings from the moment it loads. The command is inert rather than an error in the 0.8 series, and carries a registry sunset. ## Unchanged `tenkz` as the environment name, `tenkzeq` and its joiners, `\tn`, `\tnwire`, `\tnmark`, `\tndeclare` and `\tndeclareatom`, the four side-policy words (`open`, `none`, `trace`, `cup`) and their `west=`/`east=`/`north=`/`south=` keys, `frame=` as the one frame key, the cell-set contraction algebra with its terms, ranges, and `+`/`-` unions, `periodic` as the shorthand for a traced pair of sides, and the `.tnlog` event surface, whose format version and compatibility rules are declared in `TNLOG.md`. ## Also in 0.8.0 - `\tenkzkernel` binds at package load. A document that never wrote the command gets the kernel surface; a document that wrote it gets the same surface twice. What the swap deleted for a reader is the possibility of a picture in the 0.7 grid meaning. - The plane frame carries a declared basis and an independent physical axis, so a projected picture states its own topology instead of inheriting the grid's. - A physical index may be directed, and a policy leg has the standing of a declared one: a generated open end is a named record that a label or a mark can name. - `stroke={solid|dashed|dotted}` spells wire ink, and the direction mark inks on every bearing. - Region selection takes set difference, so a nested window is `A - B` rather than two overlapping marks. - `metrics=compact` names the tighter metric profile that page-constrained pictures used to obtain by setting `pitch=` in the body. - The stock `mpo` and `pill` skins are prelude declarations rather than object flags. - The alias count is zero and no public name carries two value types. - `route=orth` squares a `closed` string's turns as well as an open one's, so a ring an author draws as a square is a square. The kernel consulted the key only on the open branch before, and a closed route drew the smooth cycle whatever was asked for. The same change routes every orth path through the string engine, so an orth route states its `string` record like any other declared curve; it previously drew without speaking. ## Release scope and limitations This is the first release candidate; tenkz has not been publicly released. It does not claim the future 1.0 compatibility freeze. The package, manual, README and citations name 0.8.0, dated 2026-09-05. The event schema remains format 1.3, with no in-band version negotiation. The rendering corrections change runtime geometry and the corresponding wire-ink event coordinates and curve segments. The manual sources now ship beside the PDF under `doc/` and are rebuilt from the unpacked upload during the CTAN check. The inactive release campaign has been removed in favor of ordinary tests, review and maintainer approval. The 130-target benchmark ledger records 125 faithful cases, no cosmetic gaps and five deferred structural gaps. This is a record of individual reviews; the older full-review fingerprint is stale. Automated compile and audit passes do not constitute a new visual proof of every figure or mathematical identity. Authored routes and label stations can require adjustment; the manual build retains repeated-topology audit advisories. See `ctan/READINESS.md` for candidate validation and `RELEASE-POLICY.md` for publication steps. The projected `wind` renderer does not reliably depict torus basis cycles; see [#301](https://github.com/LionSR/tenkz/issues/301). The manual teaches the quotient construction with an explicitly labeled TikZ schematic.