Initial commit
This commit is contained in:
276
skills/docx/references/math-formulas.md
Executable file
276
skills/docx/references/math-formulas.md
Executable file
@@ -0,0 +1,276 @@
|
||||
# Math Formulas — LaTeX → docx-js Mapping
|
||||
|
||||
## Design Philosophy
|
||||
|
||||
GLM uses **LaTeX as the formula input syntax**, internally converting to docx-js Math objects.
|
||||
|
||||
**Why not write OMML directly?**
|
||||
- Models are naturally proficient in LaTeX (abundant in training data)
|
||||
- LaTeX is semantically clear and highly readable
|
||||
- Conversion layer is encapsulated internally, transparent to the user
|
||||
|
||||
## Quick Start
|
||||
|
||||
```js
|
||||
const { Math: OoxmlMath, MathRun, MathFraction, MathSuperScript,
|
||||
MathSubScript, MathRadical, MathSum, MathSubSuperScript } = require("docx");
|
||||
|
||||
// Embed formula in paragraph
|
||||
new Paragraph({
|
||||
alignment: AlignmentType.CENTER,
|
||||
children: [
|
||||
new OoxmlMath({
|
||||
children: [/* Math components */]
|
||||
})
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
## LaTeX → docx-js Conversion Table
|
||||
|
||||
### Basic Operations
|
||||
|
||||
| LaTeX | Meaning | docx-js Implementation |
|
||||
|-------|---------|----------------------|
|
||||
| `x + y` | Addition | `new MathRun("x + y")` |
|
||||
| `x - y` | Subtraction | `new MathRun("x − y")` (use Unicode minus `−`) |
|
||||
| `x \times y` | Multiplication | `new MathRun("x × y")` |
|
||||
| `x \div y` | Division | `new MathRun("x ÷ y")` |
|
||||
| `x \pm y` | Plus-minus | `new MathRun("x ± y")` |
|
||||
| `x \neq y` | Not equal | `new MathRun("x ≠ y")` |
|
||||
| `x \leq y` | Less or equal | `new MathRun("x ≤ y")` |
|
||||
| `x \geq y` | Greater or equal | `new MathRun("x ≥ y")` |
|
||||
|
||||
### Fractions
|
||||
|
||||
| LaTeX | docx-js |
|
||||
|-------|---------|
|
||||
| `\frac{a}{b}` | `new MathFraction({ numerator: [new MathRun("a")], denominator: [new MathRun("b")] })` |
|
||||
| `\frac{x+1}{x-1}` | `new MathFraction({ numerator: [new MathRun("x+1")], denominator: [new MathRun("x−1")] })` |
|
||||
|
||||
### Superscripts & Subscripts
|
||||
|
||||
| LaTeX | docx-js |
|
||||
|-------|---------|
|
||||
| `x^2` | `new MathSuperScript({ children: [new MathRun("x")], superScript: [new MathRun("2")] })` |
|
||||
| `x_i` | `new MathSubScript({ children: [new MathRun("x")], subScript: [new MathRun("i")] })` |
|
||||
| `x_i^2` | `new MathSubSuperScript({ children: [new MathRun("x")], subScript: [new MathRun("i")], superScript: [new MathRun("2")] })` |
|
||||
|
||||
### Radicals
|
||||
|
||||
| LaTeX | docx-js |
|
||||
|-------|---------|
|
||||
| `\sqrt{x}` | `new MathRadical({ children: [new MathRun("x")] })` |
|
||||
| `\sqrt[3]{x}` | `new MathRadical({ children: [new MathRun("x")], degree: [new MathRun("3")] })` |
|
||||
|
||||
### Summation & Integrals
|
||||
|
||||
| LaTeX | docx-js |
|
||||
|-------|---------|
|
||||
| `\sum_{i=1}^{n}` | `new MathSum({ subScript: [new MathRun("i=1")], superScript: [new MathRun("n")], children: [new MathRun("aᵢ")] })` |
|
||||
|
||||
### Greek Letters
|
||||
|
||||
Use Unicode characters directly:
|
||||
|
||||
```js
|
||||
// LaTeX → Unicode mapping
|
||||
const GREEK = {
|
||||
"\\alpha": "α", "\\beta": "β", "\\gamma": "γ", "\\delta": "δ",
|
||||
"\\epsilon": "ε", "\\zeta": "ζ", "\\eta": "η", "\\theta": "θ",
|
||||
"\\iota": "ι", "\\kappa": "κ", "\\lambda": "λ", "\\mu": "μ",
|
||||
"\\nu": "ν", "\\xi": "ξ", "\\pi": "π", "\\rho": "ρ",
|
||||
"\\sigma": "σ", "\\tau": "τ", "\\phi": "φ", "\\chi": "χ",
|
||||
"\\psi": "ψ", "\\omega": "ω",
|
||||
"\\Alpha": "Α", "\\Beta": "Β", "\\Gamma": "Γ", "\\Delta": "Δ",
|
||||
"\\Theta": "Θ", "\\Lambda": "Λ", "\\Pi": "Π", "\\Sigma": "Σ",
|
||||
"\\Phi": "Φ", "\\Psi": "Ψ", "\\Omega": "Ω",
|
||||
};
|
||||
```
|
||||
|
||||
## Complete Formula Examples
|
||||
|
||||
### Quadratic Formula
|
||||
|
||||
LaTeX: `x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}`
|
||||
|
||||
```js
|
||||
new OoxmlMath({
|
||||
children: [
|
||||
new MathRun("x = "),
|
||||
new MathFraction({
|
||||
numerator: [
|
||||
new MathRun("−b ± "),
|
||||
new MathRadical({
|
||||
children: [
|
||||
new MathSuperScript({
|
||||
children: [new MathRun("b")],
|
||||
superScript: [new MathRun("2")],
|
||||
}),
|
||||
new MathRun(" − 4ac"),
|
||||
],
|
||||
}),
|
||||
],
|
||||
denominator: [new MathRun("2a")],
|
||||
}),
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
### Pythagorean Theorem
|
||||
|
||||
LaTeX: `a^2 + b^2 = c^2`
|
||||
|
||||
```js
|
||||
new OoxmlMath({
|
||||
children: [
|
||||
new MathSuperScript({ children: [new MathRun("a")], superScript: [new MathRun("2")] }),
|
||||
new MathRun(" + "),
|
||||
new MathSuperScript({ children: [new MathRun("b")], superScript: [new MathRun("2")] }),
|
||||
new MathRun(" = "),
|
||||
new MathSuperScript({ children: [new MathRun("c")], superScript: [new MathRun("2")] }),
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
### Trigonometric Identity
|
||||
|
||||
LaTeX: `\sin^2\theta + \cos^2\theta = 1`
|
||||
|
||||
```js
|
||||
new OoxmlMath({
|
||||
children: [
|
||||
new MathSuperScript({ children: [new MathRun("sin")], superScript: [new MathRun("2")] }),
|
||||
new MathRun("θ + "),
|
||||
new MathSuperScript({ children: [new MathRun("cos")], superScript: [new MathRun("2")] }),
|
||||
new MathRun("θ = 1"),
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
## Common Exam Formula Templates
|
||||
|
||||
### Middle School Math
|
||||
|
||||
```js
|
||||
// Quadratic discriminant
|
||||
const discriminant = new OoxmlMath({
|
||||
children: [
|
||||
new MathRun("Δ = "),
|
||||
new MathSuperScript({ children: [new MathRun("b")], superScript: [new MathRun("2")] }),
|
||||
new MathRun(" − 4ac"),
|
||||
],
|
||||
});
|
||||
|
||||
// Circle area
|
||||
const circleArea = new OoxmlMath({
|
||||
children: [
|
||||
new MathRun("S = π"),
|
||||
new MathSuperScript({ children: [new MathRun("r")], superScript: [new MathRun("2")] }),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
### High School Math
|
||||
|
||||
```js
|
||||
// Logarithm change of base
|
||||
const logChange = new OoxmlMath({
|
||||
children: [
|
||||
new MathSubScript({ children: [new MathRun("log")], subScript: [new MathRun("a")] }),
|
||||
new MathRun("b = "),
|
||||
new MathFraction({
|
||||
numerator: [new MathRun("ln b")],
|
||||
denominator: [new MathRun("ln a")],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
// Arithmetic series sum
|
||||
const arithmeticSum = new OoxmlMath({
|
||||
children: [
|
||||
new MathSubScript({ children: [new MathRun("S")], subScript: [new MathRun("n")] }),
|
||||
new MathRun(" = "),
|
||||
new MathFraction({
|
||||
numerator: [
|
||||
new MathRun("n("),
|
||||
new MathSubScript({ children: [new MathRun("a")], subScript: [new MathRun("1")] }),
|
||||
new MathRun(" + "),
|
||||
new MathSubScript({ children: [new MathRun("a")], subScript: [new MathRun("n")] }),
|
||||
new MathRun(")"),
|
||||
],
|
||||
denominator: [new MathRun("2")],
|
||||
}),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
### Physics
|
||||
|
||||
```js
|
||||
// Newton's second law
|
||||
const newton2 = new OoxmlMath({
|
||||
children: [new MathRun("F = ma")],
|
||||
});
|
||||
|
||||
// Kinetic energy
|
||||
const kineticEnergy = new OoxmlMath({
|
||||
children: [
|
||||
new MathSubScript({ children: [new MathRun("E")], subScript: [new MathRun("k")] }),
|
||||
new MathRun(" = "),
|
||||
new MathFraction({
|
||||
numerator: [new MathRun("1")],
|
||||
denominator: [new MathRun("2")],
|
||||
}),
|
||||
new MathRun("m"),
|
||||
new MathSuperScript({ children: [new MathRun("v")], superScript: [new MathRun("2")] }),
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
## Complexity Fallback Strategy
|
||||
|
||||
When formulas are too complex (nesting >3 levels) for docx-js Math, **fall back to matplotlib PNG rendering:**
|
||||
|
||||
```python
|
||||
import matplotlib
|
||||
matplotlib.use("Agg")
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
def latex_to_png(latex_str: str, output_path: str, fontsize: int = 14, dpi: int = 200):
|
||||
"""Render LaTeX formula as PNG image"""
|
||||
fig, ax = plt.subplots(figsize=(0.1, 0.1))
|
||||
ax.axis("off")
|
||||
text = ax.text(0, 0.5, f"${latex_str}$", fontsize=fontsize,
|
||||
transform=ax.transAxes, verticalalignment="center")
|
||||
|
||||
fig.canvas.draw()
|
||||
bbox = text.get_window_extent(fig.canvas.get_renderer())
|
||||
fig.set_size_inches(bbox.width / dpi + 0.2, bbox.height / dpi + 0.2)
|
||||
|
||||
plt.savefig(output_path, dpi=dpi, bbox_inches="tight",
|
||||
pad_inches=0.05, transparent=True)
|
||||
plt.close()
|
||||
return output_path
|
||||
```
|
||||
|
||||
Then embed the PNG in the document:
|
||||
|
||||
```js
|
||||
const formulaImg = fs.readFileSync("formula.png");
|
||||
new Paragraph({
|
||||
alignment: AlignmentType.CENTER,
|
||||
children: [new ImageRun({
|
||||
data: formulaImg,
|
||||
transformation: { width: 300, height: 40 }, // adjust based on actual size
|
||||
type: "png",
|
||||
})],
|
||||
})
|
||||
```
|
||||
|
||||
**Fallback rules:**
|
||||
- Nested fractions >2 levels → fallback
|
||||
- Matrices/determinants → fallback
|
||||
- Complex integrals (multiple integrals + limits + integrand) → fallback
|
||||
- Piecewise functions → fallback
|
||||
- All other cases → prefer docx-js Math
|
||||
Reference in New Issue
Block a user