autoeq-de 0.2.52

Non linear optimisation library with own DE solvers and interface to NLOpt and MetaHeuristics
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
/// Shared function registry for differential evolution benchmarks and plotting
use crate::Strategy;
use autoeq_testfunctions::*;
use ndarray::Array1;
use std::collections::HashMap;

/// Test function type definition
pub type TestFunction = fn(&Array1<f64>) -> f64;

/// CSV trace point: (x_vector, f_value, is_improvement)
pub type TracePoint = (Vec<f64>, f64, bool);

/// Configuration for a benchmark
#[derive(Clone, Debug)]
pub struct BenchmarkConfig {
    pub name: String,
    pub function_name: String,
    pub bounds: Vec<(f64, f64)>,
    pub expected_optimum: Vec<f64>,
    pub fun_tolerance: f64,
    pub position_tolerance: f64,
    pub maxiter: usize,
    pub popsize: usize,
    pub strategy: Strategy,
    pub recombination: f64,
    pub seed: u64,
}

/// Function registry mapping names to actual function pointers
pub struct FunctionRegistry {
    functions: HashMap<String, TestFunction>,
}

impl FunctionRegistry {
    pub fn new() -> Self {
        let mut functions = HashMap::new();

        // Unimodal functions
        functions.insert("sphere".to_string(), sphere as TestFunction);
        functions.insert("rosenbrock".to_string(), rosenbrock as TestFunction);
        functions.insert("booth".to_string(), booth as TestFunction);
        functions.insert("matyas".to_string(), matyas as TestFunction);
        functions.insert("beale".to_string(), beale as TestFunction);
        functions.insert("himmelblau".to_string(), himmelblau as TestFunction);
        functions.insert("sum_squares".to_string(), sum_squares as TestFunction);
        functions.insert(
            "different_powers".to_string(),
            different_powers as TestFunction,
        );
        functions.insert("elliptic".to_string(), elliptic as TestFunction);
        functions.insert("cigar".to_string(), cigar as TestFunction);
        functions.insert("tablet".to_string(), tablet as TestFunction);
        functions.insert("discus".to_string(), discus as TestFunction);
        functions.insert("ridge".to_string(), ridge as TestFunction);
        functions.insert("sharp_ridge".to_string(), sharp_ridge as TestFunction);
        functions.insert("perm_0_d_beta".to_string(), perm_0_d_beta as TestFunction);
        functions.insert("perm_d_beta".to_string(), perm_d_beta as TestFunction);

        // Multimodal functions
        functions.insert("ackley".to_string(), ackley as TestFunction);
        functions.insert("ackley_n2".to_string(), ackley_n2 as TestFunction);
        functions.insert("ackley_n3".to_string(), ackley_n3 as TestFunction);
        functions.insert("rastrigin".to_string(), rastrigin as TestFunction);
        functions.insert("griewank".to_string(), griewank as TestFunction);
        functions.insert("schwefel".to_string(), schwefel as TestFunction);
        functions.insert("branin".to_string(), branin as TestFunction);
        functions.insert(
            "goldstein_price".to_string(),
            goldstein_price as TestFunction,
        );
        functions.insert("six_hump_camel".to_string(), six_hump_camel as TestFunction);
        functions.insert("hartman_3d".to_string(), hartman_3d as TestFunction);
        functions.insert("hartman_4d".to_string(), hartman_4d as TestFunction);
        functions.insert("hartman_6d".to_string(), hartman_6d as TestFunction);
        functions.insert(
            "xin_she_yang_n1".to_string(),
            xin_she_yang_n1 as TestFunction,
        );
        functions.insert(
            "xin_she_yang_n2".to_string(),
            xin_she_yang_n2 as TestFunction,
        );
        functions.insert(
            "xin_she_yang_n3".to_string(),
            xin_she_yang_n3 as TestFunction,
        );
        functions.insert(
            "xin_she_yang_n4".to_string(),
            xin_she_yang_n4 as TestFunction,
        );
        functions.insert("katsuura".to_string(), katsuura as TestFunction);
        functions.insert("happycat".to_string(), happycat as TestFunction);
        functions.insert("happy_cat".to_string(), happy_cat as TestFunction);

        // Alpine functions
        functions.insert("alpine_n1".to_string(), alpine_n1 as TestFunction);
        functions.insert("alpine_n2".to_string(), alpine_n2 as TestFunction);

        // Additional functions
        functions.insert(
            "gramacy_lee_2012".to_string(),
            gramacy_lee_2012 as TestFunction,
        );
        functions.insert("forrester_2008".to_string(), forrester_2008 as TestFunction);
        functions.insert("power_sum".to_string(), power_sum as TestFunction);
        functions.insert("shekel".to_string(), shekel as TestFunction);
        functions.insert(
            "gramacy_lee_function".to_string(),
            gramacy_lee_function as TestFunction,
        );
        functions.insert(
            "expanded_griewank_rosenbrock".to_string(),
            expanded_griewank_rosenbrock as TestFunction,
        );

        // More classical functions
        functions.insert("bohachevsky1".to_string(), bohachevsky1 as TestFunction);
        functions.insert("bohachevsky2".to_string(), bohachevsky2 as TestFunction);
        functions.insert("bohachevsky3".to_string(), bohachevsky3 as TestFunction);
        functions.insert("bird".to_string(), bird as TestFunction);
        functions.insert("bent_cigar".to_string(), bent_cigar as TestFunction);
        functions.insert("bent_cigar_alt".to_string(), bent_cigar_alt as TestFunction);
        functions.insert("brown".to_string(), brown as TestFunction);
        functions.insert("bukin_n6".to_string(), bukin_n6 as TestFunction);
        functions.insert("chung_reynolds".to_string(), chung_reynolds as TestFunction);
        functions.insert("colville".to_string(), colville as TestFunction);
        functions.insert("cosine_mixture".to_string(), cosine_mixture as TestFunction);
        functions.insert("cross_in_tray".to_string(), cross_in_tray as TestFunction);
        functions.insert("de_jong_step2".to_string(), de_jong_step2 as TestFunction);
        functions.insert(
            "dejong_f5_foxholes".to_string(),
            dejong_f5_foxholes as TestFunction,
        );
        functions.insert("dixons_price".to_string(), dixons_price as TestFunction);
        functions.insert("drop_wave".to_string(), drop_wave as TestFunction);
        functions.insert("easom".to_string(), easom as TestFunction);
        functions.insert("eggholder".to_string(), eggholder as TestFunction);
        functions.insert(
            "epistatic_michalewicz".to_string(),
            epistatic_michalewicz as TestFunction,
        );
        functions.insert("exponential".to_string(), exponential as TestFunction);
        functions.insert(
            "freudenstein_roth".to_string(),
            freudenstein_roth as TestFunction,
        );
        functions.insert("griewank2".to_string(), griewank2 as TestFunction);
        functions.insert("holder_table".to_string(), holder_table as TestFunction);
        functions.insert(
            "lampinen_simplified".to_string(),
            lampinen_simplified as TestFunction,
        );
        functions.insert("langermann".to_string(), langermann as TestFunction);
        functions.insert("levi13".to_string(), levi13 as TestFunction);
        functions.insert("levy".to_string(), levy as TestFunction);
        functions.insert("levy_n13".to_string(), levy_n13 as TestFunction);
        functions.insert("mccormick".to_string(), mccormick as TestFunction);
        functions.insert("michalewicz".to_string(), michalewicz as TestFunction);
        functions.insert("periodic".to_string(), periodic as TestFunction);
        functions.insert("pinter".to_string(), pinter as TestFunction);
        functions.insert("powell".to_string(), powell as TestFunction);
        functions.insert("qing".to_string(), qing as TestFunction);
        functions.insert("quadratic".to_string(), quadratic as TestFunction);
        functions.insert("quartic".to_string(), quartic as TestFunction);
        functions.insert(
            "rotated_hyper_ellipsoid".to_string(),
            rotated_hyper_ellipsoid as TestFunction,
        );
        functions.insert("salomon".to_string(), salomon as TestFunction);
        functions.insert(
            "salomon_corrected".to_string(),
            salomon_corrected as TestFunction,
        );
        functions.insert("schaffer_n2".to_string(), schaffer_n2 as TestFunction);
        functions.insert("schaffer_n4".to_string(), schaffer_n4 as TestFunction);
        functions.insert("schwefel2".to_string(), schwefel2 as TestFunction);
        functions.insert("shubert".to_string(), shubert as TestFunction);
        functions.insert("step".to_string(), step as TestFunction);
        functions.insert(
            "styblinski_tang2".to_string(),
            styblinski_tang2 as TestFunction,
        );
        functions.insert(
            "sum_of_different_powers".to_string(),
            sum_of_different_powers as TestFunction,
        );
        functions.insert(
            "three_hump_camel".to_string(),
            three_hump_camel as TestFunction,
        );
        functions.insert("trid".to_string(), trid as TestFunction);
        functions.insert("vincent".to_string(), vincent as TestFunction);
        functions.insert("whitley".to_string(), whitley as TestFunction);
        functions.insert("zakharov".to_string(), zakharov as TestFunction);
        functions.insert("zakharov2".to_string(), zakharov2 as TestFunction);

        // Constraint functions (for completeness)
        functions.insert(
            "binh_korn_constraint1".to_string(),
            binh_korn_constraint1 as TestFunction,
        );
        functions.insert(
            "binh_korn_constraint2".to_string(),
            binh_korn_constraint2 as TestFunction,
        );
        functions.insert(
            "binh_korn_weighted".to_string(),
            binh_korn_weighted as TestFunction,
        );
        functions.insert(
            "keanes_bump_constraint1".to_string(),
            keanes_bump_constraint1 as TestFunction,
        );
        functions.insert(
            "keanes_bump_constraint2".to_string(),
            keanes_bump_constraint2 as TestFunction,
        );
        functions.insert(
            "keanes_bump_objective".to_string(),
            keanes_bump_objective as TestFunction,
        );
        functions.insert(
            "mishras_bird_constraint".to_string(),
            mishras_bird_constraint as TestFunction,
        );
        functions.insert(
            "mishras_bird_objective".to_string(),
            mishras_bird_objective as TestFunction,
        );
        functions.insert(
            "rosenbrock_disk_constraint".to_string(),
            rosenbrock_disk_constraint as TestFunction,
        );
        functions.insert(
            "rosenbrock_objective".to_string(),
            rosenbrock_objective as TestFunction,
        );

        Self { functions }
    }

