Simulación de Eventos Discretos · Tema 04

Estado del sistema

Qué hay que anotar para pausar la simulación hoy y continuarla mañana sin perder nada — y cómo distinguir lo esencial de lo decorativo.

01 · Punto de partida

La prueba de la pausa

Imaginá que simulás el banco y a las 10:07 tenés que apagar la computadora. Anotás algo en un papel para seguir mañana exactamente donde quedaste. ¿Qué anotás?

Si anotás “hay 4 personas”, ¿alcanza? Mañana no sabrás si el cajero está atendiendo a una (y termina a las 10:09) o si está libre. Si anotás “hay 4, cajero ocupado, termina 10:09, próxima llegada 10:11”, sí podés continuar: cada evento futuro tiene todo lo que necesita.

Ese papel es el estado: lo mínimo que, junto al reloj y al FEL, permite retomar la historia sin adivinar.

  • Si pauso ahora, ¿qué necesito para seguir sin preguntarle a nadie?
  • ¿Qué dato, si lo borro, me deja sin saber qué hacer ante el próximo evento?
  • ¿Qué dato puedo recalcular y por lo tanto no necesito guardar?
  • ¿Mi estado cabe en 3 variables o necesito 30?

02 · Definición

Mínimo y suficiente, las dos condiciones

Un conjunto de variables es estado si pasa dos tests:

✓

Suficiente

Con ese dato + reloj + FEL puedo procesar cualquier evento futuro sin información extra. Si dudo ante una salida (“¿a quién atiendo?”), falta algo.

−

Mínimo

Nada sobra: cada variable que puedo derivar de las otras se va. en_cola sobra si guardo N y ocupado, porque cola = N − ocupado.

◧

Constante a trozos

En sistemas discretos el estado solo cambia en eventos. Entre eventos es una meseta: por eso pausar y reanudar es exacto.

Ejemplo mínimo del banco con 1 caja: s = (N, ocupado) donde N = personas en sistema y ocupado = 0/1. Con eso: llegada → N+1 y si estaba libre se ocupa; salida → N−1 y si queda N=0 se libera. Nada más hace falta para decidir.

Estado mínimo típico por sistema (más reloj + FEL).
SistemaEstado mínimo sDerivado (no guardar)Por qué alcanza
Banco, 1 cajaN, ocupado (0/1)En cola = N − ocupadoDecide llegadas y salidas
Servidor, c workersEn cola, ocupados (0…c)Libres = c − ocupadosAsigna arribos al worker libre
InventarioStock, pedido en curso (sí/no)Faltantes acumulados (estadística)Decide vender, pedir, recibir
Taller 2 máquinasCola A, estado A, cola B, estado BTotal en sistema (suma)Cada máquina decide por separado

03 · Cómo elegirlo

El test de las tres preguntas

Ante cada variable candidata, preguntate:

  1. 1
    ¿La necesito para procesar el próximo evento?

    “Servidor ocupado” sí: sin eso no sé si una llegada espera o se atiende. “Color de las sillas” no.

  2. 2
    ¿La puedo derivar de otras?

    Si guardo N y ocupado, la cola sale sola. Guardarla duplica y arriesga inconsistencia (N=5 pero cola=7).

  3. 3
    ¿Cambia solo en eventos?

    Si cambia sola con el tiempo (ej. “temperatura que se enfría”), o no es discreto puro o falta un evento que lo actualice. En discretos puros, todo cambio tiene su evento.

Variable de estado
Parte del mínimo suficiente: N, ocupado, stock. Vive en s y la modifican las rutinas.
Variable complementaria
Se deriva del estado: en cola, libres, utilización instantánea. Se calcula, no se guarda.
Parámetro
No cambia en la corrida: nº de cajas, tasa de llegada, capacidad. Configura, no es estado.
Estadística acumulada
Espera total, máximos, atendidos. Crece monótonamente para medir, no para decidir. (Tema 20)

Estado sano

