# Contrato GLM: implementación y uso

Implementado el 2026-10-04 como continuación de [REVISION_GLM_PLAN.md](REVISION_GLM_PLAN.md); actualizado a contrato v2 con adaptación el 2026-10-06. Las ecuaciones se generan en C (`slex/din/glm.inc`, incluido por `din.c`); Perl conserva memoria y suministra datos a la sesión persistente de Calcula. El motor RK no se sustituyó.

## Métodos disponibles

| Selector | Método y arranque | Memoria externa | Archivo ampliado |
| --- | --- | --- | --- |
| `GLM=[1]` | Euler explícito | Estado actual | `NOMBRE-de-d2datdinc-GLM1.din` |
| `GLM=[20]` | BDF2 por datos efectivos; arranca con Euler implícito | Dos estados; historia interna a Perl | `NOMBRE-de-d2datdinc-BDF2.din` |
| `GLM=[21]` | BDF2 directo; arranca con Euler implícito | Dos estados, que participan en las ecuaciones de Calcula | `NOMBRE-de-d2datdinc-BDF2-DIRECTO.din` |
| `GLM=[30]` | Adams–Bashforth 2; arranca con Euler explícito | Estado actual y derivada anterior escalada por el paso del intento | `NOMBRE-de-d2datdinc-GLM30.din` |

Los IDs son arbitrarios. Se admite un método por corrida, paso fijo o adaptativo y acortamiento del último paso. Se rechazan listas mixtas, convoluciones, RERUN y topologías que requieran `.mdin`. En modo adaptativo se rechaza `DT`/`TICK` dentro del modelo físico. GLM 20 conserva además la prohibición de `DT` en fijo porque transforma el paso físico en uno efectivo. GLM 1/21/30 no toman sus matrices de la tabla RK del dato; GLM 20 conserva ese sistema Euler y comprueba que RK 1 sea realmente Euler implícito sin `bc`.

GLM 1 ahora tiene sufijo propio `-GLM1.din`, en lugar de reutilizar `-ED0.din`: así no confunde su selección con RK 0. Los archivos RK conservan sus nombres históricos `-EDNRO.din` y su motor.

## Generación y corrida

En el árbol de fuentes, desde `siru/siru`, con Calcula disponible en PATH:

```bash
../slex/d2datdinc/d2datdinc -c ../slex/d2datdinc/d2datdinc.slex -b ../slex/d2datdinc/biblioteca --din corpus/corpus/GLM/seis-elementos-bdf2-directo.d --directorio /tmp
bin/siru /tmp/seis-elementos-bdf2-directo-de-d2datdinc-BDF2-DIRECTO.din
```

`--din` sin número respeta `GLM=[ID]` de la fuente. `--din-glm ID` permite elegirlo explícitamente; `--din-bdf2` y `--din-bdf2-directo` son las opciones para 20 y 21. La corrida desde `.din` no necesita un `.dat` ni leer el catálogo externo: lleva su descriptor expandido. También se puede ejecutar directamente el `.d`/`.ds` con `bin/siru`, o indicar `--calcula` y `--bibliotecas` como en el README.

## Fuente única de coeficientes

El catálogo es [glm.json](../../slex/d2datdinc/biblioteca/glm.json), distribuido junto a la biblioteca de `d2datdinc`. C y Perl leen el mismo archivo al seleccionar un método. Sus partes son:

| Campo | Significado |
| --- | --- |
| `version` | Actualmente 2. Se leen descriptores v1 con paso fijo; para activar adaptación deben regenerarse. |
| `capacidades` | v2: paso `variable_con_rearranque`, adaptación habilitada; listas, topología y convoluciones deshabilitadas. v1 conserva `fijo_final_acortado`. |
| `definitions` | Definiciones matemáticas reutilizables: Euler, BDF2 y AB2. |
| `methods` | IDs, nombre, definición referida y representación `bloques` o `efectivos`. |
| `memoria` | Primera componente `estado`; las siguientes son `estado` o `hderivada`. |
| `bloques` | `a,u,b,v,c` para los pasos normales. |
| `arranque` | Los mismos bloques y dimensiones para el primer paso; las componentes todavía no disponibles tienen peso cero. |
| `estimador` | `arranque_orden1` para la política adaptativa inicial. No demuestra el orden de un método definido por el usuario. |
| `historia` | Dimensión de la memoria externa GLM; se conserva el nombre histórico. |
| `historia_fisica` | Capacidad optativa del anillo físico, independiente de la memoria externa; por omisión usa `historia`. |

