Struktury danych dla skończonego kodu woluminu: tablice vs klasy
11
Muszę napisać skończony kod głośności dla magnetohydrodynamiki (MHD). Pisałem wcześniej kod numeryczny, ale nie w tej skali. Chciałem tylko zapytać, który będzie dobrym wyborem, używając struktury danych (podejście zorientowane obiektowo) z klasami lub po prostu używając wielu tablic dla różnych właściwości, pod względem szybkości, skalowalności itp. Planuję napisać kod w pythonie, i użyj fortran do intensywnej numerycznie części.
Prosta odpowiedź: we współczesnym pythonie każdy typ danych jest klasą, więc formalnie nie ma różnicy między dwoma zaproponowanymi przez Ciebie rozwiązaniami. (Pamiętaj, aby używać klas w nowym stylu: klasyczne klasy są przestarzałe! Zobacz http://docs.python.org/2/reference/datamodel.html#new-style-and-classic-classes )
Teraz pytanie powinno brzmieć: jak zorganizować wydajną strukturę danych w Pythonie? Nie ma wątpliwości, że sam pomysł organizowania komórek jako szeregu class Cellinstancji jest zdecydowanie zbyt nieefektywny. Skończysz na bałaganie wskaźników i nieinwazyjnych danych zorganizowanych jak skomplikowana połączona lista. Oczywiście masz możliwość łatwego wstawiania nowych komórek na liście: ale czy potrzebujesz tej funkcji? Przeciwnie, będziesz mieć nieciągłe przechowywanie danych i będziesz musiał uzyskać dostęp do każdej komórki za pomocą różnych poziomów pośrednictwa.
Jeśli uporządkujesz swoje dane jako dane, numpy.ndarraywówczas dane będą przylegały do pamięci, a dostęp do różnych komórek będzie po prostu przebiegał przez blok pamięci: oszczędność miejsca (brak marnowania pamięci na wskaźniki) i szybki .
Jak zauważył Ethan, należy stosować koncepcje OO, ale na wyższym poziomie, po wdrożeniu wydajnej struktury danych niskiego poziomu, zwykle poprzez numpy.ndarray.
Programowanie OO oznacza wiązanie danych z metodami, które działają na samych danych na wyższym poziomie abstrakcji. (Przykład: zaimplementowałem kod MES, w którym macierz sztywności została zdefiniowana jako klasa z metodą rzadkiego supernodalnego cholesowatego rozkładania na czynniki pierwsze. Pierwsza implementacja była w rdzeniu: gdy potrzebna była implementacja poza rdzeniem, to uzyskano poprzez dziedziczenie i minimalne korekty podkreślającego przechowywania danych. Ponownie wykorzystano prawie 100% supernodalnego kodu cholesky.)
Ostatni komentarz, ale kluczowy: wydajna procedura numeryczna jest wynikiem inteligentnego mapowania algorytmu i struktury danych na docelową architekturę obliczeniową. Jeśli zaczniesz od niewłaściwej struktury danych, nie będzie możliwości odzyskania wydajności bez pełnego przepisania.
@EthanCoon Dziękuję za komentarz do drugiej odpowiedzi, która skłoniła mnie do napisania własnego.
Stefano M
10
Zastanawiałem się nad tym kilka dni temu (także w Pythonie). Osobiście nie sądzę, aby programowanie obiektowe zawsze dobrze pasowało do programowania numerycznego. Możesz się rozpraszać projektowaniem klas, a nie rozwiązywaniem równań. Wolę pozostać przy prostych funkcjach, a dzięki numpy możesz wektoryzować swoje równania, więc liczba potrzebnych linii jest bardzo mała. Numpy jest dość szybkie, ponieważ rzeczywiste obliczenia są wykonywane przy użyciu zaplecza C (lub FORTRAN?).
Co poleciłbym ci zrobić,
Napisz skrypt w języku Python, który rozwiązuje najprostszą możliwą wersję twojego problemu, stosując funkcjonalne podejście z numpy. Na przykład, miej wszystko w dowolnej jednostce i wypróbuj tylko 1D (lub 2D). Na tym etapie jest całkowicie w porządku, jeśli kod jest nieuporządkowany. Ważne jest, abyś kontynuował swój projekt.
Gdy masz coś, co działa. Określ, gdzie jest kod pełny i refraktor. Na tym etapie możesz bawić się z różnymi pomysłami na uproszczenie kodu. Może wprowadzić funkcje, w których zauważysz, że się powtarzasz. Możesz porównać z oryginalną wersją, aby wiedzieć, że nie wprowadzasz błędów.
Zdecyduj, czy podejście obiektowe jeszcze bardziej zmniejszy złożoność kodu.
Głównym przesłaniem jest nie zaczynaj pisać klas, dopóki problem nie zostanie rozwiązany w najprostszy możliwy sposób. Tylko dzięki zdobyciu doświadczenia w rozwiązaniu problemu będziesz wiedział, jak zdefiniować interfejs zorientowany obiektowo. Jeśli zrobisz to przed rozdaniem, może to po prostu przeszkodzić.
Zdecydowanie nie zgadzam się ze stwierdzeniem, że OO nie jest dobrym dopasowaniem do programowania numerycznego, ale tam, gdzie jest to dobre dopasowanie, znajduje się na znacznie wyższym poziomie. OO jest bardzo przydatne do takich rzeczy, jak modele fizyczne, siatki, solwery itp., Ale prawie zawsze jest niewłaściwe na poziomie komórek.
Ethan Coon
W poście chciałem ostrzec przed potencjalnymi upadkami „przedwczesnego uprzedmiotowienia” kodu numerycznego, szczególnie gdy zaczyna się. Nie jestem przeciwny używaniu obiektów, zobacz mój trzeci punkt: jeśli obiekty mogą zmniejszyć złożoność, to są dobrym pomysłem. Zgadzam się, że przytaczane przez ciebie przykłady to dobre zastosowania, ale do tego momentu wymaga doświadczenia.
Zastanawiałem się nad tym kilka dni temu (także w Pythonie). Osobiście nie sądzę, aby programowanie obiektowe zawsze dobrze pasowało do programowania numerycznego. Możesz się rozpraszać projektowaniem klas, a nie rozwiązywaniem równań. Wolę pozostać przy prostych funkcjach, a dzięki numpy możesz wektoryzować swoje równania, więc liczba potrzebnych linii jest bardzo mała. Numpy jest dość szybkie, ponieważ rzeczywiste obliczenia są wykonywane przy użyciu zaplecza C (lub FORTRAN?).
Co poleciłbym ci zrobić,
Głównym przesłaniem jest nie zaczynaj pisać klas, dopóki problem nie zostanie rozwiązany w najprostszy możliwy sposób. Tylko dzięki zdobyciu doświadczenia w rozwiązaniu problemu będziesz wiedział, jak zdefiniować interfejs zorientowany obiektowo. Jeśli zrobisz to przed rozdaniem, może to po prostu przeszkodzić.
źródło