https://github.com/jeffail/spiril
Rust library for genetic algorithms
https://github.com/jeffail/spiril
evolutionary genetic rust
Last synced: about 1 month ago
JSON representation
Rust library for genetic algorithms
- Host: GitHub
- URL: https://github.com/jeffail/spiril
- Owner: Jeffail
- License: mit
- Created: 2017-12-10T10:44:18.000Z (almost 8 years ago)
- Default Branch: master
- Last Pushed: 2018-05-16T08:32:42.000Z (over 7 years ago)
- Last Synced: 2025-04-11T04:35:00.188Z (6 months ago)
- Topics: evolutionary, genetic, rust
- Language: Rust
- Size: 11.7 KB
- Stars: 29
- Watchers: 2
- Forks: 2
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
Spiril
======Spiril is an implementation of a genetic algorithm for obtaining optimum
variables (genetics) for a task through mutation and natural selection.The API allows you to specify an initial group of units, which will act as
the original parents of all subsequent units. Unit types implement a fitness
function and a breed function for introducing new genetic combinations and
mutations into subsequent generations.Fitnesses can be calculated across a population using parallel threads.
## Sudoku example
``` rust
extern crate spiril;
extern crate rand;use spiril::unit::Unit;
use spiril::population::Population;
use rand::{StdRng, SeedableRng, Rng};struct SudokuUnit {
sudoku: Vec, // 9x9 grid
answer: Vec, // 9x9 grid
}impl Unit for SudokuUnit {
fn fitness(&self) -> f64 {
let mut score = 1.0_f64;for i in 0..9 {
let mut seen_row: [usize; 9] = [0, 0, 0, 0, 0, 0, 0, 0, 0];
let mut seen_col: [usize; 9] = [0, 0, 0, 0, 0, 0, 0, 0, 0];
let mut seen_sqr: [usize; 9] = [0, 0, 0, 0, 0, 0, 0, 0, 0];for j in 0..9 {
seen_row[self.answer[i * 9 + j] - 1] += 1;
seen_col[self.answer[i + 9 * j] - 1] += 1;let sqr_index = ((i % 3) * 3) + (((i / 3) % 3) * 27) + (9 * (j / 3)) + j % 3;
seen_sqr[self.answer[sqr_index] - 1] += 1;
}seen_row
.iter()
.chain(seen_col.iter())
.chain(seen_sqr.iter())
.map(|x| if *x == 0 {
// score -= (1.0 / 729.0);
score *= 0.9;
})
.last();
}score
}fn breed_with(&self, other: &SudokuUnit) -> SudokuUnit {
// Even rows taken from self, odd rows taken from other.
// Mutations applied at random.
let mut new_unit: SudokuUnit = SudokuUnit {
sudoku: self.sudoku.clone(),
answer: self.answer.clone(),
};(0_usize..81_usize)
.filter(|x| self.sudoku[*x] == 0)
.map(|x| {
if rand::thread_rng().gen_range(0, 1) == 1 {
new_unit.answer[x] = other.answer[x];
}
new_unit.answer[x]
})
.last();loop {
let i = rand::thread_rng().gen_range(0, 81);
if self.sudoku[i] == 0 {
new_unit.answer[i] = rand::thread_rng().gen_range(1, 10);
break;
}
}new_unit
}
}fn main() {
let test_doku: Vec = vec![
7, 2, 6, 0, 9, 3, 8, 1, 5,
3, 0, 5, 7, 2, 8, 9, 0, 6,
4, 8, 0, 6, 0, 1, 2, 3, 7,8, 5, 2, 1, 4, 0, 6, 9, 3,
0, 7, 3, 9, 8, 5, 1, 2, 4,
9, 4, 1, 0, 6, 2, 0, 5, 8,1, 9, 0, 8, 3, 0, 5, 7, 2,
5, 6, 7, 2, 1, 4, 3, 8, 0,
2, 0, 8, 5, 0, 9, 4, 6, 1,
];let seed: &[_] = &[0];
let mut init_rng: StdRng = SeedableRng::from_seed(seed);
let units: Vec = (0..1000)
.map(|_| {
SudokuUnit {
sudoku: test_doku.clone(),
answer: test_doku
.clone()
.iter()
.map(|x| if *x == 0 {
init_rng.gen_range(1, 10)
} else {
*x
})
.collect(),
}
})
.collect();assert_eq!(Population::new(units)
.set_size(1000)
.set_breed_factor(0.3)
.set_survival_factor(0.5)
.epochs_parallel(5000, 4) // 4 CPU cores
.finish()
.first()
.unwrap()
.fitness(), 1.0);
}
```