Skip to main content

ArrayOfDoublesUnionBuilder

Struct ArrayOfDoublesUnionBuilder 

Source
pub struct ArrayOfDoublesUnionBuilder { /* private fields */ }
Expand description

Builder for ArrayOfDoublesUnion, mirroring upstream’s array_of_doubles_union::builder. lg_k defaults to 12, resize_factor to ResizeFactor::X8, p to 1.0 (no sampling), and num_values to 1. As with ArrayOfDoublesSketchBuilder, the seed is never exposed.

Implementations§

Source§

impl ArrayOfDoublesUnionBuilder

Source

pub fn new() -> Self

Creates a new builder with default settings (lg_k = 12, resize_factor = X8, p = 1.0, num_values = 1).

Examples found in repository?
examples/tuple.rs (line 40)
14fn main() {
15    // Two sketches of user IDs, each carrying [sessions, revenue] per user.
16    let mut day1 = ArrayOfDoublesSketchBuilder::new()
17        .lg_k(12)
18        .num_values(2)
19        .build()
20        .unwrap();
21    for id in 0..10_000u64 {
22        day1.update_u64(id, &[1.0, 2.50]).unwrap();
23    }
24
25    let mut day2 = ArrayOfDoublesSketchBuilder::new()
26        .lg_k(12)
27        .num_values(2)
28        .build()
29        .unwrap();
30    for id in 5_000..15_000u64 {
31        day2.update_u64(id, &[1.0, 4.00]).unwrap();
32    }
33
34    println!("Day 1 unique users (estimate): {:.0}", day1.get_estimate());
35    println!("Day 2 unique users (estimate): {:.0}", day2.get_estimate());
36    println!("Values per entry: {}", day1.get_num_values());
37
38    // Union: unique users across both days, with per-user values summed for
39    // anyone who appeared on both.
40    let mut union = ArrayOfDoublesUnionBuilder::new()
41        .lg_k(12)
42        .num_values(2)
43        .build()
44        .unwrap();
45    union.update(&day1).unwrap();
46    union.update(&day2).unwrap();
47    let combined = union.get_result(true);
48    println!(
49        "Total unique users (union estimate): {:.0}",
50        combined.get_estimate()
51    );
52
53    // Per-entry access is what distinguishes Tuple sketches from HLL/Theta/CPC:
54    // scale the retained sample's revenue back up by 1/theta to estimate the
55    // full population total.
56    let retained_revenue: f64 = combined.entries().map(|(_, values)| values[1]).sum();
57    println!(
58        "Estimated total revenue: {:.2} (from {} retained entries, theta = {:.4})",
59        retained_revenue / combined.get_theta(),
60        combined.get_num_retained(),
61        combined.get_theta()
62    );
63
64    // Intersection: users who came back on day 2.
65    let mut intersection = ArrayOfDoublesIntersection::new(2).unwrap();
66    intersection.update(&day1).unwrap();
67    intersection.update(&day2).unwrap();
68    match intersection.get_result(true) {
69        Ok(returning) => println!(
70            "Returning users (intersection estimate): {:.0}",
71            returning.get_estimate()
72        ),
73        Err(e) => println!("No intersection result: {e}"),
74    }
75
76    // A-not-b: users who only came on day 1.
77    let a_not_b = ArrayOfDoublesAnotB::new();
78    let day1_only = a_not_b.compute(&day1, &day2, true).unwrap();
79    println!(
80        "Day-1-only users (a-not-b estimate): {:.0}",
81        day1_only.get_estimate()
82    );
83
84    // Jaccard similarity of the two days' audiences.
85    let similarity = array_of_doubles_jaccard_similarity(&day1, &day2).unwrap();
86    println!(
87        "Jaccard similarity: {:.3} (range [{:.3}, {:.3}])",
88        similarity.estimate, similarity.lower_bound, similarity.upper_bound
89    );
90
91    // Serialize a compact sketch for storage/transmission, then restore it.
92    let compact = day1.compact(true);
93    let bytes = compact.serialize();
94    println!("Serialized day-1 sketch: {} bytes", bytes.len());
95    let restored = CompactArrayOfDoublesSketch::deserialize(&bytes).unwrap();
96    println!(
97        "Restored estimate: {:.0} ({} values per entry)",
98        restored.get_estimate(),
99        restored.get_num_values()
100    );
101}
Source

