Jakie strategie programowania mogę zastosować do łatwej modyfikacji parametrów algorytmu?

17

Opracowywanie algorytmów naukowych jest wysoce iteracyjnym procesem, który często wymaga zmiany wielu parametrów, które będę chciał zmieniać albo w ramach mojego projektu eksperymentalnego, albo w ramach ulepszenia wydajności algorytmu. Jakie strategie mogę zastosować, aby ustrukturyzować te parametry, aby móc je łatwo zmieniać między iteracjami i aby móc łatwo dodawać nowe?

Scottie T.
źródło

Odpowiedzi:

14

Określenie każdego aspektu algorytmu jest uciążliwe dla użytkownika. Jeśli algorytm dopuszcza zagnieżdżone komponenty, nie będzie wystarczająca skończona liczba opcji. Dlatego bardzo ważne jest, aby opcje niekoniecznie „zwiększały się” do najwyższego poziomu, jak w przypadku jawnych argumentów lub parametrów szablonu. Jest to czasami nazywane „problemem konfiguracyjnym” w inżynierii oprogramowania. Wierzę, że PETSc ma wyjątkowo wydajny system zarządzania konfiguracją. Jest podobny do wzorca Service Locator w eseju Martina Fowlera na temat odwrócenia kontroli .

System konfiguracji PETSc działa poprzez kombinację konfiguracji określonej przez użytkownika zarządzanej przez obiekty solvera (z zapytaniami get i set) oraz bazą danych opcji. Każdy element symulacji może zadeklarować opcję konfiguracji, wartość domyślną i miejsce do umieszczenia wyniku. Zagnieżdżone obiekty mają prefiksy, które można komponować, dzięki czemu każdy obiekt wymagający konfiguracji można adresować niezależnie. Same opcje można odczytać z wiersza poleceń, środowiska, plików konfiguracyjnych lub z kodu. Po zadeklarowaniu opcji określa się ciąg pomocy i stronę podręcznika, aby -helpopcja była zrozumiała i aby można było napisać poprawnie połączony interfejs GUI.

Użytkownik wywołuje SetFromOptionsmetodę, aby obiekt sam się skonfigurował na podstawie opcji wiersza poleceń. Wywołanie tej funkcji jest opcjonalne i może nie zostać wywołane, jeśli użytkownik (osoba pisząca kod wywołujący PETSc) udostępnia opcje za pośrednictwem innego interfejsu. Zdecydowanie zalecamy, aby użytkownik ujawnił bazę danych opcji, ponieważ daje to użytkownikowi końcowemu (osobie uruchamiającej aplikację) dużą moc, ale nie jest to wymagane.

Typowa konfiguracja, nazywana przez

PetscObjectOptionsBegin(object); /* object has prefix and descriptive string */
PetscOptionsReal("-ts_atol",                                      /* options database key */
                 "Absolute tolerance for local truncation error", /* long description */
                 "TSSetTolerances",                               /* function and man page on topic */
                  ts->atol,                                       /* current/default value *?
                  &ts->atol,                                      /* place to store value */
                  &option_set);                                   /* TRUE if the option was set */
PetscOptionsList("-ts_type","Time stepping method","TSSetType",TSList,
                 defaultType,typeName,sizeof typeName,&option_set);
TSAdaptSetFromOptions(ts->adapt);                                 /* configures adaptive controller method */
/* ... many others */
/* ... the following is only called from implicit implementations */
SNESSetFromOptions(ts->snes);                                     /* configure nonlinear solver. */
PetscOptionsEnd();

Uwagi:

  • PetscOptionsList()przedstawia użytkownikowi wybór z listy dynamicznej. Istnieje architektura wtyczek, która może być wykorzystana przez nowe implementacje do zaprezentowania się jako pierwsza klasa dla osób dzwoniących. (Te implementacje można umieszczać we współdzielonych bibliotekach i używać jako najwyższej klasy bez ponownej kompilacji programów).
  • SNESSetFromOptions() rekurencyjnie konfiguruje solwery liniowe, warunki wstępne i wszelkie inne składniki, które wymagają konfiguracji.
