probabilistic_machines 0.1.1-aarch64-linux

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4dcf59b83144e678d83452a03c86846d5295254a1062439beaf8ea6cf0e86e83
4
+ data.tar.gz: 072644da326d2be1f1aa9f1f2d74b7040db8a9672b9932f38ef054ee84287d10
5
+ SHA512:
6
+ metadata.gz: eb7669530fdf0f8d02f4db4f72b93139393d300de14031aa4e83a54410a427009d58531b4f1d79baf25a869406876bff873413bbedf95f23322e6ba1c747ff24
7
+ data.tar.gz: fa4c46cc6e900de7368d6ec5e559eb87726a319a64c8e077c3464d36226fe9362dafd09a420db2d8a0fdc9e26a1c85a8e5c2894e3e55c90a77e638cb0926d831
data/CHANGELOG.md ADDED
@@ -0,0 +1,58 @@
1
+ # Changelog
2
+
3
+ ## [0.1.1](https://github.com/seuros/probabilistic_machines/compare/probabilistic_machines-v0.1.0...probabilistic_machines/v0.1.1) (2026-11-01)
4
+
5
+
6
+ ### Features
7
+
8
+ * HeavyHitters codec and an infallible exact-size encode ([1cf9442](https://github.com/seuros/probabilistic_machines/commit/1cf944208e191f1cc7847221239204e14f0ad9a9))
9
+ * probabilistic data structures in no_std Rust ([e8c9711](https://github.com/seuros/probabilistic_machines/commit/e8c97117a19e39ecfb2eff588724d9bd3d33be48))
10
+ * Ruby gem and magnus FFI for the five structures ([83144bd](https://github.com/seuros/probabilistic_machines/commit/83144bd4553f2ea51fd8437ab966142b50122cec))
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * a loaded t-digest honours the compression its constructor requires ([dae877e](https://github.com/seuros/probabilistic_machines/commit/dae877eb1161dfc16f5238329c8c6fdd4b1c78e5))
16
+ * a source install can build, and a failed gem push fails the release ([4b18e42](https://github.com/seuros/probabilistic_machines/commit/4b18e42a9b4c7d6264cc3cc9f685e0cb597de409))
17
+ * a zero cluster budget spun the t-digest fold loop forever ([8f4f146](https://github.com/seuros/probabilistic_machines/commit/8f4f1466ca579a943d8a23aec4075b53314e3824))
18
+ * expose and persist count-min saturation ([0ac83ac](https://github.com/seuros/probabilistic_machines/commit/0ac83ac77d02ddee5d7614d73e95e5d103e823e8))
19
+ * fold t-digest clusters without overflowing their span ([2e33539](https://github.com/seuros/probabilistic_machines/commit/2e33539b0dbcc0eb8d288eedc936c0ece8d7f7bd))
20
+ * interpolate a subnormal t-digest span without underflowing it ([1b05f4e](https://github.com/seuros/probabilistic_machines/commit/1b05f4e5515fa4468730bec3708daf8f57052726))
21
+ * interpolate the t-digest cdf without overflowing the span ([48cd8a1](https://github.com/seuros/probabilistic_machines/commit/48cd8a11f1b2fdd56403af46614fd6a56b8b8309))
22
+ * keep t-digest total weight finite and the cluster count bounded ([0a37d4b](https://github.com/seuros/probabilistic_machines/commit/0a37d4b52cd5a0abd7de862fe0f52e4f987c956e))
23
+ * refuse a fractional compression too ([379c001](https://github.com/seuros/probabilistic_machines/commit/379c0012d2e5c21131ec8b9fb92534e796997be9))
24
+ * refuse a fractional count instead of truncating it to zero ([0b88ae8](https://github.com/seuros/probabilistic_machines/commit/0b88ae8204ebbb761e8aab42df3e7d014501d135))
25
+ * reject a compression a t-digest cannot honour ([f53e07b](https://github.com/seuros/probabilistic_machines/commit/f53e07b3af5377565253e14c7327b90c9975eb95))
26
+ * reject a hyperloglog rank its precision cannot reach ([c41210b](https://github.com/seuros/probabilistic_machines/commit/c41210b66ccfc305240244fcf151990ea317392e))
27
+ * reject a t-digest frame that lost whole clusters ([2e7e0b5](https://github.com/seuros/probabilistic_machines/commit/2e7e0b5594ff14297d98cb5c32380beed1f8192a))
28
+ * reject a t-digest frame whose total weight cannot exist ([4bdf21f](https://github.com/seuros/probabilistic_machines/commit/4bdf21fa69949159aa30a8d400a8c7d11e64fbf1))
29
+ * reject count-min counters its total cannot explain ([4413fe9](https://github.com/seuros/probabilistic_machines/commit/4413fe965cfdad617f46d9f2f2720e13a3aee6d0))
30
+ * reject heavy-hitter records no stream could leave ([3a4172e](https://github.com/seuros/probabilistic_machines/commit/3a4172e730fd7c46b06d39bde2ef2c6034be19d4))
31
+ * ship the core's test files so the packaged crate builds ([b567b39](https://github.com/seuros/probabilistic_machines/commit/b567b39144fd403f92efcb7ac48120be228d3b6f))
32
+ * t-digest overflow and NaN, and report count-min saturation ([f3aa87c](https://github.com/seuros/probabilistic_machines/commit/f3aa87c018465de0618125b3f2f84e6848e57f37))
33
+ * the t-digest arithmetic builds without std ([8009555](https://github.com/seuros/probabilistic_machines/commit/800955549c872ff7db8d257fbe63b18d326c1aa2))
34
+ * validate HLL registers on decode, and the same hash collision ([496c077](https://github.com/seuros/probabilistic_machines/commit/496c0771f9a2c06766c1296c7123ea3b6bd7f4ae))
35
+ * widen heavy-hitter bounds for what a merged table evicted ([41b0a9c](https://github.com/seuros/probabilistic_machines/commit/41b0a9c33f7433b915f448820628604c107d1cad))
36
+
37
+ ## 0.1.0
38
+
39
+ - Initial release.
40
+ - `ProbabilisticMachines::HyperLogLog`: distinct counts in 1024, 4096, 16384 or
41
+ 65536 registers, with `merge` for union and `standard_error` for the bound.
42
+ - `ProbabilisticMachines::CountMinSketch`: per-item frequencies in a width of
43
+ 1024, 4096 or 16384 by a depth of 4 or 8.
44
+ - `ProbabilisticMachines::TDigest`: quantiles and CDF from clusters, with a
45
+ runtime compression.
46
+ - `ProbabilisticMachines::CuckooFilter`: membership that can forget, in 1024,
47
+ 4096, 16384 or 65536 buckets, raising `ProbabilisticMachines::Full` when a
48
+ fingerprint has nowhere to go.
49
+ - `ProbabilisticMachines::HeavyHitters`: Space-Saving top-k over 16, 64 or 256
50
+ counters, returning `Hitter` objects that carry the overestimate.
51
+ - `dump`/`load` round-trip every sketch through the byte format of the
52
+ `probabilistic-machines` crate. A `HeavyHitters` blob is the crate's frame
53
+ followed by the extension's key table, so the tracked strings survive a
54
+ restart instead of loading back as hashes.
55
+ - RBS signatures for the whole public API.
56
+ - The `probabilistic-machines` crate codes `HeavyHitters<u64, K>`, and with
57
+ `alloc` hands every structure's frame back from `encoded` instead of filling
58
+ a caller's buffer, with `decode_into` to read one back in place.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Abdelkader Boudih
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
13
+ all 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
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,203 @@
1
+ # ProbabilisticMachines 🔭
2
+
3
+ > **Survey the whole stream on a fixed fuel budget.** The tender that answers how
4
+ > many, how often and how extreme without carrying the cargo it measured.
5
+
6
+ Distinct counts, quantiles and frequencies in memory you pick up front.
7
+
8
+ Counting exactly means keeping every key: a `Set` of user ids, a `Hash` of path
9
+ counts, an array of latencies to sort. These five structures answer the same
10
+ questions from state that was sized at construction time and never grows.
11
+ **AMS Flajolet** takes a reading and discards the sample, which is why its hold
12
+ is the same size on the way home as it was at launch.
13
+
14
+ ---
15
+
16
+ ## 🚀 Launch Sequence
17
+
18
+ ```ruby
19
+ require 'probabilistic_machines'
20
+
21
+ visitors = ProbabilisticMachines::HyperLogLog.new(registers: 4096) # 4 KiB
22
+ 50_000.times { |id| visitors.add("user-#{id % 12_000}") }
23
+
24
+ visitors.estimate # => 12_361.2
25
+ visitors.standard_error # => 0.01625
26
+ ```
27
+
28
+ ---
29
+
30
+ ## 🔩 The Native Extension Is Required
31
+
32
+ There is no pure-Ruby fallback and no `DISABLE_*` switch. HyperLogLog, Count-Min
33
+ Sketch, t-digest, cuckoo hashing and Space-Saving are five algorithms, and a
34
+ second implementation would mean maintaining each of them twice, with two sets
35
+ of accuracy tests and two byte formats to keep in step. The gem is a binding to
36
+ the `probabilistic-machines` crate in `ext/probabilistic_machines_native/core`,
37
+ and it needs Ruby 4.0 and a Rust toolchain (or a platform gem).
38
+
39
+ ---
40
+
41
+ ## 📐 Sizes Are a Fixed Menu
42
+
43
+ The crate sizes every structure by a const generic, so each size is a separately
44
+ compiled type. The extension carries these and raises `ArgumentError` for
45
+ anything else:
46
+
47
+ | Class | Keyword | Values |
48
+ | ---------------- | -------------------- | ----------------------------- |
49
+ | `HyperLogLog` | `registers:` | 1024, 4096, 16384, 65536 |
50
+ | `CountMinSketch` | `width:` by `depth:` | 1024, 4096 by 4 or 8 |
51
+ | `CuckooFilter` | `buckets:` | 1024, 4096, 16384, 65536 |
52
+ | `HeavyHitters` | `k:` | 16, 64, 256 |
53
+ | `TDigest` | `compression:` | any, it is a runtime argument |
54
+
55
+ ```ruby
56
+ ProbabilisticMachines::HyperLogLog.new(registers: 3000)
57
+ # ArgumentError: registers 3000 is not supported, expected one of [1024, 4096, 16384, 65536]
58
+ ```
59
+
60
+ ---
61
+
62
+ ## 🌌 How Many Distinct
63
+
64
+ ```ruby
65
+ hll = ProbabilisticMachines::HyperLogLog.new(registers: 4096)
66
+ hll.add('user-1')
67
+ hll.add_hash(0x9e37_79b9_7f4a_7c15) # for streams that ship hashes, not keys
68
+ hll.estimate # Float
69
+ hll.standard_error # 1.04 / sqrt(registers)
70
+ hll.merge(other) # exact union
71
+ ```
72
+
73
+ Memory is one byte per register, so 4096 registers cost 4 KiB whether the stream
74
+ held ten ids or ten billion.
75
+
76
+ ---
77
+
78
+ ## 📊 How Often Each
79
+
80
+ ```ruby
81
+ cms = ProbabilisticMachines::CountMinSketch.new(width: 4096, depth: 4)
82
+ cms.add('/login', count: 3)
83
+ cms.count('/login') # never below the truth
84
+ cms.total # every count added
85
+ cms.merge(other) # exact sum
86
+ ```
87
+
88
+ A count is over the truth by at most `e * total / width`, with probability
89
+ `1 - e ** -depth` of staying inside it. Width buys accuracy, depth buys
90
+ confidence.
91
+
92
+ ---
93
+
94
+ ## 📏 Quantiles
95
+
96
+ ```ruby
97
+ td = ProbabilisticMachines::TDigest.new(compression: 100)
98
+ td.add(12.5)
99
+ td.add(12.5, weight: 1_000.0) # one point standing for a thousand observations
100
+ td.quantile(0.99)
101
+ td.cdf(12.5)
102
+ td.centroids # Array of frozen Centroid(mean:, weight:)
103
+ td.minimum # exact, as is maximum
104
+ td.merge(other)
105
+ ```
106
+
107
+ A quantile is off by about `1 / compression` of the distribution in the middle
108
+ and is exact at the extremes, in `compression * ln(n)` clusters rather than `n`
109
+ samples. An empty digest answers `Float::NAN`.
110
+
111
+ ---
112
+
113
+ ## 🛰️ Have I Seen This Contact Before
114
+
115
+ ```ruby
116
+ cf = ProbabilisticMachines::CuckooFilter.new(buckets: 4096)
117
+ cf.insert('device-9') # raises ProbabilisticMachines::Full when wedged
118
+ cf.include?('device-9') # contains? is the same question
119
+ cf.remove('device-9') # unlike a Bloom filter, it can forget
120
+ ```
121
+
122
+ `buckets * 4` items in `buckets * 4` bytes. Never a false negative; about 3%
123
+ false positives. Only remove items you inserted, or you take a colliding item's
124
+ fingerprint with it. A cuckoo filter cannot merge, so there is no `merge` here.
125
+
126
+ ---
127
+
128
+ ## 👑 Who Dominates the Stream
129
+
130
+ ```ruby
131
+ hh = ProbabilisticMachines::HeavyHitters.new(k: 64)
132
+ hh.add('10.0.0.1')
133
+ hh.add('10.0.0.1', count: 5)
134
+ hh.top(10) # [Hitter(key:, count:, overestimate:), ...] most frequent first
135
+ hh.ranked # every tracked key
136
+ hh.observed # observations fed in
137
+ hh.merge(other)
138
+ ```
139
+
140
+ After `n` observations every key seen more than `n / k` times is tracked, in `k`
141
+ counters and no heap per key. A counter can inherit the count of the key it
142
+ evicted, or what a merged-in table's own evictions may have hidden, so the true
143
+ count lies between `count - overestimate` and `count`.
144
+
145
+ Keys are UTF-8 strings here: Space-Saving needs `Copy + Eq` keys in Rust, so the
146
+ table counts 64-bit key hashes and the extension keeps the string each tracked
147
+ hash came from, to hand back from `top` and `ranked`. The other four classes
148
+ take any byte string.
149
+
150
+ ---
151
+
152
+ ## 📦 Transmitting a Reading
153
+
154
+ `dump` returns the crate's own byte frame, `load` reads one back. The frame
155
+ names its own shape, so `load` needs no keyword and rejects a blob written with
156
+ a size this build does not carry. It also reads the frame's fields against each
157
+ other and refuses a state no stream could have left behind, so an edited blob
158
+ raises instead of handing back a sketch that counts more than it ever saw.
159
+
160
+ ```ruby
161
+ blob = hll.dump # binary String
162
+ ProbabilisticMachines::HyperLogLog.load(blob)
163
+ ProbabilisticMachines::TDigest.load(blob) # ArgumentError: codec: wrong structure tag
164
+ ```
165
+
166
+ Anything that reads the crate reads these frames, so an embedded device can ship
167
+ a sketch a Rails app folds in. `HeavyHitters` is the one blob that is not purely
168
+ the crate's: the crate's frame counts 64-bit key hashes, so the extension appends
169
+ its key table after it, one record of a 64-bit byte length and that many UTF-8
170
+ bytes per tracked key. `load` rehashes each name, and rejects a blob whose key
171
+ table is malformed or does not name every key the frame tracks.
172
+
173
+ ```ruby
174
+ restored = ProbabilisticMachines::HeavyHitters.load(hh.dump)
175
+ restored.top(1).first.key # => '10.0.0.1', the string, not its hash
176
+ ```
177
+
178
+ ---
179
+
180
+ ## ⚙️ The Rust Core
181
+
182
+ The sketches themselves are the `probabilistic-machines` crate under
183
+ `ext/probabilistic_machines_native/core`: `no_std`, zero dependencies, allocating
184
+ only for `TDigest` and for the `encoded` frames this extension dumps, and
185
+ verified on bare metal. The binding crate beside it under
186
+ `ffi/` is the Ruby surface and is not published.
187
+
188
+ ---
189
+
190
+ ## 📡 Credits
191
+
192
+ **AMS Flajolet**, NCC-0185, *Flajolet*-class tender.
193
+
194
+ Named for Philippe Flajolet and G. Nigel Martin's *Probabilistic Counting
195
+ Algorithms for Data Base Applications* (1985), and for Flajolet, Fusy, Gandouet
196
+ and Meunier's *HyperLogLog* (2007), which established that you can count what
197
+ you refuse to store.
198
+
199
+ ---
200
+
201
+ ## License
202
+
203
+ MIT.
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'ffi/extconf'
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ProbabilisticMachines
4
+ VERSION = '0.1.1'
5
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'probabilistic_machines/version'
4
+
5
+ # Every class, the two `Data` result objects and both error classes are defined
6
+ # by the native extension; there is no pure-Ruby implementation to fall back to.
7
+ require 'probabilistic_machines_native/probabilistic_machines_native'
@@ -0,0 +1,182 @@
1
+ # Sketches that answer a counting question in memory fixed at construction
2
+ # time. Every class here is defined by the native extension.
3
+ module ProbabilisticMachines
4
+ VERSION: String
5
+
6
+ class Error < StandardError
7
+ end
8
+
9
+ # Raised when a cuckoo filter has nowhere left to put a fingerprint.
10
+ class Full < Error
11
+ end
12
+
13
+ # A tracked key and its counter. The true count lies in
14
+ # `count - overestimate` through `count`.
15
+ class Hitter < ::Data
16
+ attr_reader key: String
17
+ attr_reader count: Integer
18
+ attr_reader overestimate: Integer
19
+ end
20
+
21
+ # One cluster of a digest: the mean of the values that collapsed into it.
22
+ class Centroid < ::Data
23
+ attr_reader mean: Float
24
+ attr_reader weight: Float
25
+ end
26
+
27
+ # Distinct counts in a fixed register array.
28
+ class HyperLogLog
29
+ # `registers` is 1024, 4096, 16384 or 65536.
30
+ def self.new: (registers: Integer) -> instance
31
+
32
+ def self.load: (String blob) -> instance
33
+
34
+ def registers: () -> Integer
35
+ def add: (String item) -> nil
36
+
37
+ # For streams that ship 64-bit hashes instead of keys.
38
+ def add_hash: (Integer hash) -> nil
39
+
40
+ def estimate: () -> Float
41
+
42
+ # Relative standard error of the estimate, `1.04 / sqrt(registers)`.
43
+ def standard_error: () -> Float
44
+
45
+ def empty?: () -> bool
46
+
47
+ # Unions `other` in. Raises `ArgumentError` on a different register count.
48
+ def merge: (HyperLogLog other) -> self
49
+
50
+ def dump: () -> String
51
+ def inspect: () -> String
52
+ end
53
+
54
+ # How often each item was seen, in `width * depth` counters.
55
+ class CountMinSketch
56
+ # `width` is 1024 or 4096; `depth` is 4 or 8.
57
+ def self.new: (width: Integer, depth: Integer) -> instance
58
+
59
+ def self.load: (String blob) -> instance
60
+
61
+ def width: () -> Integer
62
+ def depth: () -> Integer
63
+ def add: (String item, ?count: Integer) -> nil
64
+
65
+ # Never below the true count, and over it by at most
66
+ # `e * total / width` with probability `1 - e ** -depth`.
67
+ def count: (String item) -> Integer
68
+
69
+ # Sum of every count added.
70
+ def total: () -> Integer
71
+ def saturated?: () -> bool
72
+
73
+ # Sums `other` in. Raises `ArgumentError` on a different shape.
74
+ def merge: (CountMinSketch other) -> self
75
+
76
+ def dump: () -> String
77
+ def inspect: () -> String
78
+ end
79
+
80
+ # Quantiles of a stream, in clusters instead of samples.
81
+ class TDigest
82
+ def self.new: (compression: Integer) -> instance
83
+
84
+ def self.load: (String blob) -> instance
85
+
86
+ def compression: () -> Integer
87
+ def add: (Float value, ?weight: Float) -> nil
88
+
89
+ # Value at quantile `q`, `Float::NAN` when empty.
90
+ def quantile: (Float q) -> Float
91
+
92
+ # Fraction of the stream at or below `value`, `Float::NAN` when empty.
93
+ def cdf: (Float value) -> Float
94
+
95
+ # Total weight added.
96
+ def count: () -> Float
97
+
98
+ # Smallest value added, `Float::INFINITY` when empty.
99
+ def minimum: () -> Float
100
+
101
+ # Largest value added, `-Float::INFINITY` when empty.
102
+ def maximum: () -> Float
103
+
104
+ # Clusters currently held.
105
+ def size: () -> Integer
106
+
107
+ def empty?: () -> bool
108
+ def centroids: () -> Array[Centroid]
109
+ def merge: (TDigest other) -> self
110
+ def dump: () -> String
111
+ def inspect: () -> String
112
+ end
113
+
114
+ # Membership that can forget, in `buckets * 4` fingerprints.
115
+ class CuckooFilter
116
+ # `buckets` is 1024, 4096, 16384 or 65536.
117
+ def self.new: (buckets: Integer) -> instance
118
+
119
+ def self.load: (String blob) -> instance
120
+
121
+ def buckets: () -> Integer
122
+
123
+ # Fingerprint slots in the table, `buckets * 4`.
124
+ def capacity: () -> Integer
125
+
126
+ # Raises `Full` when the item has nowhere to go.
127
+ def insert: (String item) -> bool
128
+
129
+ # Never false for an item that was inserted; true for one that was not
130
+ # with probability about 3%.
131
+ def include?: (String item) -> bool
132
+
133
+ alias contains? include?
134
+
135
+ # Only for items that were inserted: removing an item that merely collides
136
+ # with one takes the other item's fingerprint with it.
137
+ def remove: (String item) -> bool
138
+
139
+ def size: () -> Integer
140
+ def empty?: () -> bool
141
+ def dump: () -> String
142
+ def inspect: () -> String
143
+ end
144
+
145
+ # Which keys dominate a stream, in `k` counters instead of one per key.
146
+ class HeavyHitters
147
+ # `k` is 16, 64 or 256.
148
+ def self.new: (k: Integer) -> instance
149
+
150
+ def self.load: (String blob) -> instance
151
+
152
+ def k: () -> Integer
153
+
154
+ # Keys are UTF-8 strings, so `top` and `ranked` can hand them back.
155
+ def add: (String key, ?count: Integer) -> nil
156
+
157
+ # Upper bound on how often `key` occurred, 0 when it is not tracked.
158
+ def count: (String key) -> Integer
159
+
160
+ # Observations fed in.
161
+ def observed: () -> Integer
162
+
163
+ # Keys currently tracked, at most `k`.
164
+ def size: () -> Integer
165
+
166
+ def empty?: () -> bool
167
+
168
+ # The `n` most frequent tracked keys, most frequent first.
169
+ def top: (Integer n) -> Array[Hitter]
170
+
171
+ # Every tracked key, most frequent first.
172
+ def ranked: () -> Array[Hitter]
173
+
174
+ # Folds `other` in. Raises `ArgumentError` on a different `k`.
175
+ def merge: (HeavyHitters other) -> self
176
+
177
+ # The crate's frame followed by the key table that carries the strings.
178
+ def dump: () -> String
179
+
180
+ def inspect: () -> String
181
+ end
182
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: probabilistic_machines
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: aarch64-linux
6
+ authors:
7
+ - Abdelkader Boudih
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-11-01 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: HyperLogLog, Count-Min Sketch, t-digest, cuckoo filter and Space-Saving
14
+ top-k, bound to Ruby from the no_std probabilistic-machines crate. Each sketch answers
15
+ a counting question in memory fixed at construction time, and serialises to a byte
16
+ string other languages reading the same crate can decode.
17
+ email:
18
+ - oss@seuros.com
19
+ executables: []
20
+ extensions: []
21
+ extra_rdoc_files: []
22
+ files:
23
+ - CHANGELOG.md
24
+ - LICENSE.txt
25
+ - README.md
26
+ - ext/probabilistic_machines_native/extconf.rb
27
+ - lib/probabilistic_machines.rb
28
+ - lib/probabilistic_machines/version.rb
29
+ - lib/probabilistic_machines_native/probabilistic_machines_native.so
30
+ - sig/probabilistic_machines.rbs
31
+ homepage: https://github.com/seuros/probabilistic_machines
32
+ licenses:
33
+ - MIT
34
+ metadata:
35
+ source_code_uri: https://github.com/seuros/probabilistic_machines
36
+ changelog_uri: https://github.com/seuros/probabilistic_machines/blob/main/CHANGELOG.md
37
+ bug_tracker_uri: https://github.com/seuros/probabilistic_machines/issues
38
+ rubygems_mfa_required: 'true'
39
+ cargo_crate_name: probabilistic_machines_native
40
+ cargo_manifest_path: ext/probabilistic_machines_native/ffi/Cargo.toml
41
+ post_install_message:
42
+ rdoc_options: []
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '4.0'
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: 4.1.dev
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubygems_version: 3.5.23
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: Distinct counts, quantiles and frequencies in bounded memory
63
+ test_files: []