Simulación de Eventos Discretos · Tema 38

Simulación de una cola

Del modelo matemático al experimento en Python — reloj, FEL, llegadas, salidas y auditoría en un simulador completo.

01 · Punto de partida

Todas las piezas, un solo programa

Ya tenés el reloj y el FEL (Temas 11–14), las llegadas Exp (Tema 23), los servicios Exp (Tema 24), la rutina principal (Tema 16) y las fórmulas M/M/1 con la auditoría Little (Temas 31 y 37). Este tema los suelda en el simulador completo c = 1: genera, procesa, mide y se valida solo.

Es el molde de todo lo que sigue (prioridades, redes, réplicas): si este simulador cierra, los demás son variaciones.

  • ¿Qué eventos hay y qué hace cada rutina?
  • ¿Qué estadísticas se acumulan y cuándo?
  • ¿Cómo se cierra (por T o por N) y se audita?
  • ¿Qué informe entrega un experimento serio?

02 · Definición

Motor, generadores y medición

▶

Motor

Reloj + FEL heap + rutinas de llegada/salida + condición de fin. No sabe de colas: solo procesa eventos.

~

Generadores

Próxima llegada t + Exp(λ), próximo fin t + Exp(μ). Semilla fija ⇒ corrida reproducible.

∑

Medición

Área N(t) → L; vidas fin−arr → W; ocupado → U. Little y M/M/1 las auditan.

Las dos rutinas del simulador c = 1.
EventoEstadoAgendaMide
LlegadaN += 1; si N == 1 inicia servicio, si no encola arrPróxima llegada t + Exp(λ); fin si iniciaNada aún (la vida se cierra al salir)
SalidaN −= 1; si N > 0 el próximo encola iniciaSu fin t + Exp(μ)W = t − arr, Wq = W − S del que sale

03 · El corazón: inicializar, procesar, cerrar

El esqueleto que se repite en todo el curso

inicializar→bucle de eventos→cerrar y auditar
  1. 0
    Inicializar.

    t = 0, N = 0, áreas = 0, vidas = [], FEL = [(Exp(λ), llegada)]. Semilla fija, T y parámetros en un dict.

  2. 1
    Llegada.

    N += 1; agendar la siguiente; si el servidor estaba libre, sortear S e iniciar (wq = 0); si no, encolar arr.

  3. 2
    Salida.

    Cerrar vida W = t − arr (y Wq = W − S); N −= 1; si queda cola, iniciar al siguiente con nuevo S.

  4. 3
    Cerrar y auditar.

    Área hasta T → L; vidas de completados → W; U = ocupado/T; Little y M/M/1 como jueces.

FEL con heap
heapq.heappush/pop: siempre entrega el menor tiempo en O(log n). Empate: salida antes que llegada (libera primero).
Cierre por T vs por N
Por T (horizonte) es lo realista; por N (clientes) es lo cómodo para comparar. Con T hay vidas truncadas: alargar o excluir borde.
Warmup
Descartar el arranque vacío (Tema 41): las medias se calculan en régimen, no desde t = 0.
Réplicas
Una semilla es una historia: promediar réplicas y reportar dispersión (Tema 47). El lab usa réplica fija para repetir.

Motor secuencial

Rápido para c = 1 FIFO

Arribos generados y asignación al único servidor (lo usado en labs). Equivalente, pero esconde el FEL.

Motor con FEL

Universal

El de este tema: sirve para prioridades, c > 1, redes y pérdidas sin reescribir. El que hay que dominar.

04 · Ejemplos

Tres experimentos con informe

  1. 1
    Banco T = 480 min.

    λ = 1/3/min, S = 2: informe (ρ, L, Wq, Little, vs M/M/1) para decidir la 2ª caja.

  2. 2
    Call center por N = 1000.

    Cierre por llamadas: compara Wq media y SLA P(Wq ≤ 20 s) entre turnos.

  3. 3
    Web 10k requests.

    Throughput × latencia con Little + percentil 95: dimensiona workers.

05 · Representación en Python

El simulador completo en 30 líneas

Con FEL heap de verdad: dos rutinas, áreas, vidas y U. El bloque siguiente lo audita.

Python en tu navegador. El primero simula c = 1 con FEL; el segundo audita con Little y M/M/1. Cambiá la semilla y replicá.

# Simulador M/M/1 con FEL (heap): devuelve L, W, Wq, U
import heapq, random
def sim_cola(lam, mu, T, semilla=38):
    rng = random.Random(semilla)
    FEL = [(rng.expovariate(lam), "llegada")]
    t = prev = 0.0
    N = 0
    cola, area, vidas, wqs, ocupado = [], 0.0, [], [], 0.0
    en_curso = None
    while FEL:
        t_ev, tipo = heapq.heappop(FEL)
        if t_ev > T:
            break
        area += N * (t_ev - prev)
        prev = t_ev
        t = t_ev
        if tipo == "llegada":
            N += 1
            heapq.heappush(FEL, (t + rng.expovariate(lam), "llegada"))
            if N == 1:
                S = rng.expovariate(mu)
                en_curso = (t, S)
                heapq.heappush(FEL, (t + S, "salida"))
            else:
                cola.append(t)
        else:
            arr, S = en_curso
            vidas.append(t - arr)
            wqs.append(t - arr - S)
            ocupado += S
            N -= 1
            if N > 0:
                narr = cola.pop(0)
                S2 = rng.expovariate(mu)
                en_curso = (narr, S2)
                heapq.heappush(FEL, (t + S2, "salida"))
    area += N * (T - prev)
    return {"L": area/T, "W": sum(vidas)/len(vidas), "Wq": sum(wqs)/len(wqs), "U": ocupado/T, "N": len(vidas)}

