encode part done

This commit is contained in:
2026-07-07 22:00:38 +03:00
parent 6fb676978f
commit 257db7a6a2
+143 -15
View File
@@ -11,34 +11,137 @@ class Set:
"""just a bag of strings and their hash values. """just a bag of strings and their hash values.
Attributes: Attributes:
count (int): The number of elements in the set. cnt (int): The number of elements in the set.
labels (List[Tuple[str, int]]): A list of tuples, where each tuple contains a string and its corresponding hash value. labels (List[Tuple[str, int]]): A list of tuples, where each tuple contains a string and its corresponding hash value.
""" """
count: int cnt: int
labels: List[Tuple[str, int]] # List of tuples (string, hash value) labels: List[Tuple[str, int]] # List of tuples (string, hash value)
def check_bpp(bpp: int) -> bool:
"""Check if the bits per pixel (bpp) value is within the valid range."""
return 2 <= bpp <= 64
def check_Mshift(Mshift: int) -> bool:
"""Check if the Mshift value is within the valid range."""
return 1 <= Mshift <= 63
def int_to_char(value: int) -> str:
"""Convert an integer value to a base64 character."""
if 0 <= value <= 9:
return chr(value + ord("0"))
elif 10 <= value <= 35:
return chr(value - 10 + ord("a"))
elif 36 <= value <= 61:
return chr(value - 36 + ord("A"))
elif value == 62:
return "+"
elif value == 63:
return "/"
else:
raise ValueError("Value must be in the range [0, 63] for base64 encoding.")
def encode_golomb_Mshift(cnt: int, bpp: int) -> int:
"""Calculate Mshift paramter for encoding."""
Mshift = bpp - (cnt.bit_length() - 1) - 1
Mshift = max(Mshift, 1)
Mshift = min(Mshift, 63)
assert Mshift < bpp, "Mshift must be less than bpp"
return Mshift
def encode_delta(hash_values: List[int]) -> List[int]:
"""Encode the hash values into delta values."""
if not hash_values:
return []
delta_values = [hash_values[0]]
for i in range(1, len(hash_values)):
delta = hash_values[i] - hash_values[i - 1]
delta_values.append(delta)
return delta_values
def encode_golomb(delta_values: List[int], Mshift: int) -> List[int]:
"""Main golomb encoding routine: package integers into bits."""
mask = (1 << Mshift) - 1
golomb_encoded = []
for val in delta_values:
q = val >> Mshift # quotient
r = val & mask # remainder
for _ in range(q):
golomb_encoded.append(0) # "unary" part
golomb_encoded.append(1) # separator
for i in range(Mshift):
golomb_encoded.append((r >> i) & 1) # binary part
return golomb_encoded
def encode_base64(bits: List[int]) -> str:
"""Encode a list of bits into a base64 string."""
base64_chars = []
for i in range(0, len(bits), 6):
chunk = bits[i : i + 6]
while len(chunk) < 6:
chunk.append(0) # pad with zeros if necessary
value = sum(bit << (5 - j) for j, bit in enumerate(chunk))
base64_chars.append(int_to_char(value))
return "".join(base64_chars)
def encode_set(hash_values: List[int], bpp: int) -> str:
"""Encode the set of hash values into a set-string representation using base64 and Golomb coding."""
cnt = len(hash_values)
Mshift = encode_golomb_Mshift(cnt, bpp)
assert check_bpp(bpp), "bpp must be between 2 and 64"
assert check_Mshift(Mshift), "Mshift must be between 1 and 63"
delta_values = encode_delta(hash_values)
bits = encode_golomb(delta_values, Mshift)
base64_chars = encode_base64(bits)
return int_to_char(bpp) + int_to_char(Mshift) + base64_chars
def rpmsetcmp(): def rpmsetcmp():
pass pass
def set_new() -> Set: def set_new() -> Set:
"""Create a new Set instance with count initialized to 0 and an empty list of labels.""" """Create a new Set instance with cnt initialized to 0 and an empty list of labels."""
return Set(count=0, labels=[]) return Set(cnt=0, labels=[])
def set_add(set: Set, label: str) -> None: def set_add(set: Set, label: str) -> None:
"""Add a label to the set.""" """Add a label to the set."""
hash_value = hash(label) hash_value = 0
set.labels.append((label, hash_value)) set.labels.append((label, hash_value))
set.count += 1 set.cnt += 1
def set_free(set: Set) -> None: def set_free(set: Set) -> None:
"""Free the resources associated with the set.""" """Free the resources associated with the set."""
set.labels.clear() set.labels.clear()
set.count = 0 set.cnt = 0
def hash(label: str) -> int: def hash(label: str) -> int:
@@ -50,15 +153,40 @@ def hash(label: str) -> int:
def set_fini(set: Set, bpp: int) -> str | None: def set_fini(set: Set, bpp: int) -> str | None:
"""Finalize the set and return a set-string representation.""" """Finalize the set and return a set-string representation."""
if set.count < 1: if set.cnt < 1:
return None return None
# bpp < 10 in original code assert check_bpp(bpp), "bpp must be between 2 and 64"
if bpp < 2:
return None
if bpp > 64: mask = (1 << bpp) - 1
return None
# Placeholder implementation - replace with actual finalization logic # calculate hash values for each label and store them in the set
return f"Set with {set.count} elements" for i in range(set.cnt):
label, _ = set.labels[i]
computed_hash = hash(label) & mask
set.labels[i] = (label, computed_hash)
set.labels.sort(key=lambda x: x[1]) # Sort by hash value
# warn on hash collisions
for i in range(1, set.cnt):
if set.labels[i][1] == set.labels[i - 1][1]:
print(
f"Warning: Hash collision detected for labels '{set.labels[i][0]}' and '{set.labels[i - 1][0]}'"
)
hash_values = [label_hash for _, label_hash in set.labels]
encoded_string = encode_set(hash_values, bpp)
return encoded_string
if __name__ == "__main__":
# Example usage
my_set = set_new()
set_add(my_set, "example_label_1")
set_add(my_set, "example_label_2")
result = set_fini(my_set, 8)
print(result)
set_free(my_set)