Skip to main content

experiment_parallel_vs_sequential/
experiment_parallel_vs_sequential.rs

1use std::time::Duration;
2
3use roma_lib::algorithms::{
4    GeneticAlgorithmParameters,
5    HillClimbingParameters,
6    PSOParameters,
7    SimulatedAnnealingParameters,
8    TerminationCriteria,
9    TerminationCriterion,
10};
11use roma_lib::experiment::{Experiment, ExperimentReport};
12use roma_lib::operator::{BinaryTournamentSelection, BitFlipMutation, SinglePointCrossover};
13use roma_lib::problem::{KnapsackBuilder, Problem};
14use roma_lib::utils::{measure_result, speedup};
15
16fn build_problem() -> impl Problem<bool, f64> + Sync {
17    KnapsackBuilder::new()
18        .with_capacity(150.0)
19        .add_item(1.0, 2.0)
20        .add_item(2.0, 6.0)
21        .add_item(3.0, 7.0)
22        .add_item(10.0, 20.0)
23        .add_item(20.0, 30.0)
24        .add_item(30.0, 60.0)
25        .add_item(35.0, 65.0)
26        .add_item(45.0, 100.0)
27        .add_item(55.0, 120.0)
28        .add_item(75.0, 211.0)
29        .add_item(80.0, 160.0)
30        .add_item(90.0, 301.0)
31        .add_item(150.0, 301.0)
32        .build()
33}
34
35fn run_experiment(parallel: bool, runs: usize) -> Result<(Duration, ExperimentReport), String> {
36    let problem = build_problem();
37
38    let hill_climbing_case = HillClimbingParameters::new(
39        BitFlipMutation::new(),
40        0.12,
41        TerminationCriteria::new(vec![TerminationCriterion::MaxIterations(180)]),
42    )
43    .with_seed(111);
44
45    // Keep GA internally sequential to focus the comparison on experiment-level parallelism.
46    let genetic_algorithm_case = GeneticAlgorithmParameters::new(
47            80,
48            0.90,
49            0.06,
50            SinglePointCrossover::new(),
51            BitFlipMutation::new(),
52            BinaryTournamentSelection::new(),
53            TerminationCriteria::new(vec![TerminationCriterion::MaxIterations(60)]),
54        )
55        .with_elite_size(1)
56        .with_seed(222)
57        .sequential();
58
59    let simulated_annealing_case = SimulatedAnnealingParameters::new(
60        BitFlipMutation::new(),
61        0.10,
62        45.0,
63        0.985,
64        TerminationCriteria::new(vec![TerminationCriterion::MaxIterations(220)]),
65    )
66    .with_seed(333);
67
68    let pso_case = PSOParameters::new(
69        50,
70        0.72,
71        1.49,
72        1.49,
73        TerminationCriteria::new(vec![TerminationCriterion::MaxIterations(120)]),
74    )
75    .with_velocity_clamp(4.0)
76    .with_seed(444);
77
78    let experiment = Experiment::new(problem)
79        .with_runs(runs)
80        .add_case(hill_climbing_case)
81        .add_case(genetic_algorithm_case)
82        .add_case(simulated_annealing_case)
83        .add_case(pso_case);
84
85    measure_result(|| {
86        if parallel {
87            experiment.with_parallel().execute()
88        } else {
89            experiment.sequential().execute()
90        }
91    })
92}
93
94fn main() {
95    let runs = 24;
96
97    println!("Simple benchmark: Sequential vs parallel experiment execution");
98    println!("Cases: 4 | Runs per case: {}", runs);
99
100    let (sequential_time, sequential_report) = match run_experiment(false, runs) {
101        Ok(value) => value,
102        Err(error) => {
103            eprintln!("Sequential execution error: {}", error);
104            return;
105        }
106    };
107
108    let (parallel_time, parallel_report) = match run_experiment(true, runs) {
109        Ok(value) => value,
110        Err(error) => {
111            eprintln!("Parallel execution error: {}", error);
112            return;
113        }
114    };
115
116    let speedup = speedup(sequential_time, parallel_time);
117
118    println!("\nTiming results:");
119    println!("  Sequential: {:?}", sequential_time);
120    println!("  Parallel  : {:?}", parallel_time);
121    println!("  Speedup   : {:.2}x", speedup);
122
123    println!("\nSequential summary (top 2 by best):");
124    for summary in sequential_report.summaries.iter().take(2) {
125        println!(
126            "  - {} | best={:.4} mean={:.4}",
127            summary.case_name, summary.best, summary.mean
128        );
129    }
130
131    println!("\nParallel summary (top 2 by best):");
132    for summary in parallel_report.summaries.iter().take(2) {
133        println!(
134            "  - {} | best={:.4} mean={:.4}",
135            summary.case_name, summary.best, summary.mean
136        );
137    }
138}