pub struct DEConfigBuilder { /* private fields */ }Expand description
Fluent builder for DEConfig for ergonomic configuration.
§Example
use math_audio_differential_evolution::{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
36 // Apply linear constraints with a penalty weight
37 lc.apply_to(&mut cfg, 1e3);
38
39 let rep = differential_evolution(&sphere, &bounds, cfg).expect("optimization failed");
40 println!(
41 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
42 rep.success, rep.message, rep.fun, rep.x
43 );
44}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
37 // Apply nonlinear constraints with penalties
38 nlc.apply_to(&mut cfg, 1e3, 1e3);
39
40 let rep = differential_evolution(&himmelblau, &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}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
108 println!("Running adaptive DE on Rosenbrock function with progress display...");
109 let result = differential_evolution(&rosenbrock, &bounds, config).expect("optimization failed");
110
111 println!(
112 "Final result: f = {:.6e} at x = [{:.4}, {:.4}]",
113 result.fun, result.x[0], result.x[1]
114 );
115 println!(
116 "Converged in {} iterations with {} function evaluations",
117 result.nit, result.nfev
118 );
119
120 if result.success {
121 println!("✅ Optimization succeeded: {}", result.message);
122 } else {
123 println!("⚠️ Optimization status: {}", result.message);
124 }
125}
126
127fn run_traditional_de(
128 func: fn(&Array1<f64>) -> f64,
129 bounds: &[(f64, f64)],
130) -> math_audio_differential_evolution::DEReport {
131 let config = DEConfigBuilder::new()
132 .seed(42)
133 .maxiter(100)
134 .popsize(30)
135 .strategy(Strategy::Best1Bin)
136 .mutation(Mutation::Factor(0.8))
137 .recombination(0.7)
138 .build();
139
140 differential_evolution(&func, bounds, config).expect("optimization failed")
141}
142
143fn run_adaptive_de(
144 func: fn(&Array1<f64>) -> f64,
145 bounds: &[(f64, f64)],
146 enable_wls: bool,
147) -> math_audio_differential_evolution::DEReport {
148 let adaptive_config = AdaptiveConfig {
149 adaptive_mutation: true,
150 wls_enabled: enable_wls,
151 w_max: 0.9,
152 w_min: 0.1,
153 wls_prob: 0.15,
154 wls_scale: 0.1,
155 ..AdaptiveConfig::default()
156 };
157
158 let config = DEConfigBuilder::new()
159 .seed(42)
160 .maxiter(100)
161 .popsize(30)
162 .strategy(Strategy::AdaptiveBin)
163 .mutation(Mutation::Adaptive { initial_f: 0.8 })
164 .adaptive(adaptive_config)
165 .build();
166
167 differential_evolution(&func, bounds, config).expect("optimization failed")
168}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
36 // Apply linear constraints with a penalty weight
37 lc.apply_to(&mut cfg, 1e3);
38
39 let rep = differential_evolution(&sphere, &bounds, cfg).expect("optimization failed");
40 println!(
41 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
42 rep.success, rep.message, rep.fun, rep.x
43 );
44}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
37 // Apply nonlinear constraints with penalties
38 nlc.apply_to(&mut cfg, 1e3, 1e3);
39
40 let rep = differential_evolution(&himmelblau, &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}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
108 println!("Running adaptive DE on Rosenbrock function with progress display...");
109 let result = differential_evolution(&rosenbrock, &bounds, config).expect("optimization failed");
110
111 println!(
112 "Final result: f = {:.6e} at x = [{:.4}, {:.4}]",
113 result.fun, result.x[0], result.x[1]
114 );
115 println!(
116 "Converged in {} iterations with {} function evaluations",
117 result.nit, result.nfev
118 );
119
120 if result.success {
121 println!("✅ Optimization succeeded: {}", result.message);
122 } else {
123 println!("⚠️ Optimization status: {}", result.message);
124 }
125}
126
127fn run_traditional_de(
128 func: fn(&Array1<f64>) -> f64,
129 bounds: &[(f64, f64)],
130) -> math_audio_differential_evolution::DEReport {
131 let config = DEConfigBuilder::new()
132 .seed(42)
133 .maxiter(100)
134 .popsize(30)
135 .strategy(Strategy::Best1Bin)
136 .mutation(Mutation::Factor(0.8))
137 .recombination(0.7)
138 .build();
139
140 differential_evolution(&func, bounds, config).expect("optimization failed")
141}
142
143fn run_adaptive_de(
144 func: fn(&Array1<f64>) -> f64,
145 bounds: &[(f64, f64)],
146 enable_wls: bool,
147) -> math_audio_differential_evolution::DEReport {
148 let adaptive_config = AdaptiveConfig {
149 adaptive_mutation: true,
150 wls_enabled: enable_wls,
151 w_max: 0.9,
152 w_min: 0.1,
153 wls_prob: 0.15,
154 wls_scale: 0.1,
155 ..AdaptiveConfig::default()
156 };
157
158 let config = DEConfigBuilder::new()
159 .seed(42)
160 .maxiter(100)
161 .popsize(30)
162 .strategy(Strategy::AdaptiveBin)
163 .mutation(Mutation::Adaptive { initial_f: 0.8 })
164 .adaptive(adaptive_config)
165 .build();
166
167 differential_evolution(&func, bounds, config).expect("optimization failed")
168}Sourcepub fn popsize(self, v: usize) -> Self
pub fn popsize(self, v: usize) -> Self
Sets the population size multiplier.
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
36 // Apply linear constraints with a penalty weight
37 lc.apply_to(&mut cfg, 1e3);
38
39 let rep = differential_evolution(&sphere, &bounds, cfg).expect("optimization failed");
40 println!(
41 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
42 rep.success, rep.message, rep.fun, rep.x
43 );
44}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
37 // Apply nonlinear constraints with penalties
38 nlc.apply_to(&mut cfg, 1e3, 1e3);
39
40 let rep = differential_evolution(&himmelblau, &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}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
108 println!("Running adaptive DE on Rosenbrock function with progress display...");
109 let result = differential_evolution(&rosenbrock, &bounds, config).expect("optimization failed");
110
111 println!(
112 "Final result: f = {:.6e} at x = [{:.4}, {:.4}]",
113 result.fun, result.x[0], result.x[1]
114 );
115 println!(
116 "Converged in {} iterations with {} function evaluations",
117 result.nit, result.nfev
118 );
119
120 if result.success {
121 println!("✅ Optimization succeeded: {}", result.message);
122 } else {
123 println!("⚠️ Optimization status: {}", result.message);
124 }
125}
126
127fn run_traditional_de(
128 func: fn(&Array1<f64>) -> f64,
129 bounds: &[(f64, f64)],
130) -> math_audio_differential_evolution::DEReport {
131 let config = DEConfigBuilder::new()
132 .seed(42)
133 .maxiter(100)
134 .popsize(30)
135 .strategy(Strategy::Best1Bin)
136 .mutation(Mutation::Factor(0.8))
137 .recombination(0.7)
138 .build();
139
140 differential_evolution(&func, bounds, config).expect("optimization failed")
141}
142
143fn run_adaptive_de(
144 func: fn(&Array1<f64>) -> f64,
145 bounds: &[(f64, f64)],
146 enable_wls: bool,
147) -> math_audio_differential_evolution::DEReport {
148 let adaptive_config = AdaptiveConfig {
149 adaptive_mutation: true,
150 wls_enabled: enable_wls,
151 w_max: 0.9,
152 w_min: 0.1,
153 wls_prob: 0.15,
154 wls_scale: 0.1,
155 ..AdaptiveConfig::default()
156 };
157
158 let config = DEConfigBuilder::new()
159 .seed(42)
160 .maxiter(100)
161 .popsize(30)
162 .strategy(Strategy::AdaptiveBin)
163 .mutation(Mutation::Adaptive { initial_f: 0.8 })
164 .adaptive(adaptive_config)
165 .build();
166
167 differential_evolution(&func, bounds, config).expect("optimization failed")
168}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
36 // Apply linear constraints with a penalty weight
37 lc.apply_to(&mut cfg, 1e3);
38
39 let rep = differential_evolution(&sphere, &bounds, cfg).expect("optimization failed");
40 println!(
41 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
42 rep.success, rep.message, rep.fun, rep.x
43 );
44}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
108 println!("Running adaptive DE on Rosenbrock function with progress display...");
109 let result = differential_evolution(&rosenbrock, &bounds, config).expect("optimization failed");
110
111 println!(
112 "Final result: f = {:.6e} at x = [{:.4}, {:.4}]",
113 result.fun, result.x[0], result.x[1]
114 );
115 println!(
116 "Converged in {} iterations with {} function evaluations",
117 result.nit, result.nfev
118 );
119
120 if result.success {
121 println!("✅ Optimization succeeded: {}", result.message);
122 } else {
123 println!("⚠️ Optimization status: {}", result.message);
124 }
125}
126
127fn run_traditional_de(
128 func: fn(&Array1<f64>) -> f64,
129 bounds: &[(f64, f64)],
130) -> math_audio_differential_evolution::DEReport {
131 let config = DEConfigBuilder::new()
132 .seed(42)
133 .maxiter(100)
134 .popsize(30)
135 .strategy(Strategy::Best1Bin)
136 .mutation(Mutation::Factor(0.8))
137 .recombination(0.7)
138 .build();
139
140 differential_evolution(&func, bounds, config).expect("optimization failed")
141}
142
143fn run_adaptive_de(
144 func: fn(&Array1<f64>) -> f64,
145 bounds: &[(f64, f64)],
146 enable_wls: bool,
147) -> math_audio_differential_evolution::DEReport {
148 let adaptive_config = AdaptiveConfig {
149 adaptive_mutation: true,
150 wls_enabled: enable_wls,
151 w_max: 0.9,
152 w_min: 0.1,
153 wls_prob: 0.15,
154 wls_scale: 0.1,
155 ..AdaptiveConfig::default()
156 };
157
158 let config = DEConfigBuilder::new()
159 .seed(42)
160 .maxiter(100)
161 .popsize(30)
162 .strategy(Strategy::AdaptiveBin)
163 .mutation(Mutation::Adaptive { initial_f: 0.8 })
164 .adaptive(adaptive_config)
165 .build();
166
167 differential_evolution(&func, bounds, config).expect("optimization failed")
168}Sourcepub fn recombination(self, v: f64) -> Self
pub fn recombination(self, v: f64) -> Self
Sets the crossover probability (CR).
Examples found in repository?
127fn run_traditional_de(
128 func: fn(&Array1<f64>) -> f64,
129 bounds: &[(f64, f64)],
130) -> math_audio_differential_evolution::DEReport {
131 let config = DEConfigBuilder::new()
132 .seed(42)
133 .maxiter(100)
134 .popsize(30)
135 .strategy(Strategy::Best1Bin)
136 .mutation(Mutation::Factor(0.8))
137 .recombination(0.7)
138 .build();
139
140 differential_evolution(&func, bounds, config).expect("optimization failed")
141}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
36 // Apply linear constraints with a penalty weight
37 lc.apply_to(&mut cfg, 1e3);
38
39 let rep = differential_evolution(&sphere, &bounds, cfg).expect("optimization failed");
40 println!(
41 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
42 rep.success, rep.message, rep.fun, rep.x
43 );
44}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
37 // Apply nonlinear constraints with penalties
38 nlc.apply_to(&mut cfg, 1e3, 1e3);
39
40 let rep = differential_evolution(&himmelblau, &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}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
36 // Apply linear constraints with a penalty weight
37 lc.apply_to(&mut cfg, 1e3);
38
39 let rep = differential_evolution(&sphere, &bounds, cfg).expect("optimization failed");
40 println!(
41 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
42 rep.success, rep.message, rep.fun, rep.x
43 );
44}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
37 // Apply nonlinear constraints with penalties
38 nlc.apply_to(&mut cfg, 1e3, 1e3);
39
40 let rep = differential_evolution(&himmelblau, &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}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
108 println!("Running adaptive DE on Rosenbrock function with progress display...");
109 let result = differential_evolution(&rosenbrock, &bounds, config).expect("optimization failed");
110
111 println!(
112 "Final result: f = {:.6e} at x = [{:.4}, {:.4}]",
113 result.fun, result.x[0], result.x[1]
114 );
115 println!(
116 "Converged in {} iterations with {} function evaluations",
117 result.nit, result.nfev
118 );
119
120 if result.success {
121 println!("✅ Optimization succeeded: {}", result.message);
122 } else {
123 println!("⚠️ Optimization status: {}", result.message);
124 }
125}
126
127fn run_traditional_de(
128 func: fn(&Array1<f64>) -> f64,
129 bounds: &[(f64, f64)],
130) -> math_audio_differential_evolution::DEReport {
131 let config = DEConfigBuilder::new()
132 .seed(42)
133 .maxiter(100)
134 .popsize(30)
135 .strategy(Strategy::Best1Bin)
136 .mutation(Mutation::Factor(0.8))
137 .recombination(0.7)
138 .build();
139
140 differential_evolution(&func, bounds, config).expect("optimization failed")
141}
142
143fn run_adaptive_de(
144 func: fn(&Array1<f64>) -> f64,
145 bounds: &[(f64, f64)],
146 enable_wls: bool,
147) -> math_audio_differential_evolution::DEReport {
148 let adaptive_config = AdaptiveConfig {
149 adaptive_mutation: true,
150 wls_enabled: enable_wls,
151 w_max: 0.9,
152 w_min: 0.1,
153 wls_prob: 0.15,
154 wls_scale: 0.1,
155 ..AdaptiveConfig::default()
156 };
157
158 let config = DEConfigBuilder::new()
159 .seed(42)
160 .maxiter(100)
161 .popsize(30)
162 .strategy(Strategy::AdaptiveBin)
163 .mutation(Mutation::Adaptive { initial_f: 0.8 })
164 .adaptive(adaptive_config)
165 .build();
166
167 differential_evolution(&func, bounds, config).expect("optimization failed")
168}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
36 // Apply linear constraints with a penalty weight
37 lc.apply_to(&mut cfg, 1e3);
38
39 let rep = differential_evolution(&sphere, &bounds, cfg).expect("optimization failed");
40 println!(
41 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
42 rep.success, rep.message, rep.fun, rep.x
43 );
44}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
37 // Apply nonlinear constraints with penalties
38 nlc.apply_to(&mut cfg, 1e3, 1e3);
39
40 let rep = differential_evolution(&himmelblau, &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}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
36 // Apply linear constraints with a penalty weight
37 lc.apply_to(&mut cfg, 1e3);
38
39 let rep = differential_evolution(&sphere, &bounds, cfg).expect("optimization failed");
40 println!(
41 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
42 rep.success, rep.message, rep.fun, rep.x
43 );
44}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
37 // Apply nonlinear constraints with penalties
38 nlc.apply_to(&mut cfg, 1e3, 1e3);
39
40 let rep = differential_evolution(&himmelblau, &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}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
108 println!("Running adaptive DE on Rosenbrock function with progress display...");
109 let result = differential_evolution(&rosenbrock, &bounds, config).expect("optimization failed");
110
111 println!(
112 "Final result: f = {:.6e} at x = [{:.4}, {:.4}]",
113 result.fun, result.x[0], result.x[1]
114 );
115 println!(
116 "Converged in {} iterations with {} function evaluations",
117 result.nit, result.nfev
118 );
119
120 if result.success {
121 println!("✅ Optimization succeeded: {}", result.message);
122 } else {
123 println!("⚠️ Optimization status: {}", result.message);
124 }
125}
126
127fn run_traditional_de(
128 func: fn(&Array1<f64>) -> f64,
129 bounds: &[(f64, f64)],
130) -> math_audio_differential_evolution::DEReport {
131 let config = DEConfigBuilder::new()
132 .seed(42)
133 .maxiter(100)
134 .popsize(30)
135 .strategy(Strategy::Best1Bin)
136 .mutation(Mutation::Factor(0.8))
137 .recombination(0.7)
138 .build();
139
140 differential_evolution(&func, bounds, config).expect("optimization failed")
141}
142
143fn run_adaptive_de(
144 func: fn(&Array1<f64>) -> f64,
145 bounds: &[(f64, f64)],
146 enable_wls: bool,
147) -> math_audio_differential_evolution::DEReport {
148 let adaptive_config = AdaptiveConfig {
149 adaptive_mutation: true,
150 wls_enabled: enable_wls,
151 w_max: 0.9,
152 w_min: 0.1,
153 wls_prob: 0.15,
154 wls_scale: 0.1,
155 ..AdaptiveConfig::default()
156 };
157
158 let config = DEConfigBuilder::new()
159 .seed(42)
160 .maxiter(100)
161 .popsize(30)
162 .strategy(Strategy::AdaptiveBin)
163 .mutation(Mutation::Adaptive { initial_f: 0.8 })
164 .adaptive(adaptive_config)
165 .build();
166
167 differential_evolution(&func, bounds, config).expect("optimization failed")
168}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
108 println!("Running adaptive DE on Rosenbrock function with progress display...");
109 let result = differential_evolution(&rosenbrock, &bounds, config).expect("optimization failed");
110
111 println!(
112 "Final result: f = {:.6e} at x = [{:.4}, {:.4}]",
113 result.fun, result.x[0], result.x[1]
114 );
115 println!(
116 "Converged in {} iterations with {} function evaluations",
117 result.nit, result.nfev
118 );
119
120 if result.success {
121 println!("✅ Optimization succeeded: {}", result.message);
122 } else {
123 println!("⚠️ Optimization status: {}", result.message);
124 }
125}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
108 println!("Running adaptive DE on Rosenbrock function with progress display...");
109 let result = differential_evolution(&rosenbrock, &bounds, config).expect("optimization failed");
110
111 println!(
112 "Final result: f = {:.6e} at x = [{:.4}, {:.4}]",
113 result.fun, result.x[0], result.x[1]
114 );
115 println!(
116 "Converged in {} iterations with {} function evaluations",
117 result.nit, result.nfev
118 );
119
120 if result.success {
121 println!("✅ Optimization succeeded: {}", result.message);
122 } else {
123 println!("⚠️ Optimization status: {}", result.message);
124 }
125}
126
127fn run_traditional_de(
128 func: fn(&Array1<f64>) -> f64,
129 bounds: &[(f64, f64)],
130) -> math_audio_differential_evolution::DEReport {
131 let config = DEConfigBuilder::new()
132 .seed(42)
133 .maxiter(100)
134 .popsize(30)
135 .strategy(Strategy::Best1Bin)
136 .mutation(Mutation::Factor(0.8))
137 .recombination(0.7)
138 .build();
139
140 differential_evolution(&func, bounds, config).expect("optimization failed")
141}
142
143fn run_adaptive_de(
144 func: fn(&Array1<f64>) -> f64,
145 bounds: &[(f64, f64)],
146 enable_wls: bool,
147) -> math_audio_differential_evolution::DEReport {
148 let adaptive_config = AdaptiveConfig {
149 adaptive_mutation: true,
150 wls_enabled: enable_wls,
151 w_max: 0.9,
152 w_min: 0.1,
153 wls_prob: 0.15,
154 wls_scale: 0.1,
155 ..AdaptiveConfig::default()
156 };
157
158 let config = DEConfigBuilder::new()
159 .seed(42)
160 .maxiter(100)
161 .popsize(30)
162 .strategy(Strategy::AdaptiveBin)
163 .mutation(Mutation::Adaptive { initial_f: 0.8 })
164 .adaptive(adaptive_config)
165 .build();
166
167 differential_evolution(&func, bounds, config).expect("optimization failed")
168}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 build(self) -> DEConfig
pub fn build(self) -> DEConfig
Builds and returns the 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
36 // Apply linear constraints with a penalty weight
37 lc.apply_to(&mut cfg, 1e3);
38
39 let rep = differential_evolution(&sphere, &bounds, cfg).expect("optimization failed");
40 println!(
41 "success={} message=\"{}\"\nbest f={:.6e}\nbest x={:?}",
42 rep.success, rep.message, rep.fun, rep.x
43 );
44}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
37 // Apply nonlinear constraints with penalties
38 nlc.apply_to(&mut cfg, 1e3, 1e3);
39
40 let rep = differential_evolution(&himmelblau, &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}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
108 println!("Running adaptive DE on Rosenbrock function with progress display...");
109 let result = differential_evolution(&rosenbrock, &bounds, config).expect("optimization failed");
110
111 println!(
112 "Final result: f = {:.6e} at x = [{:.4}, {:.4}]",
113 result.fun, result.x[0], result.x[1]
114 );
115 println!(
116 "Converged in {} iterations with {} function evaluations",
117 result.nit, result.nfev
118 );
119
120 if result.success {
121 println!("✅ Optimization succeeded: {}", result.message);
122 } else {
123 println!("⚠️ Optimization status: {}", result.message);
124 }
125}
126
127fn run_traditional_de(
128 func: fn(&Array1<f64>) -> f64,
129 bounds: &[(f64, f64)],
130) -> math_audio_differential_evolution::DEReport {
131 let config = DEConfigBuilder::new()
132 .seed(42)
133 .maxiter(100)
134 .popsize(30)
135 .strategy(Strategy::Best1Bin)
136 .mutation(Mutation::Factor(0.8))
137 .recombination(0.7)
138 .build();
139
140 differential_evolution(&func, bounds, config).expect("optimization failed")
141}
142
143fn run_adaptive_de(
144 func: fn(&Array1<f64>) -> f64,
145 bounds: &[(f64, f64)],
146 enable_wls: bool,
147) -> math_audio_differential_evolution::DEReport {
148 let adaptive_config = AdaptiveConfig {
149 adaptive_mutation: true,
150 wls_enabled: enable_wls,
151 w_max: 0.9,
152 w_min: 0.1,
153 wls_prob: 0.15,
154 wls_scale: 0.1,
155 ..AdaptiveConfig::default()
156 };
157
158 let config = DEConfigBuilder::new()
159 .seed(42)
160 .maxiter(100)
161 .popsize(30)
162 .strategy(Strategy::AdaptiveBin)
163 .mutation(Mutation::Adaptive { initial_f: 0.8 })
164 .adaptive(adaptive_config)
165 .build();
166
167 differential_evolution(&func, bounds, config).expect("optimization failed")
168}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 !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