1#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
10pub enum Method {
11 Multistart,
13 Mlsl,
15 Basinhopping,
17 Flooding,
19 Deflation,
21 Tunneling,
23}
24
25impl Method {
26 pub fn parse(s: &str) -> Result<Self, String> {
27 Ok(match s {
28 "multistart" => Self::Multistart,
29 "mlsl" => Self::Mlsl,
30 "basinhopping" => Self::Basinhopping,
31 "flooding" => Self::Flooding,
32 "deflation" => Self::Deflation,
33 "tunneling" => Self::Tunneling,
34 other => {
35 return Err(format!(
36 "unknown --minima method '{other}'; choose from \
37 multistart, mlsl, basinhopping, flooding, deflation, tunneling"
38 ));
39 }
40 })
41 }
42
43 pub fn as_str(&self) -> &'static str {
44 match self {
45 Self::Multistart => "multistart",
46 Self::Mlsl => "mlsl",
47 Self::Basinhopping => "basinhopping",
48 Self::Flooding => "flooding",
49 Self::Deflation => "deflation",
50 Self::Tunneling => "tunneling",
51 }
52 }
53}
54
55#[derive(Debug, Clone)]
64pub struct MinimaOptions {
65 pub method: Method,
66 pub n_minima: usize,
68 pub max_solves: Option<usize>,
70 pub patience: usize,
72 pub dedup: f64,
74 pub psd_tol: f64,
76 pub kkt_tol: Option<f64>,
80 pub seed: u64,
82 pub sobol: bool,
84 pub sigma: Option<f64>,
86 pub sigma_frac: Option<f64>,
87 pub amplitude: Option<f64>,
88 pub amp_margin: Option<f64>,
89 pub eta: Option<f64>,
90 pub power: Option<f64>,
91 pub soft: Option<f64>,
92 pub length: Option<f64>,
93 pub length_frac: Option<f64>,
94 pub gamma: Option<f64>,
95 pub samples_per_round: Option<usize>,
96 pub step: Option<f64>,
97 pub temperature: Option<f64>,
98 pub restart_jitter: Option<f64>,
99 pub sigma_per_dim: Option<Vec<f64>>,
102 pub length_per_dim: Option<Vec<f64>>,
105 pub max_samples: Option<usize>,
107 pub amp_bump: Option<f64>,
109 pub amp_bump_cap: Option<f64>,
111 pub amp_fallback: Option<f64>,
113}
114
115impl MinimaOptions {
116 fn key(&self) -> OptionsKey {
119 let bits = |v: &Option<f64>| v.map(f64::to_bits);
120 let vec_bits =
121 |v: &Option<Vec<f64>>| v.as_ref().map(|v| v.iter().map(|x| x.to_bits()).collect());
122 let Self {
123 method,
124 n_minima,
125 max_solves,
126 patience,
127 dedup,
128 psd_tol,
129 kkt_tol,
130 seed,
131 sobol,
132 sigma,
133 sigma_frac,
134 amplitude,
135 amp_margin,
136 eta,
137 power,
138 soft,
139 length,
140 length_frac,
141 gamma,
142 samples_per_round,
143 step,
144 temperature,
145 restart_jitter,
146 sigma_per_dim,
147 length_per_dim,
148 max_samples,
149 amp_bump,
150 amp_bump_cap,
151 amp_fallback,
152 } = self;
153 OptionsKey {
154 method: *method,
155 n_minima: *n_minima,
156 max_solves: *max_solves,
157 patience: *patience,
158 dedup: dedup.to_bits(),
159 psd_tol: psd_tol.to_bits(),
160 kkt_tol: bits(kkt_tol),
161 seed: *seed,
162 sobol: *sobol,
163 sigma: bits(sigma),
164 sigma_frac: bits(sigma_frac),
165 amplitude: bits(amplitude),
166 amp_margin: bits(amp_margin),
167 eta: bits(eta),
168 power: bits(power),
169 soft: bits(soft),
170 length: bits(length),
171 length_frac: bits(length_frac),
172 gamma: bits(gamma),
173 samples_per_round: *samples_per_round,
174 step: bits(step),
175 temperature: bits(temperature),
176 restart_jitter: bits(restart_jitter),
177 sigma_per_dim: vec_bits(sigma_per_dim),
178 length_per_dim: vec_bits(length_per_dim),
179 max_samples: *max_samples,
180 amp_bump: bits(amp_bump),
181 amp_bump_cap: bits(amp_bump_cap),
182 amp_fallback: bits(amp_fallback),
183 }
184 }
185
186 pub fn max_solves_or_default(&self) -> usize {
188 self.max_solves.unwrap_or(8 * self.n_minima)
189 }
190}
191
192impl Default for MinimaOptions {
193 fn default() -> Self {
194 Self {
195 method: Method::Deflation,
197 n_minima: 10,
198 max_solves: None,
199 patience: 8,
200 dedup: 1e-4,
201 psd_tol: 1e-6,
202 kkt_tol: Some(1e-4),
203 seed: 0,
204 sobol: true,
205 sigma: None,
206 sigma_frac: None,
207 amplitude: None,
208 amp_margin: None,
209 eta: None,
210 power: None,
211 soft: None,
212 length: None,
213 length_frac: None,
214 gamma: None,
215 samples_per_round: None,
216 step: None,
217 temperature: None,
218 restart_jitter: None,
219 sigma_per_dim: None,
220 length_per_dim: None,
221 max_samples: None,
222 amp_bump: None,
223 amp_bump_cap: None,
224 amp_fallback: None,
225 }
226 }
227}
228
229#[derive(PartialEq, Eq, Hash)]
232struct OptionsKey {
233 method: Method,
234 n_minima: usize,
235 max_solves: Option<usize>,
236 patience: usize,
237 dedup: u64,
238 psd_tol: u64,
239 kkt_tol: Option<u64>,
240 seed: u64,
241 sobol: bool,
242 sigma: Option<u64>,
243 sigma_frac: Option<u64>,
244 amplitude: Option<u64>,
245 amp_margin: Option<u64>,
246 eta: Option<u64>,
247 power: Option<u64>,
248 soft: Option<u64>,
249 length: Option<u64>,
250 length_frac: Option<u64>,
251 gamma: Option<u64>,
252 samples_per_round: Option<usize>,
253 step: Option<u64>,
254 temperature: Option<u64>,
255 restart_jitter: Option<u64>,
256 sigma_per_dim: Option<Vec<u64>>,
257 length_per_dim: Option<Vec<u64>>,
258 max_samples: Option<usize>,
259 amp_bump: Option<u64>,
260 amp_bump_cap: Option<u64>,
261 amp_fallback: Option<u64>,
262}
263
264impl PartialEq for MinimaOptions {
265 fn eq(&self, other: &Self) -> bool {
266 self.key() == other.key()
267 }
268}
269
270impl Eq for MinimaOptions {}
271
272impl std::hash::Hash for MinimaOptions {
273 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
274 self.key().hash(state);
275 }
276}