#!/usr/bin/env python3
from decimal import Decimal, getcontext
import logging
from typing import List

# High-precision Decimal
getcontext().prec = 120

# Logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
logger = logging.getLogger(__name__)

class PhiCompressionInteractive:
    def __init__(self, phi: str = "1.6180339887498948482", epsilon: str = "1e-12", max_value: int = 256):
        self.PHI = Decimal(phi)
        self.EPSILON = Decimal(epsilon)
        self.MAX_VALUE = max_value
        self.log_phi = self.PHI.ln()

    def encode_sequence(self, sequence: List[int]) -> Decimal:
        """Return φ-exponent instead of φ^sum."""
        return sum(Decimal(x) for x in sequence)

    def decode_sequence(self, exponent: Decimal, seq_length: int) -> List[int]:
        """Decode φ-exponent back to original sequence."""
        sequence = []
        current_sum = exponent
        for _ in range(seq_length):
            if current_sum <= 0:
                break
            b = int(current_sum.to_integral_value(rounding="ROUND_FLOOR"))
            b = min(max(b, 0), self.MAX_VALUE - 1)
            sequence.append(b)
            current_sum -= Decimal(b)
        return sequence

    def fold_sequences(self, exponents: List[Decimal]) -> Decimal:
        """Log-space fold multiple sequences."""
        if not exponents:
            return Decimal('0')
        max_exp = max(exponents)
        sum_scaled = sum(self.PHI ** (e - max_exp) for e in exponents)
        folded_exp = max_exp + (sum_scaled).ln() / self.log_phi
        return folded_exp

    def decode_folded(self, folded_exp: Decimal, seq_lengths: List[int], passes: int = 5) -> List[List[int]]:
        """Decode folded sequences using multi-pass integer-aware log-space gradient descent."""
        residual = folded_exp
        final_estimates = [Decimal('0')] * len(seq_lengths)

        for _ in range(passes):
            estimates = self._logspace_gradient_descent(residual, seq_lengths)
            # Round estimates to nearest integer to reduce cumulative errors
            estimates = [e.to_integral_value(rounding="ROUND_HALF_UP") for e in estimates]
            folded_estimate = self.fold_sequences(estimates)
            residual = folded_exp - folded_estimate
            final_estimates = [f + e for f, e in zip(final_estimates, estimates)]

        reconstructed = [
            self.decode_sequence(e, length)
            for e, length in zip(final_estimates, seq_lengths)
        ]
        return reconstructed

    def _logspace_gradient_descent(self, target_exp: Decimal, seq_lengths: List[int]) -> List[Decimal]:
        """Adaptive gradient descent entirely in log-space with mean-based initialization."""
        N = len(seq_lengths)
        # Intelligent initialization: mean of sequence
        estimates = [Decimal(length) for length in seq_lengths]
        learning_rate = Decimal('0.05')
        max_iterations = 2000
        tolerance = Decimal('1e-10')
        best_estimates = estimates[:]
        best_error = Decimal('1e50')

        for _ in range(max_iterations):
            max_est = max(estimates)
            sum_scaled = sum(self.PHI ** (e - max_est) for e in estimates)
            lse = max_est + (sum_scaled).ln() / self.log_phi
            error = lse - target_exp
            abs_error = abs(error)

            if abs_error < best_error:
                best_error = abs_error
                best_estimates = estimates[:]

            if abs_error < tolerance:
                break

            # Gradients in log-space
            gradients = [
                error * (self.PHI ** (e - max_est) / sum_scaled)
                for e in estimates
            ]

            old_estimates = estimates[:]
            for i in range(N):
                estimates[i] -= learning_rate * gradients[i]
                estimates[i] = max(estimates[i], Decimal('0'))

            # Adaptive learning rate
            max_est_new = max(estimates)
            sum_scaled_new = sum(self.PHI ** (e - max_est_new) for e in estimates)
            lse_new = max_est_new + (sum_scaled_new).ln() / self.log_phi
            new_error = abs(lse_new - target_exp)
            if new_error > abs_error:
                learning_rate *= Decimal('0.5')
                estimates = old_estimates
            else:
                learning_rate *= Decimal('1.05')

        return best_estimates

def interactive_mode():
    compressor = PhiCompressionInteractive()
    print("Interactive PhiCompression. Enter sequences as comma-separated integers.")
    print("Example: 35,33,10 97,98 120,121,122")

    user_input = input("Enter sequences: ").strip()
    if not user_input:
        print("No input provided. Exiting.")
        return

    try:
        sequences = [
            [int(x) for x in part.strip().split(',')]
            for part in user_input.split()
        ]
    except Exception as e:
        print(f"Error parsing input: {e}")
        return

    exponents = [compressor.encode_sequence(seq) for seq in sequences]
    folded_exp = compressor.fold_sequences(exponents)
    seq_lengths = [len(seq) for seq in sequences]
    reconstructed = compressor.decode_folded(folded_exp, seq_lengths, passes=5)

    print(f"Folded exponent: {folded_exp}")
    print(f"Reconstructed sequences: {reconstructed}")

if __name__ == "__main__":
    interactive_mode()
