solverforge_solver/
stats.rs1use std::time::{Duration, Instant};
7
8#[derive(Debug, Default)]
29pub struct SolverStats {
30 start_time: Option<Instant>,
31 pub step_count: u64,
33 pub moves_evaluated: u64,
35 pub moves_accepted: u64,
37 pub score_calculations: u64,
39}
40
41impl SolverStats {
42 pub fn start(&mut self) {
44 self.start_time = Some(Instant::now());
45 }
46
47 pub fn elapsed(&self) -> Duration {
48 self.start_time.map(|t| t.elapsed()).unwrap_or_default()
49 }
50
51 pub fn record_move(&mut self, accepted: bool) {
53 self.moves_evaluated += 1;
54 if accepted {
55 self.moves_accepted += 1;
56 }
57 }
58
59 pub fn record_step(&mut self) {
61 self.step_count += 1;
62 }
63
64 pub fn record_score_calculation(&mut self) {
66 self.score_calculations += 1;
67 }
68
69 pub fn moves_per_second(&self) -> f64 {
70 let secs = self.elapsed().as_secs_f64();
71 if secs > 0.0 {
72 self.moves_evaluated as f64 / secs
73 } else {
74 0.0
75 }
76 }
77
78 pub fn acceptance_rate(&self) -> f64 {
79 if self.moves_evaluated == 0 {
80 0.0
81 } else {
82 self.moves_accepted as f64 / self.moves_evaluated as f64
83 }
84 }
85}
86
87#[derive(Debug)]
107pub struct PhaseStats {
108 pub phase_index: usize,
110 pub phase_type: &'static str,
112 start_time: Instant,
113 pub step_count: u64,
115 pub moves_evaluated: u64,
117 pub moves_accepted: u64,
119}
120
121impl PhaseStats {
122 pub fn new(phase_index: usize, phase_type: &'static str) -> Self {
124 Self {
125 phase_index,
126 phase_type,
127 start_time: Instant::now(),
128 step_count: 0,
129 moves_evaluated: 0,
130 moves_accepted: 0,
131 }
132 }
133
134 pub fn elapsed(&self) -> Duration {
135 self.start_time.elapsed()
136 }
137
138 pub fn elapsed_ms(&self) -> u64 {
139 self.start_time.elapsed().as_millis() as u64
140 }
141
142 pub fn record_step(&mut self) {
144 self.step_count += 1;
145 }
146
147 pub fn record_move(&mut self, accepted: bool) {
149 self.moves_evaluated += 1;
150 if accepted {
151 self.moves_accepted += 1;
152 }
153 }
154
155 pub fn moves_per_second(&self) -> u64 {
156 let secs = self.elapsed().as_secs_f64();
157 if secs > 0.0 {
158 (self.moves_evaluated as f64 / secs) as u64
159 } else {
160 0
161 }
162 }
163
164 pub fn acceptance_rate(&self) -> f64 {
165 if self.moves_evaluated == 0 {
166 0.0
167 } else {
168 self.moves_accepted as f64 / self.moves_evaluated as f64
169 }
170 }
171}