Skip to main content

ValueStats

Struct ValueStats 

Source
pub struct ValueStats {
    pub min: f32,
    pub max: f32,
    pub count: i64,
    /* private fields */
}
Expand description

What a reduction accumulates over a locus or a profile bin.

min and max are data values and stay f32; the accumulators do not. Both start NaN, so an untouched region reports no extremes rather than ±inf.

§Why the sums are shifted

The obvious accumulator holds Σx and Σx² and computes the variance as E[x²] − E[x]². That subtracts two nearly equal large numbers whenever the values sit far from zero relative to their spread, which is the ordinary case for coverage, CPM and log-ratio tracks — and it does not merely lose a few bits. Measured against a float64 reference on normal(1e4, 1e-2) data, the naive form reported a standard deviation of 1.9e-1 where the truth was 9.8e-3: wrong by a factor of twenty, and in another case wrong all the way to zero, the variance having gone negative and been clamped.

So every sum here is taken relative to shift, the first value folded in: Σ(x − k) and Σ(x − k)². The variance is then [Σ(x−k)² − Σ(x−k)²/n] / n over numbers of the size of the spread rather than of the mean, and the cancellation goes with it. A constant column gives exactly zero, because every difference is exactly zero. mean and sum are recovered by adding k back, which costs one multiply and no accuracy.

This is the standard shifted-data algorithm. Welford’s would be equivalent for values arriving one at a time, and cannot fold in a pre-aggregated zoom record, which this has to do — see ValueStats::add_aggregate.

Accumulation order is behaviour. These are summed in the order the extraction visits intervals, which is block order within a batch and batch order across the output. That order is deterministic on purpose: it is what makes an answer independent of parallel, which tests/roundtrip.rs and tests/properties.rs both check.

Fields§

§min: f32§max: f32§count: i64

Implementations§

Source§

impl ValueStats

Source

pub fn sum(&self) -> f64

Σx, undoing the shift.

Source

pub fn sum_squared(&self) -> f64

Σx², undoing the shift. Only L2Norm and the tests want this, and it is the one quantity the shift makes less accurate — which is the right trade, l2norm having no cancellation to suffer from.

Source

pub fn add(&mut self, value: f32)

Fold in one value covering one base.

Source

pub fn add_repeated(&mut self, value: f32, bases: i64)

Fold in bases bases all carrying value, as a wide interval does.

The f32::min/max NaN rule does the seeding: NAN.min(x) == x, so the first value replaces the initial NaN without a branch.

Source

pub fn add_aggregate( &mut self, min: f32, max: f32, sum: f64, sum_squared: f64, bases: i64, )

Fold in a pre-aggregated run: bases bases whose sum is sum and whose sum of squares is sum_squared, with known extremes.

This is how a zoom record enters, prorated over the part of it a window covers. The record’s own Σx² is used rather than its mean squared: squaring the mean would keep only the variance between records and drop the variance inside each, collapsing sd as the zoom level rises.

Σ|x| cannot be recovered from a record in general — the format stores no such field — so it is derived where the record’s sign is not in doubt (min ≥ 0, or max ≤ 0, which is every non-negative track) and approximated by |Σx| where the record straddles zero. That is a lower bound, it is the only thing the format allows, and the README says so under quantify’s reduce.

Source

pub fn merge(&mut self, other: &ValueStats)

Fold another accumulator in, rebasing it onto this one’s shift.

Source

pub fn reduce(&self, reduce: Reduce, def_value: f32) -> f32

Reduce to one number.

A region no data reached has no mean, no extremes and no spread, so those keep def_value. Its count is not unknown but zero: leaving def_value there would make count the one reduction unable to say “nothing here”.

Trait Implementations§

Source§

impl Clone for ValueStats

Source§

fn clone(&self) -> ValueStats

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for ValueStats

Source§

impl Debug for ValueStats

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for ValueStats

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl PartialEq for ValueStats

Source§

fn eq(&self, other: &ValueStats) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for ValueStats

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.