///|
/// Dot product of two numeric vectors.
pub fn dot_product(
left : ArrayView[Double],
right : ArrayView[Double],
) -> Double {
let n = left.length().min(right.length())
let mut total = 0.0
for i in 0.. Int {
if low > high {
clamp_int(value, low=high, high=low)
} else {
value.max(low).min(high)
}
}
///|
/// Central difference at an index, with one-sided edge handling.
pub fn central_difference(values : ArrayView[Double], index~ : Int) -> Double {
if values.length() == 0 {
0.0
} else if index <= 0 {
if values.length() == 1 {
0.0
} else {
values[1] - values[0]
}
} else if index >= values.length() - 1 {
values[index.clamp(min=0, max=values.length() - 1)] - values[index - 1]
} else {
(values[index + 1] - values[index - 1]) * 0.5
}
}
///|
/// Return a forward difference vector.
pub fn forward_differences(values : ArrayView[Double]) -> Array[Double] {
let result = Array::new()
if values.length() >= 2 {
for i in 0..<(values.length() - 1) {
result.push(values[i + 1] - values[i])
}
}
result
}
///|
/// Return cumulative sums.
pub fn prefix_sums(values : ArrayView[Double]) -> Array[Double] {
let result = Array::new()
let mut total = 0.0
for value in values {
total += value
result.push(total)
}
result
}
///|
/// Compute a weighted mean with a zero-weight fallback.
pub fn weighted_mean(
values : ArrayView[Double],
weights_values : ArrayView[Double],
) -> Double {
let n = values.length().min(weights_values.length())
let mut weighted = 0.0
let mut total_weight = 0.0
for i in 0.. Array[Double] {
let sums = prefix_sums(values)
let total = if sums.length() == 0 { 0.0 } else { sums[sums.length() - 1] }
let result = Array::new()
for value in sums {
result.push(safe_divide(value, total, fallback=0.0))
}
result
}
///|
/// Return a vector with a fixed length and a fill value.
pub fn resize_vector(
values : ArrayView[Double],
length~ : Int,
fill? : Double = 0.0,
) -> Array[Double] {
let result = Array::make(length.max(0), fill)
for i in 0.. Int? {
if values.length() == 0 {
None
} else {
let mut index = 0
let mut maximum = values[0]
for i in 1.. maximum {
maximum = values[i]
index = i
}
}
Some(index)
}
}
///|
/// Return the index of the first minimum.
pub fn argmin(values : ArrayView[Double]) -> Int? {
if values.length() == 0 {
None
} else {
let mut index = 0
let mut minimum = values[0]
for i in 1.. Double {
let numerator = dot_product(left, right)
let denominator = rms_value(left) *
rms_value(right) *
left.length().min(right.length()).to_double()
safe_divide(numerator, denominator, fallback=0.0)
}