Бенчмарк на алгоритъма „Оптимален“

Всеки оптимизатор на разкрой се нарича „оптимален“. Ние публикуваме числата: три набора тестови задачи, независим оракул за малките, доказуеми долни граници за цеховите и суровия JSON с всички параметри на прогона. Последен прогон: 2026-09-17, ядро 6edd4c42bb6b.

▶ Отвори калкулатора

Какво всъщност е „Оптимален“

Не е една формула, а търсене с няколко стратегии върху една и съща задача: бързите евристики (FFD, BFD, FFI, подредба по брой), динамично програмиране по шаблони, разбъркан FFD и GRASP с фиксиран seed, поглед напред (lookahead) и две точни търсения с ограничен бюджет — за малко различни дължини и за малки списъци. Всеки кандидат минава през локално подобрение (изпразване на пръти и размени), след което печели решението с най-малко материал, после с най-малко пръти. Бюджетите са в брой операции, не в секунди — резултатът е един и същ на бърз и на бавен сървър. Показваме го като „най-доброто намерено решение“; „доказано оптимално“ казваме само когато то достига математическата долна граница за задачата.

Методология

Три набора синтетични задачи с фиксиран seed (20260917), генерирани от скрипта tests/benchmark_optimal.py. (A) Точно проверими: 200 малки задачи (2–4 заготовки 60–130, 2–7 отрязъка 10–65, срез 0/1/3) с независим оракул — пълно изброяване на всички разпределения. (B) Стоманен цех: 300 спецификации — заготовки 6000 mm (90 от тях със смес 6000 + 12000), 8–30 различни дължини 250–5800 mm по 1–20 броя, срез 3 mm, мин. остатък 300 mm; средно 204 отрязъка на задача (от 55 до 393). (C) Мащаб: 50, 200, 500, 1000, 2000 отрязъка × 3 задачи. Всички режими се пускат в един процес на една машина; времето е time.perf_counter около самото извикване на ядрото.

(A) Съвпадение с доказания оптимум

При малките задачи оракулът знае истинския оптимум. „Пълно съвпадение“ изисква и същото разпределение на остатъците по прътите; „материал + пръти“ е това, което реално плащаш; „мин. пръти“ — дали е постигнат най-малкият възможен брой пръти.

АлгоритъмПълно съвпадение с оракулаОптимум по материал и прътиМин. прътиМедианно време (s)
Оптимален100%100%100%<0.01
FFD42.5%74.5%84%<0.01
BFD42.5%74.5%84%<0.01
FFI32.5%62.5%76.5%<0.01
LOOK63%80.5%88.5%<0.01
GRASP64%79.5%88%<0.01
SFFD65.5%80.5%88.5%<0.01
Seq31%59.5%59.5%<0.01

(B) Стоманен цех: 300 спецификации

Тук истинският оптимум е неизвестен — сравняваме с долна граница: L1 = ⌈Σ(дължина + срез) / (6000 + срез)⌉ и по-силната L2 на Martello–Toth, която брои отрязъците над 3000 mm, неспособни да делят прът. „Доказан оптимум“ = решението достига границата. При смесен склад 6000 + 12000 броим в 6-метрови еквиваленти (12 m прът = 2) и важи само L1, затова там границата е по-хлабава. „Оптимален“ е строго по-добър от FFD в 38.3% от задачите, равен в 61.7% и по-лош в 0%; спрямо BFD — по-добър в 39.3%. Общо спестени пръти спрямо FFD в целия набор: 973. Само за задачите с единичен склад (210 бр.): доказан оптимум 31.4%, средна разлика до границата 1.67 пръта, максимална 8.

АлгоритъмСр. пръти (6 m екв.)Ср. отпадъкДоказан оптимумСр. разлика (пръти)Макс. разликаМедианно време (s)95-и перц. (s)
Оптимален110.77.7%26.3%1.79123.8511.34
FFD114.010.4%21.3%5.04470.030.08
BFD114.010.5%21.3%5.05470.030.08
FFI114.310.7%20.7%5.35470.040.11
GRASP114.010.4%21.3%5.02470.230.66
SFFD114.010.4%20.7%5.06470.150.47
Seq120.315.2%6.3%11.35490.010.02

(C) Мащабиране: време по размер

Медианно време в секунди по 3 задачи за всеки размер (единичен склад 6000, същите параметри като в B). Ядрото има вградени гейтове: погледът напред работи до 240 отрязъка, точните търсения — до 600, затова времето не расте линейно с размера. Размери, при които „Оптимален“ надхвърля 10 s: —.

ОтрязъциОптималенFFDBFDFFILOOKGRASPSFFDSeq
500.21<0.01<0.01<0.010.100.020.01<0.01
2006.740.010.030.022.900.260.160.01
5004.020.240.250.250.171.490.940.03
10005.860.280.240.300.311.521.420.08
20007.610.310.680.310.384.173.690.44

Честни уговорки

Задачите са случайни и синтетични. Равномерно разпределените дължини 250–5800 mm са по-тежки от типична спецификация — повечето отрязъци над 3 m не могат да делят прът, затова отпадъкът е висок при всички алгоритми; важна е разликата между тях, не абсолютната стойност. Разликата до долната граница не е доказана неоптималност — истинският оптимум е някъде между границата и намереното решение. Времената са от една машина (Python 3.14.0); сървърът може да е по-бърз или по-бавен. Реалните поръчки са различни — най-сигурният тест е твоята спецификация.

Сурови данни и възпроизводимост

Скриптът tests/benchmark_optimal.py (само стандартна библиотека + ядрото) е част от кода на приложението, който не е публичен — теста го пускаме ние. Публичен е суровият резултат: benchmark-results.json (backend/benchmark_results.json в кода); страницата чете числата от него при стартиране — нищо не се пише на ръка. В него са seed 20260917, параметрите на генератора на задачи, лимитите и SHA-256 на ядрото 6edd4c42bb6b7ba0b5f9ee2f6d1b5f11e054c90d2c972b9a961082d945c91f4c. Пълният прогон (py -3 tests/benchmark_optimal.py) отнема около 30 минути. Алгоритъмът „Оптимален“ е достъпен в плановете Hobby и Pro; безплатният план смята с FFD и BFD от същите таблици.

Често задавани въпроси

Защо „доказан оптимум“ не е 100% в цеховия набор?

Защото долната граница не е самият оптимум. При задача с много отрязъци над 3 m границата подценява нужните пръти и решението може да е оптимално, без да можем да го докажем. В набор A, където оптимумът е известен точно, съвпадението е 100%.

Защо FFD и BFD са толкова близо?

При случайни дължини повечето пръти се запълват еднозначно и всяка разумна евристика ги намира. Разликата идва в „стегнатите“ задачи с комбинации от 2–3 отрязъка, които еднопроходните алгоритми не виждат — там „Оптимален“ печели по един-два пръта, а на тон стомана това е реална сума.

Мога ли да пусна теста сам?

Не — скриптът и ядрото са част от кода на приложението и не са публично достъпни. Публичен е суровият JSON на /benchmark-results.json със seed, параметрите на генератора и резултатите по задача; всяко число в таблиците е от него. Най-сигурната проверка е твоята спецификация: сравни „Оптимален“ (Hobby/Pro) с FFD/BFD в калкулатора.

▶ Отвори калкулатора

Още за разкроя