///|
/// Cross-series relationship helpers for multivariate monitoring.
pub fn safe_correlation(left : Array[Double], right : Array[Double]) -> Double {
clamp_probability((correlation(left, right) + 1.0) / 2.0) * 2.0 - 1.0
}
///|
pub fn covariance_matrix(series : Array[Array[Double]]) -> SquareMatrix {
let dimension = series.length()
let result = SquareMatrix::new(dimension)
for row in 0.. SquareMatrix {
let dimension = series.length()
let result = SquareMatrix::identity(dimension)
for row in 0.. Double {
if series.length() < 2 {
return 0.0
}
let mut total = 0.0
let mut pairs = 0
for row in 0.. Double {
if lag < 0 {
return lagged_correlation(right, left, -lag)
}
if lag >= left.length() || lag >= right.length() {
return 0.0
}
let a : Array[Double] = []
let b : Array[Double] = []
let length = if left.length() - lag < right.length() {
left.length() - lag
} else {
right.length()
}
for i in 0.. Int {
let bound = if maximum_lag < 0 { 0 } else { maximum_lag }
let mut best = 0
let mut best_score = absolute(lagged_correlation(left, right, 0))
for lag in 1..<(bound + 1) {
let score = absolute(lagged_correlation(left, right, lag))
if score > best_score {
best = lag
best_score = score
}
}
best
}
///|
pub fn rolling_correlation(
left : Array[Double],
right : Array[Double],
window_size : Int,
) -> Array[Double] {
let result : Array[Double] = []
let safe = if window_size < 2 { 2 } else { window_size }
let length = if left.length() < right.length() {
left.length()
} else {
right.length()
}
for i in 0.. Double {
let before_matrix = correlation_matrix(before)
let after_matrix = correlation_matrix(after)
let dimension = if before.length() < after.length() {
before.length()
} else {
after.length()
}
let mut total = 0.0
for row in 0.. DetectionResult {
let score = correlated_change_score(before, after)
DetectionResult::new(
score >= threshold,
score,
clamp_probability(score),
DistributionShift,
0,
evidence=score,
)
}