🇬🇧 English · 🇪🇸 Español
Estado de validación de los solvers estructurales
Actualizado el 23 de septiembre de 2026 con una fila para el Newton-Krylov apilado y con las filas revisadas por las correcciones de la auditoría posterior a 4.3.0. La actualización del 20 de septiembre de 2026 siguió a los contraejemplos independientes de una evaluación crítica interna y de su seguimiento con Dynare en vivo. La disponibilidad de una función, la convergencia numérica y la replicación independiente son afirmaciones distintas. Superar una comprobación de residuos no valida un modelo económico.
| Superficie | Cálculo soportado y contrato de aceptación | Evidencia y límites pendientes |
|---|---|---|
| DSGE de tercer orden | Las pendientes de riesgo incluyen el calendario de los estados, términos en cadena del hessiano y contracciones de varianza de terceras derivadas. Los modelos parseados usan derivadas simbólicas; el respaldo para modelos definidos como funciones tiene precisión de diferencias finitas. | Cinco modelos ejecutados en Dynare 7.0 en vivo en órdenes dos y tres, incluidos choques correlacionados, estados no lineales y un modelo RBC. Todos los tensores desplegados, correcciones de riesgo, covarianzas y simulaciones/momentos con innovaciones comunes coinciden (error máximo de tensor 1.15e-13; error de trayectoria 2.70e-13). El ensamblaje de derivadas mixtas conserva ahora cada permutación de índices. Es un benchmark acotado, no paridad general. MATLAB completó las exportaciones pero falló al cerrar; véase tools/reference_validation/README.md. Momentos exactos con poda (después de 4.3.0): la identidad del espacio de estados reproduce el simulador podado a 2e-15; medias y covarianzas coinciden con los momentos podados de Dynare 8 en seis modelos (2e-13) y con una forma cerrada (3e-15). Las autocorrelaciones de orden 3 de Dynare omiten un término de correlación; una forma cerrada y las propias simulaciones de Dynare de 4e6 períodos coinciden con puremacro (tests/test_dsge_order3_moments.py). |
| Panel de paridad con Dynare | Los órdenes uno y dos comparan estados estacionarios y todos los tensores solicitados (ghx, ghu, ghxx, ghxu, ghuu, ghs2), alineados por etiquetas. Los oo_.mean/var/autocorr suministrados se comparan con los momentos del objeto resuelto en el orden comparado: en orden 2, la media corregida por riesgo y los segundos momentos de primer orden, que es la convención de stoch_simul(order=2) sin pruning. M_.Sigma_e se compara con la covarianza que declara el objeto. Las filas de autocorrelación de variables con varianza nula que son NaN en ambos lados cuentan como coincidentes y se listan en details["moments_excluded"]. Una entrada ausente, no finita (en un solo lado), mal formada o vacía, incluidos el oo_.dr = [] inicial de Dynare y la salida de loadmat como arreglo de registros, es no disponible. |
Los fixtures de Dynare 7 en vivo se exportaron con nomoments, así que la paridad de momentos de orden 2 se contrasta con las fórmulas de stoch_simul aplicadas a las propias reglas de decisión de Dynare (concordancia 3.6e-15 en la media, 7.0e-14 en la varianza, 1.8e-14 en la autocorrelación en rbc), no con momentos reportados por Dynare. Una referencia de stoch_simul(order=2, pruning) reporta segundos momentos podados: compárela con pruning=True, que usa los momentos podados exactos (las medias, covarianzas y autocorrelaciones podadas de Dynare 8 se reproducen a 7e-14 en los cinco modelos en vivo y en un modelo con forma cerrada). Los fixtures de serialización autogenerados son pruebas internas, no oráculos externos de Dynare. La CLI de paridad no puede consumir referencias y termina con un error explicativo; use la API de Python. |
| DSGE con cambio de régimen markoviano | Los residuos de las ecuaciones acopladas se recalculan en las matrices devueltas. La convergencia es diff <= tol (absoluta), o cada entrada del residuo dentro de tol o dentro de rtol (64 eps) de las magnitudes de sus propios términos que se cancelan (error hacia atrás por componentes; el menor rtol que certifica se reporta como relative_residual). Las soluciones fallidas tienen impactos de choques, radios de estabilidad y momentos ergódicos no disponibles. |
Un fallo de raíz real no debe devolver una covarianza de equilibrio finita ni un certificado de estabilidad. Los momentos finitos requieren además estabilidad tras la convergencia. Casos contrastados: reescalado uniforme hasta 1e9; una ecuación reescalada por 1e6 y 1e9 en tres modelos (las ecuaciones O(1) siguen cumpliendo tol y T queda a menos de 1e-9 de la solución sin escalar); unidades de variables que abarcan 1e14; modelos O(1) (incluido un tol más estricto del usuario) idénticos bit a bit a la puerta absoluta. |
| Newton-Krylov apilado en el tiempo | solve_stacked_newton_krylov acepta una senda solo cuando el residuo apilado cumple |F|_inf <= tol * s (s la escala del bloque estacionario) y el siguiente paso de Newton es menor que 1e-10 * max(1, |Y|_inf); step_tol=None omite la prueba del paso (con jacobian_scale=1.0 la prueba es entonces |F|_inf <= tol). El movimiento de Newton se acota en unidades de la senda (0.75 * max(1, |Y|_inf)) y se acepta mediante una búsqueda lineal de Armijo de 24 intentos. Una dirección devuelta en el tope de Krylov se registra (estado y residuo lineal verdadero recalculado) y se somete a la búsqueda lineal como cualquier otra; por sí sola no es un error. Las búsquedas lineales fallidas, los límites de iteraciones, los errores o valores no finitos dentro de una resolución lineal, un residuo en un suelo de ruido que cumple la tolerancia mientras la prueba del paso no puede cumplirse, y una matriz apilada estacionaria que no se puede factorizar lanzan StackedNewtonError con el último estado adjunto y la causa en converged_by. Los pivotes de block-Thomas con una estimación de condición de LAPACK inferior a n * eps, o una factorización cuyo error hacia atrás con un vector supera 1e-10, recurren a SuperLU (registrado en el nombre del precondicionador). Cuando ambas entradas son objetos StackedNewtonResult, compare_horizons exige entradas convergidas, fronteras idénticas y la misma senda exógena mantenida más allá del horizonte corto; los arreglos, DataFrames y entradas PerfectForesightResult se comparan tal como se dan. |
Oráculos de resolución densa hasta 1e-12 (bloques constantes y por fecha, con y sin bloques temporales), identidad de la inversa exacta en un ciclo de Krylov, paridad con solve_perfect_foresight en Ramsey y en una transición de crecimiento de 20 sectores hasta 1e-8 (observado 7e-11 y 3.5e-11), invarianza al escalado de ecuaciones (1e-9) y de variables (unidades de 1e-3 a 1e4, 1e-9 relativo, mismos recuentos de Newton), regresiones de pivotes a nivel de redondeo y mal condicionados (B = U V de rango deficiente, números de condición apilados 616 y 941; B = [[1, 1], [1, 1 + 1e-12]]), y el contrato de fallo, incluidos errores dentro de la resolución de Krylov y un suelo de ruido del residuo de 1e-12. La evidencia cubre solo fixtures analíticos de tamaño DSGE. La memoria es O(T n^2) (cerca de 3.2 GB con n_vars = 1000, T = 200); los sistemas con miles de incógnitas por fecha necesitan una eliminación estructurada, y no se incluye ninguna. La estructura por bloques por sí sola no establece la velocidad ni la memoria a escala, y las identidades lineales no garantizan por sí solas la precisión numérica ni la convergencia no lineal. Aquí no se resuelve ninguna transición a gran escala; MCP y el modo de sorpresa de solve_perfect_foresight no están disponibles. Véanse uso y evidencia. |
| Proyecciones VFI | Las banderas de colocación de Euler, FEM, Smolyak y splines exigen residuos finales finitos dentro de la tolerancia solicitada. La terminación del optimizador por sí sola es insuficiente. | Un residuo en los nodos de ajuste no establece precisión fuera de la malla, factibilidad, complementariedad ni optimalidad global. Los dominios adversos pueden devolver aproximaciones útiles con converged=False. Las variantes de Bellman tienen sus propios criterios de iteración. |
| Valores auxiliares de colocación | La política y el valor usan una sola curvatura CRRA (sigma, alias gamma) y la productividad del modelo en los bloques de Euler, Coleman, Bellman y evaluación de la política. Los parámetros de return_fn/euler_residual_fn del usuario se transmiten sin interpretar. |
Casos contrastados: la forma cerrada del crecimiento logarítmico determinista con cada forma de escribir la curvatura; la identidad de Bellman con CRRA(2) y CRRA(3); concordancia de políticas Euler/Bellman (1.1e-6) con sigma = 2; la sensibilidad TFI respecto de gamma frente a la columna de sigma y una nueva resolución por diferencias finitas. El recorte en la frontera limita la interpretación fuera del dominio elegido. Desde 4.5.0 puremacro.vfi.splines y puremacro.vfi.smolyak siguen la misma regla (sigma y, si falta, gamma); solve_smolyak(method="bellman") solo cubre utilidad logarítmica con depreciación total y en otro caso lanza un error. |
| Deep Macro | Iteración temporal de Euler con objetivo desacoplado. La caché hacia adelante del estado actual se restaura antes de actualizar los pesos. | Un gradiente completo del paso de entrenamiento se comprueba por diferencias finitas. El éxito del entrenamiento depende de la calibración y de la semilla; incluso la trayectoria determinista por defecto de diez países puede no superar el criterio de Euler fuera de muestra. Una pérdida de entrenamiento pequeña por sí sola no es convergencia. |
| Sensibilidades VFI | Soluciones lineales por el TFI usando jacobianos de residuos por diferencias centrales: derivadas semianalíticas. | La precisión depende de los pasos de diferenciación y del condicionamiento. Las sensibilidades de distribución y de equilibrio general con agentes heterogéneos no están disponibles hasta que se implementen la KFE diferenciada y las ecuaciones de equilibrio acopladas. |
La galería de validación de 110 casos (versión 4.5.0, todos superados) contiene 59 casos internos, 31 analíticos, 13 de paquetes, cinco de SciPy y dos de referencia publicada. Tiene varias clases de tolerancia. La galería no certifica cada función, cada backend ni cada despliegue.
Puremacro no distribuye ninguna extensión compilada propia. NumPy/SciPy y otros paquetes base incluyen componentes compilados; las dependencias obligatorias incluyen además pandas, Matplotlib y requests. La importabilidad en Pyodide, la ejecución realista en el navegador, la concordancia en GPU y la reproducibilidad bit a bit requieren pruebas distintas.