diff --git a/COPYING b/COPYING index 88798ab..caeca07 120000 --- a/COPYING +++ b/COPYING @@ -1 +1 @@ -/usr/share/automake-1.15/COPYING \ No newline at end of file +/usr/share/automake-1.14/COPYING \ No newline at end of file diff --git a/INSTALL b/INSTALL index ddcdb76..f812f5a 120000 --- a/INSTALL +++ b/INSTALL @@ -1 +1 @@ -/usr/share/automake-1.15/INSTALL \ No newline at end of file +/usr/share/automake-1.14/INSTALL \ No newline at end of file diff --git a/src/matrix.hxx b/src/matrix.hxx index 6fa2e34..f405d72 100644 --- a/src/matrix.hxx +++ b/src/matrix.hxx @@ -9,9 +9,45 @@ #include #include #include +#include + +namespace math { + + template + bool almostEqual(TYPE a, TYPE b) { + if (a<0) + if (b<0) { + a = -a; + b = -b; + } else return a==b; // different signs + else if (b<0) return a==b; // different signs + TYPE diff(abs(a-b)); + a = abs(a); + b = abs(b); + TYPE max(a>b?a:b); + if (max<1) return diff<=std::numeric_limits::epsilon(); + return diff<=max*std::numeric_limits::epsilon(); + } + + template + bool equal(const TYPE& a, const TYPE& b) { + return a==b; + } + + template<> + bool equal(const double& a, const double& b) { + return almostEqual(a, b); + } + + template<> + bool equal(const float& a, const float& b) { + return almostEqual(a, b); + } + +} template class MatrixBase { - + //..............................................................constants public: @@ -21,7 +57,7 @@ template class MatrixBase { const size_t MEM_SIZE; //...............................................................typedefs - public: + public: /// @name Auxiliary Classes ///{ @@ -61,7 +97,7 @@ template class MatrixBase { const MatrixBase& _m; const TYPE *_v; }; - + ///} //................................................................methods @@ -69,7 +105,7 @@ template class MatrixBase { /// @name construction ///{ - + MatrixBase(size_t rows, size_t columns): ROWS(rows), COLUMNS(columns), SIZE(ROWS*COLUMNS), MEM_SIZE(SIZE*sizeof(TYPE)) { @@ -86,48 +122,48 @@ template class MatrixBase { /// @name element access ///{ - + TYPE& at(size_t row, size_t column) { assert(row class MatrixBase { bool operator==(const MatrixBase& o) const { if (!check(o)) return false; TYPE *to((TYPE*)(_c)+SIZE), *from((TYPE*)(o._c)+SIZE); - while (to>(TYPE*)(_c)) if (*--to != *--from) return false; + while (to>(TYPE*)(_c)) if (!math::equal(*--to, *--from)) return false; return true; } @@ -176,6 +212,13 @@ template class MatrixBase { /// @name special operations ///{ + bool similar(const MatrixBase& o, const TYPE& diff) const { + if (!check(o)) return false; + TYPE *to((TYPE*)(_c)+SIZE), *from((TYPE*)(o._c)+SIZE); + while (to>(TYPE*)(_c)) if (abs(*--to - *--from)>diff) return false; + return true; + } + TYPE det() { TYPE res(gauss()); for (TYPE *p((TYPE*)(_c)+SIZE); --p>=(TYPE*)(_c); p-=COLUMNS) res *= *p; @@ -204,7 +247,7 @@ template class MatrixBase { } ///} - + //................................................................methods protected: @@ -215,7 +258,7 @@ template class MatrixBase { //..............................................................variables protected: - + ARRAY _c; }; @@ -235,7 +278,7 @@ template class Matrix: /// @name construction ///{ - + Matrix(): Parent(TROWS, TCOLUMNS) { memset(Parent::_c, 0, Parent::MEM_SIZE); } @@ -253,12 +296,12 @@ template class Matrix: /// @name operators ///{ - + Matrix& operator=(TYPE oc[TROWS][TCOLUMNS]) { memcpy(Parent::_c, oc, Parent::MEM_SIZE); return *this; } - + Matrix operator-() const { Matrix res; for (TYPE *to((TYPE*)(res._c)+Parent::SIZE); to>(TYPE*)(Parent::_c); --to) @@ -278,7 +321,7 @@ template class Matrix: } ///} - + /// @name special operations ///{ @@ -302,27 +345,45 @@ template class Matrix: Matrix o(*this); // left side *this = i(); // right side /// 1. lower left part - for (size_t row(0); rowROWS; ++row) - if (rowsCOLUMNS) { - /// 2. normalize first line to first value - TYPE pivot(o(row, row)); + for (size_t column(0); columnCOLUMNS; ++column) { + if (columnROWS) { + /// 2. normalize pivot to one + TYPE pivot(o(column, column)); if (pivot!=1) { - o(row, row) = 1; - for (size_t column(row+1); columnCOLUMNS; ++column) o(row, column)/=pivot; - for (size_t column(row); columnCOLUMNS; ++column) this->at(row, column)/=pivot; + o(column, column) = 1; + for (size_t pos(column+1); posCOLUMNS; ++pos) + o(column, pos)/=pivot; + for (size_t pos(0); posCOLUMNS; ++pos) + this->at(column, pos)/=pivot; } /// 3. nullify lower triangle for (size_t row(column+1); rowROWS; ++row) { TYPE pivot(o(row, column)); if (pivot!=0) { o(row, column) = 0; - for (size_t pos(column+1); posCOLUMNS; ++pos) o(row, pos) -= pivot*o(0, pos); - for (size_t pos(column); posCOLUMNS; ++pos) this->at(row, pos) -= pivot*this->at(0, pos); + for (size_t pos(column+1); posCOLUMNS; ++pos) + o(row, pos) -= pivot*o(column, pos); + for (size_t pos(0); posCOLUMNS; ++pos) + this->at(row, pos) -= pivot*this->at(column, pos); } } } + } /// 4. nullify the upper triangle - + const size_t LASTCOL(this->COLUMNS-1); + const size_t LASTROW(this->ROWS-1); + for (size_t column(1); columnCOLUMNS; ++column) { + for (size_t row(0); rowCOLUMNS; ++pos) + o(row, pos) -= pivot*o(column, pos); + for (size_t pos(0); posCOLUMNS; ++pos) + this->at(row, pos) -= pivot*this->at(column, pos); + } + } + } return *this; } @@ -340,12 +401,12 @@ template class Matrix: public MatrixBase { //................................................................methods public: - + /// @name construction ///{ Matrix() = delete; - + Matrix(size_t rows, size_t columns): Parent(rows, columns) { assert(rows>0); @@ -357,7 +418,7 @@ template class Matrix: public MatrixBase { Matrix(const Matrix& o): Matrix(o.ROWS, o.Parent::COLUMNS) { memcpy(Parent::_c, o.Parent::_c, Parent::MEM_SIZE); } - + template Matrix(size_t rows, size_t columns, ARGS...t): Matrix(rows, columns) { @@ -373,24 +434,12 @@ template class Matrix: public MatrixBase { virtual ~Matrix() { delete[] Parent::_c; } - + ///} - + /// @name operators ///{ - Matrix& operator=(const Matrix& o) { - if (o.ROWS!=Parent::ROWS&&o.COLUMNS!=Parent::COLUMNS) { - delete[] Parent::_c; - Parent::ROWS = o.ROWS; - Parent::COLUMNS = o.COLUMNS; - Parent::SIZE = o.SIZE; - Parent::MEM_SIZE = o.MEM_SIZE; - Parent::_c = new TYPE[Parent::SIZE]; - } - return Parent::operator=(o); - } - Matrix operator-() const { Matrix res(Parent::COLUMNS, Parent::ROWS); for (TYPE *to((TYPE*)(res._c)+Parent::SIZE); to>(TYPE*)(Parent::_c); --to) @@ -412,7 +461,7 @@ template class Matrix: public MatrixBase { ///@name special operations ///{ - + Matrix t() const { Matrix res(this->COLUMNS, this->ROWS); for (size_t row(0); rowROWS; ++row) @@ -428,6 +477,54 @@ template class Matrix: public MatrixBase { return res; } + Matrix& inv() { + /// calculate using gauss-jordan algorithmus + /// @see http://www.mathebibel.de/inverse-matrix-berechnen-nach-gauss-jordan + Matrix o(*this); // left side + *this = i(); // right side + /// 1. lower left part + for (size_t column(0); columnCOLUMNS; ++column) { + if (columnROWS) { + /// 2. normalize pivot to one + TYPE pivot(o(column, column)); + if (pivot!=1) { + o(column, column) = 1; + for (size_t pos(column+1); posCOLUMNS; ++pos) + o(column, pos)/=pivot; + for (size_t pos(0); posCOLUMNS; ++pos) + this->at(column, pos)/=pivot; + } + /// 3. nullify lower triangle + for (size_t row(column+1); rowROWS; ++row) { + TYPE pivot(o(row, column)); + if (pivot!=0) { + o(row, column) = 0; + for (size_t pos(column+1); posCOLUMNS; ++pos) + o(row, pos) -= pivot*o(column, pos); + for (size_t pos(0); posCOLUMNS; ++pos) + this->at(row, pos) -= pivot*this->at(column, pos); + } + } + } + } + /// 4. nullify the upper triangle + const size_t LASTCOL(this->COLUMNS-1); + const size_t LASTROW(this->ROWS-1); + for (size_t column(1); columnCOLUMNS; ++column) { + for (size_t row(0); rowCOLUMNS; ++pos) + o(row, pos) -= pivot*o(column, pos); + for (size_t pos(0); posCOLUMNS; ++pos) + this->at(row, pos) -= pivot*this->at(column, pos); + } + } + } + return *this; + } + ///} //................................................................methods @@ -494,4 +591,3 @@ template s<<'\n'; } } - diff --git a/test/basic.cxx b/test/basic.cxx index 3664281..3c5e8c2 100644 --- a/test/basic.cxx +++ b/test/basic.cxx @@ -204,17 +204,41 @@ class TemplateMatrixTest: public CppUnit::TestFixture { } template void inv() { - Matrix m(2, -1, 0, - 1, 2, -2, - 0, -1, 1); - const Matrix res(0.5, 0, 0, - -0.2, 0.4, 0, - -1, 2, 5); - // const Matrix res(0, 1, 2, - // -1, 2, 4, - // -1, 2, 5); - m.inv(); - CPPUNIT_ASSERT_EQUAL(res, m); + { + Matrix m(2, -1, 0, + 1, 2, -2, + 0, -1, 1); + const Matrix res(0, 1, 2, + -1, 2, 4, + -1, 2, 5); + m.inv(); + CPPUNIT_ASSERT(m.similar(res, 0.0001)); + } { + Matrix m(1, 2, 3, + 0, 1, 4, + 5, 6, 0); + const Matrix res(-24, 18, 5, + 20, -15, -4, + -5, 4, 1); + m.inv(); + CPPUNIT_ASSERT_EQUAL(res, m); + } { + Matrix m(1, 2, 3, + 0, 4, 5, + 1, 0, 6); + const Matrix res((T)12/11, (T)-6/11, (T)-1/11, + (T)5/22, (T)3/22, (T)-5/22, + (T)-2/11, (T)1/11, (T)2/11); + m.inv(); + CPPUNIT_ASSERT_EQUAL(res, m); + } { + Matrix m(4, 3, + 3, 2); + const Matrix res(-2, 3, + 3, -4); + m.inv(); + CPPUNIT_ASSERT_EQUAL(res, m); + } } CPPUNIT_TEST_SUITE(TemplateMatrixTest); CPPUNIT_TEST(initFromArray1); @@ -502,6 +526,32 @@ class VariableMatrixTest: public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(m2, m2.i()); CPPUNIT_ASSERT_EQUAL(m3, m3.i()); } + template + void inv() { + { + Matrix m(3, 3, + 2, -1, 0, + 1, 2, -2, + 0, -1, 1); + const Matrix res(3, 3, + 0, 1, 2, + -1, 2, 4, + -1, 2, 5); + m.inv(); + CPPUNIT_ASSERT(m.similar(res, 0.0001)); + } { + Matrix m(3, 3, + 1, 2, 3, + 0, 1, 4, + 5, 6, 0); + const Matrix res(3, 3, + -24, 18, 5, + 20, -15, -4, + -5, 4, 1); + m.inv(); + CPPUNIT_ASSERT_EQUAL(res, m); + } + } CPPUNIT_TEST_SUITE(VariableMatrixTest); CPPUNIT_TEST(initFromArray1); CPPUNIT_TEST(initFromArray1); @@ -583,6 +633,8 @@ class VariableMatrixTest: public CppUnit::TestFixture { CPPUNIT_TEST(i); CPPUNIT_TEST(i); CPPUNIT_TEST(i); + CPPUNIT_TEST(inv); + CPPUNIT_TEST(inv); CPPUNIT_TEST_SUITE_END(); }; CPPUNIT_TEST_SUITE_REGISTRATION(VariableMatrixTest);