mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
230 lines
6.3 KiB
Python
230 lines
6.3 KiB
Python
from bitset import bitset
|
|
from range import *
|
|
import math
|
|
|
|
# Define the number of trits, quints and bits used for an encoded range, this
|
|
# table is indexed by N-1 where N is the number of elements in a range.
|
|
TRITS_QUINTS_BITS_TABLE = \
|
|
[
|
|
(0, 0, 1), # RANGE_2
|
|
(1, 0, 0), # RANGE_3
|
|
(0, 0, 2), # RANGE_4
|
|
(0, 1, 0), # RANGE_5
|
|
(1, 0, 1), # RANGE_6
|
|
(0, 0, 3), # RANGE_8
|
|
(0, 1, 1), # RANGE_10
|
|
(1, 0, 2), # RANGE_12
|
|
(0, 0, 4), # RANGE_16
|
|
(0, 1, 2), # RANGE_20
|
|
(1, 0, 3), # RANGE_24
|
|
(0, 0, 5), # RANGE_32
|
|
(0, 1, 3), # RANGE_40
|
|
(1, 0, 4), # RANGE_48
|
|
(0, 0, 6), # RANGE_64
|
|
(0, 1, 4), # RANGE_80
|
|
(1, 0, 5), # RANGE_96
|
|
(0, 0, 7), # RANGE_128
|
|
(0, 1, 5), # RANGE_160
|
|
(1, 0, 6), # RANGE_192
|
|
(0, 0, 8) # RANGE_256
|
|
]
|
|
|
|
def bits_bise_bitcount(items, bits):
|
|
"""
|
|
Compute the number of bits needed for regular binary encoding.
|
|
"""
|
|
|
|
assert items > 0 and bits > 0
|
|
return items * bits
|
|
|
|
def trits_bise_bitcount(items, bits):
|
|
"""
|
|
Compute the number of bits needed for trit-based encoding.
|
|
"""
|
|
|
|
assert items > 0 and bits >= 0
|
|
#return math.ceil((8.0 + 5.0*bits) * items / 5.0)
|
|
return math.ceil(8.0*items / 5.0 + bits*items)
|
|
|
|
def quints_bise_bitcount(items, bits):
|
|
"""
|
|
Compute the number of bits needed for quint-based encoding.
|
|
"""
|
|
|
|
assert items > 0 and bits >= 0
|
|
#return math.ceil((7.0 + 3.0*bits) * items / 3.0)
|
|
return math.ceil(7.0*items / 3.0 + bits*items)
|
|
|
|
def compute_bise_bitcount(items, quant):
|
|
"""
|
|
Compute the number of bits needed for the BISE stream.
|
|
"""
|
|
assert type(items) is int
|
|
assert type(quant) is int
|
|
assert items > 0
|
|
assert quant >= RANGE_2 and quant <= RANGE_256
|
|
|
|
trits, quints, bits = TRITS_QUINTS_BITS_TABLE[quant]
|
|
|
|
if trits == 0 and quints == 0:
|
|
return bits_bise_bitcount(items, bits)
|
|
elif trits != 0:
|
|
return trits_bise_bitcount(items, bits)
|
|
elif quints != 0:
|
|
return quints_bise_bitcount(items, bits)
|
|
else:
|
|
assert False
|
|
|
|
def last_index(lst, a):
|
|
last = -1
|
|
for i in range(len(lst)):
|
|
if a == lst[i]:
|
|
last = i
|
|
if last == -1:
|
|
raise ValueError("%s is not in the list" % repr(a))
|
|
return last
|
|
|
|
# From ASTC specification, decode the a encoded set of 5 trits.
|
|
def decode_trits(T):
|
|
assert isinstance(T, bitset)
|
|
assert T.size() == 8
|
|
|
|
t4 = -1
|
|
t3 = -1
|
|
t2 = -1
|
|
t1 = -1
|
|
|
|
C = bitset(5, 0)
|
|
if T.substr(4, 2) == bitset(3, 0b111):
|
|
C.set(4, T.get(7))
|
|
C.set(3, T.get(6))
|
|
C.set(2, T.get(5))
|
|
C.set(1, T.get(1))
|
|
C.set(0, T.get(0))
|
|
t4 = 2
|
|
t3 = 2
|
|
else:
|
|
C = T.substr(4, 0)
|
|
if T.substr(6, 5) == bitset(2, 0b11):
|
|
t4 = 2
|
|
t3 = T.get(7)
|
|
else:
|
|
t4 = T.get(7)
|
|
t3 = T.substr(6, 5).number()
|
|
|
|
if C.substr(1, 0) == bitset(2, 0b11):
|
|
t2 = 2
|
|
t1 = C.get(4)
|
|
t0 = bitset.from_args(C.get(3), C.get(2) & (not C.get(3))).number()
|
|
elif C.substr(3, 2) == bitset(2, 0b11):
|
|
t2 = 2
|
|
t1 = 2
|
|
t0 = C.substr(1, 0).number()
|
|
else:
|
|
t2 = C.get(4)
|
|
t1 = C.substr(3, 2).number()
|
|
t0 = bitset.from_args(C.get(1), C.get(0) & (not C.get(1))).number()
|
|
|
|
assert t4 >= 0 and t4 <= 2, t4
|
|
assert t3 >= 0 and t3 <= 2, t3
|
|
assert t2 >= 0 and t2 <= 2, t2
|
|
assert t1 >= 0 and t1 <= 2, t1
|
|
assert t0 >= 0 and t0 <= 2, t0
|
|
|
|
return (t0, t1, t2, t3, t4)
|
|
|
|
# From ASTC specification, decode a encoded set of 3 quints.
|
|
def decode_quints(Q):
|
|
assert Q.size() == 7
|
|
|
|
q2 = -1
|
|
q1 = -1
|
|
q0 = -1
|
|
|
|
if Q.substr(2, 1) == bitset(2, 0b11) and Q.substr(6, 5) == bitset(2, 0b00):
|
|
q2 = bitset.from_args(
|
|
Q.get(0), Q.get(4) & (not Q.get(0)), Q.get(3) & (not Q.get(0))).number()
|
|
q1 = 4
|
|
q0 = 4
|
|
else:
|
|
C = None
|
|
if Q.substr(2, 1) == bitset(2, 0b11):
|
|
q2 = 4
|
|
C = bitset.from_args(
|
|
Q.get(4),
|
|
Q.get(3),
|
|
not Q.get(6),
|
|
not Q.get(5),
|
|
Q.get(0))
|
|
else:
|
|
q2 = Q.substr(6, 5).number()
|
|
C = Q.substr(4, 0)
|
|
|
|
if C.substr(2, 0) == bitset(3, 0b101):
|
|
q1 = 4
|
|
q0 = C.substr(4, 3).number()
|
|
else:
|
|
q1 = C.substr(4, 3).number()
|
|
q0 = C.substr(2, 0).number()
|
|
|
|
assert q2 >= 0 and q2 <= 4, q2
|
|
assert q1 >= 0 and q1 <= 4, q1
|
|
assert q0 >= 0 and q0 <= 4, q0
|
|
|
|
return (q0, q1, q2)
|
|
|
|
# Generate table for trit decoding for all possible 8 bit numbers, [0, 255].
|
|
def trits_from_integer_table():
|
|
return [decode_trits(bitset(8, i)) for i in range(256)]
|
|
|
|
# Generate table for trit decoding by brute force searching the encoding table.
|
|
# Exhaustive search solution works because the search space is small.
|
|
def integer_from_trits_table(trits):
|
|
return \
|
|
[
|
|
[
|
|
[
|
|
[
|
|
[
|
|
last_index(trits, (t0, t1, t2, t3, t4))
|
|
for t0 in range(3)
|
|
]
|
|
for t1 in range(3)
|
|
]
|
|
for t2 in range(3)
|
|
]
|
|
for t3 in range(3)
|
|
]
|
|
for t4 in range(3)
|
|
]
|
|
|
|
# Generate table for quint encoding for all possible 7 bit numbers, [0, 127].
|
|
def quints_from_integer_table():
|
|
return [decode_quints(bitset(7, i)) for i in range(128)]
|
|
|
|
# Generate table for quint decoding by brute force searching the encoding
|
|
# table. Exhaustive search solution works because the search space is small.
|
|
def integer_from_quints_table(quints):
|
|
return \
|
|
[
|
|
[
|
|
[
|
|
last_index(quints, (q0, q1, q2))
|
|
for q0 in range(5)
|
|
]
|
|
for q1 in range(5)
|
|
]
|
|
for q2 in range(5)
|
|
]
|
|
|
|
if __name__ == "__main__":
|
|
trits_from_integer = trits_from_integer_table()
|
|
integer_from_trits = integer_from_trits_table(trits_from_integer)
|
|
quints_from_integer = quints_from_integer_table()
|
|
integer_from_quints = integer_from_quints_table(quints_from_integer)
|
|
|
|
print(trits_from_integer)
|
|
print(integer_from_trits)
|
|
print(quints_from_integer)
|
|
print(integer_from_quints)
|