use melvm::{opcode::OpCode, Covenant}; use once_cell::sync::Lazy; use ordered_float::OrderedFloat; use quanta::Clock; use rayon::iter::{IntoParallelRefMutIterator, ParallelIterator}; type OF64 = OrderedFloat; static CLOCK: Lazy = Lazy::new(Clock::new); /// Computes the fitness of the input fn eval_fitness(input: &[u8]) -> OF64 { let val = if let Ok(cov) = Covenant::from_bytes(input) { cov } else { return 0.0.into(); }; let mut runtime = f64::MAX; for _ in 0..10 { let start = CLOCK.start(); val.debug_execute(&[]); runtime = runtime.min((CLOCK.end() - start) as f64); } if val.to_ops().iter().any(|f| matches!(f, OpCode::Noop)) { return 0.0.into(); }; let _weight = val.weight() as f64; let ilen = input.len() as f64; if ilen == 0.0 { return 0.0.into(); } (runtime / ilen).into() } /// Maybe mutate the input fn mutate(input: &mut Vec) { while rand::random::() < 0.9 && !input.is_empty() { let i = rand::random::() % input.len(); // either mutate or indel if rand::random() { input.insert(i, rand::random()); } else { input.remove(i); } } } fn main() { let mut population: Vec<(Vec, OrderedFloat)> = (0..2048) .map(|_| loop { let r: u64 = rand::random(); let v = r.to_le_bytes().to_vec(); let fitness = eval_fitness(&v); if fitness > 0.0.into() { return (v, fitness); } }) .collect(); println!("generation,fitness"); for generation in 0.. { population.sort_unstable_by_key(|f| f.1); if generation % 100 == 0 { eprintln!( "GENERATION {}; MAX FITNESS {} LEN {}", generation, population.last().unwrap().1, population.last().unwrap().0.len() ); if population.last().unwrap().1 > 0.0.into() { let ops = Covenant::from_bytes(&population.last().unwrap().0.clone()) .unwrap() .to_ops(); eprintln!("{:?}", ops); } } if generation % 10 == 0 { println!("{},{}", generation, population.last().unwrap().1); } for i in 0..population.len() / 2 { population[i] = population[population.len() / 2 + i].clone(); } let halflen = population.len() / 2; population[..halflen].par_iter_mut().for_each(|elem| { mutate(&mut elem.0); // elem.1 = eval_fitness(&elem.0) }); population .iter_mut() .for_each(|elem| elem.1 = eval_fitness(&elem.0)); } }