| @@ -17,53 +17,50 @@ using namespace lol; | |||||
| * naive inversion and is used for the Remez inversion method. | * naive inversion and is used for the Remez inversion method. | ||||
| */ | */ | ||||
| template<typename T> struct LinearSystem | |||||
| template<typename T> | |||||
| struct LinearSystem : public array2d<T> | |||||
| { | { | ||||
| inline LinearSystem<T>(int cols) | inline LinearSystem<T>(int cols) | ||||
| : m_cols(cols) | |||||
| { | { | ||||
| ASSERT(cols > 0); | ASSERT(cols > 0); | ||||
| m_data.Resize(m_cols * m_cols); | |||||
| } | |||||
| inline LinearSystem<T>(LinearSystem<T> const &other) | |||||
| { | |||||
| m_cols = other.m_cols; | |||||
| m_data = other.m_data; | |||||
| this->SetSize(ivec2(cols)); | |||||
| } | } | ||||
| void Init(T const &x) | void Init(T const &x) | ||||
| { | { | ||||
| for (int j = 0; j < m_cols; j++) | |||||
| for (int i = 0; i < m_cols; i++) | |||||
| m(i, j) = (i == j) ? x : (T)0; | |||||
| int const n = this->GetSize().x; | |||||
| for (int j = 0; j < n; j++) | |||||
| for (int i = 0; i < n; i++) | |||||
| (*this)[i][j] = (i == j) ? x : (T)0; | |||||
| } | } | ||||
| /* Naive matrix inversion */ | /* Naive matrix inversion */ | ||||
| LinearSystem<T> inv() const | |||||
| LinearSystem<T> inverse() const | |||||
| { | { | ||||
| LinearSystem a(*this), b(m_cols); | |||||
| int const n = this->GetSize().x; | |||||
| LinearSystem a(*this), b(n); | |||||
| b.Init((T)1); | b.Init((T)1); | ||||
| /* Inversion method: iterate through all columns and make sure | /* Inversion method: iterate through all columns and make sure | ||||
| * all the terms are 1 on the diagonal and 0 everywhere else */ | * all the terms are 1 on the diagonal and 0 everywhere else */ | ||||
| for (int i = 0; i < m_cols; i++) | |||||
| for (int i = 0; i < n; i++) | |||||
| { | { | ||||
| /* If the expected coefficient is zero, add one of | /* If the expected coefficient is zero, add one of | ||||
| * the other lines. The first we meet will do. */ | * the other lines. The first we meet will do. */ | ||||
| if (!a.m(i, i)) | |||||
| if (!a[i][i]) | |||||
| { | { | ||||
| for (int j = i + 1; j < m_cols; j++) | |||||
| for (int j = i + 1; j < n; j++) | |||||
| { | { | ||||
| if (!a.m(i, j)) | |||||
| if (!a[i][j]) | |||||
| continue; | continue; | ||||
| /* Add row j to row i */ | /* Add row j to row i */ | ||||
| for (int n = 0; n < m_cols; n++) | |||||
| for (int k = 0; k < n; k++) | |||||
| { | { | ||||
| a.m(n, i) += a.m(n, j); | |||||
| b.m(n, i) += b.m(n, j); | |||||
| a[k][i] += a[k][j]; | |||||
| b[k][i] += b[k][j]; | |||||
| } | } | ||||
| break; | break; | ||||
| } | } | ||||
| @@ -71,36 +68,28 @@ template<typename T> struct LinearSystem | |||||
| /* Now we know the diagonal term is non-zero. Get its inverse | /* Now we know the diagonal term is non-zero. Get its inverse | ||||
| * and use that to nullify all other terms in the column */ | * and use that to nullify all other terms in the column */ | ||||
| T x = (T)1 / a.m(i, i); | |||||
| for (int j = 0; j < m_cols; j++) | |||||
| T x = (T)1 / a[i][i]; | |||||
| for (int j = 0; j < n; j++) | |||||
| { | { | ||||
| if (j == i) | if (j == i) | ||||
| continue; | continue; | ||||
| T mul = x * a.m(i, j); | |||||
| for (int n = 0; n < m_cols; n++) | |||||
| T mul = x * a[i][j]; | |||||
| for (int k = 0; k < n; k++) | |||||
| { | { | ||||
| a.m(n, j) -= mul * a.m(n, i); | |||||
| b.m(n, j) -= mul * b.m(n, i); | |||||
| a[k][j] -= mul * a[k][i]; | |||||
| b[k][j] -= mul * b[k][i]; | |||||
| } | } | ||||
| } | } | ||||
| /* Finally, ensure the diagonal term is 1 */ | /* Finally, ensure the diagonal term is 1 */ | ||||
| for (int n = 0; n < m_cols; n++) | |||||
| for (int k = 0; k < n; k++) | |||||
| { | { | ||||
| a.m(n, i) *= x; | |||||
| b.m(n, i) *= x; | |||||
| a[k][i] *= x; | |||||
| b[k][i] *= x; | |||||
| } | } | ||||
| } | } | ||||
| return b; | return b; | ||||
| } | } | ||||
| inline T & m(int i, int j) { return m_data[m_cols * j + i]; } | |||||
| inline T const & m(int i, int j) const { return m_data[m_cols * j + i]; } | |||||
| int m_cols; | |||||
| private: | |||||
| array<T> m_data; | |||||
| }; | }; | ||||
| @@ -93,11 +93,11 @@ void RemezSolver::Init() | |||||
| { | { | ||||
| auto p = polynomial<real>::chebyshev(n); | auto p = polynomial<real>::chebyshev(n); | ||||
| for (int i = 0; i < m_order + 1; i++) | for (int i = 0; i < m_order + 1; i++) | ||||
| system.m(i, n) = p.eval(m_zeroes[i]); | |||||
| system[i][n] = p.eval(m_zeroes[i]); | |||||
| } | } | ||||
| /* Solve the system */ | /* Solve the system */ | ||||
| system = system.inv(); | |||||
| system = system.inverse(); | |||||
| /* Compute new Chebyshev estimate */ | /* Compute new Chebyshev estimate */ | ||||
| m_estimate = polynomial<real>(); | m_estimate = polynomial<real>(); | ||||
| @@ -105,7 +105,7 @@ void RemezSolver::Init() | |||||
| { | { | ||||
| real weight = 0; | real weight = 0; | ||||
| for (int i = 0; i < m_order + 1; i++) | for (int i = 0; i < m_order + 1; i++) | ||||
| weight += system.m(n, i) * fxn[i]; | |||||
| weight += system[n][i] * fxn[i]; | |||||
| m_estimate += weight * polynomial<real>::chebyshev(n); | m_estimate += weight * polynomial<real>::chebyshev(n); | ||||
| } | } | ||||
| @@ -234,18 +234,18 @@ void RemezSolver::Step() | |||||
| { | { | ||||
| auto p = polynomial<real>::chebyshev(n); | auto p = polynomial<real>::chebyshev(n); | ||||
| for (int i = 0; i < m_order + 2; i++) | for (int i = 0; i < m_order + 2; i++) | ||||
| system.m(i, n) = p.eval(m_control[i]); | |||||
| system[i][n] = p.eval(m_control[i]); | |||||
| } | } | ||||
| /* The last line of the system is the oscillating error */ | /* The last line of the system is the oscillating error */ | ||||
| for (int i = 0; i < m_order + 2; i++) | for (int i = 0; i < m_order + 2; i++) | ||||
| { | { | ||||
| real error = fabs(EvalWeight(m_control[i])); | real error = fabs(EvalWeight(m_control[i])); | ||||
| system.m(i, m_order + 1) = (i & 1) ? error : -error; | |||||
| system[i][m_order + 1] = (i & 1) ? error : -error; | |||||
| } | } | ||||
| /* Solve the system */ | /* Solve the system */ | ||||
| system = system.inv(); | |||||
| system = system.inverse(); | |||||
| /* Compute new polynomial estimate */ | /* Compute new polynomial estimate */ | ||||
| m_estimate = polynomial<real>(); | m_estimate = polynomial<real>(); | ||||
| @@ -253,7 +253,7 @@ void RemezSolver::Step() | |||||
| { | { | ||||
| real weight = 0; | real weight = 0; | ||||
| for (int i = 0; i < m_order + 2; i++) | for (int i = 0; i < m_order + 2; i++) | ||||
| weight += system.m(n, i) * fxn[i]; | |||||
| weight += system[n][i] * fxn[i]; | |||||
| m_estimate += weight * polynomial<real>::chebyshev(n); | m_estimate += weight * polynomial<real>::chebyshev(n); | ||||
| } | } | ||||
| @@ -261,7 +261,7 @@ void RemezSolver::Step() | |||||
| /* Compute the error */ | /* Compute the error */ | ||||
| real error = 0; | real error = 0; | ||||
| for (int i = 0; i < m_order + 2; i++) | for (int i = 0; i < m_order + 2; i++) | ||||
| error += system.m(m_order + 1, i) * fxn[i]; | |||||
| error += system[m_order + 1][i] * fxn[i]; | |||||
| } | } | ||||
| void RemezSolver::PrintPoly() | void RemezSolver::PrintPoly() | ||||
| @@ -39,16 +39,17 @@ private: | |||||
| lol::real EvalWeight(lol::real const &x); | lol::real EvalWeight(lol::real const &x); | ||||
| private: | private: | ||||
| int m_order; | |||||
| /* User-defined parameters */ | |||||
| RealFunc *m_func, *m_weight; | |||||
| int m_order, m_decimals; | |||||
| /* Solver state */ | |||||
| lol::polynomial<lol::real> m_estimate; | lol::polynomial<lol::real> m_estimate; | ||||
| lol::array<lol::real> m_zeroes; | lol::array<lol::real> m_zeroes; | ||||
| lol::array<lol::real> m_control; | lol::array<lol::real> m_control; | ||||
| RealFunc *m_func, *m_weight; | |||||
| lol::real m_k1, m_k2, m_epsilon; | lol::real m_k1, m_k2, m_epsilon; | ||||
| int m_decimals; | |||||
| /* Statistics */ | /* Statistics */ | ||||
| float m_stats_cheby; | float m_stats_cheby; | ||||