Jed Brown
źródło
11

Kilka razy napotkałem ten problem podczas opracowywania własnych kodów symulacji od zera: które parametry powinny znaleźć się w pliku wejściowym, które należy pobrać z wiersza poleceń itp. Po eksperymentach okazało się, że następujące są skuteczne. (Nie jest tak zaawansowany jak PETSc.)

Zamiast pisać eksperymentalny „program” do symulacji, jestem bardziej skłonny napisać pakiet Pythona, który zawiera wszystkie funkcje i klasy potrzebne do uruchomienia symulacji. Tradycyjny plik wejściowy jest następnie zastępowany małym skryptem Python zawierającym od 5 do 10 wierszy kodu. Niektóre wiersze są zwykle związane z ładowaniem plików danych i określaniem danych wyjściowych. Inne są instrukcjami dla rzeczywistego obliczenia. Dobre wartości domyślne dla opcjonalnych argumentów w pakiecie Python umożliwiają początkującym korzystanie z biblioteki do prostych symulacji, podczas gdy zaawansowany użytkownik nadal ma dostęp do wszystkich dzwonków i gwizdków.

Kilka przykładów:

Toon Verstraelen
źródło
To świetnie, ale myślę, że jest prostopadłe do problemu z konfiguracją. Jeśli musisz określić algorytm hierarchiczny lub zagnieżdżony, masz opcje do określenia dla wielu wewnętrznych obiektów. Kod wywołujący je nie powinien nawet wiedzieć o ich istnieniu, ponieważ liczba poziomów i typy zagnieżdżania mogą się zmieniać. Na tym polega problem wszystkich „wyborów”. Dzięki wysokopoziomowemu kodowi Python możesz ułatwić określenie tych opcji, ale nadal musisz je określić w kodzie. Myślę, że generalnie nie jest to dobra rzecz.
Jed Brown
xmonad używa tej metody do konfigurowania menedżera okien dla X.
rcollyer
2

Po pierwsze, zrobiłbym algorytm ORAZ oprogramowanie tak ogólne, jak to możliwe. Nauczyłem się tego na własnej skórze.

Załóżmy, że zaczynasz od prostego przypadku testowego. Możesz to zrobić szybciej. Ale jeśli ustawisz zbyt szczegółowe oprogramowanie (zbyt mało parametrów) dla tego początkowego przypadku, tracisz coraz więcej czasu na dostosowanie go za każdym razem, gdy dodajesz nowy stopień swobody. To, co teraz robię, to spędzanie na początku więcej czasu, dzięki czemu sprawa jest dość ogólna i zwiększam zmienność parametrów w miarę postępu.

Wymaga to więcej testów od samego początku, ponieważ będziesz mieć więcej parametrów od punktu początkowego, ale oznacza to, że możesz później dużo grać z algorytmem przy zerowym lub bardzo niskim koszcie.

Przykład: algorytm polega na obliczeniu całki powierzchniowej iloczynu kropkowego dwóch funkcji wektorowych. Nie zakładaj od samego początku rozmiaru, geometrii i dyskretyzacji powierzchni, jeśli w przyszłości będziesz chciał to zmienić. Wykonaj funkcję iloczynu, spraw, aby powierzchnia była jak najbardziej ogólna, oblicz całkę w przyjemny formalny sposób. Możesz przetestować każdą wykonaną funkcję osobno.

Na początku możesz i zaczniesz integrować proste geometrie i deklarować parametry may na początku jako stałe. Z biegiem czasu, jeśli chcesz zmienić geometrię, możesz to zrobić z łatwością. Gdyby na początku założyć, musiałbyś za każdym razem zmieniać cały kod.

jbcolmenares
źródło