use crate::native::bignum::BigUint;
use crate::native::core::ChoiceValue;
use super::Shrinker;
const RANDOM_ATTEMPTS: u64 = 3;
const MAX_MUTATE_NODES: usize = 32;
impl<'a> Shrinker<'a> {
pub(super) fn mutate_and_shrink(&mut self) {
if self.current_nodes.len() > MAX_MUTATE_NODES {
return;
}
let mut i = 0;
while i < self.current_nodes.len() {
let node = self.current_nodes[i].clone();
let kind = node.kind.clone();
let current_idx = kind.to_index(&node.value);
let mut candidates: Vec<ChoiceValue> = Vec::new();
for delta in 1u32..=5 {
for &sign in &[1i32, -1] {
let new_idx_opt = index_offset(¤t_idx, delta, sign);
let Some(new_idx) = new_idx_opt else {
continue;
};
if let Some(v) = kind.from_index(new_idx) {
if v != node.value && !candidates.contains(&v) {
candidates.push(v);
}
}
}
}
for new_val in &candidates {
let prefix: Vec<ChoiceValue> = self.current_nodes[..i]
.iter()
.map(|n| n.value.clone())
.chain(std::iter::once(new_val.clone()))
.collect();
let max_size = self.current_nodes.len();
self.probe(&prefix, 0, max_size);
for attempt in 0..RANDOM_ATTEMPTS {
let seed = (i as u64).wrapping_mul(1000).wrapping_add(attempt);
self.probe(&prefix, seed, max_size);
}
let mut j_offset: usize = 1;
while j_offset < 3 && i + j_offset < self.current_nodes.len() {
let j = i + j_offset;
j_offset += 1;
let kind_j = self.current_nodes[j].kind.clone();
let Some(unit_val) = kind_j.from_index(BigUint::from(1u32)) else {
continue;
};
let mut two_prefix = prefix.clone();
for k in (i + 1)..=j {
if k == j {
two_prefix.push(unit_val.clone());
} else {
two_prefix.push(self.current_nodes[k].kind.simplest());
}
}
for attempt in 0..RANDOM_ATTEMPTS {
let seed = (i as u64)
.wrapping_mul(1000)
.wrapping_add((j_offset as u64).wrapping_mul(100))
.wrapping_add(attempt);
self.probe(&two_prefix, seed, max_size);
}
}
}
i += 1;
}
}
}
fn index_offset(current_idx: &BigUint, delta: u32, sign: i32) -> Option<BigUint> {
let delta_big = BigUint::from(delta);
if sign >= 0 {
Some(current_idx + delta_big)
} else if current_idx < &delta_big {
None
} else {
Some(current_idx - delta_big)
}
}