forked from algorithm-archivists/algorithm-archive
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added approximate counting in Rust (algorithm-archivists#900)
* added approximate counting in rust * added comments * made output more consistent * fixed typo and printed values * added Cargo.toml * Fix binary name Co-authored-by: Dimitri Belopopsky <[email protected]> Co-authored-by: Dimitri Belopopsky <[email protected]>
- Loading branch information
1 parent
ff494db
commit 508cfb5
Showing
3 changed files
with
82 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
[package] | ||
name = "approximate_counting" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||
|
||
[dependencies] | ||
rand = "0.8.4" | ||
|
||
[[bin]] | ||
name = "main" | ||
path = "approximate_counting.rs" |
67 changes: 67 additions & 0 deletions
67
contents/approximate_counting/code/rust/approximate_counting.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
// This function takes | ||
// - v: value in register | ||
// - a: a scaling value for the logarithm based on Morris's paper | ||
// It returns n(v,a), the approximate count | ||
fn n(v: f64, a: f64) -> f64 { | ||
a * ((1_f64 + 1_f64 / a).powf(v) - 1_f64) | ||
} | ||
|
||
|
||
// This function takes | ||
// - v: value in register | ||
// - a: a scaling value for the logarithm based on Morris's paper | ||
// It returns a new value for v | ||
fn increment(v: f64, a: f64) -> f64 { | ||
// delta is the probability of incrementing our counter | ||
let delta = 1_f64 / (n(v + 1_f64, a) - n(v, a)); | ||
|
||
if rand::random::<f64>() <= delta { | ||
v + 1_f64 | ||
} else { | ||
v | ||
} | ||
} | ||
|
||
// This simulates counting and takes | ||
// - n_items: number of items to count and loop over | ||
// - a: a scaling value for the logarithm based on Morris's paper | ||
// It returns n(v,a), the approximate count | ||
fn approximate_count(n_items: usize, a: f64) -> f64 { | ||
let mut v = 0_f64; | ||
|
||
for _ in 0..n_items { | ||
v = increment(v, a); | ||
} | ||
|
||
v | ||
} | ||
|
||
// This function takes | ||
// - n_trials: the number of counting trials | ||
// - n_items: the number of items to count to | ||
// - a: a scaling value for the logarithm based on Morris's paper | ||
// - threshold: the maximum percent error allowed | ||
// It returns a "passed" / "failed" test value | ||
fn test_approximate_count(n_trials: usize, n_items: usize, a: f64, threshold: f64) { | ||
let avg = std::iter::from_fn(|| Some(approximate_count(n_items, a))) | ||
.take(n_trials) | ||
.sum::<f64>() / n_trials as f64; | ||
|
||
let n_items_float = n_items as f64; | ||
|
||
if ((avg - n_items_float) / n_items_float) < threshold { | ||
println!("passed"); | ||
} else { | ||
println!("failed"); | ||
} | ||
|
||
} | ||
|
||
fn main() { | ||
println!("testing 1,000, a = 30, 10% error"); | ||
test_approximate_count(100, 1000, 30_f64, 0.1); | ||
println!("testing 12,345, a = 10, 10% error"); | ||
test_approximate_count(100, 12345, 10_f64, 0.1); | ||
println!("testing 222,222, a = 0.5, 20% error"); | ||
test_approximate_count(100, 222222, 0.5, 0.2); | ||
} |