use apache_datasketches::theta::{ThetaIntersection, ThetaSketchBuilder};
use apache_datasketches::SketchError;
#[test]
fn get_result_before_update_is_empty_intersection() {
let isect = ThetaIntersection::new();
match isect.get_result(true) {
Err(SketchError::EmptyIntersection) => {}
Err(other) => panic!("expected EmptyIntersection, got {:?}", other),
Ok(_) => panic!("expected EmptyIntersection, got Ok"),
}
}
#[test]
fn has_result_false_before_any_update() {
let isect = ThetaIntersection::new();
assert!(!isect.has_result());
}
#[test]
fn intersect_empty_with_nonempty_is_empty() {
let a = ThetaSketchBuilder::new().build().unwrap();
let mut b = ThetaSketchBuilder::new().build().unwrap();
b.update_u64(1);
let mut isect = ThetaIntersection::new();
isect.update(&a);
isect.update(&b);
let result = isect.get_result(true).unwrap();
assert!(result.is_empty());
}
#[test]
fn intersect_disjoint_sets_is_empty() {
let mut a = ThetaSketchBuilder::new().build().unwrap();
let mut b = ThetaSketchBuilder::new().build().unwrap();
for i in 0..5u64 {
a.update_u64(i);
}
for i in 5..10u64 {
b.update_u64(i);
}
let mut isect = ThetaIntersection::new();
isect.update(&a);
isect.update(&b);
let result = isect.get_result(true).unwrap();
assert!(result.is_empty());
}
#[test]
fn intersect_identical_sets_preserves_estimate() {
let mut a = ThetaSketchBuilder::new().build().unwrap();
for i in 0..10u64 {
a.update_u64(i);
}
let mut isect = ThetaIntersection::new();
isect.update(&a);
isect.update(&a);
let result = isect.get_result(true).unwrap();
assert_eq!(result.get_estimate(), 10.0);
}
#[test]
fn intersect_non_empty_no_retained_keys() {
let mut sketch = ThetaSketchBuilder::new().p(0.001).build().unwrap();
sketch.update_u64(1);
let mut isect = ThetaIntersection::new();
isect.update(&sketch);
let result = isect.get_result(true).unwrap();
assert_eq!(result.get_num_retained(), 0);
assert!(!result.is_empty());
assert!(result.is_estimation_mode());
assert!((result.get_theta() - 0.001).abs() < 1e-10);
assert_eq!(result.get_estimate(), 0.0);
isect.update(&sketch);
let result = isect.get_result(true).unwrap();
assert_eq!(result.get_num_retained(), 0);
assert!(!result.is_empty());
assert!(result.is_estimation_mode());
assert!((result.get_theta() - 0.001).abs() < 1e-10);
assert_eq!(result.get_estimate(), 0.0);
}
#[test]
fn intersect_exact_half_overlap_ordered_compact_inputs() {
let mut sketch1 = ThetaSketchBuilder::new().build().unwrap();
for i in 0..1000u64 {
sketch1.update_u64(i);
}
let mut sketch2 = ThetaSketchBuilder::new().build().unwrap();
for i in 500..1500u64 {
sketch2.update_u64(i);
}
let mut isect = ThetaIntersection::new();
isect.update(&sketch1.compact(true));
isect.update(&sketch2.compact(true));
let result = isect.get_result(true).unwrap();
assert!(!result.is_empty());
assert!(!result.is_estimation_mode());
assert_eq!(result.get_estimate(), 500.0);
}
#[test]
fn intersect_exact_disjoint_ordered_compact_inputs() {
let mut sketch1 = ThetaSketchBuilder::new().build().unwrap();
for i in 0..1000u64 {
sketch1.update_u64(i);
}
let mut sketch2 = ThetaSketchBuilder::new().build().unwrap();
for i in 1000..2000u64 {
sketch2.update_u64(i);
}
let mut isect = ThetaIntersection::new();
isect.update(&sketch1.compact(true));
isect.update(&sketch2.compact(true));
let result = isect.get_result(true).unwrap();
assert!(result.is_empty());
assert!(!result.is_estimation_mode());
assert_eq!(result.get_estimate(), 0.0);
}
#[test]
fn intersect_estimation_half_overlap_unordered() {
let mut sketch1 = ThetaSketchBuilder::new().build().unwrap();
for i in 0..10_000u64 {
sketch1.update_u64(i);
}
let mut sketch2 = ThetaSketchBuilder::new().build().unwrap();
for i in 5_000..15_000u64 {
sketch2.update_u64(i);
}
let mut isect = ThetaIntersection::new();
isect.update(&sketch1);
isect.update(&sketch2);
let result = isect.get_result(true).unwrap();
assert!(!result.is_empty());
assert!(result.is_estimation_mode());
assert!((result.get_estimate() - 5_000.0).abs() < 5_000.0 * 0.02);
}
#[test]
fn intersect_estimation_half_overlap_ordered_compact_inputs() {
let mut sketch1 = ThetaSketchBuilder::new().build().unwrap();
for i in 0..10_000u64 {
sketch1.update_u64(i);
}
let mut sketch2 = ThetaSketchBuilder::new().build().unwrap();
for i in 5_000..15_000u64 {
sketch2.update_u64(i);
}
let mut isect = ThetaIntersection::new();
isect.update(&sketch1.compact(true));
isect.update(&sketch2.compact(true));
let result = isect.get_result(true).unwrap();
assert!(!result.is_empty());
assert!(result.is_estimation_mode());
assert!((result.get_estimate() - 5_000.0).abs() < 5_000.0 * 0.02);
}
#[test]
fn intersect_estimation_half_overlap_wrapped_compact_inputs() {
use apache_datasketches::theta::WrappedCompactThetaSketch;
let mut sketch1 = ThetaSketchBuilder::new().build().unwrap();
for i in 0..10_000u64 {
sketch1.update_u64(i);
}
let bytes1 = sketch1.compact(true).serialize_compact();
let mut sketch2 = ThetaSketchBuilder::new().build().unwrap();
for i in 5_000..15_000u64 {
sketch2.update_u64(i);
}
let bytes2 = sketch2.compact(true).serialize_compact();
let mut isect = ThetaIntersection::new();
isect.update(&WrappedCompactThetaSketch::wrap(&bytes1).unwrap());
isect.update(&WrappedCompactThetaSketch::wrap(&bytes2).unwrap());
let result = isect.get_result(true).unwrap();
assert!(!result.is_empty());
assert!(result.is_estimation_mode());
assert!((result.get_estimate() - 5_000.0).abs() < 5_000.0 * 0.02);
}
#[test]
fn intersect_estimation_disjoint_unordered() {
let mut sketch1 = ThetaSketchBuilder::new().build().unwrap();
for i in 0..10_000u64 {
sketch1.update_u64(i);
}
let mut sketch2 = ThetaSketchBuilder::new().build().unwrap();
for i in 10_000..20_000u64 {
sketch2.update_u64(i);
}
let mut isect = ThetaIntersection::new();
isect.update(&sketch1);
isect.update(&sketch2);
let result = isect.get_result(true).unwrap();
assert!(!result.is_empty());
assert!(result.is_estimation_mode());
assert_eq!(result.get_estimate(), 0.0);
}
#[test]
fn intersect_estimation_disjoint_ordered_compact_inputs() {
let mut sketch1 = ThetaSketchBuilder::new().build().unwrap();
for i in 0..10_000u64 {
sketch1.update_u64(i);
}
let mut sketch2 = ThetaSketchBuilder::new().build().unwrap();
for i in 10_000..20_000u64 {
sketch2.update_u64(i);
}
let mut isect = ThetaIntersection::new();
isect.update(&sketch1.compact(true));
isect.update(&sketch2.compact(true));
let result = isect.get_result(true).unwrap();
assert!(!result.is_empty());
assert!(result.is_estimation_mode());
assert_eq!(result.get_estimate(), 0.0);
}