HArD::Core3D
Hybrid Arbitrary Degree::Core 3D - Library to implement 3D schemes with vertex, edge, face and cell polynomials as unknowns
Loading...
Searching...
No Matches
exterior.hpp
Go to the documentation of this file.
1// Core data structure for spaces and operators on manifolds.
2//
3// Author: Marien Hanot (marien-lorenzo.hanot@umontpellier.fr)
4//
5
6
7#ifndef EXTERIOR_HPP
8#define EXTERIOR_HPP
9
11
12// Std utilities
13#include <vector>
14#include <array>
15#include <unordered_map>
16#include <algorithm>
17#include <cstdlib>
18#include <cassert>
19
20// Linear algebra utilities
21#include <Eigen/Dense>
22#include <unsupported/Eigen/KroneckerProduct> // Used to couple the action on polynomial and on the exterior algebra
23
24namespace Manicore {
39 // Exterior algebra
41
45 template<size_t l, size_t d>
47 {
48 public:
49 static void init() noexcept {
50 static_assert(0 <= l && l <= d,"Error: Tried to generate the exterior algebra basis outside the range [0,d]");
51 if (initialized == 1) return; // initialize only the first time
52 initialized = 1;
53 size_t acc = 0;
54 std::array<size_t, l> cbasis;
55 for (size_t i = 0; i < l; ++i) {
56 cbasis[i] = i; // fill to first element
57 }
58 _basis.try_emplace(acc,cbasis);
59 while (_find_next_tuple(cbasis)) {
60 ++acc;
61 _basis.try_emplace(acc,cbasis);
62 };
63 };
64
65 static const std::array<size_t,l> & expand_basis(size_t i)
66 {
67 assert(initialized==1 && "ExteriorBasis was not initialized");
68 return _basis.at(i);
69 }
70
71 static const size_t index_from_tuple(const std::array<size_t,l> & tuple) {
72 auto found = std::find_if(_basis.begin(), _basis.end(), [&tuple](const auto& p)
73 {return p.second == tuple;});
74 if (found != _basis.end()) {
75 return found->first;
76 } else {
77 throw; // tuple not in range
78 }
79 }
80
81 private:
82 // Unordered_map provide faster lookup time than map
83 static inline std::unordered_map<size_t, std::array<size_t, l>> _basis;
84 static inline int initialized = 0; // We need inline to be able to define it inside the class
85 // Helper, find the next element of the basis, return false if this is the last element
86 static bool _find_next_tuple(std::array<size_t, l> &basis) noexcept {
87 for (size_t i = 0; i < l; ++i) {
88 size_t nval = basis[l - i - 1] + 1;
89 if (nval < d - i) { // value valid, we must reset everything after
90 basis[l - i - 1] = nval;
91 for (size_t j = 1; j <= i ; ++j){
92 basis[l - i - 1 + j] = nval + j;
93 }
94 return true;
95 } else { // already using the last element available
96 continue;
97 }
98 }
99 return false;
100 };
101 };
102
104
107 template<size_t l, size_t d>
109 public:
110 typedef Eigen::Matrix<double, Dimension::ExtDim(l-1,d), Dimension::ExtDim(l,d)> ExtAlgMatType;
111
112 static const ExtAlgMatType & get_transform(size_t i) {
113 return _transforms.at(i);
114 }
115
116 static void init() noexcept {
117 static_assert(0 < l && l <= d,"Error: Tried to generate Koszul basis outside the range [1,d]");
118 if (initialized == 1) return;
119 initialized = 1;
120 ExteriorBasis<l-1,d>::init(); // ensure that the exterior basis is initialized
121 ExteriorBasis<l,d>::init(); // ensure that the exterior basis is initialized
122 for (size_t i = 0; i < d; ++i) {
123 _transforms[i].setZero();
124 }
125 if (l == 1) { // special case, ext_basis = \emptyset
126 for (size_t i = 0; i < d; ++i) {
127 _transforms[i](0,i) = 1;
128 }
129 return;
130 }
131 for (size_t i = 0; i < Dimension::ExtDim(l-1,d); ++i) {
132 int sign = 1;
133 size_t try_pos = 0;
134 const std::array<size_t, l-1> & cbasis = ExteriorBasis<l-1,d>::expand_basis(i);
135 std::array<size_t,l> basis_cp;
136 std::copy(cbasis.cbegin(),cbasis.cend(),basis_cp.begin()+1);
137 // basis_cp contains a copy of cbasis with one more slot
138 for (size_t j = 0; j < d; ++j) {
139 if (try_pos == l-1 || j < cbasis[try_pos]) { // insert here
140 basis_cp[try_pos] = j;
141 _transforms[j](i,ExteriorBasis<l,d>::index_from_tuple(basis_cp)) = sign;
142 } else { // j == cbasis[try_pos]
143 basis_cp[try_pos] = basis_cp[try_pos+1];
144 ++try_pos;
145 sign = -sign;
146 continue;
147 }
148 }
149 }
150 }; // end init()
151
152 private:
153 static inline int initialized = 0;
154 static inline std::array<ExtAlgMatType,d> _transforms;
155 };
156
157 template<size_t l, size_t d>
159 public:
160 typedef Eigen::Matrix<double, Dimension::ExtDim(l+1,d), Dimension::ExtDim(l,d)> ExtAlgMatType;
161
162 static const ExtAlgMatType & get_transform(size_t i) {
163 return _transforms.at(i);
164 }
165
166 static void init() noexcept {
167 static_assert(l < d,"Error: Tried to generate diff basis outside the range [0,d-1]");
168 if (initialized == 1) return;
169 initialized = 1;
171 for (size_t i = 0; i < d; ++i) {
172 _transforms[i] = Koszul_exterior<l+1,d>::get_transform(i).transpose().eval();
173 }
174 };
175 private:
176 static inline int initialized = 0;
177 static inline std::array<ExtAlgMatType,d> _transforms;
178 };
179
181 // Pullback helpers
183
185
188 template<typename V, typename Derived>
189 double Compute_partial_det(const V& a1, const V& a2, const Eigen::MatrixBase<Derived>& A) {
190 constexpr size_t N = std::tuple_size<V>::value;
191 if constexpr (N==0) {
192 return 0.;
193 } else if constexpr (N == 1) {
194 return A(a1[0],a2[0]);
195 } else {
196 double sign = 1.;
197 double sum = 0.;
198 std::array<typename V::value_type,N-1> b1,b2;
199 std::copy(a1.cbegin()+1,a1.cend(),b1.begin());
200 std::copy(a2.cbegin()+1,a2.cend(),b2.begin());
201 for (size_t i = 0; i < N-1;++i){
202 sum += sign*A(a1[i],a2[0])*Compute_partial_det(b1,b2,A);
203 sign *= -1.;
204 b1[i] = a1[i];
205 }
206 sum += sign*A(a1[N-1],a2[0])*Compute_partial_det(b1,b2,A);
207 return sum;
208 }
209 }
210
214 template<size_t l, size_t d1, size_t d2>
216 template<typename Derived>
217 static Eigen::Matrix<double, Dimension::ExtDim(l,d1), Dimension::ExtDim(l,d2)> compute(Eigen::MatrixBase<Derived> const & A) {
218 Eigen::Matrix<double, Dimension::ExtDim(l,d1), Dimension::ExtDim(l,d2)> rv;
219 for (size_t i = 0; i < Dimension::ExtDim(l,d1); ++i) {
220 for (size_t j = 0; j < Dimension::ExtDim(l,d2); ++j) {
222 }
223 }
224 return rv;
225 }
226 };
227
228 template<size_t d1, size_t d2>
229 struct Compute_pullback<0,d1,d2> {
230 template<typename Derived>
231 static Eigen::Matrix<double,1,1> compute(Eigen::MatrixBase<Derived> const & A) {
232 return Eigen::Matrix<double,1,1>{1.};
233 }
234 };
235
236 template<size_t d1, size_t d2>
237 struct Compute_pullback<1,d1,d2> {
238 template<typename Derived>
239 static Eigen::Matrix<double,d1,d2> compute(Eigen::MatrixBase<Derived> const & A) {
240 return A.transpose();
241 }
242 };
243
244 template<size_t d>
245 struct Compute_pullback<d,d,d> {
246 template<typename Derived>
247 static Eigen::Matrix<double,1,1> compute(Eigen::MatrixBase<Derived> const & A) {
248 return Eigen::Matrix<double,1,1>{A.determinant()};
249 }
250 };
251
252 template<>
253 struct Compute_pullback<1,1,1> {
254 template<typename Derived>
255 static Eigen::Matrix<double,1,1> compute(Eigen::MatrixBase<Derived> const & A) {
256 return Eigen::Matrix<double,1,1>{A(0,0)};
257 }
258 };
259
260 template<>
261 struct Compute_pullback<2,2,3> {
262 template<typename Derived>
263 static Eigen::Matrix<double,1,3> compute(Eigen::MatrixBase<Derived> const & A) {
264 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)}};
265 }
266 };
267 template<>
268 struct Compute_pullback<2,3,2> {
269 template<typename Derived>
270 static Eigen::Matrix<double,3,1> compute(Eigen::MatrixBase<Derived> const & A) {
271 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)};
272 }
273 };
274 template<>
275 struct Compute_pullback<2,3,3> {
276 template<typename Derived>
277 static Eigen::Matrix<double,3,3> compute(Eigen::MatrixBase<Derived> const & A) {
278 return Eigen::Matrix<double,3,3>{
279 {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)},
280 {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)},
281 {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)}
282 };
283 }
284 };
285
287 // Polynomial algebra
289
292 template<size_t d>
294 static std::vector<std::array<size_t, d>> const & homogeneous(const int r) {
295 assert(r <= _init_deg && "Error: Monomial_powers must be initialized first");
296 return _powers[r];
297 }
298
299 static std::vector<std::array<size_t,d>> const & complete(const int r) {
300 assert(r <= _init_deg && "Error: Monomial_powers must be initialized first");
301 return _powers_full[r];
302 }
303
304 static void init(const int r) {
305 static_assert(d > 0,"Error: Tried to construct a monomial basis in dimension 0");
306 assert(r <= _max_deg && "Maximum degree reached, increase _max_deg if needed");
307 if (r >_init_deg) {
308 for (int h_r = _init_deg + 1; h_r <= r; ++h_r) { // init homogeneous
309 std::vector<std::array<size_t,d>> powers;
310 std::array<size_t,d> current;
311 inner_loop(0,h_r,current,powers);
312 _powers[h_r] = powers;
313 if (h_r == 0) {
314 _powers_full[0] = powers;
315 } else {
316 _powers_full[h_r] = _powers_full[h_r-1];
317 for (size_t j = 0; j < powers.size(); ++j) {
318 _powers_full[h_r].emplace_back(powers[j]);
319 }
320 }
321 }
322 _init_deg = r;
323 }
324 }
325
326 private:
327 static constexpr int _max_deg = 20;
328 static inline int _init_deg = -1;
329 static inline std::array<std::vector<std::array<size_t,d>>,_max_deg+1> _powers;
330 static inline std::array<std::vector<std::array<size_t,d>>,_max_deg+1> _powers_full;
331
332 static void inner_loop(size_t cindex, int max, std::array<size_t,d> & current, std::vector<std::array<size_t,d>> & powers) {
333 if (cindex == d-1) {
334 current[cindex] = max; // Last direction to enforce the degree
335 powers.emplace_back(current);
336 } else {
337 for(int i = 0; i <= max; ++i) {
338 current[cindex] = i;
339 inner_loop(cindex+1,max-i,current,powers);
340 }
341 }
342 }
343 };
344
346 template<size_t d, size_t index>
348 static Eigen::MatrixXd get (const int r) {
349 static_assert(index < d,"Error: Tried to take the koszul operator on a direction outside the dimension");
350 Eigen::MatrixXd M = Eigen::MatrixXd::Zero(Dimension::HDim(r+1,d), Dimension::HDim(r,d));
351 for (size_t i = 0; i < Dimension::HDim(r,d); ++i) {
352 std::array<size_t, d> current = Monomial_powers<d>::homogeneous(r)[i];
353 current.at(index) += 1;
354 size_t val = std::find(Monomial_powers<d>::homogeneous(r+1).cbegin(),
355 Monomial_powers<d>::homogeneous(r+1).cend(),current)
356 - Monomial_powers<d>::homogeneous(r+1).cbegin();
357 M(val,i) = 1.;
358 }
359 return M;
360 }
361 };
363 template<size_t d, size_t index>
365 static Eigen::MatrixXd get (const int r) {
366 static_assert(index < d,"Error: Tried to take the differential operator on a direction outside the dimension");
367 assert(r > 0 && "Error: Cannot generate a matrix for the differential on P_0");
368 Eigen::MatrixXd M = Eigen::MatrixXd::Zero(Dimension::HDim(r-1,d), Dimension::HDim(r,d));
369 for (size_t i = 0; i < Dimension::HDim(r,d); ++i) {
370 std::array<size_t, d> current = Monomial_powers<d>::homogeneous(r)[i];
371 size_t cval = current.at(index);
372 if (cval == 0) continue; // Zero on that col
373 current.at(index) -= 1;
374 size_t val = std::find(Monomial_powers<d>::homogeneous(r-1).cbegin(),
375 Monomial_powers<d>::homogeneous(r-1).cend(),current)
376 - Monomial_powers<d>::homogeneous(r-1).cbegin();
377 M(val,i) = cval;
378 }
379 return M;
380 }
381 };
382
384 // Coupling polynomial and exterior
386
389 template<size_t l, size_t d>
390 struct Koszul_full {
391 static Eigen::MatrixXd get (const int r) {
392 if constexpr (l==0 || l > d) {
393 return Eigen::MatrixXd(0,0);
394 }
395 Eigen::MatrixXd M(Dimension::PLDim(r+1,l-1,d),Dimension::PLDim(r,l,d));
396 M.setZero();
397 if (Dimension::PLDim(r+1,l-1,d) > 0 && Dimension::PLDim(r,l,d) > 0) {
398 Eigen::MatrixXd scalar_part(Dimension::PolyDim(r+1,d),Dimension::PolyDim(r,d));
399 init_loop_for<0>(r,scalar_part,M);
400 }
401 return M;
402 }
403
404 private:
405 template<size_t i, typename T> static void init_loop_for(int r, T & scalar_part,T & M) {
406 if constexpr(i < d) {
407 scalar_part.setZero();
408 int offset_l = Dimension::HDim(0,d);
409 int offset_c = 0;
410 for (int s = 0; s <= r; ++s) {
411 int inc_l = Dimension::HDim(s+1,d);
412 int inc_c = Dimension::HDim(s,d);
413 scalar_part.block(offset_l,offset_c,inc_l,inc_c) = Koszul_homogeneous_mat<d,i>::get(s);
414 offset_l += inc_l;
415 offset_c += inc_c;
416 }
417 M += Eigen::KroneckerProduct(Koszul_exterior<l,d>::get_transform(i),scalar_part);
418 init_loop_for<i+1>(r,scalar_part,M);
419 }
420 }
421 };
422
424 template<size_t l, size_t d>
425 struct Diff_full {
426 static Eigen::MatrixXd get (const int r) {
427 if (l >= d) {
428 return Eigen::MatrixXd(0,0);
429 }
430 Eigen::MatrixXd M(Dimension::PLDim(r-1,l+1,d),Dimension::PLDim(r,l,d));
431 M.setZero();
432 if (Dimension::PLDim(r-1,l+1,d) > 0 || Dimension::PLDim(r,l,d) > 0) {
433 Eigen::MatrixXd scalar_part(Dimension::PolyDim(r-1,d),Dimension::PolyDim(r,d));
434 init_loop_for<0>(r,scalar_part,M);
435 }
436 return M;
437 };
438
439 static Eigen::MatrixXd get_as_degr (const int r) {
440 auto inj = Eigen::KroneckerProduct(Eigen::Matrix<double,Dimension::ExtDim(l+1,d),Dimension::ExtDim(l+1,d)>::Identity(),
441 Eigen::MatrixXd::Identity(Dimension::PolyDim(r,d),Dimension::PolyDim(r-1,d)));
442 return inj*get(r);
443 };
444
445 private:
446 template<size_t i,typename T> static void init_loop_for(int r,T &scalar_part,T &M) {
447 if constexpr (i < d) {
448 scalar_part.setZero();
449 int offset_l = 0;
450 int offset_c = Dimension::HDim(0,d);
451 for (int s = 0; s < r; ++s) {
452 int inc_l = Dimension::HDim(s,d);
453 int inc_c = Dimension::HDim(s+1,d);
454 scalar_part.block(offset_l,offset_c,inc_l,inc_c) = Diff_homogeneous_mat<d,i>::get(s+1);
455 offset_l += inc_l;
456 offset_c += inc_c;
457 }
458 M += Eigen::KroneckerProduct(Diff_exterior<l,d>::get_transform(i),scalar_part);
459 init_loop_for<i+1>(r,scalar_part,M);
460 }
461 }
462 };
463
465 template<size_t d>
467 static void init(int r)
468 {
469 init_loop_for<0,1>(r+1);
470 }
471
472 private:
473 template<size_t l,size_t k> static void init_loop_for(int r) {
474 if constexpr(k <= d) {
475 if constexpr(l < k) {
477 init_loop_for<l+1,k>(r);
478 } else {
480 init_loop_for<0,k+1>(r);
481 }
482 }
483 }
484 };
485 // As a general rule, global classes will call init() but not the local classes (the classes which operates differently on each element)
486
487} // End namespace
488
489#endif
Definition exterior.hpp:158
Eigen::Matrix< double, Dimension::ExtDim(l+1, d), Dimension::ExtDim(l, d)> ExtAlgMatType
Definition exterior.hpp:160
static const ExtAlgMatType & get_transform(size_t i)
Definition exterior.hpp:162
static void init() noexcept
Definition exterior.hpp:166
Class to handle the exterior algebra basis.
Definition exterior.hpp:47
static const std::array< size_t, l > & expand_basis(size_t i)
Definition exterior.hpp:65
static const size_t index_from_tuple(const std::array< size_t, l > &tuple)
Definition exterior.hpp:71
static void init() noexcept
Definition exterior.hpp:49
Compute the action of Kozsul and Diff on the exterior algebra.
Definition exterior.hpp:108
static void init() noexcept
Definition exterior.hpp:116
Eigen::Matrix< double, Dimension::ExtDim(l-1, d), Dimension::ExtDim(l, d)> ExtAlgMatType
Definition exterior.hpp:110
static const ExtAlgMatType & get_transform(size_t i)
Definition exterior.hpp:112
constexpr size_t ExtDim(size_t l, size_t d) noexcept
Dimension of the exterior algebra.
Definition exterior_dimension.hpp:19
constexpr size_t PolyDim(int r, size_t d) noexcept
Dimension of P^r(\Real^d)
Definition exterior_dimension.hpp:25
constexpr size_t PLDim(int r, size_t l, size_t d) noexcept
Dimension of $P_r\Lambda^l(R^d)$.
Definition exterior_dimension.hpp:37
constexpr size_t HDim(int r, size_t d) noexcept
Dimension of homogeneous polynomials.
Definition exterior_dimension.hpp:31
Definition exterior.hpp:24
double Compute_partial_det(const V &a1, const V &a2, const Eigen::MatrixBase< Derived > &A)
Generic determinant computation.
Definition exterior.hpp:189
static Eigen::Matrix< double, 1, 1 > compute(Eigen::MatrixBase< Derived > const &A)
Definition exterior.hpp:231
static Eigen::Matrix< double, 1, 1 > compute(Eigen::MatrixBase< Derived > const &A)
Definition exterior.hpp:255
static Eigen::Matrix< double, d1, d2 > compute(Eigen::MatrixBase< Derived > const &A)
Definition exterior.hpp:239
static Eigen::Matrix< double, 1, 3 > compute(Eigen::MatrixBase< Derived > const &A)
Definition exterior.hpp:263
static Eigen::Matrix< double, 3, 1 > compute(Eigen::MatrixBase< Derived > const &A)
Definition exterior.hpp:270
static Eigen::Matrix< double, 3, 3 > compute(Eigen::MatrixBase< Derived > const &A)
Definition exterior.hpp:277
static Eigen::Matrix< double, 1, 1 > compute(Eigen::MatrixBase< Derived > const &A)
Definition exterior.hpp:247
Definition exterior.hpp:215
static Eigen::Matrix< double, Dimension::ExtDim(l, d1), Dimension::ExtDim(l, d2)> compute(Eigen::MatrixBase< Derived > const &A)
Definition exterior.hpp:217
Differential operator from $P_r\Lambda^l(R^d)$ to $P_{r-1}\Lambda^{l+1}(R^d)$.
Definition exterior.hpp:425
static Eigen::MatrixXd get_as_degr(const int r)
Definition exterior.hpp:439
static Eigen::MatrixXd get(const int r)
Definition exterior.hpp:426
Generate the matrices for the Differential operator on homogeneous monomial.
Definition exterior.hpp:364
static Eigen::MatrixXd get(const int r)
Definition exterior.hpp:365
Initialize every class related to the polynomial degree r.
Definition exterior.hpp:466
static void init(int r)
Definition exterior.hpp:467
Koszul operator from $P_r\Lambda^l(R^d)$ to $P_{r+1}\Lambda^{l-1}(R^d)$.
Definition exterior.hpp:390
static Eigen::MatrixXd get(const int r)
Definition exterior.hpp:391
Generate the matrices for the Koszul operator on homogeneous monomial.
Definition exterior.hpp:347
static Eigen::MatrixXd get(const int r)
Definition exterior.hpp:348
Generate a basis of monomial powers of degree r.
Definition exterior.hpp:293
static std::vector< std::array< size_t, d > > const & complete(const int r)
Definition exterior.hpp:299
static void init(const int r)
Definition exterior.hpp:304
static std::vector< std::array< size_t, d > > const & homogeneous(const int r)
Definition exterior.hpp:294