tiny.simd.ShardMulPlan
Defined in shardmul.
API (8)
Actions
Public operations.
Fields and members
Public fields and members.
Source
Source: lib/simd/src/shardmul.zig:154
zig
pub const ShardMulPlan = struct { best_seed: u64, key_counts: [bucket_count]usize, extra_counts: [bucket_count]usize, offsets: [bucket_count + 1]usize, slot_count: usize, scratch_len: usize, const Self = @This(); pub fn inspect(keys: []const u64, extra_outputs: []const u32) ShardMulBuildError!Self { const total = std.math.add(usize, keys.len, extra_outputs.len) catch return error.CapacityExceeded; if (total > std.math.maxInt(u32)) return error.CapacityExceeded; const engine = random.AesCtrEngine.initDeterministic(); var extra_counts: [bucket_count]usize = @splat(0); for (extra_outputs) |value| extra_counts[value >> 28] += 1; var best_seed: u64 = feistel_candidate_count; var best_ratio: f32 = std.math.inf(f32); for (0..feistel_candidate_count) |candidate| { const candidate_seed: u64 = @intCast(candidate); const shard = ShardMul.init(.{ .keys = makeFeistelKeys(&engine, candidate_seed) }); var counts = extra_counts; for (keys) |key| counts[ShardMul.bucketIndex(shard.feistel(key).left)] += 1; var minimum = counts[0]; var maximum = counts[0]; for (counts[1..]) |count| { minimum = @min(minimum, count); maximum = @max(maximum, count); } if (minimum == 0) continue; const ratio = @as(f32, @floatFromInt(maximum)) / @as(f32, @floatFromInt(minimum)); if (ratio < best_ratio) { best_ratio = ratio; best_seed = candidate_seed; } } const shard = ShardMul.init(.{ .keys = makeFeistelKeys(&engine, best_seed) }); var key_counts: [bucket_count]usize = @splat(0); for (keys) |key| key_counts[ShardMul.bucketIndex(shard.feistel(key).left)] += 1; var offsets: [bucket_count + 1]usize = @splat(0); var maximum_bucket_size: usize = 0; for (0..bucket_count) |bucket| { const bucket_size = std.math.add( usize, key_counts[bucket], extra_counts[bucket], ) catch return error.CapacityExceeded; if (bucket_size > @as(usize, 1) << 28) return error.CapacityExceeded; maximum_bucket_size = @max(maximum_bucket_size, bucket_size); offsets[bucket + 1] = std.math.add(usize, offsets[bucket], bucket_size) catch return error.CapacityExceeded; } std.debug.assert(offsets[bucket_count] == total); const slot_count = try slotsFor(maximum_bucket_size); const slot_u64 = std.math.divCeil(usize, slot_count, 2) catch unreachable; const scratch_len = std.math.add(usize, total, slot_u64) catch return error.CapacityExceeded; return .{ .best_seed = best_seed, .key_counts = key_counts, .extra_counts = extra_counts, .offsets = offsets, .slot_count = slot_count, .scratch_len = scratch_len, }; } pub fn build( self: Self, scratch: []u64, keys: []const u64, extra_outputs: []const u32, ) ShardMulBuildError!ShardMulData { if (scratch.len < self.scratch_len) return error.ScratchTooSmall; const total = std.math.add(usize, keys.len, extra_outputs.len) catch return error.CapacityExceeded; if (total != self.offsets[bucket_count]) return error.PlanMismatch; const engine = random.AesCtrEngine.initDeterministic(); const feistel_keys = makeFeistelKeys(&engine, self.best_seed); const shard = ShardMul.init(.{ .keys = feistel_keys }); const records = scratch[0..total]; const slot_bytes = std.mem.sliceAsBytes(scratch[total..self.scratch_len]); const all_slots = std.mem.bytesAsSlice(u32, slot_bytes)[0..self.slot_count]; var key_cursor = self.offsets[0..bucket_count].*; var extra_cursor: [bucket_count]usize = undefined; for (0..bucket_count) |bucket| { extra_cursor[bucket] = self.offsets[bucket] + self.key_counts[bucket]; } for (keys) |key| { const pair = shard.feistel(key); const bucket = ShardMul.bucketIndex(pair.left); if (key_cursor[bucket] >= self.offsets[bucket] + self.key_counts[bucket]) { return error.PlanMismatch; } records[key_cursor[bucket]] = encodePair(pair); key_cursor[bucket] += 1; } for (extra_outputs) |value| { const bucket = value >> 28; if (extra_cursor[bucket] >= self.offsets[bucket + 1]) return error.PlanMismatch; records[extra_cursor[bucket]] = value; extra_cursor[bucket] += 1; } for (0..bucket_count) |bucket| { if (key_cursor[bucket] != self.offsets[bucket] + self.key_counts[bucket] or extra_cursor[bucket] != self.offsets[bucket + 1]) { return error.PlanMismatch; } } var data = ShardMulData{ .keys = feistel_keys }; for (0..bucket_count) |bucket| { const bucket_size = self.key_counts[bucket] + self.extra_counts[bucket]; const slots = all_slots[0..try slotsFor(bucket_size)]; const first = self.offsets[bucket]; const key_records = records[first .. first + self.key_counts[bucket]]; const extras = records[first + self.key_counts[bucket] .. self.offsets[bucket + 1]]; for (0..max_attempts_per_bucket) |attempt| { @memset(slots, 0); var stream = random.RngStream.init( &engine, multiplierSeed(self.best_seed, bucket, attempt), ); const muls = makeMultiplierPair(&stream); var collision = false; for (key_records) |encoded| { const pair = decodePair(encoded); const output = mulAndXorScalar(pair.left, pair.right, muls); if (!insertUnique(slots, output)) { collision = true; break; } } if (!collision) { for (extras) |encoded| { if (!insertUnique(slots, @truncate(encoded))) { collision = true; break; } } } if (!collision) { data.table[bucket] = muls; data.attempts[bucket] = @intCast(attempt + 1); break; } } if (data.table[bucket] == 0) return .{}; } return data; }};Source: lib/simd/src/root.zig:624
zig
pub const ShardMulPlan = shardmul.ShardMulPlan;Complete call list for ShardMulPlan.build
13 direct calls.
tiny.simd.AesCtrEngine.initDeterministic[function] atlib/simd/src/random.zig:257tiny.simd.RngStream.init[function] atlib/simd/src/random.zig:300tiny.simd.ShardMul.bucketIndex[function] atlib/simd/src/shardmul.zig:60tiny.simd.ShardMul.feistel[method] atlib/simd/src/shardmul.zig:50tiny.simd.ShardMul.init[function] atlib/simd/src/shardmul.zig:30lib.simd.src.shardmul.decodePair[function] — private source atlib/simd/src/shardmul.zig:401in nearest public ownertiny.simd.shardmullib.simd.src.shardmul.encodePair[function] — private source atlib/simd/src/shardmul.zig:397in nearest public ownertiny.simd.shardmullib.simd.src.shardmul.insertUnique[function] — private source atlib/simd/src/shardmul.zig:381in nearest public ownertiny.simd.shardmullib.simd.src.shardmul.makeFeistelKeys[function] — private source atlib/simd/src/shardmul.zig:353in nearest public ownertiny.simd.shardmullib.simd.src.shardmul.makeMultiplierPair[function] — private source atlib/simd/src/shardmul.zig:361in nearest public ownertiny.simd.shardmullib.simd.src.shardmul.mulAndXorScalar[function] — private source atlib/simd/src/shardmul.zig:343in nearest public ownertiny.simd.shardmullib.simd.src.shardmul.multiplierSeed[function] — private source atlib/simd/src/shardmul.zig:370in nearest public ownertiny.simd.shardmullib.simd.src.shardmul.slotsFor[function] — private source atlib/simd/src/shardmul.zig:375in nearest public ownertiny.simd.shardmul
Audit
| Definitions | 3 |
|---|---|
| Public names | 6 |
| Members | 6 |
| Version | 26.7.0 |
| Revision | daab053ee433 |