1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//! An implementation of NeuroEvolution of Augmenting Topologies,
//! following the 2002 paper: <http://nn.cs.utexas.edu/keyword?stanley:ec02>
//! 
//! It is designed to be highly-configurable, and supports population 
//! logging throughout the evolutionary process.
//! 
//! This crate was implemented as both a learning exercise in using Rust
//! and as a tool for my own experimentation. Critiques and contributions
//! are welcome.
//! 
//! # Usage example
//! The following is an implementation of the classic XOR problem:
//! 
//! ```
//! use oxineat::{
//!     PopulationConfig,
//!     GeneticConfig,
//!     genomes::{Genome, ActivationType},
//!     networks::Network,
//!     populations::Population,
//! };
//! use std::num::NonZeroUsize;
//! 
//! // Allowed error margin for neural net answers.
//! const ERROR_MARGIN: f32 = 0.3;
//! 
//! fn evaluate_xor(genome: &Genome) -> f32 {
//!     let mut network = Network::from(genome);
//!
//!     let values = [
//!         ([1.0, 0.0, 0.0], 0.0),
//!         ([1.0, 0.0, 1.0], 1.0),
//!         ([1.0, 1.0, 0.0], 1.0),
//!         ([1.0, 1.0, 1.0], 0.0),
//!     ];
//!
//!     let mut errors = [0.0, 0.0, 0.0, 0.0];
//!     for (i, (input, output)) in values.iter().enumerate() {
//!         network.clear_state();
//!         for _ in 0..3 {
//!             network.set_inputs(input);
//!             network.activate();
//!         }
//!         errors[i] = (network.outputs()[0] - output).abs();
//!         if errors[i] < ERROR_MARGIN {
//!             errors[i] = 0.0;
//!         }
//!     }
//!
//!     (4.0 - errors.iter().copied().sum::<f32>()).powf(2.0)
//! }
//!
//! fn main() {
//!     let genetic_config = GeneticConfig {
//!         input_count: NonZeroUsize::new(3).unwrap(),
//!         output_count: NonZeroUsize::new(1).unwrap(),
//!         activation_types: vec![ActivationType::Sigmoid],
//!         output_activation_types: vec![ActivationType::Sigmoid],
//!         mutate_only_chance: 0.25,
//!         mate_only_chance: 0.2,
//!         mate_by_averaging_chance: 0.4,
//!         suppression_reset_chance: 1.0,
//!         initial_expression_chance: 1.0,
//!         weight_bound: 5.0,
//!         weight_reset_chance: 0.2,
//!         weight_nudge_chance: 0.9,
//!         weight_mutation_power: 2.5,
//!         node_mutation_chance: 0.03,
//!         gene_mutation_chance: 0.05,
//!         max_gene_mutation_attempts: 20,
//!         recursion_chance: 0.0,
//!         excess_gene_factor: 1.0,
//!         disjoint_gene_factor: 1.0,
//!         common_weight_factor: 0.4,
//!     };
//!
//!     let population_config = PopulationConfig {
//!         population_size: NonZeroUsize::new(150).unwrap(),
//!         distance_threshold: 3.0,
//!         elitism: 1,
//!         survival_threshold: 0.2,
//!         adoption_rate: 1.0,
//!         interspecies_mating_chance: 0.001,
//!         stagnation_threshold: NonZeroUsize::new(15).unwrap(),
//!         stagnation_penalty: 1.0,
//!     };
//! 
//!     let mut population = Population::new(population_config, genetic_config);
//!     for _ in 0..100 {
//!         population.evaluate_fitness(evaluate_xor);
//!         if (population.champion().fitness() - 16.0).abs() < f32::EPSILON {
//!             println!("Solution found: {}", population.champion());
//!             break;
//!         }
//!         if let Err(e) = population.evolve() {
//!             eprintln!("{}", e);
//!             break;
//!         }
//!     }
//! }
//! ```

pub mod genomes;
pub mod networks;
pub mod populations;

pub use genomes::GeneticConfig;
pub use populations::PopulationConfig;

/// Identifier type used to designate historically
/// identical mutations for the purposes of
/// genome comparison and genetic tracking.
pub type Innovation = usize;