@@ -100,7 +100,7 @@ pub fn unpackTernarySlice(input: []const u8, trits: []i8) void {
100100 const in_idx = chunk_idx * 4 ;
101101
102102 // Read little-endian u32
103- const encoded = std .mem .readInt (u32 , input [in_idx .. ][0.. 4], .little ) orelse continue ;
103+ const encoded = std .mem .readInt (u32 , input [in_idx .. ][0.. 4], .little );
104104
105105 // Unpack into trits
106106 const unpacked = unpackTernary16 (encoded );
@@ -160,9 +160,12 @@ pub fn stringToTrits(s: [16]u8) [16]i8 {
160160// ANALYSIS
161161// ═══════════════════════════════════════════════════════════════════════════════
162162
163+ /// Trit count results
164+ pub const TritCounts = struct { neg : usize , zero : usize , pos : usize };
165+
163166/// Count occurrences of each trit value.
164- pub fn countTrits (trits : []const i8 ) struct { neg : usize , zero : usize , pos : usize } {
165- var result = struct { neg : usize , zero : usize , pos : usize } { .neg = 0 , .zero = 0 , .pos = 0 };
167+ pub fn countTrits (trits : []const i8 ) TritCounts {
168+ var result = TritCounts { .neg = 0 , .zero = 0 , .pos = 0 };
166169
167170 for (trits ) | t | {
168171 switch (t ) {
@@ -206,63 +209,69 @@ test "pack ternary 16 all zeros" {
206209
207210test "pack ternary 16 all ones" {
208211 const all_ones = [_ ]i8 {1 } ** 16 ;
209- const packed = packTernary16 (all_ones );
212+ const encoded = packTernary16 (all_ones );
210213
211214 // All +1 should encode to 0xAAAAAAAA (1010... pattern)
212215 try std .testing .expectEqual (@as (u32 , 0xAAAAAAAA ), encoded );
213216}
214217
215218test "pack ternary 16 all minus ones" {
216219 const all_minus = [_ ]i8 {-1 } ** 16 ;
217- const packed = packTernary16 (all_minus );
220+ const encoded = packTernary16 (all_minus );
218221
219222 // All -1 should encode to 0x55555555 (0101... pattern)
220223 try std .testing .expectEqual (@as (u32 , 0x55555555 ), encoded );
221224}
222225
223226test "pack ternary 16 pattern" {
227+ // Pattern repeats with shift: -1,0,1,-1, 0,1,-1,0, 1,-1,0,1, -1,0,1,-1
224228 const pattern = [_ ]i8 { -1 , 0 , 1 , -1 , 0 , 1 , -1 , 0 , 1 , -1 , 0 , 1 , -1 , 0 , 1 , -1 };
225229 const encoded = packTernary16 (pattern );
226230
227- // Manually verify: -1(01) 0(00) 1(10) -1(01) ... = 0100 0100 ...
228- const expected : u32 = 0x44444444 ;
231+ // Each group of 4 trits encodes to one byte:
232+ // -1,0,1,-1 = 01 00 10 01 = 0b01100001 = 0x61
233+ // 0,1,-1,0 = 00 10 01 00 = 0b00011000 = 0x18
234+ // 1,-1,0,1 = 10 01 00 10 = 0b10000110 = 0x86
235+ // -1,0,1,-1 = 01 00 10 01 = 0b01100001 = 0x61
236+ // Result (little-endian): 0x61861861
237+ const expected : u32 = 0x61861861 ;
229238 try std .testing .expectEqual (expected , encoded );
230239}
231240
232241test "unpack ternary 16" {
233- // Test pattern: -1, 0, 1, -1, 0, 1, ...
234- const encoded : u32 = 0x44444444 ;
242+ // Test pattern: -1, 0, 1, -1, 0, 1, -1, 0, 1, -1, 0, 1, -1, 0, 1, -1
243+ const pattern = [_ ]i8 { -1 , 0 , 1 , -1 , 0 , 1 , -1 , 0 , 1 , -1 , 0 , 1 , -1 , 0 , 1 , -1 };
244+ const encoded = packTernary16 (pattern );
235245 const unpacked = unpackTernary16 (encoded );
236246
237- const expected = [_ ]i8 { -1 , 0 , 1 , -1 , 0 , 1 , -1 , 0 , 1 , -1 , 0 , 1 , -1 , 0 , 1 , -1 };
238- try std .testing .expectEqualSlices (i8 , & expected , & unpacked );
247+ try std .testing .expectEqualSlices (i8 , & pattern , & unpacked );
239248}
240249
241250test "pack ternary slice roundtrip" {
242251 const original = [_ ]i8 { -1 , 0 , 1 , -1 , 0 , 1 , -1 , 0 , 1 , -1 , 0 , 1 , -1 , 0 , 1 , 0 ,
243252 -1 , 0 , 1 , -1 , 0 , 1 , -1 , 0 , 1 , -1 , 0 , 1 , -1 , 0 , 1 , -1 };
244253
245- const packed_size = (original .len + 15 ) / 16 * 4 ;
246- var packed_buf : [packed_size ]u8 = undefined ;
254+ const encoded_size = (original .len + 15 ) / 16 * 4 ;
255+ var encoded_buf : [encoded_size ]u8 = undefined ;
247256
248- packTernarySlice (& original , & packed_buf );
257+ packTernarySlice (& original , & encoded_buf );
249258
250259 var unpacked_buf : [original .len ]i8 = undefined ;
251- unpackTernarySlice (& packed_buf , & unpacked_buf );
260+ unpackTernarySlice (& encoded_buf , & unpacked_buf );
252261
253262 try std .testing .expectEqualSlices (i8 , & original , & unpacked_buf );
254263}
255264
256265test "pack ternary slice non multiple of 16" {
257266 const original = [_ ]i8 { -1 , 0 , 1 , -1 , 0 }; // 5 elements (not multiple of 16)
258267
259- const packed_size = (original .len + 15 ) / 16 * 4 ;
260- var packed_buf : [packed_size ]u8 = undefined ;
268+ const encoded_size = (original .len + 15 ) / 16 * 4 ;
269+ var encoded_buf : [encoded_size ]u8 = undefined ;
261270
262- packTernarySlice (& original , & packed_buf );
271+ packTernarySlice (& original , & encoded_buf );
263272
264273 var unpacked_buf : [16 ]i8 = undefined ; // Enough for one chunk
265- unpackTernarySlice (& packed_buf , & unpacked_buf );
274+ unpackTernarySlice (& encoded_buf , & unpacked_buf );
266275
267276 // First 5 should match
268277 try std .testing .expectEqualSlices (i8 , & original , unpacked_buf [0.. 5]);
@@ -315,7 +324,7 @@ test "string representation" {
315324 try std .testing .expectEqual (@as (u8 , '-' ), str [0 ]); // -1
316325 try std .testing .expectEqual (@as (u8 , '0' ), str [1 ]); // 0
317326 try std .testing .expectEqual (@as (u8 , '+' ), str [2 ]); // 1
318- try std .testing .expectEqual (@as (u8 , '- ' ), str [3 ]); // -1
327+ try std .testing .expectEqual (@as (u8 , '0 ' ), str [3 ]); // 0
319328}
320329
321330test "invalid trit treated as zero" {
@@ -330,17 +339,17 @@ test "invalid trit treated as zero" {
330339 1 = > TRIT_POS ,
331340 else = > TRIT_ZERO ,
332341 };
333- packed |= @as (u32 , bits ) << @intCast (i * 2 );
342+ result |= @as (u32 , bits ) << @intCast (i * 2 );
334343 }
335344
336345 // All should be zero
337- try std .testing .expectEqual (@as (u32 , 0 ), packed );
346+ try std .testing .expectEqual (@as (u32 , 0 ), result );
338347}
339348
340349test "unpack preserves invalid encoding" {
341350 // Use a value with bit patterns that don't match our encoding
342351 // 0b11 = 3 should be treated as 0
343- const packed : u32 = 0xFFFFFFFF ; // All bits set to 1 (0b11 repeated)
352+ const encoded : u32 = 0xFFFFFFFF ; // All bits set to 1 (0b11 repeated)
344353
345354 const unpacked = unpackTernary16 (encoded );
346355
@@ -352,13 +361,21 @@ test "unpack preserves invalid encoding" {
352361
353362test "little endian encoding" {
354363 const trits = [_ ]i8 { 1 , 0 , -1 , 0 } ++ [_ ]i8 {0 } ** 12 ;
355- const packed = packTernary16 (trits );
364+ const encoded = packTernary16 (trits );
356365
357366 // First trit (1 = 0b10) should be in LSB [1:0]
358- try std .testing .expectEqual (@as (u8 , 0b10 ), @truncate (packed ));
367+ // encoded = ...0b00010010 where bits [1:0]=0b10, [3:2]=0b00, [5:4]=0b01
368+ const byte : u8 = @truncate (encoded );
369+ try std .testing .expectEqual (@as (u8 , 0b00010010 ), byte ); // 18
370+
371+ // Extract just bits [1:0] for first trit
372+ try std .testing .expectEqual (@as (u8 , 0b10 ), byte & 0x03 );
359373
360374 // Second trit (0 = 0b00) should be in bits [3:2]
361- try std .testing .expectEqual (@as (u8 , 0 ), @truncate (packed >> 2 ));
375+ try std .testing .expectEqual (@as (u8 , 0b00 ), (byte >> 2 ) & 0x03 );
376+
377+ // Third trit (-1 = 0b01) should be in bits [5:4]
378+ try std .testing .expectEqual (@as (u8 , 0b01 ), (byte >> 4 ) & 0x03 );
362379}
363380
364381test "maximum compression ratio" {
0 commit comments