Skip to content

Commit

Permalink
Demonstrate error reported in #27
Browse files Browse the repository at this point in the history
This commit demonstrates the error reported by @c0deaddict. In some
cases, for reasons unknown, when elements are inserted into the CKMS
the error bound is not obeyed. This appears to be related to the total
number of elements inserted into the structure and not the points
themselves.
  • Loading branch information
blt committed Aug 2, 2020
1 parent d1a25d6 commit ab1dd6f
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 5 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name = "quantiles"
version = "0.7.1"
authors = ["Brian L. Troutwine <[email protected]>"]
edition = "2018"

description = "a collection of approximate quantile algorithms"
repository = "https://github.com/postmates/quantiles"
Expand Down
44 changes: 42 additions & 2 deletions src/ckms/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ impl<
/// Query CKMS for a ε-approximate quantile
///
/// This function returns an approximation to the true quantile-- +/- εΦn
/// --for the points inserted. Argument q is valid 0. <= q <= 1.0. The first
/// --for the points inserted. Argument q is valid 0.0 <= q <= 1.0. The first
/// element of the return tuple is the rank estimation for q, the second
/// element is the quantile estimation for q. The minimum and maximum
/// quantile, corresponding to 0.0 and 1.0 respectively, are always known
Expand Down Expand Up @@ -293,8 +293,9 @@ impl<
#[cfg(test)]
mod test {
use super::*;
use ckms::store::invariant;
use crate::ckms::store::invariant;
use quickcheck::{QuickCheck, TestResult};
use std::cmp;
use std::cmp::Ordering;
use std::f64::consts::E;

Expand All @@ -303,6 +304,45 @@ mod test {
data[idx]
}

#[test]
fn test_large_insert() {
let error = 0.001;
for total_points in 1000..10_000 {
let mut data = Vec::<u16>::new();
let mut ckms = CKMS::<u16>::new(error);

for v in 0..total_points {
data.push(v);
ckms.insert(v);
}

data.sort();

for p in 0..1001 {
let q = p as f64 / 1000.0;
let idx = cmp::max(1, (q * total_points as f64).ceil() as usize);
let expected = data[idx - 1];
let (_rank, actual) = ckms.query(q).unwrap();
let diff = if expected > actual {
expected - actual
} else {
actual - expected
};
let result = (diff as f64).partial_cmp(&error);
assert!(result.is_some());
assert_ne!(
result,
Some(Ordering::Greater),
"total_points: {} | quantile: {} | {} > {}",
total_points,
q,
diff,
error
);
}
}
}

#[test]
fn test_cma() {
fn inner(data: Vec<f64>, err: f64) -> TestResult {
Expand Down
5 changes: 2 additions & 3 deletions src/ckms/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@
//! constructed of nested Vecs of bounded sized -- which contains at each 'node'
//! all the information we need to perform an insert, as if we had examined
//! every sample in the block. Anyhow, we'll get into it below.
use crate::ckms::entry::Entry;
use std::fmt;
use std::ops::{Index, IndexMut};

use ckms::entry::Entry;

/// The all-important CKMS invariant.
pub fn invariant(r: f64, error: f64) -> u32 {
let i = (2.0 * error * r).floor() as u32;
Expand Down Expand Up @@ -459,7 +458,7 @@ where
#[cfg(test)]
mod test {
use super::*;
use ckms::test::between_inclusive;
use crate::ckms::test::between_inclusive;
use quickcheck::{QuickCheck, TestResult};

#[test]
Expand Down

0 comments on commit ab1dd6f

Please sign in to comment.