Struct Pool

Source
pub struct Pool { /* private fields */ }
Expand description

A “Gene” Pool that contains and manages a population of Genomes separated into one or more Species.

Implementations§

Source§

impl Pool

Source

pub fn new( inputs: usize, outputs: usize, population_size: usize, connection_mut_rate: f32, node_mut_rate: f32, weight_mut_rate: f32, perturb_rate: f32, weight_mut_step_size: f32, disable_mut_rate: f32, enable_mut_rate: f32, excess_coef: f32, disjoint_coef: f32, weight_diff_coef: f32, species_threshold: f32, mut_only_rate: f32, mate_only_rate: f32, crossover_rate: f32, species_dropoff_age: usize, age_significance: f32, survival_threshold: f32, ) -> Self

Initialize a new Pool with the given number of inputs, outputs, and overriding all of the default constants. (If you wish to use some of the defaults they are accessible in the defaults module.)

Source

pub fn with_defaults(inputs: usize, outputs: usize) -> Self

Initialize a new Pool with the given number of inputs, outputs, and use all of the default constants.

Examples found in repository?
examples/adding_managed.rs (line 28)
13fn main() {
14    let args: Vec<String> = env::args().collect();
15
16    if args.len() < 2 {
17        println!("Usage: '{} train' to train a new comparer.", args[0]);
18        println!("Usage: '{} evaluate serialized_genome.json input1 input2 input3 input4' to evaluate with an existing genome.", args[0]);
19        return;
20    }
21
22    if args[1] == "train" {
23        // One input node for each input in the training data structure
24        let input_nodes = 4;
25        // One output node with the "prediction"
26        let output_nodes = 1;
27        // Create a new gene pool with an initial population of genomes
28        let mut gene_pool = Pool::with_defaults(input_nodes, output_nodes);
29
30        let training_data = load_training_data(TRAINING_DATA_STRING, 4, 1);
31
32        let mut trainer = Trainer::new(training_data);
33        // This function will be called once per Genome per piece of
34        // TrainingData in each generation, passing the values of the
35        // output nodes of the Genome as well as the expected result
36        // from the TrainingData.
37        trainer.evaluate_fn = adding_fitness_func;
38        trainer.hidden_activation = linear_activation;
39        trainer.output_activation = linear_activation;
40
41        // Train over the course of 100 generations
42        trainer.train(&mut gene_pool, 100);
43
44        let best_genome = gene_pool.get_best_genome();
45
46        println!("Serializing best genome to winner.json");
47        serde_json::to_writer(&File::create("winner.json").unwrap(), &best_genome).unwrap();
48    } else {
49        if args.len() < 7 {
50            println!("Usage: '{} evaluate serialized_genome.json input1 input2 input3 input4' to evaluate with an existing genome.", args[0]);
51            return;
52        }
53        let mut genome: Genome = serde_json::from_reader(File::open(&args[2]).unwrap()).unwrap();
54        let input1 = args[3]
55            .parse::<f32>()
56            .expect("Couldn't parse input1 as f32");
57        let input2 = args[4]
58            .parse::<f32>()
59            .expect("Couldn't parse input2 as f32");
60        let input3 = args[5]
61            .parse::<f32>()
62            .expect("Couldn't parse input1 as f32");
63        let input4 = args[6]
64            .parse::<f32>()
65            .expect("Couldn't parse input2 as f32");
66        // Note that this is the exact same function we used in training
67        // further up!
68        genome.evaluate(
69            &vec![input1, input2, input3, input4],
70            Some(linear_activation),
71            Some(linear_activation),
72        );
73        println!(
74            "Sum of inputs is..........{}",
75            genome.get_outputs()[0] as u32
76        );
77    }
78}
More examples
Hide additional examples
examples/compare.rs (line 51)
36fn main() {
37    let args: Vec<String> = env::args().collect();
38
39    if args.len() < 2 {
40        println!("Usage: '{} train' to train a new comparer.", args[0]);
41        println!("Usage: '{} evaluate serialized_genome.json input1 input2' to evaluate with an existing genome.", args[0]);
42        return;
43    }
44
45    if args[1] == "train" {
46        // One input node for each input in the TrainingData structure
47        let input_nodes = 2;
48        // One output node with the "prediction"
49        let output_nodes = 1;
50        // Create a new gene pool with an initial population of genomes
51        let mut gene_pool = Pool::with_defaults(input_nodes, output_nodes);
52
53        let training_data = load_training_data(TRAINING_DATA_STRING, 4, 1);
54
55        // These variables are used to keep track of the top performer, so we
56        // can write it out later.
57        let mut best_genome: Option<Genome> = None;
58        let mut best_fitness = 0.0;
59
60        // We use a label here to allow us to break out if we find a genome
61        // with a perfect score before we run through all of the generations.
62        'outer: for generation in 0..1000 {
63            println!("Evaluating generation {}", generation + 1);
64            let total_species = gene_pool.len();
65            for s in 0..total_species {
66                let species = &mut gene_pool[s];
67                let genomes_in_species = species.len();
68                for g in 0..genomes_in_species {
69                    let genome = &mut species[g];
70                    let mut fitness = 0.0;
71
72                    for td in &training_data {
73                        // Evaluate the genome using the training data as the
74                        // initial inputs.
75                        genome.evaluate(&td.inputs[0..2].to_vec(), None, None);
76
77                        // We add this to the existing fitness for the genome
78                        // to ensure that the genomes with the best score across
79                        // all tests will have the highest overall fitness.
80                        fitness += fitness_func(genome.get_outputs()[0], td.expected[0]);
81                    }
82
83                    // Update the genome with the calculate fitness score.
84                    // (This is important, as this fitness score is needed to
85                    // spawn the next generation correctly.)
86                    genome.update_fitness(fitness);
87
88                    if fitness > best_fitness {
89                        println!(
90                            "Species {} Genome {} increased best fitness to {}",
91                            s, g, best_fitness
92                        );
93                        best_fitness = fitness;
94                        best_genome = Some(genome.clone());
95                    }
96
97                    if fitness == PERFECT_SCORE {
98                        println!("Found a perfect genome!");
99                        break 'outer;
100                    }
101                }
102            }
103            // Spawn the next generation.
104            gene_pool.new_generation();
105        }
106        println!("Serializing best genome to winner.json");
107        serde_json::to_writer(&File::create("winner.json").unwrap(), &best_genome.unwrap())
108            .unwrap();
109    } else {
110        if args.len() < 5 {
111            println!("Usage: '{} evaluate serialized_genome.json input1 input2' to evaluate with an existing genome.", args[0]);
112            return;
113        }
114        let mut genome: Genome = serde_json::from_reader(File::open(&args[2]).unwrap()).unwrap();
115        let input1 = args[3]
116            .parse::<f32>()
117            .expect("Couldn't parse input1 as f32");
118        let input2 = args[4]
119            .parse::<f32>()
120            .expect("Couldn't parse input2 as f32");
121        genome.evaluate(&vec![input1, input2], None, None);
122        if genome.get_outputs()[0] > 0.5 {
123            println!("Predicted that {} is greater than {}!", input1, input2);
124        } else {
125            println!(
126                "Predicted that {} is equal or less than {}!",
127                input1, input2
128            );
129        }
130    }
131}
examples/adding.rs (line 29)
14fn main() {
15    let args: Vec<String> = env::args().collect();
16
17    if args.len() < 2 {
18        println!("Usage: '{} train' to train a new comparer.", args[0]);
19        println!("Usage: '{} evaluate serialized_genome.json input1 input2 input3 input4' to evaluate with an existing genome.", args[0]);
20        return;
21    }
22
23    if args[1] == "train" {
24        // One input node for each input in the TrainingData structure
25        let input_nodes = 4;
26        // One output node with the "prediction"
27        let output_nodes = 1;
28        // Create a new gene pool with an initial population of genomes
29        let mut gene_pool = Pool::with_defaults(input_nodes, output_nodes);
30
31        let training_data = load_training_data(TRAINING_DATA_STRING, 4, 1);
32
33        // These variables are used to keep track of the top performer, so we
34        // can write it out later.
35        let mut best_genome: Option<Genome> = None;
36        let mut best_fitness = 0.0;
37
38        // We will test genomes from 100 generations
39        for generation in 0..100 {
40            println!("Evaluating generation {}", generation + 1);
41            let total_species = gene_pool.len();
42            // As genomes diverge in structure and configuration, they will
43            // be divided into separate species.
44            for s in 0..total_species {
45                let species = &mut gene_pool[s];
46                let genomes_in_species = species.len();
47                for g in 0..genomes_in_species {
48                    let genome = &mut species[g];
49
50                    let mut fitness = 0.0;
51                    for td in &training_data {
52                        // Evaluate the genome using the training data as the
53                        // initial inputs.
54                        genome.evaluate(
55                            &td.inputs[0..4].to_vec(),
56                            Some(linear_activation),
57                            Some(linear_activation),
58                        );
59
60                        // We add this to the existing fitness for the genome
61                        // to ensure that the genomes with the best score across
62                        // all tests will have the highest overall fitness.
63                        fitness += adding_fitness_func(&genome.get_outputs(), &td.expected);
64                    }
65
66                    // Update the genome with the calculate fitness score.
67                    // (This is important, as this fitness score is needed to
68                    // spawn the next generation correctly.)
69                    genome.update_fitness(fitness);
70
71                    if fitness > best_fitness {
72                        println!(
73                            "Species {} Genome {} increased best fitness to {}",
74                            s, g, best_fitness
75                        );
76                        best_fitness = fitness;
77                        best_genome = Some(genome.clone());
78                    }
79                }
80            }
81            // Spawn the next generation.
82            gene_pool.new_generation();
83        }
84        println!("Serializing best genome to winner.json");
85        serde_json::to_writer(&File::create("winner.json").unwrap(), &best_genome.unwrap())
86            .unwrap();
87    } else {
88        if args.len() < 7 {
89            println!("Usage: '{} evaluate serialized_genome.json input1 input2 input3 input4' to evaluate with an existing genome.", args[0]);
90            return;
91        }
92        let mut genome: Genome = serde_json::from_reader(File::open(&args[2]).unwrap()).unwrap();
93        let input1 = args[3]
94            .parse::<f32>()
95            .expect("Couldn't parse input1 as f32");
96        let input2 = args[4]
97            .parse::<f32>()
98            .expect("Couldn't parse input2 as f32");
99        let input3 = args[5]
100            .parse::<f32>()
101            .expect("Couldn't parse input1 as f32");
102        let input4 = args[6]
103            .parse::<f32>()
104            .expect("Couldn't parse input2 as f32");
105        // Note that this is the exact same function we used in training
106        // further up!
107        genome.evaluate(
108            &vec![input1, input2, input3, input4],
109            Some(linear_activation),
110            Some(linear_activation),
111        );
112        println!(
113            "Sum of inputs is..........{}",
114            genome.get_outputs()[0] as u32
115        );
116    }
117}
Source