Pequeño y consistente

2–4 variables, sin redundancia, siempre válidas (N ≥ 0, ocupados ≤ c). Pausar es copiar 3 números.

Estado enfermo

Grande y contradictorio

Guarda N, cola y total por separado y un día dicen cosas distintas. Cada evento debe actualizar 5 lugares y olvida uno.

04 · Ejemplos

Cuatro estados que ya sabés leer

s = (N, ocupado)→llega e→s′ = f(s, e)
  1. 1
    Banco 1 caja: s=(2, ocupado).

    Llegada con libre → (3, ocupado). Salida con N=1 → (0, libre). Cola = N − ocupado siempre.

  2. 2
    Servidor 3 workers: s=(cola=4, ocupados=3).

    Arribo → cola=5 (nadie libre). Fin → ocupados sigue 3 pero cola=4 (el siguiente toma el worker).

  3. 3
    Inventario: s=(stock=6, pedido=no).

    Venta de 2 → (4, no). Si cruza el punto de pedido → (4, sí) y se agenda arribo de reposición.

  4. 4
    Urgencias con prioridad: s=(cola_alta=1, cola_baja=3, médicos_ocupados=2).

    Sin separar por prioridad el estado no sabe a quién atender: la granularidad la pide la decisión.

05 · Representación en Python

El estado es un dict; la transición es pura

Guardá el estado en un diccionario (o dataclass) y escribí transiciones como funciones que reciben (estado, evento) y devuelven el nuevo estado. Así podés hacer snapshot con copy() y probar “¿qué pasaría si…?” sin romper nada.

Python en tu navegador. El primer bloque define el estado mínimo y sus transiciones; el segundo hace snapshot, pausa y reanuda. Editá N y re-ejecutá.

estado = {"N": 2, "ocupado": 1}  # mínimo suficiente (1 caja)

def al_llegar(s):
    s = dict(s)
    s["N"] += 1
    s["ocupado"] = 1
    return s

def al_salir(s):
    s = dict(s)
    s["N"] = max(0, s["N"] - 1)
    if s["N"] == 0:
        s["ocupado"] = 0
    return s

print(al_llegar(estado))  # {'N': 3, 'ocupado': 1}
print(al_salir({"N": 1, "ocupado": 1}))  # {'N': 0, 'ocupado': 0}
# Snapshot: pausar en t=6 y reanudar mañana es copiar el dict + reloj
reloj = 6
snapshot = (reloj, dict({"N": 3, "ocupado": 1}))
print("pausa:", snapshot)

# Mañana: restauro y sigo
reloj2, estado2 = snapshot[0], dict(snapshot[1])
estado2 = {"N": estado2["N"] + 1, "ocupado": 1}  # llega uno en t=7
print("reanudo en", reloj2, "-> tras llegada:", estado2)
print("en cola:", estado2["N"] - estado2["ocupado"], "(derivado, no guardado)")

06 · Exploración

Laboratorio: pausar y reanudar sin perder nada

Elegí llegadas (A), servicio (S) y N(0). La curva muestra N(t) y la barra inferior si el servidor está ocupado. Movete el control pausa en Tp: la ficha muestra el snapshot mínimo para reanudar (N, ocupado, reloj, próximos del FEL). Comprobá que con esos 5 datos alcanza.

EXPERIMENTO 04

El papel para continuar mañana

snapshot(Tp) = (reloj, N, ocupado, próx. llegada, próx. salida)

Los resultados numéricos aparecen debajo.
N en Tp0
Servidor—
En cola (derivado)0
Próx. llegada / salida—

Mueve la pausa para inspeccionar el estado.

Escalera lima: N(t). Banda inferior verde: servidor ocupado; gris: libre. Línea blanca vertical: instante de pausa Tp. Con N, ocupado, reloj y los dos próximos alcanza para seguir.

