GA

Struct GA 

Source
pub struct GA<F>
where F: Fn(Population) -> f64,
{ pub population: Population, /* private fields */ }

Fields§

§population: Population

Implementations§

Source§

impl<F> GA<F>
where F: Fn(Population) -> f64,

Source

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
Hide additional 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}
Source

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}
Source

pub fn evaluate(&self) -> Vec<f64>

evaluate fitness of the whole population

Source

pub fn sort(&mut self, evals: Vec<f64>)

sort in place population based on an input vector of fitness

Source

pub fn update(&mut self, new_population: Population)

update population with a provided one

Source

pub fn rank_selection_cdf(&self) -> Population

rank select parents based on cumulative distribution function

Source

pub fn mate_population(&self) -> Population

shuffle population and perform crossover

Source

pub fn mutate(&mut self) -> Population

mutate population

Source

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

Source

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
Hide additional 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> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V