Research-Stack/5-Applications/tools-scripts/utils/analyze_quaternary_preprocessing.py

307 lines
11 KiB
Python

#!/usr/bin/env python3
"""
Analyze effects of quaternary logic gate preprocessing on enwik9.
Implements various quaternary transformations and measures impact on compressibility.
"""
import zlib
import math
from collections import Counter
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parent
ENWIK9_PATH = REPO_ROOT / "hutter_bind_implementation" / "enwik9"
def extract_waveform(data, window_size=1024):
"""Extract waveform from data using sliding window."""
waveform = []
n_windows = len(data) // window_size
for i in range(n_windows):
window = data[i*window_size:(i+1)*window_size]
energy = sum(window)
waveform.append(energy)
return waveform
def calculate_entropy(data):
"""Calculate Shannon entropy of data."""
if not data:
return 0.0
freq = Counter(data)
total = len(data)
entropy = 0.0
for count in freq.values():
p = count / total
if p > 0:
entropy -= p * math.log2(p)
return entropy
def byte_to_quaternary(byte_val):
"""Convert a byte (0-255) to 4 quaternary digits (base-4)."""
quaternary = []
for _ in range(4):
quaternary.append(byte_val % 4)
byte_val //= 4
return quaternary[::-1] # Most significant digit first
def quaternary_to_byte(quad_digits):
"""Convert 4 quaternary digits back to a byte."""
byte_val = 0
for digit in quad_digits:
byte_val = byte_val * 4 + digit
return byte_val
def preprocess_quaternary_group(data):
"""
Preprocess: Convert bytes to quaternary digits, group by position.
This separates the 4-bit planes into separate streams.
"""
if not data:
return b''
# Separate into 4 streams (one for each quaternary position)
streams = [[], [], [], []]
for byte_val in data:
quad = byte_to_quaternary(byte_val)
for pos, digit in enumerate(quad):
streams[pos].append(digit)
# Re-encode: each stream becomes bytes (2 digits per byte)
result = bytearray()
for stream in streams:
# Pad stream to even length
if len(stream) % 2 == 1:
stream.append(0)
# Pack 2 quaternary digits per byte
for i in range(0, len(stream), 2):
packed = stream[i] * 4 + stream[i+1]
result.append(packed)
return bytes(result)
def preprocess_quaternary_transform(data, transform_type='identity'):
"""
Apply quaternary logic gate transformations.
transform_type: 'identity', 'not', 'cycle', 'invert_high'
"""
if not data:
return b''
result = bytearray()
for byte_val in data:
quad = byte_to_quaternary(byte_val)
if transform_type == 'identity':
transformed = quad
elif transform_type == 'not':
# Invert each digit (3-x)
transformed = [3 - d for d in quad]
elif transform_type == 'cycle':
# Cycle digits: [a,b,c,d] -> [b,c,d,a]
transformed = quad[1:] + [quad[0]]
elif transform_type == 'invert_high':
# Invert only high-order digits
transformed = [3 - d if i < 2 else d for i, d in enumerate(quad)]
else:
transformed = quad
# Convert back to byte
result.append(quaternary_to_byte(transformed))
return bytes(result)
def preprocess_quaternary_smooth(data):
"""
Smooth quaternary transitions by reducing high-frequency changes.
If a digit differs from previous, interpolate or clamp.
"""
if not data or len(data) < 2:
return data
result = bytearray()
prev_quad = byte_to_quaternary(data[0])
result.append(data[0])
for byte_val in data[1:]:
curr_quad = byte_to_quaternary(byte_val)
smoothed_quad = []
for i in range(4):
diff = abs(curr_quad[i] - prev_quad[i])
if diff > 1:
# Clamp to reduce large transitions
if curr_quad[i] > prev_quad[i]:
smoothed_quad.append(prev_quad[i] + 1)
else:
smoothed_quad.append(prev_quad[i] - 1)
else:
smoothed_quad.append(curr_quad[i])
# Clamp to valid range
smoothed_quad = [max(0, min(3, d)) for d in smoothed_quad]
result.append(quaternary_to_byte(smoothed_quad))
prev_quad = smoothed_quad
return bytes(result)
def analyze_preprocessing(data, method_name, preprocess_func):
"""Analyze the effect of a preprocessing method."""
print(f"\n{'=' * 60}")
print(f"Method: {method_name}")
print(f"{'=' * 60}")
# Apply preprocessing
start = time.time()
preprocessed = preprocess_func(data)
preprocess_time = time.time() - start
# Calculate metrics
original_entropy = calculate_entropy(data)
preprocessed_entropy = calculate_entropy(preprocessed)
# Compress both
original_compressed = zlib.compress(data, level=9)
preprocessed_compressed = zlib.compress(preprocessed, level=9)
# Extract waveforms
original_waveform = extract_waveform(data)
preprocessed_waveform = extract_waveform(preprocessed)
# Calculate waveform difference
if len(original_waveform) == len(preprocessed_waveform):
waveform_diff = sum(abs(a - b) for a, b in zip(original_waveform, preprocessed_waveform))
waveform_diff_norm = waveform_diff / len(original_waveform)
else:
waveform_diff = None
waveform_diff_norm = None
print(f"Original size: {len(data):,} bytes")
print(f"Preprocessed size: {len(preprocessed):,} bytes")
print(f"Size change: {len(preprocessed) / len(data):.4f}x")
print(f"\nOriginal entropy: {original_entropy:.4f} bits/byte")
print(f"Preprocessed entropy: {preprocessed_entropy:.4f} bits/byte")
print(f"Entropy change: {preprocessed_entropy - original_entropy:+.4f}")
print(f"\nOriginal compressed: {len(original_compressed):,} bytes ({len(original_compressed) / len(data):.4f}x)")
print(f"Preprocessed compressed: {len(preprocessed_compressed):,} bytes ({len(preprocessed_compressed) / len(preprocessed):.4f}x)")
print(f"Compression ratio change: {(len(preprocessed_compressed) / len(preprocessed)) / (len(original_compressed) / len(data)):+.4f}x")
print(f"\nPreprocess time: {preprocess_time:.2f}s")
print(f"Waveform difference: {waveform_diff_norm:.2f} avg energy per window" if waveform_diff_norm is not None else "Waveform difference: N/A (length mismatch)")
return {
'method': method_name,
'preprocessed_size': len(preprocessed),
'size_ratio': len(preprocessed) / len(data),
'original_entropy': original_entropy,
'preprocessed_entropy': preprocessed_entropy,
'entropy_change': preprocessed_entropy - original_entropy,
'original_compressed': len(original_compressed),
'preprocessed_compressed': len(preprocessed_compressed),
'compression_ratio_change': (len(preprocessed_compressed) / len(preprocessed)) / (len(original_compressed) / len(data)),
'preprocess_time': preprocess_time,
'waveform_diff_norm': waveform_diff_norm
}
import time
def main():
print("=" * 60)
print("Quaternary Logic Gate Preprocessing Analysis")
print("=" * 60)
# Load enwik9 (sample first 10MB for faster analysis)
print("\nLoading enwik9 (first 10MB)...")
with open(ENWIK9_PATH, "rb") as f:
data = f.read(10_000_000) # 10MB sample
print(f"Sample size: {len(data):,} bytes")
# Test different preprocessing methods
results = []
# Method 1: Quaternary grouping (separate bit planes)
results.append(analyze_preprocessing(
data,
"Quaternary Grouping (Bit Plane Separation)",
preprocess_quaternary_group
))
# Method 2: Quaternary NOT gate
results.append(analyze_preprocessing(
data,
"Quaternary NOT Gate (Digit Inversion)",
lambda d: preprocess_quaternary_transform(d, 'not')
))
# Method 3: Quaternary Cycle (rotate digits)
results.append(analyze_preprocessing(
data,
"Quaternary Cycle (Digit Rotation)",
lambda d: preprocess_quaternary_transform(d, 'cycle')
))
# Method 4: Quaternary Invert High (invert high-order digits)
results.append(analyze_preprocessing(
data,
"Quaternary Invert High (High-Order Inversion)",
lambda d: preprocess_quaternary_transform(d, 'invert_high')
))
# Method 5: Quaternary Smoothing (reduce high-frequency transitions)
results.append(analyze_preprocessing(
data,
"Quaternary Smoothing (Transition Clamping)",
preprocess_quaternary_smooth
))
# Summary
print("\n" + "=" * 60)
print("SUMMARY")
print("=" * 60)
print("{:<40} {:<12} {:<12} {:<12} {:<12}".format('Method', 'Size Ratio', 'Entropy Δ', 'Comp Δ', 'Wave Δ'))
print("-" * 88)
for r in results:
entropy_str = "{:+.4f}".format(r['entropy_change'])
comp_str = "{:+.4f}".format(r['compression_ratio_change'])
wave_str = "{:.2f}".format(r['waveform_diff_norm']) if r['waveform_diff_norm'] is not None else "N/A"
print("{:<40} {:<12.4f} {:<12} {:<12} {:<12}".format(r['method'], r['size_ratio'], entropy_str, comp_str, wave_str))
print("\n" + "=" * 60)
print("KEY INSIGHTS")
print("=" * 60)
best_compression = min(results, key=lambda x: x['compression_ratio_change'])
print(f"Best compression improvement: {best_compression['method']}")
print(f"Compression ratio change: {best_compression['compression_ratio_change']:+.4f}x")
best_entropy = min(results, key=lambda x: x['preprocessed_entropy'])
print(f"\nLowest entropy: {best_entropy['method']}")
print(f"Entropy: {best_entropy['preprocessed_entropy']:.4f} bits/byte (original: {results[0]['original_entropy']:.4f})")
best_waveform = min(results, key=lambda x: x['waveform_diff_norm'] if x['waveform_diff_norm'] is not None else float('inf'))
print(f"\nSmallest waveform change: {best_waveform['method']}")
print(f"Waveform difference: {best_waveform['waveform_diff_norm']:.2f} avg energy")
print("\n" + "=" * 60)
print("QUATERNARY LOGIC THEORY")
print("=" * 60)
print("Quaternary logic uses 4 states (0, 1, 2, 3) instead of binary's 2.")
print("Each byte (8 bits) can be represented as 4 quaternary digits (4^4 = 256).")
print("\nPotential benefits for preprocessing:")
print("1. Bit plane separation: Groups similar-position digits together")
print("2. Smoothing: Reduces high-frequency transitions")
print("3. Logic gates: Can create patterns exploitable by compressors")
print("\nPotential drawbacks:")
print("1. May increase entropy if transformation adds complexity")
print("2. May not improve standard compression (gzip, etc.)")
print("3. Requires inverse transformation for decompression")
if __name__ == "__main__":
main()