Language-U-Microscopy / zymatica_integration /svd_dct_compression.py
TheAiCollectiveART's picture
Initial release of Language U Microscopy submission framework
8554f04 verified
Raw
History Blame Contribute Delete
4.6 kB
import numpy as np
from scipy.fft import dct, idct
class TrajectoryCompressor:
"""
SVD/DCT Trajectory Compressor (Zymatica Invention 07 Adaptation).
Compresses cell trajectories (3D position sequences over time, shape T x 3)
using Singular Value Decomposition (SVD) and Discrete Cosine Transform (DCT)
to represent the spatial movement patterns compactly.
"""
def __init__(self, rank=2, k_coef=8):
self.rank = rank
self.k_coef = k_coef
def compress(self, trajectory):
"""
Compresses a T x 3 trajectory.
Returns:
compressed_dict: Dictionary containing compressed DCT coefficients and scale factors.
"""
T, D = trajectory.shape
assert D == 3, "Trajectory must be 3-dimensional (Z, Y, X)"
# Center the trajectory
mean_vector = np.mean(trajectory, axis=0)
centered_traj = trajectory - mean_vector
# Perform SVD
# U: T x 3, S: 3, Vh: 3 x 3
U, S, Vh = np.linalg.svd(centered_traj, full_matrices=False)
# Truncate to Rank
r = min(self.rank, D)
U_r = U[:, :r]
S_r = S[:r]
V_r = Vh[:r, :].T # columns are right singular vectors (D x r)
# Scale U and V by singular values
sqrt_S = np.sqrt(S_r)
U_scaled = U_r * sqrt_S
V_scaled = V_r * sqrt_S
# Compress U_scaled using DCT (since temporal trajectories are smooth)
U_dct_coefs = np.zeros((self.k_coef, r))
for col in range(r):
# Compute DCT
col_dct = dct(U_scaled[:, col], norm='ortho')
# Keep first k_coef low frequency coefficients
k_eff = min(self.k_coef, T)
U_dct_coefs[:k_eff, col] = col_dct[:k_eff]
return {
"mean": mean_vector,
"U_dct_coefs": U_dct_coefs,
"V_scaled": V_scaled,
"original_shape": (T, D)
}
def decompress(self, compressed_dict):
"""
Decompresses trajectory coefficients back to T x 3 spatial coordinates.
"""
mean_vector = compressed_dict["mean"]
U_dct_coefs = compressed_dict["U_dct_coefs"]
V_scaled = compressed_dict["V_scaled"]
T, D = compressed_dict["original_shape"]
r = U_dct_coefs.shape[1]
# Reconstruct U_scaled using IDCT
U_recon = np.zeros((T, r))
for col in range(r):
# Pad truncated coefficients with zeros
full_dct = np.zeros(T)
k_eff = min(self.k_coef, T)
full_dct[:k_eff] = U_dct_coefs[:k_eff, col]
U_recon[:, col] = idct(full_dct, norm='ortho')
# Reconstruct centered trajectory: U_recon * V_scaled.T
centered_recon = np.dot(U_recon, V_scaled.T)
# Restore mean offset
return centered_recon + mean_vector
def test_compression():
print("Testing SVD/DCT Trajectory Compressor...")
# Simulate a smooth spiral cell trajectory (T = 50 time steps)
T = 50
t = np.linspace(0, 4 * np.pi, T)
z = t * 1.5 + 5.0
y = np.sin(t) * 10.0 + 100.0
x = np.cos(t) * 10.0 + 100.0
trajectory = np.stack([z, y, x], axis=1) # T x 3
# Initialize compressor with rank 3 (retaining all 3 principal axes of motion) and k_coef 12
compressor = TrajectoryCompressor(rank=3, k_coef=12)
# Compress
compressed = compressor.compress(trajectory)
# Decompress
recon = compressor.decompress(compressed)
# Compute stats
original_size = trajectory.nbytes
# Stored floats: mean (3) + U_dct_coefs (k_coef * rank) + V_scaled (3 * rank)
stored_floats = 3 + (compressor.k_coef * compressor.rank) + (3 * compressor.rank)
compressed_size = stored_floats * 8 # float64 size
mse = np.mean((trajectory - recon) ** 2)
cosine_sim = np.dot(trajectory.flatten(), recon.flatten()) / (np.linalg.norm(trajectory) * np.linalg.norm(recon) + 1e-9)
print(f" - Original size: {original_size} bytes")
print(f" - Compressed parameters: {stored_floats} floats ({compressed_size} bytes)")
print(f" - Compression Ratio: {original_size / compressed_size:.2f}x")
print(f" - Reconstruction MSE: {mse:.4f}")
print(f" - Cosine Fidelity: {cosine_sim * 100:.2f}%")
assert mse < 1.0, "MSE reconstruction error is too high!"
assert cosine_sim > 0.999, "Fidelity is too low!"
print(" - Trajectory SVD/DCT spectral projection: PASSED")
if __name__ == "__main__":
test_compression()