Initial upload: GitPulse - Developer Productivity Analyzer CLI tool
This commit is contained in:
159
src/models/time_series.rs
Normal file
159
src/models/time_series.rs
Normal file
@@ -0,0 +1,159 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||
pub enum TimeBucket {
|
||||
Hour,
|
||||
Day,
|
||||
Week,
|
||||
Month,
|
||||
}
|
||||
|
||||
impl TimeBucket {
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
TimeBucket::Hour => "hour",
|
||||
TimeBucket::Day => "day",
|
||||
TimeBucket::Week => "week",
|
||||
TimeBucket::Month => "month",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct TimeSeriesData {
|
||||
pub bucket: String,
|
||||
pub bucket_type: String,
|
||||
pub commits: usize,
|
||||
pub lines_added: usize,
|
||||
pub lines_removed: usize,
|
||||
pub authors: usize,
|
||||
}
|
||||
|
||||
impl Default for TimeSeriesData {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
bucket: String::new(),
|
||||
bucket_type: String::new(),
|
||||
commits: 0,
|
||||
lines_added: 0,
|
||||
lines_removed: 0,
|
||||
authors: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct MovingAverage {
|
||||
pub period: usize,
|
||||
pub values: Vec<f64>,
|
||||
}
|
||||
|
||||
impl MovingAverage {
|
||||
pub fn new(period: usize) -> Self {
|
||||
Self {
|
||||
period,
|
||||
values: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn calculate(&mut self, value: f64) -> f64 {
|
||||
self.values.push(value);
|
||||
if self.values.len() > self.period {
|
||||
self.values.remove(0);
|
||||
}
|
||||
let sum: f64 = self.values.iter().sum();
|
||||
sum / self.values.len() as f64
|
||||
}
|
||||
|
||||
pub fn is_ready(&self) -> bool {
|
||||
self.values.len() >= self.period
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct TrendAnalysis {
|
||||
pub slope: f64,
|
||||
pub direction: TrendDirection,
|
||||
pub strength: f64,
|
||||
pub prediction: Vec<f64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum TrendDirection {
|
||||
Increasing,
|
||||
Decreasing,
|
||||
Stable,
|
||||
Volatile,
|
||||
}
|
||||
|
||||
impl Default for TrendAnalysis {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
slope: 0.0,
|
||||
direction: TrendDirection::Stable,
|
||||
strength: 0.0,
|
||||
prediction: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn calculate_trend(values: &[f64]) -> TrendAnalysis {
|
||||
if values.len() < 2 {
|
||||
return TrendAnalysis::default();
|
||||
}
|
||||
|
||||
let n = values.len() as f64;
|
||||
let sum_x = (0..values.len()).map(|x| x as f64).sum::<f64>();
|
||||
let sum_y = values.iter().sum::<f64>();
|
||||
let sum_xy = values
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(x, y)| x as f64 * y)
|
||||
.sum::<f64>();
|
||||
let sum_x2 = values
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(x, _)| (x as f64).powi(2))
|
||||
.sum::<f64>();
|
||||
|
||||
let slope = if n * sum_x2 - sum_x * sum_x != 0.0 {
|
||||
(n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x * sum_x)
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
let avg_y = sum_y / n;
|
||||
let direction = if slope > 0.01 {
|
||||
TrendDirection::Increasing
|
||||
} else if slope < -0.01 {
|
||||
TrendDirection::Decreasing
|
||||
} else {
|
||||
TrendDirection::Stable
|
||||
};
|
||||
|
||||
let variance: f64 = values
|
||||
.iter()
|
||||
.map(|y| (y - avg_y).powi(2))
|
||||
.sum::<f64>()
|
||||
/ n;
|
||||
let std_dev = variance.sqrt();
|
||||
let strength = if std_dev > 0.0 {
|
||||
(slope.abs() / std_dev).min(1.0)
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
let prediction: Vec<f64> = (0..3)
|
||||
.map(|i| {
|
||||
let x = values.len() as f64 + i as f64;
|
||||
slope * (x - sum_x / n) + avg_y
|
||||
})
|
||||
.collect();
|
||||
|
||||
TrendAnalysis {
|
||||
slope,
|
||||
direction,
|
||||
strength,
|
||||
prediction,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user