pub fn lg_k(self, lg_k: u8) -> Self

Sets the base-2 log of the target number of retained entries in the union’s result.

Examples found in repository?
examples/tuple.rs (line 41)
14fn main() {
15    // Two sketches of user IDs, each carrying [sessions, revenue] per user.
16    let mut day1 = ArrayOfDoublesSketchBuilder::new()
17        .lg_k(12)
18        .num_values(2)
19        .build()
20        .unwrap();
21    for id in 0..10_000u64 {
22        day1.update_u64(id, &[1.0, 2.50]).unwrap();
23    }
24
25    let mut day2 = ArrayOfDoublesSketchBuilder::new()
26        .lg_k(12)
27        .num_values(2)
28        .build()
29        .unwrap();
30    for id in 5_000..15_000u64 {
31        day2.update_u64(id, &[1.0, 4.00]).unwrap();
32    }
33
34    println!("Day 1 unique users (estimate): {:.0}", day1.get_estimate());
35    println!("Day 2 unique users (estimate): {:.0}", day2.get_estimate());
36    println!("Values per entry: {}", day1.get_num_values());
37
38    // Union: unique users across both days, with per-user values summed for
39    // anyone who appeared on both.
40    let mut union = ArrayOfDoublesUnionBuilder::new()
41        .lg_k(12)
42        .num_values(2)
43        .build()
44        .unwrap();
45    union.update(&day1).unwrap();
46    union.update(&day2).unwrap();
47    let combined = union.get_result(true);
48    println!(
49        "Total unique users (union estimate): {:.0}",
50        combined.get_estimate()
51    );
52
53    // Per-entry access is what distinguishes Tuple sketches from HLL/Theta/CPC:
54    // scale the retained sample's revenue back up by 1/theta to estimate the
55    // full population total.
56    let retained_revenue: f64 = combined.entries().map(|(_, values)| values[1]).sum();
57    println!(
58        "Estimated total revenue: {:.2} (from {} retained entries, theta = {:.4})",
59        retained_revenue / combined.get_theta(),
60        combined.get_num_retained(),
61        combined.get_theta()
62    );
63
64    // Intersection: users who came back on day 2.
65    let mut intersection = ArrayOfDoublesIntersection::new(2).unwrap();
66    intersection.update(&day1).unwrap();
67    intersection.update(&day2).unwrap();
68    match intersection.get_result(true) {
69        Ok(returning) => println!(
70            "Returning users (intersection estimate): {:.0}",
71            returning.get_estimate()
72        ),
73        Err(e) => println!("No intersection result: {e}"),
74    }
75
76    // A-not-b: users who only came on day 1.
77    let a_not_b = ArrayOfDoublesAnotB::new();
78    let day1_only = a_not_b.compute(&day1, &day2, true).unwrap();
79    println!(
80        "Day-1-only users (a-not-b estimate): {:.0}",
81        day1_only.get_estimate()
82    );
83
84    // Jaccard similarity of the two days' audiences.
85    let similarity = array_of_doubles_jaccard_similarity(&day1, &day2).unwrap();
86    println!(
87        "Jaccard similarity: {:.3} (range [{:.3}, {:.3}])",
88        similarity.estimate, similarity.lower_bound, similarity.upper_bound
89    );
90
91    // Serialize a compact sketch for storage/transmission, then restore it.
92    let compact = day1.compact(true);
93    let bytes = compact.serialize();
94    println!("Serialized day-1 sketch: {} bytes", bytes.len());
95    let restored = CompactArrayOfDoublesSketch::deserialize(&bytes).unwrap();
96    println!(
97        "Restored estimate: {:.0} ({} values per entry)",
98        restored.get_estimate(),
99        restored.get_num_values()
100    );
101}
Source

pub fn resize_factor(self, resize_factor: ResizeFactor) -> Self

Sets the hash table’s growth ResizeFactor.

