pub struct GA<F>{
pub population: Population,
/* private fields */
}Fields§
§population: PopulationImplementations§
Source§impl<F> GA<F>
impl<F> GA<F>
Sourcepub fn new(
initialization: InitializationStrategy,
fitness: F,
config: Config,
) -> Self
pub fn new( initialization: InitializationStrategy, fitness: F, config: Config, ) -> Self
initialize population based on an initialization strategy and a fitness function
Examples found in repository?
examples/optimization.rs (line 26)
6fn main() {
7 fn fitness(weights: Population) -> f64 {
8 let inputs = vec![4.0, -2.0, 3.5, 5.0, -11.0, -4.7];
9 let target = 44.0;
10 match weights {
11 Population::F64(vec) => {
12 let distance: f64 = inputs.iter()
13 .zip(&vec[0])
14 .map(|(x, y)| x * y)
15 .sum();
16 let result = 1.0 / ((target - distance).abs()+0.000000001);
17 result
18 }
19 _ => panic!("Expected Population::F64"),
20 }
21 }
22
23 let init_strategy = InitializationStrategy::F64(Box::new(RandomInitialization));
24 let mut config = Config::default();
25 config.num_individuals = 1000;
26 let mut ga = GA::new(init_strategy,fitness, config);
27
28 let hist = ga.evolve(100);
29 let inputs = vec![4.0, -2.0, 3.5, 5.0, -11.0, -4.7];
30 let distance: f64 = inputs.iter()
31 .zip(&ga.population.get_individual(0).unwrap())
32 .map(|(x, y)| x * y)
33 .sum();
34 println!("Solution = {}",distance);
35 draw_fitness(hist, "fitness_curve.png");
36}More examples
examples/n_queens.rs (line 31)
3fn main() {
4 fn calculate_fitness(weights: Population) -> f64 {
5 match weights {
6 Population::Usize(vec)=>{
7 if let Some(individual) = vec.get(0) {
8 let mut fitness = 0;
9 for i in 0..individual.len() {
10 for j in i + 1..individual.len() {
11 if individual[i] != individual[j] &&
12 individual[i] + i != individual[j] + j &&
13 individual[i] as isize - i as isize != individual[j] as isize - j as isize {
14 fitness += 1;
15 }
16 }
17 }
18 fitness as f64
19 } else {
20 0.0
21 }
22 }
23 _ => panic!("Expected Population::usize")
24 }
25 }
26 let num_queens = 9;
27 let init_strategy = InitializationStrategy::Usize(Box::new(TSPInitialization));
28 let mut config = Config::default();
29 config.num_individuals=100;
30 config.num_genes = num_queens;
31 let mut ga = GA::new(init_strategy, calculate_fitness, config);
32 let hist = ga.evolve(100);
33 let solution:Vec<usize> = ga.population.get_individual(0).unwrap();
34 println!("Solution = {:?}",solution);
35 draw_fitness(hist, "fitness_curve.png");
36}examples/tsp.rs (line 30)
4fn main() {
5 struct City{x:f64,y:f64,}
6 fn distance_(city1: &City, city2: &City) -> f64 {
7 ((city1.x - city2.x).powi(2) + (city1.y - city2.y).powi(2)).sqrt()
8 }
9 fn total_distance(weights: Population) -> f64 {
10 //solving for 5-points star
11 //historical europe tour: Rome, Paris, Athens, Berlin, London, Vienna
12 let cities = vec![City{x:41.9028,y:12.4964},City{x:48.8566,y:2.3522},City{x:37.9838,y:23.7275},City{x:52.5200,y:13.4050},City{x:51.5074,y:-0.1278},City{x:48.2082,y:16.3738}];
13 let mut distance = 0.0;
14 match weights {
15 Population::Usize(vec)=>{
16 for i in 0..cities.len() - 1 {
17 distance += distance_(&cities[vec[0][i]], &cities[vec[0][i + 1]]);
18 }
19 distance += distance_(&cities[cities.len() - 1], &cities[0]);
20 distance
21 }
22 _ => panic!("Expected Population::usize")
23 }
24 }
25
26 let init_strategy = InitializationStrategy::Usize(Box::new(TSPInitialization));
27 let mut config = Config::default();
28 config.num_individuals=100;
29 config.num_genes = 6;
30 let mut ga = GA::new(init_strategy, total_distance, config);
31
32 let hist = ga.evolve(100);
33 let solution:Vec<usize> = ga.population.get_individual(0).unwrap();
34 println!("Solution = {:?}",solution);
35 draw_fitness(hist, "fitness_curve.png");
36}examples/sudoku.rs (line 51)
3fn main() {
4 fn calculate_fitness(weights:Population) -> f64 {
5 match weights {
6 Population::Usize(vec)=>{
7 let mut score = 0.0;
8 // Check rows
9 for row in 0..9 {
10 let start = row * 9;
11 let unique_digits: std::collections::HashSet<_> =
12 vec[0][start..start + 9].iter().cloned().collect();
13 score += unique_digits.len() as f64;
14 }
15 // Check columns
16 for col in 0..9 {
17 let unique_digits: std::collections::HashSet<_> =
18 (0..9).map(|row| vec[0][row * 9 + col]).collect();
19 score += unique_digits.len() as f64;
20 }
21 // Check subgrids
22 for subgrid_row in (0..9).step_by(3) {
23 for subgrid_col in (0..9).step_by(3) {
24 let mut unique_digits = std::collections::HashSet::new();
25 for i in 0..3 {
26 for j in 0..3 {
27 unique_digits.insert(vec[0][(subgrid_row + i) * 9 + subgrid_col + j]);
28 }
29 }
30 score += unique_digits.len() as f64;
31 }
32 }
33 // Penalize invalid numbers (outside 1-9)
34 for &value in vec[0].iter() {
35 if value < 1 || value > 9 {
36 score -= 5.0; // Arbitrary penalty
37 }
38 }
39 // Add bonus for completeness
40 let filled_cells = vec[0].iter().filter(|&&value| value != 0).count();
41 score += filled_cells as f64 / 81.0; // Fraction of cells filled
42 score
43 }
44 _ => panic!("Expected Population::usize")
45 }
46 }
47 let init_strategy = InitializationStrategy::Usize(Box::new(SudokuInitialization));
48 let mut config = Config::default();
49 config.num_individuals=100;
50 config.num_genes = 81;
51 let mut ga = GA::new(init_strategy, calculate_fitness, config);
52 ga.inspect();
53 //ga.evaluate();
54 let hist = ga.evolve(100);
55 let solution:Vec<usize> = ga.population.get_individual(0).unwrap();
56 println!("Solution = {:?}",solution);
57 draw_fitness(hist, "fitness_curve.png");
58}Sourcepub fn inspect(&self)
pub fn inspect(&self)
print population
Examples found in repository?
examples/sudoku.rs (line 52)
3fn main() {
4 fn calculate_fitness(weights:Population) -> f64 {
5 match weights {
6 Population::Usize(vec)=>{
7 let mut score = 0.0;
8 // Check rows
9 for row in 0..9 {
10 let start = row * 9;
11 let unique_digits: std::collections::HashSet<_> =
12 vec[0][start..start + 9].iter().cloned().collect();
13 score += unique_digits.len() as f64;
14 }
15 // Check columns
16 for col in 0..9 {
17 let unique_digits: std::collections::HashSet<_> =
18 (0..9).map(|row| vec[0][row * 9 + col]).collect();
19 score += unique_digits.len() as f64;
20 }
21 // Check subgrids
22 for subgrid_row in (0..9).step_by(3) {
23 for subgrid_col in (0..9).step_by(3) {
24 let mut unique_digits = std::collections::HashSet::new();
25 for i in 0..3 {
26 for j in 0..3 {
27 unique_digits.insert(vec[0][(subgrid_row + i) * 9 + subgrid_col + j]);
28 }
29 }
30 score += unique_digits.len() as f64;
31 }
32 }
33 // Penalize invalid numbers (outside 1-9)
34 for &value in vec[0].iter() {
35 if value < 1 || value > 9 {
36 score -= 5.0; // Arbitrary penalty
37 }
38 }
39 // Add bonus for completeness
40 let filled_cells = vec[0].iter().filter(|&&value| value != 0).count();
41 score += filled_cells as f64 / 81.0; // Fraction of cells filled
42 score
43 }
44 _ => panic!("Expected Population::usize")
45 }
46 }
47 let init_strategy = InitializationStrategy::Usize(Box::new(SudokuInitialization));
48 let mut config = Config::default();
49 config.num_individuals=100;
50 config.num_genes = 81;
51 let mut ga = GA::new(init_strategy, calculate_fitness, config);
52 ga.inspect();
53 //ga.evaluate();
54 let hist = ga.evolve(100);
55 let solution:Vec<usize> = ga.population.get_individual(0).unwrap();
56 println!("Solution = {:?}",solution);
57 draw_fitness(hist, "fitness_curve.png");
58}Sourcepub fn sort(&mut self, evals: Vec<f64>)
pub fn sort(&mut self, evals: Vec<f64>)
sort in place population based on an input vector of fitness
Sourcepub fn update(&mut self, new_population: Population)
pub fn update(&mut self, new_population: Population)
update population with a provided one
Sourcepub fn rank_selection_cdf(&self) -> Population
pub fn rank_selection_cdf(&self) -> Population
rank select parents based on cumulative distribution function
Sourcepub fn mate_population(&self) -> Population
pub fn mate_population(&self) -> Population
shuffle population and perform crossover
Sourcepub fn mutate(&mut self) -> Population
pub fn mutate(&mut self) -> Population
mutate population
Sourcepub fn step(&mut self) -> f64
pub fn step(&mut self) -> f64
evolve population forward by one step
in particular:
evaluate population
select population to mate
mate
mutate
evaluate again population
returns new score of updated population
Sourcepub fn evolve(&mut self, num_steps: usize) -> Vec<f64>
pub fn evolve(&mut self, num_steps: usize) -> Vec<f64>
execute num_steps forward of evolution, return a vector of scores (curve of fitness)
Examples found in repository?
examples/optimization.rs (line 28)
6fn main() {
7 fn fitness(weights: Population) -> f64 {
8 let inputs = vec![4.0, -2.0, 3.5, 5.0, -11.0, -4.7];
9 let target = 44.0;
10 match weights {
11 Population::F64(vec) => {
12 let distance: f64 = inputs.iter()
13 .zip(&vec[0])
14 .map(|(x, y)| x * y)
15 .sum();
16 let result = 1.0 / ((target - distance).abs()+0.000000001);
17 result
18 }
19 _ => panic!("Expected Population::F64"),
20 }
21 }
22
23 let init_strategy = InitializationStrategy::F64(Box::new(RandomInitialization));
24 let mut config = Config::default();
25 config.num_individuals = 1000;
26 let mut ga = GA::new(init_strategy,fitness, config);
27
28 let hist = ga.evolve(100);
29 let inputs = vec![4.0, -2.0, 3.5, 5.0, -11.0, -4.7];
30 let distance: f64 = inputs.iter()
31 .zip(&ga.population.get_individual(0).unwrap())
32 .map(|(x, y)| x * y)
33 .sum();
34 println!("Solution = {}",distance);
35 draw_fitness(hist, "fitness_curve.png");
36}More examples
examples/n_queens.rs (line 32)
3fn main() {
4 fn calculate_fitness(weights: Population) -> f64 {
5 match weights {
6 Population::Usize(vec)=>{
7 if let Some(individual) = vec.get(0) {
8 let mut fitness = 0;
9 for i in 0..individual.len() {
10 for j in i + 1..individual.len() {
11 if individual[i] != individual[j] &&
12 individual[i] + i != individual[j] + j &&
13 individual[i] as isize - i as isize != individual[j] as isize - j as isize {
14 fitness += 1;
15 }
16 }
17 }
18 fitness as f64
19 } else {
20 0.0
21 }
22 }
23 _ => panic!("Expected Population::usize")
24 }
25 }
26 let num_queens = 9;
27 let init_strategy = InitializationStrategy::Usize(Box::new(TSPInitialization));
28 let mut config = Config::default();
29 config.num_individuals=100;
30 config.num_genes = num_queens;
31 let mut ga = GA::new(init_strategy, calculate_fitness, config);
32 let hist = ga.evolve(100);
33 let solution:Vec<usize> = ga.population.get_individual(0).unwrap();
34 println!("Solution = {:?}",solution);
35 draw_fitness(hist, "fitness_curve.png");
36}examples/tsp.rs (line 32)
4fn main() {
5 struct City{x:f64,y:f64,}
6 fn distance_(city1: &City, city2: &City) -> f64 {
7 ((city1.x - city2.x).powi(2) + (city1.y - city2.y).powi(2)).sqrt()
8 }
9 fn total_distance(weights: Population) -> f64 {
10 //solving for 5-points star
11 //historical europe tour: Rome, Paris, Athens, Berlin, London, Vienna
12 let cities = vec![City{x:41.9028,y:12.4964},City{x:48.8566,y:2.3522},City{x:37.9838,y:23.7275},City{x:52.5200,y:13.4050},City{x:51.5074,y:-0.1278},City{x:48.2082,y:16.3738}];
13 let mut distance = 0.0;
14 match weights {
15 Population::Usize(vec)=>{
16 for i in 0..cities.len() - 1 {
17 distance += distance_(&cities[vec[0][i]], &cities[vec[0][i + 1]]);
18 }
19 distance += distance_(&cities[cities.len() - 1], &cities[0]);
20 distance
21 }
22 _ => panic!("Expected Population::usize")
23 }
24 }
25
26 let init_strategy = InitializationStrategy::Usize(Box::new(TSPInitialization));
27 let mut config = Config::default();
28 config.num_individuals=100;
29 config.num_genes = 6;
30 let mut ga = GA::new(init_strategy, total_distance, config);
31
32 let hist = ga.evolve(100);
33 let solution:Vec<usize> = ga.population.get_individual(0).unwrap();
34 println!("Solution = {:?}",solution);
35 draw_fitness(hist, "fitness_curve.png");
36}examples/sudoku.rs (line 54)
3fn main() {
4 fn calculate_fitness(weights:Population) -> f64 {
5 match weights {
6 Population::Usize(vec)=>{
7 let mut score = 0.0;
8 // Check rows
9 for row in 0..9 {
10 let start = row * 9;
11 let unique_digits: std::collections::HashSet<_> =
12 vec[0][start..start + 9].iter().cloned().collect();
13 score += unique_digits.len() as f64;
14 }
15 // Check columns
16 for col in 0..9 {
17 let unique_digits: std::collections::HashSet<_> =
18 (0..9).map(|row| vec[0][row * 9 + col]).collect();
19 score += unique_digits.len() as f64;
20 }
21 // Check subgrids
22 for subgrid_row in (0..9).step_by(3) {
23 for subgrid_col in (0..9).step_by(3) {
24 let mut unique_digits = std::collections::HashSet::new();
25 for i in 0..3 {
26 for j in 0..3 {
27 unique_digits.insert(vec[0][(subgrid_row + i) * 9 + subgrid_col + j]);
28 }
29 }
30 score += unique_digits.len() as f64;
31 }
32 }
33 // Penalize invalid numbers (outside 1-9)
34 for &value in vec[0].iter() {
35 if value < 1 || value > 9 {
36 score -= 5.0; // Arbitrary penalty
37 }
38 }
39 // Add bonus for completeness
40 let filled_cells = vec[0].iter().filter(|&&value| value != 0).count();
41 score += filled_cells as f64 / 81.0; // Fraction of cells filled
42 score
43 }
44 _ => panic!("Expected Population::usize")
45 }
46 }
47 let init_strategy = InitializationStrategy::Usize(Box::new(SudokuInitialization));
48 let mut config = Config::default();
49 config.num_individuals=100;
50 config.num_genes = 81;
51 let mut ga = GA::new(init_strategy, calculate_fitness, config);
52 ga.inspect();
53 //ga.evaluate();
54 let hist = ga.evolve(100);
55 let solution:Vec<usize> = ga.population.get_individual(0).unwrap();
56 println!("Solution = {:?}",solution);
57 draw_fitness(hist, "fitness_curve.png");
58}Auto Trait Implementations§
impl<F> Freeze for GA<F>where
F: Freeze,
impl<F> !RefUnwindSafe for GA<F>
impl<F> !Send for GA<F>
impl<F> !Sync for GA<F>
impl<F> Unpin for GA<F>where
F: Unpin,
impl<F> !UnwindSafe for GA<F>
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
Mutably borrows from an owned value. Read more