#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum Method {
Multistart,
Mlsl,
Basinhopping,
Flooding,
Deflation,
Tunneling,
}
impl Method {
pub fn parse(s: &str) -> Result<Self, String> {
Ok(match s {
"multistart" => Self::Multistart,
"mlsl" => Self::Mlsl,
"basinhopping" => Self::Basinhopping,
"flooding" => Self::Flooding,
"deflation" => Self::Deflation,
"tunneling" => Self::Tunneling,
other => {
return Err(format!(
"unknown --minima method '{other}'; choose from \
multistart, mlsl, basinhopping, flooding, deflation, tunneling"
));
}
})
}
pub fn as_str(&self) -> &'static str {
match self {
Self::Multistart => "multistart",
Self::Mlsl => "mlsl",
Self::Basinhopping => "basinhopping",
Self::Flooding => "flooding",
Self::Deflation => "deflation",
Self::Tunneling => "tunneling",
}
}
}
#[derive(Debug, Clone)]
pub struct MinimaOptions {
pub method: Method,
pub n_minima: usize,
pub max_solves: Option<usize>,
pub patience: usize,
pub dedup: f64,
pub psd_tol: f64,
pub kkt_tol: Option<f64>,
pub seed: u64,
pub sobol: bool,
pub sigma: Option<f64>,
pub sigma_frac: Option<f64>,
pub amplitude: Option<f64>,
pub amp_margin: Option<f64>,
pub eta: Option<f64>,
pub power: Option<f64>,
pub soft: Option<f64>,
pub length: Option<f64>,
pub length_frac: Option<f64>,
pub gamma: Option<f64>,
pub samples_per_round: Option<usize>,
pub step: Option<f64>,
pub temperature: Option<f64>,
pub restart_jitter: Option<f64>,
pub sigma_per_dim: Option<Vec<f64>>,
pub length_per_dim: Option<Vec<f64>>,
pub max_samples: Option<usize>,
pub amp_bump: Option<f64>,
pub amp_bump_cap: Option<f64>,
pub amp_fallback: Option<f64>,
}
impl MinimaOptions {
fn key(&self) -> OptionsKey {
let bits = |v: &Option<f64>| v.map(f64::to_bits);
let vec_bits =
|v: &Option<Vec<f64>>| v.as_ref().map(|v| v.iter().map(|x| x.to_bits()).collect());
let Self {
method,
n_minima,
max_solves,
patience,
dedup,
psd_tol,
kkt_tol,
seed,
sobol,
sigma,
sigma_frac,
amplitude,
amp_margin,
eta,
power,
soft,
length,
length_frac,
gamma,
samples_per_round,
step,
temperature,
restart_jitter,
sigma_per_dim,
length_per_dim,
max_samples,
amp_bump,
amp_bump_cap,
amp_fallback,
} = self;
OptionsKey {
method: *method,
n_minima: *n_minima,
max_solves: *max_solves,
patience: *patience,
dedup: dedup.to_bits(),
psd_tol: psd_tol.to_bits(),
kkt_tol: bits(kkt_tol),
seed: *seed,
sobol: *sobol,
sigma: bits(sigma),
sigma_frac: bits(sigma_frac),
amplitude: bits(amplitude),
amp_margin: bits(amp_margin),
eta: bits(eta),
power: bits(power),
soft: bits(soft),
length: bits(length),
length_frac: bits(length_frac),
gamma: bits(gamma),
samples_per_round: *samples_per_round,
step: bits(step),
temperature: bits(temperature),
restart_jitter: bits(restart_jitter),
sigma_per_dim: vec_bits(sigma_per_dim),
length_per_dim: vec_bits(length_per_dim),
max_samples: *max_samples,
amp_bump: bits(amp_bump),
amp_bump_cap: bits(amp_bump_cap),
amp_fallback: bits(amp_fallback),
}
}
pub fn max_solves_or_default(&self) -> usize {
self.max_solves.unwrap_or(8 * self.n_minima)
}
}
impl Default for MinimaOptions {
fn default() -> Self {
Self {
method: Method::Deflation,
n_minima: 10,
max_solves: None,
patience: 8,
dedup: 1e-4,
psd_tol: 1e-6,
kkt_tol: Some(1e-4),
seed: 0,
sobol: true,
sigma: None,
sigma_frac: None,
amplitude: None,
amp_margin: None,
eta: None,
power: None,
soft: None,
length: None,
length_frac: None,
gamma: None,
samples_per_round: None,
step: None,
temperature: None,
restart_jitter: None,
sigma_per_dim: None,
length_per_dim: None,
max_samples: None,
amp_bump: None,
amp_bump_cap: None,
amp_fallback: None,
}
}
}
#[derive(PartialEq, Eq, Hash)]
struct OptionsKey {
method: Method,
n_minima: usize,
max_solves: Option<usize>,
patience: usize,
dedup: u64,
psd_tol: u64,
kkt_tol: Option<u64>,
seed: u64,
sobol: bool,
sigma: Option<u64>,
sigma_frac: Option<u64>,
amplitude: Option<u64>,
amp_margin: Option<u64>,
eta: Option<u64>,
power: Option<u64>,
soft: Option<u64>,
length: Option<u64>,
length_frac: Option<u64>,
gamma: Option<u64>,
samples_per_round: Option<usize>,
step: Option<u64>,
temperature: Option<u64>,
restart_jitter: Option<u64>,
sigma_per_dim: Option<Vec<u64>>,
length_per_dim: Option<Vec<u64>>,
max_samples: Option<usize>,
amp_bump: Option<u64>,
amp_bump_cap: Option<u64>,
amp_fallback: Option<u64>,
}
impl PartialEq for MinimaOptions {
fn eq(&self, other: &Self) -> bool {
self.key() == other.key()
}
}
impl Eq for MinimaOptions {}
impl std::hash::Hash for MinimaOptions {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.key().hash(state);
}
}