Todo optimizador de corte se llama a sí mismo «óptimo». Nosotros publicamos las cifras: tres conjuntos de problemas de prueba, un oráculo independiente para los pequeños, cotas inferiores demostrables para los de taller y el JSON bruto con todos los parámetros de la ejecución. Última ejecución: 2026-09-17, motor 6edd4c42bb6b.
▶ Abrir la calculadoraNo es una fórmula, sino una búsqueda con varias estrategias sobre el mismo trabajo: las heurísticas rápidas (FFD, BFD, FFI, orden por cantidad), programación dinámica por patrones, FFD barajado y GRASP con semilla fija, anticipación (look-ahead) y dos búsquedas exactas con presupuesto acotado — una para pocas longitudes distintas, otra para listas cortas. Cada candidato pasa por una mejora local (vaciado de barras e intercambios) y gana la solución con menos material, después con menos barras. Los presupuestos se cuentan en operaciones, no en segundos — el resultado es idéntico en un servidor rápido o lento. Lo mostramos como «mejor solución encontrada»; decimos «óptimo probado» solo cuando alcanza la cota inferior matemática del problema.
Tres conjuntos de problemas sintéticos con semilla fija (20260917), generados por tests/benchmark_optimal.py. (A) Verificables exactamente: 200 problemas pequeños (2–4 barras 60–130, 2–7 piezas 10–65, grosor de corte 0/1/3) con oráculo independiente — enumeración completa de todas las asignaciones. (B) Taller de acero: 300 listas de corte — barras de 6000 mm (90 de ellas con mezcla 6000 + 12000), 8–30 longitudes distintas de 250–5800 mm con 1–20 unidades cada una, corte 3 mm, resto mínimo 300 mm; 204 piezas por trabajo de media (de 55 a 393). (C) Escalado: 50, 200, 500, 1000, 2000 piezas × 3 trabajos. Todos los modos se ejecutan en un solo proceso en una máquina; el tiempo es time.perf_counter alrededor de la propia llamada al motor.
En los problemas pequeños el oráculo conoce el óptimo real. «Coincidencia total» exige también la misma distribución de restos entre barras; «material + barras» es lo que realmente pagas; «mín. barras» — si se alcanzó el menor número posible de barras.
| Algoritmo | Coincidencia total con el oráculo | Óptimo material + barras | Mín. barras | Tiempo mediano (s) |
|---|---|---|---|---|
| Óptimo | 100% | 100% | 100% | <0,01 |
| FFD | 42,5% | 74,5% | 84% | <0,01 |
| BFD | 42,5% | 74,5% | 84% | <0,01 |
| FFI | 32,5% | 62,5% | 76,5% | <0,01 |
| LOOK | 63% | 80,5% | 88,5% | <0,01 |
| GRASP | 64% | 79,5% | 88% | <0,01 |
| SFFD | 65,5% | 80,5% | 88,5% | <0,01 |
| Seq | 31% | 59,5% | 59,5% | <0,01 |
Aquí el óptimo real es desconocido — comparamos con una cota inferior: L1 = ⌈Σ(longitud + corte) / (6000 + corte)⌉ y la más fuerte L2 de Martello–Toth, que cuenta las piezas de más de 3000 mm que no pueden compartir barra. «Óptimo probado» = la solución alcanza la cota. Con la mezcla 6000 + 12000 contamos en equivalentes de 6 m (una barra de 12 m = 2) y solo aplica L1, así que la cota es más holgada. «Óptimo» es estrictamente mejor que FFD en el 38,3% de los trabajos, igual en el 61,7% y peor en el 0%; frente a BFD es mejor en el 39,3%. Barras ahorradas frente a FFD en todo el conjunto: 973. Solo trabajos con una longitud de barra (210): óptimo probado 31,4%, diferencia media a la cota 1,67 barras, máxima 8.
| Algoritmo | Barras medias (eq. 6 m) | Desperdicio medio | Óptimo probado | Diferencia media (barras) | Diferencia máx. | Tiempo mediano (s) | Percentil 95 (s) |
|---|---|---|---|---|---|---|---|
| Óptimo | 110,7 | 7,7% | 26,3% | 1,79 | 12 | 3,85 | 11,34 |
| FFD | 114,0 | 10,4% | 21,3% | 5,04 | 47 | 0,03 | 0,08 |
| BFD | 114,0 | 10,5% | 21,3% | 5,05 | 47 | 0,03 | 0,08 |
| FFI | 114,3 | 10,7% | 20,7% | 5,35 | 47 | 0,04 | 0,11 |
| GRASP | 114,0 | 10,4% | 21,3% | 5,02 | 47 | 0,23 | 0,66 |
| SFFD | 114,0 | 10,4% | 20,7% | 5,06 | 47 | 0,15 | 0,47 |
| Seq | 120,3 | 15,2% | 6,3% | 11,35 | 49 | 0,01 | 0,02 |
Tiempo mediano en segundos sobre 3 trabajos por tamaño (solo barras de 6000, mismos parámetros que en B). El motor tiene límites integrados: la anticipación funciona hasta 240 piezas y las búsquedas exactas hasta 600, por eso el tiempo no crece linealmente con el tamaño. Tamaños en los que «Óptimo» supera los 10 s: —.
| Piezas | Óptimo | FFD | BFD | FFI | LOOK | GRASP | SFFD | Seq |
|---|---|---|---|---|---|---|---|---|
| 50 | 0,21 | <0,01 | <0,01 | <0,01 | 0,10 | 0,02 | 0,01 | <0,01 |
| 200 | 6,74 | 0,01 | 0,03 | 0,02 | 2,90 | 0,26 | 0,16 | 0,01 |
| 500 | 4,02 | 0,24 | 0,25 | 0,25 | 0,17 | 1,49 | 0,94 | 0,03 |
| 1000 | 5,86 | 0,28 | 0,24 | 0,30 | 0,31 | 1,52 | 1,42 | 0,08 |
| 2000 | 7,61 | 0,31 | 0,68 | 0,31 | 0,38 | 4,17 | 3,69 | 0,44 |
Los problemas son aleatorios y sintéticos. Longitudes uniformemente distribuidas de 250–5800 mm son más duras que una lista de corte típica — la mayoría de las piezas de más de 3 m no pueden compartir barra, así que el desperdicio es alto para todos los algoritmos; lo que importa es la diferencia entre ellos, no el valor absoluto. Una diferencia con la cota inferior no es una suboptimalidad probada — el óptimo real está en algún punto entre la cota y la solución encontrada. Los tiempos son de una sola máquina (Python 3.14.0); el servidor puede ser más rápido o más lento. Los trabajos reales son distintos — la prueba más segura es tu propia lista de corte.
El script tests/benchmark_optimal.py (solo biblioteca estándar + el motor) forma parte del código de la aplicación, que no es público — la prueba la ejecutamos nosotros. Lo público es el resultado bruto: benchmark-results.json (backend/benchmark_results.json en el código); la página lee sus cifras de ese archivo al arrancar — nada se escribe a mano. Contiene la semilla 20260917, los parámetros del generador de problemas, los límites y el SHA-256 del motor 6edd4c42bb6b7ba0b5f9ee2f6d1b5f11e054c90d2c972b9a961082d945c91f4c. La ejecución completa (py -3 tests/benchmark_optimal.py) tarda unos 30 minutos. El algoritmo «Óptimo» está disponible en los planes Hobby y Pro; el plan gratuito calcula con FFD y BFD de las mismas tablas.
Porque la cota inferior no es el óptimo en sí. En un trabajo con muchas piezas de más de 3 m la cota subestima las barras necesarias, así que una solución puede ser óptima sin que podamos probarlo. En el conjunto A, donde el óptimo se conoce exactamente, la coincidencia es del 100%.
Con longitudes aleatorias la mayoría de las barras se llenan de forma evidente y cualquier heurística razonable lo encuentra. La diferencia aparece en los trabajos «ajustados» con combinaciones de 2–3 piezas que los algoritmos de una sola pasada nunca ven — ahí «Óptimo» gana una o dos barras, y por tonelada de acero eso es dinero real.
No — el script y el motor forman parte del código de la aplicación y no son de acceso público. Lo público es el JSON bruto en /benchmark-results.json con la semilla, los parámetros del generador y los resultados por problema; cada cifra de las tablas sale de él. La comprobación más segura es tu propia lista de corte: compara «Óptimo» (Hobby/Pro) con FFD/BFD en la calculadora.