zizek 0.1.0 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 56550f1df48e9289714d76af41df79738652c10e11109dadf88701f8d9ad8a92
4
- data.tar.gz: 3e8be13c05032b6801c870bbd652777677d023561ccf9e378d36bcc52149abb1
3
+ metadata.gz: a13245a0633d896960fb32535b0216a19220ac11945b3c64b8a6fcabb3ec0ff6
4
+ data.tar.gz: bc883a26299d4af6c9b73c3d3096d2a9373f045a7f76853afa213657c97a782c
5
5
  SHA512:
6
- metadata.gz: 8fbc8669a860b93a6471991677b38beb4221d65f60f73e0021e2c2f7f15d3f52f1d90ac80b990d1f62e0d5c431581bafa32a1ff8a114a6bc0b09debda714af0d
7
- data.tar.gz: 758527d12cc63a504bcda8f65d084b2f5ba50e571d66d5885f2b613a0d72ae9110911f25fd47d5392bbaa7d00ecd917b48f0b47a03e5cdbd533e3e0c1a6f5acf
6
+ metadata.gz: b1e1b5ad6b81eda6f9e6903fd64ee5b583b78684e893090f6c095141d59068bcef8b8165bfd176c00a496085cfa96fcac9db78682b55b6ad057c370ceb2ad4f5
7
+ data.tar.gz: 34ae7a0f7a001b1f70bdcd0b89303fe1e8d6d4892bf1dc9ede060f6b0793411c595dc0fad2b55d4545a4bfc7be0a86b843d65447aa79ce8da866acd680e76fbd
data/CHANGELOG.md CHANGED
@@ -5,7 +5,18 @@ All notable changes to the Ruby package are recorded here. The format follows
5
5
  [semantic versioning](https://semver.org/spec/v2.0.0.html) — while the version
6
6
  is `0.x`, the API may change in any release.
7
7
 
8
- ## [0.1.0] - 2026-10-27
8
+ ## [0.1.2] - 2026-10-28
9
+
10
+ ### Fixed
11
+
12
+ - Shrinking a long byte-string or text draw no longer stalls. Converting a
13
+ draw to and from its shortlex index took time roughly cubic in its length, so
14
+ a draw of about 1 KB could keep a shrink running for minutes; byte indexes are
15
+ now built and decoded in one linear pass, text indexes without full bigint
16
+ products, and two text draws compare without building either index. Shrunk
17
+ results and reproduce blobs are unchanged.
18
+
19
+ ## [0.1.1] - 2026-10-27
9
20
 
10
21
  First release of the Ruby package.
11
22
 
data/lib/zizek/gen.rb CHANGED
@@ -866,6 +866,133 @@ module Zizek
866
866
  return result
867
867
  end
868
868
 
869
+ def positive_mul_add_small_le(value_raw, factor, addend)
870
+ value = signed_abs_le(value_raw)
871
+ n = value.bytesize
872
+ i0 = 0
873
+ i1 = 1
874
+ u0 = 0
875
+ u8 = 8
876
+ u255 = 255
877
+ out = String.new(encoding: Encoding::BINARY)
878
+ carry = addend
879
+ pos = i0
880
+ loop do
881
+ done = (pos >= n)
882
+ if done
883
+ break
884
+ end
885
+ byte_ = value.getbyte(pos)
886
+ scaled = ((byte_ * factor) & MASK)
887
+ sum = ((scaled + carry) & MASK)
888
+ out_byte = (sum & u255)
889
+ out << (out_byte & 0xff)
890
+ carry = (sum >> u8)
891
+ pos = (pos + i1)
892
+ end
893
+ loop do
894
+ drained = (carry == u0)
895
+ if drained
896
+ break
897
+ end
898
+ carry_byte = (carry & u255)
899
+ out << (carry_byte & 0xff)
900
+ carry = (carry >> u8)
901
+ end
902
+ out << (u0 & 0xff)
903
+ canonical = canonicalize_signed_le(out)
904
+ return canonical
905
+ end
906
+
907
+ def small_quotient_digit(current, divisor)
908
+ u0 = 0
909
+ u1 = 1
910
+ u8 = 8
911
+ digit = u0
912
+ rest = current
913
+ bit = u8
914
+ loop do
915
+ done = (bit == u0)
916
+ if done
917
+ break
918
+ end
919
+ bit = ((bit - u1) & MASK)
920
+ step = ((divisor << bit) & MASK)
921
+ fits = (rest >= step)
922
+ if fits
923
+ rest = ((rest - step) & MASK)
924
+ place = ((u1 << bit) & MASK)
925
+ digit = (digit | place)
926
+ end
927
+ end
928
+ return digit
929
+ end
930
+
931
+ def positive_div_small_le(value_raw, divisor)
932
+ value = signed_abs_le(value_raw)
933
+ n = value.bytesize
934
+ i0 = 0
935
+ i1 = 1
936
+ u0 = 0
937
+ u8 = 8
938
+ high_first = String.new(encoding: Encoding::BINARY)
939
+ remainder = u0
940
+ pos = n
941
+ loop do
942
+ done = (pos == i0)
943
+ if done
944
+ break
945
+ end
946
+ pos = (pos - i1)
947
+ byte_ = value.getbyte(pos)
948
+ shifted = ((remainder << u8) & MASK)
949
+ current = ((shifted + byte_) & MASK)
950
+ digit = small_quotient_digit(current, divisor)
951
+ high_first << (digit & 0xff)
952
+ taken = ((digit * divisor) & MASK)
953
+ remainder = ((current - taken) & MASK)
954
+ end
955
+ out = String.new(encoding: Encoding::BINARY)
956
+ pos = n
957
+ loop do
958
+ done = (pos == i0)
959
+ if done
960
+ break
961
+ end
962
+ pos = (pos - i1)
963
+ byte_ = high_first.getbyte(pos)
964
+ out << (byte_ & 0xff)
965
+ end
966
+ out << (u0 & 0xff)
967
+ canonical = canonicalize_signed_le(out)
968
+ return canonical
969
+ end
970
+
971
+ def positive_rem_small_le(value_raw, divisor)
972
+ value = signed_abs_le(value_raw)
973
+ n = value.bytesize
974
+ i0 = 0
975
+ i1 = 1
976
+ u0 = 0
977
+ u8 = 8
978
+ remainder = u0
979
+ pos = n
980
+ loop do
981
+ done = (pos == i0)
982
+ if done
983
+ break
984
+ end
985
+ pos = (pos - i1)
986
+ byte_ = value.getbyte(pos)
987
+ shifted = ((remainder << u8) & MASK)
988
+ current = ((shifted + byte_) & MASK)
989
+ digit = small_quotient_digit(current, divisor)
990
+ taken = ((digit * divisor) & MASK)
991
+ remainder = ((current - taken) & MASK)
992
+ end
993
+ return remainder
994
+ end
995
+
869
996
  def signed_compare_le(left_raw, right_raw)
870
997
  left = canonicalize_signed_le(left_raw)
871
998
  right = canonicalize_signed_le(right_raw)
@@ -1372,34 +1499,35 @@ module Zizek
1372
1499
  def bytes_to_index(min_size, value)
1373
1500
  i0 = 0
1374
1501
  i1 = 1
1375
- base = bigint_base_256()
1376
- offset = bigint_zero()
1377
- length = min_size
1502
+ u0 = 0
1503
+ u1 = 1
1504
+ u8 = 8
1505
+ u255 = 255
1378
1506
  value_length = value.bytesize
1379
- loop do
1380
- done = (length >= value_length)
1381
- if done
1382
- break
1383
- end
1384
- exponent = (length & MASK)
1385
- bucket = positive_pow_le(base, exponent)
1386
- offset = signed_add_le(offset, bucket)
1387
- length = (length + i1)
1388
- end
1389
- position = bigint_zero()
1507
+ last = (value_length - i1)
1508
+ out = String.new(encoding: Encoding::BINARY)
1509
+ carry = u0
1390
1510
  pos = i0
1391
1511
  loop do
1392
1512
  done = (pos >= value_length)
1393
1513
  if done
1394
1514
  break
1395
1515
  end
1396
- byte_ = value.getbyte(pos)
1397
- digit = positive_u8_le(byte_)
1398
- shifted = signed_mul_le(position, base)
1399
- position = signed_add_le(shifted, digit)
1516
+ mirror = (last - pos)
1517
+ digit = value.getbyte(mirror)
1518
+ sum = ((digit + carry) & MASK)
1519
+ in_offset = (pos >= min_size)
1520
+ if in_offset
1521
+ sum = ((sum + u1) & MASK)
1522
+ end
1523
+ out_byte = (sum & u255)
1524
+ out << (out_byte & 0xff)
1525
+ carry = (sum >> u8)
1400
1526
  pos = (pos + i1)
1401
1527
  end
1402
- index = signed_add_le(offset, position)
1528
+ out << (carry & 0xff)
1529
+ out << (u0 & 0xff)
1530
+ index = canonicalize_signed_le(out)
1403
1531
  return index
1404
1532
  end
1405
1533
 
@@ -1424,49 +1552,99 @@ module Zizek
1424
1552
  def bytes_from_index(min_size, max_size, index_raw)
1425
1553
  i0 = 0
1426
1554
  i1 = 1
1427
- base = bigint_base_256()
1428
- remaining = signed_abs_le(index_raw)
1429
- length = min_size
1555
+ u0 = 0
1556
+ u1 = 1
1557
+ u8 = 8
1558
+ u255 = 255
1559
+ u256 = 256
1560
+ index = signed_abs_le(index_raw)
1561
+ index_n = index.bytesize
1562
+ significant = index_n
1430
1563
  loop do
1431
- past_end = (length > max_size)
1432
- if past_end
1564
+ none_left = (significant == i0)
1565
+ if none_left
1433
1566
  break
1434
1567
  end
1435
- exponent = (length & MASK)
1436
- bucket = positive_pow_le(base, exponent)
1437
- bucket_cmp = signed_compare_le(remaining, bucket)
1438
- inside_bucket = (bucket_cmp < i0)
1439
- if inside_bucket
1440
- out = String.new(encoding: Encoding::BINARY)
1441
- empty = (length == i0)
1442
- if empty
1443
- some_empty = out.dup
1444
- return some_empty
1568
+ top_pos = (significant - i1)
1569
+ top = index.getbyte(top_pos)
1570
+ top_set = (top != u0)
1571
+ if top_set
1572
+ break
1573
+ end
1574
+ significant = top_pos
1575
+ end
1576
+ length = min_size
1577
+ past_min = (significant > min_size)
1578
+ if past_min
1579
+ length = significant
1580
+ pos = significant
1581
+ loop do
1582
+ done = (pos == i0)
1583
+ if done
1584
+ break
1445
1585
  end
1446
- power = (length - i1)
1447
- power_u64 = (power & MASK)
1448
- divisor = positive_pow_le(base, power_u64)
1449
- pos = i0
1450
- loop do
1451
- done = (pos >= length)
1452
- if done
1453
- break
1454
- end
1455
- digit = positive_div_le_nonzero(remaining, divisor)
1456
- byte_ = digit.getbyte(i0)
1457
- out << (byte_ & 0xff)
1458
- remaining = positive_rem_le_nonzero(remaining, divisor)
1459
- divisor = positive_div_le_nonzero(divisor, base)
1460
- pos = (pos + i1)
1586
+ pos = (pos - i1)
1587
+ index_byte = index.getbyte(pos)
1588
+ offset_byte = u0
1589
+ in_offset = (pos >= min_size)
1590
+ if in_offset
1591
+ offset_byte = u1
1592
+ end
1593
+ below = (index_byte < offset_byte)
1594
+ if below
1595
+ length = (significant - i1)
1596
+ break
1597
+ end
1598
+ above = (index_byte > offset_byte)
1599
+ if above
1600
+ break
1461
1601
  end
1462
- some = out.dup
1463
- return some
1464
1602
  end
1465
- remaining = signed_sub_le(remaining, bucket)
1466
- length = (length + i1)
1467
1603
  end
1468
- none = nil
1469
- return none
1604
+ past_end = (length > max_size)
1605
+ if past_end
1606
+ none = nil
1607
+ return none
1608
+ end
1609
+ low_first = String.new(encoding: Encoding::BINARY)
1610
+ borrow = u0
1611
+ pos = i0
1612
+ loop do
1613
+ done = (pos >= length)
1614
+ if done
1615
+ break
1616
+ end
1617
+ index_byte = u0
1618
+ present = (pos < index_n)
1619
+ if present
1620
+ index_byte = index.getbyte(pos)
1621
+ end
1622
+ subtrahend = borrow
1623
+ in_offset = (pos >= min_size)
1624
+ if in_offset
1625
+ subtrahend = ((subtrahend + u1) & MASK)
1626
+ end
1627
+ lifted = ((index_byte + u256) & MASK)
1628
+ difference = ((lifted - subtrahend) & MASK)
1629
+ out_byte = (difference & u255)
1630
+ low_first << (out_byte & 0xff)
1631
+ kept = (difference >> u8)
1632
+ borrow = ((u1 - kept) & MASK)
1633
+ pos = (pos + i1)
1634
+ end
1635
+ out = String.new(encoding: Encoding::BINARY)
1636
+ pos = length
1637
+ loop do
1638
+ done = (pos == i0)
1639
+ if done
1640
+ break
1641
+ end
1642
+ pos = (pos - i1)
1643
+ byte_ = low_first.getbyte(pos)
1644
+ out << (byte_ & 0xff)
1645
+ end
1646
+ some = out.dup
1647
+ return some
1470
1648
  end
1471
1649
 
1472
1650
  def f64_abs(value)
@@ -5953,9 +6131,11 @@ module Zizek
5953
6131
  u0 = 0
5954
6132
  u1 = 1
5955
6133
  u2 = 2
6134
+ u4 = 4
6135
+ u8 = 8
6136
+ u255 = 255
5956
6137
  length = string_length(value)
5957
- best = u0
5958
- found = false
6138
+ ranks = String.new(encoding: Encoding::BINARY)
5959
6139
  at = i0
5960
6140
  loop do
5961
6141
  done = (at >= length)
@@ -5965,9 +6145,37 @@ module Zizek
5965
6145
  codepoint = string_codepoint_at(value, at)
5966
6146
  index = alphabet_index_of(alphabet, codepoint)
5967
6147
  present = !index.nil?
6148
+ stored = u0
5968
6149
  if present
5969
6150
  index_value = index
5970
6151
  rank = alphabet_shrink_rank(alphabet, index_value)
6152
+ stored = ((rank + u1) & MASK)
6153
+ end
6154
+ stored_byte = u0
6155
+ loop do
6156
+ packed_all = (stored_byte == u4)
6157
+ if packed_all
6158
+ break
6159
+ end
6160
+ stored_low = (stored & u255)
6161
+ ranks << (stored_low & 0xff)
6162
+ stored = (stored >> u8)
6163
+ stored_byte = ((stored_byte + u1) & MASK)
6164
+ end
6165
+ at = (at + i1)
6166
+ end
6167
+ best = u0
6168
+ found = false
6169
+ at = i0
6170
+ loop do
6171
+ done = (at >= length)
6172
+ if done
6173
+ break
6174
+ end
6175
+ stored = string_codepoint_at(ranks, at)
6176
+ present = (stored != u0)
6177
+ if present
6178
+ rank = ((stored - u1) & MASK)
5971
6179
  lowerable = (rank != u0)
5972
6180
  improves = (rank > best)
5973
6181
  not_found = (!found)
@@ -5981,15 +6189,13 @@ module Zizek
5981
6189
  if counted
5982
6190
  break
5983
6191
  end
5984
- other_codepoint = string_codepoint_at(value, other)
5985
- other_index = alphabet_index_of(alphabet, other_codepoint)
5986
- other_present = !other_index.nil?
5987
- if other_present
5988
- other_index_value = other_index
5989
- other_rank = alphabet_shrink_rank(alphabet, other_index_value)
5990
- same = (other_rank == rank)
5991
- if same
5992
- seen = ((seen + u1) & MASK)
6192
+ other_stored = string_codepoint_at(ranks, other)
6193
+ same = (other_stored == stored)
6194
+ if same
6195
+ seen = ((seen + u1) & MASK)
6196
+ twice = (seen >= u2)
6197
+ if twice
6198
+ break
5993
6199
  end
5994
6200
  end
5995
6201
  other = (other + i1)
@@ -6075,19 +6281,23 @@ module Zizek
6075
6281
  none_past = nil
6076
6282
  return none_past
6077
6283
  end
6284
+ i4 = 4
6285
+ whole = (length * i4)
6286
+ drop_start = (position * i4)
6287
+ drop_end = (drop_start + i4)
6078
6288
  out = String.new(encoding: Encoding::BINARY)
6079
6289
  at = i0
6080
6290
  loop do
6081
- done = (at >= length)
6291
+ done = (at >= whole)
6082
6292
  if done
6083
6293
  break
6084
6294
  end
6085
- dropped = (at == position)
6086
- kept = (!dropped)
6295
+ before = (at < drop_start)
6296
+ after = (at >= drop_end)
6297
+ kept = (before || after)
6087
6298
  if kept
6088
- codepoint = string_codepoint_at(value, at)
6089
- packed_ = u32_to_le(codepoint)
6090
- out = append_bytes(out, packed_)
6299
+ byte_ = value.getbyte(at)
6300
+ out << (byte_ & 0xff)
6091
6301
  end
6092
6302
  at = (at + i1)
6093
6303
  end
@@ -6099,20 +6309,30 @@ module Zizek
6099
6309
  i0 = 0
6100
6310
  i1 = 1
6101
6311
  u0 = 0
6312
+ u1 = 1
6102
6313
  size = alphabet_size(alphabet)
6103
- base = u64_to_bigint_le(size)
6104
6314
  count = string_length(value)
6105
6315
  offset = bigint_zero()
6106
- length = min_size
6107
- loop do
6108
- done = (length >= count)
6109
- if done
6110
- break
6316
+ has_offset = (count > min_size)
6317
+ if has_offset
6318
+ length = min_size
6319
+ loop do
6320
+ done = (length >= count)
6321
+ if done
6322
+ break
6323
+ end
6324
+ offset = positive_mul_add_small_le(offset, size, u1)
6325
+ length = (length + i1)
6326
+ end
6327
+ scale = i0
6328
+ loop do
6329
+ done = (scale >= min_size)
6330
+ if done
6331
+ break
6332
+ end
6333
+ offset = positive_mul_add_small_le(offset, size, u0)
6334
+ scale = (scale + i1)
6111
6335
  end
6112
- exponent = (length & MASK)
6113
- bucket = positive_pow_le(base, exponent)
6114
- offset = signed_add_le(offset, bucket)
6115
- length = (length + i1)
6116
6336
  end
6117
6337
  position = bigint_zero()
6118
6338
  pos = i0
@@ -6129,15 +6349,79 @@ module Zizek
6129
6349
  alphabet_index = found
6130
6350
  rank = alphabet_shrink_rank(alphabet, alphabet_index)
6131
6351
  end
6132
- digit = u64_to_bigint_le(rank)
6133
- shifted = signed_mul_le(position, base)
6134
- position = signed_add_le(shifted, digit)
6352
+ position = positive_mul_add_small_le(position, size, rank)
6135
6353
  pos = (pos + i1)
6136
6354
  end
6137
6355
  index = signed_add_le(offset, position)
6138
6356
  return index
6139
6357
  end
6140
6358
 
6359
+ def string_index_compare(alphabet, min_size, left, right)
6360
+ i0 = 0
6361
+ i1 = 1
6362
+ u0 = 0
6363
+ negative_one = (i0 - i1)
6364
+ size = alphabet_size(alphabet)
6365
+ left_count = string_length(left)
6366
+ right_count = string_length(right)
6367
+ has_members = (size != u0)
6368
+ left_sized = (left_count >= min_size)
6369
+ right_sized = (right_count >= min_size)
6370
+ both_sized = (left_sized && right_sized)
6371
+ direct = (has_members && both_sized)
6372
+ indirect = (!direct)
6373
+ if indirect
6374
+ left_index = string_to_index(alphabet, min_size, left)
6375
+ right_index = string_to_index(alphabet, min_size, right)
6376
+ order = signed_compare_le(left_index, right_index)
6377
+ return order
6378
+ end
6379
+ left_shorter = (left_count < right_count)
6380
+ if left_shorter
6381
+ return negative_one
6382
+ end
6383
+ left_longer = (left_count > right_count)
6384
+ if left_longer
6385
+ return i1
6386
+ end
6387
+ pos = i0
6388
+ loop do
6389
+ done = (pos >= left_count)
6390
+ if done
6391
+ break
6392
+ end
6393
+ left_codepoint = string_codepoint_at(left, pos)
6394
+ right_codepoint = string_codepoint_at(right, pos)
6395
+ differs = (left_codepoint != right_codepoint)
6396
+ if differs
6397
+ left_found = alphabet_index_of(alphabet, left_codepoint)
6398
+ left_present = !left_found.nil?
6399
+ left_rank = u0
6400
+ if left_present
6401
+ left_alphabet_index = left_found
6402
+ left_rank = alphabet_shrink_rank(alphabet, left_alphabet_index)
6403
+ end
6404
+ right_found = alphabet_index_of(alphabet, right_codepoint)
6405
+ right_present = !right_found.nil?
6406
+ right_rank = u0
6407
+ if right_present
6408
+ right_alphabet_index = right_found
6409
+ right_rank = alphabet_shrink_rank(alphabet, right_alphabet_index)
6410
+ end
6411
+ rank_less = (left_rank < right_rank)
6412
+ if rank_less
6413
+ return negative_one
6414
+ end
6415
+ rank_greater = (left_rank > right_rank)
6416
+ if rank_greater
6417
+ return i1
6418
+ end
6419
+ end
6420
+ pos = (pos + i1)
6421
+ end
6422
+ return i0
6423
+ end
6424
+
6141
6425
  def string_max_index(alphabet, min_size, max_size)
6142
6426
  i0 = 0
6143
6427
  i1 = 1
@@ -6176,64 +6460,102 @@ module Zizek
6176
6460
  def string_from_index(alphabet, min_size, max_size, index_raw)
6177
6461
  i0 = 0
6178
6462
  i1 = 1
6463
+ i8 = 8
6179
6464
  u0 = 0
6465
+ u1 = 1
6466
+ u2 = 2
6467
+ u4 = 4
6468
+ u8 = 8
6469
+ u255 = 255
6180
6470
  size = alphabet_size(alphabet)
6181
6471
  no_members = (size == u0)
6182
6472
  if no_members
6183
6473
  none = nil
6184
6474
  return none
6185
6475
  end
6186
- base = u64_to_bigint_le(size)
6187
6476
  remaining = signed_abs_le(index_raw)
6477
+ remaining_n = remaining.bytesize
6478
+ remaining_bits = (remaining_n * i8)
6479
+ narrow = (remaining_bits <= min_size)
6480
+ several = (size >= u2)
6481
+ first_bucket = (narrow && several)
6482
+ bucket = bigint_one()
6483
+ build_bucket = (!first_bucket)
6484
+ if build_bucket
6485
+ scale = i0
6486
+ loop do
6487
+ done = (scale >= min_size)
6488
+ if done
6489
+ break
6490
+ end
6491
+ bucket = positive_mul_add_small_le(bucket, size, u0)
6492
+ scale = (scale + i1)
6493
+ end
6494
+ end
6188
6495
  length = min_size
6189
6496
  loop do
6190
6497
  past_end = (length > max_size)
6191
6498
  if past_end
6192
6499
  break
6193
6500
  end
6194
- exponent = (length & MASK)
6195
- bucket = positive_pow_le(base, exponent)
6196
6501
  bucket_cmp = signed_compare_le(remaining, bucket)
6197
6502
  inside_bucket = (bucket_cmp < i0)
6503
+ inside_bucket = (inside_bucket || first_bucket)
6198
6504
  if inside_bucket
6199
- out = String.new(encoding: Encoding::BINARY)
6200
- empty = (length == i0)
6201
- if empty
6202
- some_empty = out.dup
6203
- return some_empty
6204
- end
6205
- power = (length - i1)
6206
- power_u64 = (power & MASK)
6207
- divisor = positive_pow_le(base, power_u64)
6505
+ ranks = String.new(encoding: Encoding::BINARY)
6208
6506
  pos = i0
6209
6507
  loop do
6210
6508
  done = (pos >= length)
6211
6509
  if done
6212
6510
  break
6213
6511
  end
6214
- digit = positive_div_le_nonzero(remaining, divisor)
6215
- digit_u64 = bigint_to_u64_le(digit)
6216
- digit_fits = !digit_u64.nil?
6217
- rank = u0
6218
- if digit_fits
6219
- rank = digit_u64
6512
+ rank = positive_rem_small_le(remaining, size)
6513
+ rank_byte = u0
6514
+ loop do
6515
+ packed_all = (rank_byte == u4)
6516
+ if packed_all
6517
+ break
6518
+ end
6519
+ rank_low = (rank & u255)
6520
+ ranks << (rank_low & 0xff)
6521
+ rank = (rank >> u8)
6522
+ rank_byte = ((rank_byte + u1) & MASK)
6523
+ end
6524
+ remaining = positive_div_small_le(remaining, size)
6525
+ pos = (pos + i1)
6526
+ end
6527
+ out = String.new(encoding: Encoding::BINARY)
6528
+ pos = length
6529
+ loop do
6530
+ done = (pos == i0)
6531
+ if done
6532
+ break
6220
6533
  end
6534
+ pos = (pos - i1)
6535
+ rank = string_codepoint_at(ranks, pos)
6221
6536
  found = alphabet_shrink_codepoint(alphabet, rank)
6222
6537
  present = !found.nil?
6223
6538
  codepoint = u0
6224
6539
  if present
6225
6540
  codepoint = found
6226
6541
  end
6227
- packed_ = u32_to_le(codepoint)
6228
- out = append_bytes(out, packed_)
6229
- remaining = positive_rem_le_nonzero(remaining, divisor)
6230
- divisor = positive_div_le_nonzero(divisor, base)
6231
- pos = (pos + i1)
6542
+ codepoint_byte = u0
6543
+ loop do
6544
+ packed_all = (codepoint_byte == u4)
6545
+ if packed_all
6546
+ break
6547
+ end
6548
+ codepoint_low = (codepoint & u255)
6549
+ out << (codepoint_low & 0xff)
6550
+ codepoint = (codepoint >> u8)
6551
+ codepoint_byte = ((codepoint_byte + u1) & MASK)
6552
+ end
6232
6553
  end
6233
6554
  some = out.dup
6234
6555
  return some
6235
6556
  end
6236
6557
  remaining = signed_sub_le(remaining, bucket)
6558
+ bucket = positive_mul_add_small_le(bucket, size, u0)
6237
6559
  length = (length + i1)
6238
6560
  end
6239
6561
  none = nil
data/lib/zizek/shell.rb CHANGED
@@ -1635,6 +1635,12 @@ module Zizek
1635
1635
 
1636
1636
  next
1637
1637
  end
1638
+ order = string_draws_compare(candidate_draw, current_draw)
1639
+ unless order.nil?
1640
+ return order unless order.zero?
1641
+
1642
+ next
1643
+ end
1638
1644
  candidate_index = draw_sort_index(candidate_draw)
1639
1645
  current_index = draw_sort_index(current_draw)
1640
1646
  return 1 if candidate_index.nil? || current_index.nil?
@@ -1645,6 +1651,22 @@ module Zizek
1645
1651
  0
1646
1652
  end
1647
1653
 
1654
+ # Order two string draws of one alphabet and minimum size by index, nil
1655
+ # for any other pair. The core compares them without building either
1656
+ # index; a long string's index is too costly to build for every shrink
1657
+ # candidate.
1658
+ def string_draws_compare(candidate, current)
1659
+ return nil unless candidate.kind == :string && current.kind == :string
1660
+
1661
+ characters, minimum, = candidate.params
1662
+ return nil unless current.params[0] == characters && current.params[1] == minimum
1663
+
1664
+ Core.string_index_compare(
1665
+ characters, minimum,
1666
+ Shell.pack_codepoints(candidate.value), Shell.pack_codepoints(current.value)
1667
+ )
1668
+ end
1669
+
1648
1670
  # Rebuild a draw at a schedule index, or report a miss.
1649
1671
  #
1650
1672
  # The rebuilt draw keeps its key: a lowered candidate that lost its name
@@ -1722,43 +1744,22 @@ module Zizek
1722
1744
  Core.choice_list_header(draws.length) + draws.map { |draw| Shell.entry(draw) }.join
1723
1745
  end
1724
1746
 
1725
- class ChoiceTree
1747
+ # Every choice stream a run has executed, so a mutation that would only
1748
+ # repeat one is skipped. Membership is of whole streams, never of
1749
+ # prefixes: a trie with a node per byte answered the same questions while
1750
+ # holding megabytes for each long example until the run ended. Streams are
1751
+ # keyed as binary strings, so equal bytes are equal keys.
1752
+ class StreamSet
1726
1753
  def initialize
1727
- @terminal = false
1728
- @children = {}
1729
- end
1730
-
1731
- def include?(path)
1732
- node = self
1733
- path.each_byte do |byte|
1734
- node = node.child(byte)
1735
- return false if node.nil?
1736
- end
1737
- node.terminal?
1738
- end
1739
-
1740
- def insert(path)
1741
- node = self
1742
- path.each_byte { |byte| node = node.child_or_insert(byte) }
1743
- node.mark_terminal
1744
- end
1745
-
1746
- protected
1747
-
1748
- def child(byte)
1749
- @children[byte]
1750
- end
1751
-
1752
- def child_or_insert(byte)
1753
- @children[byte] ||= ChoiceTree.new
1754
+ @streams = {}
1754
1755
  end
1755
1756
 
1756
- def terminal?
1757
- @terminal
1757
+ def include?(stream)
1758
+ @streams.key?(stream.b)
1758
1759
  end
1759
1760
 
1760
- def mark_terminal
1761
- @terminal = true
1761
+ def insert(stream)
1762
+ @streams[stream.b] = true
1762
1763
  end
1763
1764
  end
1764
1765
 
@@ -2593,7 +2594,7 @@ module Zizek
2593
2594
  # Consecutive executed mutation requests; the schedule caps it at one
2594
2595
  # brood so fresh random generation keeps its share of the run.
2595
2596
  mutation_streak = 0
2596
- choice_tree = Shell::ChoiceTree.new
2597
+ seen_streams = Shell::StreamSet.new
2597
2598
  # Per-label best score and the stream that produced it, for the targeting
2598
2599
  # hill climber. The schedule, budgets, record and accept rules, stepping,
2599
2600
  # and the step-size search are all compiled (ir/targeting.zir); this loop
@@ -2655,7 +2656,7 @@ module Zizek
2655
2656
  else
2656
2657
  attempts += 1
2657
2658
  error, trial_case = Shell.execute(property, rng: rng, replay: stream)
2658
- choice_tree.insert(trial_case.__send__(:serialized))
2659
+ seen_streams.insert(trial_case.__send__(:serialized))
2659
2660
  if error.nil?
2660
2661
  valid += 1
2661
2662
  record_targets.call(trial_case)
@@ -2811,9 +2812,9 @@ module Zizek
2811
2812
  simplest_probe = request == 1
2812
2813
  mutation_probe = request == 2
2813
2814
  mutation = mutation_probe ? pending_mutations.shift : nil
2814
- novelty = Core.generation_novelty_action(request, mutation_probe && choice_tree.include?(mutation))
2815
+ novelty = Core.generation_novelty_action(request, mutation_probe && seen_streams.include?(mutation))
2815
2816
  next if novelty.zero?
2816
- choice_tree.insert(mutation) if novelty == 2
2817
+ seen_streams.insert(mutation) if novelty == 2
2817
2818
  attempts += 1
2818
2819
  mutation_streak = mutation_probe ? mutation_streak + 1 : 0
2819
2820
  error, test_case = Shell.execute(
@@ -2822,7 +2823,7 @@ module Zizek
2822
2823
  replay: mutation,
2823
2824
  simplest: simplest_probe
2824
2825
  )
2825
- choice_tree.insert(test_case.__send__(:serialized))
2826
+ seen_streams.insert(test_case.__send__(:serialized))
2826
2827
  generation_us = [((1 << 64) - 1), generation_us + test_case.__send__(:generation_us)].min
2827
2828
  outcome = Shell.classify(error)
2828
2829
  if Core.health_large_base_example(
data/lib/zizek/version.rb CHANGED
@@ -4,5 +4,5 @@ module Zizek
4
4
  # The gemspec reads this file directly, so it must stay free of requires:
5
5
  # loading the rest of the package to learn the version would drag the
6
6
  # generated core into every `gem build`.
7
- VERSION = "0.1.0"
7
+ VERSION = "0.1.2"
8
8
  end
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zizek
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
- - waldemar.quevedo@gmail.com
7
+ - Waldemar Quevedo
8
8
  bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z