#![allow(dead_code)]
use formulaa::ast::{Node, Row, normalize};
use formulaa::latex::row_to_latex;
use formulaa::render::{RenderCtx, render_row};
use formulaa::symbols::Radical;
use formulaa::symbols::{Accent, Arrow, ColDelim};
fn s(t: &str) -> Row {
t.chars().map(Node::Sym).collect()
}
fn n(node: Node) -> Row {
vec![node]
}
fn frac(num: Row, den: Row) -> Node {
Node::Frac { num, den }
}
fn sqrt(arg: Row) -> Node {
Node::Sqrt {
arg,
index: Radical::Sqrt,
}
}
fn cbrt(arg: Row) -> Node {
Node::Sqrt {
arg,
index: Radical::Cbrt,
}
}
fn sup(arg: Row) -> Node {
Node::Sup { arg }
}
fn sub(arg: Row) -> Node {
Node::Sub { arg }
}
fn paren(inner: Row) -> Node {
Node::Delim {
left: formulaa::symbols::Delim::Col(ColDelim::Paren),
right: formulaa::symbols::Delim::Col(ColDelim::Paren),
mids: 0,
segs: vec![inner],
}
}
fn bigop(op: char, lower: Row, upper: Row) -> Node {
Node::BigOpSym { op, lower, upper }
}
fn opname(name: &str, lower: Row, upper: Row) -> Node {
Node::BigOp {
name: name.into(),
lower,
upper,
}
}
fn func(name: &str) -> Node {
Node::Func(name.into())
}
fn acc(accent: Accent, base: char) -> Node {
if accent.under() {
Node::Accent {
overs: vec![],
unders: vec![accent],
base,
}
} else {
Node::Accent {
overs: vec![accent],
unders: vec![],
base,
}
}
}
fn mat(rows: usize, cols: usize, cells: Vec<Row>) -> Node {
assert_eq!(cells.len(), rows * cols);
Node::Delim {
left: formulaa::symbols::Delim::Col(ColDelim::Bracket),
right: formulaa::symbols::Delim::Col(ColDelim::Bracket),
mids: 0,
segs: vec![vec![Node::Array { rows, cols, cells }]],
}
}
fn cat(parts: &[Row]) -> Row {
parts.concat()
}
fn roundtrip(name: &str, row: &Row) {
let row = normalize(row);
let ctx = RenderCtx::canonical();
let aa = render_row(&row, None, false, &ctx).to_text();
println!("### {}\n", name);
println!("```plain\n{}\n```\n", aa);
println!("LaTeX:\n\n```latex\n{}\n```\n", row_to_latex(&row));
}
fn cardano_formula() {
let discriminant = sqrt(cat(&[
n(frac(cat(&[s("q"), n(sup(s("2")))]), s("4"))),
s("+"),
n(frac(cat(&[s("p"), n(sup(s("3")))]), s("27"))),
]));
let half_q = |sign: &str| {
cat(&[
s(sign),
n(frac(s("q"), s("2"))),
s(if sign == "-" { "+" } else { "-" }),
n(discriminant.clone()),
])
};
let row = cat(&[s("t="), n(cbrt(half_q("-"))), s("+"), n(cbrt(half_q("")))]);
roundtrip("cardano", &row);
}
fn cauchy_schwarz_inequality() {
let sum = |body: Row| {
n(bigop('∑', s("k=1"), s("n")))
.into_iter()
.chain(body)
.collect::<Row>()
};
let row = cat(&[
n(paren(sum(cat(&[
s("u"),
n(sub(s("k"))),
n(acc(Accent::Bar, 'v')),
n(sub(s("k"))),
])))),
n(sup(s("2"))),
s("≤"),
n(paren(sum(cat(&[s("u"), n(sub(s("k"))), n(sup(s("2")))])))),
n(paren(sum(cat(&[s("v"), n(sub(s("k"))), n(sup(s("2")))])))),
]);
roundtrip("cauchy-schwarz", &row);
}
fn vandermonde_determinant() {
let x = |i: &str, p: Option<&str>| -> Row {
let mut row = cat(&[s("x"), n(sub(s(i)))]);
if let Some(p) = p {
row.push(sup(s(p)));
}
row
};
let m = mat(
4,
5,
vec![
s("1"),
x("1", None),
x("1", Some("2")),
s("⋯"),
x("1", Some("n-1")),
s("1"),
x("2", None),
x("2", Some("2")),
s("⋯"),
x("2", Some("n-1")),
s("⋮"),
s("⋮"),
s("⋮"),
s("⋱"),
s("⋮"),
s("1"),
x("n", None),
x("n", Some("2")),
s("⋯"),
x("n", Some("n-1")),
],
);
let row = cat(&[
n(m),
s("="),
n(bigop('∏', s("1≤i<j≤n"), vec![])),
n(paren(cat(&[
s("x"),
n(sub(s("j"))),
s("-"),
s("x"),
n(sub(s("i"))),
]))),
]);
roundtrip("vandermonde", &row);
}
fn gaussian_integral() {
let row = cat(&[
n(bigop('∫', s("-∞"), s("∞"))),
s("e"),
n(sup(cat(&[s("-x"), n(sup(s("2")))]))),
s("dx="),
n(sqrt(s("π"))),
]);
roundtrip("gaussian", &row);
}
fn schroedinger_equation() {
let row = cat(&[
s("iℏ"),
n(frac(s("∂Ψ"), s("∂t"))),
s("=-"),
n(frac(cat(&[s("ℏ"), n(sup(s("2")))]), s("2m"))),
n(frac(
cat(&[s("∂"), n(sup(s("2"))), s("Ψ")]),
cat(&[s("∂x"), n(sup(s("2")))]),
)),
s("+V"),
n(paren(s("x"))),
s("Ψ"),
]);
roundtrip("schroedinger", &row);
}
fn gauss_law() {
let row = cat(&[
n(bigop('∮', vec![], vec![])),
n(acc(Accent::Vec, 'E')),
s("⋅d"),
n(acc(Accent::Vec, 'A')),
s("="),
n(frac(s("Q"), cat(&[s("ε"), n(sub(s("0")))]))),
]);
roundtrip("gauss-law", &row);
}
fn cauchy_integral_formula() {
let row = cat(&[
s("f"),
n(paren(s("a"))),
s("="),
n(frac(s("1"), s("2πi"))),
n(bigop('∮', vec![], vec![])),
n(frac(cat(&[s("f"), n(paren(s("z")))]), cat(&[s("z-a")]))),
s("dz"),
]);
roundtrip("cauchy-integral", &row);
}
fn euler_identity() {
let row = cat(&[s("e"), n(sup(s("iπ"))), s("+1=0")]);
roundtrip("euler", &row);
}
fn normal_pdf() {
let row = cat(&[
s("f"),
n(paren(s("x"))),
s("="),
n(frac(s("1"), n(sqrt(cat(&[s("2πσ"), n(sup(s("2")))]))))),
s("e"),
n(sup(cat(&[
s("-"),
n(frac(
cat(&[n(paren(s("x-μ"))), n(sup(s("2")))]),
cat(&[s("2σ"), n(sup(s("2")))]),
)),
]))),
]);
roundtrip("normal-pdf", &row);
}
fn variance() {
let row = cat(&[
s("σ"),
n(sup(s("2"))),
s("="),
n(frac(s("1"), s("n"))),
n(bigop('∑', s("i=1"), s("n"))),
n(paren(cat(&[s("x"), n(sub(s("i"))), s("-μ")]))),
n(sup(s("2"))),
]);
roundtrip("variance", &row);
}
fn bayes_theorem() {
let p = |arg: &str| cat(&[s("P"), n(paren(s(arg)))]);
let row = cat(&[p("A|B"), s("="), n(frac(cat(&[p("B|A"), p("A")]), p("B")))]);
roundtrip("bayes", &row);
}
fn rotation_matrix() {
let row = cat(&[
s("R="),
n(mat(
2,
2,
vec![
cat(&[n(func("cos")), s("θ")]),
cat(&[s("-"), n(func("sin")), s("θ")]),
cat(&[n(func("sin")), s("θ")]),
cat(&[n(func("cos")), s("θ")]),
],
)),
]);
roundtrip("rotation", &row);
}
fn matrix_exponential() {
let row = cat(&[
s("e"),
n(sup(cat(&[
n(mat(2, 2, vec![s("0"), s("1"), s("-1"), s("0")])),
s("t"),
]))),
]);
roundtrip("matrix-exponential", &row);
}
fn nested_matrices() {
let inner = mat(2, 2, vec![s("a"), s("b"), s("c"), s("d")]);
let row = n(mat(
2,
2,
vec![
n(frac(s("1"), s("2"))),
s("0"),
n(inner),
cat(&[s("x"), n(sup(s("2")))]),
],
));
roundtrip("nested-matrices", &row);
}
fn continued_fraction() {
let mut row = s("x");
for _ in 0..4 {
row = cat(&[s("1+"), n(frac(s("1"), row))]);
}
roundtrip("continued-fraction", &row);
}
fn delim(left: char, right: char, mids: Vec<char>, segs: Vec<Row>) -> Node {
use formulaa::symbols::Delim;
Node::Delim {
left: Delim::of_spec_side(left, true).unwrap(),
right: Delim::of_spec_side(right, false).unwrap(),
mids: mids.len(),
segs,
}
}
fn array(rows: usize, cols: usize, cells: Vec<Row>) -> Node {
Node::Array { rows, cols, cells }
}
fn cases_abs() {
let row = cat(&[
n(delim('|', '|', vec![], vec![s("x")])),
s("="),
n(delim(
'{',
'.',
vec![],
vec![n(array(2, 2, vec![s("x"), s("x≥0"), s("-x"), s("x<0")]))],
)),
]);
roundtrip("cases-abs", &row);
}
fn braket_and_set() {
let row = n(delim(
'⟨',
'⟩',
vec!['|', '|'],
vec![s("ψ"), s("H"), s("ψ")],
));
roundtrip("braket", &row);
let row = n(delim(
'{',
'}',
vec!['|'],
vec![
s("x"),
cat(&[s("x"), n(sup(s("2"))), s(">"), n(frac(s("1"), s("2")))]),
],
));
roundtrip("set-builder", &row);
}
fn interval_and_bare_array() {
roundtrip("interval", &n(delim('(', ']', vec![], vec![s("0,1")])));
roundtrip(
"bare-array",
&n(array(2, 2, vec![s("a"), s("b"), s("c"), s("d")])),
);
}
fn nested_limits() {
let row = cat(&[
n(bigop(
'∑',
cat(&[
s("i∈"),
n(bigop('⋃', s("k"), vec![])),
s("S"),
n(sub(s("k"))),
]),
n(frac(s("n"), s("2"))),
)),
s("a"),
n(sub(s("i"))),
]);
roundtrip("nested-limits", &row);
}
fn braces_over_under() {
let row = cat(&[
n(Node::Brace {
over: true,
arg: cat(&[s("a"), s("+"), s("b")]),
label: s("n"),
}),
s("+"),
n(Node::Brace {
over: false,
arg: s("c"),
label: s("m"),
}),
]);
roundtrip("overbrace", &row);
}
fn limit_funcs() {
let row = cat(&[
n(Node::BigOp {
name: "lim".into(),
lower: cat(&[s("x"), s("→"), s("0")]),
upper: vec![],
}),
s("f"),
n(paren(s("x"))),
]);
roundtrip("lim", &row);
let row = cat(&[
n(Node::BigOp {
name: "argmax".into(),
lower: s("x∈S"),
upper: vec![],
}),
s("f"),
n(paren(s("x"))),
]);
roundtrip("argmax", &row);
}
fn arrows_and_text() {
let row = cat(&[
s("A"),
n(Node::Arrow {
op: Arrow::To,
over: s("f"),
under: s("n→∞"),
}),
s("B"),
]);
roundtrip("xrightarrow", &row);
let row = cat(&[
n(bigop('∫', vec![], vec![])),
s("f"),
n(paren(s("x"))),
n(Node::Func("dx".into())),
]);
roundtrip("mathrm-dx", &row);
}
fn main() {
println!("# Formula corpus catalog\n");
println!("Side-by-side listing of the roundtrip-verified formulas in");
println!("`tests/roundtrip.rs`. Regenerate with");
println!("`cargo run --example catalog > docs/examples.md`.\n");
println!("Every formula satisfies `parse(render(normalize(x))) == normalize(x)`");
println!("and `render(parse(aa)) == aa` (the AA feeds straight into `formulaa --aa2latex`).\n");
println!("## MDN's three famous mathematical formulas\n");
cardano_formula();
cauchy_schwarz_inequality();
vandermonde_determinant();
println!("## Physics\n");
gaussian_integral();
schroedinger_equation();
gauss_law();
cauchy_integral_formula();
euler_identity();
println!("## Statistics\n");
normal_pdf();
variance();
bayes_theorem();
println!("## Structural stress tests\n");
rotation_matrix();
matrix_exponential();
nested_matrices();
continued_fraction();
nested_limits();
println!("## Delimiters\n");
cases_abs();
braket_and_set();
interval_and_bare_array();
println!("## Arrows and text\n");
arrows_and_text();
println!("## Limit-taking functions\n");
limit_funcs();
println!("## Braces\n");
braces_over_under();
println!("<!-- regenerated by examples/catalog.rs -->");
}