    pub fn get(&self, name: &str) -> Option<TestFunction> {
        self.functions.get(name).copied()
    }

    pub fn list_functions(&self) -> Vec<String> {
        let mut names: Vec<_> = self.functions.keys().cloned().collect();
        names.sort();
        names
    }

    pub fn iter(&self) -> impl Iterator<Item = (&String, &TestFunction)> {
        self.functions.iter()
    }
}

impl Default for FunctionRegistry {
    fn default() -> Self {
        Self::new()
    }
}

/// Generate all benchmark configurations
#[allow(clippy::vec_init_then_push)]
pub fn generate_benchmark_configs() -> Vec<BenchmarkConfig> {
    let mut configs = Vec::new();

    // ACKLEY function benchmarks
    configs.push(BenchmarkConfig {
        name: "ackley_2d".to_string(),
        function_name: "ackley".to_string(),
        bounds: vec![(-32.768, 32.768), (-32.768, 32.768)],
        expected_optimum: vec![0.0, 0.0],
        fun_tolerance: 1e-3,
        position_tolerance: 0.5,
        maxiter: 800,
        popsize: 40,
        strategy: Strategy::Best1Exp,
        recombination: 0.9,
        seed: 42,
    });

    configs.push(BenchmarkConfig {
        name: "ackley_10d".to_string(),
        function_name: "ackley".to_string(),
        bounds: vec![(-32.768, 32.768); 10],
        expected_optimum: vec![0.0; 10],
        fun_tolerance: 1e-2,
        position_tolerance: 0.5,
        maxiter: 1200,
        popsize: 100,
        strategy: Strategy::Rand1Exp,
        recombination: 0.95,
        seed: 43,
    });

    // BEALE function
    configs.push(BenchmarkConfig {
        name: "beale_2d".to_string(),
        function_name: "beale".to_string(),
        bounds: vec![(-4.5, 4.5); 2],
        expected_optimum: vec![3.0, 0.5],
        fun_tolerance: 1e-6,
        position_tolerance: 1e-3,
        maxiter: 800,
        popsize: 40,
        strategy: Strategy::Best1Exp,
        recombination: 0.9,
        seed: 108,
    });

    // ROSENBROCK function benchmarks
    configs.push(BenchmarkConfig {
        name: "rosenbrock_2d".to_string(),
        function_name: "rosenbrock".to_string(),
        bounds: vec![(-2.048, 2.048), (-2.048, 2.048)],
        expected_optimum: vec![1.0, 1.0],
        fun_tolerance: 1e-4,
        position_tolerance: 1e-2,
        maxiter: 800,
        popsize: 40,
        strategy: Strategy::Best1Exp,
        recombination: 0.9,
        seed: 48,
    });

    // Add more configurations as needed...
    // (For brevity, I'm not including all configs here, but they should all be moved from benchmark_convergence.rs)

    configs
}

