| @@ -0,0 +1,111 @@ | |||||
| // | |||||
| // LolRemez - Remez algorithm implementation | |||||
| // | |||||
| // Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net> | |||||
| // This program is free software; you can redistribute it and/or | |||||
| // modify it under the terms of the Do What The Fuck You Want To | |||||
| // Public License, Version 2, as published by Sam Hocevar. See | |||||
| // http://www.wtfpl.net/ for more details. | |||||
| // | |||||
| #pragma once | |||||
| using namespace lol; | |||||
| /* | |||||
| * Arbitrarily-sized square matrices; for now this only supports | |||||
| * naive inversion and is used for the Remez inversion method. | |||||
| */ | |||||
| template<typename T> struct Matrix | |||||
| { | |||||
| inline Matrix<T>(int cols, int rows) | |||||
| : m_cols(cols), | |||||
| m_rows(rows) | |||||
| { | |||||
| ASSERT(cols > 0); | |||||
| ASSERT(rows > 0); | |||||
| m_data.Resize(m_cols * m_rows); | |||||
| } | |||||
| inline Matrix<T>(Matrix<T> const &other) | |||||
| { | |||||
| m_cols = other.m_cols; | |||||
| m_rows = other.m_rows; | |||||
| m_data = other.m_data; | |||||
| } | |||||
| void Init(T const &x) | |||||
| { | |||||
| for (int j = 0; j < m_rows; j++) | |||||
| for (int i = 0; i < m_cols; i++) | |||||
| m(i, j) = (i == j) ? x : (T)0; | |||||
| } | |||||
| /* Naive matrix inversion */ | |||||
| Matrix<T> inv() const | |||||
| { | |||||
| ASSERT(m_cols == m_rows); | |||||
| Matrix a(*this), b(m_cols, m_rows); | |||||
| b.Init((T)1); | |||||
| /* Inversion method: iterate through all columns and make sure | |||||
| * all the terms are 1 on the diagonal and 0 everywhere else */ | |||||
| for (int i = 0; i < m_cols; i++) | |||||
| { | |||||
| /* If the expected coefficient is zero, add one of | |||||
| * the other lines. The first we meet will do. */ | |||||
| if (!a.m(i, i)) | |||||
| { | |||||
| for (int j = i + 1; j < m_cols; j++) | |||||
| { | |||||
| if (!a.m(i, j)) | |||||
| continue; | |||||
| /* Add row j to row i */ | |||||
| for (int n = 0; n < m_cols; n++) | |||||
| { | |||||
| a.m(n, i) += a.m(n, j); | |||||
| b.m(n, i) += b.m(n, j); | |||||
| } | |||||
| break; | |||||
| } | |||||
| } | |||||
| /* Now we know the diagonal term is non-zero. Get its inverse | |||||
| * 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++) | |||||
| { | |||||
| if (j == i) | |||||
| continue; | |||||
| T mul = x * a.m(i, j); | |||||
| for (int n = 0; n < m_cols; n++) | |||||
| { | |||||
| a.m(n, j) -= mul * a.m(n, i); | |||||
| b.m(n, j) -= mul * b.m(n, i); | |||||
| } | |||||
| } | |||||
| /* Finally, ensure the diagonal term is 1 */ | |||||
| for (int n = 0; n < m_cols; n++) | |||||
| { | |||||
| a.m(n, i) *= x; | |||||
| b.m(n, i) *= x; | |||||
| } | |||||
| } | |||||
| return b; | |||||
| } | |||||
| inline T & m(int i, int j) { return m_data[m_rows * j + i]; } | |||||
| inline T const & m(int i, int j) const { return m_data[m_rows * j + i]; } | |||||
| int m_cols, m_rows; | |||||
| private: | |||||
| Array<T> m_data; | |||||
| }; | |||||