entrenar/train/tui/
mod.rs1mod andon;
20mod buffer;
21mod callback;
22mod capability;
23mod charts;
24mod config;
25mod progress;
26mod reference;
27mod refresh;
28mod sparkline;
29
30pub use andon::{Alert, AlertLevel, AndonSystem};
32pub use buffer::MetricsBuffer;
33pub use callback::TerminalMonitorCallback;
34pub use capability::{DashboardLayout, TerminalCapabilities, TerminalMode};
35pub use charts::{
36 FeatureImportanceChart, GradientFlowHeatmap, LossCurveDisplay, SeriesSummaryTuple,
37};
38pub use config::MonitorConfig;
39pub use progress::{format_duration, KalmanEta, ProgressBar};
40pub use reference::ReferenceCurve;
41pub use refresh::RefreshPolicy;
42pub use sparkline::{sparkline, sparkline_range, SPARK_CHARS};
43
44#[cfg(test)]
49mod proptests {
50 use super::*;
51 use proptest::prelude::*;
52
53 proptest! {
54 #[test]
56 fn metrics_buffer_bounded(values in prop::collection::vec(-1000.0f32..1000.0, 0..1000)) {
57 let mut buf = MetricsBuffer::new(100);
58 for v in &values {
59 buf.push(*v);
60 }
61 prop_assert!(buf.len() <= buf.capacity());
62 }
63
64 #[test]
66 fn metrics_buffer_order(values in prop::collection::vec(0.0f32..1000.0, 1..100)) {
67 let mut buf = MetricsBuffer::new(values.len());
68 for v in &values {
69 buf.push(*v);
70 }
71 prop_assert_eq!(buf.values(), values);
72 }
73
74 #[test]
76 fn sparkline_length(
77 values in prop::collection::vec(-100.0f32..100.0, 1..100),
78 width in 1usize..50
79 ) {
80 let result = sparkline(&values, width);
81 let expected_len = values.len().min(width);
82 prop_assert_eq!(result.chars().count(), expected_len);
83 }
84
85 #[test]
87 fn sparkline_valid_chars(values in prop::collection::vec(-100.0f32..100.0, 1..100)) {
88 let result = sparkline(&values, values.len());
89 for c in result.chars() {
90 prop_assert!(SPARK_CHARS.contains(&c));
91 }
92 }
93
94 #[test]
96 fn progress_bar_bounded(current in 0usize..1000, total in 1usize..1000) {
97 let mut bar = ProgressBar::new(total, 20);
98 for _ in 0..current {
100 bar.update(current);
101 }
102 let pct = bar.percent();
103 prop_assert!(pct >= 0.0);
104 prop_assert!(pct <= 100.0 || current > total);
106 }
107
108 #[test]
110 fn kalman_eta_nonnegative(
111 durations in prop::collection::vec(0.001f64..10.0, 1..100),
112 remaining in 0usize..1000
113 ) {
114 let mut kalman = KalmanEta::new();
115 for d in durations {
116 kalman.update(d);
117 }
118 prop_assert!(kalman.eta_seconds(remaining) >= 0.0);
119 }
120
121 #[test]
123 fn andon_no_false_positive(values in prop::collection::vec(0.0f32..100.0, 1..100)) {
124 let mut andon = AndonSystem::new().with_stop_on_critical(false);
125 for v in values {
126 andon.check_loss(v);
127 }
128 prop_assert!(!andon.has_critical());
130 }
131 }
132}