pub struct DEConfigBuilder { /* private fields */ }Expand description
Fluent builder for DEConfig for ergonomic configuration.
§Example
use math_audio_optimisation::{DEConfigBuilder, Strategy, Mutation};
let config = DEConfigBuilder::new()
.maxiter(500)
.popsize(20)
.strategy(Strategy::Best1Bin)
.mutation(Mutation::Factor(0.8))
.recombination(0.9)
.seed(42)
.build();Implementations§
Source§impl DEConfigBuilder
impl DEConfigBuilder
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new builder with default configuration.
Examples found in repository?
7fn main() {
8 // Objective: sphere in 2D
9 let sphere = |x: &Array1<f64>| x.iter().map(|v| v * v).sum::<f64>();
10
11 // Bounds
12 let bounds = [(-5.0, 5.0), (-5.0, 5.0)];
13
14 // Linear constraint example: lb <= A x <= ub
15 // 1) x0 + x1 <= 1.0
16 // 2) 0.2 <= x0 - x1 <= 0.4
17 let a = Array2::from_shape_vec((2, 2), vec![1.0, 1.0, 1.0, -1.0]).unwrap();
18 let lb = Array1::from(vec![-f64::INFINITY, 0.2]);
19 let ub = Array1::from(vec![1.0, 0.4]);
20 let lc = LinearConstraintHelper { a, lb, ub };
21
22 // Strategy parsing from string (mirrors SciPy names)
23 let strategy = Strategy::from_str("randtobest1exp").unwrap_or(Strategy::RandToBest1Exp);
24
25 // Build config using the fluent builder
26 let mut cfg = DEConfigBuilder::new()
27 .seed(123)
28 .maxiter(600)
29 .popsize(30)
30 .strategy(strategy)
31 .recombination(0.9)
32 .mutation(Mutation::Range { min: 0.4, max: 1.0 })
33 .crossover(Crossover::Exponential)
34 .build()
35 .expect("popsize must be >= 4");
36
37 // Apply linear constraints with a penalty weight
38 lc.apply_to(&mut cfg, 1e3);
39
40 let rep = differential_evolution(&sphere, &bounds, cfg).expect("optimization failed");
41 println!(
42 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
43 rep.success, rep.message, rep.fun, rep.x
44 );
45}More examples
8fn main() {
9 // Himmelblau as objective, but with nonlinear constraints to demonstrate helper
10 let himmelblau =
11 |x: &Array1<f64>| (x[0] * x[0] + x[1] - 11.0).powi(2) + (x[0] + x[1] * x[1] - 7.0).powi(2);
12
13 // Bounds
14 let bounds = [(-6.0, 6.0), (-6.0, 6.0)];
15
16 // Nonlinear vector function f(x) with 2 components
17 // 1) Circle-ish constraint: x0^2 + x1^2 <= 10 -> f0(x) = x0^2 + x1^2, lb=-inf, ub=10
18 // 2) Sum equality: x0 + x1 = 1 -> f1(x) = x0 + x1, lb=1, ub=1
19 let fun =
20 Arc::new(|x: &Array1<f64>| Array1::from(vec![x[0] * x[0] + x[1] * x[1], x[0] + x[1]]));
21 let lb = Array1::from(vec![-f64::INFINITY, 1.0]);
22 let ub = Array1::from(vec![10.0, 1.0]);
23 let nlc = NonlinearConstraintHelper { fun, lb, ub };
24
25 // Strategy parsing from string
26 let strategy = Strategy::from_str("best1exp").unwrap_or(Strategy::Best1Exp);
27
28 let mut cfg = DEConfigBuilder::new()
29 .seed(456)
30 .maxiter(800)
31 .popsize(30)
32 .strategy(strategy)
33 .recombination(0.9)
34 .crossover(Crossover::Exponential)
35 .build()
36 .expect("popsize must be >= 4");
37
38 // Apply nonlinear constraints with penalties
39 nlc.apply_to(&mut cfg, 1e3, 1e3);
40
41 let rep = differential_evolution(&himmelblau, &bounds, cfg).expect("optimization failed");
42 println!(
43 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
44 rep.success, rep.message, rep.fun, rep.x
45 );
46}13fn main() {
14 println!("🧬 Adaptive Differential Evolution Demo");
15 println!("=====================================");
16 println!();
17
18 // Test functions to evaluate
19 let test_functions = [
20 (
21 "Quadratic (f(x) = x₁² + x₂²)",
22 quadratic as fn(&Array1<f64>) -> f64,
23 [(-5.0, 5.0), (-5.0, 5.0)],
24 ),
25 (
26 "Rosenbrock 2D",
27 rosenbrock as fn(&Array1<f64>) -> f64,
28 [(-5.0, 5.0), (-5.0, 5.0)],
29 ),
30 ("Ackley", ackley, [(-32.0, 32.0), (-32.0, 32.0)]),
31 ];
32
33 for (name, func, bounds) in test_functions.iter() {
34 println!("🎯 Function: {}", name);
35 println!(
36 " Bounds: [{:.1}, {:.1}] × [{:.1}, {:.1}]",
37 bounds[0].0, bounds[0].1, bounds[1].0, bounds[1].1
38 );
39
40 // Traditional DE
41 println!(" 📊 Traditional DE:");
42 let traditional_result = run_traditional_de(*func, bounds);
43
44 // Adaptive DE with SAM only
45 println!(" 🧬 Adaptive DE (SAM only):");
46 let sam_result = run_adaptive_de(*func, bounds, false);
47
48 // Adaptive DE with SAM + WLS
49 println!(" 🔧 Adaptive DE (SAM + WLS):");
50 let sam_wls_result = run_adaptive_de(*func, bounds, true);
51
52 // Compare results
53 println!(" 🏆 Comparison:");
54 println!(
55 " Traditional: f = {:.6e}, {} iterations",
56 traditional_result.fun, traditional_result.nit
57 );
58 println!(
59 " SAM only: f = {:.6e}, {} iterations",
60 sam_result.fun, sam_result.nit
61 );
62 println!(
63 " SAM + WLS: f = {:.6e}, {} iterations",
64 sam_wls_result.fun, sam_wls_result.nit
65 );
66
67 let improvement_sam =
68 ((traditional_result.fun - sam_result.fun) / traditional_result.fun * 100.0).max(0.0);
69 let improvement_wls =
70 ((traditional_result.fun - sam_wls_result.fun) / traditional_result.fun * 100.0)
71 .max(0.0);
72
73 println!(" 📈 Improvement with SAM: {:.1}%", improvement_sam);
74 println!(" 📈 Improvement with WLS: {:.1}%", improvement_wls);
75 println!();
76 }
77
78 // Demonstrate parameter adaptation tracking
79 println!("🔄 Parameter Adaptation Demo");
80 println!("===========================");
81
82 // Use a recording callback to track parameter evolution
83 let bounds = [(-5.0, 5.0), (-5.0, 5.0)];
84
85 let adaptive_config = AdaptiveConfig {
86 adaptive_mutation: true,
87 wls_enabled: true,
88 w_max: 0.9, // Start with 90% of population for selection
89 w_min: 0.1, // End with 10% of population
90 w_f: 0.9, // F parameter adaptation rate
91 w_cr: 0.9, // CR parameter adaptation rate
92 f_m: 0.5, // Initial F location parameter
93 cr_m: 0.6, // Initial CR location parameter
94 wls_prob: 0.2, // Apply WLS to 20% of population
95 wls_scale: 0.1, // WLS perturbation scale
96 };
97
98 let config = DEConfigBuilder::new()
99 .seed(42)
100 .maxiter(50)
101 .popsize(40)
102 .strategy(Strategy::AdaptiveBin)
103 .mutation(Mutation::Adaptive { initial_f: 0.8 })
104 .adaptive(adaptive_config)
105 .disp(true) // Enable progress display
106 .build()
107 .expect("popsize must be >= 4");
108
109 println!("Running adaptive DE on Rosenbrock function with progress display...");
110 let result = differential_evolution(&rosenbrock, &bounds, config).expect("optimization failed");
111
112 println!(
113 "Final result: f = {:.6e} at x = [{:.4}, {:.4}]",
114 result.fun, result.x[0], result.x[1]
115 );
116 println!(
117 "Converged in {} iterations with {} function evaluations",
118 result.nit, result.nfev
119 );
120
121 if result.success {
122 println!("✅ Optimization succeeded: {}", result.message);
123 } else {
124 println!("⚠️ Optimization status: {}", result.message);
125 }
126}
127
128fn run_traditional_de(
129 func: fn(&Array1<f64>) -> f64,
130 bounds: &[(f64, f64)],
131) -> math_audio_optimisation::DEReport {
132 let config = DEConfigBuilder::new()
133 .seed(42)
134 .maxiter(100)
135 .popsize(30)
136 .strategy(Strategy::Best1Bin)
137 .mutation(Mutation::Factor(0.8))
138 .recombination(0.7)
139 .build()
140 .expect("popsize must be >= 4");
141
142 differential_evolution(&func, bounds, config).expect("optimization failed")
143}
144
145fn run_adaptive_de(
146 func: fn(&Array1<f64>) -> f64,
147 bounds: &[(f64, f64)],
148 enable_wls: bool,
149) -> math_audio_optimisation::DEReport {
150 let adaptive_config = AdaptiveConfig {
151 adaptive_mutation: true,
152 wls_enabled: enable_wls,
153 w_max: 0.9,
154 w_min: 0.1,
155 wls_prob: 0.15,
156 wls_scale: 0.1,
157 ..AdaptiveConfig::default()
158 };
159
160 let config = DEConfigBuilder::new()
161 .seed(42)
162 .maxiter(100)
163 .popsize(30)
164 .strategy(Strategy::AdaptiveBin)
165 .mutation(Mutation::Adaptive { initial_f: 0.8 })
166 .adaptive(adaptive_config)
167 .build()
168 .expect("popsize must be >= 4");
169
170 differential_evolution(&func, bounds, config).expect("optimization failed")
171}Sourcepub fn maxiter(self, v: usize) -> Self
pub fn maxiter(self, v: usize) -> Self
Sets the maximum number of iterations.
Examples found in repository?
7fn main() {
8 // Objective: sphere in 2D
9 let sphere = |x: &Array1<f64>| x.iter().map(|v| v * v).sum::<f64>();
10
11 // Bounds
12 let bounds = [(-5.0, 5.0), (-5.0, 5.0)];
13
14 // Linear constraint example: lb <= A x <= ub
15 // 1) x0 + x1 <= 1.0
16 // 2) 0.2 <= x0 - x1 <= 0.4
17 let a = Array2::from_shape_vec((2, 2), vec![1.0, 1.0, 1.0, -1.0]).unwrap();
18 let lb = Array1::from(vec![-f64::INFINITY, 0.2]);
19 let ub = Array1::from(vec![1.0, 0.4]);
20 let lc = LinearConstraintHelper { a, lb, ub };
21
22 // Strategy parsing from string (mirrors SciPy names)
23 let strategy = Strategy::from_str("randtobest1exp").unwrap_or(Strategy::RandToBest1Exp);
24
25 // Build config using the fluent builder
26 let mut cfg = DEConfigBuilder::new()
27 .seed(123)
28 .maxiter(600)
29 .popsize(30)
30 .strategy(strategy)
31 .recombination(0.9)
32 .mutation(Mutation::Range { min: 0.4, max: 1.0 })
33 .crossover(Crossover::Exponential)
34 .build()
35 .expect("popsize must be >= 4");
36
37 // Apply linear constraints with a penalty weight
38 lc.apply_to(&mut cfg, 1e3);
39
40 let rep = differential_evolution(&sphere, &bounds, cfg).expect("optimization failed");
41 println!(
42 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
43 rep.success, rep.message, rep.fun, rep.x
44 );
45}More examples
8fn main() {
9 // Himmelblau as objective, but with nonlinear constraints to demonstrate helper
10 let himmelblau =
11 |x: &Array1<f64>| (x[0] * x[0] + x[1] - 11.0).powi(2) + (x[0] + x[1] * x[1] - 7.0).powi(2);
12
13 // Bounds
14 let bounds = [(-6.0, 6.0), (-6.0, 6.0)];
15
16 // Nonlinear vector function f(x) with 2 components
17 // 1) Circle-ish constraint: x0^2 + x1^2 <= 10 -> f0(x) = x0^2 + x1^2, lb=-inf, ub=10
18 // 2) Sum equality: x0 + x1 = 1 -> f1(x) = x0 + x1, lb=1, ub=1
19 let fun =
20 Arc::new(|x: &Array1<f64>| Array1::from(vec![x[0] * x[0] + x[1] * x[1], x[0] + x[1]]));
21 let lb = Array1::from(vec![-f64::INFINITY, 1.0]);
22 let ub = Array1::from(vec![10.0, 1.0]);
23 let nlc = NonlinearConstraintHelper { fun, lb, ub };
24
25 // Strategy parsing from string
26 let strategy = Strategy::from_str("best1exp").unwrap_or(Strategy::Best1Exp);
27
28 let mut cfg = DEConfigBuilder::new()
29 .seed(456)
30 .maxiter(800)
31 .popsize(30)
32 .strategy(strategy)
33 .recombination(0.9)
34 .crossover(Crossover::Exponential)
35 .build()
36 .expect("popsize must be >= 4");
37
38 // Apply nonlinear constraints with penalties
39 nlc.apply_to(&mut cfg, 1e3, 1e3);
40
41 let rep = differential_evolution(&himmelblau, &bounds, cfg).expect("optimization failed");
42 println!(
43 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
44 rep.success, rep.message, rep.fun, rep.x
45 );
46}13fn main() {
14 println!("🧬 Adaptive Differential Evolution Demo");
15 println!("=====================================");
16 println!();
17
18 // Test functions to evaluate
19 let test_functions = [
20 (
21 "Quadratic (f(x) = x₁² + x₂²)",
22 quadratic as fn(&Array1<f64>) -> f64,
23 [(-5.0, 5.0), (-5.0, 5.0)],
24 ),
25 (
26 "Rosenbrock 2D",
27 rosenbrock as fn(&Array1<f64>) -> f64,
28 [(-5.0, 5.0), (-5.0, 5.0)],
29 ),
30 ("Ackley", ackley, [(-32.0, 32.0), (-32.0, 32.0)]),
31 ];
32
33 for (name, func, bounds) in test_functions.iter() {
34 println!("🎯 Function: {}", name);
35 println!(
36 " Bounds: [{:.1}, {:.1}] × [{:.1}, {:.1}]",
37 bounds[0].0, bounds[0].1, bounds[1].0, bounds[1].1
38 );
39
40 // Traditional DE
41 println!(" 📊 Traditional DE:");
42 let traditional_result = run_traditional_de(*func, bounds);
43
44 // Adaptive DE with SAM only
45 println!(" 🧬 Adaptive DE (SAM only):");
46 let sam_result = run_adaptive_de(*func, bounds, false);
47
48 // Adaptive DE with SAM + WLS
49 println!(" 🔧 Adaptive DE (SAM + WLS):");
50 let sam_wls_result = run_adaptive_de(*func, bounds, true);
51
52 // Compare results
53 println!(" 🏆 Comparison:");
54 println!(
55 " Traditional: f = {:.6e}, {} iterations",
56 traditional_result.fun, traditional_result.nit
57 );
58 println!(
59 " SAM only: f = {:.6e}, {} iterations",
60 sam_result.fun, sam_result.nit
61 );
62 println!(
63 " SAM + WLS: f = {:.6e}, {} iterations",
64 sam_wls_result.fun, sam_wls_result.nit
65 );
66
67 let improvement_sam =
68 ((traditional_result.fun - sam_result.fun) / traditional_result.fun * 100.0).max(0.0);
69 let improvement_wls =
70 ((traditional_result.fun - sam_wls_result.fun) / traditional_result.fun * 100.0)
71 .max(0.0);
72
73 println!(" 📈 Improvement with SAM: {:.1}%", improvement_sam);
74 println!(" 📈 Improvement with WLS: {:.1}%", improvement_wls);
75 println!();
76 }
77
78 // Demonstrate parameter adaptation tracking
79 println!("🔄 Parameter Adaptation Demo");
80 println!("===========================");
81
82 // Use a recording callback to track parameter evolution
83 let bounds = [(-5.0, 5.0), (-5.0, 5.0)];
84
85 let adaptive_config = AdaptiveConfig {
86 adaptive_mutation: true,
87 wls_enabled: true,
88 w_max: 0.9, // Start with 90% of population for selection
89 w_min: 0.1, // End with 10% of population
90 w_f: 0.9, // F parameter adaptation rate
91 w_cr: 0.9, // CR parameter adaptation rate
92 f_m: 0.5, // Initial F location parameter
93 cr_m: 0.6, // Initial CR location parameter
94 wls_prob: 0.2, // Apply WLS to 20% of population
95 wls_scale: 0.1, // WLS perturbation scale
96 };
97
98 let config = DEConfigBuilder::new()
99 .seed(42)
100 .maxiter(50)
101 .popsize(40)
102 .strategy(Strategy::AdaptiveBin)
103 .mutation(Mutation::Adaptive { initial_f: 0.8 })
104 .adaptive(adaptive_config)
105 .disp(true) // Enable progress display
106 .build()
107 .expect("popsize must be >= 4");
108
109 println!("Running adaptive DE on Rosenbrock function with progress display...");
110 let result = differential_evolution(&rosenbrock, &bounds, config).expect("optimization failed");
111
112 println!(
113 "Final result: f = {:.6e} at x = [{:.4}, {:.4}]",
114 result.fun, result.x[0], result.x[1]
115 );
116 println!(
117 "Converged in {} iterations with {} function evaluations",
118 result.nit, result.nfev
119 );
120
121 if result.success {
122 println!("✅ Optimization succeeded: {}", result.message);
123 } else {
124 println!("⚠️ Optimization status: {}", result.message);
125 }
126}
127
128fn run_traditional_de(
129 func: fn(&Array1<f64>) -> f64,
130 bounds: &[(f64, f64)],
131) -> math_audio_optimisation::DEReport {
132 let config = DEConfigBuilder::new()
133 .seed(42)
134 .maxiter(100)
135 .popsize(30)
136 .strategy(Strategy::Best1Bin)
137 .mutation(Mutation::Factor(0.8))
138 .recombination(0.7)
139 .build()
140 .expect("popsize must be >= 4");
141
142 differential_evolution(&func, bounds, config).expect("optimization failed")
143}
144
145fn run_adaptive_de(
146 func: fn(&Array1<f64>) -> f64,
147 bounds: &[(f64, f64)],
148 enable_wls: bool,
149) -> math_audio_optimisation::DEReport {
150 let adaptive_config = AdaptiveConfig {
151 adaptive_mutation: true,
152 wls_enabled: enable_wls,
153 w_max: 0.9,
154 w_min: 0.1,
155 wls_prob: 0.15,
156 wls_scale: 0.1,
157 ..AdaptiveConfig::default()
158 };
159
160 let config = DEConfigBuilder::new()
161 .seed(42)
162 .maxiter(100)
163 .popsize(30)
164 .strategy(Strategy::AdaptiveBin)
165 .mutation(Mutation::Adaptive { initial_f: 0.8 })
166 .adaptive(adaptive_config)
167 .build()
168 .expect("popsize must be >= 4");
169
170 differential_evolution(&func, bounds, config).expect("optimization failed")
171}Sourcepub fn popsize(self, v: usize) -> Self
pub fn popsize(self, v: usize) -> Self
Sets the population size multiplier.
§Panics
Panics if v < 4 since DE requires at least 4 individuals for
rand/1 and rand/2 mutation strategies.
Examples found in repository?
7fn main() {
8 // Objective: sphere in 2D
9 let sphere = |x: &Array1<f64>| x.iter().map(|v| v * v).sum::<f64>();
10
11 // Bounds
12 let bounds = [(-5.0, 5.0), (-5.0, 5.0)];
13
14 // Linear constraint example: lb <= A x <= ub
15 // 1) x0 + x1 <= 1.0
16 // 2) 0.2 <= x0 - x1 <= 0.4
17 let a = Array2::from_shape_vec((2, 2), vec![1.0, 1.0, 1.0, -1.0]).unwrap();
18 let lb = Array1::from(vec![-f64::INFINITY, 0.2]);
19 let ub = Array1::from(vec![1.0, 0.4]);
20 let lc = LinearConstraintHelper { a, lb, ub };
21
22 // Strategy parsing from string (mirrors SciPy names)
23 let strategy = Strategy::from_str("randtobest1exp").unwrap_or(Strategy::RandToBest1Exp);
24
25 // Build config using the fluent builder
26 let mut cfg = DEConfigBuilder::new()
27 .seed(123)
28 .maxiter(600)
29 .popsize(30)
30 .strategy(strategy)
31 .recombination(0.9)
32 .mutation(Mutation::Range { min: 0.4, max: 1.0 })
33 .crossover(Crossover::Exponential)
34 .build()
35 .expect("popsize must be >= 4");
36
37 // Apply linear constraints with a penalty weight
38 lc.apply_to(&mut cfg, 1e3);
39
40 let rep = differential_evolution(&sphere, &bounds, cfg).expect("optimization failed");
41 println!(
42 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
43 rep.success, rep.message, rep.fun, rep.x
44 );
45}More examples
8fn main() {
9 // Himmelblau as objective, but with nonlinear constraints to demonstrate helper
10 let himmelblau =
11 |x: &Array1<f64>| (x[0] * x[0] + x[1] - 11.0).powi(2) + (x[0] + x[1] * x[1] - 7.0).powi(2);
12
13 // Bounds
14 let bounds = [(-6.0, 6.0), (-6.0, 6.0)];
15
16 // Nonlinear vector function f(x) with 2 components
17 // 1) Circle-ish constraint: x0^2 + x1^2 <= 10 -> f0(x) = x0^2 + x1^2, lb=-inf, ub=10
18 // 2) Sum equality: x0 + x1 = 1 -> f1(x) = x0 + x1, lb=1, ub=1
19 let fun =
20 Arc::new(|x: &Array1<f64>| Array1::from(vec![x[0] * x[0] + x[1] * x[1], x[0] + x[1]]));
21 let lb = Array1::from(vec![-f64::INFINITY, 1.0]);
22 let ub = Array1::from(vec![10.0, 1.0]);
23 let nlc = NonlinearConstraintHelper { fun, lb, ub };
24
25 // Strategy parsing from string
26 let strategy = Strategy::from_str("best1exp").unwrap_or(Strategy::Best1Exp);
27
28 let mut cfg = DEConfigBuilder::new()
29 .seed(456)
30 .maxiter(800)
31 .popsize(30)
32 .strategy(strategy)
33 .recombination(0.9)
34 .crossover(Crossover::Exponential)
35 .build()
36 .expect("popsize must be >= 4");
37
38 // Apply nonlinear constraints with penalties
39 nlc.apply_to(&mut cfg, 1e3, 1e3);
40
41 let rep = differential_evolution(&himmelblau, &bounds, cfg).expect("optimization failed");
42 println!(
43 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
44 rep.success, rep.message, rep.fun, rep.x
45 );
46}13fn main() {
14 println!("🧬 Adaptive Differential Evolution Demo");
15 println!("=====================================");
16 println!();
17
18 // Test functions to evaluate
19 let test_functions = [
20 (
21 "Quadratic (f(x) = x₁² + x₂²)",
22 quadratic as fn(&Array1<f64>) -> f64,
23 [(-5.0, 5.0), (-5.0, 5.0)],
24 ),
25 (
26 "Rosenbrock 2D",
27 rosenbrock as fn(&Array1<f64>) -> f64,
28 [(-5.0, 5.0), (-5.0, 5.0)],
29 ),
30 ("Ackley", ackley, [(-32.0, 32.0), (-32.0, 32.0)]),
31 ];
32
33 for (name, func, bounds) in test_functions.iter() {
34 println!("🎯 Function: {}", name);
35 println!(
36 " Bounds: [{:.1}, {:.1}] × [{:.1}, {:.1}]",
37 bounds[0].0, bounds[0].1, bounds[1].0, bounds[1].1
38 );
39
40 // Traditional DE
41 println!(" 📊 Traditional DE:");
42 let traditional_result = run_traditional_de(*func, bounds);
43
44 // Adaptive DE with SAM only
45 println!(" 🧬 Adaptive DE (SAM only):");
46 let sam_result = run_adaptive_de(*func, bounds, false);
47
48 // Adaptive DE with SAM + WLS
49 println!(" 🔧 Adaptive DE (SAM + WLS):");
50 let sam_wls_result = run_adaptive_de(*func, bounds, true);
51
52 // Compare results
53 println!(" 🏆 Comparison:");
54 println!(
55 " Traditional: f = {:.6e}, {} iterations",
56 traditional_result.fun, traditional_result.nit
57 );
58 println!(
59 " SAM only: f = {:.6e}, {} iterations",
60 sam_result.fun, sam_result.nit
61 );
62 println!(
63 " SAM + WLS: f = {:.6e}, {} iterations",
64 sam_wls_result.fun, sam_wls_result.nit
65 );
66
67 let improvement_sam =
68 ((traditional_result.fun - sam_result.fun) / traditional_result.fun * 100.0).max(0.0);
69 let improvement_wls =
70 ((traditional_result.fun - sam_wls_result.fun) / traditional_result.fun * 100.0)
71 .max(0.0);
72
73 println!(" 📈 Improvement with SAM: {:.1}%", improvement_sam);
74 println!(" 📈 Improvement with WLS: {:.1}%", improvement_wls);
75 println!();
76 }
77
78 // Demonstrate parameter adaptation tracking
79 println!("🔄 Parameter Adaptation Demo");
80 println!("===========================");
81
82 // Use a recording callback to track parameter evolution
83 let bounds = [(-5.0, 5.0), (-5.0, 5.0)];
84
85 let adaptive_config = AdaptiveConfig {
86 adaptive_mutation: true,
87 wls_enabled: true,
88 w_max: 0.9, // Start with 90% of population for selection
89 w_min: 0.1, // End with 10% of population
90 w_f: 0.9, // F parameter adaptation rate
91 w_cr: 0.9, // CR parameter adaptation rate
92 f_m: 0.5, // Initial F location parameter
93 cr_m: 0.6, // Initial CR location parameter
94 wls_prob: 0.2, // Apply WLS to 20% of population
95 wls_scale: 0.1, // WLS perturbation scale
96 };
97
98 let config = DEConfigBuilder::new()
99 .seed(42)
100 .maxiter(50)
101 .popsize(40)
102 .strategy(Strategy::AdaptiveBin)
103 .mutation(Mutation::Adaptive { initial_f: 0.8 })
104 .adaptive(adaptive_config)
105 .disp(true) // Enable progress display
106 .build()
107 .expect("popsize must be >= 4");
108
109 println!("Running adaptive DE on Rosenbrock function with progress display...");
110 let result = differential_evolution(&rosenbrock, &bounds, config).expect("optimization failed");
111
112 println!(
113 "Final result: f = {:.6e} at x = [{:.4}, {:.4}]",
114 result.fun, result.x[0], result.x[1]
115 );
116 println!(
117 "Converged in {} iterations with {} function evaluations",
118 result.nit, result.nfev
119 );
120
121 if result.success {
122 println!("✅ Optimization succeeded: {}", result.message);
123 } else {
124 println!("⚠️ Optimization status: {}", result.message);
125 }
126}
127
128fn run_traditional_de(
129 func: fn(&Array1<f64>) -> f64,
130 bounds: &[(f64, f64)],
131) -> math_audio_optimisation::DEReport {
132 let config = DEConfigBuilder::new()
133 .seed(42)
134 .maxiter(100)
135 .popsize(30)
136 .strategy(Strategy::Best1Bin)
137 .mutation(Mutation::Factor(0.8))
138 .recombination(0.7)
139 .build()
140 .expect("popsize must be >= 4");
141
142 differential_evolution(&func, bounds, config).expect("optimization failed")
143}
144
145fn run_adaptive_de(
146 func: fn(&Array1<f64>) -> f64,
147 bounds: &[(f64, f64)],
148 enable_wls: bool,
149) -> math_audio_optimisation::DEReport {
150 let adaptive_config = AdaptiveConfig {
151 adaptive_mutation: true,
152 wls_enabled: enable_wls,
153 w_max: 0.9,
154 w_min: 0.1,
155 wls_prob: 0.15,
156 wls_scale: 0.1,
157 ..AdaptiveConfig::default()
158 };
159
160 let config = DEConfigBuilder::new()
161 .seed(42)
162 .maxiter(100)
163 .popsize(30)
164 .strategy(Strategy::AdaptiveBin)
165 .mutation(Mutation::Adaptive { initial_f: 0.8 })
166 .adaptive(adaptive_config)
167 .build()
168 .expect("popsize must be >= 4");
169
170 differential_evolution(&func, bounds, config).expect("optimization failed")
171}Sourcepub fn mutation(self, v: Mutation) -> Self
pub fn mutation(self, v: Mutation) -> Self
Sets the mutation factor configuration.
Examples found in repository?
7fn main() {
8 // Objective: sphere in 2D
9 let sphere = |x: &Array1<f64>| x.iter().map(|v| v * v).sum::<f64>();
10
11 // Bounds
12 let bounds = [(-5.0, 5.0), (-5.0, 5.0)];
13
14 // Linear constraint example: lb <= A x <= ub
15 // 1) x0 + x1 <= 1.0
16 // 2) 0.2 <= x0 - x1 <= 0.4
17 let a = Array2::from_shape_vec((2, 2), vec![1.0, 1.0, 1.0, -1.0]).unwrap();
18 let lb = Array1::from(vec![-f64::INFINITY, 0.2]);
19 let ub = Array1::from(vec![1.0, 0.4]);
20 let lc = LinearConstraintHelper { a, lb, ub };
21
22 // Strategy parsing from string (mirrors SciPy names)
23 let strategy = Strategy::from_str("randtobest1exp").unwrap_or(Strategy::RandToBest1Exp);
24
25 // Build config using the fluent builder
26 let mut cfg = DEConfigBuilder::new()
27 .seed(123)
28 .maxiter(600)
29 .popsize(30)
30 .strategy(strategy)
31 .recombination(0.9)
32 .mutation(Mutation::Range { min: 0.4, max: 1.0 })
33 .crossover(Crossover::Exponential)
34 .build()
35 .expect("popsize must be >= 4");
36
37 // Apply linear constraints with a penalty weight
38 lc.apply_to(&mut cfg, 1e3);
39
40 let rep = differential_evolution(&sphere, &bounds, cfg).expect("optimization failed");
41 println!(
42 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
43 rep.success, rep.message, rep.fun, rep.x
44 );
45}More examples
13fn main() {
14 println!("🧬 Adaptive Differential Evolution Demo");
15 println!("=====================================");
16 println!();
17
18 // Test functions to evaluate
19 let test_functions = [
20 (
21 "Quadratic (f(x) = x₁² + x₂²)",
22 quadratic as fn(&Array1<f64>) -> f64,
23 [(-5.0, 5.0), (-5.0, 5.0)],
24 ),
25 (
26 "Rosenbrock 2D",
27 rosenbrock as fn(&Array1<f64>) -> f64,
28 [(-5.0, 5.0), (-5.0, 5.0)],
29 ),
30 ("Ackley", ackley, [(-32.0, 32.0), (-32.0, 32.0)]),
31 ];
32
33 for (name, func, bounds) in test_functions.iter() {
34 println!("🎯 Function: {}", name);
35 println!(
36 " Bounds: [{:.1}, {:.1}] × [{:.1}, {:.1}]",
37 bounds[0].0, bounds[0].1, bounds[1].0, bounds[1].1
38 );
39
40 // Traditional DE
41 println!(" 📊 Traditional DE:");
42 let traditional_result = run_traditional_de(*func, bounds);
43
44 // Adaptive DE with SAM only
45 println!(" 🧬 Adaptive DE (SAM only):");
46 let sam_result = run_adaptive_de(*func, bounds, false);
47
48 // Adaptive DE with SAM + WLS
49 println!(" 🔧 Adaptive DE (SAM + WLS):");
50 let sam_wls_result = run_adaptive_de(*func, bounds, true);
51
52 // Compare results
53 println!(" 🏆 Comparison:");
54 println!(
55 " Traditional: f = {:.6e}, {} iterations",
56 traditional_result.fun, traditional_result.nit
57 );
58 println!(
59 " SAM only: f = {:.6e}, {} iterations",
60 sam_result.fun, sam_result.nit
61 );
62 println!(
63 " SAM + WLS: f = {:.6e}, {} iterations",
64 sam_wls_result.fun, sam_wls_result.nit
65 );
66
67 let improvement_sam =
68 ((traditional_result.fun - sam_result.fun) / traditional_result.fun * 100.0).max(0.0);
69 let improvement_wls =
70 ((traditional_result.fun - sam_wls_result.fun) / traditional_result.fun * 100.0)
71 .max(0.0);
72
73 println!(" 📈 Improvement with SAM: {:.1}%", improvement_sam);
74 println!(" 📈 Improvement with WLS: {:.1}%", improvement_wls);
75 println!();
76 }
77
78 // Demonstrate parameter adaptation tracking
79 println!("🔄 Parameter Adaptation Demo");
80 println!("===========================");
81
82 // Use a recording callback to track parameter evolution
83 let bounds = [(-5.0, 5.0), (-5.0, 5.0)];
84
85 let adaptive_config = AdaptiveConfig {
86 adaptive_mutation: true,
87 wls_enabled: true,
88 w_max: 0.9, // Start with 90% of population for selection
89 w_min: 0.1, // End with 10% of population
90 w_f: 0.9, // F parameter adaptation rate
91 w_cr: 0.9, // CR parameter adaptation rate
92 f_m: 0.5, // Initial F location parameter
93 cr_m: 0.6, // Initial CR location parameter
94 wls_prob: 0.2, // Apply WLS to 20% of population
95 wls_scale: 0.1, // WLS perturbation scale
96 };
97
98 let config = DEConfigBuilder::new()
99 .seed(42)
100 .maxiter(50)
101 .popsize(40)
102 .strategy(Strategy::AdaptiveBin)
103 .mutation(Mutation::Adaptive { initial_f: 0.8 })
104 .adaptive(adaptive_config)
105 .disp(true) // Enable progress display
106 .build()
107 .expect("popsize must be >= 4");
108
109 println!("Running adaptive DE on Rosenbrock function with progress display...");
110 let result = differential_evolution(&rosenbrock, &bounds, config).expect("optimization failed");
111
112 println!(
113 "Final result: f = {:.6e} at x = [{:.4}, {:.4}]",
114 result.fun, result.x[0], result.x[1]
115 );
116 println!(
117 "Converged in {} iterations with {} function evaluations",
118 result.nit, result.nfev
119 );
120
121 if result.success {
122 println!("✅ Optimization succeeded: {}", result.message);
123 } else {
124 println!("⚠️ Optimization status: {}", result.message);
125 }
126}
127
128fn run_traditional_de(
129 func: fn(&Array1<f64>) -> f64,
130 bounds: &[(f64, f64)],
131) -> math_audio_optimisation::DEReport {
132 let config = DEConfigBuilder::new()
133 .seed(42)
134 .maxiter(100)
135 .popsize(30)
136 .strategy(Strategy::Best1Bin)
137 .mutation(Mutation::Factor(0.8))
138 .recombination(0.7)
139 .build()
140 .expect("popsize must be >= 4");
141
142 differential_evolution(&func, bounds, config).expect("optimization failed")
143}
144
145fn run_adaptive_de(
146 func: fn(&Array1<f64>) -> f64,
147 bounds: &[(f64, f64)],
148 enable_wls: bool,
149) -> math_audio_optimisation::DEReport {
150 let adaptive_config = AdaptiveConfig {
151 adaptive_mutation: true,
152 wls_enabled: enable_wls,
153 w_max: 0.9,
154 w_min: 0.1,
155 wls_prob: 0.15,
156 wls_scale: 0.1,
157 ..AdaptiveConfig::default()
158 };
159
160 let config = DEConfigBuilder::new()
161 .seed(42)
162 .maxiter(100)
163 .popsize(30)
164 .strategy(Strategy::AdaptiveBin)
165 .mutation(Mutation::Adaptive { initial_f: 0.8 })
166 .adaptive(adaptive_config)
167 .build()
168 .expect("popsize must be >= 4");
169
170 differential_evolution(&func, bounds, config).expect("optimization failed")
171}Sourcepub fn recombination(self, v: f64) -> Self
pub fn recombination(self, v: f64) -> Self
Sets the crossover probability (CR).
Examples found in repository?
128fn run_traditional_de(
129 func: fn(&Array1<f64>) -> f64,
130 bounds: &[(f64, f64)],
131) -> math_audio_optimisation::DEReport {
132 let config = DEConfigBuilder::new()
133 .seed(42)
134 .maxiter(100)
135 .popsize(30)
136 .strategy(Strategy::Best1Bin)
137 .mutation(Mutation::Factor(0.8))
138 .recombination(0.7)
139 .build()
140 .expect("popsize must be >= 4");
141
142 differential_evolution(&func, bounds, config).expect("optimization failed")
143}More examples
7fn main() {
8 // Objective: sphere in 2D
9 let sphere = |x: &Array1<f64>| x.iter().map(|v| v * v).sum::<f64>();
10
11 // Bounds
12 let bounds = [(-5.0, 5.0), (-5.0, 5.0)];
13
14 // Linear constraint example: lb <= A x <= ub
15 // 1) x0 + x1 <= 1.0
16 // 2) 0.2 <= x0 - x1 <= 0.4
17 let a = Array2::from_shape_vec((2, 2), vec![1.0, 1.0, 1.0, -1.0]).unwrap();
18 let lb = Array1::from(vec![-f64::INFINITY, 0.2]);
19 let ub = Array1::from(vec![1.0, 0.4]);
20 let lc = LinearConstraintHelper { a, lb, ub };
21
22 // Strategy parsing from string (mirrors SciPy names)
23 let strategy = Strategy::from_str("randtobest1exp").unwrap_or(Strategy::RandToBest1Exp);
24
25 // Build config using the fluent builder
26 let mut cfg = DEConfigBuilder::new()
27 .seed(123)
28 .maxiter(600)
29 .popsize(30)
30 .strategy(strategy)
31 .recombination(0.9)
32 .mutation(Mutation::Range { min: 0.4, max: 1.0 })
33 .crossover(Crossover::Exponential)
34 .build()
35 .expect("popsize must be >= 4");
36
37 // Apply linear constraints with a penalty weight
38 lc.apply_to(&mut cfg, 1e3);
39
40 let rep = differential_evolution(&sphere, &bounds, cfg).expect("optimization failed");
41 println!(
42 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
43 rep.success, rep.message, rep.fun, rep.x
44 );
45}8fn main() {
9 // Himmelblau as objective, but with nonlinear constraints to demonstrate helper
10 let himmelblau =
11 |x: &Array1<f64>| (x[0] * x[0] + x[1] - 11.0).powi(2) + (x[0] + x[1] * x[1] - 7.0).powi(2);
12
13 // Bounds
14 let bounds = [(-6.0, 6.0), (-6.0, 6.0)];
15
16 // Nonlinear vector function f(x) with 2 components
17 // 1) Circle-ish constraint: x0^2 + x1^2 <= 10 -> f0(x) = x0^2 + x1^2, lb=-inf, ub=10
18 // 2) Sum equality: x0 + x1 = 1 -> f1(x) = x0 + x1, lb=1, ub=1
19 let fun =
20 Arc::new(|x: &Array1<f64>| Array1::from(vec![x[0] * x[0] + x[1] * x[1], x[0] + x[1]]));
21 let lb = Array1::from(vec![-f64::INFINITY, 1.0]);
22 let ub = Array1::from(vec![10.0, 1.0]);
23 let nlc = NonlinearConstraintHelper { fun, lb, ub };
24
25 // Strategy parsing from string
26 let strategy = Strategy::from_str("best1exp").unwrap_or(Strategy::Best1Exp);
27
28 let mut cfg = DEConfigBuilder::new()
29 .seed(456)
30 .maxiter(800)
31 .popsize(30)
32 .strategy(strategy)
33 .recombination(0.9)
34 .crossover(Crossover::Exponential)
35 .build()
36 .expect("popsize must be >= 4");
37
38 // Apply nonlinear constraints with penalties
39 nlc.apply_to(&mut cfg, 1e3, 1e3);
40
41 let rep = differential_evolution(&himmelblau, &bounds, cfg).expect("optimization failed");
42 println!(
43 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
44 rep.success, rep.message, rep.fun, rep.x
45 );
46}Sourcepub fn strategy(self, v: Strategy) -> Self
pub fn strategy(self, v: Strategy) -> Self
Sets the mutation/crossover strategy.
Examples found in repository?
7fn main() {
8 // Objective: sphere in 2D
9 let sphere = |x: &Array1<f64>| x.iter().map(|v| v * v).sum::<f64>();
10
11 // Bounds
12 let bounds = [(-5.0, 5.0), (-5.0, 5.0)];
13
14 // Linear constraint example: lb <= A x <= ub
15 // 1) x0 + x1 <= 1.0
16 // 2) 0.2 <= x0 - x1 <= 0.4
17 let a = Array2::from_shape_vec((2, 2), vec![1.0, 1.0, 1.0, -1.0]).unwrap();
18 let lb = Array1::from(vec![-f64::INFINITY, 0.2]);
19 let ub = Array1::from(vec![1.0, 0.4]);
20 let lc = LinearConstraintHelper { a, lb, ub };
21
22 // Strategy parsing from string (mirrors SciPy names)
23 let strategy = Strategy::from_str("randtobest1exp").unwrap_or(Strategy::RandToBest1Exp);
24
25 // Build config using the fluent builder
26 let mut cfg = DEConfigBuilder::new()
27 .seed(123)
28 .maxiter(600)
29 .popsize(30)
30 .strategy(strategy)
31 .recombination(0.9)
32 .mutation(Mutation::Range { min: 0.4, max: 1.0 })
33 .crossover(Crossover::Exponential)
34 .build()
35 .expect("popsize must be >= 4");
36
37 // Apply linear constraints with a penalty weight
38 lc.apply_to(&mut cfg, 1e3);
39
40 let rep = differential_evolution(&sphere, &bounds, cfg).expect("optimization failed");
41 println!(
42 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
43 rep.success, rep.message, rep.fun, rep.x
44 );
45}More examples
8fn main() {
9 // Himmelblau as objective, but with nonlinear constraints to demonstrate helper
10 let himmelblau =
11 |x: &Array1<f64>| (x[0] * x[0] + x[1] - 11.0).powi(2) + (x[0] + x[1] * x[1] - 7.0).powi(2);
12
13 // Bounds
14 let bounds = [(-6.0, 6.0), (-6.0, 6.0)];
15
16 // Nonlinear vector function f(x) with 2 components
17 // 1) Circle-ish constraint: x0^2 + x1^2 <= 10 -> f0(x) = x0^2 + x1^2, lb=-inf, ub=10
18 // 2) Sum equality: x0 + x1 = 1 -> f1(x) = x0 + x1, lb=1, ub=1
19 let fun =
20 Arc::new(|x: &Array1<f64>| Array1::from(vec![x[0] * x[0] + x[1] * x[1], x[0] + x[1]]));
21 let lb = Array1::from(vec![-f64::INFINITY, 1.0]);
22 let ub = Array1::from(vec![10.0, 1.0]);
23 let nlc = NonlinearConstraintHelper { fun, lb, ub };
24
25 // Strategy parsing from string
26 let strategy = Strategy::from_str("best1exp").unwrap_or(Strategy::Best1Exp);
27
28 let mut cfg = DEConfigBuilder::new()
29 .seed(456)
30 .maxiter(800)
31 .popsize(30)
32 .strategy(strategy)
33 .recombination(0.9)
34 .crossover(Crossover::Exponential)
35 .build()
36 .expect("popsize must be >= 4");
37
38 // Apply nonlinear constraints with penalties
39 nlc.apply_to(&mut cfg, 1e3, 1e3);
40
41 let rep = differential_evolution(&himmelblau, &bounds, cfg).expect("optimization failed");
42 println!(
43 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
44 rep.success, rep.message, rep.fun, rep.x
45 );
46}13fn main() {
14 println!("🧬 Adaptive Differential Evolution Demo");
15 println!("=====================================");
16 println!();
17
18 // Test functions to evaluate
19 let test_functions = [
20 (
21 "Quadratic (f(x) = x₁² + x₂²)",
22 quadratic as fn(&Array1<f64>) -> f64,
23 [(-5.0, 5.0), (-5.0, 5.0)],
24 ),
25 (
26 "Rosenbrock 2D",
27 rosenbrock as fn(&Array1<f64>) -> f64,
28 [(-5.0, 5.0), (-5.0, 5.0)],
29 ),
30 ("Ackley", ackley, [(-32.0, 32.0), (-32.0, 32.0)]),
31 ];
32
33 for (name, func, bounds) in test_functions.iter() {
34 println!("🎯 Function: {}", name);
35 println!(
36 " Bounds: [{:.1}, {:.1}] × [{:.1}, {:.1}]",
37 bounds[0].0, bounds[0].1, bounds[1].0, bounds[1].1
38 );
39
40 // Traditional DE
41 println!(" 📊 Traditional DE:");
42 let traditional_result = run_traditional_de(*func, bounds);
43
44 // Adaptive DE with SAM only
45 println!(" 🧬 Adaptive DE (SAM only):");
46 let sam_result = run_adaptive_de(*func, bounds, false);
47
48 // Adaptive DE with SAM + WLS
49 println!(" 🔧 Adaptive DE (SAM + WLS):");
50 let sam_wls_result = run_adaptive_de(*func, bounds, true);
51
52 // Compare results
53 println!(" 🏆 Comparison:");
54 println!(
55 " Traditional: f = {:.6e}, {} iterations",
56 traditional_result.fun, traditional_result.nit
57 );
58 println!(
59 " SAM only: f = {:.6e}, {} iterations",
60 sam_result.fun, sam_result.nit
61 );
62 println!(
63 " SAM + WLS: f = {:.6e}, {} iterations",
64 sam_wls_result.fun, sam_wls_result.nit
65 );
66
67 let improvement_sam =
68 ((traditional_result.fun - sam_result.fun) / traditional_result.fun * 100.0).max(0.0);
69 let improvement_wls =
70 ((traditional_result.fun - sam_wls_result.fun) / traditional_result.fun * 100.0)
71 .max(0.0);
72
73 println!(" 📈 Improvement with SAM: {:.1}%", improvement_sam);
74 println!(" 📈 Improvement with WLS: {:.1}%", improvement_wls);
75 println!();
76 }
77
78 // Demonstrate parameter adaptation tracking
79 println!("🔄 Parameter Adaptation Demo");
80 println!("===========================");
81
82 // Use a recording callback to track parameter evolution
83 let bounds = [(-5.0, 5.0), (-5.0, 5.0)];
84
85 let adaptive_config = AdaptiveConfig {
86 adaptive_mutation: true,
87 wls_enabled: true,
88 w_max: 0.9, // Start with 90% of population for selection
89 w_min: 0.1, // End with 10% of population
90 w_f: 0.9, // F parameter adaptation rate
91 w_cr: 0.9, // CR parameter adaptation rate
92 f_m: 0.5, // Initial F location parameter
93 cr_m: 0.6, // Initial CR location parameter
94 wls_prob: 0.2, // Apply WLS to 20% of population
95 wls_scale: 0.1, // WLS perturbation scale
96 };
97
98 let config = DEConfigBuilder::new()
99 .seed(42)
100 .maxiter(50)
101 .popsize(40)
102 .strategy(Strategy::AdaptiveBin)
103 .mutation(Mutation::Adaptive { initial_f: 0.8 })
104 .adaptive(adaptive_config)
105 .disp(true) // Enable progress display
106 .build()
107 .expect("popsize must be >= 4");
108
109 println!("Running adaptive DE on Rosenbrock function with progress display...");
110 let result = differential_evolution(&rosenbrock, &bounds, config).expect("optimization failed");
111
112 println!(
113 "Final result: f = {:.6e} at x = [{:.4}, {:.4}]",
114 result.fun, result.x[0], result.x[1]
115 );
116 println!(
117 "Converged in {} iterations with {} function evaluations",
118 result.nit, result.nfev
119 );
120
121 if result.success {
122 println!("✅ Optimization succeeded: {}", result.message);
123 } else {
124 println!("⚠️ Optimization status: {}", result.message);
125 }
126}
127
128fn run_traditional_de(
129 func: fn(&Array1<f64>) -> f64,
130 bounds: &[(f64, f64)],
131) -> math_audio_optimisation::DEReport {
132 let config = DEConfigBuilder::new()
133 .seed(42)
134 .maxiter(100)
135 .popsize(30)
136 .strategy(Strategy::Best1Bin)
137 .mutation(Mutation::Factor(0.8))
138 .recombination(0.7)
139 .build()
140 .expect("popsize must be >= 4");
141
142 differential_evolution(&func, bounds, config).expect("optimization failed")
143}
144
145fn run_adaptive_de(
146 func: fn(&Array1<f64>) -> f64,
147 bounds: &[(f64, f64)],
148 enable_wls: bool,
149) -> math_audio_optimisation::DEReport {
150 let adaptive_config = AdaptiveConfig {
151 adaptive_mutation: true,
152 wls_enabled: enable_wls,
153 w_max: 0.9,
154 w_min: 0.1,
155 wls_prob: 0.15,
156 wls_scale: 0.1,
157 ..AdaptiveConfig::default()
158 };
159
160 let config = DEConfigBuilder::new()
161 .seed(42)
162 .maxiter(100)
163 .popsize(30)
164 .strategy(Strategy::AdaptiveBin)
165 .mutation(Mutation::Adaptive { initial_f: 0.8 })
166 .adaptive(adaptive_config)
167 .build()
168 .expect("popsize must be >= 4");
169
170 differential_evolution(&func, bounds, config).expect("optimization failed")
171}Sourcepub fn crossover(self, v: Crossover) -> Self
pub fn crossover(self, v: Crossover) -> Self
Sets the crossover type.
Examples found in repository?
7fn main() {
8 // Objective: sphere in 2D
9 let sphere = |x: &Array1<f64>| x.iter().map(|v| v * v).sum::<f64>();
10
11 // Bounds
12 let bounds = [(-5.0, 5.0), (-5.0, 5.0)];
13
14 // Linear constraint example: lb <= A x <= ub
15 // 1) x0 + x1 <= 1.0
16 // 2) 0.2 <= x0 - x1 <= 0.4
17 let a = Array2::from_shape_vec((2, 2), vec![1.0, 1.0, 1.0, -1.0]).unwrap();
18 let lb = Array1::from(vec![-f64::INFINITY, 0.2]);
19 let ub = Array1::from(vec![1.0, 0.4]);
20 let lc = LinearConstraintHelper { a, lb, ub };
21
22 // Strategy parsing from string (mirrors SciPy names)
23 let strategy = Strategy::from_str("randtobest1exp").unwrap_or(Strategy::RandToBest1Exp);
24
25 // Build config using the fluent builder
26 let mut cfg = DEConfigBuilder::new()
27 .seed(123)
28 .maxiter(600)
29 .popsize(30)
30 .strategy(strategy)
31 .recombination(0.9)
32 .mutation(Mutation::Range { min: 0.4, max: 1.0 })
33 .crossover(Crossover::Exponential)
34 .build()
35 .expect("popsize must be >= 4");
36
37 // Apply linear constraints with a penalty weight
38 lc.apply_to(&mut cfg, 1e3);
39
40 let rep = differential_evolution(&sphere, &bounds, cfg).expect("optimization failed");
41 println!(
42 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
43 rep.success, rep.message, rep.fun, rep.x
44 );
45}More examples
8fn main() {
9 // Himmelblau as objective, but with nonlinear constraints to demonstrate helper
10 let himmelblau =
11 |x: &Array1<f64>| (x[0] * x[0] + x[1] - 11.0).powi(2) + (x[0] + x[1] * x[1] - 7.0).powi(2);
12
13 // Bounds
14 let bounds = [(-6.0, 6.0), (-6.0, 6.0)];
15
16 // Nonlinear vector function f(x) with 2 components
17 // 1) Circle-ish constraint: x0^2 + x1^2 <= 10 -> f0(x) = x0^2 + x1^2, lb=-inf, ub=10
18 // 2) Sum equality: x0 + x1 = 1 -> f1(x) = x0 + x1, lb=1, ub=1
19 let fun =
20 Arc::new(|x: &Array1<f64>| Array1::from(vec![x[0] * x[0] + x[1] * x[1], x[0] + x[1]]));
21 let lb = Array1::from(vec![-f64::INFINITY, 1.0]);
22 let ub = Array1::from(vec![10.0, 1.0]);
23 let nlc = NonlinearConstraintHelper { fun, lb, ub };
24
25 // Strategy parsing from string
26 let strategy = Strategy::from_str("best1exp").unwrap_or(Strategy::Best1Exp);
27
28 let mut cfg = DEConfigBuilder::new()
29 .seed(456)
30 .maxiter(800)
31 .popsize(30)
32 .strategy(strategy)
33 .recombination(0.9)
34 .crossover(Crossover::Exponential)
35 .build()
36 .expect("popsize must be >= 4");
37
38 // Apply nonlinear constraints with penalties
39 nlc.apply_to(&mut cfg, 1e3, 1e3);
40
41 let rep = differential_evolution(&himmelblau, &bounds, cfg).expect("optimization failed");
42 println!(
43 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
44 rep.success, rep.message, rep.fun, rep.x
45 );
46}Sourcepub fn seed(self, v: u64) -> Self
pub fn seed(self, v: u64) -> Self
Sets the random seed for reproducibility.
Examples found in repository?
7fn main() {
8 // Objective: sphere in 2D
9 let sphere = |x: &Array1<f64>| x.iter().map(|v| v * v).sum::<f64>();
10
11 // Bounds
12 let bounds = [(-5.0, 5.0), (-5.0, 5.0)];
13
14 // Linear constraint example: lb <= A x <= ub
15 // 1) x0 + x1 <= 1.0
16 // 2) 0.2 <= x0 - x1 <= 0.4
17 let a = Array2::from_shape_vec((2, 2), vec![1.0, 1.0, 1.0, -1.0]).unwrap();
18 let lb = Array1::from(vec![-f64::INFINITY, 0.2]);
19 let ub = Array1::from(vec![1.0, 0.4]);
20 let lc = LinearConstraintHelper { a, lb, ub };
21
22 // Strategy parsing from string (mirrors SciPy names)
23 let strategy = Strategy::from_str("randtobest1exp").unwrap_or(Strategy::RandToBest1Exp);
24
25 // Build config using the fluent builder
26 let mut cfg = DEConfigBuilder::new()
27 .seed(123)
28 .maxiter(600)
29 .popsize(30)
30 .strategy(strategy)
31 .recombination(0.9)
32 .mutation(Mutation::Range { min: 0.4, max: 1.0 })
33 .crossover(Crossover::Exponential)
34 .build()
35 .expect("popsize must be >= 4");
36
37 // Apply linear constraints with a penalty weight
38 lc.apply_to(&mut cfg, 1e3);
39
40 let rep = differential_evolution(&sphere, &bounds, cfg).expect("optimization failed");
41 println!(
42 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
43 rep.success, rep.message, rep.fun, rep.x
44 );
45}More examples
8fn main() {
9 // Himmelblau as objective, but with nonlinear constraints to demonstrate helper
10 let himmelblau =
11 |x: &Array1<f64>| (x[0] * x[0] + x[1] - 11.0).powi(2) + (x[0] + x[1] * x[1] - 7.0).powi(2);
12
13 // Bounds
14 let bounds = [(-6.0, 6.0), (-6.0, 6.0)];
15
16 // Nonlinear vector function f(x) with 2 components
17 // 1) Circle-ish constraint: x0^2 + x1^2 <= 10 -> f0(x) = x0^2 + x1^2, lb=-inf, ub=10
18 // 2) Sum equality: x0 + x1 = 1 -> f1(x) = x0 + x1, lb=1, ub=1
19 let fun =
20 Arc::new(|x: &Array1<f64>| Array1::from(vec![x[0] * x[0] + x[1] * x[1], x[0] + x[1]]));
21 let lb = Array1::from(vec![-f64::INFINITY, 1.0]);
22 let ub = Array1::from(vec![10.0, 1.0]);
23 let nlc = NonlinearConstraintHelper { fun, lb, ub };
24
25 // Strategy parsing from string
26 let strategy = Strategy::from_str("best1exp").unwrap_or(Strategy::Best1Exp);
27
28 let mut cfg = DEConfigBuilder::new()
29 .seed(456)
30 .maxiter(800)
31 .popsize(30)
32 .strategy(strategy)
33 .recombination(0.9)
34 .crossover(Crossover::Exponential)
35 .build()
36 .expect("popsize must be >= 4");
37
38 // Apply nonlinear constraints with penalties
39 nlc.apply_to(&mut cfg, 1e3, 1e3);
40
41 let rep = differential_evolution(&himmelblau, &bounds, cfg).expect("optimization failed");
42 println!(
43 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
44 rep.success, rep.message, rep.fun, rep.x
45 );
46}13fn main() {
14 println!("🧬 Adaptive Differential Evolution Demo");
15 println!("=====================================");
16 println!();
17
18 // Test functions to evaluate
19 let test_functions = [
20 (
21 "Quadratic (f(x) = x₁² + x₂²)",
22 quadratic as fn(&Array1<f64>) -> f64,
23 [(-5.0, 5.0), (-5.0, 5.0)],
24 ),
25 (
26 "Rosenbrock 2D",
27 rosenbrock as fn(&Array1<f64>) -> f64,
28 [(-5.0, 5.0), (-5.0, 5.0)],
29 ),
30 ("Ackley", ackley, [(-32.0, 32.0), (-32.0, 32.0)]),
31 ];
32
33 for (name, func, bounds) in test_functions.iter() {
34 println!("🎯 Function: {}", name);
35 println!(
36 " Bounds: [{:.1}, {:.1}] × [{:.1}, {:.1}]",
37 bounds[0].0, bounds[0].1, bounds[1].0, bounds[1].1
38 );
39
40 // Traditional DE
41 println!(" 📊 Traditional DE:");
42 let traditional_result = run_traditional_de(*func, bounds);
43
44 // Adaptive DE with SAM only
45 println!(" 🧬 Adaptive DE (SAM only):");
46 let sam_result = run_adaptive_de(*func, bounds, false);
47
48 // Adaptive DE with SAM + WLS
49 println!(" 🔧 Adaptive DE (SAM + WLS):");
50 let sam_wls_result = run_adaptive_de(*func, bounds, true);
51
52 // Compare results
53 println!(" 🏆 Comparison:");
54 println!(
55 " Traditional: f = {:.6e}, {} iterations",
56 traditional_result.fun, traditional_result.nit
57 );
58 println!(
59 " SAM only: f = {:.6e}, {} iterations",
60 sam_result.fun, sam_result.nit
61 );
62 println!(
63 " SAM + WLS: f = {:.6e}, {} iterations",
64 sam_wls_result.fun, sam_wls_result.nit
65 );
66
67 let improvement_sam =
68 ((traditional_result.fun - sam_result.fun) / traditional_result.fun * 100.0).max(0.0);
69 let improvement_wls =
70 ((traditional_result.fun - sam_wls_result.fun) / traditional_result.fun * 100.0)
71 .max(0.0);
72
73 println!(" 📈 Improvement with SAM: {:.1}%", improvement_sam);
74 println!(" 📈 Improvement with WLS: {:.1}%", improvement_wls);
75 println!();
76 }
77
78 // Demonstrate parameter adaptation tracking
79 println!("🔄 Parameter Adaptation Demo");
80 println!("===========================");
81
82 // Use a recording callback to track parameter evolution
83 let bounds = [(-5.0, 5.0), (-5.0, 5.0)];
84
85 let adaptive_config = AdaptiveConfig {
86 adaptive_mutation: true,
87 wls_enabled: true,
88 w_max: 0.9, // Start with 90% of population for selection
89 w_min: 0.1, // End with 10% of population
90 w_f: 0.9, // F parameter adaptation rate
91 w_cr: 0.9, // CR parameter adaptation rate
92 f_m: 0.5, // Initial F location parameter
93 cr_m: 0.6, // Initial CR location parameter
94 wls_prob: 0.2, // Apply WLS to 20% of population
95 wls_scale: 0.1, // WLS perturbation scale
96 };
97
98 let config = DEConfigBuilder::new()
99 .seed(42)
100 .maxiter(50)
101 .popsize(40)
102 .strategy(Strategy::AdaptiveBin)
103 .mutation(Mutation::Adaptive { initial_f: 0.8 })
104 .adaptive(adaptive_config)
105 .disp(true) // Enable progress display
106 .build()
107 .expect("popsize must be >= 4");
108
109 println!("Running adaptive DE on Rosenbrock function with progress display...");
110 let result = differential_evolution(&rosenbrock, &bounds, config).expect("optimization failed");
111
112 println!(
113 "Final result: f = {:.6e} at x = [{:.4}, {:.4}]",
114 result.fun, result.x[0], result.x[1]
115 );
116 println!(
117 "Converged in {} iterations with {} function evaluations",
118 result.nit, result.nfev
119 );
120
121 if result.success {
122 println!("✅ Optimization succeeded: {}", result.message);
123 } else {
124 println!("⚠️ Optimization status: {}", result.message);
125 }
126}
127
128fn run_traditional_de(
129 func: fn(&Array1<f64>) -> f64,
130 bounds: &[(f64, f64)],
131) -> math_audio_optimisation::DEReport {
132 let config = DEConfigBuilder::new()
133 .seed(42)
134 .maxiter(100)
135 .popsize(30)
136 .strategy(Strategy::Best1Bin)
137 .mutation(Mutation::Factor(0.8))
138 .recombination(0.7)
139 .build()
140 .expect("popsize must be >= 4");
141
142 differential_evolution(&func, bounds, config).expect("optimization failed")
143}
144
145fn run_adaptive_de(
146 func: fn(&Array1<f64>) -> f64,
147 bounds: &[(f64, f64)],
148 enable_wls: bool,
149) -> math_audio_optimisation::DEReport {
150 let adaptive_config = AdaptiveConfig {
151 adaptive_mutation: true,
152 wls_enabled: enable_wls,
153 w_max: 0.9,
154 w_min: 0.1,
155 wls_prob: 0.15,
156 wls_scale: 0.1,
157 ..AdaptiveConfig::default()
158 };
159
160 let config = DEConfigBuilder::new()
161 .seed(42)
162 .maxiter(100)
163 .popsize(30)
164 .strategy(Strategy::AdaptiveBin)
165 .mutation(Mutation::Adaptive { initial_f: 0.8 })
166 .adaptive(adaptive_config)
167 .build()
168 .expect("popsize must be >= 4");
169
170 differential_evolution(&func, bounds, config).expect("optimization failed")
171}Sourcepub fn integrality(self, v: Vec<bool>) -> Self
pub fn integrality(self, v: Vec<bool>) -> Self
Sets the integrality mask for mixed-integer optimization.
Sourcepub fn disp(self, v: bool) -> Self
pub fn disp(self, v: bool) -> Self
Enables/disables progress display.
Examples found in repository?
13fn main() {
14 println!("🧬 Adaptive Differential Evolution Demo");
15 println!("=====================================");
16 println!();
17
18 // Test functions to evaluate
19 let test_functions = [
20 (
21 "Quadratic (f(x) = x₁² + x₂²)",
22 quadratic as fn(&Array1<f64>) -> f64,
23 [(-5.0, 5.0), (-5.0, 5.0)],
24 ),
25 (
26 "Rosenbrock 2D",
27 rosenbrock as fn(&Array1<f64>) -> f64,
28 [(-5.0, 5.0), (-5.0, 5.0)],
29 ),
30 ("Ackley", ackley, [(-32.0, 32.0), (-32.0, 32.0)]),
31 ];
32
33 for (name, func, bounds) in test_functions.iter() {
34 println!("🎯 Function: {}", name);
35 println!(
36 " Bounds: [{:.1}, {:.1}] × [{:.1}, {:.1}]",
37 bounds[0].0, bounds[0].1, bounds[1].0, bounds[1].1
38 );
39
40 // Traditional DE
41 println!(" 📊 Traditional DE:");
42 let traditional_result = run_traditional_de(*func, bounds);
43
44 // Adaptive DE with SAM only
45 println!(" 🧬 Adaptive DE (SAM only):");
46 let sam_result = run_adaptive_de(*func, bounds, false);
47
48 // Adaptive DE with SAM + WLS
49 println!(" 🔧 Adaptive DE (SAM + WLS):");
50 let sam_wls_result = run_adaptive_de(*func, bounds, true);
51
52 // Compare results
53 println!(" 🏆 Comparison:");
54 println!(
55 " Traditional: f = {:.6e}, {} iterations",
56 traditional_result.fun, traditional_result.nit
57 );
58 println!(
59 " SAM only: f = {:.6e}, {} iterations",
60 sam_result.fun, sam_result.nit
61 );
62 println!(
63 " SAM + WLS: f = {:.6e}, {} iterations",
64 sam_wls_result.fun, sam_wls_result.nit
65 );
66
67 let improvement_sam =
68 ((traditional_result.fun - sam_result.fun) / traditional_result.fun * 100.0).max(0.0);
69 let improvement_wls =
70 ((traditional_result.fun - sam_wls_result.fun) / traditional_result.fun * 100.0)
71 .max(0.0);
72
73 println!(" 📈 Improvement with SAM: {:.1}%", improvement_sam);
74 println!(" 📈 Improvement with WLS: {:.1}%", improvement_wls);
75 println!();
76 }
77
78 // Demonstrate parameter adaptation tracking
79 println!("🔄 Parameter Adaptation Demo");
80 println!("===========================");
81
82 // Use a recording callback to track parameter evolution
83 let bounds = [(-5.0, 5.0), (-5.0, 5.0)];
84
85 let adaptive_config = AdaptiveConfig {
86 adaptive_mutation: true,
87 wls_enabled: true,
88 w_max: 0.9, // Start with 90% of population for selection
89 w_min: 0.1, // End with 10% of population
90 w_f: 0.9, // F parameter adaptation rate
91 w_cr: 0.9, // CR parameter adaptation rate
92 f_m: 0.5, // Initial F location parameter
93 cr_m: 0.6, // Initial CR location parameter
94 wls_prob: 0.2, // Apply WLS to 20% of population
95 wls_scale: 0.1, // WLS perturbation scale
96 };
97
98 let config = DEConfigBuilder::new()
99 .seed(42)
100 .maxiter(50)
101 .popsize(40)
102 .strategy(Strategy::AdaptiveBin)
103 .mutation(Mutation::Adaptive { initial_f: 0.8 })
104 .adaptive(adaptive_config)
105 .disp(true) // Enable progress display
106 .build()
107 .expect("popsize must be >= 4");
108
109 println!("Running adaptive DE on Rosenbrock function with progress display...");
110 let result = differential_evolution(&rosenbrock, &bounds, config).expect("optimization failed");
111
112 println!(
113 "Final result: f = {:.6e} at x = [{:.4}, {:.4}]",
114 result.fun, result.x[0], result.x[1]
115 );
116 println!(
117 "Converged in {} iterations with {} function evaluations",
118 result.nit, result.nfev
119 );
120
121 if result.success {
122 println!("✅ Optimization succeeded: {}", result.message);
123 } else {
124 println!("⚠️ Optimization status: {}", result.message);
125 }
126}Sourcepub fn callback(
self,
cb: Box<dyn FnMut(&DEIntermediate) -> CallbackAction>,
) -> Self
pub fn callback( self, cb: Box<dyn FnMut(&DEIntermediate) -> CallbackAction>, ) -> Self
Sets a per-iteration callback function.
Sourcepub fn add_penalty_ineq<FN>(self, f: FN, w: f64) -> Self
pub fn add_penalty_ineq<FN>(self, f: FN, w: f64) -> Self
Adds an inequality constraint penalty function.
Sourcepub fn add_penalty_eq<FN>(self, f: FN, w: f64) -> Self
pub fn add_penalty_eq<FN>(self, f: FN, w: f64) -> Self
Adds an equality constraint penalty function.
Sourcepub fn linear_penalty(self, lp: LinearPenalty) -> Self
pub fn linear_penalty(self, lp: LinearPenalty) -> Self
Sets a linear constraint penalty.
Sourcepub fn polish(self, pol: PolishConfig) -> Self
pub fn polish(self, pol: PolishConfig) -> Self
Sets the polishing configuration.
Sourcepub fn adaptive(self, adaptive: AdaptiveConfig) -> Self
pub fn adaptive(self, adaptive: AdaptiveConfig) -> Self
Sets the adaptive DE configuration.
Examples found in repository?
13fn main() {
14 println!("🧬 Adaptive Differential Evolution Demo");
15 println!("=====================================");
16 println!();
17
18 // Test functions to evaluate
19 let test_functions = [
20 (
21 "Quadratic (f(x) = x₁² + x₂²)",
22 quadratic as fn(&Array1<f64>) -> f64,
23 [(-5.0, 5.0), (-5.0, 5.0)],
24 ),
25 (
26 "Rosenbrock 2D",
27 rosenbrock as fn(&Array1<f64>) -> f64,
28 [(-5.0, 5.0), (-5.0, 5.0)],
29 ),
30 ("Ackley", ackley, [(-32.0, 32.0), (-32.0, 32.0)]),
31 ];
32
33 for (name, func, bounds) in test_functions.iter() {
34 println!("🎯 Function: {}", name);
35 println!(
36 " Bounds: [{:.1}, {:.1}] × [{:.1}, {:.1}]",
37 bounds[0].0, bounds[0].1, bounds[1].0, bounds[1].1
38 );
39
40 // Traditional DE
41 println!(" 📊 Traditional DE:");
42 let traditional_result = run_traditional_de(*func, bounds);
43
44 // Adaptive DE with SAM only
45 println!(" 🧬 Adaptive DE (SAM only):");
46 let sam_result = run_adaptive_de(*func, bounds, false);
47
48 // Adaptive DE with SAM + WLS
49 println!(" 🔧 Adaptive DE (SAM + WLS):");
50 let sam_wls_result = run_adaptive_de(*func, bounds, true);
51
52 // Compare results
53 println!(" 🏆 Comparison:");
54 println!(
55 " Traditional: f = {:.6e}, {} iterations",
56 traditional_result.fun, traditional_result.nit
57 );
58 println!(
59 " SAM only: f = {:.6e}, {} iterations",
60 sam_result.fun, sam_result.nit
61 );
62 println!(
63 " SAM + WLS: f = {:.6e}, {} iterations",
64 sam_wls_result.fun, sam_wls_result.nit
65 );
66
67 let improvement_sam =
68 ((traditional_result.fun - sam_result.fun) / traditional_result.fun * 100.0).max(0.0);
69 let improvement_wls =
70 ((traditional_result.fun - sam_wls_result.fun) / traditional_result.fun * 100.0)
71 .max(0.0);
72
73 println!(" 📈 Improvement with SAM: {:.1}%", improvement_sam);
74 println!(" 📈 Improvement with WLS: {:.1}%", improvement_wls);
75 println!();
76 }
77
78 // Demonstrate parameter adaptation tracking
79 println!("🔄 Parameter Adaptation Demo");
80 println!("===========================");
81
82 // Use a recording callback to track parameter evolution
83 let bounds = [(-5.0, 5.0), (-5.0, 5.0)];
84
85 let adaptive_config = AdaptiveConfig {
86 adaptive_mutation: true,
87 wls_enabled: true,
88 w_max: 0.9, // Start with 90% of population for selection
89 w_min: 0.1, // End with 10% of population
90 w_f: 0.9, // F parameter adaptation rate
91 w_cr: 0.9, // CR parameter adaptation rate
92 f_m: 0.5, // Initial F location parameter
93 cr_m: 0.6, // Initial CR location parameter
94 wls_prob: 0.2, // Apply WLS to 20% of population
95 wls_scale: 0.1, // WLS perturbation scale
96 };
97
98 let config = DEConfigBuilder::new()
99 .seed(42)
100 .maxiter(50)
101 .popsize(40)
102 .strategy(Strategy::AdaptiveBin)
103 .mutation(Mutation::Adaptive { initial_f: 0.8 })
104 .adaptive(adaptive_config)
105 .disp(true) // Enable progress display
106 .build()
107 .expect("popsize must be >= 4");
108
109 println!("Running adaptive DE on Rosenbrock function with progress display...");
110 let result = differential_evolution(&rosenbrock, &bounds, config).expect("optimization failed");
111
112 println!(
113 "Final result: f = {:.6e} at x = [{:.4}, {:.4}]",
114 result.fun, result.x[0], result.x[1]
115 );
116 println!(
117 "Converged in {} iterations with {} function evaluations",
118 result.nit, result.nfev
119 );
120
121 if result.success {
122 println!("✅ Optimization succeeded: {}", result.message);
123 } else {
124 println!("⚠️ Optimization status: {}", result.message);
125 }
126}
127
128fn run_traditional_de(
129 func: fn(&Array1<f64>) -> f64,
130 bounds: &[(f64, f64)],
131) -> math_audio_optimisation::DEReport {
132 let config = DEConfigBuilder::new()
133 .seed(42)
134 .maxiter(100)
135 .popsize(30)
136 .strategy(Strategy::Best1Bin)
137 .mutation(Mutation::Factor(0.8))
138 .recombination(0.7)
139 .build()
140 .expect("popsize must be >= 4");
141
142 differential_evolution(&func, bounds, config).expect("optimization failed")
143}
144
145fn run_adaptive_de(
146 func: fn(&Array1<f64>) -> f64,
147 bounds: &[(f64, f64)],
148 enable_wls: bool,
149) -> math_audio_optimisation::DEReport {
150 let adaptive_config = AdaptiveConfig {
151 adaptive_mutation: true,
152 wls_enabled: enable_wls,
153 w_max: 0.9,
154 w_min: 0.1,
155 wls_prob: 0.15,
156 wls_scale: 0.1,
157 ..AdaptiveConfig::default()
158 };
159
160 let config = DEConfigBuilder::new()
161 .seed(42)
162 .maxiter(100)
163 .popsize(30)
164 .strategy(Strategy::AdaptiveBin)
165 .mutation(Mutation::Adaptive { initial_f: 0.8 })
166 .adaptive(adaptive_config)
167 .build()
168 .expect("popsize must be >= 4");
169
170 differential_evolution(&func, bounds, config).expect("optimization failed")
171}Sourcepub fn enable_adaptive_mutation(self, enable: bool) -> Self
pub fn enable_adaptive_mutation(self, enable: bool) -> Self
Enables/disables adaptive mutation.
Sourcepub fn enable_wls(self, enable: bool) -> Self
pub fn enable_wls(self, enable: bool) -> Self
Enables/disables Wrapper Local Search.
Sourcepub fn adaptive_weights(self, w_max: f64, w_min: f64) -> Self
pub fn adaptive_weights(self, w_max: f64, w_min: f64) -> Self
Sets the adaptive weight bounds.
Sourcepub fn parallel(self, parallel: ParallelConfig) -> Self
pub fn parallel(self, parallel: ParallelConfig) -> Self
Sets the parallel evaluation configuration.
Sourcepub fn enable_parallel(self, enable: bool) -> Self
pub fn enable_parallel(self, enable: bool) -> Self
Enables/disables parallel evaluation.
Sourcepub fn parallel_threads(self, num_threads: usize) -> Self
pub fn parallel_threads(self, num_threads: usize) -> Self
Sets the number of parallel threads.
Sourcepub fn lshade(self, lshade: LShadeConfig) -> Self
pub fn lshade(self, lshade: LShadeConfig) -> Self
Sets the L-SHADE configuration.
Sourcepub fn build(self) -> Result<DEConfig>
pub fn build(self) -> Result<DEConfig>
Examples found in repository?
7fn main() {
8 // Objective: sphere in 2D
9 let sphere = |x: &Array1<f64>| x.iter().map(|v| v * v).sum::<f64>();
10
11 // Bounds
12 let bounds = [(-5.0, 5.0), (-5.0, 5.0)];
13
14 // Linear constraint example: lb <= A x <= ub
15 // 1) x0 + x1 <= 1.0
16 // 2) 0.2 <= x0 - x1 <= 0.4
17 let a = Array2::from_shape_vec((2, 2), vec![1.0, 1.0, 1.0, -1.0]).unwrap();
18 let lb = Array1::from(vec![-f64::INFINITY, 0.2]);
19 let ub = Array1::from(vec![1.0, 0.4]);
20 let lc = LinearConstraintHelper { a, lb, ub };
21
22 // Strategy parsing from string (mirrors SciPy names)
23 let strategy = Strategy::from_str("randtobest1exp").unwrap_or(Strategy::RandToBest1Exp);
24
25 // Build config using the fluent builder
26 let mut cfg = DEConfigBuilder::new()
27 .seed(123)
28 .maxiter(600)
29 .popsize(30)
30 .strategy(strategy)
31 .recombination(0.9)
32 .mutation(Mutation::Range { min: 0.4, max: 1.0 })
33 .crossover(Crossover::Exponential)
34 .build()
35 .expect("popsize must be >= 4");
36
37 // Apply linear constraints with a penalty weight
38 lc.apply_to(&mut cfg, 1e3);
39
40 let rep = differential_evolution(&sphere, &bounds, cfg).expect("optimization failed");
41 println!(
42 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
43 rep.success, rep.message, rep.fun, rep.x
44 );
45}More examples
8fn main() {
9 // Himmelblau as objective, but with nonlinear constraints to demonstrate helper
10 let himmelblau =
11 |x: &Array1<f64>| (x[0] * x[0] + x[1] - 11.0).powi(2) + (x[0] + x[1] * x[1] - 7.0).powi(2);
12
13 // Bounds
14 let bounds = [(-6.0, 6.0), (-6.0, 6.0)];
15
16 // Nonlinear vector function f(x) with 2 components
17 // 1) Circle-ish constraint: x0^2 + x1^2 <= 10 -> f0(x) = x0^2 + x1^2, lb=-inf, ub=10
18 // 2) Sum equality: x0 + x1 = 1 -> f1(x) = x0 + x1, lb=1, ub=1
19 let fun =
20 Arc::new(|x: &Array1<f64>| Array1::from(vec![x[0] * x[0] + x[1] * x[1], x[0] + x[1]]));
21 let lb = Array1::from(vec![-f64::INFINITY, 1.0]);
22 let ub = Array1::from(vec![10.0, 1.0]);
23 let nlc = NonlinearConstraintHelper { fun, lb, ub };
24
25 // Strategy parsing from string
26 let strategy = Strategy::from_str("best1exp").unwrap_or(Strategy::Best1Exp);
27
28 let mut cfg = DEConfigBuilder::new()
29 .seed(456)
30 .maxiter(800)
31 .popsize(30)
32 .strategy(strategy)
33 .recombination(0.9)
34 .crossover(Crossover::Exponential)
35 .build()
36 .expect("popsize must be >= 4");
37
38 // Apply nonlinear constraints with penalties
39 nlc.apply_to(&mut cfg, 1e3, 1e3);
40
41 let rep = differential_evolution(&himmelblau, &bounds, cfg).expect("optimization failed");
42 println!(
43 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
44 rep.success, rep.message, rep.fun, rep.x
45 );
46}13fn main() {
14 println!("🧬 Adaptive Differential Evolution Demo");
15 println!("=====================================");
16 println!();
17
18 // Test functions to evaluate
19 let test_functions = [
20 (
21 "Quadratic (f(x) = x₁² + x₂²)",
22 quadratic as fn(&Array1<f64>) -> f64,
23 [(-5.0, 5.0), (-5.0, 5.0)],
24 ),
25 (
26 "Rosenbrock 2D",
27 rosenbrock as fn(&Array1<f64>) -> f64,
28 [(-5.0, 5.0), (-5.0, 5.0)],
29 ),
30 ("Ackley", ackley, [(-32.0, 32.0), (-32.0, 32.0)]),
31 ];
32
33 for (name, func, bounds) in test_functions.iter() {
34 println!("🎯 Function: {}", name);
35 println!(
36 " Bounds: [{:.1}, {:.1}] × [{:.1}, {:.1}]",
37 bounds[0].0, bounds[0].1, bounds[1].0, bounds[1].1
38 );
39
40 // Traditional DE
41 println!(" 📊 Traditional DE:");
42 let traditional_result = run_traditional_de(*func, bounds);
43
44 // Adaptive DE with SAM only
45 println!(" 🧬 Adaptive DE (SAM only):");
46 let sam_result = run_adaptive_de(*func, bounds, false);
47
48 // Adaptive DE with SAM + WLS
49 println!(" 🔧 Adaptive DE (SAM + WLS):");
50 let sam_wls_result = run_adaptive_de(*func, bounds, true);
51
52 // Compare results
53 println!(" 🏆 Comparison:");
54 println!(
55 " Traditional: f = {:.6e}, {} iterations",
56 traditional_result.fun, traditional_result.nit
57 );
58 println!(
59 " SAM only: f = {:.6e}, {} iterations",
60 sam_result.fun, sam_result.nit
61 );
62 println!(
63 " SAM + WLS: f = {:.6e}, {} iterations",
64 sam_wls_result.fun, sam_wls_result.nit
65 );
66
67 let improvement_sam =
68 ((traditional_result.fun - sam_result.fun) / traditional_result.fun * 100.0).max(0.0);
69 let improvement_wls =
70 ((traditional_result.fun - sam_wls_result.fun) / traditional_result.fun * 100.0)
71 .max(0.0);
72
73 println!(" 📈 Improvement with SAM: {:.1}%", improvement_sam);
74 println!(" 📈 Improvement with WLS: {:.1}%", improvement_wls);
75 println!();
76 }
77
78 // Demonstrate parameter adaptation tracking
79 println!("🔄 Parameter Adaptation Demo");
80 println!("===========================");
81
82 // Use a recording callback to track parameter evolution
83 let bounds = [(-5.0, 5.0), (-5.0, 5.0)];
84
85 let adaptive_config = AdaptiveConfig {
86 adaptive_mutation: true,
87 wls_enabled: true,
88 w_max: 0.9, // Start with 90% of population for selection
89 w_min: 0.1, // End with 10% of population
90 w_f: 0.9, // F parameter adaptation rate
91 w_cr: 0.9, // CR parameter adaptation rate
92 f_m: 0.5, // Initial F location parameter
93 cr_m: 0.6, // Initial CR location parameter
94 wls_prob: 0.2, // Apply WLS to 20% of population
95 wls_scale: 0.1, // WLS perturbation scale
96 };
97
98 let config = DEConfigBuilder::new()
99 .seed(42)
100 .maxiter(50)
101 .popsize(40)
102 .strategy(Strategy::AdaptiveBin)
103 .mutation(Mutation::Adaptive { initial_f: 0.8 })
104 .adaptive(adaptive_config)
105 .disp(true) // Enable progress display
106 .build()
107 .expect("popsize must be >= 4");
108
109 println!("Running adaptive DE on Rosenbrock function with progress display...");
110 let result = differential_evolution(&rosenbrock, &bounds, config).expect("optimization failed");
111
112 println!(
113 "Final result: f = {:.6e} at x = [{:.4}, {:.4}]",
114 result.fun, result.x[0], result.x[1]
115 );
116 println!(
117 "Converged in {} iterations with {} function evaluations",
118 result.nit, result.nfev
119 );
120
121 if result.success {
122 println!("✅ Optimization succeeded: {}", result.message);
123 } else {
124 println!("⚠️ Optimization status: {}", result.message);
125 }
126}
127
128fn run_traditional_de(
129 func: fn(&Array1<f64>) -> f64,
130 bounds: &[(f64, f64)],
131) -> math_audio_optimisation::DEReport {
132 let config = DEConfigBuilder::new()
133 .seed(42)
134 .maxiter(100)
135 .popsize(30)
136 .strategy(Strategy::Best1Bin)
137 .mutation(Mutation::Factor(0.8))
138 .recombination(0.7)
139 .build()
140 .expect("popsize must be >= 4");
141
142 differential_evolution(&func, bounds, config).expect("optimization failed")
143}
144
145fn run_adaptive_de(
146 func: fn(&Array1<f64>) -> f64,
147 bounds: &[(f64, f64)],
148 enable_wls: bool,
149) -> math_audio_optimisation::DEReport {
150 let adaptive_config = AdaptiveConfig {
151 adaptive_mutation: true,
152 wls_enabled: enable_wls,
153 w_max: 0.9,
154 w_min: 0.1,
155 wls_prob: 0.15,
156 wls_scale: 0.1,
157 ..AdaptiveConfig::default()
158 };
159
160 let config = DEConfigBuilder::new()
161 .seed(42)
162 .maxiter(100)
163 .popsize(30)
164 .strategy(Strategy::AdaptiveBin)
165 .mutation(Mutation::Adaptive { initial_f: 0.8 })
166 .adaptive(adaptive_config)
167 .build()
168 .expect("popsize must be >= 4");
169
170 differential_evolution(&func, bounds, config).expect("optimization failed")
171}Trait Implementations§
Auto Trait Implementations§
impl Freeze for DEConfigBuilder
impl !RefUnwindSafe for DEConfigBuilder
impl !Send for DEConfigBuilder
impl !Sync for DEConfigBuilder
impl Unpin for DEConfigBuilder
impl UnsafeUnpin for DEConfigBuilder
impl !UnwindSafe for DEConfigBuilder
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more