/* ============================================================================== This file is part of the JUCE 6 technical preview. Copyright (c) 2020 - Raw Material Software Limited You may use this code under the terms of the GPL v3 (see www.gnu.org/licenses). For this technical preview, this file is not subject to commercial licensing. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE DISCLAIMED. ============================================================================== */ namespace juce { namespace dsp { template Matrix Matrix::identity (size_t size) { Matrix result (size, size); for (size_t i = 0; i < size; ++i) result(i, i) = 1; return result; } template Matrix Matrix::toeplitz (const Matrix& vector, size_t size) { jassert (vector.isOneColumnVector()); jassert (size <= vector.rows); Matrix result (size, size); for (size_t i = 0; i < size; ++i) result (i, i) = vector (0, 0); for (size_t i = 1; i < size; ++i) for (size_t j = i; j < size; ++j) result (j, j - i) = result (j - i, j) = vector (i, 0); return result; } template Matrix Matrix::hankel (const Matrix& vector, size_t size, size_t offset) { jassert(vector.isOneColumnVector()); jassert(vector.rows >= (2 * (size - 1) + 1)); Matrix result (size, size); for (size_t i = 0; i < size; ++i) result (i, i) = vector ((2 * i) + offset, 0); for (size_t i = 1; i < size; ++i) for (size_t j = i; j < size; ++j) result (j, j - i) = result (j - i, j) = vector (i + 2 * (j - i) + offset, 0); return result; } //============================================================================== template Matrix& Matrix::swapColumns (size_t columnOne, size_t columnTwo) noexcept { jassert (columnOne < columns && columnTwo < columns); auto* p = data.getRawDataPointer(); for (size_t i = 0; i < rows; ++i) { auto offset = dataAcceleration.getUnchecked (static_cast (i)); std::swap (p[offset + columnOne], p[offset + columnTwo]); } return *this; } template Matrix& Matrix::swapRows (size_t rowOne, size_t rowTwo) noexcept { jassert (rowOne < rows && rowTwo < rows); auto offset1 = rowOne * columns; auto offset2 = rowTwo * columns; auto* p = data.getRawDataPointer(); for (size_t i = 0; i < columns; ++i) std::swap (p[offset1 + i], p[offset2 + i]); return *this; } //============================================================================== template Matrix Matrix::operator* (const Matrix& other) const { auto n = getNumRows(), m = other.getNumColumns(), p = getNumColumns(); Matrix result (n, m); jassert (p == other.getNumRows()); size_t offsetMat = 0, offsetlhs = 0; auto* dst = result.getRawDataPointer(); auto* a = getRawDataPointer(); auto* b = other.getRawDataPointer(); for (size_t i = 0; i < n; ++i) { size_t offsetrhs = 0; for (size_t k = 0; k < p; ++k) { auto ak = a[offsetlhs++]; for (size_t j = 0; j < m; ++j) dst[offsetMat + j] += ak * b[offsetrhs + j]; offsetrhs += m; } offsetMat += m; } return result; } //============================================================================== template bool Matrix::compare (const Matrix& a, const Matrix& b, ElementType tolerance) noexcept { if (a.rows != b.rows || a.columns != b.columns) return false; tolerance = std::abs (tolerance); auto* bPtr = b.begin(); for (auto aValue : a) if (std::abs (aValue - *bPtr++) > tolerance) return false; return true; } //============================================================================== template bool Matrix::solve (Matrix& b) const noexcept { auto n = columns; jassert (n == n && n == b.rows && b.isOneColumnVector()); auto* x = b.getRawDataPointer(); const auto& A = *this; switch (n) { case 1: { auto denominator = A (0,0); if (denominator == 0) return false; b (0, 0) /= denominator; } break; case 2: { auto denominator = A (0, 0) * A (1, 1) - A (0, 1) * A (1, 0); if (denominator == 0) return false; auto factor = (1 / denominator); auto b0 = x[0], b1 = x[1]; x[0] = factor * (A (1, 1) * b0 - A (0, 1) * b1); x[1] = factor * (A (0, 0) * b1 - A (1, 0) * b0); } break; case 3: { auto denominator = A (0, 0) * (A (1, 1) * A (2, 2) - A (1, 2) * A (2, 1)) + A (0, 1) * (A (1, 2) * A (2, 0) - A (1, 0) * A (2, 2)) + A (0, 2) * (A (1, 0) * A (2, 1) - A (1, 1) * A (2, 0)); if (denominator == 0) return false; auto factor = 1 / denominator; auto b0 = x[0], b1 = x[1], b2 = x[2]; x[0] = ( ( A (0, 1) * A (1, 2) - A (0, 2) * A (1, 1)) * b2 + (-A (0, 1) * A (2, 2) + A (0, 2) * A (2, 1)) * b1 + ( A (1, 1) * A (2, 2) - A (1, 2) * A (2, 1)) * b0) * factor; x[1] = -( ( A (0, 0) * A (1, 2) - A (0, 2) * A (1, 0)) * b2 + (-A (0, 0) * A (2, 2) + A (0, 2) * A (2, 0)) * b1 + ( A (1, 0) * A (2, 2) - A (1, 2) * A (2, 0)) * b0) * factor; x[2] = ( ( A (0, 0) * A (1, 1) - A (0, 1) * A (1, 0)) * b2 + (-A (0, 0) * A (2, 1) + A (0, 1) * A (2, 0)) * b1 + ( A (1, 0) * A (2, 1) - A (1, 1) * A (2, 0)) * b0) * factor; } break; default: { Matrix M (A); for (size_t j = 0; j < n; ++j) { if (M (j, j) == 0) { auto i = j; while (i < n && M (i, j) == 0) ++i; if (i == n) return false; for (size_t k = 0; k < n; ++k) M (j, k) += M (i, k); x[j] += x[i]; } auto t = 1 / M (j, j); for (size_t k = 0; k < n; ++k) M (j, k) *= t; x[j] *= t; for (size_t k = j + 1; k < n; ++k) { auto u = -M (k, j); for (size_t l = 0; l < n; ++l) M (k, l) += u * M (j, l); x[k] += u * x[j]; } } for (int k = static_cast (n) - 2; k >= 0; --k) for (size_t i = static_cast (k) + 1; i < n; ++i) x[k] -= M (static_cast (k), i) * x[i]; } } return true; } //============================================================================== template String Matrix::toString() const { StringArray entries; int sizeMax = 0; auto* p = data.begin(); for (size_t i = 0; i < rows; ++i) { for (size_t j = 0; j < columns; ++j) { String entry (*p++, 4); sizeMax = jmax (sizeMax, entry.length()); entries.add (entry); } } sizeMax = ((sizeMax + 1) / 4 + 1) * 4; MemoryOutputStream result; auto n = static_cast (entries.size()); for (size_t i = 0; i < n; ++i) { result << entries[(int) i].paddedRight (' ', sizeMax); if (i % columns == (columns - 1)) result << newLine; } return result.toString(); } template class Matrix; template class Matrix; } // namespace dsp } // namespace juce