use super::backend::FilterOptimizer;
use std::sync::OnceLock;
pub fn all_algorithms() -> Vec<Box<dyn FilterOptimizer>> {
let mut algos: Vec<Box<dyn FilterOptimizer>> = Vec::new();
use super::cobyla::AutoeqCobylaBackend;
algos.push(Box::new(AutoeqCobylaBackend::new("autoeq:cobyla")));
use super::isres::AutoeqIsresBackend;
algos.push(Box::new(AutoeqIsresBackend::new("autoeq:isres")));
use super::de::AutoeqDeBackend;
algos.push(Box::new(AutoeqDeBackend::new("autoeq:de")));
use super::mh::MhBackend;
algos.push(Box::new(MhBackend::new_de("mh:de")));
algos.push(Box::new(MhBackend::new_pso("mh:pso")));
algos.push(Box::new(MhBackend::new_rga("mh:rga")));
algos.push(Box::new(MhBackend::new_tlbo("mh:tlbo")));
algos.push(Box::new(MhBackend::new_firefly("mh:firefly")));
algos
}
fn nlopt_deprecation_map(name: &str) -> Option<&'static str> {
let lower = name.to_lowercase();
let mapped = match lower.as_str() {
"nlopt:cobyla" | "nlopt:slsqp" => "autoeq:cobyla",
"nlopt:bobyqa" | "nlopt:neldermead" | "nlopt:sbplx" => "autoeq:cobyla",
"nlopt:isres" | "nlopt:ags" | "nlopt:origdirect" => "autoeq:isres",
"nlopt:crs2lm" | "nlopt:direct" | "nlopt:directl" | "nlopt:gmlsl"
| "nlopt:gmlsllds" | "nlopt:stogo" | "nlopt:stogorand" => "autoeq:de",
_ => return None,
};
Some(mapped)
}
pub fn resolve(name: &str) -> Option<Box<dyn FilterOptimizer>> {
let mut algos = all_algorithms();
if let Some(idx) = algos.iter().position(|a| a.name().eq_ignore_ascii_case(name)) {
return Some(algos.swap_remove(idx));
}
let name_lower = name.to_lowercase();
if let Some(idx) = algos.iter().position(|a| {
a.name()
.split(':')
.nth(1)
.map(|s| s.eq_ignore_ascii_case(&name_lower))
.unwrap_or(false)
}) {
return Some(algos.swap_remove(idx));
}
if let Some(replacement) = nlopt_deprecation_map(name) {
warn_deprecated_once(name, replacement);
return resolve(replacement);
}
None
}
fn warn_deprecated_once(removed: &str, replacement: &str) {
use std::sync::Mutex;
static SEEN: OnceLock<Mutex<Vec<String>>> = OnceLock::new();
let seen = SEEN.get_or_init(|| Mutex::new(Vec::new()));
let mut seen = seen.lock().unwrap();
let key = removed.to_lowercase();
if !seen.iter().any(|k| k == &key) {
seen.push(key);
log::warn!(
"Algorithm '{}' was removed when the C-FFI nlopt dependency was dropped. \
Falling back to '{}' (pure-Rust). Update your config to silence this warning.",
removed,
replacement,
);
}
}