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.

256 lines
11KB

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