pub fn apply_scoped_mutation<PT: ProtocolTypes, R: Rand>(
trace: &mut Trace<PT>,
to_mutate_path: &TracePath,
representative: &Term<PT>,
new_term: &Term<PT>,
config: &MutationConfig,
rand: &mut R,
) -> MutationResultExpand description
Apply new_term in place of the term at to_mutate_path, generalising the replacement to
structurally equal terms according to a randomly drawn MutationScope.
This is the shared engine behind the replacement DY mutators (generate / replace-match /
replace-reuse): they all have the shape “pick a sub-term, compute a replacement for it, write it
back”, so broadcasting that replacement to the other occurrences of the same term is
well-defined. Doing so collapses the cost of goals that require the same edit in several places
(e.g. turning every fn_seq_2 of one action into fn_seq_5) from one lucky draw per
occurrence down to one lucky draw per distinct sub-term.
The generalisation is deliberately performed without any term constraint: skipping a large recipe here would silently turn “replace all occurrences” into a partial replacement, which is precisely what a broader scope is meant to avoid; and the cost stays linear in the size of the trace, i.e. the same order as the selection pass that already ran.
The chosen occurrence is always part of the targets, so that a broader scope is a strict
superset of MutationScope::Individual whatever the search returns.