/** * @file linalg.h * @author 9exa * @brief objects and algorithms to solve linear equations * @version 0.1 * @date 2023-05-04 * * @copyright Copyright (c) 2023 * */ #ifndef MENGA_LINALG #define MENGA_LINALG #include #include #include #include namespace Mengu { namespace dsp { //2-D matrix // dot_product // c-style dot product template inline T dot(const T *a, const T *b, const int size) { T total = T(); for (int i = 0; i < size; i++) { total += a[i] * b[i]; } return total; } // do product on iterator template inline float dot(InputIt1 afirst, InputIt1 alast, InputIt2 bfirst) { float total = 0.0f; while (afirst != alast) { total += *afirst * *bfirst; afirst++; bfirst++; } return total; } template std::vector scalar_mul(const T lambda, const std::vector &a) { std::vector scaled; for (T x: a) { scaled.push_back(lambda * x); } return scaled; } template std::array scalar_mul(const T lambda, const T *a, size_t size) { std::array scaled; for (size_t i = 0; i < size; i++) { scaled[i] = lambda * a[i]; } return scaled; } template void scalar_mul_inplace(const T lambda, T *a, const int size) { for (int i = 0; i < size; i++) { a[i] = lambda * a[i]; } } // add b to a inplace template void vec_add_inplace(const std::vector &b, std::vector &a) { for (int i = 0; i < a.size(); i++) { a[i] += b.at(i); } } template void vec_add_inplace(const T *b, T *a, const int size) { for (int i = 0; i < size; i++) { a[i] += b[i]; } } // Solves a system of equations where the matrix is a symmetric TOEplitz matrix, // The matrix is represented as a list of its column values std::vector solve_sym_toeplitz(const std::vector &cols, const std::vector &y); template std::array solve_sym_toeplitz(const std::array &cols, const std::array &y) { // good ol dynamic programming to repeatedly do each step of levinson_recursion consequtively std::array backward_vec; std::array forward_vec; backward_vec[backward_vec.size() - 1] = forward_vec[0] = 1.0 / cols.at(0); float error = 0.0f; std::array result; result[0] = {y.at(0) / cols.at(0)}; for (int n = 1; n < N; n++) { // calculate the current error and backward vec std::copy(backward_vec.crbegin(), backward_vec.crbegin() + n, forward_vec.begin()); error = dot(cols.data() + 1, backward_vec.data() + (N - n), n); float denom = 1.0f / (1 - error * error); scalar_mul_inplace(denom, backward_vec.data() + (N - n), n); backward_vec[N - 1 - n] = T(); scalar_mul_inplace(-error * denom, forward_vec.data(), n); forward_vec[n] = T(); vec_add_inplace(forward_vec.data(), backward_vec.data() + (N - n - 1), n + 1); // calculate this iterations result auto cols_iter = cols.crbegin() + (cols.size() - n - 1); // the elements n to 0 float result_error = dot(cols_iter, cols.crend() - 1, result.cbegin()); std::array scaled_backward_vec = scalar_mul( y[n] - result_error, backward_vec.data() + (N - n - 1), n + 1); result[n] = T(); vec_add_inplace(scaled_backward_vec.data(), result.data(), n + 1); } return result; } } } // #endif