diff --git a/configure.ac b/configure.ac index 627ee31..f3fd7b5 100644 --- a/configure.ac +++ b/configure.ac @@ -9,8 +9,9 @@ ## 45678901234567890123456789012345678901234567890123456789012345678901234567890 m4_define(x_package_name, libmatricxx) # project's name -m4_define(x_major, 0) # project's major version -m4_define(x_minor, 2) # project's minor version +m4_define(x_major, 1) # project's major version +m4_define(x_minor, 0) # project's minor version +m4_define(x_least_diff, 12) # start at 0 m4_include(ax_init_standard_project.m4) AC_INIT(x_package_name, x_version, x_bugreport, x_package_name) AM_INIT_AUTOMAKE([1.9 tar-pax parallel-tests color-tests]) diff --git a/src/matrix.hxx b/src/matrix.hxx index f405d72..0687868 100644 --- a/src/matrix.hxx +++ b/src/matrix.hxx @@ -6,27 +6,26 @@ // 45678901234567890123456789012345678901234567890123456789012345678901234567890 #include +#include #include #include #include #include +#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); + a = std::fabs(a); + b = std::fabs(b); + TYPE diff(std::fabs(a-b)); TYPE max(a>b?a:b); - if (max<1) return diff<=std::numeric_limits::epsilon(); - return diff<=max*std::numeric_limits::epsilon(); + if (max<1) return diff<=1000*std::numeric_limits::epsilon(); + return diff<=max*1000*std::numeric_limits::epsilon(); } template @@ -34,6 +33,11 @@ namespace math { return a==b; } + template<> + bool equal(const long double& a, const long double& b) { + return almostEqual(a, b); + } + template<> bool equal(const double& a, const double& b) { return almostEqual(a, b); @@ -158,12 +162,6 @@ template class MatrixBase { /// @name operators ///{ - MatrixBase& operator=(TYPE oc[]) { - assert(sizeof(oc)==MEM_SIZE); - memcpy(_c, oc, MEM_SIZE); - return *this; - } - MatrixBase& operator=(const MatrixBase& o) { assert_check(o); memcpy(_c, o._c, MEM_SIZE); @@ -212,11 +210,10 @@ 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; + MatrixBase& apply(std::function fn) { + TYPE *to((TYPE*)(_c)+SIZE); + while (to>(TYPE*)(_c)) fn(*--to); + return *this; } TYPE det() { @@ -230,6 +227,10 @@ template class MatrixBase { /// @see http://www.mathebibel.de/determinante-berechnen-nach-gauss /// 1. normalize first line to first value TYPE lambda(at(0, 0)); + if (lambda==0) { + feraiseexcept(FE_DIVBYZERO); + throw std::range_error("gauss calculation failed"); + } at(0, 0) = 1; for (TYPE *p((TYPE*)(_c)+COLUMNS); p>(TYPE*)(_c)+1;) *--p/=lambda; /// 2. nullify lower triangle @@ -297,15 +298,34 @@ template class Matrix: /// @name operators ///{ - Matrix& operator=(TYPE oc[TROWS][TCOLUMNS]) { - memcpy(Parent::_c, oc, Parent::MEM_SIZE); + Matrix& operator=(const Matrix& o) { + Parent::operator=(o); + return *this; + } + + Matrix& operator+=(const Matrix& o) { + Parent::operator+=(o); + return *this; + } + + Matrix& operator-=(const Matrix& o) { + Parent::operator-=(o); + return *this; + } + + Matrix& operator*=(const TYPE& o) { + Parent::operator*=(o); + return *this; + } + + Matrix& operator/=(const TYPE& o) { + Parent::operator/=(o); return *this; } Matrix operator-() const { - Matrix res; - for (TYPE *to((TYPE*)(res._c)+Parent::SIZE); to>(TYPE*)(Parent::_c); --to) - *to = -*to; + Matrix res(*this); + for (TYPE *to((TYPE*)(res._c)+this->SIZE); to>(TYPE*)(res._c); *--to = -*to); return res; } @@ -325,6 +345,11 @@ template class Matrix: /// @name special operations ///{ + Matrix& apply(std::function fn) { + Parent::apply(fn); + return *this; + } + Matrix t() const { Matrix res; for (size_t row(0); row class Matrix: public MatrixBase { /// @name operators ///{ + Matrix& operator=(const Matrix& o) { + Parent::operator=(o); + return *this; + } + + Matrix& operator+=(const Matrix& o) { + Parent::operator+=(o); + return *this; + } + + Matrix& operator-=(const Matrix& o) { + Parent::operator-=(o); + return *this; + } + + Matrix& operator*=(const TYPE& o) { + Parent::operator*=(o); + return *this; + } + + Matrix& operator/=(const TYPE& o) { + Parent::operator/=(o); + return *this; + } + Matrix operator-() const { - Matrix res(Parent::COLUMNS, Parent::ROWS); - for (TYPE *to((TYPE*)(res._c)+Parent::SIZE); to>(TYPE*)(Parent::_c); --to) - *to = -*to; + Matrix res(*this); + for (TYPE *to((TYPE*)(res._c)+this->SIZE); to>(TYPE*)(res._c); *--to = -*to); return res; } @@ -462,6 +511,11 @@ template class Matrix: public MatrixBase { ///@name special operations ///{ + Matrix& apply(std::function fn) { + Parent::apply(fn); + return *this; + } + Matrix t() const { Matrix res(this->COLUMNS, this->ROWS); for (size_t row(0); rowROWS; ++row) @@ -582,12 +636,61 @@ template return res; } +template + Matrix operator/(const Matrix& m, + const TYPE& v) { + Matrix res(m); + res /= v; + return res; +} + +template + Matrix operator/(const TYPE& v, + const Matrix& m) { + Matrix res(m); + res.inv() *= v; + return res; +} + +template + Matrix operator/(const Matrix& m1, + const Matrix& m2) { + Matrix res(m2); + return m1 * res.inv(); +} + template std::ostream& operator<<(std::ostream& s, const Matrix& m) { - for (size_t w = 0; w < m.ROWS; ++w) { - for (size_t h = 0; h < m.COLUMNS;++h) { - s< + std::istream& operator>>(std::istream& in, Matrix& m) { + std::ios_base::failure err("illegal matrix format"); + char c(0); + size_t sz(0); + TYPE val(0); + std::string s; + if (!in.get(c) || c!='[') throw err; + if (!std::getline(in, s, 'x') || !(std::stringstream(s)>>sz) || sz!=m.ROWS) throw err; + if (!std::getline(in, s, ']') || !(std::stringstream(s)>>sz) || sz!=m.COLUMNS) throw err; + if (!in.get(c) || c!='{') throw err; + for (size_t row = 0; row < m.ROWS; ++row) { + for (size_t column = 0; column < m.COLUMNS; ++column) { + if (row==m.ROWS-1&&column==m.COLUMNS) { + if (!std::getline(in, s, '}') || !(std::stringstream(s)>>val)) throw err; + } else { + if (!std::getline(in, s, ',') || !(std::stringstream(s)>>val)) throw err; + } + m(row, column) = val; } - s<<'\n'; } + return in; } diff --git a/test/basic.cxx b/test/basic.cxx index 3c5e8c2..d44fe72 100644 --- a/test/basic.cxx +++ b/test/basic.cxx @@ -19,6 +19,10 @@ class TemplateMatrixTest: public CppUnit::TestFixture { void initFromArray1() { const Matrix m {1, 2, 3, 4, 5, 6, 7, 8}; + Matrix m2; + m2 = {1, 2, 3, 4, + 5, 6, 7, 8}; + CPPUNIT_ASSERT_EQUAL(m, m2); CPPUNIT_ASSERT_EQUAL((T)1, m[0][0]); CPPUNIT_ASSERT_EQUAL((T)2, m[0][1]); CPPUNIT_ASSERT_EQUAL((T)3, m[0][2]); @@ -62,6 +66,9 @@ class TemplateMatrixTest: public CppUnit::TestFixture { Matrix m2(m1); m1[0][2] = 16; m2[0][0] = 0; + Matrix m3; + m3 = m2; + CPPUNIT_ASSERT_EQUAL(m2, m3); CPPUNIT_ASSERT_EQUAL((T)1, m1[0][0]); CPPUNIT_ASSERT_EQUAL((T)2, m1[0][1]); CPPUNIT_ASSERT_EQUAL((T)16, m1[0][2]); @@ -133,6 +140,7 @@ class TemplateMatrixTest: public CppUnit::TestFixture { const Matrix res(-1, -2, -3, -4, 4, 3, 2, 1); CPPUNIT_ASSERT_EQUAL(res, m); + CPPUNIT_ASSERT_EQUAL(res, -m2+m1); } template void scalar_mult() { @@ -148,6 +156,15 @@ class TemplateMatrixTest: public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(two*m1*two, m1*four); CPPUNIT_ASSERT_EQUAL(big*m1*four, m1*four*big); } + template + void scalar_div() { + const Matrix m1(2, 4, 6, 8, + 10, 12, 14, 16); + const Matrix m2(1, 2, 3, 4, + 5, 6, 7, 8); + CPPUNIT_ASSERT_EQUAL(m2, m1/(T)2); + CPPUNIT_ASSERT_EQUAL(m2, (T)3*m1/(T)6); + } template void matrix_mult() { const Matrix m1(1, 2, 3, @@ -169,6 +186,14 @@ class TemplateMatrixTest: public CppUnit::TestFixture { 3, 6); CPPUNIT_ASSERT_EQUAL(res, m.t()); } + template + void apply() { + Matrix m(2, -2, 4, + -2, 1, -6, + 1, 0, -2); + Matrix o(m); + CPPUNIT_ASSERT_EQUAL((T)3*o, m.apply([](T& t){t*=3;})); + } template void gauss() { Matrix m(2, -2, 4, @@ -211,8 +236,12 @@ class TemplateMatrixTest: public CppUnit::TestFixture { const Matrix res(0, 1, 2, -1, 2, 4, -1, 2, 5); + Matrix o1(m), o2(m); m.inv(); - CPPUNIT_ASSERT(m.similar(res, 0.0001)); + CPPUNIT_ASSERT_EQUAL((T)2*res, (T)2/o1); + CPPUNIT_ASSERT_EQUAL(o1.i(), o1/o2); + CPPUNIT_ASSERT_EQUAL(res, m); + } { Matrix m(1, 2, 3, 0, 1, 4, @@ -229,7 +258,34 @@ class TemplateMatrixTest: public CppUnit::TestFixture { 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); + Matrix o1(m), o2(m); m.inv(); + CPPUNIT_ASSERT_EQUAL((T)2*res, (T)2/o1); + CPPUNIT_ASSERT_EQUAL(o1.i(), o1/o2); + CPPUNIT_ASSERT_EQUAL(res, m); + } { + Matrix m(-2, 0, 1, + 9, 2, -3, + 5, 1, -2); + const Matrix res(-1, 1, -2, + 3, -1, 3, + -1, 2, -4); + Matrix o(m); + m.inv(); + CPPUNIT_ASSERT_EQUAL(m.i(), m*o); + CPPUNIT_ASSERT_EQUAL(res, m); + } { + Matrix m(2, 1, 4, 1, + -1, 1, 0, 2, + 0, 0, 2, 4, + 2, -2, 0, 1); + const Matrix res((T)-1/3, (T)13/15, (T)-2/3, 0.6, + (T)1/3, (T)16/15, (T)-2/3, 0.2, + 0, -0.8, 0.5, -0.4, + 0, 0.4, 0, 0.2); + Matrix o(m); + m.inv(); + CPPUNIT_ASSERT_EQUAL(m.i(), m*o); CPPUNIT_ASSERT_EQUAL(res, m); } { Matrix m(4, 3, @@ -240,6 +296,19 @@ class TemplateMatrixTest: public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(res, m); } } + template + void stream() { + const Matrix m1(1, 2, 3, 4, + 5, 6, 7, 8, + 1, 4, 2, 8); + Matrix m2; + std::string res("[3x4]{1,2,3,4,5,6,7,8,1,4,2,8}"); + std::stringstream ss; + ss<>m2; + CPPUNIT_ASSERT_EQUAL(m1, m2); + } CPPUNIT_TEST_SUITE(TemplateMatrixTest); CPPUNIT_TEST(initFromArray1); CPPUNIT_TEST(initFromArray1); @@ -295,6 +364,12 @@ class TemplateMatrixTest: public CppUnit::TestFixture { CPPUNIT_TEST(scalar_mult); CPPUNIT_TEST(scalar_mult); CPPUNIT_TEST(scalar_mult); + CPPUNIT_TEST(scalar_div); + CPPUNIT_TEST(scalar_div); + CPPUNIT_TEST(scalar_div); + CPPUNIT_TEST(scalar_div); + CPPUNIT_TEST(scalar_div); + CPPUNIT_TEST(scalar_div); CPPUNIT_TEST(matrix_mult); CPPUNIT_TEST(matrix_mult); CPPUNIT_TEST(matrix_mult); @@ -307,6 +382,12 @@ class TemplateMatrixTest: public CppUnit::TestFixture { CPPUNIT_TEST(transpose); CPPUNIT_TEST(transpose); CPPUNIT_TEST(transpose); + CPPUNIT_TEST(apply); + CPPUNIT_TEST(apply); + CPPUNIT_TEST(apply); + CPPUNIT_TEST(apply); + CPPUNIT_TEST(apply); + CPPUNIT_TEST(apply); CPPUNIT_TEST(gauss); CPPUNIT_TEST(gauss); CPPUNIT_TEST(gauss); @@ -323,6 +404,13 @@ class TemplateMatrixTest: public CppUnit::TestFixture { CPPUNIT_TEST(i); CPPUNIT_TEST(inv); CPPUNIT_TEST(inv); + CPPUNIT_TEST(inv); + CPPUNIT_TEST(stream); + CPPUNIT_TEST(stream); + CPPUNIT_TEST(stream); + CPPUNIT_TEST(stream); + CPPUNIT_TEST(stream); + CPPUNIT_TEST(stream); CPPUNIT_TEST_SUITE_END(); }; CPPUNIT_TEST_SUITE_REGISTRATION(TemplateMatrixTest); @@ -334,6 +422,11 @@ class VariableMatrixTest: public CppUnit::TestFixture { Matrix m(2,4, 1, 2, 3, 4, 5, 6, 7, 8); + Matrix m2(2, 4); + m2 = {2, 4, + 1, 2, 3, 4, + 5, 6, 7, 8}; + CPPUNIT_ASSERT_EQUAL(m, m2); CPPUNIT_ASSERT_EQUAL((T)1, m[0][0]); CPPUNIT_ASSERT_EQUAL((T)2, m[0][1]); CPPUNIT_ASSERT_EQUAL((T)3, m[0][2]); @@ -345,9 +438,9 @@ class VariableMatrixTest: public CppUnit::TestFixture { } template void initFromArray2() { - Matrix m(2, 4, - 1, 2, 3, 4, - 5, 6, 7, 8); + Matrix m(2, 4, + 1, 2, 3, 4, + 5, 6, 7, 8); CPPUNIT_ASSERT_EQUAL((T)1, m[0][0]); CPPUNIT_ASSERT_EQUAL((T)2, m[0][1]); CPPUNIT_ASSERT_EQUAL((T)3, m[0][2]); @@ -366,6 +459,9 @@ class VariableMatrixTest: public CppUnit::TestFixture { Matrix m2(m1); m1[0][2] = 16; m2[0][0] = 0; + Matrix m3(2, 4); + m3 = m2; + CPPUNIT_ASSERT_EQUAL(m2, m3); CPPUNIT_ASSERT_EQUAL((T)1, m1[0][0]); CPPUNIT_ASSERT_EQUAL((T)2, m1[0][1]); CPPUNIT_ASSERT_EQUAL((T)16, m1[0][2]); @@ -445,6 +541,7 @@ class VariableMatrixTest: public CppUnit::TestFixture { -1, -2, -3, -4, 4, 3, 2, 1); CPPUNIT_ASSERT_EQUAL(res, m); + CPPUNIT_ASSERT_EQUAL(res, -m2+m1); } template void scalar_mult() { @@ -461,6 +558,17 @@ class VariableMatrixTest: public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(two*m1*two, m1*four); CPPUNIT_ASSERT_EQUAL(big*m1*four, m1*four*big); } + template + void scalar_div() { + const Matrix m1(2, 4, + 2, 4, 6, 8, + 10, 12, 14, 16); + const Matrix m2(2, 4, + 1, 2, 3, 4, + 5, 6, 7, 8); + CPPUNIT_ASSERT_EQUAL(m2, m1/(T)2); + CPPUNIT_ASSERT_EQUAL(m2, (T)3*m1/(T)6); + } template void matrix_mult() { const Matrix m1(2, 3, @@ -487,6 +595,15 @@ class VariableMatrixTest: public CppUnit::TestFixture { 3, 6); CPPUNIT_ASSERT_EQUAL(res, m.t()); } + template + void apply() { + Matrix m(3, 3, + 2, -2, 4, + -2, 1, -6, + 1, 0, -2); + Matrix o(m); + CPPUNIT_ASSERT_EQUAL((T)3*o, m.apply([](T& t){t*=3;})); + } template void gauss() { Matrix m(3, 3, @@ -537,8 +654,11 @@ class VariableMatrixTest: public CppUnit::TestFixture { 0, 1, 2, -1, 2, 4, -1, 2, 5); + Matrix o1(m), o2(m); m.inv(); - CPPUNIT_ASSERT(m.similar(res, 0.0001)); + CPPUNIT_ASSERT_EQUAL((T)2*res, (T)2/o1); + CPPUNIT_ASSERT_EQUAL(o1.i(), o1/o2); + CPPUNIT_ASSERT_EQUAL(res, m); } { Matrix m(3, 3, 1, 2, 3, @@ -550,6 +670,54 @@ class VariableMatrixTest: public CppUnit::TestFixture { -5, 4, 1); m.inv(); CPPUNIT_ASSERT_EQUAL(res, m); + } { + Matrix m(3, 3, + 1, 2, 3, + 0, 4, 5, + 1, 0, 6); + const Matrix res(3, 3, + (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(3, 3, + -2, 0, 1, + 9, 2, -3, + 5, 1, -2); + const Matrix res(3, 3, + -1, 1, -2, + 3, -1, 3, + -1, 2, -4); + Matrix o(m); + m.inv(); + CPPUNIT_ASSERT_EQUAL(m.i(), m*o); + CPPUNIT_ASSERT_EQUAL(res, m); + } { + Matrix m(4, 4, + 2, 1, 4, 1, + -1, 1, 0, 2, + 0, 0, 2, 4, + 2, -2, 0, 1); + const Matrix res(4, 4, + (T)-1/3, (T)13/15, (T)-2/3, 0.6, + (T)1/3, (T)16/15, (T)-2/3, 0.2, + 0, -0.8, 0.5, -0.4, + 0, 0.4, 0, 0.2); + Matrix o(m); + m.inv(); + CPPUNIT_ASSERT_EQUAL(m.i(), m*o); + CPPUNIT_ASSERT_EQUAL(res, m); + } { + Matrix m(2, 2, + 4, 3, + 3, 2); + const Matrix res(2, 2, + -2, 3, + 3, -4); + m.inv(); + CPPUNIT_ASSERT_EQUAL(res, m); } } CPPUNIT_TEST_SUITE(VariableMatrixTest); @@ -602,11 +770,12 @@ class VariableMatrixTest: public CppUnit::TestFixture { CPPUNIT_TEST(scalar_mult); CPPUNIT_TEST(scalar_mult); CPPUNIT_TEST(scalar_mult); - CPPUNIT_TEST(scalar_mult); - CPPUNIT_TEST(scalar_mult); - CPPUNIT_TEST(scalar_mult); - CPPUNIT_TEST(scalar_mult); - CPPUNIT_TEST(scalar_mult); + CPPUNIT_TEST(scalar_div); + CPPUNIT_TEST(scalar_div); + CPPUNIT_TEST(scalar_div); + CPPUNIT_TEST(scalar_div); + CPPUNIT_TEST(scalar_div); + CPPUNIT_TEST(scalar_div); CPPUNIT_TEST(matrix_mult); CPPUNIT_TEST(matrix_mult); CPPUNIT_TEST(matrix_mult); @@ -619,6 +788,12 @@ class VariableMatrixTest: public CppUnit::TestFixture { CPPUNIT_TEST(transpose); CPPUNIT_TEST(transpose); CPPUNIT_TEST(transpose); + CPPUNIT_TEST(apply); + CPPUNIT_TEST(apply); + CPPUNIT_TEST(apply); + CPPUNIT_TEST(apply); + CPPUNIT_TEST(apply); + CPPUNIT_TEST(apply); CPPUNIT_TEST(gauss); CPPUNIT_TEST(gauss); CPPUNIT_TEST(gauss); @@ -635,6 +810,7 @@ class VariableMatrixTest: public CppUnit::TestFixture { CPPUNIT_TEST(i); CPPUNIT_TEST(inv); CPPUNIT_TEST(inv); + CPPUNIT_TEST(inv); CPPUNIT_TEST_SUITE_END(); }; CPPUNIT_TEST_SUITE_REGISTRATION(VariableMatrixTest);