diff --git a/tools/lolremez/matrix.h b/tools/lolremez/matrix.h new file mode 100644 index 00000000..e60bc1c7 --- /dev/null +++ b/tools/lolremez/matrix.h @@ -0,0 +1,111 @@ +// +// LolRemez - Remez algorithm implementation +// +// Copyright: (c) 2010-2013 Sam Hocevar +// 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 struct Matrix +{ + inline Matrix(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(Matrix 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 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 m_data; +}; +