inverse tested

master
Marc Wäckerlin 8 years ago
parent 549db697b7
commit 2f35c1e3a0
  1. 2
      COPYING
  2. 2
      INSTALL
  3. 194
      src/matrix.hxx
  4. 74
      test/basic.cxx

@ -1 +1 @@
/usr/share/automake-1.15/COPYING /usr/share/automake-1.14/COPYING

@ -1 +1 @@
/usr/share/automake-1.15/INSTALL /usr/share/automake-1.14/INSTALL

@ -9,9 +9,45 @@
#include <cstring> #include <cstring>
#include <cassert> #include <cassert>
#include <type_traits> #include <type_traits>
#include <limits>
namespace math {
template<typename TYPE>
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<TYPE>::epsilon();
return diff<=max*std::numeric_limits<TYPE>::epsilon();
}
template<typename TYPE>
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<typename TYPE, typename ARRAY=TYPE*> class MatrixBase { template<typename TYPE, typename ARRAY=TYPE*> class MatrixBase {
//..............................................................constants //..............................................................constants
public: public:
@ -21,7 +57,7 @@ template<typename TYPE, typename ARRAY=TYPE*> class MatrixBase {
const size_t MEM_SIZE; const size_t MEM_SIZE;
//...............................................................typedefs //...............................................................typedefs
public: public:
/// @name Auxiliary Classes /// @name Auxiliary Classes
///{ ///{
@ -61,7 +97,7 @@ template<typename TYPE, typename ARRAY=TYPE*> class MatrixBase {
const MatrixBase& _m; const MatrixBase& _m;
const TYPE *_v; const TYPE *_v;
}; };
///} ///}
//................................................................methods //................................................................methods
@ -69,7 +105,7 @@ template<typename TYPE, typename ARRAY=TYPE*> class MatrixBase {
/// @name construction /// @name construction
///{ ///{
MatrixBase(size_t rows, size_t columns): MatrixBase(size_t rows, size_t columns):
ROWS(rows), COLUMNS(columns), ROWS(rows), COLUMNS(columns),
SIZE(ROWS*COLUMNS), MEM_SIZE(SIZE*sizeof(TYPE)) { SIZE(ROWS*COLUMNS), MEM_SIZE(SIZE*sizeof(TYPE)) {
@ -86,48 +122,48 @@ template<typename TYPE, typename ARRAY=TYPE*> class MatrixBase {
/// @name element access /// @name element access
///{ ///{
TYPE& at(size_t row, size_t column) { TYPE& at(size_t row, size_t column) {
assert(row<ROWS); assert(row<ROWS);
assert(column<COLUMNS); assert(column<COLUMNS);
return *((TYPE*)_c+row*COLUMNS+column); return *((TYPE*)_c+row*COLUMNS+column);
} }
const TYPE& at(size_t row, size_t column) const { const TYPE& at(size_t row, size_t column) const {
assert(row<ROWS); assert(row<ROWS);
assert(column<COLUMNS); assert(column<COLUMNS);
return *((TYPE*)_c+row*COLUMNS+column); return *((TYPE*)_c+row*COLUMNS+column);
} }
TYPE& operator()(size_t row, size_t column) { TYPE& operator()(size_t row, size_t column) {
return at(row, column); return at(row, column);
} }
const TYPE& operator()(size_t row, size_t column) const { const TYPE& operator()(size_t row, size_t column) const {
return at(row, column); return at(row, column);
} }
RowVector operator[](size_t row) { RowVector operator[](size_t row) {
assert(row<ROWS); assert(row<ROWS);
return RowVector(*this, (TYPE*)_c+row*COLUMNS); return RowVector(*this, (TYPE*)_c+row*COLUMNS);
} }
const ConstRowVector operator[](size_t row) const { const ConstRowVector operator[](size_t row) const {
assert(row<ROWS); assert(row<ROWS);
return ConstRowVector(*this, (TYPE*)_c+row*COLUMNS); return ConstRowVector(*this, (TYPE*)_c+row*COLUMNS);
} }
///} ///}
/// @name operators /// @name operators
///{ ///{
MatrixBase& operator=(TYPE oc[]) { MatrixBase& operator=(TYPE oc[]) {
assert(sizeof(oc)==MEM_SIZE); assert(sizeof(oc)==MEM_SIZE);
memcpy(_c, oc, MEM_SIZE); memcpy(_c, oc, MEM_SIZE);
return *this; return *this;
} }
MatrixBase& operator=(const MatrixBase& o) { MatrixBase& operator=(const MatrixBase& o) {
assert_check(o); assert_check(o);
memcpy(_c, o._c, MEM_SIZE); memcpy(_c, o._c, MEM_SIZE);
@ -137,7 +173,7 @@ template<typename TYPE, typename ARRAY=TYPE*> class MatrixBase {
bool operator==(const MatrixBase& o) const { bool operator==(const MatrixBase& o) const {
if (!check(o)) return false; if (!check(o)) return false;
TYPE *to((TYPE*)(_c)+SIZE), *from((TYPE*)(o._c)+SIZE); 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; return true;
} }
@ -176,6 +212,13 @@ template<typename TYPE, typename ARRAY=TYPE*> class MatrixBase {
/// @name special operations /// @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 det() {
TYPE res(gauss()); TYPE res(gauss());
for (TYPE *p((TYPE*)(_c)+SIZE); --p>=(TYPE*)(_c); p-=COLUMNS) res *= *p; for (TYPE *p((TYPE*)(_c)+SIZE); --p>=(TYPE*)(_c); p-=COLUMNS) res *= *p;
@ -204,7 +247,7 @@ template<typename TYPE, typename ARRAY=TYPE*> class MatrixBase {
} }
///} ///}
//................................................................methods //................................................................methods
protected: protected:
@ -215,7 +258,7 @@ template<typename TYPE, typename ARRAY=TYPE*> class MatrixBase {
//..............................................................variables //..............................................................variables
protected: protected:
ARRAY _c; ARRAY _c;
}; };
@ -235,7 +278,7 @@ template<typename TYPE, size_t TROWS=0, size_t TCOLUMNS=0> class Matrix:
/// @name construction /// @name construction
///{ ///{
Matrix(): Parent(TROWS, TCOLUMNS) { Matrix(): Parent(TROWS, TCOLUMNS) {
memset(Parent::_c, 0, Parent::MEM_SIZE); memset(Parent::_c, 0, Parent::MEM_SIZE);
} }
@ -253,12 +296,12 @@ template<typename TYPE, size_t TROWS=0, size_t TCOLUMNS=0> class Matrix:
/// @name operators /// @name operators
///{ ///{
Matrix& operator=(TYPE oc[TROWS][TCOLUMNS]) { Matrix& operator=(TYPE oc[TROWS][TCOLUMNS]) {
memcpy(Parent::_c, oc, Parent::MEM_SIZE); memcpy(Parent::_c, oc, Parent::MEM_SIZE);
return *this; return *this;
} }
Matrix operator-() const { Matrix operator-() const {
Matrix res; Matrix res;
for (TYPE *to((TYPE*)(res._c)+Parent::SIZE); to>(TYPE*)(Parent::_c); --to) for (TYPE *to((TYPE*)(res._c)+Parent::SIZE); to>(TYPE*)(Parent::_c); --to)
@ -278,7 +321,7 @@ template<typename TYPE, size_t TROWS=0, size_t TCOLUMNS=0> class Matrix:
} }
///} ///}
/// @name special operations /// @name special operations
///{ ///{
@ -302,27 +345,45 @@ template<typename TYPE, size_t TROWS=0, size_t TCOLUMNS=0> class Matrix:
Matrix o(*this); // left side Matrix o(*this); // left side
*this = i(); // right side *this = i(); // right side
/// 1. lower left part /// 1. lower left part
for (size_t row(0); row<this->ROWS; ++row) for (size_t column(0); column<this->COLUMNS; ++column) {
if (rows<this->COLUMNS) { if (column<this->ROWS) {
/// 2. normalize first line to first value /// 2. normalize pivot to one
TYPE pivot(o(row, row)); TYPE pivot(o(column, column));
if (pivot!=1) { if (pivot!=1) {
o(row, row) = 1; o(column, column) = 1;
for (size_t column(row+1); column<this->COLUMNS; ++column) o(row, column)/=pivot; for (size_t pos(column+1); pos<this->COLUMNS; ++pos)
for (size_t column(row); column<this->COLUMNS; ++column) this->at(row, column)/=pivot; o(column, pos)/=pivot;
for (size_t pos(0); pos<this->COLUMNS; ++pos)
this->at(column, pos)/=pivot;
} }
/// 3. nullify lower triangle /// 3. nullify lower triangle
for (size_t row(column+1); row<this->ROWS; ++row) { for (size_t row(column+1); row<this->ROWS; ++row) {
TYPE pivot(o(row, column)); TYPE pivot(o(row, column));
if (pivot!=0) { if (pivot!=0) {
o(row, column) = 0; o(row, column) = 0;
for (size_t pos(column+1); pos<this->COLUMNS; ++pos) o(row, pos) -= pivot*o(0, pos); for (size_t pos(column+1); pos<this->COLUMNS; ++pos)
for (size_t pos(column); pos<this->COLUMNS; ++pos) this->at(row, pos) -= pivot*this->at(0, pos); o(row, pos) -= pivot*o(column, pos);
for (size_t pos(0); pos<this->COLUMNS; ++pos)
this->at(row, pos) -= pivot*this->at(column, pos);
} }
} }
} }
}
/// 4. nullify the upper triangle /// 4. nullify the upper triangle
const size_t LASTCOL(this->COLUMNS-1);
const size_t LASTROW(this->ROWS-1);
for (size_t column(1); column<this->COLUMNS; ++column) {
for (size_t row(0); row<column && row<LASTROW; ++row) {
TYPE pivot(o(row, column));
if (pivot!=0) {
o(row, column) = 0;
for (size_t pos(column+1); pos<this->COLUMNS; ++pos)
o(row, pos) -= pivot*o(column, pos);
for (size_t pos(0); pos<this->COLUMNS; ++pos)
this->at(row, pos) -= pivot*this->at(column, pos);
}
}
}
return *this; return *this;
} }
@ -340,12 +401,12 @@ template<typename TYPE> class Matrix<TYPE, 0, 0>: public MatrixBase<TYPE> {
//................................................................methods //................................................................methods
public: public:
/// @name construction /// @name construction
///{ ///{
Matrix() = delete; Matrix() = delete;
Matrix(size_t rows, size_t columns): Matrix(size_t rows, size_t columns):
Parent(rows, columns) { Parent(rows, columns) {
assert(rows>0); assert(rows>0);
@ -357,7 +418,7 @@ template<typename TYPE> class Matrix<TYPE, 0, 0>: public MatrixBase<TYPE> {
Matrix(const Matrix& o): Matrix(o.ROWS, o.Parent::COLUMNS) { Matrix(const Matrix& o): Matrix(o.ROWS, o.Parent::COLUMNS) {
memcpy(Parent::_c, o.Parent::_c, Parent::MEM_SIZE); memcpy(Parent::_c, o.Parent::_c, Parent::MEM_SIZE);
} }
template<typename ...ARGS> template<typename ...ARGS>
Matrix(size_t rows, size_t columns, ARGS...t): Matrix(size_t rows, size_t columns, ARGS...t):
Matrix(rows, columns) { Matrix(rows, columns) {
@ -373,24 +434,12 @@ template<typename TYPE> class Matrix<TYPE, 0, 0>: public MatrixBase<TYPE> {
virtual ~Matrix() { virtual ~Matrix() {
delete[] Parent::_c; delete[] Parent::_c;
} }
///} ///}
/// @name operators /// @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 operator-() const {
Matrix res(Parent::COLUMNS, Parent::ROWS); Matrix res(Parent::COLUMNS, Parent::ROWS);
for (TYPE *to((TYPE*)(res._c)+Parent::SIZE); to>(TYPE*)(Parent::_c); --to) for (TYPE *to((TYPE*)(res._c)+Parent::SIZE); to>(TYPE*)(Parent::_c); --to)
@ -412,7 +461,7 @@ template<typename TYPE> class Matrix<TYPE, 0, 0>: public MatrixBase<TYPE> {
///@name special operations ///@name special operations
///{ ///{
Matrix t() const { Matrix t() const {
Matrix res(this->COLUMNS, this->ROWS); Matrix res(this->COLUMNS, this->ROWS);
for (size_t row(0); row<this->ROWS; ++row) for (size_t row(0); row<this->ROWS; ++row)
@ -428,6 +477,54 @@ template<typename TYPE> class Matrix<TYPE, 0, 0>: public MatrixBase<TYPE> {
return res; 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); column<this->COLUMNS; ++column) {
if (column<this->ROWS) {
/// 2. normalize pivot to one
TYPE pivot(o(column, column));
if (pivot!=1) {
o(column, column) = 1;
for (size_t pos(column+1); pos<this->COLUMNS; ++pos)
o(column, pos)/=pivot;
for (size_t pos(0); pos<this->COLUMNS; ++pos)
this->at(column, pos)/=pivot;
}
/// 3. nullify lower triangle
for (size_t row(column+1); row<this->ROWS; ++row) {
TYPE pivot(o(row, column));
if (pivot!=0) {
o(row, column) = 0;
for (size_t pos(column+1); pos<this->COLUMNS; ++pos)
o(row, pos) -= pivot*o(column, pos);
for (size_t pos(0); pos<this->COLUMNS; ++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); column<this->COLUMNS; ++column) {
for (size_t row(0); row<column && row<LASTROW; ++row) {
TYPE pivot(o(row, column));
if (pivot!=0) {
o(row, column) = 0;
for (size_t pos(column+1); pos<this->COLUMNS; ++pos)
o(row, pos) -= pivot*o(column, pos);
for (size_t pos(0); pos<this->COLUMNS; ++pos)
this->at(row, pos) -= pivot*this->at(column, pos);
}
}
}
return *this;
}
///} ///}
//................................................................methods //................................................................methods
@ -494,4 +591,3 @@ template<typename TYPE, size_t ROWS, size_t COLUMNS>
s<<'\n'; s<<'\n';
} }
} }

@ -204,17 +204,41 @@ class TemplateMatrixTest: public CppUnit::TestFixture {
} }
template<typename T> template<typename T>
void inv() { void inv() {
Matrix<T,3,3> m(2, -1, 0, {
1, 2, -2, Matrix<T,3,3> m(2, -1, 0,
0, -1, 1); 1, 2, -2,
const Matrix<T,3,3> res(0.5, 0, 0, 0, -1, 1);
-0.2, 0.4, 0, const Matrix<T,3,3> res(0, 1, 2,
-1, 2, 5); -1, 2, 4,
// const Matrix<T,3,3> res(0, 1, 2, -1, 2, 5);
// -1, 2, 4, m.inv();
// -1, 2, 5); CPPUNIT_ASSERT(m.similar(res, 0.0001));
m.inv(); } {
CPPUNIT_ASSERT_EQUAL(res, m); Matrix<T,3,3> m(1, 2, 3,
0, 1, 4,
5, 6, 0);
const Matrix<T,3,3> res(-24, 18, 5,
20, -15, -4,
-5, 4, 1);
m.inv();
CPPUNIT_ASSERT_EQUAL(res, m);
} {
Matrix<T,3,3> m(1, 2, 3,
0, 4, 5,
1, 0, 6);
const Matrix<T,3,3> 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<T,2,2> m(4, 3,
3, 2);
const Matrix<T,2,2> res(-2, 3,
3, -4);
m.inv();
CPPUNIT_ASSERT_EQUAL(res, m);
}
} }
CPPUNIT_TEST_SUITE(TemplateMatrixTest); CPPUNIT_TEST_SUITE(TemplateMatrixTest);
CPPUNIT_TEST(initFromArray1<int>); CPPUNIT_TEST(initFromArray1<int>);
@ -502,6 +526,32 @@ class VariableMatrixTest: public CppUnit::TestFixture {
CPPUNIT_ASSERT_EQUAL(m2, m2.i()); CPPUNIT_ASSERT_EQUAL(m2, m2.i());
CPPUNIT_ASSERT_EQUAL(m3, m3.i()); CPPUNIT_ASSERT_EQUAL(m3, m3.i());
} }
template<typename T>
void inv() {
{
Matrix<T> m(3, 3,
2, -1, 0,
1, 2, -2,
0, -1, 1);
const Matrix<T> res(3, 3,
0, 1, 2,
-1, 2, 4,
-1, 2, 5);
m.inv();
CPPUNIT_ASSERT(m.similar(res, 0.0001));
} {
Matrix<T> m(3, 3,
1, 2, 3,
0, 1, 4,
5, 6, 0);
const Matrix<T> 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_SUITE(VariableMatrixTest);
CPPUNIT_TEST(initFromArray1<int>); CPPUNIT_TEST(initFromArray1<int>);
CPPUNIT_TEST(initFromArray1<long>); CPPUNIT_TEST(initFromArray1<long>);
@ -583,6 +633,8 @@ class VariableMatrixTest: public CppUnit::TestFixture {
CPPUNIT_TEST(i<unsigned long>); CPPUNIT_TEST(i<unsigned long>);
CPPUNIT_TEST(i<float>); CPPUNIT_TEST(i<float>);
CPPUNIT_TEST(i<double>); CPPUNIT_TEST(i<double>);
CPPUNIT_TEST(inv<float>);
CPPUNIT_TEST(inv<double>);
CPPUNIT_TEST_SUITE_END(); CPPUNIT_TEST_SUITE_END();
}; };
CPPUNIT_TEST_SUITE_REGISTRATION(VariableMatrixTest); CPPUNIT_TEST_SUITE_REGISTRATION(VariableMatrixTest);

Loading…
Cancel
Save