print({k: round(v, 2) for k, v in sim_cola(0.25, 0.5, 500).items()})
# Auditar: Little + M/M/1 (lam=0.25, mu=0.5, T=500)
r = sim_cola(0.25, 0.5, 500)
print(f"Little: L={r['L']:.2f} vs lamW={0.25*r['W']:.2f}")
print(f"M/M/1: Wq={r['Wq']:.2f} vs {0.25/(0.5*0.25):.2f}, U={r['U']:.2f} vs 0.50")

06 · Exploración

Laboratorio: tu simulador con perillas

El mismo motor del bloque Python (FEL + Exp) corriendo en el navegador hasta T. Movè λ, S y el horizonte T: la escalera es N(t), la línea es L teórica M/M/1 y el veredicto junta Little con la teoría. Con T = 30 verás al auditor quejarse; con T = 300, callarse.

EXPERIMENTO 38

Motor + generadores + auditoría

L≈λW · Wq≈λ/(μ(μ−λ))

Los resultados numéricos aparecen debajo.
L sim / teórica0
W sim0
Error Little0%
Wq vs teoría0

Alargá T para callar al auditor.

Escalera lima = N(t) del motor FEL; punteada = L = ρ/(1−ρ). Veredicto = Little + distancia a M/M/1.

Preguntas para explorar

  1. Con ρ=0.5 y T=200: ¿L sim ≈ 1? ¿Error Little? ¿Wq vs 2?
  2. Bajá a T=30: ¿qué le pasa al error y a Wq? ¿Por qué?
  3. Con ρ=0.875 y T=60: ¿cierra contra teoría? ¿Qué pedirías para validar ahí?
Ver respuestas sugeridas
  1. Sí: L ~0.9–1.1, error ~1–3%, Wq ~1.7–2.3. Régimen manso.
  2. Error ~10–20% y Wq corta: arranque vacío + vidas truncadas. Remedio: T largo + warmup.
  3. No: con ρ alta el régimen tarda; pedir T ≥ 300, warmup y réplicas (Temas 41–43).

07 · Comprensión

Confusiones frecuentes

«El FEL se ordena a mano cada vez»

Se usa heap (heappush/pop): ordenar la lista en cada evento es O(n log n) y propenso a empates mal resueltos.

«Simulo hasta vaciar»

Vaciar sesga a la baja (solo historias que terminan pronto). Se cierra por T u N fijo, con borde tratado, no “hasta que se vacíe”.

«Una corrida larga basta»

Una es una historia: con ρ alta, réplicas vecinas difieren mucho. Se replica con semillas y se reporta media ± dispersión.

«Si Little cierra, el modelo es correcto»

Little cierra con el modelo que programaste, no con la realidad: valida código, no supuestos (eso lo hace el dato).

08 · Práctica guiada

Ejercicios con Python

Ejercicio 1: correr y leer el dict

Corré sim_cola(0.25, 0.5, 500). ¿ρ, L, Wq? ¿Cierra con M/M/1?

# Esperado: L≈1.0, Wq≈2.0, U≈0.5 (semilla 38)
print("rho=0.5: L=1.0 Wq=2.0 W=4.0 U=0.5")
Ver solución razonada

Sí (~±5%): el motor FEL replica la teoría. Esa es la luz verde para modificarlo (prioridades, c > 1).

Ejercicio 2: acortar el horizonte

Corré con T=30 y T=500 (misma semilla). ¿Error Little en cada uno?

# Con T=30 el error ronda 10-20%; con T=500 cae a 1-3%
print("T corto: arranque + truncadas; T largo: régimen")
Ver solución

El mismo código, distinto T: la auditoría mide horizonte, no solo código. De ahí warmup y réplicas.

Ejercicio 3: informe mínimo

Escribí el informe de una corrida: parámetros + medidas + auditorías.

Ver una posible respuesta
r = sim_cola(0.4, 0.5, 500)
print(f"lam=0.4 mu=0.5 T=500 sem=38 N={r['N']}")
print(f"L={r['L']:.2f} W={r['W']:.2f} Wq={r['Wq']:.2f} U={r['U']:.2f}")

Sin (λ, μ, T, semilla, N) el número es huérfano: nadie replica ni confía.

09 · Síntesis

Ideas para recordar

  • Motor FEL + Exp(λ, μ) + áreas y vidas = experimento completo c = 1.
  • Rutinas: llegada agenda llegada (y fin si libre); salida cierra vida (e inicia al próximo).
  • Cierre por T con borde tratado; warmup y réplicas para ρ alta.
  • Doble auditoría: Little (código) + M/M/1 (modelo).
  • Informe = parámetros + (L, W, Wq, U, N) + errores: replicable o nada.

En el próximo tema torcemos el orden: colas con prioridades.