pub fn train_population( &mut self, generations: usize, training_data: &Vec<TrainingData>, evaluate_fn: EvaluationFn, hidden_activation: Option<ActivationFn>, output_activation: Option<ActivationFn>, )

Trains a population of Genomes over generations generations. training_data must be a &Vec of TrainingData. Each Genome will be gevn the inputs from each TrainingData as inputs to its network. evaluate_fn will be called after each item of TrainingData is fed to the Genome. This function will be passed a Vec of the Genome’s outputs and the expected value or values from the TrainingData. This function is expected to assess the Genome’s performance by comparing the two, and return an f32 representing its “score”. The scores from each call to evaluate_fn will be summed together to form the final fitness value of the Genome.

Source

pub fn stats(&self) -> PoolStats

Returns the PoolStats at a moment in time. (If you need updated statistics you must call this method each time you need them.)

Source

pub fn len(&self) -> usize

Returns the number of Species in the Pool.

Examples found in repository?
examples/compare.rs (line 64)
36fn main() {
37    let args: Vec<String> = env::args().collect();
38
39    if args.len() < 2 {
40        println!("Usage: '{} train' to train a new comparer.", args[0]);
41        println!("Usage: '{} evaluate serialized_genome.json input1 input2' to evaluate with an existing genome.", args[0]);
42        return;
43    }
44
45    if args[1] == "train" {
46        // One input node for each input in the TrainingData structure
47        let input_nodes = 2;
48        // One output node with the "prediction"
49        let output_nodes = 1;
50        // Create a new gene pool with an initial population of genomes
51        let mut gene_pool = Pool::with_defaults(input_nodes, output_nodes);
52
53        let training_data = load_training_data(TRAINING_DATA_STRING, 4, 1);
54
55        // These variables are used to keep track of the top performer, so we
56        // can write it out later.
57        let mut best_genome: Option<Genome> = None;
58        let mut best_fitness = 0.0;
59
60        // We use a label here to allow us to break out if we find a genome
61        // with a perfect score before we run through all of the generations.
62        'outer: for generation in 0..1000 {
63            println!("Evaluating generation {}", generation + 1);
64            let total_species = gene_pool.len();
65            for s in 0..total_species {
66                let species = &mut gene_pool[s];
67                let genomes_in_species = species.len();
68                for g in 0..genomes_in_species {
69                    let genome = &mut species[g];
70                    let mut fitness = 0.0;
71
72                    for td in &training_data {
73                        // Evaluate the genome using the training data as the
74                        // initial inputs.
75                        genome.evaluate(&td.inputs[0..2].to_vec(), None, None);
76
77                        // We add this to the existing fitness for the genome
78                        // to ensure that the genomes with the best score across
79                        // all tests will have the highest overall fitness.
80                        fitness += fitness_func(genome.get_outputs()[0], td.expected[0]);
81                    }
82
83                    // Update the genome with the calculate fitness score.
84                    // (This is important, as this fitness score is needed to
85                    // spawn the next generation correctly.)
86                    genome.update_fitness(fitness);
87
88                    if fitness > best_fitness {
89                        println!(
90                            "Species {} Genome {} increased best fitness to {}",
91                            s, g, best_fitness
92                        );
93                        best_fitness = fitness;
94                        best_genome = Some(genome.clone());
95                    }
96
97                    if fitness == PERFECT_SCORE {
98                        println!("Found a perfect genome!");
99                        break 'outer;
100                    }
101                }
102            }
103            // Spawn the next generation.
104            gene_pool.new_generation();
105        }
106        println!("Serializing best genome to winner.json");
107        serde_json::to_writer(&File::create("winner.json").unwrap(), &best_genome.unwrap())
108            .unwrap();
109    } else {
110        if args.len() < 5 {
111            println!("Usage: '{} evaluate serialized_genome.json input1 input2' to evaluate with an existing genome.", args[0]);
112            return;
113        }
114        let mut genome: Genome = serde_json::from_reader(File::open(&args[2]).unwrap()).unwrap();
115        let input1 = args[3]
116            .parse::<f32>()
117            .expect("Couldn't parse input1 as f32");
118        let input2 = args[4]
119            .parse::<f32>()
120            .expect("Couldn't parse input2 as f32");
121        genome.evaluate(&vec![input1, input2], None, None);
122        if genome.get_outputs()[0] > 0.5 {
123            println!("Predicted that {} is greater than {}!", input1, input2);
124        } else {
125            println!(
126                "Predicted that {} is equal or less than {}!",
127                input1, input2
128            );
129        }
130    }
131}
More examples
Hide additional examples
examples/adding.rs (line 41)
14fn main() {
15    let args: Vec<String> = env::args().collect();
16
17    if args.len() < 2 {
18        println!("Usage: '{} train' to train a new comparer.", args[0]);
19        println!("Usage: '{} evaluate serialized_genome.json input1 input2 input3 input4' to evaluate with an existing genome.", args[0]);
20        return;
21    }
22
23    if args[1] == "train" {
24        // One input node for each input in the TrainingData structure
25        let input_nodes = 4;
26        // One output node with the "prediction"
27        let output_nodes = 1;
28        // Create a new gene pool with an initial population of genomes
29        let mut gene_pool = Pool::with_defaults(input_nodes, output_nodes);
30
31        let training_data = load_training_data(TRAINING_DATA_STRING, 4, 1);
32
33        // These variables are used to keep track of the top performer, so we
34        // can write it out later.
35        let mut best_genome: Option<Genome> = None;
36        let mut best_fitness = 0.0;
37
38        // We will test genomes from 100 generations
39        for generation in 0..100 {
40            println!("Evaluating generation {}", generation + 1);
41            let total_species = gene_pool.len();
42            // As genomes diverge in structure and configuration, they will
43            // be divided into separate species.
44            for s in 0..total_species {
45                let species = &mut gene_pool[s];
46                let genomes_in_species = species.len();
47                for g in 0..genomes_in_species {
48                    let genome = &mut species[g];
49
50                    let mut fitness = 0.0;
51                    for td in &training_data {
52                        // Evaluate the genome using the training data as the
53                        // initial inputs.
54                        genome.evaluate(
55                            &td.inputs[0..4].to_vec(),
56                            Some(linear_activation),
57                            Some(linear_activation),
58                        );
59
60                        // We add this to the existing fitness for the genome
61                        // to ensure that the genomes with the best score across
62                        // all tests will have the highest overall fitness.
63                        fitness += adding_fitness_func(&genome.get_outputs(), &td.expected);
64                    }
65
66                    // Update the genome with the calculate fitness score.
67                    // (This is important, as this fitness score is needed to
68                    // spawn the next generation correctly.)
69                    genome.update_fitness(fitness);
70
71                    if fitness > best_fitness {
72                        println!(
73                            "Species {} Genome {} increased best fitness to {}",
74                            s, g, best_fitness
75                        );
76                        best_fitness = fitness;
77                        best_genome = Some(genome.clone());
78                    }
79                }
80            }
81            // Spawn the next generation.
82            gene_pool.new_generation();
83        }
84        println!("Serializing best genome to winner.json");
85        serde_json::to_writer(&File::create("winner.json").unwrap(), &best_genome.unwrap())
86            .unwrap();
87    } else {
88        if args.len() < 7 {
89            println!("Usage: '{} evaluate serialized_genome.json input1 input2 input3 input4' to evaluate with an existing genome.", args[0]);
90            return;
91        }
92        let mut genome: Genome = serde_json::from_reader(File::open(&args[2]).unwrap()).unwrap();
93        let input1 = args[3]
94            .parse::<f32>()
95            .expect("Couldn't parse input1 as f32");
96        let input2 = args[4]
97            .parse::<f32>()
98            .expect("Couldn't parse input2 as f32");
99        let input3 = args[5]
100            .parse::<f32>()
101            .expect("Couldn't parse input1 as f32");
102        let input4 = args[6]
103            .parse::<f32>()
104            .expect("Couldn't parse input2 as f32");
105        // Note that this is the exact same function we used in training
106        // further up!
107        genome.evaluate(
108            &vec![input1, input2, input3, input4],
109            Some(linear_activation),
110            Some(linear_activation),
111        );
112        println!(
113            "Sum of inputs is..........{}",
114            genome.get_outputs()[0] as u32
115        );
116    }
117}
Source

