const KNOWN_FUNCTIONS: &[&str] = &[
"sin",
"cos",
"tan",
"csc",
"sec",
"cot",
"arcsin",
"arccos",
"arctan",
"sinh",
"cosh",
"tanh",
"log",
"ln",
"exp",
"sqrt",
"abs",
"floor",
"ceil",
"round",
"sign",
"min",
"max",
"gcd",
"lcm",
"atan2",
"cbrt",
"pow",
"sgn",
"lg",
"asin",
"acos",
"atan",
"log2",
"diff",
"partial",
"integrate",
"integral",
"sum",
"summation",
"product",
"prod",
"limit",
"lim",
"grad",
"nabla",
"div",
"curl",
"laplacian",
"dot",
"cross",
"det",
"tr",
"rank",
"gamma",
"beta",
"erf",
"erfc",
"zeta",
"bessel_j",
"bessel_y",
"bessel_i",
"bessel_k",
"besselj",
"bessely",
"besseli",
"besselk",
"laplace",
"fourier",
"ilaplace",
"ifourier",
"laplace_transform",
"fourier_transform",
];
pub(crate) fn levenshtein(a: &str, b: &str) -> usize {
let a_chars: Vec<char> = a.chars().collect();
let b_chars: Vec<char> = b.chars().collect();
let a_len = a_chars.len();
let b_len = b_chars.len();
if a_len == 0 {
return b_len;
}
if b_len == 0 {
return a_len;
}
let mut prev_row: Vec<usize> = (0..=b_len).collect();
let mut curr_row: Vec<usize> = vec![0; b_len + 1];
for (i, a_char) in a_chars.iter().enumerate() {
curr_row[0] = i + 1;
for (j, b_char) in b_chars.iter().enumerate() {
let cost = if a_char == b_char { 0 } else { 1 };
curr_row[j + 1] = std::cmp::min(
std::cmp::min(curr_row[j] + 1, prev_row[j + 1] + 1),
prev_row[j] + cost,
);
}
std::mem::swap(&mut prev_row, &mut curr_row);
}
prev_row[b_len]
}
pub fn suggest_function(unknown: &str) -> Option<String> {
KNOWN_FUNCTIONS
.iter()
.filter(|&&f| levenshtein(unknown, f) <= 2)
.min_by_key(|&&f| levenshtein(unknown, f))
.map(|&f| format!("Did you mean '{}'?", f))
}