====================================== LU-Zerlegung mit Matrix/Vektor-Klassen ====================================== Bisher wurde die LU-Zerlegung mit den Low-Level BLAS Funktionen im Namensraum `hpc::ulmblas` implementiert. Dies soll nun abstrakter möglich sein, so dass bei der Implementierung technische Details wie Zeiger und Inkremente versteckt werden. Wie dies möglich ist, soll am Beispiel der ungeblockten LU-Zerlegung gezeigt werden. Dazu werden folgende Schritte notwendig sein: - Implementierung einer Vektor Klasse `DenseVector` mit zugehörigen View-Klassen `DenseVectorView` und `DenseVectorConstView`. - Anpassen der Matrix-Klassen, so dass Vektor-Views erzeugt werden, die eine Zeile oder Spalte referenzieren. - High-Level BLAS Wrapper für die BLAS Funktionen `scal`, `swap`, `iamax` und `ger`. Die DenseVector-Klassen ======================= Benutzt nachfolgende Vorlage für die Vektor-Klassen. Mit dem Funktions-Operator `x(i, num)` soll eine View erzeugt werden, die die Elemente mit Indices $i, \dots, i+num-1$ referenziert. ==== CODE (type=cc) ============================================================ #ifndef HPC_MATVEC_DENSEVECTOR_H #define HPC_MATVEC_DENSEVECTOR_H 1 #include #include namespace hpc { namespace matvec { template struct DenseVectorConstView; template struct DenseVectorView; template struct DenseVector { typedef T ElementType; typedef I Index; typedef DenseVector NoView; typedef DenseVectorConstView ConstView; typedef DenseVectorView View; DenseVector(Index length); ~DenseVector(); const ElementType & operator()(Index i) const; ElementType & operator()(Index i); ConstView operator()(Index i, Index num, Index stride=1) const; View operator()(Index i, Index num, Index stride=1); const Index length, inc; ElementType* data; }; template struct DenseVectorView { typedef T ElementType; typedef I Index; typedef DenseVector NoView; typedef DenseVectorConstView ConstView; typedef DenseVectorView View; DenseVectorView(Index length, ElementType *data, Index inc); const ElementType & operator()(Index i) const; ElementType & operator()(Index i); ConstView operator()(Index i, Index num, Index stride=1) const; View operator()(Index i, Index num, Index stride=1); const Index length, inc; ElementType* data; }; template struct DenseVectorConstView { typedef T ElementType; typedef I Index; typedef DenseVector NoView; typedef DenseVectorConstView ConstView; typedef DenseVectorView View; DenseVectorConstView(Index length, const ElementType *data, Index inc); const ElementType & operator()(Index i) const; ConstView operator()(Index i, Index num, Index stride=1) const; const Index length, inc; const ElementType* data; }; } } // namespace matvec, hpc #endif // HPC_MATVEC_DENSEVECTOR_H ================================================================================ Traits ====== Analog zu den Matrix-Klassen benötigen wir eine Traits-Klasse, die zur Compile-Zeit feststellt, ob es sich bei einem Template-Parameter um eine Vektor-Klasse handelt. Diese könnt ihr direkt übernehmen: ==== CODE (type=cc) ============================================================ #ifndef HPC_MATVEC_ISDENSEVECTOR_H #define HPC_MATVEC_ISDENSEVECTOR_H 1 #include #include #include #include namespace hpc { namespace matvec { template struct IsDenseVector_ { static constexpr bool value = false; }; template struct IsDenseVector_ > { static constexpr bool value = true; }; template struct IsDenseVector_ > { static constexpr bool value = true; }; template struct IsDenseVector_ > { static constexpr bool value = true; }; template struct IsDenseVector { typedef typename std::remove_reference::type Any; static constexpr bool value = IsDenseVector_::value; }; template struct IsRealDenseVector { typedef typename Vector::ElementType T; static constexpr bool value = IsDenseVector::value && !aux::IsComplex::value; }; template struct IsComplexDenseVector { typedef typename Vector::ElementType T; static constexpr bool value = IsDenseVector::value && aux::IsComplex::value; }; } } // namespace matvec, hpc #endif // HPC_MATVEC_ISDENSEVECTOR_H ================================================================================ Aufgabe ======= Folgendes Test-Programm soll benutzt werden, um die Implementierung zu testen. Dabei sollt Ihr feststellen, welchen konkreten Typ die mit `auto` deklarierten Variablen tatsächlich besitzen. Werden alle Operatoren zum Erzeugen einer Vektor-View aufgerufen? Falls nicht, ergänzt das Programm entsprechend. ==== CODE (type=cc) ============================================================ #include #include #include #include #include // // Random initializer for general matrices: real and complex valued // template void randomInit(Index m, Index n, T *A, Index incRowA, Index incColA) { std::random_device random; std::default_random_engine mt(random()); std::uniform_real_distribution uniform(-100,100); for (Index i=0; i typename std::enable_if::value, void>::type randomInit(VX &x) { typedef typename VX::Index Index; randomInit(x.length, Index(1), x.data, x.inc, Index(1)); } //------------------------------------------------------------------------------ template typename std::enable_if::value, void>::type foo(const VX &x) { std::printf("Entering foo\n"); auto y = x(3, 7); auto z = y(0, 4, 2); print(x, "x"); print(y, "y"); print(z, "z"); std::printf("Leaving foo\n"); } int main() { using namespace hpc::matvec; typedef double T; typedef std::size_t Index; DenseVector x(10); auto y = x(3, 7); auto z = y(0, 4, 2); randomInit(x); print(x, "x"); print(y, "y"); print(z, "z"); foo(x); } ================================================================================ :navigate: up -> doc:index next -> doc:session19/page02