pub fn population_size(&self) -> usize

Returns the total number of Genomes in the Pool. Note that this should always be the same as the default population size, but this method will always return the real number of Genomes in the Pool.

Source

pub fn get_best_genome(&self) -> Genome

Returns the best Genome in the current population. (Earlier generations could theoretically have had a better Genome. If it is important to have the best Genome ever, you should call this method once per generation to check each generation’s best Genome.)

Examples found in repository?
examples/adding_managed.rs (line 44)
13fn main() {
14    let args: Vec<String> = env::args().collect();
15
16    if args.len() < 2 {
17        println!("Usage: '{} train' to train a new comparer.", args[0]);
18        println!("Usage: '{} evaluate serialized_genome.json input1 input2 input3 input4' to evaluate with an existing genome.", args[0]);
19        return;
20    }
21
22    if args[1] == "train" {
23        // One input node for each input in the training data structure
24        let input_nodes = 4;
25        // One output node with the "prediction"
26        let output_nodes = 1;
27        // Create a new gene pool with an initial population of genomes
28        let mut gene_pool = Pool::with_defaults(input_nodes, output_nodes);
29
30        let training_data = load_training_data(TRAINING_DATA_STRING, 4, 1);
31
32        let mut trainer = Trainer::new(training_data);
33        // This function will be called once per Genome per piece of
34        // TrainingData in each generation, passing the values of the
35        // output nodes of the Genome as well as the expected result
36        // from the TrainingData.
37        trainer.evaluate_fn = adding_fitness_func;
38        trainer.hidden_activation = linear_activation;
39        trainer.output_activation = linear_activation;
40
41        // Train over the course of 100 generations
42        trainer.train(&mut gene_pool, 100);
43
44        let best_genome = gene_pool.get_best_genome();
45
46        println!("Serializing best genome to winner.json");
47        serde_json::to_writer(&File::create("winner.json").unwrap(), &best_genome).unwrap();
48    } else {
49        if args.len() < 7 {
50            println!("Usage: '{} evaluate serialized_genome.json input1 input2 input3 input4' to evaluate with an existing genome.", args[0]);
51            return;
52        }
53        let mut genome: Genome = serde_json::from_reader(File::open(&args[2]).unwrap()).unwrap();
54        let input1 = args[3]
55            .parse::<f32>()
56            .expect("Couldn't parse input1 as f32");
57        let input2 = args[4]
58            .parse::<f32>()
59            .expect("Couldn't parse input2 as f32");
60        let input3 = args[5]
61            .parse::<f32>()
62            .expect("Couldn't parse input1 as f32");
63        let input4 = args[6]
64            .parse::<f32>()
65            .expect("Couldn't parse input2 as f32");
66        // Note that this is the exact same function we used in training
67        // further up!
68        genome.evaluate(
69            &vec![input1, input2, input3, input4],
70            Some(linear_activation),
71            Some(linear_activation),
72        );
73        println!(
74            "Sum of inputs is..........{}",
75            genome.get_outputs()[0] as u32
76        );
77    }
78}
Source

