solverforge_solver/
stats.rs1use std::time::{Duration, Instant};
7
8#[derive(Debug, Clone, Copy, Default)]
29pub struct SolverTelemetry {
30 pub elapsed_ms: u64,
31 pub step_count: u64,
32 pub moves_evaluated: u64,
33 pub moves_accepted: u64,
34 pub score_calculations: u64,
35 pub moves_per_second: u64,
36 pub acceptance_rate: f64,
37}
38
39#[derive(Debug, Default)]
40pub struct SolverStats {
41 start_time: Option<Instant>,
42 pub step_count: u64,
44 pub moves_evaluated: u64,
46 pub moves_accepted: u64,
48 pub score_calculations: u64,
50}
51
52impl SolverStats {
53 pub fn start(&mut self) {
55 self.start_time = Some(Instant::now());
56 }
57
58 pub fn elapsed(&self) -> Duration {
59 self.start_time.map(|t| t.elapsed()).unwrap_or_default()
60 }
61
62 pub fn record_move(&mut self, accepted: bool) {
64 self.moves_evaluated += 1;
65 if accepted {
66 self.moves_accepted += 1;
67 }
68 }
69
70 pub fn record_step(&mut self) {
72 self.step_count += 1;
73 }
74
75 pub fn record_score_calculation(&mut self) {
77 self.score_calculations += 1;
78 }
79
80 pub fn moves_per_second(&self) -> f64 {
81 let secs = self.elapsed().as_secs_f64();
82 if secs > 0.0 {
83 self.moves_evaluated as f64 / secs
84 } else {
85 0.0
86 }
87 }
88
89 pub fn acceptance_rate(&self) -> f64 {
90 if self.moves_evaluated == 0 {
91 0.0
92 } else {
93 self.moves_accepted as f64 / self.moves_evaluated as f64
94 }
95 }
96
97 pub fn snapshot(&self) -> SolverTelemetry {
98 SolverTelemetry {
99 elapsed_ms: self.elapsed().as_millis() as u64,
100 step_count: self.step_count,
101 moves_evaluated: self.moves_evaluated,
102 moves_accepted: self.moves_accepted,
103 score_calculations: self.score_calculations,
104 moves_per_second: self.moves_per_second() as u64,
105 acceptance_rate: self.acceptance_rate(),
106 }
107 }
108}
109
110#[derive(Debug)]
130pub struct PhaseStats {
131 pub phase_index: usize,
133 pub phase_type: &'static str,
135 start_time: Instant,
136 pub step_count: u64,
138 pub moves_evaluated: u64,
140 pub moves_accepted: u64,
142}
143
144impl PhaseStats {
145 pub fn new(phase_index: usize, phase_type: &'static str) -> Self {
147 Self {
148 phase_index,
149 phase_type,
150 start_time: Instant::now(),
151 step_count: 0,
152 moves_evaluated: 0,
153 moves_accepted: 0,
154 }
155 }
156
157 pub fn elapsed(&self) -> Duration {
158 self.start_time.elapsed()
159 }
160
161 pub fn elapsed_ms(&self) -> u64 {
162 self.start_time.elapsed().as_millis() as u64
163 }
164
165 pub fn record_step(&mut self) {
167 self.step_count += 1;
168 }
169
170 pub fn record_move(&mut self, accepted: bool) {
172 self.moves_evaluated += 1;
173 if accepted {
174 self.moves_accepted += 1;
175 }
176 }
177
178 pub fn moves_per_second(&self) -> u64 {
179 let secs = self.elapsed().as_secs_f64();
180 if secs > 0.0 {
181 (self.moves_evaluated as f64 / secs) as u64
182 } else {
183 0
184 }
185 }
186
187 pub fn acceptance_rate(&self) -> f64 {
188 if self.moves_evaluated == 0 {
189 0.0
190 } else {
191 self.moves_accepted as f64 / self.moves_evaluated as f64
192 }
193 }
194}