Aby spróbować sprawdzić, czy algorytm dla jakiegoś problemu jest prawidłowy, zwykle punktem wyjścia jest próba uruchomienia algorytmu ręcznie na kilku prostych przypadkach testowych - wypróbuj go na kilku przykładowych przypadkach problemów, w tym na kilku prostych „przypadkach narożnych” „. To świetna heurystyka: to świetny sposób na szybkie wyeliminowanie wielu niepoprawnych prób algorytmu i uzyskanie zrozumienia, dlaczego algorytm nie działa.
Jednak podczas uczenia się algorytmów niektórzy uczniowie mają pokusę, aby na tym poprzestać: jeśli ich algorytm działa poprawnie na kilku przykładach, w tym we wszystkich przypadkach, w których mogą spróbować, to dochodzą do wniosku, że algorytm musi być poprawny. Zawsze jest uczeń, który pyta: „Dlaczego muszę udowodnić, że mój algorytm jest poprawny, jeśli mogę po prostu wypróbować go na kilku testowych przypadkach?”
Jak więc oszukać heurystykę „wypróbuj kilka przypadków testowych”? Szukam kilku dobrych przykładów, które pokazują, że ta heurystyka nie wystarczy. Innymi słowy, szukam jednego lub więcej przykładów algorytmu, który na pozór wygląda na poprawny, i który daje prawidłową odpowiedź na wszystkie małe dane wejściowe, które ktoś może wymyślić, ale gdzie algorytm faktycznie nie działa Być może algorytm po prostu działa poprawnie na wszystkich małych wejściach i zawodzi tylko w przypadku dużych danych wejściowych lub tylko w przypadku danych wejściowych o nietypowym wzorze.
W szczególności szukam:
Algorytm. Wada musi być na poziomie algorytmu. Nie szukam błędów implementacyjnych. (Na przykład, jako minimum, przykład powinien być niezależny od języka, a wada powinna dotyczyć problemów algorytmicznych, a nie inżynierii oprogramowania lub problemów z implementacją).
Algorytm, który ktoś może wymyślić. Pseudokod powinien wyglądać co najmniej poprawnie (np. Zaciemniony lub oczywiście wątpliwy kod nie jest dobrym przykładem). Punkty bonusowe, jeśli jest to algorytm, który wymyślił uczeń podczas próby rozwiązania zadania domowego lub egzaminu.
Algorytm, który z dużym prawdopodobieństwem przejdzie rozsądną strategię testów manualnych. Ktoś, kto wypróbuje kilka małych przypadków testowych ręcznie, raczej nie powinien odkryć wady. Na przykład „symulowanie QuickCheck ręcznie na tuzinie małych przypadków testowych” raczej nie powinno ujawnić, że algorytm jest nieprawidłowy.
Najlepiej algorytm deterministyczny. Widziałem wielu uczniów, którzy uważają, że „wypróbowanie niektórych przypadków testowych ręcznie” jest rozsądnym sposobem sprawdzenia, czy algorytm deterministyczny jest prawidłowy, ale podejrzewam, że większość studentów nie założyłaby, że próba kilku przypadków testowych jest dobrym sposobem na sprawdzenie prawdopodobieństwa algorytmy. W przypadku algorytmów probabilistycznych często nie można stwierdzić, czy dane dane wyjściowe są poprawne; i nie można ręcznie przekręcić wystarczająco dużo przykładów, aby wykonać użyteczny test statystyczny rozkładu wyjściowego. Wolałbym więc skupić się na algorytmach deterministycznych, ponieważ łatwiej dostrzegają sedno nieporozumień uczniów.
Chciałbym nauczyć znaczenie sprawdzania poprawności algorytmu i mam nadzieję, że wykorzystam kilka takich przykładów, aby zmotywować dowody poprawności. Wolałbym przykłady, które są stosunkowo proste i dostępne dla studentów; przykłady wymagające ciężkiego sprzętu lub tony matematyki / algorytmu są mniej przydatne. Nie chcę też algorytmów, które są „nienaturalne”; chociaż może być łatwo skonstruować jakiś dziwny sztuczny algorytm oszukiwania heurystyki, jeśli wygląda on bardzo nienaturalnie lub ma oczywiste backdoora zbudowane tylko w celu oszukiwania tej heurystyki, prawdopodobnie nie będzie to przekonujące dla studentów. Jakieś dobre przykłady?