1 #ifndef OMEGA_H_EIGEN_HPP
2 #define OMEGA_H_EIGEN_HPP
4 #include <Omega_h_matrix.hpp>
21 OMEGA_H_INLINE
Roots<3> find_polynomial_roots(
27 roots[0] = roots[1] = roots[2] = 0.0;
29 mults[0] = mults[1] = mults[2] = 0;
31 Real p = (3. * a_1 - square(a_2)) / 3.;
32 Real q = (9. * a_1 * a_2 - 27. * a_0 - 2. * cube(a_2)) / 27.;
35 Real D = cube(Q) + square(R);
36 Real shift = -a_2 / 3.;
38 Real S = std::cbrt(R + std::sqrt(D));
39 Real T = std::cbrt(R - std::sqrt(D));
42 Real z_23_real = shift - (1. / 2.) * B;
46 roots[1] = roots[2] = z_23_real;
49 auto cos_theta = R / std::sqrt(-cube(Q));
50 Real theta = std::acos(clamp(cos_theta, -1.0, 1.0));
51 Real radius = 2. * std::sqrt(-Q);
52 Real z_1 = radius * std::cos((theta) / 3.) + shift;
53 Real z_2 = radius * std::cos((theta + 2. * PI) / 3.) + shift;
54 Real z_3 = radius * std::cos((theta - 2. * PI) / 3.) + shift;
59 mults[0] = mults[1] = mults[2] = 1;
64 if (std::abs(roots[0] - roots[1]) < eps) {
65 swap2(roots[0], roots[2]);
66 }
else if (std::abs(roots[0] - roots[2]) < eps) {
67 swap2(roots[0], roots[1]);
68 }
else if (std::abs(roots[1] - roots[2]) < eps) {
72 return {3, roots, mults};
75 roots[1] = average(roots[1], roots[2]);
78 if (std::abs(roots[0] - roots[1]) < eps) {
80 roots[0] = (1. / 3.) * roots[0] + (2. / 3.) * roots[1];
82 return {1, roots, mults};
84 return {2, roots, mults};
88 OMEGA_H_INLINE Roots<2> find_polynomial_roots(
89 Few<Real, 2> coeffs, Real eps = 1e-6) {
93 roots[0] = roots[1] = 0.0;
95 mults[0] = mults[1] = 0;
96 Real disc = square(a) - 4. * b;
97 if (std::abs(disc) < eps) {
102 return {1, roots, mults};
107 roots[0] = (-a + std::sqrt(disc)) / 2.;
108 roots[1] = (-a - std::sqrt(disc)) / 2.;
109 return {2, roots, mults};
111 return {0, roots, mults};
115 OMEGA_H_INLINE Roots<1> find_polynomial_roots(
116 Few<Real, 1> coeffs, Real eps = 1e-6) {
123 return {1, roots, mults};
127 OMEGA_H_INLINE Few<Real, 3> characteristic_polynomial(Tensor<3> A) {
131 coeffs[1] = (1. / 2.) * ((tA * tA) - trace(A * A));
132 coeffs[0] = -determinant(A);
137 OMEGA_H_INLINE Few<Real, 2> characteristic_polynomial(Tensor<2> A) {
139 coeffs[1] = -trace(A);
140 coeffs[0] = determinant(A);
144 OMEGA_H_INLINE Few<Real, 1> characteristic_polynomial(Tensor<1> A) {
146 coeffs[0] = -determinant(A);
151 OMEGA_H_INLINE Roots<n> get_eigenvalues(Tensor<n> A) {
152 auto poly = characteristic_polynomial(A);
155 return find_polynomial_roots(poly, 5e-5);
159 OMEGA_H_INLINE Tensor<m> subtract_from_diag(Tensor<m> a, Real
const mu) {
160 for (Int i = 0; i < m; ++i) a[i][i] -= mu;
175 OMEGA_H_INLINE Vector<3> single_eigenvector(Tensor<3>
const m, Real
const l) {
176 auto s = transpose(subtract_from_diag(m, l));
177 auto v = cross(s[0], s[1]);
178 auto v_norm = norm(v);
179 auto c = cross(s[1], s[2]);
180 auto c_norm = norm(c);
181 if (c_norm > v_norm) {
185 c = cross(s[0], s[2]);
187 if (c_norm > v_norm) {
191 OMEGA_H_CHECK(v_norm > EPSILON);
200 OMEGA_H_INLINE Vector<m> get_1d_row_space(Tensor<m>
const a) {
201 auto ta = transpose(a);
203 auto best_norm = norm(ta[best_row]);
204 for (Int i = 1; i < m; ++i) {
205 auto row_norm = norm(ta[i]);
206 if (row_norm > best_norm) {
208 best_norm = row_norm;
211 OMEGA_H_CHECK(best_norm > EPSILON);
212 return ta[best_row] / best_norm;
217 OMEGA_H_INLINE Few<Vector<3>, 2> double_eigenvector(
218 Tensor<3>
const m, Real
const l) {
219 auto s = subtract_from_diag(m, l);
220 auto n = get_1d_row_space(s);
221 auto b = form_ortho_basis(n);
235 auto roots_obj = get_eigenvalues(m);
236 auto nroots = roots_obj.n;
237 auto roots = roots_obj.values;
238 auto mults = roots_obj.mults;
243 for (Int i = 0; i < 3; ++i) {
244 q[i] = single_eigenvector(m, roots[i]);
247 }
else if (nroots == 2 && mults[1] == 2) {
248 q[0] = single_eigenvector(m, roots[0]);
250 auto dev = double_eigenvector(m, roots[1]);
253 l[1] = l[2] = roots[1];
255 OMEGA_H_CHECK(nroots == 1 && mults[0] == 3);
256 l[0] = l[1] = l[2] = roots[0];
257 q = identity_matrix<3, 3>();
264 OMEGA_H_INLINE Vector<2> single_eigenvector(Tensor<2>
const m, Real
const l) {
265 return perp(get_1d_row_space(subtract_from_diag(m, l)));
268 OMEGA_H_INLINE DiagDecomp<2> decompose_eigen_dim(Tensor<2>
const m) {
269 auto roots_obj = get_eigenvalues(m);
270 auto nroots = roots_obj.n;
271 auto roots = roots_obj.values;
276 for (Int i = 0; i < 2; ++i) {
277 q[i] = single_eigenvector(m, roots[i]);
281 OMEGA_H_CHECK(nroots == 1 && roots_obj.mults[0] == 2);
282 l[0] = l[1] = roots[0];
283 q = identity_matrix<2, 2>();
288 OMEGA_H_INLINE DiagDecomp<1> decompose_eigen_dim(Tensor<1>
const m) {
289 auto roots_obj = get_eigenvalues(m);
290 auto roots = roots_obj.values;
291 OMEGA_H_CHECK(are_close(roots[0], m[0][0]));
292 return {matrix_1x1(1.0), vector_1(roots[0])};
307 OMEGA_H_INLINE DiagDecomp<dim> decompose_eigen(Tensor<dim> m) {
311 Real nm = max_norm(m);
314 return {identity_matrix<dim, dim>(), zero_vector<dim>()};
317 auto decomp = decompose_eigen_dim(m);
318 return {decomp.q, decomp.l * nm};
324 OMEGA_H_INLINE Tensor<dim> compose_eigen(
325 Tensor<dim>
const q, Vector<dim>
const l) {
326 return q * diagonal(l) * invert(q);
332 OMEGA_H_INLINE Tensor<dim> compose_ortho(Tensor<dim>
const q, Vector<dim> l) {
333 return q * diagonal(l) * transpose(q);
341 OMEGA_H_INLINE Real norm_off_diag(Tensor<dim>
const a) {
343 for (Int j = 0; j < dim; ++j) {
344 for (Int i = 0; i < dim; ++i) {
346 s += square(a(i, j));
358 OMEGA_H_INLINE Few<Int, 2> arg_max_off_diag(Tensor<dim>
const a) {
362 for (Int j = 0; j < dim; ++j) {
363 for (Int i = 0; i < dim; ++i) {
364 auto s2 = std::abs(a(i, j));
365 if (i != j && s2 > s) {
381 OMEGA_H_INLINE Vector<2> schur_sym(Real f, Real g, Real h) {
385 Real t = (h - f) / (2.0 * g);
387 t = 1.0 / (std::sqrt(1.0 + square(t)) + t);
389 t = -1.0 / (std::sqrt(1.0 + square(t)) - t);
391 c = 1.0 / std::sqrt(1.0 + square(t));
394 return vector_2(c, s);
399 OMEGA_H_INLINE Tensor<dim> givens_left(
400 Real
const c, Real
const s, Int
const i, Int
const k, Tensor<dim> a) {
401 for (Int j = 0; j < dim; ++j) {
404 a(i, j) = c * t1 - s * t2;
405 a(k, j) = s * t1 + c * t2;
412 OMEGA_H_INLINE Tensor<dim> givens_right(
413 Real
const c, Real
const s, Int
const i, Int
const k, Tensor<dim> a) {
414 for (Int j = 0; j < dim; ++j) {
417 a(j, i) = c * t1 - s * t2;
418 a(j, k) = s * t1 + c * t2;
427 OMEGA_H_INLINE DiagDecomp<dim> decompose_eigen_jacobi(
428 Tensor<dim> a, Real
const eps = DBL_EPSILON, Int max_iter = -1) {
431 if (max_iter == -1) max_iter = (5 * dim * dim) / 2;
432 auto v = identity_matrix<dim, dim>();
433 auto tol = eps * norm(a);
435 while (norm_off_diag(a) > tol && iter < max_iter) {
436 auto pq = arg_max_off_diag(a);
442 auto cs = schur_sym(f, g, h);
445 a = givens_left(c, s, p, q, a);
446 a = givens_right(c, s, p, q, a);
447 v = givens_right(c, s, p, q, v);
450 return {v, diagonal(a)};
454 OMEGA_H_INLINE DiagDecomp<dim> sort_by_magnitude(DiagDecomp<dim>
const dd) {
456 for (Int i = 0; i < dim; ++i) perm[i] = i;
457 for (Int i = 0; i < dim; ++i) {
459 auto max_m = std::abs(dd.l[perm[max_j]]);
460 for (Int j = i + 1; j < dim; ++j) {
461 auto m = std::abs(dd.l[perm[j]]);
462 if (m > max_m) max_j = j;
464 swap2(perm[i], perm[max_j]);
467 for (Int i = 0; i < dim; ++i) out.l[i] = dd.l[perm[i]];
468 for (Int i = 0; i < dim; ++i) out.q[i] = dd.q[perm[i]];
474 OMEGA_H_INLINE_BIG Tensor<dim> log_spd_old(
475 Tensor<dim>
const m) OMEGA_H_NOEXCEPT {
476 auto decomp = decompose_eigen(m);
477 for (Int i = 0; i < dim; ++i) decomp.l[i] = std::log(decomp.l[i]);
478 return compose_ortho(decomp.q, decomp.l);
483 OMEGA_H_INLINE_BIG Tensor<dim> exp_spd_old(
484 Tensor<dim>
const m) OMEGA_H_NOEXCEPT {
485 auto decomp = decompose_eigen(m);
486 for (Int i = 0; i < dim; ++i) decomp.l[i] = std::exp(decomp.l[i]);
487 return compose_ortho(decomp.q, decomp.l);
492 OMEGA_H_INLINE_BIG Tensor<dim> log_spd(Tensor<dim>
const m) OMEGA_H_NOEXCEPT {
493 auto decomp = decompose_eigen_jacobi(m);
494 for (Int i = 0; i < dim; ++i) decomp.l[i] = std::log(decomp.l[i]);
495 return compose_ortho(decomp.q, decomp.l);
500 OMEGA_H_INLINE_BIG Tensor<dim> exp_spd(Tensor<dim>
const m) OMEGA_H_NOEXCEPT {
501 auto decomp = decompose_eigen_jacobi(m);
502 for (Int i = 0; i < dim; ++i) decomp.l[i] = std::exp(decomp.l[i]);
503 return compose_ortho(decomp.q, decomp.l);
508 OMEGA_H_INLINE_BIG Tensor<dim> sqrt_spd(Tensor<dim>
const m) OMEGA_H_NOEXCEPT {
509 auto decomp = decompose_eigen_jacobi(m);
510 for (Int i = 0; i < dim; ++i) decomp.l[i] = std::sqrt(decomp.l[i]);
511 return compose_ortho(decomp.q, decomp.l);
514 Reals get_max_eigenvalues(Int dim, Reals symms);
Definition: amr_mpi_test.cpp:6
Definition: Omega_h_eigen.hpp:229
Definition: Omega_h_eigen.hpp:9