Los coeficientes pueden ser números o expresiones aritméticas con `r=h/h_anterior`, constantes, paréntesis y `+ - * /`. Un analizador aritmético de Perl, sin `eval` de código, los evalúa para cada intento. Rechaza sintaxis inválida, divisiones por cero y resultados no finitos. Los validadores comprueban versión, capacidades, memoria y dimensiones; eso no demuestra el orden ni la estabilidad de una tabla arbitraria. La interfaz inicial no anuncia soporte general para cualquier representación de memoria GLM, como Nordsieck: solo los tipos declarados arriba.

GLM 20 y 21 comparten la definición `bdf2`; no mantienen dos fórmulas independientes. La representación efectiva deriva su estado y paso efectivos de los mismos bloques. La representación directa entrega los coeficientes como datos de Calcula.

## Variables y ecuaciones del `.din`

Para cada estado `y`, el generador escribe las copias residuales del modelo y las relaciones `Y=h*A*F+U*H`, `H_nuevo=h*B*F+V*H`. No exige despejar las derivadas ni eliminar previamente las variables algebraicas.

| Nombre | Papel |
| --- | --- |
| `y` | Primera componente de memoria: estado actual, dato. |
| `glm_h1_y`, etc. | Componentes adicionales de memoria, datos. |
| `s0_y`, `s0_dy`, etc. | Variables de las etapas, incógnitas. |
| `p_y` | Estado físico siguiente, primera componente de memoria de salida. |
| `glm_next1_y`, etc. | Memoria de salida adicional, incógnitas. |
| `glm_a_i_j`, `glm_u_i_j`, `glm_b_i_j`, `glm_v_i_j`, `glm_c_i_0` | Coeficientes suministrados en cada consulta, datos. |

Se reservan los prefijos `glm_`, `p_` y los nombres de etapa que empiezan por `s` seguido de un dígito; se rechazan colisiones con el modelo. La copia temporal usa `t+glm_c_i_0*dt`, no la suma de la fila de `A`. Para BDF2 la etapa ocurre en `t+h`, aunque `A=[[2/3]]` a paso uniforme.

Las secciones comentadas incluyen `# corrida` con `metodo GLM` y `# glm` con `descriptor` seguido del JSON completo en una sola línea. El lector valida la correspondencia de estados, dimensiones, capacidades y declaraciones de los datos/salidas requeridos; no pretende demostrar por inspección que ecuaciones editadas arbitrariamente todavía implementen ese descriptor. Los `.din` RK antiguos sin marcador siguen funcionando. Se mantiene lectura de los BDF2 anteriores con `metodo BDF2` y `# historia`.

## Memoria, arranque y paso final

- `Siru::Historia` guarda un anillo de puntos aceptados (tiempo, paso, estados y derivadas disponibles), dimensionado por el método. Agregar o consultar devuelve copias; no hay un máximo fijo de dos puntos. La memoria externa GLM se mantiene por separado y se actualiza con las salidas de las matrices, no mediante ramas numéricas por ID.
- En BDF2 la segunda componente es el estado anterior. El primer paso usa Euler implícito sin utilizar una historia ficticia; el segundo ya utiliza los dos estados aceptados.
- En AB2 la segunda componente de entrada es `h*f_anterior`. Perl conserva la derivada sin escalar: divide la memoria de salida por el paso aceptado y la multiplica por el paso del intento siguiente. Esto evita reutilizar una escala incorrecta al acortar el final.
- BDF2 y AB2 usan coeficientes de razón variable, también al acortar el último paso. AB2 aplica `y_nuevo=y+h*((1+r/2)*f_n-r*f_anterior/2)`; con `r=1` se obtiene la fórmula habitual.
- Estado, memoria y tiempo se confirman después de validar toda la respuesta y, en adaptación, satisfacer la tolerancia. Ante un fallo, no se publica la trayectoria parcial ni se sobrescribe una salida preexistente. Un rechazo temporal conserva la instantánea confirmada y sus quiebres pendientes.

## Adaptación inicial: contrato v2

