sublinear 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. sublinear-0.1.0/LICENSE +21 -0
  2. sublinear-0.1.0/PKG-INFO +67 -0
  3. sublinear-0.1.0/README.md +55 -0
  4. sublinear-0.1.0/setup.cfg +4 -0
  5. sublinear-0.1.0/setup.py +25 -0
  6. sublinear-0.1.0/sublinear/__init__.py +0 -0
  7. sublinear-0.1.0/sublinear/count/__init__.py +0 -0
  8. sublinear-0.1.0/sublinear/count/morris/__init__.py +0 -0
  9. sublinear-0.1.0/sublinear/count/morris/experiments/__init__.py +0 -0
  10. sublinear-0.1.0/sublinear/count/morris/experiments/experiment1.py +32 -0
  11. sublinear-0.1.0/sublinear/count/morris/morris_basic.py +49 -0
  12. sublinear-0.1.0/sublinear/count/morris/morris_plus.py +53 -0
  13. sublinear-0.1.0/sublinear/count/morris/morris_plus_plus.py +61 -0
  14. sublinear-0.1.0/sublinear/distinct_elements/__init__.py +0 -0
  15. sublinear-0.1.0/sublinear/distinct_elements/bjkst/__init__.py +0 -0
  16. sublinear-0.1.0/sublinear/distinct_elements/bjkst/bjkst_plus.py +71 -0
  17. sublinear-0.1.0/sublinear/distinct_elements/bjkst/bjkst_sketch.py +82 -0
  18. sublinear-0.1.0/sublinear/distinct_elements/bjkst/experiments/__init__.py +0 -0
  19. sublinear-0.1.0/sublinear/distinct_elements/bjkst/experiments/experiment1.py +21 -0
  20. sublinear-0.1.0/sublinear/distinct_elements/bjkst/experiments/experiment2.py +22 -0
  21. sublinear-0.1.0/sublinear/distinct_elements/hyperloglog/__init__.py +0 -0
  22. sublinear-0.1.0/sublinear/distinct_elements/hyperloglog/experiments/__init__.py +0 -0
  23. sublinear-0.1.0/sublinear/distinct_elements/hyperloglog/experiments/experiment1.py +20 -0
  24. sublinear-0.1.0/sublinear/distinct_elements/hyperloglog/hyper_log_log.py +135 -0
  25. sublinear-0.1.0/sublinear/distinct_elements/sketch_switching/__init__.py +0 -0
  26. sublinear-0.1.0/sublinear/distinct_elements/sketch_switching/experiments/__init__.py +0 -0
  27. sublinear-0.1.0/sublinear/distinct_elements/sketch_switching/experiments/experiment1.py +18 -0
  28. sublinear-0.1.0/sublinear/distinct_elements/sketch_switching/sketch_switch.py +76 -0
  29. sublinear-0.1.0/sublinear/frequency_table/__init__.py +0 -0
  30. sublinear-0.1.0/sublinear/frequency_table/cms/__init__.py +0 -0
  31. sublinear-0.1.0/sublinear/frequency_table/cms/count_min_sketch.py +112 -0
  32. sublinear-0.1.0/sublinear/frequency_table/cms/experiments/__init__.py +0 -0
  33. sublinear-0.1.0/sublinear/frequency_table/cms/experiments/cms_text.py +140 -0
  34. sublinear-0.1.0/sublinear/frequency_table/cms/experiments/experiment1.py +41 -0
  35. sublinear-0.1.0/sublinear/frequency_table/cms/experiments/experiment2.py +50 -0
  36. sublinear-0.1.0/sublinear/heavy_hitters/__init__.py +0 -0
  37. sublinear-0.1.0/sublinear/heavy_hitters/mgs/__init__.py +0 -0
  38. sublinear-0.1.0/sublinear/heavy_hitters/mgs/experiments/__init__.py +0 -0
  39. sublinear-0.1.0/sublinear/heavy_hitters/mgs/experiments/experiment1.py +19 -0
  40. sublinear-0.1.0/sublinear/heavy_hitters/mgs/misra_gries_sketch.py +71 -0
  41. sublinear-0.1.0/sublinear/second_moment/__init__.py +0 -0
  42. sublinear-0.1.0/sublinear/second_moment/ams/__init__.py +0 -0
  43. sublinear-0.1.0/sublinear/second_moment/ams/ams_sketch_basic.py +53 -0
  44. sublinear-0.1.0/sublinear/second_moment/ams/ams_sketch_plus.py +57 -0
  45. sublinear-0.1.0/sublinear/second_moment/ams/ams_sketch_plus_plus.py +59 -0
  46. sublinear-0.1.0/sublinear/second_moment/ams/experiments/__init__.py +0 -0
  47. sublinear-0.1.0/sublinear/second_moment/ams/experiments/experiment1.py +25 -0
  48. sublinear-0.1.0/sublinear/second_moment/ams/experiments/experiment2.py +26 -0
  49. sublinear-0.1.0/sublinear/second_moment/ams/experiments/experiment3.py +27 -0
  50. sublinear-0.1.0/sublinear/utils/__init__.py +0 -0
  51. sublinear-0.1.0/sublinear/utils/experiments/__init__.py +0 -0
  52. sublinear-0.1.0/sublinear/utils/experiments/experiment1.py +12 -0
  53. sublinear-0.1.0/sublinear/utils/hash_generator.py +118 -0
  54. sublinear-0.1.0/sublinear/utils/zeros.py +22 -0
  55. sublinear-0.1.0/sublinear.egg-info/PKG-INFO +67 -0
  56. sublinear-0.1.0/sublinear.egg-info/SOURCES.txt +57 -0
  57. sublinear-0.1.0/sublinear.egg-info/dependency_links.txt +1 -0
  58. sublinear-0.1.0/sublinear.egg-info/requires.txt +2 -0
  59. sublinear-0.1.0/sublinear.egg-info/top_level.txt +1 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Ivan Nikitovic
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,67 @@
1
+ Metadata-Version: 2.1
2
+ Name: sublinear
3
+ Version: 0.1.0
4
+ Summary: Python library implementing a subset of streaming algorithms. Includes variations of these algorithms (e.g. adversarially robust), as well as support for multiple data types.
5
+ Home-page: https://github.com/ivannikitovic/sublinear
6
+ Author: Ivan Nikitovic
7
+ Author-email: ivan.bnikitovic@gmail.com
8
+ License: MIT
9
+ Requires-Python: >=3.7
10
+ Description-Content-Type: text/markdown
11
+ License-File: LICENSE
12
+
13
+ # sublinear
14
+
15
+ Python library implementing a subset of streaming algorithms. Includes variations of these algorithms (e.g. adversarially robust), as well as support for multiple data types.
16
+
17
+ ## :zap: Algorithms
18
+
19
+ Here is the list of the currently implemented streaming algorithms.
20
+
21
+ ### F0 Estimation (Count of Distinct Elements)
22
+
23
+ - BJKST Sketch (basic, plus, adversarially robust) [1]
24
+
25
+ - HyperLogLog [2]
26
+
27
+ ### F1 Estimation (Length of Stream)
28
+
29
+ - Morris (basic, plus, plus plus) [3][4]
30
+
31
+ ### F2 Estimation (Estimate of Second Moment)
32
+
33
+ - AMS Sketch (basic, plus, plus plus) [5]
34
+
35
+ ### Frequency Table Estimation
36
+
37
+ - Count Min Sketch [6]
38
+
39
+ ### Heavy Hitters
40
+
41
+ - Misra-Gries Sketch [7]
42
+
43
+ ### Other
44
+
45
+ - K Independent Hash Function [8]
46
+
47
+ ## :book: Bibliography
48
+
49
+ [1] Bar-Yossef, Ziv, et al. "Counting distinct elements in a data stream." Randomization and Approximation Techniques in Computer Science. Springer Berlin Heidelberg, 2002.
50
+
51
+ [2] Flajolet, Philippe, et al. "HyperLogLog: the analysis of a near-optimal cardinality estimation algorithm." Conference on Analysis of Algorithms. Springer Berlin Heidelberg, 2007.
52
+
53
+ [3] Morris, R. "Counting large numbers of events in small registers". Communications of the ACM 21, 10, 1978.
54
+
55
+ [4] Flajolet, P. "Approximate Counting: A Detailed Analysis". BIT 25, 1985.
56
+
57
+ [5] Noga Alon, Yossi Matias, Mario Szegedy,
58
+ "The Space Complexity of Approximating the Frequency Moments".
59
+ Journal of Computer and System Sciences,
60
+ Volume 58, Issue 1,
61
+ 1999.
62
+
63
+ [6] Cormode, Graham; S. Muthukrishnan. "An Improved Data Stream Summary: The Count-Min Sketch and its Applications". 2005.
64
+
65
+ [7] Misra, J.; Gries, David. "Finding repeated elements". Science of Computer Programming. 1982
66
+
67
+ [8] Wegman, Mark N., et al. "New Hash Functions and Their Use in Authentication and Set Equality". Journal of Computer and System Sciences. 1981.
@@ -0,0 +1,55 @@
1
+ # sublinear
2
+
3
+ Python library implementing a subset of streaming algorithms. Includes variations of these algorithms (e.g. adversarially robust), as well as support for multiple data types.
4
+
5
+ ## :zap: Algorithms
6
+
7
+ Here is the list of the currently implemented streaming algorithms.
8
+
9
+ ### F0 Estimation (Count of Distinct Elements)
10
+
11
+ - BJKST Sketch (basic, plus, adversarially robust) [1]
12
+
13
+ - HyperLogLog [2]
14
+
15
+ ### F1 Estimation (Length of Stream)
16
+
17
+ - Morris (basic, plus, plus plus) [3][4]
18
+
19
+ ### F2 Estimation (Estimate of Second Moment)
20
+
21
+ - AMS Sketch (basic, plus, plus plus) [5]
22
+
23
+ ### Frequency Table Estimation
24
+
25
+ - Count Min Sketch [6]
26
+
27
+ ### Heavy Hitters
28
+
29
+ - Misra-Gries Sketch [7]
30
+
31
+ ### Other
32
+
33
+ - K Independent Hash Function [8]
34
+
35
+ ## :book: Bibliography
36
+
37
+ [1] Bar-Yossef, Ziv, et al. "Counting distinct elements in a data stream." Randomization and Approximation Techniques in Computer Science. Springer Berlin Heidelberg, 2002.
38
+
39
+ [2] Flajolet, Philippe, et al. "HyperLogLog: the analysis of a near-optimal cardinality estimation algorithm." Conference on Analysis of Algorithms. Springer Berlin Heidelberg, 2007.
40
+
41
+ [3] Morris, R. "Counting large numbers of events in small registers". Communications of the ACM 21, 10, 1978.
42
+
43
+ [4] Flajolet, P. "Approximate Counting: A Detailed Analysis". BIT 25, 1985.
44
+
45
+ [5] Noga Alon, Yossi Matias, Mario Szegedy,
46
+ "The Space Complexity of Approximating the Frequency Moments".
47
+ Journal of Computer and System Sciences,
48
+ Volume 58, Issue 1,
49
+ 1999.
50
+
51
+ [6] Cormode, Graham; S. Muthukrishnan. "An Improved Data Stream Summary: The Count-Min Sketch and its Applications". 2005.
52
+
53
+ [7] Misra, J.; Gries, David. "Finding repeated elements". Science of Computer Programming. 1982
54
+
55
+ [8] Wegman, Mark N., et al. "New Hash Functions and Their Use in Authentication and Set Equality". Journal of Computer and System Sciences. 1981.
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,25 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ # read the contents of your README file
4
+ from pathlib import Path
5
+ this_directory = Path(__file__).parent
6
+ long_description = (this_directory / "README.md").read_text()
7
+
8
+ setup(
9
+ name="sublinear",
10
+ version="0.1.0",
11
+ description="Python library implementing a subset of streaming algorithms. Includes variations of these algorithms (e.g. adversarially robust), as well as support for multiple data types.",
12
+ long_description_content_type='text/markdown',
13
+ long_description=long_description,
14
+ license="MIT",
15
+ author="Ivan Nikitovic",
16
+ author_email="ivan.bnikitovic@gmail.com",
17
+ url="https://github.com/ivannikitovic/sublinear",
18
+ packages=find_packages(),
19
+ python_requires=">=3.7",
20
+ include_package_data=True,
21
+ install_requires=[
22
+ 'numpy',
23
+ 'matplotlib',
24
+ ],
25
+ )
File without changes
File without changes
File without changes
@@ -0,0 +1,32 @@
1
+ from ..morris_plus_plus import MorrisPlusPlusCounter
2
+ from ..morris_plus import MorrisPlusCounter
3
+ from ..morris_basic import MorrisCounter
4
+
5
+ def test_morris():
6
+ morris = MorrisCounter()
7
+ test_stream = [i for i in range(100)]
8
+
9
+ morris.process_stream(test_stream)
10
+ estimate = morris.estimate_count()
11
+
12
+ print(f"Morris: Estimated count of elements: {estimate}")
13
+
14
+ s = 10
15
+ morris_plus = MorrisPlusCounter(s)
16
+
17
+ morris_plus.process_stream(test_stream)
18
+ estimate = morris_plus.estimate_count()
19
+
20
+ print(f"Morris+: Estimated count of elements: {estimate}")
21
+
22
+ epsilon = 0.1
23
+ delta = 0.1
24
+ morris_plus_plus = MorrisPlusPlusCounter(epsilon, delta)
25
+
26
+ morris_plus_plus.process_stream(test_stream)
27
+ estimate = morris_plus_plus.estimate_count()
28
+
29
+ print(f"Morris++: Estimated count of elements: {estimate}")
30
+
31
+ print(f"Actual count of elements: {len(test_stream)}")
32
+
@@ -0,0 +1,49 @@
1
+ import random
2
+ from typing import List
3
+
4
+ class MorrisCounter:
5
+ """
6
+ Morris Counter is a probabilistic counter for counting elements in a stream
7
+ using logarithmic space. The algorithm was proposed by Robert Morris in 1978.
8
+
9
+ Attributes
10
+ ----------
11
+ c : int
12
+ Counter value.
13
+ """
14
+
15
+ def __init__(self):
16
+ """
17
+ Initializes Morris Counter.
18
+ """
19
+ self.c = 0
20
+
21
+ def process_stream(self, stream: List[int]) -> None:
22
+ """
23
+ Processes the input data stream with the Morris Counter algorithm.
24
+
25
+ Parameters
26
+ ----------
27
+ stream : List[int]
28
+ Data stream represented as a list of integers.
29
+ """
30
+ for item in stream:
31
+ self.process()
32
+
33
+ def process(self) -> None:
34
+ """
35
+ Updates the counter value with probability 1/(2^c).
36
+ """
37
+ if random.random() < 1 / (2 ** self.c):
38
+ self.c += 1
39
+
40
+ def estimate_count(self) -> int:
41
+ """
42
+ Estimates the count of the elements in the data stream.
43
+
44
+ Returns
45
+ -------
46
+ int
47
+ Estimated count of elements in the data stream.
48
+ """
49
+ return (2 ** self.c) - 1
@@ -0,0 +1,53 @@
1
+ from typing import List
2
+ from .morris_basic import MorrisCounter
3
+
4
+ class MorrisPlusCounter:
5
+ """
6
+ Morris Plus Counter is an extension of the Morris Counter that runs multiple
7
+ Morris Counters in parallel and outputs the average of the estimates. This
8
+ improves the accuracy of the count estimate.
9
+
10
+ Attributes
11
+ ----------
12
+ s : int
13
+ Number of Morris Counters.
14
+ counters : List[MorrisCounter]
15
+ List of Morris Counters.
16
+ """
17
+
18
+ def __init__(self, s: int):
19
+ """
20
+ Initializes Morris Plus Counter.
21
+
22
+ Parameters
23
+ ----------
24
+ s : int
25
+ Number of Morris Counters.
26
+ """
27
+ self.s = s
28
+ self.counters = [MorrisCounter() for _ in range(s)]
29
+
30
+ def process_stream(self, stream: List[int]) -> None:
31
+ """
32
+ Processes the input data stream with the Morris Plus Counter algorithm.
33
+
34
+ Parameters
35
+ ----------
36
+ stream : List[int]
37
+ Data stream represented as a list of integers.
38
+ """
39
+ for item in stream:
40
+ for counter in self.counters:
41
+ counter.process()
42
+
43
+ def estimate_count(self) -> int:
44
+ """
45
+ Estimates the count of the elements in the data stream.
46
+
47
+ Returns
48
+ -------
49
+ int
50
+ Estimated count of elements in the data stream.
51
+ """
52
+ estimates = [counter.estimate_count() for counter in self.counters]
53
+ return int(sum(estimates) / self.s)
@@ -0,0 +1,61 @@
1
+ import math
2
+ import numpy as np
3
+ from typing import List
4
+
5
+ from .morris_plus import MorrisPlusCounter
6
+
7
+ class MorrisPlusPlusCounter:
8
+ """
9
+ Morris Plus Plus Counter is an extension of the Morris Plus Counter that
10
+ runs multiple Morris Plus Counters in parallel and outputs the median of
11
+ the estimates. This improves the accuracy of the count estimate further.
12
+
13
+ Attributes
14
+ ----------
15
+ s : int
16
+ Number of Morris Counters in each Morris Plus Counter.
17
+ t : int
18
+ Number of Morris Plus Counters.
19
+ counters : List[MorrisPlusCounter]
20
+ List of Morris Plus Counters.
21
+ """
22
+
23
+ def __init__(self, epsilon: float, delta: float):
24
+ """
25
+ Initializes Morris Plus Plus Counter.
26
+
27
+ Parameters
28
+ ----------
29
+ epsilon : float
30
+ Error factor.
31
+ delta : float
32
+ Confidence factor.
33
+ """
34
+ self.s = int(math.ceil(1 / (epsilon ** 2)))
35
+ self.t = int(math.ceil(math.log(1 / delta)))
36
+ self.counters = [MorrisPlusCounter(self.s) for _ in range(self.t)]
37
+
38
+ def process_stream(self, stream: List[int]) -> None:
39
+ """
40
+ Processes the input data stream with the Morris Plus Plus Counter algorithm.
41
+
42
+ Parameters
43
+ ----------
44
+ stream : List[int]
45
+ Data stream represented as a list of integers.
46
+ """
47
+ for item in stream:
48
+ for counter in self.counters:
49
+ counter.process_stream([item])
50
+
51
+ def estimate_count(self) -> int:
52
+ """
53
+ Estimates the count of the elements in the data stream.
54
+
55
+ Returns
56
+ -------
57
+ int
58
+ Estimated count of elements in the data stream.
59
+ """
60
+ estimates = [counter.estimate_count() for counter in self.counters]
61
+ return int(np.median(estimates))
@@ -0,0 +1,71 @@
1
+ from typing import List
2
+ from .bjkst_sketch import BJKSTSketch
3
+ from math import ceil, log
4
+ import statistics
5
+
6
+ class BJKSTSketchPlus:
7
+ """
8
+ The BJKST sketch with epsilon-delta approximation is a probabilistic data structure
9
+ that serves as a distinct element counter in a stream of data.
10
+
11
+ This implementation runs multiple instances of the BJKST algorithm and returns the
12
+ median of the estimates to improve the accuracy of the estimation.
13
+ """
14
+
15
+ def __init__(self, n: int, epsilon: float, delta: float, b: float = 10, max_input_length: int = 64, c: float = 576):
16
+ """
17
+ Initializes BJKSTSketchPlus class.
18
+
19
+ Parameters
20
+ ----------
21
+ Initializes BJKST Sketch class.
22
+
23
+ Parameters
24
+ ----------
25
+ n: int
26
+ Size of the input universe.
27
+
28
+ b: float
29
+ Constant factor for controlling the hash function range of g.
30
+
31
+ c: float
32
+ Constant factor for size of set B.
33
+
34
+ epsilon: float
35
+ Approximation error factor.
36
+
37
+ delta: float
38
+ Confidence level.
39
+
40
+ max_input_length: int, optional
41
+ Maximum length of the input elements, used for generating hash functions.
42
+ """
43
+ self.instances = []
44
+ self.num_instances = ceil(log(1 / delta))
45
+ for _ in range(self.num_instances):
46
+ self.instances.append(BJKSTSketch(n, epsilon, b, max_input_length=max_input_length, c=c))
47
+
48
+ def process_stream(self, stream: List[object]) -> None:
49
+ """
50
+ Executes the BJKST algorithm with epsilon-delta approximation on a stream (list) of elements.
51
+
52
+ Parameters
53
+ ----------
54
+ stream: List[object]
55
+ Stream of objects represented as a list.
56
+ """
57
+ for instance in self.instances:
58
+ instance.process_stream(stream)
59
+
60
+ def estimate_distinct_elements(self) -> int:
61
+ """
62
+ Returns the estimated number of distinct elements in the stream using the median of
63
+ the results from the multiple instances.
64
+
65
+ Returns
66
+ -------
67
+ int
68
+ Estimated number of distinct elements.
69
+ """
70
+ estimates = [instance.estimate_distinct_elements() for instance in self.instances]
71
+ return int(statistics.median(estimates))
@@ -0,0 +1,82 @@
1
+ import math
2
+ from typing import List
3
+ from sublinear.utils.hash_generator import HashGenerator
4
+ from sublinear.utils.zeros import Zeros
5
+
6
+ class BJKSTSketch:
7
+ """
8
+ The BJKST sketch is a probabilistic data structure
9
+ that serves as a distinct element counter in a stream of data.
10
+
11
+ It uses two hash functions and a set to estimate the number of distinct elements.
12
+ It operates in sub-linear space, at the expense of some approximation error.
13
+
14
+ The BJKST algorithm was invented by Bar-Yossef, Jayram, Kumar, Sivakumar, and Trevisan.
15
+ """
16
+
17
+ def __init__(self, n: int, epsilon: float, b: float = 10, max_input_length: int = 64, c: float = 576):
18
+ """
19
+ Initializes BJKST Sketch class.
20
+
21
+ Parameters
22
+ ----------
23
+ n: int
24
+ Size of the input universe.
25
+
26
+ b: float
27
+ Constant factor for controlling the hash function range of g.
28
+
29
+ c: float
30
+ Constant factor for size of set B.
31
+
32
+ epsilon: float
33
+ Approximation error factor.
34
+
35
+ max_input_length: int, optional
36
+ Maximum length of the input elements, used for generating hash functions.
37
+ """
38
+ self.n = n
39
+ self.b = b
40
+ self.c = c
41
+ self.epsilon = epsilon
42
+
43
+ self.z = 0
44
+ self.B = set()
45
+
46
+ self.h_generator = HashGenerator(self.n, max_input_length, m=n)
47
+ self.h = self.h_generator.generate_hash_function()
48
+
49
+ g_size = int(b * n * (epsilon ** (-4)) * (math.log(n) ** 2))
50
+ self.g_generator = HashGenerator(self.n, max_input_length, m=g_size)
51
+ self.g = self.g_generator.generate_hash_function()
52
+
53
+ def process_stream(self, stream: List[object]) -> None:
54
+ """
55
+ Executes the BJKST algorithm on a stream (list) of elements.
56
+
57
+ Parameters
58
+ ----------
59
+ stream: List[object]
60
+ Stream of objects represented as a list.
61
+ """
62
+ for token in stream:
63
+ h_j = self.h_generator.hash_string(token)
64
+ zeros_hj = Zeros.zeros(h_j)
65
+ if zeros_hj >= self.z:
66
+ g_j = self.g_generator.hash_string(token)
67
+ self.B.add((g_j, zeros_hj))
68
+
69
+ while len(self.B) >= self.c / (self.epsilon ** 2):
70
+ self.z += 1
71
+ self.B = {(a, b) for (a, b) in self.B if b >= self.z}
72
+
73
+ def estimate_distinct_elements(self) -> int:
74
+ """
75
+ Returns the estimated number of distinct elements in the stream.
76
+
77
+ Returns
78
+ -------
79
+ int
80
+ Estimated number of distinct elements.
81
+ """
82
+ return len(self.B) * (2 ** self.z)
@@ -0,0 +1,21 @@
1
+ # Experiment 1 (Test)
2
+
3
+ from ..bjkst_sketch import BJKSTSketch
4
+
5
+ def test_bjkst():
6
+
7
+ n = 128
8
+ epsilon = 0.1
9
+
10
+ bjkst = BJKSTSketch(n, epsilon)
11
+
12
+ test1 = []
13
+
14
+ for i in range(100):
15
+ test1 += i * [f"word{i}"]
16
+
17
+ bjkst.process_stream(test1)
18
+
19
+ estimate = bjkst.estimate_distinct_elements()
20
+
21
+ print("Estimated number of distinct elements:", estimate)
@@ -0,0 +1,22 @@
1
+ # Experiment 1 (Test)
2
+
3
+ from ..bjkst_plus import BJKSTSketchPlus
4
+
5
+ def test_bjkst_plus():
6
+
7
+ n = 128
8
+ epsilon = 0.1
9
+ delta = 0.1
10
+
11
+ bjkst_plus = BJKSTSketchPlus(n, epsilon, delta)
12
+
13
+ test1 = []
14
+
15
+ for i in range(100):
16
+ test1 += i * [f"word{i}"]
17
+
18
+ bjkst_plus.process_stream(test1)
19
+
20
+ estimate = bjkst_plus.estimate_distinct_elements()
21
+
22
+ print("Estimated number of distinct elements:", estimate)
@@ -0,0 +1,20 @@
1
+ from ..hyper_log_log import HyperLogLog
2
+ import sys
3
+
4
+ def test_hll():
5
+ hll = HyperLogLog(16) # Initialize HyperLogLog with 16-bit bucket address
6
+
7
+ num_elements = 100000
8
+
9
+ test2 = []
10
+ for i in range(num_elements):
11
+ test2 += [f"word{i}"]
12
+
13
+ for item in test2:
14
+ hll.add(item)
15
+
16
+ cardinality = hll.estimate_cardinality()
17
+
18
+ print(f"Estimated number of distinct elements: {cardinality}")
19
+
20
+ print(f"Actual number of distinct elements: {num_elements}")