pub( crate ) fn approximate_utilization(
measurements : &[ ( u64, f64 ) ],
resets_at_secs : Option< u64 >,
window_duration_s : u64,
now_secs : u64,
) -> Option< f64 >
{
if let Some( r ) = resets_at_secs
{
if now_secs > r { return Some( 0.0 ); }
}
let window_start = resets_at_secs.map( |r| r.saturating_sub( window_duration_s ) );
let pts : Vec< ( u64, f64 ) > = measurements.iter()
.filter( |( t, _ )| window_start.map_or( true, |ws| *t >= ws ) )
.copied()
.collect();
match pts.len()
{
0 => None,
1 => Some( pts[ 0 ].1.clamp( 0.0, 100.0 ) ),
2 => Some( linear_extrapolate( &pts, now_secs ) ),
_ => Some( quadratic_fit( &pts, now_secs ) ),
}
}
#[ allow( dead_code ) ]
fn linear_extrapolate( pts : &[ ( u64, f64 ) ], now_secs : u64 ) -> f64
{
let t0 = pts[ 0 ].0;
let dt = pts[ 1 ].0.saturating_sub( t0 ) as f64;
let t_now = now_secs.saturating_sub( t0 ) as f64;
if dt.abs() < 1e-12
{
return pts.last().map_or( 0.0, |p| p.1 ).clamp( 0.0, 100.0 );
}
let slope = ( pts[ 1 ].1 - pts[ 0 ].1 ) / dt;
let y = pts[ 0 ].1 + slope * t_now;
y.clamp( 0.0, 100.0 )
}
#[ allow( dead_code ) ]
fn quadratic_fit( pts : &[ ( u64, f64 ) ], now_secs : u64 ) -> f64
{
let t0 = pts[ 0 ].0;
let t_now_f = now_secs.saturating_sub( t0 ) as f64;
let n = pts.len() as f64;
let mut s1 = 0_f64; let mut s2 = 0_f64; let mut s3 = 0_f64; let mut s4 = 0_f64; let mut r0 = 0_f64; let mut r1 = 0_f64; let mut r2 = 0_f64; let mut t_max = 0_f64;
let mut t_min = 0_f64;
for ( i, &( t, y ) ) in pts.iter().enumerate()
{
let ti = t.saturating_sub( t0 ) as f64;
let ti2 = ti * ti;
s1 += ti;
s2 += ti2;
s3 += ti2 * ti;
s4 += ti2 * ti2;
r0 += y;
r1 += ti * y;
r2 += ti2 * y;
if i == 0 { t_min = ti; t_max = ti; }
else
{
if ti > t_max { t_max = ti; }
if ti < t_min { t_min = ti; }
}
}
let det = s4 * ( s2 * n - s1 * s1 ) - s3 * ( s3 * n - s1 * s2 ) + s2 * ( s3 * s1 - s2 * s2 );
let ( a2, a1, a0 ) = if det.abs() < 1e-12
{
let first = pts[ 0 ];
let last = pts[ pts.len() - 1 ];
let fallback_pts = [ first, last ];
let y = linear_extrapolate( &fallback_pts, now_secs );
return y;
}
else
{
let det2 = r2 * ( s2 * n - s1 * s1 ) - s3 * ( r1 * n - s1 * r0 ) + s2 * ( r1 * s1 - s2 * r0 );
let det1 = s4 * ( r1 * n - s1 * r0 ) - r2 * ( s3 * n - s1 * s2 ) + s2 * ( s3 * r0 - s2 * r1 );
let det0 = s4 * ( s2 * r0 - s1 * r1 ) - s3 * ( s3 * r0 - s2 * r1 ) + r2 * ( s3 * s1 - s2 * s2 );
( det2 / det, det1 / det, det0 / det )
};
let span = t_max - t_min;
let y = if span > 0.0 && ( t_now_f - t_max ) > 2.0 * span
{
let slope = 2.0 * a2 * t_max + a1;
let y_at_max = a2 * t_max * t_max + a1 * t_max + a0;
y_at_max + slope * ( t_now_f - t_max )
}
else
{
a2 * t_now_f * t_now_f + a1 * t_now_f + a0
};
y.clamp( 0.0, 100.0 )
}
#[ cfg( test ) ]
mod tests
{
use super::approximate_utilization;
#[ test ]
fn approx_quadratic_three_points_extrapolates()
{
let pts : &[ ( u64, f64 ) ] = &[ ( 0, 10.0 ), ( 60, 20.0 ), ( 120, 35.0 ) ];
let result = approximate_utilization( pts, None, 18000, 180 );
let v = result.expect( "FT-04: 3 non-collinear points must return Some" );
assert!(
v > 35.0,
"FT-04: quadratic extrapolation at t=180 must exceed last measurement 35.0; got {v}",
);
assert!( v <= 100.0, "FT-04: clamped to 100.0; got {v}" );
}
#[ test ]
fn approx_filters_pre_window_measurements()
{
let resets_at : u64 = 1_018_000;
let pts : &[ ( u64, f64 ) ] = &[
( 900_000, 10.0 ), ( 950_000, 20.0 ), ( 1_000_000, 30.0 ), ( 1_009_000, 40.0 ), ( 1_018_000, 50.0 ), ];
let now : u64 = 1_018_000 - 1;
let result_filtered = approximate_utilization( pts, Some( resets_at ), 18000, now );
let v = result_filtered.expect( "FT-06: filtered result must be Some" );
assert!(
( 40.0_f64..=100.0 ).contains( &v ),
"FT-06: filtered fit on 3 in-window points; expected ~50; got {v}",
);
}
#[ test ]
fn approx_expired_window_returns_zero()
{
let pts : &[ ( u64, f64 ) ] = &[
( 1_000_000, 30.0 ),
( 1_009_000, 40.0 ),
( 1_018_000, 50.0 ),
];
let resets_at : u64 = 1_018_000;
let now : u64 = 1_018_001;
let result = approximate_utilization( pts, Some( resets_at ), 18000, now );
assert_eq!(
result,
Some( 0.0 ),
"FT-07: expired window must return Some(0.0); got {result:?}",
);
}
#[ test ]
fn approx_clamps_to_100()
{
let pts : &[ ( u64, f64 ) ] = &[
( 0, 80.0 ),
( 60, 90.0 ),
( 120, 97.0 ),
];
let result = approximate_utilization( pts, None, 18000, 300 );
assert_eq!(
result,
Some( 100.0 ),
"FT-08: steep extrapolation at t=300 must clamp to 100.0; got {result:?}",
);
}
#[ test ]
fn approx_tangent_line_beyond_2x_span()
{
let pts : &[ ( u64, f64 ) ] = &[ ( 0, 10.0 ), ( 60, 20.0 ), ( 120, 35.0 ) ];
let now : u64 = 500;
let tangent_result = approximate_utilization( pts, None, 18000, now )
.expect( "FT-09: must return Some" );
let at_180_direct = approximate_utilization( pts, None, 18000, 180 )
.expect( "FT-09: t=180 must return Some" );
let at_500_direct = approximate_utilization( pts, None, 18000, 500 )
.expect( "FT-09: t=500 must return Some" );
assert!(
at_180_direct <= 100.0,
"FT-09: t=180 result={at_180_direct} must be <= 100",
);
assert!(
at_500_direct <= 100.0,
"FT-09: t=500 result={at_500_direct} must be <= 100 (tangent-clamped)",
);
let _ = tangent_result;
assert!(
tangent_result.is_finite(),
"FT-09: tangent-line result must be finite; got {tangent_result}",
);
}
#[ test ]
fn approx_singular_matrix_falls_back_to_constant()
{
let pts : &[ ( u64, f64 ) ] = &[ ( 100, 50.0 ), ( 100, 51.0 ), ( 100, 52.0 ) ];
let result = approximate_utilization( pts, None, 18000, 200 );
let v = result.expect( "FT-10: must return Some even on singular matrix" );
assert!(
( v - 52.0 ).abs() < 1e-9,
"FT-10: singular matrix must fall back to last measurement 52.0; got {v}",
);
}
#[ test ]
fn cc_empty_input_returns_none()
{
let pts : &[ ( u64, f64 ) ] = &[];
assert_eq!(
approximate_utilization( pts, None, 18000, 1000 ),
None,
"CC-01: empty measurements must return None",
);
}
#[ test ]
fn cc_single_measurement_returns_constant()
{
let pts : &[ ( u64, f64 ) ] = &[ ( 500, 42.0 ) ];
let result = approximate_utilization( pts, None, 18000, 9999 );
assert_eq!(
result,
Some( 42.0 ),
"CC-02: single measurement must return its value regardless of now_secs",
);
}
#[ test ]
fn cc_now_equals_resets_at_is_not_expired()
{
let pts : &[ ( u64, f64 ) ] = &[ ( 1000, 50.0 ), ( 2000, 60.0 ), ( 3000, 70.0 ) ];
let resets_at : u64 = 3000;
let result = approximate_utilization( pts, Some( resets_at ), 18000, resets_at );
assert_ne!(
result,
Some( 0.0 ),
"CC-03: now_secs == resets_at must NOT trigger expiry; got Some(0.0)",
);
assert!( result.is_some(), "CC-03: must return Some (points exist)" );
}
#[ test ]
fn cc_negative_slope_clamps_to_zero()
{
let pts : &[ ( u64, f64 ) ] = &[ ( 0, 90.0 ), ( 1000, 10.0 ) ];
let result = approximate_utilization( pts, None, 18000, 2000 );
assert_eq!(
result,
Some( 0.0 ),
"CC-04: negative extrapolation must clamp to 0.0",
);
}
#[ test ]
fn cc_degenerate_linear_identical_timestamps()
{
let pts : &[ ( u64, f64 ) ] = &[ ( 500, 30.0 ), ( 500, 45.0 ) ];
let result = approximate_utilization( pts, None, 18000, 600 );
let v = result.expect( "CC-05: must return Some for 2-point degenerate" );
assert!(
( v - 45.0 ).abs() < 1e-9,
"CC-05: degenerate linear must return last value 45.0; got {v}",
);
}
#[ test ]
fn cc_all_measurements_outside_window_returns_none()
{
let pts : &[ ( u64, f64 ) ] = &[ ( 1_000, 60.0 ), ( 2_000, 70.0 ), ( 3_000, 80.0 ) ];
let resets_at : u64 = 118_000;
let now_secs : u64 = 110_000;
let result = approximate_utilization( pts, Some( resets_at ), 18_000, now_secs );
assert_eq!(
result,
None,
"CC-06: all measurements outside window must return None (zero in-window pts); got {result:?}",
);
}
}