// // LolRemez - Remez algorithm implementation // // Copyright © 2005—2015 Sam Hocevar // // This program is free software. It comes without any warranty, to // the extent permitted by applicable law. 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 the WTFPL Task Force. // 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 linear_system : public array2d { inline linear_system(int cols) { ASSERT(cols > 0); this->resize(ivec2(cols)); } void init(T const &x) { int const n = this->size().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 */ linear_system inverse() const { int const n = this->size().x; linear_system a(*this), b(n); 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 < n; i++) { /* If the expected coefficient is zero, add one of * the other lines. The first we meet will do. */ if (!a[i][i]) { for (int j = i + 1; j < n; j++) { if (!a[i][j]) continue; /* Add row j to row i */ for (int k = 0; k < n; k++) { a[k][i] += a[k][j]; b[k][i] += b[k][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[i][i]; for (int j = 0; j < n; j++) { if (j == i) continue; T mul = x * a[i][j]; for (int k = 0; k < n; k++) { a[k][j] -= mul * a[k][i]; b[k][j] -= mul * b[k][i]; } } /* Finally, ensure the diagonal term is 1 */ for (int k = 0; k < n; k++) { a[k][i] *= x; b[k][i] *= x; } } return b; } };