Matrix.h 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /*
  2. * Copyright (c) 2020, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/Types.h>
  8. #include <initializer_list>
  9. namespace Gfx {
  10. template<size_t N, typename T>
  11. class Matrix {
  12. template<size_t U, typename V>
  13. friend class Matrix;
  14. public:
  15. static constexpr size_t Size = N;
  16. constexpr Matrix() = default;
  17. constexpr Matrix(std::initializer_list<T> elements)
  18. {
  19. VERIFY(elements.size() == N * N);
  20. size_t i = 0;
  21. for (auto& element : elements) {
  22. m_elements[i / N][i % N] = element;
  23. ++i;
  24. }
  25. }
  26. template<typename... Args>
  27. constexpr Matrix(Args... args)
  28. : Matrix({ (T)args... })
  29. {
  30. }
  31. Matrix(Matrix const& other)
  32. {
  33. __builtin_memcpy(m_elements, other.elements(), sizeof(T) * N * N);
  34. }
  35. Matrix& operator=(Matrix const& other)
  36. {
  37. __builtin_memcpy(m_elements, other.elements(), sizeof(T) * N * N);
  38. return *this;
  39. }
  40. constexpr auto elements() const { return m_elements; }
  41. constexpr auto elements() { return m_elements; }
  42. constexpr Matrix operator*(Matrix const& other) const
  43. {
  44. Matrix product;
  45. for (size_t i = 0; i < N; ++i) {
  46. for (size_t j = 0; j < N; ++j) {
  47. auto& element = product.m_elements[i][j];
  48. if constexpr (N == 4) {
  49. element = m_elements[i][0] * other.m_elements[0][j]
  50. + m_elements[i][1] * other.m_elements[1][j]
  51. + m_elements[i][2] * other.m_elements[2][j]
  52. + m_elements[i][3] * other.m_elements[3][j];
  53. } else if constexpr (N == 3) {
  54. element = m_elements[i][0] * other.m_elements[0][j]
  55. + m_elements[i][1] * other.m_elements[1][j]
  56. + m_elements[i][2] * other.m_elements[2][j];
  57. } else if constexpr (N == 2) {
  58. element = m_elements[i][0] * other.m_elements[0][j]
  59. + m_elements[i][1] * other.m_elements[1][j];
  60. } else if constexpr (N == 1) {
  61. element = m_elements[i][0] * other.m_elements[0][j];
  62. } else {
  63. T value {};
  64. for (size_t k = 0; k < N; ++k)
  65. value += m_elements[i][k] * other.m_elements[k][j];
  66. element = value;
  67. }
  68. }
  69. }
  70. return product;
  71. }
  72. constexpr Matrix operator/(T divisor) const
  73. {
  74. Matrix division;
  75. for (size_t i = 0; i < N; ++i) {
  76. for (size_t j = 0; j < N; ++j)
  77. division.m_elements[i][j] = m_elements[i][j] / divisor;
  78. }
  79. return division;
  80. }
  81. [[nodiscard]] constexpr Matrix adjugate() const
  82. {
  83. if constexpr (N == 1)
  84. return Matrix(1);
  85. Matrix adjugate;
  86. for (size_t i = 0; i < N; ++i) {
  87. for (size_t j = 0; j < N; ++j) {
  88. int sign = (i + j) % 2 == 0 ? 1 : -1;
  89. adjugate.m_elements[j][i] = sign * first_minor(i, j);
  90. }
  91. }
  92. return adjugate;
  93. }
  94. [[nodiscard]] constexpr T determinant() const
  95. {
  96. if constexpr (N == 1) {
  97. return m_elements[0][0];
  98. } else {
  99. T result = {};
  100. int sign = 1;
  101. for (size_t j = 0; j < N; ++j) {
  102. result += sign * m_elements[0][j] * first_minor(0, j);
  103. sign *= -1;
  104. }
  105. return result;
  106. }
  107. }
  108. [[nodiscard]] constexpr T first_minor(size_t skip_row, size_t skip_column) const
  109. {
  110. static_assert(N > 1);
  111. VERIFY(skip_row < N);
  112. VERIFY(skip_column < N);
  113. Matrix<N - 1, T> first_minor;
  114. constexpr auto new_size = N - 1;
  115. size_t k = 0;
  116. for (size_t i = 0; i < N; ++i) {
  117. for (size_t j = 0; j < N; ++j) {
  118. if (i == skip_row || j == skip_column)
  119. continue;
  120. first_minor.elements()[k / new_size][k % new_size] = m_elements[i][j];
  121. ++k;
  122. }
  123. }
  124. return first_minor.determinant();
  125. }
  126. [[nodiscard]] constexpr static Matrix identity()
  127. {
  128. Matrix result;
  129. for (size_t i = 0; i < N; ++i) {
  130. for (size_t j = 0; j < N; ++j) {
  131. if (i == j)
  132. result.m_elements[i][j] = 1;
  133. else
  134. result.m_elements[i][j] = 0;
  135. }
  136. }
  137. return result;
  138. }
  139. [[nodiscard]] constexpr Matrix inverse() const
  140. {
  141. return adjugate() / determinant();
  142. }
  143. [[nodiscard]] constexpr Matrix transpose() const
  144. {
  145. Matrix result;
  146. for (size_t i = 0; i < N; ++i) {
  147. for (size_t j = 0; j < N; ++j)
  148. result.m_elements[i][j] = m_elements[j][i];
  149. }
  150. return result;
  151. }
  152. template<size_t U>
  153. [[nodiscard]] constexpr Matrix<U, T> submatrix_from_topleft() const requires(U > 0 && U < N)
  154. {
  155. Matrix<U, T> result;
  156. for (size_t i = 0; i < U; ++i) {
  157. for (size_t j = 0; j < U; ++j)
  158. result.m_elements[i][j] = m_elements[i][j];
  159. }
  160. return result;
  161. }
  162. private:
  163. T m_elements[N][N];
  164. };
  165. }
  166. using Gfx::Matrix;