pub(crate) mod path_reduction;
mod precision;
use crate::eval::{
machine::{Discretization, Hint, Machine},
profile::Execution,
tricks::slack_bits,
};
use path_reduction::{path_reduction, schedule_child};
use precision::{precision_tuning, update_repeats};
impl<D: Discretization> Machine<D> {
pub(crate) fn adjust(&mut self, hints: &[Hint]) -> bool {
assert_eq!(hints.len(), self.instructions.len(), "hint length mismatch");
if self.iteration == 0 {
return false;
}
backward_pass(self, hints)
}
pub(crate) fn make_hint(&self, old_hint: &[Hint]) -> (Vec<Hint>, bool) {
let len = self.instructions.len();
let mut hints = vec![Hint::Skip; len];
let mut converged = old_hint.len() == len;
for &root in &self.outputs {
if let Some(idx) = self.register_to_instruction(root) {
hints[idx] = Hint::Execute;
}
}
for idx in (0..len).rev() {
if matches!(hints[idx], Hint::Skip) {
continue;
}
if let Some(previous) = old_hint.get(idx) {
match previous {
Hint::KnownBool(val) => {
hints[idx] = Hint::KnownBool(*val);
continue;
}
Hint::Alias(pos) => {
if let Some(reg) = self.instructions[idx].data.input_at(*pos as usize) {
schedule_child(&mut hints, self, reg);
}
hints[idx] = Hint::Alias(*pos);
continue;
}
Hint::Execute | Hint::Skip => {}
}
} else {
converged = false;
}
let mut schedule = |reg: usize| schedule_child(&mut hints, self, reg);
let outcome = path_reduction(self, idx, &mut schedule);
converged = converged && outcome.converged;
hints[idx] = outcome.hint;
}
(hints, converged)
}
}
fn backward_pass<D: Discretization>(machine: &mut Machine<D>, hints: &[Hint]) -> bool {
let instruction_count = machine.instructions.len();
let profiling = machine.profiling_enabled;
let start_time = if profiling {
Some(std::time::Instant::now())
} else {
None
};
let first_tuning_pass = machine.iteration == 1;
let mut vprecs_max = vec![0u32; instruction_count];
let mut work_repeats = vec![true; instruction_count];
let slack = slack_bits(machine.iteration, machine.slack_unit);
for (&root, &boundary_issue) in machine.outputs.iter().zip(machine.output_distance.iter()) {
if boundary_issue && let Some(idx) = machine.register_to_instruction(root) {
vprecs_max[idx] = vprecs_max[idx].max(slack);
}
}
for &root in &machine.outputs {
if let Some(idx) = machine.register_to_instruction(root) {
work_repeats[idx] = false;
}
}
for idx in (0..instruction_count).rev() {
if work_repeats[idx] {
continue;
}
let reg = &machine.registers[machine.instruction_register(idx)];
if reg.lo.immovable && reg.hi.immovable {
work_repeats[idx] = true;
continue;
}
let var_count = machine.arguments.len();
let mut mark = |reg: usize| {
if reg >= var_count {
work_repeats[reg - var_count] = false;
}
};
path_reduction(machine, idx, &mut mark);
}
let mut vprecs_min = vec![0u32; instruction_count];
if precision_tuning(
machine,
hints,
&work_repeats,
&mut vprecs_max,
&mut vprecs_min,
) {
return true;
}
let mut any_reevaluation =
update_repeats(machine, &mut work_repeats, &vprecs_max, first_tuning_pass);
if !any_reevaluation {
machine.bumps = machine.bumps.saturating_add(1);
machine.bumps_activated = true;
vprecs_max.fill(0);
work_repeats.fill(false);
if precision_tuning(
machine,
hints,
&work_repeats,
&mut vprecs_max,
&mut vprecs_min,
) {
return true;
}
any_reevaluation =
update_repeats(machine, &mut work_repeats, &vprecs_max, first_tuning_pass);
if !any_reevaluation {
work_repeats.fill(true);
}
}
machine.repeats.copy_from_slice(&work_repeats);
machine.precisions.copy_from_slice(&vprecs_max);
if profiling && let Some(t0) = start_time {
let dt_ms = t0.elapsed().as_secs_f64() * 1000.0;
machine.profiler.record(Execution {
name: "adjust",
number: -1,
precision: (machine.iteration as u32) * 1000,
time_ms: dt_ms,
iteration: machine.iteration,
});
}
false
}