algebra/include/nil/crypto3/algebra/matrix/math.hpp
Go to the documentation of this file.
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2020-2021 Mikhail Komarov <nemo@nil.foundation>
3 // Copyright (c) 2020-2021 Nikita Kaskov <nbering@nil.foundation>
4 // Copyright (c) 2020-2021 Ilias Khairullin <ilias@nil.foundation>
5 //
6 // MIT License
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to deal
10 // in the Software without restriction, including without limitation the rights
11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 // copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
14 //
15 // The above copyright notice and this permission notice shall be included in all
16 // copies or substantial portions of the Software.
17 //
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 // SOFTWARE.
25 //---------------------------------------------------------------------------//
26 
27 #ifndef CRYPTO3_ALGEBRA_MATRIX_MATH_HPP
28 #define CRYPTO3_ALGEBRA_MATRIX_MATH_HPP
29 
30 #include <algorithm>
31 
33 
36 
39 
41 
42 namespace nil {
43  namespace crypto3 {
44  namespace algebra {
56  template<typename T, std::size_t M, std::size_t N>
57  constexpr matrix<T, M, N> conj(const matrix<T, M, N> &m) {
58  return elementwise(algebra::conj<T>, m);
59  }
60 
68  template<typename T, std::size_t M, std::size_t N>
70  return elementwise([](auto i) { return std::real(i); }, m);
71  }
72 
80  template<typename T, std::size_t M, std::size_t N>
82  return elementwise([](auto i) { return std::imag(i); }, m);
83  }
84 
92  template<typename T, std::size_t M, std::size_t N>
94  return generate<N, M>([&m](auto i, auto j) { return m[j][i]; });
95  }
96 
104  template<typename T, std::size_t M, std::size_t N>
106  return transpose(conj(m));
107  }
108 
117  template<typename T, std::size_t M, std::size_t N, std::size_t P>
118  constexpr matrix<T, M, P> matmul(const matrix<T, M, N> &a, const matrix<T, N, P> &b) {
119  return generate<M, P>([&a, &b](auto i, auto j) { return algebra::sum(a.row(i) * b.column(j)); });
120  }
121 
128  template<typename T, std::size_t M, std::size_t N>
129  constexpr vector<T, N> vectmatmul(const vector<T, M> &v, const matrix<T, M, N> &m) {
130  return generate<N>([&v, &m](auto i) { return sum(v * m.column(i)); });
131  }
132 
139  template<typename T, std::size_t M, std::size_t N>
140  constexpr vector<T, M> matvectmul(const matrix<T, M, N> &m, const vector<T, N> &v) {
141  return generate<M>([&v, &m](auto i) { return sum(m.row(i) * v); });
142  }
143 
154  template<typename T, std::size_t M, std::size_t N, std::size_t P, std::size_t Q>
156  return generate<M * P, N * Q>([&a, &b](auto i, auto j) { return a[i / P][j / Q] * b[i % P][j % Q]; });
157  }
158 
167  template<typename T, std::size_t M, std::size_t N>
168  constexpr T macs(const matrix<T, M, N> &m) {
169  return max(generate<N>([&m](std::size_t i) { return sum(abs(m.column(i))); }));
170  }
171 
180  template<typename T, std::size_t M, std::size_t N>
181  constexpr T mars(const matrix<T, M, N> &m) {
182  return max(generate<M>([&m](std::size_t i) { return sum(abs(m.row(i))); }));
183  }
184 
186  template<typename T, std::size_t M, std::size_t N>
187  constexpr std::tuple<matrix<T, M, N>, std::size_t, T> gauss_jordan_impl(matrix<T, M, N> m, T tolerance) {
188  // CRYPTO3_DETAIL_ASSERT_FLOATING_POINT(T)
189  // CRYPTO3_DETAIL_ASSERT_REAL(T)
190 
191  // Define function for determining if an element is negligible
192  auto negligible = [&tolerance](const T &v) { return abs(v) < tolerance; };
193 
194  T det = 1;
195  std::size_t rank = 0;
196  std::size_t i = 0, j = 0;
197  while (i < M && j < N) {
198  // Choose largest magnitude as pivot to avoid adding different magnitudes
199  for (std::size_t ip = i + 1; ip < M; ++ip) {
200  if (abs(m[ip][j]) > abs(m[i][j])) {
201  for (std::size_t jp = 0; jp < N; ++jp) {
202  auto tmp = m[ip][jp];
203  m[ip][jp] = m[i][jp];
204  m[i][jp] = tmp;
205  }
206  det = -det;
207  break;
208  }
209  }
210 
211  // If m_ij is still 0, continue to the next column
212  if (!negligible(m[i][j])) {
213  // Scale m_ij to 1
214  auto s = m[i][j];
215  for (std::size_t jp = 0; jp < N; ++jp)
216  m[i][jp] /= s;
217  det /= s;
218 
219  // Eliminate other values in the column
220  for (std::size_t ip = 0; ip < M; ++ip) {
221  if (ip == i)
222  continue;
223  if (!negligible(m[ip][j])) {
224  auto s = m[ip][j];
225  [&]() { // wrap this in a lambda to get around a gcc bug
226  for (std::size_t jp = 0; jp < N; ++jp)
227  m[ip][jp] -= s * m[i][jp];
228  }();
229  }
230  }
231 
232  // Increment rank
233  ++rank;
234 
235  // Select next row
236  ++i;
237  }
238  ++j;
239  }
240  det = (rank == M) ? det : 0;
241  return {m, rank, det};
242  }
243 
245  template<typename T, std::size_t M, std::size_t N>
246  constexpr std::tuple<matrix<T, M, N>, std::size_t, T> gauss_jordan_impl(const matrix<T, M, N> &m) {
247  T tol = T(std::max(N, M)) * std::numeric_limits<T>::epsilon() * mars(m);
248  return gauss_jordan_impl(m, tol);
249  }
250 
261  template<typename T, std::size_t M, std::size_t N>
262  constexpr matrix<T, M, N> rref(const matrix<T, M, N> &m) {
263  return std::get<0>(gauss_jordan_impl(m));
264  }
265 
276  template<typename T, std::size_t M, std::size_t N>
277  constexpr matrix<T, M, N> rref(const matrix<T, M, N> &m, T tolerance) {
278  return std::get<0>(gauss_jordan_impl(m), tolerance);
279  }
280 
287  template<typename T, std::size_t M, std::size_t N>
288  constexpr std::size_t rank(const matrix<T, M, N> &m) {
289  return std::get<1>(gauss_jordan_impl(m));
290  }
291 
298  template<typename T, std::size_t M>
299  constexpr T det(const matrix<T, M, M> &m) {
300  return std::get<2>(gauss_jordan_impl(m));
301  }
302 
311  template<typename T, std::size_t M>
313  if (rank(m) < M)
314  throw "matrix is not invertible";
315  return submat<M, M>(rref(horzcat(m, get_identity<T, M>())), 0, M);
316  }
317 
325  template<typename T, std::size_t M>
326  constexpr T trace(const matrix<T, M, M> &m) {
327  return sum(generate<M>([&m](std::size_t i) { return m[i][i]; }));
328  }
329 
332  } // namespace algebra
333  } // namespace crypto3
334 } // namespace nil
335 
336 #endif // CRYPTO3_ALGEBRA_MATRIX_MATH_HPP
constexpr matrix< T, M, N > rref(const matrix< T, M, N > &m)
Compute the reduced row echelon form.
Definition: algebra/include/nil/crypto3/algebra/matrix/math.hpp:262
constexpr matrix< T, M, M > inverse(const matrix< T, M, M > &m)
computes the matrix inverse
Definition: algebra/include/nil/crypto3/algebra/matrix/math.hpp:312
constexpr T det(const matrix< T, M, M > &m)
Compute the determinant.
Definition: algebra/include/nil/crypto3/algebra/matrix/math.hpp:299
constexpr T trace(const matrix< T, M, M > &m)
computes the trace
Definition: algebra/include/nil/crypto3/algebra/matrix/math.hpp:326
constexpr matrix< T, M, P > matmul(const matrix< T, M, N > &a, const matrix< T, N, P > &b)
computes the matrix product
Definition: algebra/include/nil/crypto3/algebra/matrix/math.hpp:118
constexpr matrix< T, N, M > hermitian(const matrix< T, M, N > &m)
computes the Hermitian transpose
Definition: algebra/include/nil/crypto3/algebra/matrix/math.hpp:105
constexpr matrix< T, M, N+P > horzcat(const matrix< T, M, N > &a, const matrix< T, M, P > &b)
horizontally concatenates two matrices
Definition: matrix/utility.hpp:186
constexpr std::size_t rank(const matrix< T, M, N > &m)
Compute the rank.
Definition: algebra/include/nil/crypto3/algebra/matrix/math.hpp:288
constexpr matrix< T, M *P, N *Q > kron(const matrix< T, M, N > &a, const matrix< T, P, Q > &b)
Computes the kronecker tensor product.
Definition: algebra/include/nil/crypto3/algebra/matrix/math.hpp:155
constexpr matrix< U, N, M > elementwise(F f, const matrix< T, N, M > &m, const Matrices &...matrices)
applies a function elementwise between many matrices
Definition: matrix/utility.hpp:55
constexpr matrix< T, N, M > transpose(const matrix< T, M, N > &m)
computes the transpose
Definition: algebra/include/nil/crypto3/algebra/matrix/math.hpp:93
constexpr matrix< nil::crypto3::detail::remove_complex_t< T >, M, N > imag(const matrix< T, M, N > &m)
computes the elementwise imag
Definition: algebra/include/nil/crypto3/algebra/matrix/math.hpp:81
constexpr matrix< T, M, N > conj(const matrix< T, M, N > &m)
computes the elementwise complex conjugate
Definition: algebra/include/nil/crypto3/algebra/matrix/math.hpp:57
constexpr T macs(const matrix< T, M, N > &m)
Computes the maximum absolute column sum norm.
Definition: algebra/include/nil/crypto3/algebra/matrix/math.hpp:168
constexpr vector< T, M > matvectmul(const matrix< T, M, N > &m, const vector< T, N > &v)
computes the product of matrix and vector
Definition: algebra/include/nil/crypto3/algebra/matrix/math.hpp:140
constexpr T mars(const matrix< T, M, N > &m)
Computes the maximum absolute row sum norm.
Definition: algebra/include/nil/crypto3/algebra/matrix/math.hpp:181
constexpr matrix< nil::crypto3::detail::remove_complex_t< T >, M, N > real(const matrix< T, M, N > &m)
computes the elementwise real
Definition: algebra/include/nil/crypto3/algebra/matrix/math.hpp:69
constexpr vector< T, N > vectmatmul(const vector< T, M > &v, const matrix< T, M, N > &m)
computes the product of vector and matrix
Definition: algebra/include/nil/crypto3/algebra/matrix/math.hpp:129
constexpr nil::crypto3::detail::remove_complex_t< T > abs(T x)
computes the absolute value
Definition: algebra/include/nil/crypto3/algebra/scalar/math.hpp:76
constexpr T sum(const vector< T, N > &v)
computes the sum of elements
Definition: algebra/include/nil/crypto3/algebra/vector/math.hpp:124
constexpr T max(const vector< T, N > &v)
computes the maximum valued element
Definition: algebra/include/nil/crypto3/algebra/vector/math.hpp:146
Definition: pair.hpp:31
A container representing a matrix.
Definition: matrix.hpp:52
constexpr vector< T, N > column(std::size_t i) const
access specified column
Definition: matrix.hpp:82
constexpr vector< T, M > row(std::size_t i) const
access specified row
Definition: matrix.hpp:70
A container representing a vector.
Definition: vector.hpp:50