demo_analytical.py 4,74 ko
Newer Older
"""
Demo script to test Jackson's theorem analytical module.

Compares analytical predictions with simulation results.
"""
from src.core.simulation import Simulator
from src.core.scenarios import get_scenario_1, get_scenario_2, get_scenario_3
from src.analytics.jackson import JacksonAnalyzer
from src.analytics.comparison import compare_results, print_comparison


def test_scenario(scenario_name: str, config):
    """Test a scenario with both analytical and simulation."""
    print("\n" + "=" * 80)
    print(f"{scenario_name}")
    print("=" * 80)

    # Analytical analysis using Jackson's theorem
    print("\n📐 ANALYTICAL ANALYSIS (Jackson's Theorem)")
    print("-" * 80)

    analyzer = JacksonAnalyzer(
        external_arrival_rate=config.arrival_rate,
        coordinator_service_rate=config.coordinator_service_rate,
        coordinator_exit_prob=config.coordinator_exit_probability,
        server_service_rates=config.server_service_rates,
        server_routing_probs=config.server_routing_probs
    )

    analytical_results = analyzer.analyze()

    # Print analytical results
    print(f"\nStability: {'✅ STABLE' if analytical_results.is_stable else '❌ UNSTABLE'}")

    print(f"\nCoordinator:")
    coord = analytical_results.coordinator
    print(f"  ρc = {coord.utilization:.4f}")
    if coord.is_stable:
        print(f"  L = {coord.average_customers:.4f} customers")
        print(f"  W = {coord.average_time:.4f} ms")

    for i, (server_id, server) in enumerate(analytical_results.servers.items()):
        print(f"\n{server_id}:")
        print(f"  ρ = {server.utilization:.4f} {'❌ UNSTABLE' if not server.is_stable else ''}")
        if server.is_stable:
            print(f"  L = {server.average_customers:.4f} customers")
            print(f"  W = {server.average_time:.4f} ms")

    if analytical_results.is_stable:
        print(f"\nSystem-Wide:")
        print(f"  Total L = {analytical_results.total_average_customers:.4f} customers")
        print(f"  Total W = {analytical_results.total_average_time:.4f} ms")

    # Simulation
    print("\n\n🎲 SIMULATION")
    print("-" * 80)

    simulator = Simulator(config)
    simulation_results = simulator.run()

    print(f"\nCoordinator:")
    coord_sim = simulation_results.coordinator_stats
    print(f"  ρc = {coord_sim['utilization']:.4f}")
    print(f"  W = {coord_sim['average_system_time']:.4f} ms")

    for server_id, server_sim in simulation_results.server_stats.items():
        print(f"\n{server_id}:")
        print(f"  ρ = {server_sim['utilization']:.4f}")
        print(f"  W = {server_sim['average_system_time']:.4f} ms")

    print(f"\nSystem-Wide:")
    print(f"  Total W = {simulation_results.average_system_time:.4f} ms")

    # Comparison
    print("\n\n📊 COMPARISON")
    print("-" * 80)

    comparison = compare_results(analytical_results, simulation_results)
    print_comparison(comparison)

    return analytical_results, simulation_results, comparison


def main():
    print("=" * 80)
    print("JACKSON'S THEOREM VALIDATION")
    print("=" * 80)
    print("\nComparing analytical predictions with simulation results...")

    # Test Scenario 1
    config1 = get_scenario_1()
    analytical1, simulation1, comparison1 = test_scenario(
        "SCENARIO 1: Single Fast Server",
        config1
    )

    # Test Scenario 2
    config2 = get_scenario_2()
    analytical2, simulation2, comparison2 = test_scenario(
        "SCENARIO 2: Fast + Slow Server",
        config2
    )

    # Test Scenario 3
    config3 = get_scenario_3()
    analytical3, simulation3, comparison3 = test_scenario(
        "SCENARIO 3: Three Slow Servers",
        config3
    )

    # Summary
    print("\n\n" + "=" * 80)
    print("VALIDATION SUMMARY")
    print("=" * 80)

    scenarios = [
        ("Scenario 1", comparison1),
        ("Scenario 2", comparison2),
        ("Scenario 3", comparison3)
    ]

    print(f"\n{'Scenario':<15} {'Total W Diff %':<20} {'Coord ρ Diff %':<20} {'Max Server ρ Diff %':<20}")
    print("-" * 80)

    for name, comp in scenarios:
        max_server_rho_diff = max(
            abs(s.utilization_diff_percent) for s in comp.servers.values()
        )
        print(f"{name:<15} {abs(comp.total_W_diff_percent):<20.2f} "
              f"{abs(comp.coordinator.utilization_diff_percent):<20.2f} "
              f"{max_server_rho_diff:<20.2f}")

    print("\n✅ Validation complete!")
    print("\nObservations:")
    print("  - Differences are expected due to statistical variation in simulation")
    print("  - Utilization typically within 10-20% (simulation has finite sample)")
    print("  - Average times can vary more for heavily loaded systems")
    print("  - Analytical assumes infinite time; simulation has warmup + finite duration")
    print("=" * 80)


if __name__ == "__main__":
    main()