#!/usr/bin/env python3
import numpy as np
import time
from backpack_binaray import backpack_binary
from backpack_annealing import backpack_annealing

def run_comparison():
    print("Detailed Comparison: Binary vs Simulated Annealing")
    print("=" * 70)
    
    # Set threshold for when to skip binary search
    BINARY_THRESHOLD = 15
    
    # Test different problem sizes
    problem_sizes = [5, 8, 10, 12, 15, 18, 20]
    
    results = []
    
    for n in problem_sizes:
        print(f"\nTesting Problem Size: {n} items")
        print("-" * 40)
        
        # Generate random test data
        np.random.seed(42)  # For reproducible results
        values = (100 * np.random.uniform(size=(n))).astype(int)
        volumes = (80 * np.random.uniform(size=(n))).astype(int)
        max_capacity = 50
        
        print(f"Values: {values}")
        print(f"Volumes: {volumes}")
        print(f"Capacity: {max_capacity}")
        
        # Run binary method (only for smaller problems due to exponential complexity)
        binary_time = 0
        binary_value = 0
        binary_selected = None
        
        if n <= BINARY_THRESHOLD:  # Only run binary for manageable sizes
            start_time = time.time()
            binary_value, binary_selected = backpack_binary(max_capacity, values, volumes)
            binary_time = time.time() - start_time
            print(f"Binary Solution:")
            print(f"  Value: {binary_value}")
            print(f"  Time: {binary_time:.6f}s")
        else:
            print(f"Binary method skipped (n > {BINARY_THRESHOLD})")
        
        # Run annealing method
        start_time = time.time()
        annealing_value, annealing_selected = backpack_annealing(
            max_capacity, values, volumes, 
            Tstart=1000, coolingRate=0.95, Niterations=10000
        )
        annealing_time = time.time() - start_time
        
        print(f"Annealing Solution:")
        print(f"  Value: {annealing_value}")
        print(f"  Time: {annealing_time:.6f}s")
        
        # Store results
        result = {
            'n': n,
            'binary_value': binary_value if n <= BINARY_THRESHOLD else None,
            'binary_time': binary_time,
            'annealing_value': annealing_value,
            'annealing_time': annealing_time,
            'binary_selected': binary_selected,
            'annealing_selected': annealing_selected
        }
        
        results.append(result)
        
        # Calculate relative performance
        if n <= BINARY_THRESHOLD:
            improvement = ((binary_value - annealing_value) / binary_value) * 100
            print(f"Relative difference: {improvement:.2f}%")
        
        # Check if solution is valid
        if n <= BINARY_THRESHOLD:
            binary_volume = np.sum(volumes * binary_selected)
            print(f"Binary capacity used: {binary_volume}/{max_capacity}")
            
        annealing_volume = np.sum(volumes * annealing_selected)
        print(f"Annealing capacity used: {annealing_volume}/{max_capacity}")
    
    # Summary statistics
    print("\n" + "=" * 70)
    print("SUMMARY")
    print("=" * 70)
    
    valid_results = [r for r in results if r['binary_value'] is not None]
    
    if valid_results:
        avg_improvement = np.mean([(r['binary_value'] - r['annealing_value']) / r['binary_value'] * 100 
                                 for r in valid_results])
        print(f"Average relative difference (Annealing vs Binary): {avg_improvement:.2f}%")
    
    # Performance comparison table with relative values
    print("\nDetailed Performance Comparison:")
    print("Problem | Binary | Annealing | Relative | Binary | Annealing | Speedup")
    print(" Size   |  Value |   Value   | Difference| Time   |   Time    |")
    print("-" * 75)
    
    for result in results:
        if result['binary_time'] > 0:
            speedup = result['binary_time'] / result['annealing_time']
            relative_diff = ((result['binary_value'] - result['annealing_value']) / result['binary_value']) * 100
            print(f"{result['n']:6d} | {result['binary_value']:6d} | {result['annealing_value']:8d} | {relative_diff:7.2f}% | {result['binary_time']:7.6f}s | {result['annealing_time']:8.6f}s | {speedup:5.2f}x")
        else:
            print(f"{result['n']:6d} |   Skipped | {result['annealing_value']:8d} |    N/A   |   Skipped  | {result['annealing_time']:8.6f}s |   N/A")

if __name__ == "__main__":
    run_comparison()