pub fn new_generation(&mut self)

Spawn the next generation of Genomes. This should only be done after you’ve assessed all Genomes in the current generation and updated their fitness scores. Calling this function will use the top performing existing Genomes as the basis of the next generation.

Examples found in repository?
examples/compare.rs (line 104)
36fn main() {
37    let args: Vec<String> = env::args().collect();
38
39    if args.len() < 2 {
40        println!("Usage: '{} train' to train a new comparer.", args[0]);
41        println!("Usage: '{} evaluate serialized_genome.json input1 input2' to evaluate with an existing genome.", args[0]);
42        return;
43    }
44
45    if args[1] == "train" {
46        // One input node for each input in the TrainingData structure
47        let input_nodes = 2;
48        // One output node with the "prediction"
49        let output_nodes = 1;
50        // Create a new gene pool with an initial population of genomes
51        let mut gene_pool = Pool::with_defaults(input_nodes, output_nodes);
52
53        let training_data = load_training_data(TRAINING_DATA_STRING, 4, 1);
54
55        // These variables are used to keep track of the top performer, so we
56        // can write it out later.
57        let mut best_genome: Option<Genome> = None;
58        let mut best_fitness = 0.0;
59
60        // We use a label here to allow us to break out if we find a genome
61        // with a perfect score before we run through all of the generations.
62        'outer: for generation in 0..1000 {
63            println!("Evaluating generation {}", generation + 1);
64            let total_species = gene_pool.len();
65            for s in 0..total_species {
66                let species = &mut gene_pool[s];
67                let genomes_in_species = species.len();
68                for g in 0..genomes_in_species {
69                    let genome = &mut species[g];
70                    let mut fitness = 0.0;
71
72                    for td in &training_data {
73                        // Evaluate the genome using the training data as the
74                        // initial inputs.
75                        genome.evaluate(&td.inputs[0..2].to_vec(), None, None);
76
77                        // We add this to the existing fitness for the genome
78                        // to ensure that the genomes with the best score across
79                        // all tests will have the highest overall fitness.
80                        fitness += fitness_func(genome.get_outputs()[0], td.expected[0]);
81                    }
82
83                    // Update the genome with the calculate fitness score.
84                    // (This is important, as this fitness score is needed to
85                    // spawn the next generation correctly.)
86                    genome.update_fitness(fitness);
87
88                    if fitness > best_fitness {
89                        println!(
90                            "Species {} Genome {} increased best fitness to {}",
91                            s, g, best_fitness
92                        );
93                        best_fitness = fitness;
94                        best_genome = Some(genome.clone());
95                    }
96
97                    if fitness == PERFECT_SCORE {
98                        println!("Found a perfect genome!");
99                        break 'outer;
100                    }
101                }
102            }
103            // Spawn the next generation.
104            gene_pool.new_generation();
105        }
106        println!("Serializing best genome to winner.json");
107        serde_json::to_writer(&File::create("winner.json").unwrap(), &best_genome.unwrap())
108            .unwrap();
109    } else {
110        if args.len() < 5 {
111            println!("Usage: '{} evaluate serialized_genome.json input1 input2' to evaluate with an existing genome.", args[0]);
112            return;
113        }
114        let mut genome: Genome = serde_json::from_reader(File::open(&args[2]).unwrap()).unwrap();
115        let input1 = args[3]
116            .parse::<f32>()
117            .expect("Couldn't parse input1 as f32");
118        let input2 = args[4]
119            .parse::<f32>()
120            .expect("Couldn't parse input2 as f32");
121        genome.evaluate(&vec![input1, input2], None, None);
122        if genome.get_outputs()[0] > 0.5 {
123            println!("Predicted that {} is greater than {}!", input1, input2);
124        } else {
125            println!(
126                "Predicted that {} is equal or less than {}!",
127                input1, input2
128            );
129        }
130    }
131}
More examples
Hide additional examples
examples/adding.rs (line 82)
14fn main() {
15    let args: Vec<String> = env::args().collect();
16
17    if args.len() < 2 {
18        println!("Usage: '{} train' to train a new comparer.", args[0]);
19        println!("Usage: '{} evaluate serialized_genome.json input1 input2 input3 input4' to evaluate with an existing genome.", args[0]);
20        return;
21    }
22
23    if args[1] == "train" {
24        // One input node for each input in the TrainingData structure
25        let input_nodes = 4;
26        // One output node with the "prediction"
27        let output_nodes = 1;
28        // Create a new gene pool with an initial population of genomes
29        let mut gene_pool = Pool::with_defaults(input_nodes, output_nodes);
30
31        let training_data = load_training_data(TRAINING_DATA_STRING, 4, 1);
32
33        // These variables are used to keep track of the top performer, so we
34        // can write it out later.
35        let mut best_genome: Option<Genome> = None;
36        let mut best_fitness = 0.0;
37
38        // We will test genomes from 100 generations
39        for generation in 0..100 {
40            println!("Evaluating generation {}", generation + 1);
41            let total_species = gene_pool.len();
42            // As genomes diverge in structure and configuration, they will
43            // be divided into separate species.
44            for s in 0..total_species {
45                let species = &mut gene_pool[s];
46                let genomes_in_species = species.len();
47                for g in 0..genomes_in_species {
48                    let genome = &mut species[g];
49
50                    let mut fitness = 0.0;
51                    for td in &training_data {
52                        // Evaluate the genome using the training data as the
53                        // initial inputs.
54                        genome.evaluate(
55                            &td.inputs[0..4].to_vec(),
56                            Some(linear_activation),
57                            Some(linear_activation),
58                        );
59
60                        // We add this to the existing fitness for the genome
61                        // to ensure that the genomes with the best score across
62                        // all tests will have the highest overall fitness.
63                        fitness += adding_fitness_func(&genome.get_outputs(), &td.expected);
64                    }
65
66                    // Update the genome with the calculate fitness score.
67                    // (This is important, as this fitness score is needed to
68                    // spawn the next generation correctly.)
69                    genome.update_fitness(fitness);
70
71                    if fitness > best_fitness {
72                        println!(
73                            "Species {} Genome {} increased best fitness to {}",
74                            s, g, best_fitness
75                        );
76                        best_fitness = fitness;
77                        best_genome = Some(genome.clone());
78                    }
79                }
80            }
81            // Spawn the next generation.
82            gene_pool.new_generation();
83        }
84        println!("Serializing best genome to winner.json");
85        serde_json::to_writer(&File::create("winner.json").unwrap(), &best_genome.unwrap())
86            .unwrap();
87    } else {
88        if args.len() < 7 {
89            println!("Usage: '{} evaluate serialized_genome.json input1 input2 input3 input4' to evaluate with an existing genome.", args[0]);
90            return;
91        }
92        let mut genome: Genome = serde_json::from_reader(File::open(&args[2]).unwrap()).unwrap();
93        let input1 = args[3]
94            .parse::<f32>()
95            .expect("Couldn't parse input1 as f32");
96        let input2 = args[4]
97            .parse::<f32>()
98            .expect("Couldn't parse input2 as f32");
99        let input3 = args[5]
100            .parse::<f32>()
101            .expect("Couldn't parse input1 as f32");
102        let input4 = args[6]
103            .parse::<f32>()
104            .expect("Couldn't parse input2 as f32");
105        // Note that this is the exact same function we used in training
106        // further up!
107        genome.evaluate(
108            &vec![input1, input2, input3, input4],
109            Some(linear_activation),
110            Some(linear_activation),
111        );
112        println!(
113            "Sum of inputs is..........{}",
114            genome.get_outputs()[0] as u32
115        );
116    }
117}

Trait Implementations§

Source§

impl Debug for Pool

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Index<usize> for Pool

Source§

type Output = Species

The returned type after indexing.
Source§

fn index(&self, index: usize) -> &Self::Output

Performs the indexing (container[index]) operation. Read more
Source§

impl IndexMut<usize> for Pool

Source§

fn index_mut(&mut self, index: usize) -> &mut Self::Output

Performs the mutable indexing (container[index]) operation. Read more

Auto Trait Implementations§

§

impl Freeze for Pool

§

impl RefUnwindSafe for Pool

§

impl Send for Pool

§

impl Sync for Pool

§

impl Unpin for Pool

§

impl UnwindSafe for Pool

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