use super::chromosome::GpChromosome;
use super::node::{grow_tree, GpNode, Node};
use rand::Rng;
pub(crate) fn full_tree<N: GpNode>(max_depth: usize, rng: &mut impl Rng) -> Node<N> {
if max_depth <= 1 {
return Node::Terminal(N::sample_random_terminal(rng));
}
let functions = N::all_functions();
if functions.is_empty() {
return Node::Terminal(N::sample_random_terminal(rng));
}
let idx = rng.random_range(0..functions.len());
let f = functions[idx].clone();
let arity = f.arity();
let children: Vec<Box<Node<N>>> = (0..arity)
.map(|_| Box::new(full_tree::<N>(max_depth - 1, rng)))
.collect();
Node::Function { value: f, children }
}
pub fn ramped_half_and_half<N: GpNode + Default>(
pop_size: usize,
init_max_depth: usize,
rng: &mut impl Rng,
) -> Vec<GpChromosome<N>> {
let depth_range = 2..=init_max_depth.max(2);
let num_depths = depth_range.clone().count().max(1);
let per_depth = (pop_size / num_depths).max(1);
let mut pop: Vec<GpChromosome<N>> = Vec::with_capacity(pop_size);
'outer: for d in depth_range {
for i in 0..per_depth {
if pop.len() >= pop_size {
break 'outer;
}
let root = if i % 2 == 0 {
full_tree::<N>(d, rng)
} else {
grow_tree::<N>(d, rng)
};
pop.push(GpChromosome::with_root(Box::new(root)));
}
}
while pop.len() < pop_size {
let root = grow_tree::<N>(init_max_depth.max(2), rng);
pop.push(GpChromosome::with_root(Box::new(root)));
}
pop
}