Benchmark algorytmu „Optymalny”

Każdy optymalizator rozkroju nazywa się „optymalnym”. My publikujemy liczby: trzy zestawy zadań testowych, niezależną wyrocznię dla małych, dowodliwe dolne ograniczenia dla warsztatowych oraz surowy JSON ze wszystkimi parametrami przebiegu. Ostatni przebieg: 2026-09-17, silnik 6edd4c42bb6b.

▶ Otwórz kalkulator

Czym naprawdę jest „Optymalny”

To nie jeden wzór, lecz przeszukiwanie kilkoma strategiami tego samego zadania: szybkie heurystyki (FFD, BFD, FFI, porządek wg ilości), programowanie dynamiczne po wzorcach, tasowany FFD i GRASP ze stałym seedem, podgląd naprzód (look-ahead) oraz dwa dokładne przeszukiwania z ograniczonym budżetem — jedno dla niewielu różnych długości, drugie dla krótkich list. Każdy kandydat przechodzi lokalne ulepszanie (opróżnianie prętów i zamiany), po czym wygrywa rozwiązanie z najmniejszą ilością materiału, a następnie z najmniejszą liczbą prętów. Budżety liczone są w operacjach, nie w sekundach — wynik jest identyczny na szybkim i na wolnym serwerze. Pokazujemy go jako „najlepsze znalezione rozwiązanie”; „udowodnione optimum” mówimy tylko wtedy, gdy osiąga matematyczne dolne ograniczenie zadania.

Metodologia

Trzy zestawy syntetycznych zadań ze stałym seedem (20260917), generowane przez tests/benchmark_optimal.py. (A) Dokładnie weryfikowalne: 200 małych zadań (2–4 pręty 60–130, 2–7 elementów 10–65, rzaz 0/1/3) z niezależną wyrocznią — pełne wyliczenie wszystkich przydziałów. (B) Stalownia: 300 list cięć — pręty 6000 mm (90 z nich z mieszanką 6000 + 12000), 8–30 różnych długości 250–5800 mm po 1–20 sztuk, rzaz 3 mm, min. resztka 300 mm; średnio 204 elementów na zadanie (od 55 do 393). (C) Skalowanie: 50, 200, 500, 1000, 2000 elementów × 3 zadania. Wszystkie tryby działają w jednym procesie na jednej maszynie; czas mierzy time.perf_counter wokół samego wywołania silnika.

(A) Zgodność z udowodnionym optimum

Dla małych zadań wyrocznia zna prawdziwe optimum. „Pełna zgodność” wymaga też tego samego rozkładu resztek na prętach; „materiał + pręty” to to, za co realnie płacisz; „min. prętów” — czy osiągnięto najmniejszą możliwą liczbę prętów.

AlgorytmPełna zgodność z wyroczniąOptimum materiał + prętyMin. prętówMediana czasu (s)
Optymalny100%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) Stalownia: 300 list cięć

Tu prawdziwe optimum jest nieznane — porównujemy z dolnym ograniczeniem: L1 = ⌈Σ(długość + rzaz) / (6000 + rzaz)⌉ oraz silniejszym L2 Martello–Totha, które liczy elementy powyżej 3000 mm, niemogące dzielić pręta. „Udowodnione optimum” = rozwiązanie osiąga ograniczenie. Przy mieszanym magazynie 6000 + 12000 liczymy w ekwiwalentach 6 m (pręt 12 m = 2) i obowiązuje tylko L1, więc ograniczenie jest tam luźniejsze. „Optymalny” jest ściśle lepszy od FFD w 38,3% zadań, równy w 61,7% i gorszy w 0%; wobec BFD — lepszy w 39,3%. Pręty zaoszczędzone względem FFD w całym zestawie: 973. Tylko zadania z jedną długością pręta (210 szt.): udowodnione optimum 31,4%, średnia różnica do ograniczenia 1,67 pręta, maksymalna 8.

AlgorytmŚr. prętów (ekw. 6 m)Śr. odpadUdowodnione optimumŚr. różnica (pręty)Maks. różnicaMediana czasu (s)95. percentyl (s)
Optymalny110,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) Skalowanie: czas wg rozmiaru

Mediana czasu w sekundach z 3 zadań dla każdego rozmiaru (tylko pręty 6000, te same parametry co w B). Silnik ma wbudowane progi: podgląd naprzód działa do 240 elementów, przeszukiwania dokładne do 600 — dlatego czas nie rośnie liniowo z rozmiarem. Rozmiary, przy których „Optymalny” przekracza 10 s: —.

ElementyOptymalnyFFDBFDFFILOOKGRASPSFFDSeq
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

Uczciwe zastrzeżenia

Zadania są losowe i syntetyczne. Równomiernie rozłożone długości 250–5800 mm są trudniejsze niż typowa lista cięć — większość elementów powyżej 3 m nie może dzielić pręta, więc odpad jest wysoki dla każdego algorytmu; liczy się różnica między nimi, nie wartość bezwzględna. Różnica do dolnego ograniczenia nie jest udowodnioną nieoptymalnością — prawdziwe optimum leży gdzieś między ograniczeniem a znalezionym rozwiązaniem. Czasy pochodzą z jednej maszyny (Python 3.14.0); serwer może być szybszy lub wolniejszy. Prawdziwe zlecenia są inne — najpewniejszy test to Twoja własna lista cięć.

Surowe dane i powtarzalność

Skrypt tests/benchmark_optimal.py (tylko biblioteka standardowa + silnik) jest częścią kodu aplikacji, który nie jest publiczny — test uruchamiamy sami. Publiczny jest surowy wynik: benchmark-results.json (backend/benchmark_results.json w kodzie); strona czyta liczby z tego pliku przy starcie — nic nie jest wpisywane ręcznie. Zapisane są w nim seed 20260917, parametry generatora zadań, limity i SHA-256 silnika 6edd4c42bb6b7ba0b5f9ee2f6d1b5f11e054c90d2c972b9a961082d945c91f4c. Pełny przebieg (py -3 tests/benchmark_optimal.py) trwa około 30 minut. Algorytm „Optymalny” jest dostępny w planach Hobby i Pro; plan darmowy liczy FFD i BFD z tych samych tabel.

Częste pytania

Dlaczego „udowodnione optimum” nie wynosi 100% w zestawie stalowni?

Bo dolne ograniczenie nie jest samym optimum. Przy zadaniu z wieloma elementami powyżej 3 m ograniczenie zaniża potrzebną liczbę prętów, więc rozwiązanie może być optymalne, choć nie potrafimy tego udowodnić. W zestawie A, gdzie optimum jest znane dokładnie, zgodność wynosi 100%.

Dlaczego FFD i BFD są tak blisko?

Przy losowych długościach większość prętów wypełnia się w oczywisty sposób i każda rozsądna heurystyka to znajduje. Różnica pojawia się w „ciasnych” zadaniach z kombinacjami 2–3 elementów, których algorytmy jednoprzebiegowe nigdy nie widzą — tam „Optymalny” wygrywa jeden–dwa pręty, a na tonę stali to realne pieniądze.

Czy mogę sam uruchomić test?

Nie — skrypt i silnik są częścią kodu aplikacji i nie są publicznie dostępne. Publiczny jest surowy JSON pod /benchmark-results.json z seedem, parametrami generatora i wynikami dla każdego zadania; każda liczba w tabelach pochodzi z niego. Najpewniejszy sprawdzian to Twoja własna lista cięć: porównaj „Optymalny” (Hobby/Pro) z FFD/BFD w kalkulatorze.

▶ Otwórz kalkulator

Więcej o optymalizacji cięcia