01 · Punto de partida
Todo simulador debe pasar dos exámenes
Imaginá que programás la fila de un banco: clientes que llegan, esperan y son atendidos. El programa corre sin errores y dibuja gráficos hermosos. ¿Podés recomendar contratar otro cajero basándote en esos gráficos? Todavía no. Te faltan dos exámenes independientes:
- ¿El código implementa fielmente lo que diseñaste en papel?
- ¿Lo que diseñaste en papel se parece lo suficiente a la sucursal real?
- ¿Qué pasa si una falla y la otra no?
- ¿En qué orden conviene hacerlas y con qué evidencia?
02 · Definición
Construir bien frente a construir lo correcto
La distinción clásica de la ingeniería de software (Boehm, 1981) calza perfecto en simulación:
Verificación
Compara modelo conceptual vs. programa. Pregunta: ¿el código ejecuta exactamente las reglas, ecuaciones y eventos especificados? No usa datos reales.
Validación
Compara modelo vs. sistema real. Pregunta: ¿las salidas simuladas se parecen lo suficiente a las mediciones para el uso previsto? Exige datos reales.
Uso previsto
Ninguna de las dos es absoluta: un modelo se verifica contra su especificación y se valida para un propósito y un rango concretos.
| Caso | Verificado | Validado | Lectura |
|---|---|---|---|
| A. Ideal | Sí | Sí | Código fiel y modelo útil. Se puede experimentar y decidir. |
| B. Bug | No | Sí / parece | El modelo es bueno pero el programa lo traiciona. Hay que depurar. |
| C. Modelo ingenuo | Sí | No | El programa hace exactamente lo pedido, pero lo pedido no representa la realidad. Hay que remodelar o calibrar. |
| D. Doble falla | No | No | Nada es confiable. Volver al diseño y a los datos. |
El caso C es el más traicionero: todo pasa los tests unitarios, pero las decisiones son malas porque el supuesto de base era falso (llegadas constantes cuando en realidad hay hora pico, tanque sin pérdidas cuando hay evaporación, etc.).
03 · Verificación a fondo
Qué revisa la verificación
La verificación no sale del mundo del modelo: contrasta tres artefactos entre sí.
- Revisión del diseño
- ¿Las reglas, diagramas y ecuaciones son coherentes y completas antes de programar? (Tema 2)
- Revisión del código
- ¿Cada evento, cola y actualización de estado hace lo especificado? Pruebas unitarias, trazas, invariantes. (Temas 3–4)
- Casos con solución conocida
- Si la entrada es trivial (cero llegadas, balance cero), ¿la salida es la esperada matemáticamente?
Verificación típica
Sin datos reales
Se usan valores inventados pero exigentes: bordes, ceros, máximos. Si el tanque con entrada 3 y salida 2 durante 6 pasos no da [13, …], el bug está en el código, no en el mundo.
Error típico
El programa miente
Índices corridos, eventos fuera de orden, semillas reusadas, unidades mezcladas (minutos vs. segundos). Todo verificable sin medir la realidad.
04 · Validación a fondo
Qué revisa la validación
La validación sí sale al mundo: contrasta el modelo (ya verificado) con evidencia externa.
- 1Datos.
Mediciones del sistema real con calidad documentada: ¿quién midió, cuándo, con qué instrumento y con qué sesgo? (Tema 10)
- 2Comparación.
Gráficos real vs. simulado, errores (absoluto, relativo, cuadrático) y tests de bondad de ajuste. (Temas 11–17, 20–22)
- 3Juicio de uso.
¿El error es aceptable para decidir? Un error de 5 minutos puede ser fatal en urgencias e irrelevante en logística mensual.
| Estrategia | Idea | Tema |
|---|---|---|
| Histórica | ¿Reproduce el pasado conocido? | 6 |
| Predictiva | ¿Acierta datos nuevos no usados para calibrar? | 7 |
| Por expertos | ¿Los que conocen el sistema lo dan por razonable? | 8 |
| Estadística | ¿Pasa chi-cuadrado, K-S, Mann-Whitney, Wilcoxon? | 12–17 |
05 · Representación en Python
Verificar con asserts, validar con datos
En Python las dos actividades se ven muy distinto. La verificación usa casos exactos y assert; la validación usa datos medidos y métricas de error.
Python en tu navegador. Estos bloques se ejecutan localmente con Pyodide. Podés editarlos y re-ejecutarlos para romper y arreglar a propósito.
Verificación: el programa respeta la regla
def simular_tanque(nivel_inicial, entrada, salida, pasos):
nivel = nivel_inicial
historia = []
for t in range(pasos):
nivel = nivel + entrada - salida
if nivel < 0:
nivel = 0
historia.append(nivel)
return historia
# Casos con solución conocida (verificación, sin datos reales)
assert simular_tanque(10, 3, 2, 3) == [11, 12, 13]
assert simular_tanque(5, 4, 4, 3) == [5, 5, 5]
assert simular_tanque(2, 1, 3, 3) == [0, 0, 0]
print("Verificación OK: el código ejecuta la regla")
Rompé a propósito la regla (por ejemplo, quitá el tope en cero) y observá qué assert falla: eso es un defecto de verificación, no de la realidad.
Validación: el modelo se parece a lo medido
real = [11, 12, 12, 13, 14, 15] # mediciones del tanque real
sim = simular_tanque(10, 3, 2, 6)
errores = [abs(s - r) for s, r in zip(sim, real)]
mae = sum(errores) / len(errores)
print("sim:", sim)
print("errores absolutos:", errores)
print("MAE:", round(mae, 3))
tolerancia = 1.0
print("¿Válido para tolerancia 1.0?", mae <= tolerancia)
06 · Exploración
Laboratorio: bug frente a sesgo del modelo
La realidad sigue nivel = 10 + 1 × t. Tu simulador tiene dos perillas independientes: un bug de código (resta de más por paso aunque la regla diga otra cosa) y un sesgo del modelo (suponés un balance distinto del real). Mové cada una y observá cuál rompe la verificación y cuál rompe la validación.
Verificación vs. validación
real = 10 + t · simulado = 10 + (1 + sesgo + bug) · t
Sin bug ni sesgo: el simulador está verificado y validado.
La línea verde es la realidad medida. La línea lima es lo que el modelo conceptual promete. La línea naranja es lo que el programa realmente calcula (con bug y sesgo). Cuando el bug es cero pero el sesgo no, el código es fiel pero el modelo no representa la realidad: caso C.
Preguntas para explorar
- Poné bug 1,5 y sesgo 0. ¿Qué se rompe: verificación, validación o ambas? ¿Por qué ambas caen si el modelo era bueno?
- Poné bug 0 y sesgo 2. Los asserts de verificación pasarían, ¿pero el MAE es aceptable? ¿Qué harías: depurar o recalibrar?
- ¿Podés lograr MAE bajo con bug y sesgo que se compensen (ej. bug 1 y sesgo −1)? ¿Es eso verificar o validar? ¿Por qué es peligroso?
Ver respuestas sugeridas
- Se rompe la verificación (el programa no ejecuta la regla) y, como consecuencia, también la validación. Un buen modelo mal programado decide mal igual.
- La verificación pasaría (el código es fiel), pero el MAE ≈ 7 supera la tolerancia: falla la validación. No hay que depurar código, hay que corregir el supuesto o calibrar el balance.
- Sí: los errores se cancelan y el MAE queda bajo por casualidad. Es validación aparente sin verificación: el próximo escenario lo rompe. Por eso la verificación va primero y no se negocia.
07 · Comprensión
Confusiones frecuentes
«Si pasa los tests, ya está validado»
Los tests unitarios verifican. Validar exige datos reales, tolerancia declarada y tests estadísticos. Un programa perfectamente testeado puede modelar un mundo inexistente.
«Si se parece a los datos, el código está bien»
Un bug y un sesgo pueden compensarse y dar un MAE bajo por casualidad. Sin verificación independiente, esa coincidencia es frágil y no generaliza.
«Validar una vez vale para siempre»
La validez tiene rango: horizonte, carga, parámetros y contexto. Cambia la hora pico, el público o la capacidad, y hay que revalidar.
«Calibrar es lo mismo que validar»
Calibrar ajusta parámetros para parecerse a unos datos (Tema 9). Validar comprueba con datos distintos de los usados para calibrar, o el éxito es circular.
08 · Práctica guiada
Ejercicios con Python
Ejercicio 1: clasificar la falla
Leé cada caso y decidí si es falla de verificación, de validación o de ambas. Después comprobalo ejecutando el código.
# Regla especificada: nivel(t+1) = nivel(t) + 3 - 2, con piso en 0.
def sim_rota(nivel, entrada, salida, pasos):
# BUG: usa salida + 1 por error de tipeo
historia = []
for t in range(pasos):
nivel = nivel + entrada - (salida + 1)
if nivel < 0:
nivel = 0
historia.append(nivel)
return historia
print(sim_rota(10, 3, 2, 3)) # especificación pide [11, 12, 13]
print("¿Verificado? ¿Validado?")
Ver solución razonada
Devuelve [10, 10, 10] en lugar de [11, 12, 13]: falla de verificación. Aunque el balance real fuera 1, este programa nunca lo reproduciría. Primero se corrige el +1; recién después tiene sentido validar.
Ejercicio 2: validar con tolerancia
Calculá el MAE entre estas mediciones y tu simulador verificado. ¿Es válido con tolerancia 0,8? ¿Y con 1,5?
def sim_ok(nivel, entrada, salida, pasos):
h = []
for t in range(pasos):
nivel = max(0, nivel + entrada - salida)
h.append(nivel)
return h
real = [11, 13, 12, 14, 15, 16]
sim = sim_ok(10, 3, 2, 6)
mae = sum(abs(s - r) for s, r in zip(sim, real)) / len(real)
print(sim)
print("MAE:", round(mae, 3))
print("tol 0.8:", mae <= 0.8, "| tol 1.5:", mae <= 1.5)
Ver solución
sim = [11, 12, 13, 14, 15, 16], MAE ≈ 0,333. Es válido con ambas tolerancias. El juicio de validación siempre incluye el umbral: sin tolerancia escrita no hay veredicto.
Ejercicio 3: la compensación peligrosa
Este programa tiene un bug que resta 1 de más, pero el modelo supone un balance 1 mayor que el real. El MAE queda bajo. Explicá por qué igual debe rechazarse.
Ver una posible respuesta
# Realidad: balance 1. Modelo supuesto: balance 2. Código: balance 2 - 1 (bug).
real = [11, 12, 13, 14]
sim_con_bug = [11, 12, 13, 14] # coincide por cancelación
print("MAE:", 0.0, "¿Verificado?", False)
El MAE es 0 por cancelación de errores, pero la verificación es falsa: el código no ejecuta el modelo supuesto. Cambiá el escenario (por ejemplo, 12 pasos o piso en cero) y la coincidencia desaparece. Verificación primero, validación después, siempre.
09 · Síntesis
Ideas para recordar
- Verificación = modelo conceptual vs. programa (¿construimos bien?). No usa datos reales.
- Validación = modelo vs. sistema real (¿construimos lo correcto?). Exige datos y tolerancia.
- Verificado y no validado: código fiel a un modelo ingenuo. Validado aparente sin verificación: coincidencia frágil.
- El orden importa: primero verificar con asserts y casos exactos, después validar con errores y tests estadísticos.
- La validez siempre tiene alcance: propósito, rango y tolerancia escritos.
En el próximo tema veremos la verificación del modelo conceptual: cómo revisar la lógica, los supuestos y los diagramas antes de escribir una sola línea de código.