The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

252 lines
11KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce::dsp
  19. {
  20. /**
  21. General matrix and vectors class, meant for classic math manipulation such as
  22. additions, multiplications, and linear systems of equations solving.
  23. @see LinearAlgebra
  24. @tags{DSP}
  25. */
  26. template <typename ElementType>
  27. class Matrix
  28. {
  29. public:
  30. //==============================================================================
  31. /** Creates a new matrix with a given number of rows and columns. */
  32. Matrix (size_t numRows, size_t numColumns)
  33. : rows (numRows), columns (numColumns)
  34. {
  35. resize();
  36. clear();
  37. }
  38. /** Creates a new matrix with a given number of rows and columns, with initial
  39. data coming from an array, stored in row-major order.
  40. */
  41. Matrix (size_t numRows, size_t numColumns, const ElementType* dataPointer)
  42. : rows (numRows), columns (numColumns)
  43. {
  44. resize();
  45. memcpy (data.getRawDataPointer(), dataPointer, rows * columns * sizeof (ElementType));
  46. }
  47. /** Creates a copy of another matrix. */
  48. Matrix (const Matrix&) = default;
  49. /** Moves a copy of another matrix. */
  50. Matrix (Matrix&&) noexcept = default;
  51. /** Creates a copy of another matrix. */
  52. Matrix& operator= (const Matrix&) = default;
  53. /** Moves another matrix into this one */
  54. Matrix& operator= (Matrix&&) noexcept = default;
  55. //==============================================================================
  56. /** Creates the identity matrix */
  57. static Matrix identity (size_t size);
  58. /** Creates a Toeplitz Matrix from a vector with a given squared size */
  59. static Matrix toeplitz (const Matrix& vector, size_t size);
  60. /** Creates a squared size x size Hankel Matrix from a vector with an optional offset.
  61. @param vector The vector from which the Hankel matrix should be generated.
  62. Its number of rows should be at least 2 * (size - 1) + 1
  63. @param size The size of resulting square matrix.
  64. @param offset An optional offset into the given vector.
  65. */
  66. static Matrix hankel (const Matrix& vector, size_t size, size_t offset = 0);
  67. //==============================================================================
  68. /** Returns the number of rows in the matrix. */
  69. size_t getNumRows() const noexcept { return rows; }
  70. /** Returns the number of columns in the matrix. */
  71. size_t getNumColumns() const noexcept { return columns; }
  72. /** Returns an Array of 2 integers with the number of rows and columns in the
  73. matrix.
  74. */
  75. Array<size_t> getSize() const noexcept { return { rows, columns }; }
  76. /** Fills the contents of the matrix with zeroes. */
  77. void clear() noexcept { zeromem (data.begin(), (size_t) data.size() * sizeof (ElementType)); }
  78. //==============================================================================
  79. /** Swaps the contents of two rows in the matrix and returns a reference to itself. */
  80. Matrix& swapRows (size_t rowOne, size_t rowTwo) noexcept;
  81. /** Swaps the contents of two columns in the matrix and returns a reference to itself. */
  82. Matrix& swapColumns (size_t columnOne, size_t columnTwo) noexcept;
  83. //==============================================================================
  84. /** Returns the value of the matrix at a given row and column (for reading). */
  85. inline ElementType operator() (size_t row, size_t column) const noexcept
  86. {
  87. jassert (row < rows && column < columns);
  88. return data.getReference (static_cast<int> (dataAcceleration.getReference (static_cast<int> (row))) + static_cast<int> (column));
  89. }
  90. /** Returns the value of the matrix at a given row and column (for modifying). */
  91. inline ElementType& operator() (size_t row, size_t column) noexcept
  92. {
  93. jassert (row < rows && column < columns);
  94. return data.getReference (static_cast<int> (dataAcceleration.getReference (static_cast<int> (row))) + static_cast<int> (column));
  95. }
  96. /** Returns a pointer to the raw data of the matrix object, ordered in row-major
  97. order (for modifying).
  98. */
  99. inline ElementType* getRawDataPointer() noexcept { return data.getRawDataPointer(); }
  100. /** Returns a pointer to the raw data of the matrix object, ordered in row-major
  101. order (for reading).
  102. */
  103. inline const ElementType* getRawDataPointer() const noexcept { return data.begin(); }
  104. //==============================================================================
  105. /** Addition of two matrices */
  106. inline Matrix& operator+= (const Matrix& other) noexcept { return apply (other, [] (ElementType a, ElementType b) { return a + b; } ); }
  107. /** Subtraction of two matrices */
  108. inline Matrix& operator-= (const Matrix& other) noexcept { return apply (other, [] (ElementType a, ElementType b) { return a - b; } ); }
  109. /** Scalar multiplication */
  110. inline Matrix& operator*= (ElementType scalar) noexcept
  111. {
  112. std::for_each (begin(), end(), [scalar] (ElementType& x) { x *= scalar; });
  113. return *this;
  114. }
  115. /** Addition of two matrices */
  116. inline Matrix operator+ (const Matrix& other) const { Matrix result (*this); result += other; return result; }
  117. /** Addition of two matrices */
  118. inline Matrix operator- (const Matrix& other) const { Matrix result (*this); result -= other; return result; }
  119. /** Scalar multiplication */
  120. inline Matrix operator* (ElementType scalar) const { Matrix result (*this); result *= scalar; return result; }
  121. /** Matrix multiplication */
  122. Matrix operator* (const Matrix& other) const;
  123. /** Does a hadarmard product with the receiver and other and stores the result in the receiver */
  124. inline Matrix& hadarmard (const Matrix& other) noexcept { return apply (other, [] (ElementType a, ElementType b) { return a * b; } ); }
  125. /** Does a hadarmard product with a and b returns the result. */
  126. static Matrix hadarmard (const Matrix& a, const Matrix& b) { Matrix result (a); result.hadarmard (b); return result; }
  127. //==============================================================================
  128. /** Compare to matrices with a given tolerance */
  129. static bool compare (const Matrix& a, const Matrix& b, ElementType tolerance = 0) noexcept;
  130. /* Comparison operator */
  131. inline bool operator== (const Matrix& other) const noexcept { return compare (*this, other); }
  132. //==============================================================================
  133. /** Tells if the matrix is a square matrix */
  134. bool isSquare() const noexcept { return rows == columns; }
  135. /** Tells if the matrix is a vector */
  136. bool isVector() const noexcept { return isOneColumnVector() || isOneRowVector(); }
  137. /** Tells if the matrix is a one column vector */
  138. bool isOneColumnVector() const noexcept { return columns == 1; }
  139. /** Tells if the matrix is a one row vector */
  140. bool isOneRowVector() const noexcept { return rows == 1; }
  141. /** Tells if the matrix is a null matrix */
  142. bool isNullMatrix() const noexcept { return rows == 0 || columns == 0; }
  143. //==============================================================================
  144. /** Solves a linear system of equations represented by this object and the argument b,
  145. using various algorithms depending on the size of the arguments.
  146. The matrix must be a square matrix N times N, and b must be a vector N times 1,
  147. with the coefficients of b. After the execution of the algorithm,
  148. the vector b will contain the solution.
  149. Returns true if the linear system of equations was successfully solved.
  150. */
  151. bool solve (Matrix& b) const noexcept;
  152. //==============================================================================
  153. /** Returns a String displaying in a convenient way the matrix contents. */
  154. String toString() const;
  155. //==============================================================================
  156. ElementType* begin() noexcept { return data.begin(); }
  157. ElementType* end() noexcept { return data.end(); }
  158. const ElementType* begin() const noexcept { return &data.getReference (0); }
  159. const ElementType* end() const noexcept { return begin() + data.size(); }
  160. private:
  161. //==============================================================================
  162. /** Resizes the matrix. */
  163. void resize()
  164. {
  165. data.resize (static_cast<int> (columns * rows));
  166. dataAcceleration.resize (static_cast<int> (rows));
  167. for (size_t i = 0; i < rows; ++i)
  168. dataAcceleration.setUnchecked (static_cast<int> (i), i * columns);
  169. }
  170. template <typename BinaryOperation>
  171. Matrix& apply (const Matrix& other, BinaryOperation binaryOp)
  172. {
  173. jassert (rows == other.rows && columns == other.columns);
  174. auto* dst = getRawDataPointer();
  175. for (auto src : other)
  176. {
  177. *dst = binaryOp (*dst, src);
  178. ++dst;
  179. }
  180. return *this;
  181. }
  182. //==============================================================================
  183. Array<ElementType> data;
  184. Array<size_t> dataAcceleration;
  185. size_t rows, columns;
  186. //==============================================================================
  187. JUCE_LEAK_DETECTOR (Matrix)
  188. };
  189. } // namespace juce::dsp