65 lines
2.5 KiB
Rust
65 lines
2.5 KiB
Rust
use rand::Rng;
|
|
use crate::compiler::ast::{UntypedAst, OpCode};
|
|
use crate::gp::generate::{random_ast, random_opcode};
|
|
|
|
/// Returns a new `UntypedAst` that is a mutated version of `original`.
|
|
/// We do not modify `original`; we clone or build new pieces as needed.
|
|
///
|
|
/// - `depth`: current depth of this node,
|
|
/// - `max_depth`: max allowed depth (to prevent infinite recursion).
|
|
pub fn mutated_ast(original: &UntypedAst, rng: &mut impl Rng, depth: usize, max_depth: usize) -> UntypedAst {
|
|
// 10% chance: completely replace this node with a fresh random subtree
|
|
if rng.gen_range(0..100) < 10 {
|
|
return random_ast(rng, depth, max_depth);
|
|
}
|
|
|
|
match original {
|
|
UntypedAst::IntLiteral(val) => {
|
|
// Another small chance to replace the entire node with random subtree
|
|
if rng.gen_range(0..100) < 10 {
|
|
return random_ast(rng, depth, max_depth);
|
|
}
|
|
|
|
// Otherwise, "tweak" the int by a small offset
|
|
let delta = rng.gen_range(-2..=2);
|
|
let new_val = val.saturating_add(delta);
|
|
UntypedAst::IntLiteral(new_val)
|
|
}
|
|
UntypedAst::Instruction(op) => {
|
|
// 10% chance to replace node
|
|
if rng.gen_range(0..100) < 10 {
|
|
return random_ast(rng, depth, max_depth);
|
|
}
|
|
|
|
// 50% chance to pick a new opcode
|
|
// or else keep the same
|
|
if rng.gen_bool(0.5) {
|
|
UntypedAst::Instruction(random_opcode(rng))
|
|
} else {
|
|
// Just clone the original
|
|
UntypedAst::Instruction(op.clone())
|
|
}
|
|
}
|
|
UntypedAst::Sublist(children) => {
|
|
// 10% chance to replace this sublist entirely
|
|
if rng.gen_range(0..100) < 10 {
|
|
return random_ast(rng, depth, max_depth);
|
|
}
|
|
|
|
// Otherwise, mutate zero or more children
|
|
let mut new_children = children.clone();
|
|
if !new_children.is_empty() {
|
|
// Choose how many kids to mutate:
|
|
// e.g., 1..=min(2, children.len())
|
|
let mut_count = rng.gen_range(1..=new_children.len().min(2));
|
|
|
|
for _ in 0..mut_count {
|
|
let idx = rng.gen_range(0..new_children.len());
|
|
new_children[idx] = mutated_ast(&new_children[idx], rng, depth+1, max_depth);
|
|
}
|
|
}
|
|
UntypedAst::Sublist(new_children)
|
|
}
|
|
}
|
|
}
|