use approx::assert_abs_diff_eq;
use geo::Point;
use pelorus::probability::{
emission_probability, emission_probability_from_distance, transition_probability,
};
#[test]
fn test_emission_probability_basic_unit() {
let sigma = 4.07;
let prob_1_std = emission_probability_from_distance(4.07, sigma);
assert_abs_diff_eq!(prob_1_std, 0.2420, epsilon = 0.0001);
let prob_0 = emission_probability_from_distance(0.0, sigma);
assert_abs_diff_eq!(prob_0, 0.3989, epsilon = 0.0001);
}
#[test]
fn test_emission_probability_with_points_unit() {
let sigma = 4.07;
let gps = Point::new(0.0, 0.0);
let candidate = Point::new(4.07, 0.0);
let prob = emission_probability(&gps, &candidate, sigma);
assert_abs_diff_eq!(prob, 0.2420, epsilon = 0.0001);
}
#[test]
fn test_emission_probability_edge_cases_unit() {
let prob_large = emission_probability_from_distance(250.0, 4.07);
assert_eq!(prob_large, 0.0);
let gps = Point::new(0.0, 0.0);
let far_candidate = Point::new(250.0, 0.0);
let prob_large_points = emission_probability(&gps, &far_candidate, 4.07);
assert_eq!(prob_large_points, 0.0);
}
#[test]
fn test_transition_probability_basic_unit() {
let beta = 10.0;
let prob = transition_probability(100.0, 105.0, beta);
assert_abs_diff_eq!(prob, 0.0607, epsilon = 0.0001);
}
#[test]
fn test_transition_probability_edge_cases_unit() {
let beta = 10.0;
let prob_large = transition_probability(100.0, 2500.0, beta);
assert_eq!(prob_large, 0.0);
}
#[test]
fn test_emission_probability_at_one_std_dev() {
let sigma = 4.07;
let distance = 4.07;
let probability = emission_probability_from_distance(distance, sigma);
assert_abs_diff_eq!(probability, 0.2420, epsilon = 1e-4);
}
#[test]
fn test_emission_probability_at_zero_distance() {
let sigma = 4.07;
let distance = 0.0;
let probability = emission_probability_from_distance(distance, sigma);
assert_abs_diff_eq!(probability, 0.3989, epsilon = 1e-4);
}
#[test]
fn test_emission_probability_with_points() {
let sigma = 4.07;
let gps = Point::new(0.0, 0.0);
let candidate = Point::new(4.07, 0.0);
let probability = emission_probability(&gps, &candidate, sigma);
assert_abs_diff_eq!(probability, 0.2420, epsilon = 1e-4);
}
#[test]
fn test_emission_probability_decreases_with_distance() {
let sigma = 4.07;
let prob_0 = emission_probability_from_distance(0.0, sigma);
let prob_1 = emission_probability_from_distance(1.0, sigma);
let prob_2 = emission_probability_from_distance(2.0, sigma);
let prob_4 = emission_probability_from_distance(4.07, sigma);
assert!(prob_0 > prob_1);
assert!(prob_1 > prob_2);
assert!(prob_2 > prob_4);
}
#[test]
fn test_emission_probability_large_distance_cutoff() {
let sigma = 4.07;
assert_eq!(emission_probability_from_distance(200.1, sigma), 0.0);
assert_eq!(emission_probability_from_distance(250.0, sigma), 0.0);
assert_eq!(emission_probability_from_distance(1000.0, sigma), 0.0);
let gps = Point::new(0.0, 0.0);
let far_candidate = Point::new(250.0, 0.0);
assert_eq!(emission_probability(&gps, &far_candidate, sigma), 0.0);
}
#[test]
fn test_emission_probability_different_sigma_values() {
let distance = 5.0;
let prob_small_sigma = emission_probability_from_distance(distance, 2.0);
let prob_large_sigma = emission_probability_from_distance(distance, 10.0);
assert!(prob_large_sigma > prob_small_sigma);
}
#[test]
fn test_transition_probability_basic_case() {
let great_circle_distance = 100.0;
let route_distance = 105.0;
let beta = 10.0;
let probability =
transition_probability(great_circle_distance, route_distance, beta);
assert_abs_diff_eq!(probability, 0.0607, epsilon = 1e-4);
}
#[test]
fn test_transition_probability_perfect_match() {
let great_circle_distance = 100.0;
let route_distance = 100.0; let beta = 10.0;
let probability =
transition_probability(great_circle_distance, route_distance, beta);
assert_abs_diff_eq!(probability, 0.1, epsilon = 1e-4);
}
#[test]
fn test_transition_probability_route_shorter_than_great_circle() {
let great_circle_distance = 105.0;
let route_distance = 100.0; let beta = 10.0;
let probability =
transition_probability(great_circle_distance, route_distance, beta);
assert_abs_diff_eq!(probability, 0.0607, epsilon = 1e-4);
}
#[test]
fn test_transition_probability_decreases_with_difference() {
let great_circle_distance = 100.0;
let beta = 10.0;
let prob_0_diff = transition_probability(great_circle_distance, 100.0, beta);
let prob_5_diff = transition_probability(great_circle_distance, 105.0, beta);
let prob_10_diff = transition_probability(great_circle_distance, 110.0, beta);
let prob_20_diff = transition_probability(great_circle_distance, 120.0, beta);
assert!(prob_0_diff > prob_5_diff);
assert!(prob_5_diff > prob_10_diff);
assert!(prob_10_diff > prob_20_diff);
}
#[test]
fn test_transition_probability_large_route_distance_cutoff() {
let great_circle_distance = 100.0;
let beta = 10.0;
assert_eq!(
transition_probability(great_circle_distance, 2200.0, beta),
0.0
);
assert_eq!(
transition_probability(great_circle_distance, 5000.0, beta),
0.0
);
}
#[test]
fn test_transition_probability_different_beta_values() {
let great_circle_distance = 100.0;
let route_distance = 110.0;
let prob_strict =
transition_probability(great_circle_distance, route_distance, 5.0);
let prob_lenient =
transition_probability(great_circle_distance, route_distance, 20.0);
assert!(prob_lenient > prob_strict);
}
#[test]
fn test_emission_probability_zero_sigma() {
let prob = emission_probability_from_distance(1.0, 0.0);
assert_eq!(prob, 0.0);
let prob_zero_distance = emission_probability_from_distance(0.0, 0.0);
assert_abs_diff_eq!(
prob_zero_distance,
1.0 / (2.0 * std::f64::consts::PI).sqrt(),
epsilon = 1e-10
);
}
#[test]
fn test_transition_probability_zero_beta() {
let prob = transition_probability(100.0, 105.0, 0.0);
assert!(prob.is_infinite() || prob.is_nan());
}
#[test]
fn test_probabilities_are_non_negative() {
assert!(emission_probability_from_distance(10.0, 5.0) >= 0.0);
assert!(emission_probability_from_distance(0.0, 5.0) >= 0.0);
assert!(transition_probability(100.0, 110.0, 10.0) >= 0.0);
assert!(transition_probability(110.0, 100.0, 10.0) >= 0.0);
}
#[test]
fn test_emission_probability_bounds() {
let sigma = 4.07;
assert!(emission_probability_from_distance(0.0, sigma) <= 1.0);
assert!(emission_probability_from_distance(1.0, sigma) <= 1.0);
assert!(emission_probability_from_distance(10.0, sigma) <= 1.0);
}
#[test]
fn test_emission_probability_symmetry() {
let sigma = 5.0;
let gps = Point::new(0.0, 0.0);
let candidate1 = Point::new(3.0, 0.0);
let candidate2 = Point::new(-3.0, 0.0);
let prob1 = emission_probability(&gps, &candidate1, sigma);
let prob2 = emission_probability(&gps, &candidate2, sigma);
assert_abs_diff_eq!(prob1, prob2, epsilon = 1e-10);
}
#[test]
fn test_transition_probability_symmetry() {
let beta = 10.0;
let prob1 = transition_probability(100.0, 110.0, beta);
let prob2 = transition_probability(110.0, 100.0, beta);
assert_abs_diff_eq!(prob1, prob2, epsilon = 1e-10);
}
#[test]
fn test_emission_probability_small_sigma() {
let small_sigma = 0.001;
let prob = emission_probability_from_distance(0.0, small_sigma);
assert!(prob.is_finite());
assert!(prob > 0.0);
}
#[test]
fn test_transition_probability_large_difference() {
let prob = transition_probability(100.0, 1900.0, 10.0); assert!(prob.is_finite());
assert!(prob > 0.0);
assert!(prob < 1e-10); }