Browse Source

started genetic algorithm ops for image representation

main
Thomas Johnson 11 months ago
parent
commit
966556c599
  1. 4
      src/genetic.rs
  2. 2
      src/main.rs
  3. 77
      src/map.rs

4
src/genetic.rs

@ -9,10 +9,10 @@ pub struct Arena<T: Genetic> {
}
impl<T: Genetic> Arena<T> {
pub fn new(keep: usize, mutate: usize, crossover: usize, config: T::Configuration) -> Self {
pub fn new<R: Rng>(rng: &mut R, keep: usize, mutate: usize, crossover: usize, config: T::Configuration) -> Self {
let mut set = Vec::new();
for _ in 0..keep {
// set.push(T::generate(&config));
set.push(T::generate(rng, &config));
}
Arena {
keep,

2
src/main.rs

@ -22,7 +22,7 @@ fn main() {
let mut image_out: ImageBuffer<Rgb<f32>, Vec<f32>> = ImageBuffer::from_fn(dims.0, dims.1, |_, _| Rgb([0.0, 0.0, 0.0]));
let mut rng = rand::thread_rng();
let mut cfg = MapGeneticConfig {
let cfg = MapGeneticConfig {
dims,
initial_size: 50,
};

77
src/map.rs

@ -1,13 +1,15 @@
use crate::{transform::{Transform, NCOLORS}, genetic::Genetic};
use core::fmt::Debug;
use core::cell::Cell;
use rand::{Rng, distributions::{Uniform, WeightedIndex}};
use rand_distr::{Distribution};
use rand_distr::{Distribution, Bernoulli};
use image::{Rgb, GenericImage};
#[derive(Clone, Debug)]
pub struct Map
{
transforms: Vec<Transform>,
cached_cost: Cell<Option<f64>>,
}
impl Map {
@ -24,6 +26,14 @@ impl Map {
}
}
}
pub fn cost(&self) -> f64 {
if let Some(c) = self.cached_cost.get() {
c
} else {
unimplemented!();
}
}
}
#[derive(Debug)]
@ -41,28 +51,65 @@ impl Genetic for Map
cfg.create_map(rng, cfg.initial_size)
}
fn mutate<R: Rng>(&self, mut rng: &mut R, _cfg: &Self::Configuration) -> Self {
match WeightedIndex::new(&[1, 1, 1, 1]).unwrap().sample(&mut rng) {
fn mutate<R: Rng>(&self, mut rng: &mut R, cfg: &Self::Configuration) -> Self {
match WeightedIndex::new(&[1, 1, 1]).unwrap().sample(&mut rng) {
// four options are:
// - change a matrix
// - add element(s)
// - remove element(s)
// - change extents
// //- change extents
0 => {
let which = rng.gen_range(0..self.transforms.len());
let mut new_tfs = self.transforms.clone();
},
_ => unimplemented!()
let mut matrix_coeff_dist = Uniform::new(-1.0, 1.0).sample_iter(&mut rng);
for i in 0..NCOLORS * NCOLORS {
new_tfs[which].color_matrix[i] = matrix_coeff_dist.next().unwrap();
}
Map {
transforms: new_tfs,
cached_cost: Cell::new(None),
}
}
1 => {
let transform = cfg.random_transform(rng);
let mut new = self.clone();
new.transforms.push(transform);
new
}
2 => {
let which = rng.gen_range(0..self.transforms.len());
let mut new = self.clone();
new.transforms.swap_remove(which);
new
}
_ => { unreachable!() }
}
unimplemented!()
}
fn crossover<R: Rng>(&self, _rng: &mut R, _other: &Self, _config: &Self::Configuration) -> Self {
unimplemented!()
fn crossover<R: Rng>(&self, rng: &mut R, other: &Self, _config: &Self::Configuration) -> Self {
let mut new = self.clone();
new.transforms.extend_from_slice(&other.transforms);
// some paper that i read said this works correctly for selecting (in this
// case, removing) a number of randomly selected elements
let mut num_remaining = self.transforms.len() + other.transforms.len();
let mut num_to_remove = num_remaining / 2;
let mut idx = 0;
for _ in 0..num_remaining {
let distr = Bernoulli::new(num_to_remove as f64 / num_remaining as f64).unwrap();
if distr.sample(rng) {
new.transforms.swap_remove(idx);
num_remaining -= 1;
num_to_remove -= 1;
} else {
idx += 1;
num_remaining -= 1;
}
}
new
}
fn compare<R: Rng>(&self, _rng: &mut R, _other: &Self, _config: &Self::Configuration) -> std::cmp::Ordering {
unimplemented!()
fn compare<R: Rng>(&self, _rng: &mut R, other: &Self, _config: &Self::Configuration) -> std::cmp::Ordering {
self.cost().partial_cmp(&other.cost()).unwrap_or(std::cmp::Ordering::Equal)
}
}
@ -70,14 +117,15 @@ impl MapGeneticConfig {
pub fn create_map<R: Rng>(&self, rng: &mut R, tf_count: usize) -> Map {
let mut transforms = vec![];
for _ in 0..tf_count {
transforms.push(self.random_transform(rng, 1.0));
transforms.push(self.random_transform(rng));
}
Map {
transforms,
cached_cost: Cell::new(None),
}
}
pub fn random_transform<R: Rng>(&self, mut rng: &mut R, c: f32) -> Transform {
pub fn random_transform<R: Rng>(&self, mut rng: &mut R) -> Transform {
let rect_xs = loop {
let first = rng.gen_range(0..self.dims.0);
let second = first as i32 + rng.gen_range(-(self.dims.0 as i32)..=self.dims.0 as i32);
@ -109,8 +157,7 @@ impl MapGeneticConfig {
3 => ((cx + e2x, cy + e2y), [(-e2x, -e2y), (e1x, e1y)]),
_ => unreachable!(),
};
let color_matrix_bound = c;
let mut matrix_coeff_dist = Uniform::new(-color_matrix_bound, color_matrix_bound).sample_iter(rng);
let mut matrix_coeff_dist = Uniform::new(-1.0, 1.0).sample_iter(rng);
let mut color_matrix = [0.0f32; NCOLORS * NCOLORS];
for i in 0..NCOLORS * NCOLORS {
color_matrix[i] = matrix_coeff_dist.next().unwrap();

Loading…
Cancel
Save