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.
| Evento | Estado | Agenda | Mide |
|---|---|---|---|
| Llegada | N += 1; si N == 1 inicia servicio, si no encola arr | Próxima llegada t + Exp(λ); fin si inicia | Nada aún (la vida se cierra al salir) |
| Salida | N −= 1; si N > 0 el próximo encola inicia | Su 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
- 0Inicializar.
t = 0, N = 0, áreas = 0, vidas = [], FEL = [(Exp(λ), llegada)]. Semilla fija, T y parámetros en un dict.
- 1Llegada.
N += 1; agendar la siguiente; si el servidor estaba libre, sortear S e iniciar (wq = 0); si no, encolar arr.
- 2Salida.
Cerrar vida W = t − arr (y Wq = W − S); N −= 1; si queda cola, iniciar al siguiente con nuevo S.
- 3Cerrar 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
- 1Banco T = 480 min.
λ = 1/3/min, S = 2: informe (ρ, L, Wq, Little, vs M/M/1) para decidir la 2ª caja.
- 2Call center por N = 1000.
Cierre por llamadas: compara Wq media y SLA P(Wq ≤ 20 s) entre turnos.
- 3Web 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.
Motor + generadores + auditoría
L≈λW · Wq≈λ/(μ(μ−λ))
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
- Con ρ=0.5 y T=200: ¿L sim ≈ 1? ¿Error Little? ¿Wq vs 2?
- Bajá a T=30: ¿qué le pasa al error y a Wq? ¿Por qué?
- Con ρ=0.875 y T=60: ¿cierra contra teoría? ¿Qué pedirías para validar ahí?
Ver respuestas sugeridas
- Sí: L ~0.9–1.1, error ~1–3%, Wq ~1.7–2.3. Régimen manso.
- Error ~10–20% y Wq corta: arranque vacío + vidas truncadas. Remedio: T largo + warmup.
- 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.