Compare commits
3
Commits
9f635d358b
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b24eba3c8 | ||
|
|
f2ccd6fb08 | ||
|
|
45db61f3e2 |
@@ -5,8 +5,8 @@ description: >-
|
|||||||
steps, justification rails, cancel and substitute highlights.
|
steps, justification rails, cancel and substitute highlights.
|
||||||
Use when a rewrite must be seen (cancel-visual, subst-visual, or
|
Use when a rewrite must be seen (cancel-visual, subst-visual, or
|
||||||
more than four steps), or the user asks for $superderive. Not for
|
more than four steps), or the user asks for $superderive. Not for
|
||||||
architecture (superfig), tensor faces (supertensor), or ordinary
|
architecture (superfig), tensor faces (supertensor), or a full
|
||||||
note-side align (superpaper v1).
|
paper-note job (use superpaper; short rewrites stay as align).
|
||||||
---
|
---
|
||||||
|
|
||||||
# superderive
|
# superderive
|
||||||
|
|||||||
@@ -256,9 +256,9 @@
|
|||||||
\node[anchor=west, inner sep=0pt] (#1) at (\the\sd@cx,\the\sd@cy) {%
|
\node[anchor=west, inner sep=0pt] (#1) at (\the\sd@cx,\the\sd@cy) {%
|
||||||
\begin{tikzpicture}[baseline=(sd@mid)]
|
\begin{tikzpicture}[baseline=(sd@mid)]
|
||||||
\node[sd term, fill=sdCoral!30] (sd@B) {$\displaystyle #2$};
|
\node[sd term, fill=sdCoral!30] (sd@B) {$\displaystyle #2$};
|
||||||
\node[font=\scriptsize, text=sdCoral, above=1pt of sd@B] {非法};
|
\node[font=\scriptsize, text=sdCoral, above=1pt of sd@B] {\sd@lblillegal};
|
||||||
\node[sd term, fill=sdTeal!30, right=8mm of sd@B] (sd@G) {$\displaystyle #3$};
|
\node[sd term, fill=sdTeal!30, right=8mm of sd@B] (sd@G) {$\displaystyle #3$};
|
||||||
\node[font=\scriptsize, text=sdTeal, above=1pt of sd@G] {合法};
|
\node[font=\scriptsize, text=sdTeal, above=1pt of sd@G] {\sd@lbllegal};
|
||||||
\coordinate (sd@mid) at ($(sd@B.east)!0.5!(sd@G.west)$);
|
\coordinate (sd@mid) at ($(sd@B.east)!0.5!(sd@G.west)$);
|
||||||
\end{tikzpicture}};%
|
\end{tikzpicture}};%
|
||||||
\pgfextractx{\sd@tmpx}{\pgfpointanchor{#1}{east}}%
|
\pgfextractx{\sd@tmpx}{\pgfpointanchor{#1}{east}}%
|
||||||
@@ -267,8 +267,10 @@
|
|||||||
|
|
||||||
\ifder@en
|
\ifder@en
|
||||||
\def\sd@lblidea{Idea}\def\sd@lblrw{Rewrite}\def\sd@lblcaveat{Caveat}
|
\def\sd@lblidea{Idea}\def\sd@lblrw{Rewrite}\def\sd@lblcaveat{Caveat}
|
||||||
|
\def\sd@lblillegal{illegal}\def\sd@lbllegal{legal}
|
||||||
\else
|
\else
|
||||||
\def\sd@lblidea{思路}\def\sd@lblrw{改写}\def\sd@lblcaveat{注意}
|
\def\sd@lblidea{思路}\def\sd@lblrw{改写}\def\sd@lblcaveat{注意}
|
||||||
|
\def\sd@lblillegal{非法}\def\sd@lbllegal{合法}
|
||||||
\fi
|
\fi
|
||||||
\newcommand{\sdsetlabels}[3]{\def\sd@lblidea{#1}\def\sd@lblrw{#2}\def\sd@lblcaveat{#3}}
|
\newcommand{\sdsetlabels}[3]{\def\sd@lblidea{#1}\def\sd@lblrw{#2}\def\sd@lblcaveat{#3}}
|
||||||
\newlength{\sd@raillen}
|
\newlength{\sd@raillen}
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
% Anti-patterns -- figures that compile cleanly and still teach something false.
|
||||||
|
% ../scripts/build.sh antipatterns.tex
|
||||||
|
% superderive-lint: allow-multiple-contrast
|
||||||
|
% superderive-build: allow
|
||||||
|
\documentclass[border=10pt]{standalone}
|
||||||
|
\usepackage[cjk]{superderive}
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
\begin{tikzpicture}
|
||||||
|
\sdstage{AP}{四张反例}
|
||||||
|
\sdrow{R1}
|
||||||
|
% AP1: \sdsubst 只填了 from,to 也是同一个 -- 改写没有产生任何变化
|
||||||
|
\sdsubst[role=rewrite]{ap1}{x+y}{x+y}
|
||||||
|
\sdreason{ap1}{subst 的 from 和 to 相同,改写为空}
|
||||||
|
\sdrowend
|
||||||
|
|
||||||
|
\sdrow{R2}
|
||||||
|
% AP2: \sdcancel 划线后旁边又写了一遍同样的东西 -- 读者不知道划掉的是哪一部分
|
||||||
|
\sdcancel[role=cancel]{ap2a}{x+y}
|
||||||
|
\sdbox[role=keep]{ap2b}{x+y}
|
||||||
|
\sdreason{ap2a}{cancel 后面紧跟同一式子,等于没有 cancel}
|
||||||
|
\sdrowend
|
||||||
|
|
||||||
|
\sdrow{R3}
|
||||||
|
% AP3: 同一行里塞了五组 role,hue budget 超了
|
||||||
|
\sdbox[role=keep]{ap3a}{a}
|
||||||
|
\sdbox[role=rewrite]{ap3b}{b}
|
||||||
|
\sdbox[role=cancel]{ap3c}{c}
|
||||||
|
\sdbox[role=intro]{ap3d}{d}
|
||||||
|
\sdbox[role=neutral]{ap3e}{e}
|
||||||
|
\sdrowend
|
||||||
|
|
||||||
|
\sdrow{R4}
|
||||||
|
% AP4: 两个 contrast pair,第二个是多余的
|
||||||
|
\sdcol{ap4a}{x+y}{x+y}
|
||||||
|
\sdcol{ap4b}{a+b}{a+b}
|
||||||
|
\sdrowend
|
||||||
|
|
||||||
|
\sdbbox{all}
|
||||||
|
\sdtopformula{F}{反例见 \texttt{references/antipatterns.md}}
|
||||||
|
\sdmeaningbox{mb}{140mm}{all}
|
||||||
|
{subst from=to;cancel 后重复;row 内五色;两个 sdcol}
|
||||||
|
{每一行都符合语法,但每一行都在说谎}
|
||||||
|
{参考 antipatterns.md 的对应规则}
|
||||||
|
\end{tikzpicture}
|
||||||
|
\end{document}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
% Golden example -- a subst chain that must be seen, not just aligned.
|
||||||
|
% ../scripts/build.sh subst-chain.tex
|
||||||
|
\documentclass[border=10pt]{standalone}
|
||||||
|
\usepackage[cjk]{superderive}
|
||||||
|
|
||||||
|
\sdsetrole{live}{sdTeal}
|
||||||
|
|
||||||
|
\begin{document}
|
||||||
|
\begin{tikzpicture}
|
||||||
|
\sdstage{D1}{换元让积分内部对齐}
|
||||||
|
\sdrow{R1}
|
||||||
|
\sdbox[role=keep]{x}{$u$}
|
||||||
|
\sdsubst[role=live]{s1}{u}{x^2}
|
||||||
|
\sdstep[role=rewrite]{s2}{\int_0^1 x\,e^{x^2}\,dx}{\tfrac12\int_0^1 e^u\,du}
|
||||||
|
\sdrowend
|
||||||
|
\sdbbox{all}
|
||||||
|
\sdtopformula{F}{$\int_0^1 x\,e^{x^2}\,dx = \tfrac12\int_0^1 e^u\,du$}
|
||||||
|
\sdmeaningbox{mb}{120mm}{all}
|
||||||
|
{换元是恒等改写,不改值}
|
||||||
|
{令 $u=x^2$,则 $du=2x\,dx$}
|
||||||
|
{上下限随 $u$ 一起换掉}
|
||||||
|
\end{tikzpicture}
|
||||||
|
\end{document}
|
||||||
+98
-4
@@ -1,7 +1,101 @@
|
|||||||
# API
|
# superderive.sty API
|
||||||
|
|
||||||
`\usepackage[cjk]{superderive}` or `[en]`.
|
```tex
|
||||||
|
\documentclass[border=10pt]{standalone}
|
||||||
|
\usepackage[cjk]{superderive} % cjk: ctex + fandol (XeLaTeX). en: English meaning-box and sdcol labels.
|
||||||
|
```
|
||||||
|
|
||||||
Layout: `\sdstage{n}{text}` `\sdrow[height]{name}` … `\sdrowend` `\sdbbox{all}` `\sdtopformula{F}{math}`.
|
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.
|
||||||
|
|
||||||
Call `\sdtopformula` after the last `\sdrowend`.
|
The build first runs `scripts/lint.py`. It rejects raw TikZ drawing, a formula placed
|
||||||
|
before the last row, more than one `\sdcol` contrast pair, and more than four active hue
|
||||||
|
families in the figure. Intentional galleries/tests may put
|
||||||
|
`% superderive-lint: allow-raw-tikz` near the top; do not add an exemption to a
|
||||||
|
deliverable merely to make it pass.
|
||||||
|
|
||||||
|
## Ledgers
|
||||||
|
|
||||||
|
```tex
|
||||||
|
\sdsetrole{keep}{sdTeal} % role -> color. Macros take a ROLE, never a color.
|
||||||
|
\sdsetlabels{Idea}{Rewrite}{Caveat} % override the three meaning-box rail labels
|
||||||
|
```
|
||||||
|
|
||||||
|
Colors: `sdTeal sdOrange sdCoral sdViolet sdGray sdInk`. An unknown role falls back to
|
||||||
|
gray **and emits a package warning**, which `build.sh` turns into a failed build.
|
||||||
|
Redeclaring a role with the same value is harmless; changing its value emits a warning
|
||||||
|
and keeps the original mapping.
|
||||||
|
|
||||||
|
## Flow layout
|
||||||
|
|
||||||
|
**This is the default.** `\sdrow` opens a band, every object inside is placed at the
|
||||||
|
cursor, `\sdrowend` closes it. Hand-written offsets are the main source of layout bugs.
|
||||||
|
|
||||||
|
```tex
|
||||||
|
\sdstage{D1}{stage heading} % on the left rail, below the previous band
|
||||||
|
\sdrow[16mm]{R1} % open a band; height default is 16mm
|
||||||
|
\sdbox[role=keep]{x}{$u$} % existing term, kept as-is
|
||||||
|
\sdsubst[role=live]{s1}{$u$}{$x^2$} % from->to with a strike on the from
|
||||||
|
\sdstep[role=rewrite]{s2}{QK^\top}{QK^\top/\sqrt{d_k}} % lhs -> rhs
|
||||||
|
\sdreason{s1}{§3.2.1} % justification note, anchored to s1
|
||||||
|
\sdrowend % fit the band
|
||||||
|
```
|
||||||
|
|
||||||
|
| macro | does |
|
||||||
|
|---|---|
|
||||||
|
| `\sdstage{name}{text}` | stage heading on the left rail, below all ink so far |
|
||||||
|
| `\sdrow[height]{name}` | open a band; optional height defaults to 16mm |
|
||||||
|
| `\sdrowend` | `fit` the band, warn if empty, close it |
|
||||||
|
| `\sdstep[keys]{name}{lhs}{rhs}` | one rewrite step: two term boxes with an arrow |
|
||||||
|
| `\sdcancel[keys]{name}{math}` | one term, struck through |
|
||||||
|
| `\sdsubst[keys]{name}{from}{to}` | from-term struck through, to-term in role hue |
|
||||||
|
| `\sdbox[keys]{name}{math}` | plain term, no arrow, no strike |
|
||||||
|
| `\sdreason{step-name}{text}` | justification note anchored to a named step |
|
||||||
|
| `\sdcol{name}{illegal}{legal}` | one contrast pair per figure — second is a warning |
|
||||||
|
| `\sdbbox{all}` | everything drawn so far, as one node, for `\sdmeaningbox` |
|
||||||
|
| `\sdtopformula{F}{math}` | the claim line, centered on what was actually drawn |
|
||||||
|
| `\sdtrack{node}` | fold a hand-placed node into the bbox and the vertical cursor |
|
||||||
|
| `\sdvgap{4mm}` / `\sdgap{4mm}` | one-off extra space, vertical / horizontal |
|
||||||
|
| `\sdleftrail{x}` / `\sdlayoutreset` | move the rail / start over |
|
||||||
|
|
||||||
|
### Keys for step/cancel/subst/box
|
||||||
|
|
||||||
|
| key | default | meaning |
|
||||||
|
|---|---|---|
|
||||||
|
| `role=` | `rewrite` for step/subst, `cancel` for cancel, `keep` for box | hue, via `\sdsetrole` |
|
||||||
|
| `level=` | `2` | lightness level 0–3 for the fill |
|
||||||
|
| `gap=` | `\sdgutter` | space *before* this object; `gap=0pt` = exactly adjacent |
|
||||||
|
|
||||||
|
Authors can declare their own roles: `\sdsetrole{live}{sdTeal}`.
|
||||||
|
|
||||||
|
## Contrast column
|
||||||
|
|
||||||
|
`\sdcol{name}{illegal}{legal}` draws two boxes side by side: the left in `sdCoral!30`
|
||||||
|
struck, labelled **illegal** (or **非法** in `[cjk]` mode — never both); the right in
|
||||||
|
`sdTeal!30`, labelled **legal** (or **合法**). The budget is **one per figure**; a second
|
||||||
|
`\sdcol` triggers a package warning → build failure.
|
||||||
|
|
||||||
|
## Bottom
|
||||||
|
|
||||||
|
```tex
|
||||||
|
\sdbbox{all}
|
||||||
|
\sdtopformula{F}{$\mathrm{Attention}(Q,K,V)=\mathrm{softmax}(QK^\top/\sqrt{d_k})V$}
|
||||||
|
\sdmeaningbox{mb}{120mm}{all}{Idea text}{Rewrite text}{Caveat text}
|
||||||
|
\sdsignature{scaled-dot-product attention}{mb} % optional
|
||||||
|
```
|
||||||
|
|
||||||
|
Arg 2 of `\sdmeaningbox` is the total box width; arg 3 is the node it hangs below.
|
||||||
|
Arg 4/5/6 are the three rail rows; an empty `{}` row is dropped.
|
||||||
|
|
||||||
|
`\sdsignature` renders only its subject; it has no author or handle mechanism. Its node
|
||||||
|
is named `(#2-sig)` from the anchor.
|
||||||
|
|
||||||
|
## Gotchas
|
||||||
|
|
||||||
|
- `\sdrow`, `\sdrowend`, `\sdstage` must appear outside any other flow object.
|
||||||
|
- A band that overflows its declared height triggers `Package superderive Warning` →
|
||||||
|
build failure.
|
||||||
|
- `\sdcheckrole` never redefines an existing role. Use `\sdsetrole{name}{newColor}`
|
||||||
|
to change the mapping for subsequent figures in the same document.
|
||||||
|
- `\sdcol` labels are **not** customizable via `\sdsetlabels` — they depend only on the
|
||||||
|
package option `[en]`/`[cjk]`.
|
||||||
|
|||||||
@@ -35,10 +35,14 @@ if grep -qE "^(Overfull|Underfull) \\\\[hv]box" "$LOG"; then
|
|||||||
status=1
|
status=1
|
||||||
fi
|
fi
|
||||||
if grep -q "Package superderive Warning" "$LOG"; then
|
if grep -q "Package superderive Warning" "$LOG"; then
|
||||||
|
if grep -q "^% superderive-build: allow" "$SRC"; then
|
||||||
|
echo " superderive warnings present (suppressed by superderive-build: allow)" >&2
|
||||||
|
else
|
||||||
echo "!! superderive warnings:" >&2
|
echo "!! superderive warnings:" >&2
|
||||||
grep -m5 -A2 "Package superderive Warning" "$LOG" >&2
|
grep -m5 -A2 "Package superderive Warning" "$LOG" >&2
|
||||||
status=1
|
status=1
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
if command -v pdftocairo >/dev/null 2>&1; then
|
if command -v pdftocairo >/dev/null 2>&1; then
|
||||||
echo "==> exporting svg / png"
|
echo "==> exporting svg / png"
|
||||||
|
|||||||
@@ -22,6 +22,16 @@ for f in "$ROOT"/tests/lint-invalid/*.tex; do
|
|||||||
echo " ok $name (rejected by lint)"
|
echo " ok $name (rejected by lint)"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
for f in "$ROOT"/tests/invalid/*.tex; do
|
||||||
|
[[ -e "$f" ]] || continue
|
||||||
|
name="$(basename "$f")"
|
||||||
|
if "$ROOT/scripts/build.sh" "$f" >/dev/null 2>&1; then
|
||||||
|
echo " FAIL $name (invalid fixture built)"
|
||||||
|
fail=$((fail+1))
|
||||||
|
else
|
||||||
|
echo " ok $name (rejected by package/build)"
|
||||||
|
fi
|
||||||
|
done
|
||||||
if [[ $fail -gt 0 ]]; then
|
if [[ $fail -gt 0 ]]; then
|
||||||
echo "$fail failing check(s)" >&2
|
echo "$fail failing check(s)" >&2
|
||||||
exit 1
|
exit 1
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
\usepackage[en]{superderive}
|
||||||
|
\begin{document}\begin{tikzpicture}
|
||||||
|
\sdrow{R1}
|
||||||
|
\sdrowend
|
||||||
|
\end{tikzpicture}\end{document}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
\usepackage[en]{superderive}
|
||||||
|
\begin{document}\begin{tikzpicture}
|
||||||
|
\sdstep{s1}{a}{b}
|
||||||
|
\end{tikzpicture}\end{document}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
\usepackage[en]{superderive}
|
||||||
|
\begin{document}\begin{tikzpicture}
|
||||||
|
\sdrow{R1}
|
||||||
|
\sdcol{c1}{a}{b}
|
||||||
|
\sdcol{c2}{c}{d}
|
||||||
|
\sdrowend
|
||||||
|
\end{tikzpicture}\end{document}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
\usepackage[en]{superderive}
|
||||||
|
\begin{document}\begin{tikzpicture}
|
||||||
|
\sdrow{R1}
|
||||||
|
\sdbox[role=nosuch]{a}{x}
|
||||||
|
\sdrowend
|
||||||
|
\end{tikzpicture}\end{document}
|
||||||
Reference in New Issue
Block a user