Squashed 'vendor/ruvector/' content from commit b64c2172

git-subtree-dir: vendor/ruvector
git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
This commit is contained in:
ruv
2026-02-28 14:39:40 -05:00
commit d803bfe2b1
7854 changed files with 3522914 additions and 0 deletions

View File

@@ -0,0 +1,395 @@
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
use std::time::Duration;
/// Benchmark simple LaTeX expression generation
fn bench_simple_expressions(c: &mut Criterion) {
let mut group = c.benchmark_group("simple_expressions");
group.measurement_time(Duration::from_secs(5));
let test_cases = vec![
(
"fraction",
Expression::Fraction(
Box::new(Expression::Number(1)),
Box::new(Expression::Number(2)),
),
),
(
"power",
Expression::Power(
Box::new(Expression::Variable("x".to_string())),
Box::new(Expression::Number(2)),
),
),
(
"sum",
Expression::Sum(
Box::new(Expression::Number(1)),
Box::new(Expression::Number(2)),
),
),
(
"product",
Expression::Product(
Box::new(Expression::Variable("a".to_string())),
Box::new(Expression::Variable("b".to_string())),
),
),
];
for (name, expr) in test_cases {
group.bench_with_input(BenchmarkId::new("to_latex", name), &expr, |b, expr| {
b.iter(|| black_box(expr.to_latex()));
});
}
group.finish();
}
/// Benchmark complex LaTeX expression generation
fn bench_complex_expressions(c: &mut Criterion) {
let mut group = c.benchmark_group("complex_expressions");
group.measurement_time(Duration::from_secs(8));
// Create complex nested expressions
let test_cases = vec![
("matrix_2x2", create_matrix(2, 2)),
("matrix_3x3", create_matrix(3, 3)),
("matrix_4x4", create_matrix(4, 4)),
("integral", create_integral()),
("summation", create_summation()),
("nested_fraction", create_nested_fraction(3)),
("polynomial", create_polynomial(5)),
];
for (name, expr) in test_cases {
group.bench_with_input(BenchmarkId::new("to_latex", name), &expr, |b, expr| {
b.iter(|| black_box(expr.to_latex()));
});
}
group.finish();
}
/// Benchmark AST traversal performance
fn bench_ast_traversal(c: &mut Criterion) {
let mut group = c.benchmark_group("ast_traversal");
group.measurement_time(Duration::from_secs(5));
let depths = [3, 5, 7, 10];
for depth in depths {
let expr = create_nested_expression(depth);
group.bench_with_input(BenchmarkId::new("depth", depth), &expr, |b, expr| {
b.iter(|| black_box(count_nodes(black_box(expr))));
});
}
group.finish();
}
/// Benchmark string building and concatenation
fn bench_string_building(c: &mut Criterion) {
let mut group = c.benchmark_group("string_building");
group.measurement_time(Duration::from_secs(5));
let expr = create_polynomial(20);
// Compare different string building strategies
group.bench_function("to_latex_default", |b| {
b.iter(|| black_box(expr.to_latex()));
});
group.bench_function("to_latex_with_capacity", |b| {
b.iter(|| black_box(expr.to_latex_with_capacity()));
});
group.finish();
}
/// Benchmark LaTeX escaping and special characters
fn bench_latex_escaping(c: &mut Criterion) {
let mut group = c.benchmark_group("latex_escaping");
group.measurement_time(Duration::from_secs(5));
let test_strings = vec![
("no_special", "simple text"),
("underscores", "var_1 + var_2"),
("braces", "{x} + {y}"),
("mixed", "α + β_1^2 ∫ dx"),
];
for (name, text) in test_strings {
group.bench_with_input(BenchmarkId::new("escape", name), &text, |b, text| {
b.iter(|| black_box(escape_latex(black_box(text))));
});
}
group.finish();
}
/// Benchmark target: LaTeX generation should complete in <5ms
fn bench_latency_target(c: &mut Criterion) {
let mut group = c.benchmark_group("latency_target_5ms");
group.measurement_time(Duration::from_secs(10));
group.sample_size(100);
// Typical complex expression from OCR
let expr = create_typical_ocr_expression();
group.bench_function("typical_ocr_expression", |b| {
b.iter(|| black_box(expr.to_latex()));
});
group.finish();
}
/// Benchmark batch LaTeX generation
fn bench_batch_generation(c: &mut Criterion) {
let mut group = c.benchmark_group("batch_generation");
group.measurement_time(Duration::from_secs(10));
let batch_sizes = [10, 50, 100];
for size in batch_sizes {
let expressions: Vec<_> = (0..size).map(|i| create_polynomial(i % 10 + 1)).collect();
group.bench_with_input(
BenchmarkId::new("batch_size", size),
&expressions,
|b, exprs| {
b.iter(|| {
let results: Vec<_> = exprs.iter().map(|expr| expr.to_latex()).collect();
black_box(results)
});
},
);
}
group.finish();
}
// Mock AST and Expression types
#[derive(Clone)]
enum Expression {
Number(i32),
Variable(String),
Fraction(Box<Expression>, Box<Expression>),
Power(Box<Expression>, Box<Expression>),
Sum(Box<Expression>, Box<Expression>),
Product(Box<Expression>, Box<Expression>),
Matrix(Vec<Vec<Expression>>),
Integral(Box<Expression>, String, String, String),
Summation(Box<Expression>, String, String, String),
}
impl Expression {
fn to_latex(&self) -> String {
match self {
Expression::Number(n) => n.to_string(),
Expression::Variable(v) => v.clone(),
Expression::Fraction(num, den) => {
format!("\\frac{{{}}}{{{}}}", num.to_latex(), den.to_latex())
}
Expression::Power(base, exp) => {
format!("{{{}}}^{{{}}}", base.to_latex(), exp.to_latex())
}
Expression::Sum(a, b) => {
format!("{} + {}", a.to_latex(), b.to_latex())
}
Expression::Product(a, b) => {
format!("{} \\cdot {}", a.to_latex(), b.to_latex())
}
Expression::Matrix(rows) => {
let mut result = String::from("\\begin{bmatrix}");
for (i, row) in rows.iter().enumerate() {
for (j, cell) in row.iter().enumerate() {
result.push_str(&cell.to_latex());
if j < row.len() - 1 {
result.push_str(" & ");
}
}
if i < rows.len() - 1 {
result.push_str(" \\\\ ");
}
}
result.push_str("\\end{bmatrix}");
result
}
Expression::Integral(expr, var, lower, upper) => {
format!(
"\\int_{{{}}}^{{{}}} {} \\, d{}",
lower,
upper,
expr.to_latex(),
var
)
}
Expression::Summation(expr, var, lower, upper) => {
format!(
"\\sum_{{{}={}}}^{{{}}} {}",
var,
lower,
upper,
expr.to_latex()
)
}
}
}
fn to_latex_with_capacity(&self) -> String {
let mut result = String::with_capacity(256);
self.append_latex(&mut result);
result
}
fn append_latex(&self, buffer: &mut String) {
buffer.push_str(&self.to_latex());
}
}
fn create_matrix(rows: usize, cols: usize) -> Expression {
let matrix = (0..rows)
.map(|i| {
(0..cols)
.map(|j| Expression::Number((i * cols + j) as i32))
.collect()
})
.collect();
Expression::Matrix(matrix)
}
fn create_integral() -> Expression {
Expression::Integral(
Box::new(Expression::Power(
Box::new(Expression::Variable("x".to_string())),
Box::new(Expression::Number(2)),
)),
"x".to_string(),
"0".to_string(),
"1".to_string(),
)
}
fn create_summation() -> Expression {
Expression::Summation(
Box::new(Expression::Power(
Box::new(Expression::Variable("i".to_string())),
Box::new(Expression::Number(2)),
)),
"i".to_string(),
"1".to_string(),
"n".to_string(),
)
}
fn create_nested_fraction(depth: usize) -> Expression {
if depth == 0 {
Expression::Number(1)
} else {
Expression::Fraction(
Box::new(Expression::Number(1)),
Box::new(create_nested_fraction(depth - 1)),
)
}
}
fn create_polynomial(degree: usize) -> Expression {
let mut expr = Expression::Number(0);
for i in 0..=degree {
let term = Expression::Product(
Box::new(Expression::Number(i as i32 + 1)),
Box::new(Expression::Power(
Box::new(Expression::Variable("x".to_string())),
Box::new(Expression::Number(i as i32)),
)),
);
expr = Expression::Sum(Box::new(expr), Box::new(term));
}
expr
}
fn create_nested_expression(depth: usize) -> Expression {
if depth == 0 {
Expression::Variable("x".to_string())
} else {
Expression::Sum(
Box::new(create_nested_expression(depth - 1)),
Box::new(Expression::Number(depth as i32)),
)
}
}
fn create_typical_ocr_expression() -> Expression {
// Typical expression: (a + b)^2 = a^2 + 2ab + b^2
Expression::Sum(
Box::new(Expression::Sum(
Box::new(Expression::Power(
Box::new(Expression::Variable("a".to_string())),
Box::new(Expression::Number(2)),
)),
Box::new(Expression::Product(
Box::new(Expression::Product(
Box::new(Expression::Number(2)),
Box::new(Expression::Variable("a".to_string())),
)),
Box::new(Expression::Variable("b".to_string())),
)),
)),
Box::new(Expression::Power(
Box::new(Expression::Variable("b".to_string())),
Box::new(Expression::Number(2)),
)),
)
}
fn count_nodes(expr: &Expression) -> usize {
match expr {
Expression::Number(_) | Expression::Variable(_) => 1,
Expression::Fraction(a, b)
| Expression::Power(a, b)
| Expression::Sum(a, b)
| Expression::Product(a, b) => 1 + count_nodes(a) + count_nodes(b),
Expression::Matrix(rows) => {
1 + rows
.iter()
.map(|row| row.iter().map(|e| count_nodes(e)).sum::<usize>())
.sum::<usize>()
}
Expression::Integral(expr, _, _, _) | Expression::Summation(expr, _, _, _) => {
1 + count_nodes(expr)
}
}
}
fn escape_latex(text: &str) -> String {
text.chars()
.map(|c| match c {
'_' => "\\_".to_string(),
'{' => "\\{".to_string(),
'}' => "\\}".to_string(),
'&' => "\\&".to_string(),
'%' => "\\%".to_string(),
'$' => "\\$".to_string(),
'#' => "\\#".to_string(),
'^' => "\\^{}".to_string(),
'~' => "\\~{}".to_string(),
'\\' => "\\textbackslash{}".to_string(),
_ => c.to_string(),
})
.collect()
}
criterion_group!(
benches,
bench_simple_expressions,
bench_complex_expressions,
bench_ast_traversal,
bench_string_building,
bench_latex_escaping,
bench_latency_target,
bench_batch_generation
);
criterion_main!(benches);