from mpmath import mp

def Z_cycle_recognition(t, n_terms=1000, tolerance=1e-6):
    """
    Z(t) = Σ cos(π/4 - t*log(n)) / √n
    
    Evolve elements to recognize repeating cycle in cos().
    
    cos(θ) = cos(-θ) = cos(2πk ± θ) for integer k
    
    So cos(π/4 - t*log(n)) repeats when:
    t*log(n) differs by 2πk (integer k)
    
    Equivalently: n/m ≈ e^(2πk/t) for some k
    """
    mp.dps = 50
    t = mp.mpf(t)
    
    print(f"\n{'='*80}")
    print(f"CYCLE RECOGNITION FOR Z(t) at t = {t}")
    print(f"{'='*80}")
    
    # Store (n, argument, cos_value, phase_class)
    terms = []
    phase_groups = {}  # group terms by equivalent phase
    
    for n in range(1, n_terms + 1):
        arg = mp.pi/4 - t * mp.log(n)
        cos_val = mp.cos(arg)
        
        # Find phase equivalence class
        # Two terms are equivalent if arg differs by 2πk
        # Normalize arg to [0, 2π)
        normalized = (arg % (2 * mp.pi))
        
        # Create a key (round to tolerance)
        key = float(normalized) // tolerance * tolerance
        
        if key not in phase_groups:
            phase_groups[key] = []
        phase_groups[key].append((n, float(cos_val), float(normalized)))
        
        terms.append((n, float(arg), float(cos_val)))
    
    # Analyze cycles
    print(f"\n[1] Total terms: {n_terms}")
    print(f"[2] Unique phase classes (within tolerance {tolerance}): {len(phase_groups)}")
    
    # Group by phase
    print(f"\n[3] Phase cycle analysis:")
    
    sorted_keys = sorted(phase_groups.keys())
    for key in sorted_keys[:20]:  # Show first 20 groups
        group = phase_groups[key]
        avg_cos = sum(c[1] for c in group) / len(group)
        n_values = [c[0] for c in group]
        
        print(f"   Phase {key:.4f}π: n={n_values[:5]}{'...' if len(n_values)>5 else ''} "
              f"(×{len(group)} terms), avg_cos={avg_cos:.4f}")
    
    # Find periodic structure in n
    print(f"\n[4] Finding period in n that gives same cos():")
    
    # For each phase group with multiple terms, find ratio pattern
    for key in sorted_keys[:10]:
        group = phase_groups[key]
        if len(group) >= 2:
            n_vals = sorted([c[0] for c in group])
            ratios = [n_vals[i+1] / n_vals[i] for i in range(len(n_vals)-1)]
            avg_ratio = sum(ratios) / len(ratios)
            
            # Expected ratio from e^(2πk/t)
            # k=1 gives period: e^(2π/t)
            period = float(mp.e ** (2 * mp.pi / t))
            
            print(f"   Phase {key:.4f}: avg_n_ratio = {avg_ratio:.6f}, "
                  f"expected e^(2π/t) = {period:.6f}")
    
    # Compute Z(t) with cycle-aware grouping
    print(f"\n[5] Computing Z(t) by cycle groups:")
    
    group_sums = {}
    for key in sorted_keys:
        group = phase_groups[key]
        sum_val = sum(c[1] for c in group) / mp.sqrt(len(group))  # weighted by 1/√n averaged
        group_sums[key] = sum_val
    
    Z_approx = 2 * sum(group_sums.values())
    
    print(f"   Z(t) ≈ {Z_approx}")
    
    # Show convergence by adding cycles progressively
    print(f"\n[6] Convergence by cycle count:")
    
    cumulative = mp.mpf(0)
    for i, key in enumerate(sorted_keys[:30]):
        group = phase_groups[key]
        for n, cos_val, normalized in group:
            cumulative += 2 * cos_val / mp.sqrt(n)
        
        if (i + 1) % 5 == 0:
            print(f"   After {i+1} cycles: Z(t) = {cumulative}")
    
    return {
        'Z': Z_approx,
        'n_terms': n_terms,
        'phase_classes': len(phase_groups),
        'phase_groups': phase_groups
    }

# Run
mp.dps = 50
#result = Z_cycle_recognition(t=14.134725, n_terms=100, tolerance=0.01)
result = Z_cycle_recognition(t=1.936804, n_terms=100, tolerance=0.01)
