use crate::math::Real;
#[allow(unused_imports)]
use simba::scalar::ComplexField as _;
#[derive(Default, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
pub enum CoefficientCombineRule {
#[default]
Average = 0,
Min = 1,
Multiply = 2,
Max = 3,
ClampedSum = 4,
GeometricMean = 5,
}
impl CoefficientCombineRule {
#[allow(dead_code)]
pub(crate) fn combine(
coeff1: Real,
coeff2: Real,
rule_value1: CoefficientCombineRule,
rule_value2: CoefficientCombineRule,
) -> Real {
let effective_rule = rule_value1.max(rule_value2);
match effective_rule {
CoefficientCombineRule::Average => (coeff1 + coeff2) / 2.0,
CoefficientCombineRule::Min => {
coeff1.min(coeff2).abs()
}
CoefficientCombineRule::Multiply => coeff1 * coeff2,
CoefficientCombineRule::Max => coeff1.max(coeff2),
CoefficientCombineRule::ClampedSum => (coeff1 + coeff2).clamp(0.0, 1.0),
CoefficientCombineRule::GeometricMean => (coeff1.max(0.0) * coeff2.max(0.0)).sqrt(),
}
}
}
#[cfg(test)]
mod test {
use super::CoefficientCombineRule;
use crate::math::Real;
fn combine(c1: Real, c2: Real, rule: CoefficientCombineRule) -> Real {
CoefficientCombineRule::combine(c1, c2, rule, rule)
}
#[test]
fn geometric_mean_combine() {
assert_eq!(
combine(0.25, 1.0, CoefficientCombineRule::GeometricMean),
0.5
);
assert_eq!(
combine(0.7, 0.0, CoefficientCombineRule::GeometricMean),
0.0
);
assert_eq!(
combine(-0.5, 0.5, CoefficientCombineRule::GeometricMean),
0.0
);
assert_eq!(
combine(-0.5, -0.5, CoefficientCombineRule::GeometricMean),
0.0
);
}
#[test]
fn geometric_mean_wins_rule_priority() {
assert_eq!(
CoefficientCombineRule::combine(
0.25,
1.0,
CoefficientCombineRule::GeometricMean,
CoefficientCombineRule::Average,
),
0.5
);
}
}