Source

pub fn p(self, p: f32) -> Self

Sets the sampling probability. 1.0 (the default) disables sampling.

Source

pub fn num_values(self, num_values: u8) -> Self

Sets the fixed number of f64 values per entry. Must be at least 1, and must match every sketch later passed to ArrayOfDoublesUnion::update.

Examples found in repository?
examples/tuple.rs (line 42)
14fn main() {
15    // Two sketches of user IDs, each carrying [sessions, revenue] per user.
16    let mut day1 = ArrayOfDoublesSketchBuilder::new()
17        .lg_k(12)
18        .num_values(2)
19        .build()
20        .unwrap();
21    for id in 0..10_000u64 {
22        day1.update_u64(id, &[1.0, 2.50]).unwrap();
23    }
24
25    let mut day2 = ArrayOfDoublesSketchBuilder::new()
26        .lg_k(12)
27        .num_values(2)
28        .build()
29        .unwrap();
30    for id in 5_000..15_000u64 {
31        day2.update_u64(id, &[1.0, 4.00]).unwrap();
32    }
33
34    println!("Day 1 unique users (estimate): {:.0}", day1.get_estimate());
35    println!("Day 2 unique users (estimate): {:.0}", day2.get_estimate());
36    println!("Values per entry: {}", day1.get_num_values());
37
38    // Union: unique users across both days, with per-user values summed for
39    // anyone who appeared on both.
40    let mut union = ArrayOfDoublesUnionBuilder::new()
41        .lg_k(12)
42        .num_values(2)
43        .build()
44        .unwrap();
45    union.update(&day1).unwrap();
46    union.update(&day2).unwrap();
47    let combined = union.get_result(true);
48    println!(
49        "Total unique users (union estimate): {:.0}",
50        combined.get_estimate()
51    );
52
53    // Per-entry access is what distinguishes Tuple sketches from HLL/Theta/CPC:
54    // scale the retained sample's revenue back up by 1/theta to estimate the
55    // full population total.
56    let retained_revenue: f64 = combined.entries().map(|(_, values)| values[1]).sum();
57    println!(
58        "Estimated total revenue: {:.2} (from {} retained entries, theta = {:.4})",
59        retained_revenue / combined.get_theta(),
60        combined.get_num_retained(),
61        combined.get_theta()
62    );
63
64    // Intersection: users who came back on day 2.
65    let mut intersection = ArrayOfDoublesIntersection::new(2).unwrap();
66    intersection.update(&day1).unwrap();
67    intersection.update(&day2).unwrap();
68    match intersection.get_result(true) {
69        Ok(returning) => println!(
70            "Returning users (intersection estimate): {:.0}",
71            returning.get_estimate()
72        ),
73        Err(e) => println!("No intersection result: {e}"),
74    }
75
76    // A-not-b: users who only came on day 1.
77    let a_not_b = ArrayOfDoublesAnotB::new();
78    let day1_only = a_not_b.compute(&day1, &day2, true).unwrap();
79    println!(
80        "Day-1-only users (a-not-b estimate): {:.0}",
81        day1_only.get_estimate()
82    );
83
84    // Jaccard similarity of the two days' audiences.
85    let similarity = array_of_doubles_jaccard_similarity(&day1, &day2).unwrap();
86    println!(
87        "Jaccard similarity: {:.3} (range [{:.3}, {:.3}])",
88        similarity.estimate, similarity.lower_bound, similarity.upper_bound
89    );
90
91    // Serialize a compact sketch for storage/transmission, then restore it.
92    let compact = day1.compact(true);
93    let bytes = compact.serialize();
94    println!("Serialized day-1 sketch: {} bytes", bytes.len());
95    let restored = CompactArrayOfDoublesSketch::deserialize(&bytes).unwrap();
96    println!(
97        "Restored estimate: {:.0} ({} values per entry)",
98        restored.get_estimate(),
99        restored.get_num_values()
100    );
101}
Source

pub fn build(self) -> Result<ArrayOfDoublesUnion, SketchError>

Builds the union. Returns SketchError::InvalidConfig if lg_k is out of range, p is outside (0, 1], or num_values is 0.