/// Find CSV files for a given function in the records directory
/// Handles both old single-file format and new block-based format
pub fn find_csv_files_for_function(csv_dir: &str, function_name: &str) -> Vec<String> {
    use std::fs;
    use std::path::Path;

    let mut csv_files = Vec::new();

    // Try old format first
    let old_path = format!("{}/{}.csv", csv_dir, function_name);
    if Path::new(&old_path).exists() {
        csv_files.push(old_path);
        return csv_files;
    }

    // Look for block-based format files
    if let Ok(entries) = fs::read_dir(csv_dir) {
        for entry in entries.flatten() {
            if let Some(filename) = entry.file_name().to_str() {
                // Match files like function_name_block_NNNN.csv
                if filename.starts_with(function_name)
                    && filename.contains("_block_")
                    && filename.ends_with(".csv")
                {
                    csv_files.push(entry.path().to_string_lossy().to_string());
                }
            }
        }
    }

    // Sort files to ensure they're read in order
    csv_files.sort();
    csv_files
}

/// Read and combine multiple CSV files for a function
pub fn read_combined_csv_traces(
    csv_files: &[String],
) -> Result<Vec<TracePoint>, Box<dyn std::error::Error>> {
    use std::fs;

    let mut all_points = Vec::new();

    for csv_path in csv_files {
        let content = fs::read_to_string(csv_path)?;
        let lines: Vec<&str> = content.trim().split('\n').collect();

        if lines.len() < 2 {
            continue; // Skip empty files
        }

        let header = lines[0];

        // Check if it's the new format
        if !header.starts_with("eval_id,generation,") {
            return Err(format!("Unsupported CSV format in {}", csv_path).into());
        }

        for line in lines.iter().skip(1) {
            let parts: Vec<&str> = line.split(',').collect();

            if parts.len() < 7 {
                continue; // Skip malformed lines
            }

            // Parse x coordinates (between generation and f_value/best_so_far/is_improvement)
            let x_end = parts.len() - 3;
            let mut x = Vec::new();
            for part in parts.iter().take(x_end).skip(2) {
                if let Ok(coord) = part.parse::<f64>() {
                    x.push(coord);
                }
            }

            if let (Ok(f_value), Ok(is_improvement)) = (
                parts[x_end].parse::<f64>(),
                parts[x_end + 2].parse::<bool>(),
            ) {
                all_points.push((x, f_value, is_improvement));
            }
        }
    }

    Ok(all_points)
}