This library allows you to write evolutionary algorithms (EA) using the Rust programming language.
Written by Willi Kappler, License: MIT - Version 0.2 (2016.08.17)
Documentation: darwin-rs
The example folder contains three examples:
darwin-rs uses semantic versioning
Add the following to the Cargo.toml in your project:
toml
[dependencies]
darwin-rs = "0.2"
And this in the rust source code of your application:
```rust extern crate darwin_rs;
use darwin_rs::{Individual, SimulationBuilder, PopulationBuilder, SimError}; ```
Basically you have to implement the trait Individual
for your data structure:
```rust
struct MyStruct { text: String }
impl Individual for MyStruct { fn new() -> MyStruct { MyStruct{ text: "Some fancy data values...".to_string() } }
fn mutate(&mut self) {
// Mutate the struct here.
}
fn calculate_fitness(&self) -> f64 {
// Calculate how good the data values are compared to the perfect solution
0.0
}
} ```
These three methods are needed:
new(): creates new instance of your struct.
mutate(&mut self): mutates the content of the struct.
calculate_fitness(&self) -> f64: this calculates the fitness value, that is how close is this individual struct instance to the perfect solution ? Lower values means better fit (or less error).
Tip: Use lazy_static to share large data structure between individuals (see TSP example).
Now you have to create one or more populations that can have different properties:
```rust
let population1 = PopulationBuilder::
let population2 = PopulationBuilder::
``` set_id(): Sets the population ID. This can be any positive u32 integer. Currently this is only used for internal statistics, for example: which population does have the most fittest individuals ? This may help you to set the correct parameters for your simulations.
individuals(): How many individuals (= distinct copies of your data structure) should the population have ?
increasingexpmutation_rate(): Sets the mutation rate for each individual: Use exponential mutation rate.
resetlimitincrement(): Increase the reset limit by this amount every time the iteration counter reaches the limit
resetlimitstart(): The start value of the reset limit.
resetlimitend(): The end value of the reset limit. If this end value is reached the reset limit is reset to the start value above.
After that you have to create a new instance of the simulation and provide the settings:
```rust
let mybuilder = SimulationBuilder::
match my_builder {
Err(SimError::EndIterationTooLow) => println!("more than 10 iteratons needed"),
Ok(mut my_simulation) => {
my_simulation.run();
println!("total run time: {} ms", my_simulation.total_time_in_ms);
println!("improvement factor: {}", my_simulation.simulation_result.improvement_factor);
println!("number of iterations: {}", my_simulation.simulation_result.iteration_counter);
my_simulation.print_fitness();
}
}
```
factor(): Sets the termination condition: if the improvement factor is better or equal to this value, the simulation stops.
threads(): Number of threads to use for the simulation.
add_population(): This adds the previously created population to the simulation.
finalize(): Finish setup and do sanity check. Returns Ok(Simulation)
if there are no errors in the configuration.
Then just do a match on the result of finalize()
and call simulation.run()
to start the simulation. After the finishing it, you can access some statistics (total_time_in_ms
, improvement_factor
, iteration_counter
) and the populations of course:
rust
for population in my_simulation.habitat {
for wrapper in population.population {...}
}
Each individual is wrapped inside a Wrapper
struct that contains additional information needed for the simulation: fitness and the number of mutations.
See also the example folder for full working programs.
TODO: - [ ] Add more documentation comments for library - [ ] Add test cases - [ ] Add more examples (ocr, ...) - [x] Split up code - [x] Allow user to specify start and end of reset limit - [ ] Use log file instead of println!() - [x] Use multiple population - [ ] Maybe use phantom type for builder pattern to detect configuration error at compile type ? (https://www.reddit.com/r/rust/comments/2pgrz7/requiredparametersutilizingthebuilder_pattern/) - [ ] Add super optimization (only allow changes that have an improvement) ? - [ ] Add possibility to load and save population / individuals in order to cancel / resume simulation (serde)
Any feedback is welcome!