Preguntas para explorar

  1. Con A=2, S=3, N(0)=2 y Tp=6, ¿cuánto valen N, ocupado y en cola? ¿Necesitás algo más para seguir?
  2. Buscá un Tp donde N=0. ¿Qué vale ocupado? ¿Y la próxima salida?
  3. Si agregaras “en cola” al estado guardado, ¿qué riesgo aparece? Provocá un ejemplo inconsistente.
Ver respuestas sugeridas
  1. N=3, ocupado=1, en cola=2 (derivado). Más reloj=6, próxima llegada 8 y próxima salida 9: con esos 5 datos reanudás exacto.
  2. Ocupado=0 y “próxima salida: —”. Sin nadie en servicio no hay salida futura: el FEL solo trae llegadas. Guardar una salida fantasma rompería la causalidad.
  3. Podrías guardar N=3 con cola=5 (imposible, pues cola ≤ N). Con una sola fuente (N y ocupado) ese error no existe: la cola se calcula.

07 · Comprensión

Confusiones frecuentes

«El estado es todo lo que sé del sistema»

No: es lo mínimo suficiente. Parámetros (nº de cajas), derivados (en cola) y estadísticas (espera total) no son estado aunque los conozcas.

«El FEL es parte del estado»

El FEL acompaña al estado para reanudar, pero conceptualmente es futuro anunciado, no situación actual. Mezclarlos complica las transiciones.

«Más variables = modelo más fiel»

Más variables = más lugares para olvidar actualizar. La fidelidad la da elegir bien las mínimas, no acumular.

«El estado cambia solo»

En discretos puros, si algo cambió sin evento, tu diseño está incompleto: falta el evento que lo explica o el sistema no es discreto.

08 · Práctica guiada

Ejercicios con Python

Ejercicio 1: detectar redundancia

Este “estado” guarda de más. ¿Qué sobra y cómo lo derivás?

s = {"N": 4, "ocupado": 1, "en_cola": 3}
print("derivado:", s["N"] - s["ocupado"], "| guardado:", s["en_cola"])  # ¿coinciden?
Ver solución razonada

Sobra en_cola: vale N − ocupado = 3. Guardarlo invita a que un día valga 5 con N=4. Estado sano: {"N": 4, "ocupado": 1} + función cola(s).

Ejercicio 2: transición completa

Sin ejecutar primero: con {"N": 0, "ocupado": 0}, ¿qué dejan una llegada y luego una salida?

def llegar(s):
    return {"N": s["N"] + 1, "ocupado": 1}

def salir(s):
    n = max(0, s["N"] - 1)
    return {"N": n, "ocupado": 0 if n == 0 else 1}

s0 = {"N": 0, "ocupado": 0}
print(salir(llegar(s0)))
Ver solución

{"N": 0, "ocupado": 0}: la llegada ocupa (N=1) y la salida vacía y libera. El sistema vuelve al reposo exacto.

Ejercicio 3: snapshot que sí reanuda

Guardá reloj + estado en una tupla, modificá una copia y mostrá que el original no se contaminó.

Ver una posible respuesta
reloj, estado = 6, {"N": 3, "ocupado": 1}
foto = (reloj, dict(estado))  # snapshot
copia = dict(foto[1])
copia["N"] += 1  # experimento "¿y si llega uno?"
print("foto intacta:", foto)
print("copia:", copia)

La foto sigue (6, N=3) y la copia prueba el escenario. Así se implementan réplicas y “qué pasaría si” sin corromper la corrida.

09 · Síntesis

Ideas para recordar

  • Estado = mínimo y suficiente para continuar solo con reloj + FEL (test de la pausa).
  • Banco 1 caja: (N, ocupado); lo demás (en cola, libres) se deriva.
  • Parámetros configuran, estadísticas miden: ninguno es estado.
  • En Python: dict pequeño + transiciones puras + dict(s) para snapshot.
  • Todo cambio de estado tiene su evento; si cambia solo, falta modelar.

En el próximo tema conoceremos las entidades: quiénes circulan por el sistema y qué las distingue.