From 55b73617171c9390940f946007f29de1bc282f13 Mon Sep 17 00:00:00 2001 From: Hartmut Seichter <hartmut@technotecture.com> Date: Fri, 18 Jan 2019 09:34:48 +0100 Subject: [PATCH] basic function work and are validated against octave output --- src/core/include/pw/core/matrixbase.hpp | 102 ++++++++++++++++++------ src/core/tests/pwcore_test_matrix.cpp | 45 ++++++++++- 2 files changed, 123 insertions(+), 24 deletions(-) diff --git a/src/core/include/pw/core/matrixbase.hpp b/src/core/include/pw/core/matrixbase.hpp index d5608c5..402b631 100644 --- a/src/core/include/pw/core/matrixbase.hpp +++ b/src/core/include/pw/core/matrixbase.hpp @@ -31,9 +31,9 @@ #include <utility> #include <initializer_list> -namespace pw { +#include <iostream> -// http://coliru.stacked-crooked.com/a/34db679ee8c13a80 +namespace pw { template <typename T, typename Derived> struct matrixbase_ { @@ -97,6 +97,14 @@ struct matrix_ : matrixbase_<T, matrix_<T, R, C>> { return *this; } + template <typename... Arguments> + matrix_(Arguments ...values) + : data {values... } + { + static_assert(sizeof...(Arguments) == R*C, + "Incorrect number of arguments"); + } + //! rows inline std::size_t rows() const { return R; } @@ -106,7 +114,7 @@ struct matrix_ : matrixbase_<T, matrix_<T, R, C>> { //! get cell count inline std::size_t coefficients() const { return R * C; } - inline size_t offset(int r,int c) const { + inline size_t offset(size_t r,size_t c) const { return (RowMajor) ? r * C + c : c * R + r; } @@ -146,11 +154,33 @@ struct matrix_ : matrixbase_<T, matrix_<T, R, C>> { return *this; } + + template<std::size_t Rs,std::size_t Cs,bool RowMajorSlice = RowMajor> + matrix_<T,Rs,Cs,RowMajorSlice> minor(std::size_t r0,std::size_t c0) const + { + matrix_<T,Rs,Cs,RowMajorSlice> m; + size_t r = 0; + for (size_t ri = 0; ri < R; ri++) { + size_t c = 0; + if (ri == r0) + continue; + for (size_t ci = 0; ci < C; ci++) + { + if (ci == c0) + continue; + m(r,c) = (*this)(ri,ci); + c++; + } + r++; + } + return m; + } + T determinant() const { T det(0); - for (size_t c = 0; c < C; c++) { - det += ((c % 2 == 0) ? (*this)(0,c) : -(*this)(0,c)) * this->slice<R-1,C-1>(0,c).determinant(); - } + for (size_t c = 0; c < C; c++) + det += ((c % 2 == 0) ? (*this)(0,c) : -(*this)(0,c)) + * this->minor<R-1,C-1,RowMajor>(0,c).determinant(); return det; } @@ -162,21 +192,17 @@ struct matrix_ : matrixbase_<T, matrix_<T, R, C>> { return res; } - matrix_ inverse() const - { - matrix_ resMat; - - for ( unsigned int r = 0; r < C; ++r) { - for ( unsigned int j = 0; j < R; ++j) { - short sgn = ((r+j)%2) ? -1 : 1; - auto minor = this->slice<R-1,C-1>(r,j); - resMat(r,j) = minor.determinant() * sgn; - } - } - - resMat = resMat.transposed(); - resMat *= T(1)/this->determinant(); - return resMat; + matrix_<T,C,R,RowMajor> inverse() const { + T invDet = T(1) / this->determinant(); + matrix_<T,C,R,RowMajor> inv; + for (int j = 0; j < C; j++) + for (int i = 0; i < R; i++) + { + const T minorDet = this->minor<R-1,C-1,RowMajor>(j,i).determinant(); + const T coFactor = ((i + j) % 2 == 1) ? -minorDet : minorDet; + inv(i, j) = invDet * coFactor; + } + return inv; } inline bool row_major() const { @@ -190,23 +216,48 @@ struct matrix_ : matrixbase_<T, matrix_<T, R, C>> { template <> inline float matrix_<float,1,1>::determinant() const { - return (*this)[0]; + return (*this)(0,0); } template <> inline double matrix_<double,1,1>::determinant() const { - return (*this)[0]; + return (*this)(0,0); } +template <typename T, std::size_t R, std::size_t Ca,std::size_t Cb> +auto operator * (const matrix_<T, R, Ca>& A, + const matrix_<T, R, Cb>& B + ) +{ + matrix_<T,R,Cb> result; result.zero(); // zero the output + for (size_t r = 0; r < R; r++) + for (size_t c = 0; c < Cb; c++) + for (size_t iI = 0; iI < R; iI++) + result(r,c) += A(r,iI) * B(iI,c); // inner product + return result; +} + +// +// +// + template <typename T, std::size_t N,bool RowMajor = false> struct vector_ : matrix_<T, N, 1, RowMajor> { typedef matrix_<T, N, 1, RowMajor> derived_type; + vector_() = default; vector_(const derived_type& rhs) : derived_type(rhs) {} + template <typename... Arguments> + vector_(Arguments ...values) + : derived_type( { values...} ) + { + static_assert(sizeof...(Arguments) == N, + "Incorrect number of arguments"); + } }; template <typename T, typename U, std::size_t N,bool RowMajor = false> @@ -233,9 +284,14 @@ auto dot(const vector_<T, N, RowMajor>& a, const vector_<U, N, RowMajor>& b) // template <typename T> using matrix2x2_ = matrix_<T, 2, 2>; +template <typename T> using matrix3x3_ = matrix_<T, 3, 3>; +template <typename T> using matrix4x4_ = matrix_<T, 4, 4>; + using matrix2x2f = matrix_<float, 2, 2>; template <typename T> using vector2_ = vector_<T, 2>; +template <typename T> using vector3_ = vector_<T, 3>; +template <typename T> using vector4_ = vector_<T, 4>; using vector2f = vector2_<float>; diff --git a/src/core/tests/pwcore_test_matrix.cpp b/src/core/tests/pwcore_test_matrix.cpp index 885db41..ae063fc 100644 --- a/src/core/tests/pwcore_test_matrix.cpp +++ b/src/core/tests/pwcore_test_matrix.cpp @@ -7,21 +7,64 @@ #include <pw/core/debug.hpp> #include <iostream> +#include <sstream> + +template <typename T_,typename O_,size_t R,size_t C> inline static +std::basic_ostream<O_>& operator << (std::basic_ostream<O_>& os, + const pw::matrix_<T_,R,C>& m + ) +{ + for (size_t r = 0; r < R;r++){ + for (size_t c = 0;c < C;c++) { + os << m(r,c) << " "; + } + os << std::endl; + } + return os; +} int main(int argc,char **argv) { - using namespace pw; matrix2x2f m22; m22.zero(); + m22(0,0) = 1; m22(0,1) = 2; m22(1,0) = 3; m22(1,1) = 4; + vector2f v2; + v2[0] = 1; v2[1] = 3; + + vector2f v3(1.f,2.f); + + auto m22_inv = m22.inverse(); + auto m22_id = m22_inv * m22; + + auto v2_t = m22_id * v2; + auto v3_t = m22_id * v3; + + + + auto v2_f = m22 * v2; + auto v2_b = m22_inv * v2_f; + debug::d() << "offset(0,1) col-major " << m22.offset(0,1); debug::d() << "det " << m22.determinant(); + std::cout << "m22 " << m22 << std::endl; + std::cout << "m22-1 " << m22_inv << std::endl; + std::cout << "m22-i " << m22_id << std::endl; + std::cout << "v22_t " << v2_t << std::endl; + std::cout << "v3_t " << v3_t << std::endl; + + std::cout << "v2_f " << v2_f << std::endl; + std::cout << "v2_b " << v2_b << std::endl; + + + + // vector2f v2 = m22.slice<2,1>(0,0); // m22.set_slice<2,1>(v2,0,0);