| @@ -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; | |||
| }; | |||