Manicore
Library to implement schemes on n-dimensionnal manifolds.
exterior_algebra.hpp
Go to the documentation of this file.
1 // Core data structure for spaces and operators on manifolds.
2 //
3 /*
4  * Copyright (c) 2023 Marien Hanot <marien-lorenzo.hanot@umontpellier.fr>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef EXTERIOR_ALGEBRA_HPP
21 #define EXTERIOR_ALGEBRA_HPP
22 
23 #include "exterior_dimension.hpp"
24 
25 // Std utilities
26 #include <vector>
27 #include <array>
28 #include <unordered_map>
29 #include <algorithm>
30 #include <cstdlib>
31 #include <cassert>
32 
33 // Linear algebra utilities
34 #include <Eigen/Dense>
35 #include <unsupported/Eigen/KroneckerProduct> // Used to couple the action on polynomial and on the exterior algebra
36 
37 namespace Manicore {
52  // Exterior algebra
54  /* Contains the part of methods dealing with the exterior algebra basis
55  */
56 
59 
61  template<size_t l, size_t d>
63  {
64  public:
66  static void init() noexcept {
67  static_assert(0 <= l && l <= d,"Error: Tried to generate the exterior algebra basis outside the range [0,d]");
68  if (initialized == 1) return; // initialize only the first time
69  initialized = 1;
70  size_t acc = 0;
71  std::array<size_t, l> cbasis;
72  for (size_t i = 0; i < l; ++i) {
73  cbasis[i] = i; // fill to first element
74  }
75  _basis.try_emplace(acc,cbasis);
76  while (_find_next_tuple(cbasis)) {
77  ++acc;
78  _basis.try_emplace(acc,cbasis);
79  };
80  };
81 
83  static const std::array<size_t,l> & expand_basis(size_t i)
84  {
85  assert(initialized==1 && "ExteriorBasis was not initialized");
86  return _basis.at(i);
87  }
88 
90  static const size_t index_from_tuple(const std::array<size_t,l> & tuple ) {
91  auto found = std::find_if(_basis.begin(), _basis.end(), [&tuple](const auto& p)
92  {return p.second == tuple;});
93  if (found != _basis.end()) {
94  return found->first;
95  } else {
96  throw; // tuple not in range
97  }
98  }
99 
100  private:
101  // Unordered_map provide faster lookup time than map
102  static inline std::unordered_map<size_t, std::array<size_t, l>> _basis;
103  static inline int initialized = 0; // We need inline to be able to define it inside the class
104  // Helper, find the next element of the basis, return false if this is the last element
105  static bool _find_next_tuple(std::array<size_t, l> &basis) noexcept {
106  for (size_t i = 0; i < l; ++i) {
107  size_t nval = basis[l - i - 1] + 1;
108  if (nval < d - i) { // value valid, we must reset everything after
109  basis[l - i - 1] = nval;
110  for (size_t j = 1; j <= i ; ++j){
111  basis[l - i - 1 + j] = nval + j;
112  }
113  return true;
114  } else { // already using the last element available
115  continue;
116  }
117  }
118  return false;
119  };
120  };
121 
123  template<size_t l, size_t d>
124  class ComplBasis {
125  public:
126  static Eigen::Matrix<double,Dimension::ExtDim(d-l,d),Dimension::ExtDim(l,d)> const & compute() {
127  static Eigen::Matrix<double,Dimension::ExtDim(d-l,d),Dimension::ExtDim(l,d)> mat = _compute();
128  return mat;
129  }
130  private:
131  static int _get_basis_sign(std::array<size_t,l> const &ori_basis, std::array<size_t,d-l> const &star_basis) {
132  size_t ori_rem = l;
133  size_t star_rem = d-l;
134  int sign = 1;
135  // Parse both basis to try to reconstitute the volume form, return the sign of the transformation, or 0 if this fail
136  for (size_t c_t = 0; c_t < d; ++c_t) {
137  if (ori_rem > 0 && ori_basis[l-ori_rem] == c_t) {
138  ori_rem--;
139  if (star_rem > 0 && star_basis[d-l-star_rem] == c_t) {
140  return 0; // Element present in both basis
141  } else {
142  continue;
143  }
144  } else {
145  if (star_rem > 0 && star_basis[d-l-star_rem] == c_t) {
146  star_rem--;
147  sign *= (ori_rem%2 == 0)? 1 : -1;
148  continue;
149  } else {
150  return 0; // Element not present in any basis
151  }
152  }
153  }
154  return sign;
155  }
156  static Eigen::Matrix<double,Dimension::ExtDim(d-l,d),Dimension::ExtDim(l,d)> _compute() {
157  if constexpr (l == 0 || l == d) {
158  return Eigen::Matrix<double,1,1>{1.};
159  } else {
160  Eigen::Matrix<double,Dimension::ExtDim(d-l,d),Dimension::ExtDim(l,d)> rv;
161  for (size_t i_r = 0; i_r < Dimension::ExtDim(l,d); ++i_r) {
162  std::array<size_t,l> const & ori_basis = ExteriorBasis<l,d>::expand_basis(i_r);
163  for (size_t i_l = 0; i_l < Dimension::ExtDim(d-l,d); ++i_l) {
164  std::array<size_t,d-l> const & star_basis = ExteriorBasis<d-l,d>::expand_basis(i_l);
165  rv(i_l,i_r) = _get_basis_sign(ori_basis,star_basis);
166  }
167  }
168  return rv;
169  }
170  }
171  };
172 
174  // Pullback helpers
176 
178 
181  template<typename V, typename Derived>
182  double Compute_partial_det(const V& a1, const V& a2, const Eigen::MatrixBase<Derived>& A) {
183  constexpr size_t N = std::tuple_size<V>::value;
184  if constexpr (N==0) {
185  return 0.;
186  } else if constexpr (N == 1) {
187  return A(a1[0],a2[0]);
188  } else {
189  double sign = 1.;
190  double sum = 0.;
191  std::array<typename V::value_type,N-1> b1,b2;
192  std::copy(a1.cbegin()+1,a1.cend(),b1.begin());
193  std::copy(a2.cbegin()+1,a2.cend(),b2.begin());
194  for (size_t i = 0; i < N-1;++i){
195  sum += sign*A(a1[i],a2[0])*Compute_partial_det(b1,b2,A);
196  sign *= -1.;
197  b1[i] = a1[i];
198  }
199  sum += sign*A(a1[N-1],a2[0])*Compute_partial_det(b1,b2,A);
200  return sum;
201  }
202  }
203 
205 
208  template<size_t l, size_t d1, size_t d2>
210  template<typename Derived>
211  static Eigen::Matrix<double, Dimension::ExtDim(l,d1), Dimension::ExtDim(l,d2)> compute(Eigen::MatrixBase<Derived> const & A) {
212  Eigen::Matrix<double, Dimension::ExtDim(l,d1), Dimension::ExtDim(l,d2)> rv;
213  for (size_t i = 0; i < Dimension::ExtDim(l,d1); ++i) {
214  for (size_t j = 0; j < Dimension::ExtDim(l,d2); ++j) {
216  }
217  }
218  return rv;
219  }
220  };
221 
222  template<size_t d1, size_t d2>
223  struct Compute_pullback<0,d1,d2> {
224  template<typename Derived>
225  static Eigen::Matrix<double,1,1> compute(Eigen::MatrixBase<Derived> const & A) {
226  return Eigen::Matrix<double,1,1>{1.};
227  }
228  };
229 
230  template<size_t d1, size_t d2>
231  struct Compute_pullback<1,d1,d2> {
232  template<typename Derived>
233  static Eigen::Matrix<double,d1,d2> compute(Eigen::MatrixBase<Derived> const & A) {
234  return A.transpose();
235  }
236  };
237 
238  template<size_t d>
239  struct Compute_pullback<d,d,d> {
240  template<typename Derived>
241  static Eigen::Matrix<double,1,1> compute(Eigen::MatrixBase<Derived> const & A) {
242  return Eigen::Matrix<double,1,1>{A.determinant()};
243  }
244  };
245 
246  template<>
247  struct Compute_pullback<1,1,1> {
248  template<typename Derived>
249  static Eigen::Matrix<double,1,1> compute(Eigen::MatrixBase<Derived> const & A) {
250  return Eigen::Matrix<double,1,1>{A(0,0)};
251  }
252  };
253 
254  template<>
255  struct Compute_pullback<2,2,3> {
256  template<typename Derived>
257  static Eigen::Matrix<double,1,3> compute(Eigen::MatrixBase<Derived> const & A) {
258  return Eigen::Matrix<double,1,3>{{A(0,0)*A(1,1) - A(0,1)*A(1,0), A(0,0)*A(2,1) - A(0,1)*A(2,0), A(1,0)*A(2,1) - A(1,1)*A(2,0)}};
259  }
260  };
261  template<>
262  struct Compute_pullback<2,3,2> {
263  template<typename Derived>
264  static Eigen::Matrix<double,3,1> compute(Eigen::MatrixBase<Derived> const & A) {
265  return Eigen::Matrix<double,3,1>{A(0,0)*A(1,1) - A(0,1)*A(1,0), A(0,0)*A(1,2) - A(0,2)*A(1,0), A(0,1)*A(1,2) - A(0,2)*A(1,1)};
266  }
267  };
268  template<>
269  struct Compute_pullback<2,3,3> {
270  template<typename Derived>
271  static Eigen::Matrix<double,3,3> compute(Eigen::MatrixBase<Derived> const & A) {
272  return Eigen::Matrix<double,3,3>{
273  {A(0,0)*A(1,1) - A(0,1)*A(1,0), A(0,0)*A(2,1) - A(0,1)*A(2,0), A(1,0)*A(2,1) - A(1,1)*A(2,0)},
274  {A(0,0)*A(1,2) - A(0,2)*A(1,0), A(0,0)*A(2,2) - A(0,2)*A(2,0), A(1,0)*A(2,2) - A(1,2)*A(2,0)},
275  {A(0,1)*A(1,2) - A(0,2)*A(1,1), A(0,1)*A(2,2) - A(0,2)*A(2,1), A(1,1)*A(2,2) - A(1,2)*A(2,1)}
276  };
277  }
278  };
279 
281 
282  template<size_t l>
284  template<typename Derived>
285  static Eigen::Matrix<double, Dimension::ExtDim(l,Eigen::internal::traits< Derived >::RowsAtCompileTime),
286  Dimension::ExtDim(l,Eigen::internal::traits< Derived >::RowsAtCompileTime)>
287  compute(Eigen::MatrixBase<Derived> const & g) {
288  constexpr auto N = Eigen::internal::traits< Derived >::RowsAtCompileTime;
289  static_assert(N == Eigen::internal::traits< Derived >::ColsAtCompileTime);
290  static_assert(N > 0);
292  }
293  };
294 
295 
297  // Polynomial algebra
299  /* Contains the part of methods dealing with the polynomial basis
300  */
301 
303  template<size_t d>
306  static std::vector<std::array<size_t, d>> const & homogeneous(const int r) {
307  assert(r <= _init_deg && "Error: Monomial_powers must be initialized first");
308  return _powers[r];
309  }
310 
312  static std::vector<std::array<size_t,d>> const & complete(const int r) {
313  assert(r <= _init_deg && "Error: Monomial_powers must be initialized first");
314  return _powers_full[r];
315  }
316 
318  static void init(const int r) {
319  static_assert(d > 0,"Error: Tried to construct a monomial basis in dimension 0");
320  assert(r <= _max_deg && "Maximum degree reached, increase _max_deg if needed");
321  if (r >_init_deg) {
322  for (int h_r = _init_deg + 1; h_r <= r; ++h_r) { // init homogeneous
323  std::vector<std::array<size_t,d>> powers;
324  std::array<size_t,d> current;
325  inner_loop(0,h_r,current,powers);
326  _powers[h_r] = powers;
327  if (h_r == 0) {
328  _powers_full[0] = powers;
329  } else {
330  _powers_full[h_r] = _powers_full[h_r-1];
331  for (size_t j = 0; j < powers.size(); ++j) {
332  _powers_full[h_r].emplace_back(powers[j]);
333  }
334  }
335  }
336  _init_deg = r;
337  }
338  }
339 
340  private:
341  static constexpr int _max_deg = 20;
342  static inline int _init_deg = -1;
343  static inline std::array<std::vector<std::array<size_t,d>>,_max_deg+1> _powers;
344  static inline std::array<std::vector<std::array<size_t,d>>,_max_deg+1> _powers_full;
345 
346  static void inner_loop(size_t cindex, int max, std::array<size_t,d> & current, std::vector<std::array<size_t,d>> & powers) {
347  if (cindex == d-1) {
348  current[cindex] = max; // Last direction to enforce the degree
349  powers.emplace_back(current);
350  } else {
351  for(int i = 0; i <= max; ++i) {
352  current[cindex] = i;
353  inner_loop(cindex+1,max-i,current,powers);
354  }
355  }
356  }
357  };
359 
360 } // End namespace
361 
362 #endif
Return a mapping from the basis of l-forms in dimension d to the basis of (d-l)-forms.
Definition: exterior_algebra.hpp:124
static Eigen::Matrix< double, Dimension::ExtDim(d-l, d), Dimension::ExtDim(l, d)> const & compute()
Definition: exterior_algebra.hpp:126
Class to handle the exterior algebra basis.
Definition: exterior_algebra.hpp:63
static const size_t index_from_tuple(const std::array< size_t, l > &tuple)
Search the index corresponding to the given tuple. Throw if not found.
Definition: exterior_algebra.hpp:90
static const std::array< size_t, l > & expand_basis(size_t i)
Return the coefficient of the basis at the given index.
Definition: exterior_algebra.hpp:83
static void init() noexcept
Initialize the exterior algebra basis. Must be called at least once before use.
Definition: exterior_algebra.hpp:66
constexpr functions to compute the dimension of various polynomial spaces
constexpr size_t ExtDim(size_t l, size_t d)
Dimension of the exterior algebra .
Definition: exterior_dimension.hpp:37
double Compute_partial_det(const V &a1, const V &a2, const Eigen::MatrixBase< Derived > &A)
Generic determinant computation.
Definition: exterior_algebra.hpp:182
Definition: maxwell.hpp:21
Wrapper for the product on the exterior algebra.
Definition: exterior_algebra.hpp:283
static Eigen::Matrix< double, Dimension::ExtDim(l, Eigen::internal::traits< Derived >::RowsAtCompileTime), Dimension::ExtDim(l, Eigen::internal::traits< Derived >::RowsAtCompileTime)> compute(Eigen::MatrixBase< Derived > const &g)
Definition: exterior_algebra.hpp:287
static Eigen::Matrix< double, 1, 1 > compute(Eigen::MatrixBase< Derived > const &A)
Definition: exterior_algebra.hpp:225
static Eigen::Matrix< double, 1, 1 > compute(Eigen::MatrixBase< Derived > const &A)
Definition: exterior_algebra.hpp:249
static Eigen::Matrix< double, d1, d2 > compute(Eigen::MatrixBase< Derived > const &A)
Definition: exterior_algebra.hpp:233
static Eigen::Matrix< double, 1, 3 > compute(Eigen::MatrixBase< Derived > const &A)
Definition: exterior_algebra.hpp:257
static Eigen::Matrix< double, 3, 1 > compute(Eigen::MatrixBase< Derived > const &A)
Definition: exterior_algebra.hpp:264
static Eigen::Matrix< double, 3, 3 > compute(Eigen::MatrixBase< Derived > const &A)
Definition: exterior_algebra.hpp:271
static Eigen::Matrix< double, 1, 1 > compute(Eigen::MatrixBase< Derived > const &A)
Definition: exterior_algebra.hpp:241
Generic pullback computation.
Definition: exterior_algebra.hpp:209
static Eigen::Matrix< double, Dimension::ExtDim(l, d1), Dimension::ExtDim(l, d2)> compute(Eigen::MatrixBase< Derived > const &A)
Definition: exterior_algebra.hpp:211
Generate a basis of monomial powers of degree r.
Definition: exterior_algebra.hpp:304
static std::vector< std::array< size_t, d > > const & homogeneous(const int r)
Basis of homogeneous polynomial of degree r.
Definition: exterior_algebra.hpp:306
static void init(const int r)
Initialise the basis for degree up to r. Must be called at least once before use.
Definition: exterior_algebra.hpp:318
static std::vector< std::array< size_t, d > > const & complete(const int r)
Basis of polynomial of at most degree r.
Definition: exterior_algebra.hpp:312