01 · Punto de partida
El papel pegado en la heladera del simulador
A las 10:00 el banco sabe dos cosas del futuro: llegará uno a las 10:02 y otro a las 10:04. Ese papel con futuros ordenados es el calendario. A las 10:02 tacha la primera línea, atiende, y agrega una nueva: “salida a las 10:05”. El papel siempre dice “lo próximo”.
Sin ese papel, el reloj no sabría a dónde saltar (Tema 11) y el avance por eventos sería imposible (Tema 12). El calendario es el contrato entre el presente y el futuro: todo lo que el simulador hará ya está escrito allí, ordenado por hora.
- ¿Qué futuros están anunciados ahora mismo?
- ¿Cuál es el próximo y cuánto falta para él?
- ¿Qué nuevos futuros agrega el evento actual?
- ¿Qué significa que el papel quede en blanco?
02 · Definición
Orden, mínimo y vida dinámica
Orden total
Siempre ordenado por (tiempo, prioridad). El primero es “lo próximo” por definición, no por suerte.
Mínimo manda
Solo importa el primero: el reloj salta a él y la rutina lo procesa. El resto espera su turno.
Vivo
Cada evento extraído puede agendar 0, 1 o más futuros (llegada agenda próxima llegada + eventual salida).
| Operación | Qué hace | Ejemplo |
|---|---|---|
| Agendar | Inserta un futuro con su hora | “Salida a las 10:05” tras iniciar |
| Extraer mínimo | Saca y devuelve lo próximo | Tacha “llegada 10:02” y la procesa |
| Ver próximo | Mira sin sacar (para decidir fin) | “Lo próximo es a las 10:04, sigo” |
| Vacío | No hay futuro anunciado | Se acabaron llegadas y servicios: fin |
03 · Traza viva
El calendario respira en cada evento
Banco con llegadas en 2 y 4, atención S=3, 1 caja. Mirá cómo el calendario se achica por arriba y crece por abajo:
| Reloj | Se extrae | Se agenda | Calendario después |
|---|---|---|---|
| 0 | — (inicializa) | llegadas 2 y 4 | [2:L, 4:L] |
| 2 | llegada | salida 5 (caja libre) | [4:L, 5:S] |
| 4 | llegada | nada (caja ocupada → a cola) | [5:S] |
| 5 | salida | salida 8 (sigue el de la cola) | [8:S] |
| 8 | salida | nada | [] → fin |
- Invariante de orden
- Tras cada operación el calendario sigue ordenado. Si se rompe, “lo próximo” deja de serlo y la causalidad cae.
- Empates con prioridad
- Mismo tiempo → decide la prioridad (0 salida antes que 1 llegada) y luego un contador FIFO. Sin regla, el orden es azar del programa.
- Cancelación
- A veces hay que borrar un futuro (cliente que abandona, falla que invalida una salida). El calendario debe poder quitar, no solo agregar.
- Calendario vs. FEL
- El calendario es el concepto (la agenda); la FEL es la estructura que lo implementa (heap en Python). Este tema define el qué; el 14 el cómo.
04 · Ejemplos
Qué agenda cada sistema
| Sistema | Futuros anunciados | Quién los agenda |
|---|---|---|
| Banco 1 caja | Próxima llegada, fin en curso | Llegada / inicio |
| Web 8 workers | Próximo arribo, 8 fines en curso | Arribo / asignaciones |
| Inventario | Próxima demanda, arribo de pedido | Demanda / emisión de pedido |
| Taller 2 máquinas | Fines en A y B, próxima llegada | Inicios en cada máquina |
05 · Representación en Python
La agenda como lista ordenada
Para entender el concepto alcanza una lista ordenada con sort: se agrega, se ordena, se saca el primero. (En el Tema 14 la haremos eficiente con heapq.)
Python en tu navegador. El primer bloque opera la agenda; el segundo muestra la traza del banco. Agregá un evento y mirá dónde cae.
cal = [(4.0, "llegada"), (2.0, "llegada")]
cal.sort() # invariante: ordenado
proximo = cal.pop(0) # extraer mínimo
print("atiendo:", proximo, "| quedan:", cal)
cal.append((5.0, "salida"))
cal.sort()
print("tras agendar:", cal)
# Traza del banco: llegadas 2 y 4, S=3
cal = [(2.0, "llegada"), (4.0, "llegada")]
reloj = 0.0
while cal:
cal.sort()
t, tipo = cal.pop(0)
reloj = t
print(f"t={reloj}: {tipo} | quedan: {cal}")
if tipo == "llegada" and reloj == 2.0:
cal.append((5.0, "salida")) # la de las 2 ocupa la caja
06 · Exploración
Laboratorio: mirar el futuro en Tp
Llega uno cada A, atención S, 1 caja, horizonte 12. La línea blanca es Tp (tu “hoy”): a la izquierda lo ya procesado (tenue), a la derecha la agenda viva —llegadas pendientes (lima) y salidas previstas (naranja)— ordenada como la vería el simulador. Mové Tp y mirá cómo el futuro se achica.
La agenda ordenada
futuro(Tp) = llegadas > Tp + salidas con fin > Tp
Mueve Tp para ver el futuro achicarse.
Filas ordenadas por tiempo: lima = llegada pendiente, naranja = salida prevista. La primera fila es “lo próximo” adonde saltará el reloj.
Preguntas para explorar
- Con A=2, S=3 y Tp=5, ¿qué contiene la agenda? ¿Qué es lo próximo?
- Llevá Tp a 11: ¿cuántos futuros quedan? ¿Y en Tp=12?
- ¿Por qué las salidas previstas superan a veces el horizonte 12? ¿Se procesan?
Ver respuestas sugeridas
- Llegadas pendientes (6, 8, 10, 12) y salidas previstas de los ya iniciados: lo próximo es la salida o llegada más cercana (empate posible en 6 u 8 según la traza).
- Quedan 1–2; en 12 la agenda de llegadas se vacía y solo puede restar alguna salida en curso: reloj al borde del horizonte.
- Porque un servicio iniciado a las 11 termina a las 14: está anunciado pero fuera del horizonte; según la regla de cierre (Tema 19) se trunca o se ignora.
07 · Comprensión
Confusiones frecuentes
«El calendario es la historia»
La historia es pasado (lo procesado); el calendario es futuro (lo anunciado). Mezclarlos es procesar dos veces o no procesar nunca.
«Agendar es opcional si me acuerdo»
Lo no agendado no existe para el simulador. Si la próxima llegada no está en la agenda, el reloj jamás saltará a ella.
«El orden aproximado alcanza»
Un calendario casi ordenado entrega “casi lo próximo”: suficiente para viajar al pasado de a ratos y corromper estadísticas.
«Vacío significa error»
Vacío significa sin futuro: terminación natural. Error es que se vacíe antes de tiempo por olvidar agendar.
08 · Práctica guiada
Ejercicios con Python
Ejercicio 1: operar la agenda
Agendá 3 futuros, extraé lo próximo y verificá el orden.
cal = [(5.0, "salida"), (2.0, "llegada"), (4.0, "llegada")]
cal.sort()
print("próximo:", cal.pop(0))
print("agenda:", cal)
Ver solución razonada
Próximo (2.0, llegada); agenda [(4.0, llegada), (5.0, salida)]. El invariante se restaura con sort tras cada append.
Ejercicio 2: la cadena que no se corta
Cada llegada agenda la siguiente (cada 2) hasta 8. Generá la cadena desde t=2.
cal = [(2.0, "llegada")]
reloj = 0.0
while cal:
cal.sort()
t, e = cal.pop(0)
reloj = t
print("proceso", t)
if t + 2 <= 8:
cal.append((t + 2, "llegada"))
Ver solución
Procesa 2, 4, 6, 8: cada una agenda la siguiente. Si olvidás el append, la cadena muere en 2.
Ejercicio 3: detectar el vaciado natural
¿Cuándo termina esta agenda y por qué es natural?
Ver una posible respuesta
cal = [(2.0, "llegada")]
while cal:
cal.sort()
t, e = cal.pop(0)
print("t =", t, "| quedan:", len(cal))
print("fin natural: sin futuros anunciados")
Termina tras procesar 2.0 porque nada agendó futuro: es fin natural por agenda vacía, distinto de fin por horizonte.
09 · Síntesis
Ideas para recordar
- Calendario = futuros ordenados por (tiempo, prioridad); sostiene agendar, extraer mínimo y ver.
- Cada evento extraído agenda sus futuros: llegadas encadenan llegadas, inicios agendan fines.
- Vacío = sin futuro = fin natural (distinto del fin por horizonte).
- En Python didáctico: lista +
sort+pop(0); en producción: heap (Tema 14). - Depurar es mirar la agenda: el futuro del simulador está ahí.
En el próximo tema veremos la lista de eventos futuros (FEL): la estructura eficiente que implementa este calendario.