Examples found in repository?
examples/tuple.rs (line 43)
14fn main() {
15    // Two sketches of user IDs, each carrying [sessions, revenue] per user.
16    let mut day1 = ArrayOfDoublesSketchBuilder::new()
17        .lg_k(12)
18        .num_values(2)
19        .build()
20        .unwrap();
21    for id in 0..10_000u64 {
22        day1.update_u64(id, &[1.0, 2.50]).unwrap();
23    }
24
25    let mut day2 = ArrayOfDoublesSketchBuilder::new()
26        .lg_k(12)
27        .num_values(2)
28        .build()
29        .unwrap();
30    for id in 5_000..15_000u64 {
31        day2.update_u64(id, &[1.0, 4.00]).unwrap();
32    }
33
34    println!("Day 1 unique users (estimate): {:.0}", day1.get_estimate());
35    println!("Day 2 unique users (estimate): {:.0}", day2.get_estimate());
36    println!("Values per entry: {}", day1.get_num_values());
37
38    // Union: unique users across both days, with per-user values summed for
39    // anyone who appeared on both.
40    let mut union = ArrayOfDoublesUnionBuilder::new()
41        .lg_k(12)
42        .num_values(2)
43        .build()
44        .unwrap();
45    union.update(&day1).unwrap();
46    union.update(&day2).unwrap();
47    let combined = union.get_result(true);
48    println!(
49        "Total unique users (union estimate): {:.0}",
50        combined.get_estimate()
51    );
52
53    // Per-entry access is what distinguishes Tuple sketches from HLL/Theta/CPC:
54    // scale the retained sample's revenue back up by 1/theta to estimate the
55    // full population total.
56    let retained_revenue: f64 = combined.entries().map(|(_, values)| values[1]).sum();
57    println!(
58        "Estimated total revenue: {:.2} (from {} retained entries, theta = {:.4})",
59        retained_revenue / combined.get_theta(),
60        combined.get_num_retained(),
61        combined.get_theta()
62    );
63
64    // Intersection: users who came back on day 2.
65    let mut intersection = ArrayOfDoublesIntersection::new(2).unwrap();
66    intersection.update(&day1).unwrap();
67    intersection.update(&day2).unwrap();
68    match intersection.get_result(true) {
69        Ok(returning) => println!(
70            "Returning users (intersection estimate): {:.0}",
71            returning.get_estimate()
72        ),
73        Err(e) => println!("No intersection result: {e}"),
74    }
75
76    // A-not-b: users who only came on day 1.
77    let a_not_b = ArrayOfDoublesAnotB::new();
78    let day1_only = a_not_b.compute(&day1, &day2, true).unwrap();
79    println!(
80        "Day-1-only users (a-not-b estimate): {:.0}",
81        day1_only.get_estimate()
82    );
83
84    // Jaccard similarity of the two days' audiences.
85    let similarity = array_of_doubles_jaccard_similarity(&day1, &day2).unwrap();
86    println!(
87        "Jaccard similarity: {:.3} (range [{:.3}, {:.3}])",
88        similarity.estimate, similarity.lower_bound, similarity.upper_bound
89    );
90
91    // Serialize a compact sketch for storage/transmission, then restore it.
92    let compact = day1.compact(true);
93    let bytes = compact.serialize();
94    println!("Serialized day-1 sketch: {} bytes", bytes.len());
95    let restored = CompactArrayOfDoublesSketch::deserialize(&bytes).unwrap();
96    println!(
97        "Restored estimate: {:.0} ({} values per entry)",
98        restored.get_estimate(),
99        restored.get_num_values()
100    );
101}

Trait Implementations§

Source§

impl Clone for ArrayOfDoublesUnionBuilder

Source§

fn clone(&self) -> ArrayOfDoublesUnionBuilder

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 ArrayOfDoublesUnionBuilder

Source§

impl Debug for ArrayOfDoublesUnionBuilder

Source§

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

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

impl Default for ArrayOfDoublesUnionBuilder

Source§

fn default() -> Self

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

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> 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 = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.