1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#[cfg(feature = "use_serde")]
use serde::{Deserialize, Serialize};

const DEFAULT_MAX_BINS: u32 = 2048;
const DEFAULT_ALPHA: f64 = 0.01;
const DEFAULT_MIN_VALUE: f64 = 1.0e-9;

/// The configuration struct for constructing a `DDSketch`
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
pub struct Config {
    pub max_num_bins: u32,
    pub gamma: f64,
    gamma_ln: f64,
    min_value: f64,
    pub offset: i32,
}

fn log_gamma(value: f64, gamma_ln: f64) -> f64 {
    value.ln() / gamma_ln
}

impl Config {
    /// Construct a new `Config` struct with specific parameters. If you are unsure of how to
    /// configure this, the `defaults` method constructs a `Config` with built-in defaults.
    ///
    /// `max_num_bins` is the max number of bins the DDSketch will grow to, in steps of 128 bins.
    pub fn new(alpha: f64, max_num_bins: u32, min_value: f64) -> Self {
        let gamma_ln = (2.0 * alpha) / (1.0 - alpha);
        let gamma_ln = gamma_ln.ln_1p();

        Config {
            max_num_bins,
            gamma: 1.0 + (2.0 * alpha) / (1.0 - alpha),
            gamma_ln,
            min_value,
            offset: 1 - (log_gamma(min_value, gamma_ln) as i32),
        }
    }

    /// Return a `Config` using built-in default settings
    pub fn defaults() -> Self {
        Self::new(DEFAULT_ALPHA, DEFAULT_MAX_BINS, DEFAULT_MIN_VALUE)
    }

    pub fn key(&self, v: f64) -> i32 {
        self.log_gamma(v).ceil() as i32
    }

    pub fn value(&self, key: i32) -> f64 {
        self.pow_gamma(key) * (2.0 / (1.0 + self.gamma))
    }

    pub fn log_gamma(&self, value: f64) -> f64 {
        log_gamma(value, self.gamma_ln)
    }

    pub fn pow_gamma(&self, key: i32) -> f64 {
        ((key as f64) * self.gamma_ln).exp()
    }

    pub fn min_possible(&self) -> f64 {
        self.min_value
    }
}

impl Default for Config {
    fn default() -> Self {
        Self::new(DEFAULT_ALPHA, DEFAULT_MAX_BINS, DEFAULT_MIN_VALUE)
    }
}