internal_parallel_demo/
internal_parallel_demo.rs1use std::sync::Arc;
2use std::time::Duration;
3
4use roma_lib::algorithms::{
5 Algorithm,
6 GeneticAlgorithm,
7 GeneticAlgorithmParameters,
8 run_algorithm_instances_async,
9 spawn_algorithm_run,
10 TerminationCriteria,
11 TerminationCriterion,
12};
13use roma_lib::operator::{BinaryTournamentSelection, BitFlipMutation, SinglePointCrossover};
14use roma_lib::problem::{KnapsackBuilder, KnapsackProblem};
15use roma_lib::solution_set::SolutionSet;
16use roma_lib::utils::{measure_result, speedup};
17use roma_lib::utils::cli::seed_from_cli_or;
18
19fn build_problem() -> KnapsackProblem {
20 let items: Vec<(f64, f64)> = (0..90)
21 .map(|i| {
22 let weight = 3.0 + ((i * 19 % 47) as f64);
23 let value = 9.0 + ((i * 31 % 113) as f64) + weight * 1.2;
24 (weight, value)
25 })
26 .collect();
27
28 KnapsackBuilder::new()
29 .with_capacity(1000.0)
30 .add_items(items)
31 .build()
32}
33
34fn ga_params(
35 seed: u64,
36) -> GeneticAlgorithmParameters<bool, SinglePointCrossover, BitFlipMutation, BinaryTournamentSelection>
37{
38 GeneticAlgorithmParameters::new(
39 120,
40 0.90,
41 0.05,
42 SinglePointCrossover::new(),
43 BitFlipMutation::new(),
44 BinaryTournamentSelection::new(),
45 TerminationCriteria::new(vec![TerminationCriterion::MaxIterations(120)]),
46 )
47 .with_elite_size(2)
48 .with_seed(seed)
49 .sequential()
51}
52
53fn benchmark_sequential(problem: &KnapsackProblem, instances: usize, base_seed: u64) -> Result<(Duration, f64), String> {
54 measure_result(|| {
55 let mut checksum = 0.0;
56
57 for i in 0..instances {
58 let mut algorithm = GeneticAlgorithm::new(ga_params(base_seed + i as u64));
59 let solution_set = algorithm.run(problem)?;
60 checksum += solution_set.best_solution_value_or(problem, 0.0);
61 }
62
63 Ok::<f64, String>(checksum)
64 })
65}
66
67fn benchmark_spawn_runtime(problem: Arc<KnapsackProblem>, instances: usize, base_seed: u64) -> Result<(Duration, f64), String> {
68 measure_result(|| {
69 let mut handles = Vec::with_capacity(instances);
70
71 for i in 0..instances {
72 let algorithm = GeneticAlgorithm::new(ga_params(base_seed + i as u64));
73 handles.push(spawn_algorithm_run(algorithm, Arc::clone(&problem)));
74 }
75
76 let mut checksum = 0.0;
77 for handle in handles {
78 let (_algorithm, run_result) = handle
79 .join()
80 .expect("spawn_algorithm_run worker panicked while executing");
81 let solution_set = run_result?;
82 checksum += solution_set.best_solution_value_or(problem.as_ref(), 0.0);
83 }
84
85 Ok::<f64, String>(checksum)
86 })
87}
88
89fn benchmark_batch_async(problem: Arc<KnapsackProblem>, instances: usize, base_seed: u64) -> Result<(Duration, f64), String> {
90 let algorithms: Vec<GeneticAlgorithm<bool, SinglePointCrossover, BitFlipMutation, BinaryTournamentSelection>> =
91 (0..instances)
92 .map(|i| GeneticAlgorithm::new(ga_params(base_seed + i as u64)))
93 .collect();
94
95 measure_result(|| {
96 let results = run_algorithm_instances_async::<
97 GeneticAlgorithm<bool, SinglePointCrossover, BitFlipMutation, BinaryTournamentSelection>,
98 bool,
99 f64,
100 KnapsackProblem,
101 >(Arc::clone(&problem), algorithms);
102
103 let mut checksum = 0.0;
104 for (_algorithm, run_result) in results {
105 let solution_set = run_result?;
106 checksum += solution_set.best_solution_value_or(problem.as_ref(), 0.0);
107 }
108
109 Ok::<f64, String>(checksum)
110 })
111}
112
113fn main() {
114 let seed = seed_from_cli_or(10_000u64);
115 let instances = 16usize;
116 let problem = Arc::new(build_problem());
117
118 println!("Normal-run benchmark with deterministic seeds");
119 println!("This example compares orchestration overhead for identical GA runs.");
120 println!("Each algorithm run is internally sequential (.sequential()).");
121 println!("Instances: {}", instances);
122 println!("Modes: sequential | spawn_algorithm_run | run_algorithm_instances_async");
123
124 let (seq_time, seq_sum) = match benchmark_sequential(problem.as_ref(), instances, seed) {
125 Ok(v) => v,
126 Err(e) => {
127 eprintln!("Sequential run failed: {}", e);
128 return;
129 }
130 };
131
132 let (spawn_time, spawn_sum) = match benchmark_spawn_runtime(Arc::clone(&problem), instances, seed) {
133 Ok(v) => v,
134 Err(e) => {
135 eprintln!("spawn_algorithm_run benchmark failed: {}", e);
136 return;
137 }
138 };
139
140 let (async_time, async_sum) = match benchmark_batch_async(Arc::clone(&problem), instances, seed) {
141 Ok(v) => v,
142 Err(e) => {
143 eprintln!("run_algorithm_instances_async benchmark failed: {}", e);
144 return;
145 }
146 };
147
148 println!("\nTiming:");
149 println!(" sequential = {:?}", seq_time);
150 println!(" spawn_algorithm_run = {:?}", spawn_time);
151 println!(" run_algorithm_instances_async = {:?}", async_time);
152
153 println!("\nSpeedup vs sequential:");
154 println!(" spawn_algorithm_run : {:.2}x", speedup(seq_time, spawn_time));
155 println!(" run_algorithm_instances_async: {:.2}x", speedup(seq_time, async_time));
156
157 println!("\nChecksums (sum of best objective values):");
158 println!(" sequential = {:.6}", seq_sum);
159 println!(" spawn_algorithm_run = {:.6}", spawn_sum);
160 println!(" run_algorithm_instances_async = {:.6}", async_sum);
161}