Se usan los controles existentes `SIRU_ADAPT`, `SIRU_PASO`, `SIRU_PASO_MIN`, `SIRU_PASO_MAX`, `SIRU_ABSOLUTO`, `SIRU_RELATIVO` y `SIRU_ORDEN_ERROR`. Con `[0]` se conserva el paso fijo. El generador incluye `# adaptacion` con `metodo glm_arranque` y `orden_error 2`; cualquier otro orden de estimador se rechaza. Los coeficientes y controles viajan en el `.din`, sin exigir acceso al catálogo durante la corrida. Ejemplo de sintaxis en [MANUAL.md](MANUAL.md#glm-fijo-o-adaptativo).

| Situación | Candidato principal | Comparación para el error |
| --- | --- | --- |
| Arranque, rearranque o Euler | Un paso Euler completo del tipo declarado | Dos medios pasos del mismo Euler, con factor 2 sobre la diferencia para estimar el error del paso completo. No se aplica BDF2/AB2 en la segunda mitad. |
| BDF2 normal (20/21) | BDF2 con la razón de pasos actual | Un paso Euler implícito desde el mismo estado confirmado. |
| AB2 normal (30) | AB2 con la razón de pasos actual | Un paso Euler explícito desde el mismo estado confirmado. |

Siempre se acepta el candidato principal. El anillo, la memoria y el estado opaco del proveedor de la comparación son independientes y se descartan. `Siru::Paso::rama` devuelve al proveedor principal antes de confirmar. El error normalizado es el máximo de `abs(diferencia_i)/(absoluto_i + relativo_i*max(abs(y_i),abs(y_nuevo_i)))`; el controlador compartido usa exponente `1/2`, seguridad 0,9, reducción limitada a 0,2 y crecimiento limitado a 2, dentro de los límites de paso. No se confunde esta tolerancia temporal con la de convergencia de Calcula.

La diferencia BDF2/AB2–Euler tiene orden dos: es una política inicial conservadora, no el error local de orden tres del método principal. No garantiza una cota de error global ni implementa el controlador de un BDF de orden variable. Se valida para los cuatro métodos publicados; declarar `orden: 2` en un catálogo del usuario no demuestra sus propiedades. El lector exige orden 1/2, una etapa y arranque Euler coherente antes de habilitar esta política.

Si `h/h_anterior` queda fuera de `[0.2,2]`, se rearranca con Euler, con una pequeña holgura de redondeo en el extremo superior. También se conservan los rearranques en quiebres conocidos. Ni un rechazo ni la comparación consumen un quiebre confirmado. El último paso puede ser menor que el mínimo configurado para llegar al final; si no satisface tolerancia, aborta. Un fallo de consulta de Calcula sigue siendo fatal: aquí no se agregó un rescate por convergencia. Intentos, consultas de comparación y descartes se registran en el informe.

## Ampliaciones pendientes

1. Estimadores más eficientes y de orden superior, coeficientes que dependan de varios pasos anteriores, orden variable y otras representaciones como Nordsieck. La adaptación inicial no completa toda M2.
2. **Listas mixtas:** habilitar `GLM=[...]` solo con conversores de memoria probados. Disponer de un anillo suficientemente grande no reemplaza calcular derivadas faltantes ni transformar escalas. Analizar la composición de los métodos, además de cada método aislado.
3. **Discontinuidades y topología:** localizar el evento, resolver las restricciones del nuevo modelo e invalidar/reconstruir memoria. Esto requiere un hito específico para `.mdin`, no se activa mediante un cambio de bandera.

Contrato transaccional en [CONTRATO_PASO.md](CONTRATO_PASO.md); prioridad global en [PLAN_CAPACIDADES_MOTOR.md](PLAN_CAPACIDADES_MOTOR.md).

Pruebas: `prove -Ilib tests/*.t`; los casos persistentes están en [corpus/corpus/GLM](../corpus/corpus/GLM/README.md). `glm_matricial.t` comprueba recurrencias independientes, orden, rigidez, no linealidad, tiempos, circuito reducido, ejecución `.din`, metadatos y errores. `glm_adaptativo.t` verifica tolerancias, rechazos, historias separadas, rearranques y fallos; `glm_adaptativo_din.t`, los cuatro ejemplos adaptativos desde fuente y `.din` aislado, informes y lectura v1 fija. No se regeneraron los resultados congelados del corpus.

Verificación histórica del contrato v1: 357 pruebas de siru en 17 archivos y 67 pruebas autocontenidas de `slex/d2datdinc/probar`. La suite matricial también genera Heun de dos etapas desde un catálogo temporal y ejecuta su `.din` fijo con un ID que no existe en el catálogo instalado, comprobando que no hay una fórmula por ID oculta en el motor. Las cifras actuales de la regresión completa se registran en el ChangeLog.
