HILA
Loading...
Searching...
No Matches
sun_matrix.h
Go to the documentation of this file.
1/**
2 * @file sun_matrix.h
3 * @brief SU(N) Matrix definitions
4 * @details This file contains definitions for SU(N) matrix class and specialized Algebra
5 * class for SU(N) matrix.
6 */
7
8#ifndef SUN_MATRIX_H_
9#define SUN_MATRIX_H_
10
11#include "matrix.h"
12#include "su2.h"
14
15/// Define type SU<n,type>
16/// Derives from square Matrix<Complex> type
17
18template <typename G>
19class Algebra;
20
21template <typename T>
22class sparse_el {
23 public:
24 using base_type = hila::arithmetic_type<T>;
25 using argument_type = T;
26 int ind1;
27 int ind2;
28 T val;
29 sparse_el<T>() = default;
30 ~sparse_el<T>() = default;
31 sparse_el<T>(const sparse_el<T> &a) = default;
32 sparse_el<T>(int i1, int i2, const T &v) : ind1(i1), ind2(i2), val(v) {}
33
34 inline sparse_el<T> &operator=(const sparse_el<T> &s) & = default;
35 sparse_el<T> &set(const sparse_el<T> &s) {
36 ind1 = s.ind1;
37 ind2 = s.ind2;
38 val = s.val;
39 return *this;
40 }
41
42 sparse_el<T> &set(int i1, int i2, const T &v) {
43 ind1 = i1;
44 ind2 = i2;
45 val = v;
46 return *this;
47 }
48};
49
50template <int N, typename T>
51class Alg_gen {
52 public:
53 using base_type = T;
54 using argument_type = Complex<T>;
55 int size;
56 sparse_el<Complex<T>> c[N];
57 Alg_gen() : size(0){};
58 ~Alg_gen() = default;
59 inline Alg_gen &operator=(const Alg_gen &s) & = default;
60 Alg_gen &push(sparse_el<T> tel) {
61 c[size] = tel;
62 ++size;
63 return *this;
64 }
65 Alg_gen &push(int i1, int i2, const T &v) {
66 c[size].set(i1, i2, Complex<T>(v,0.0));
67 ++size;
68 return *this;
69 }
70 Alg_gen &push(int i1, int i2, const Complex<T> &v) {
71 c[size].set(i1, i2, v);
72 ++size;
73 return *this;
74 }
75 sparse_el<T> pop() {
76 sparse_el<T> res(c[size - 1]);
77 --size;
78 return res;
79 }
80 Matrix<N, N, Complex<T>> to_matrix() const {
82 for (int i = 0; i < size; ++i) {
83 res.e(c[i].ind1, c[i].ind2) = c[i].val;
84 }
85 return res;
86 }
87 Alg_gen &empty() {
88 size = 0;
89 return *this;
90 }
91};
92
93/**
94 * @brief Class for SU(N) matrix
95 * @details Class for Special unitary group SU(N).
96 *
97 * SU class is a special case inherited from Matrix_t class. SU specific or overloaded methods are:
98 *
99 * - SU::make_unitary
100 * - SU::fix_det
101 * - SU::reunitarize
102 * - SU::random
103 * - SU::project_to_algebra
104 *
105 *
106 * @tparam N Dimensionality of SU(N) matrix
107 * @tparam T Arithmetic type of Complex<T> number which SU(N) matrix elements consist of
108 */
109template <int N, typename T>
110class SU : public Matrix_t<N, N, Complex<T>, SU<N, T>> {
111
112 public:
113 // std incantation for field types
114 using base_type = T;
115 using argument_type = Complex<T>; // constructed from complex
116
117 // get all constructors from base
119 // same with assignent, but delete rvalue assign
120 using Matrix_t<N, N, Complex<T>, SU<N, T>>::operator=;
121 SU &operator=(const SU &su) && = delete;
122
123
124 /**
125 * @brief Makes the matrix unitary by orthogonalizing the rows
126 * @details This is not the most optimal method, but it is simple:
127 *
128 * Let `SU<N> H ` be a special unitary matrix and define the indicies \f$ i \in
129 * \{0,...,N-1\} \f$. The method is as follows:
130 * 1. Normalize ` H.row(i) `
131 * 2. Make rows `H.row(i+1) ` ...` H.row(n-1)` orthogonal with respect
132 * to row `H.row(i) `
133 *
134 *
135 * @return const SU&
136 */
137 const SU &make_unitary() {
138
139 for (int r = 0; r < N; r++) {
140
141 // normalize row r
142 T n2 = 0;
143 // use here function instead of method, works for double/float too
144 for (int i = 0; i < N; i++)
145 n2 += ::squarenorm(this->e(r, i));
146 n2 = 1.0 / sqrt(n2);
147 for (int i = 0; i < N; i++)
148 this->e(r, i) *= n2;
149
150 // Now make rows r+1 .. n-1 orthogonal to row r,
151 // by doing j = j - (r^* j) r
152
153 Complex<T> d;
154 for (int j = r + 1; j < N; j++) {
155 // dot productof r^* j
156 d = 0;
157 for (int i = 0; i < N; i++) {
158 d += ::conj(this->e(r, i)) * this->e(j, i);
159 }
160 // and j -= d * r
161 for (int i = 0; i < N; i++) {
162 this->e(j, i) -= d * this->e(r, i);
163 }
164 }
165 }
166 return *this;
167 }
168
169 /**
170 * @brief Fix determinant
171 * @details Set the determinant of the SU(N) matrix to 1
172 * @return const SU&
173 */
174 const SU &fix_det() {
175
176 Complex<T> d = det(*(this));
177 T t = d.arg() / N;
178 d = Complex<T>(cos(-t), sin(-t));
179 for (int i = 0; i < N * N; i++) {
180 this->c[i] *= d;
181 }
182 return *this;
183 }
184
185 /**
186 * @brief Reunitarize SU(N) matrix
187 * @details Steps to reunitarize are:
188 * 1. Make SU(N) matrix unitary
189 * 2. Fix determinant
190 *
191 * @return const SU&
192 */
193 const SU &reunitarize() {
194 make_unitary();
195 fix_det();
196 return *this;
197 }
198
199 /**
200 * @brief Generate random SU(N) matrix
201 * @details If N=2 random SU(N) matrix is generated by using Pauli matrix representation.
202 *
203 * If N > 2 then first we generate a random SU(2) matrix, and multiply the Identity matrix I(N)
204 * by this matrix using SU::mult_by_2x2_left. After this we SU::reunitarize the matrix due to
205 * numerical errors in the multiplication.
206 *
207 * @param nhits Number of times I(N) matrix is multiplied to generate random SU(N) matrix, only
208 * relevant for N > 2s
209 * @return const SU&
210 */
211 const SU &random(int nhits = 16) out_only {
212
213 // use Pauli matrix representation to generate SU(2) random matrix
214 if constexpr (N == 2) {
215 Vector<4, T> v;
216 v.gaussian_random();
217 v /= v.norm();
218 this->e(0, 0) = Complex<T>(v[0], v[3]);
219 this->e(1, 1) = Complex<T>(v[0], -v[3]);
220 this->e(0, 1) = Complex<T>(v[2], v[1]);
221 this->e(1, 0) = Complex<T>(-v[2], v[1]);
222
223 } else {
224
225 *this = 1;
226 SU<2, T> m2;
227
228 for (int h = 1; h <= nhits; h++) {
229 for (int r = 0; r < N - 1; r++)
230 for (int q = r + 1; q < N; q++) {
231 m2.random();
232 this->mult_by_2x2_left(r, q, m2);
233 }
234
235 // keep it SU(N)
236 if (h % 16 == 0) {
237 this->reunitarize();
238 }
239 }
240 if (nhits % 16 != 0)
241 this->reunitarize();
242 }
243 return *this;
244 }
245
246 ///
247 /// Project matrix to antihermitean and traceless algebra
248 /// of the group.
249 /// suN generators, normalized as
250 /// Tr(\lambda_n \lambda_m) = -1/2 \delta_nm ,
251 /// or equivalently: Tr(\lambda^{\dagger}_n \lambda_m) = 1/2 \delta_nm
252 ///
253 /// off-diagonal are just that:
254 /// \lambda^od_nm = i/2 for elements nm and mn
255 /// \lambda^od_nm = 1/2 for nm; -1/2 for mn
256 ///
257 /// diagonals: su(N) has N-1 diag generators
258 /// parametrize these recursively:
259 /// \lambda_1 = diag(i,-i,0,0,..)/sqrt(1)/2
260 /// \lambda_2 = diag(i,i,-2i,0,..)/sqrt(3)/2
261 /// \lambda_3 = diag(i,i,i,-3i,0,..)/sqrt(6)/2
262 /// \lambda_k = diag(i,.. i,-ki,0,..)/sqrt(k(k+1)/2)/2
263 /// ..
264 /// \lambda_N-1 = diag(i,.. i,-(N-1)i)/sqrt(N(N-1)/2)/2
265 ///
266 /// Define \lambda's so that diagonals come first
267 ///
268 /// Dividing U = U_ah + U_h, U_ah = 1/2 (U - U^+) = a_k \lambda_k + tr.im I/N
269 /// => Tr(\lambda_k U_ah) = -1/2 a_k = 1/2 (\lambda_k)_lm (u_ml - u_lm^*)
270 /// => a_k = - (\lambda_k)_lm (u_ml - u_lm^*)
271 ///
272 /// Thus, for diags,
273 /// a_k = (u_00 + ..u_(k-1)(k-1) - k*u_kk).im 2/(sqrt(2k(k+1)))
274 ///
275 /// and off-diags:
276 /// symm: a_i = -i (u_kj - u_kj^* + u_jk - u_jk^*)/2 = -i i(u_kj.im + u_jk.im)
277 /// = (u_kj.im + u_jk.im)
278 /// antisymm: a_i = -i (i u_kj - i u_jk^* - i u_jk + i u_kj^*)/2
279 /// = (u_kj.re - u_jk.re)
280
282 // computes real vector a[] of Lie-algebra decomposition coefficients
283 // of A[][]=(*this) , s.t. a[i] = 2 ReTr( \lambda^{\dagger}_i A )
284
286
287 // diagonal generators
288 T sum = this->e(0, 0).im;
289 for (int i = 1; i < N; i++) {
290 a.e(i - 1) = (sum - i * this->e(i, i).im) / sqrt(0.5 * i * (i + 1));
291 sum += this->e(i, i).im;
292 }
293
294 // Then off-diag bits
295 int k = a.n_diag;
296 for (int i = 0; i < N - 1; i++) {
297 for (int j = i + 1; j < N; j++) {
298 auto od = this->e(i, j) - this->e(j, i).conj();
299 a.e(k) = od.re;
300 a.e(k + 1) = od.im;
301 k += 2;
302 }
303 }
304
305 return a;
306 }
307
308 Algebra<SU<N, T>> project_to_algebra_scaled(T scf) const {
309 // as above, but rescales the output vector by the factor scf
311
312 // diagonal generators
313 T sum = this->e(0, 0).im;
314 for (int i = 1; i < N; i++) {
315 a.e(i - 1) = scf * (sum - i * this->e(i, i).im) / sqrt(0.5 * i * (i + 1));
316 sum += this->e(i, i).im;
317 }
318
319 // Then off-diag bits
320 int k = a.n_diag;
321 for (int i = 0; i < N - 1; i++) {
322 for (int j = i + 1; j < N; j++) {
323 auto od = this->e(i, j) - this->e(j, i).conj();
324 a.e(k) = scf * od.re;
325 a.e(k + 1) = scf * od.im;
326 k += 2;
327 }
328 }
329
330 return a;
331 }
332
333 Algebra<SU<N, T>> project_to_algebra(out_only T &onenorm) const {
334 // computes and returns vector a[] of real-valued Lie-algebra
335 // projection coefficients and sets in addition onenorm
336 // to be the 1-norm of a[]
338
339 onenorm = 0;
340 // diagonal generators
341 T sum = this->e(0, 0).im;
342 for (int i = 1; i < N; i++) {
343 a.e(i - 1) = (sum - i * this->e(i, i).im) / sqrt(0.5 * i * (i + 1));
344 sum += this->e(i, i).im;
345 onenorm += abs(a.e(i - 1));
346 }
347
348 // Then off-diag bits
349 int k = a.n_diag;
350 for (int i = 0; i < N - 1; i++) {
351 for (int j = i + 1; j < N; j++) {
352 auto od = this->e(i, j) - this->e(j, i).conj();
353 a.e(k) = od.re;
354 a.e(k + 1) = od.im;
355 onenorm += abs(a.e(k)) + abs(a.e(k + 1));
356 k += 2;
357 }
358 }
359
360 return a;
361 }
362};
363
364///////////////////////////////////////////////////////////
365/// Specialize Algebra type to SU(N)
366/// Derive from (real) Vector of N*N-1 elements
367
368template <int N, typename T>
369class Algebra<SU<N, T>> : public Matrix_t<N * N - 1, 1, T, Algebra<SU<N, T>>> {
370 public:
371 // std incantation for field types
372 using base_type = hila::arithmetic_type<T>;
373 using argument_type = T;
374
375 // storage for the diagonal and off-diag
376 // components of the antihermitean traceless matrix
377 static constexpr int n_offdiag = N * (N - 1);
378 static constexpr int n_diag = N - 1;
379 static constexpr int N_a = N * N - 1;
380
381 /// std constructors and operators derived from vector
382 using Matrix_t<N * N - 1, 1, T, Algebra<SU<N, T>>>::Matrix_t;
383 using Matrix_t<N * N - 1, 1, T, Algebra<SU<N, T>>>::operator=;
384 Algebra &operator=(const Algebra &a) && = delete;
385
386 // suN generators, normalized as
387 // Tr(\lambda_i \lambda_j) = -1/2 \delta_ij ,
388 // or equivalently: Tr(\lambda_i \lambda_j) = 1/2 \delta_ij
389 // off-diagonal are just that:
390 // \lambda^od_ij,r = 1/2 for elements ij and ji
391 // \lambda^od_ij,i = i/2 for ij; -i for ji
392 //
393 // diagonals: su(N) has N-1 diag generators
394 // parametrize these recursively:
395 // \lambda_1 = diag(1,-1,0,0,..)/sqrt(1)/2
396 // \lambda_2 = diag(1,1,-2,0,..)/sqrt(3)/2
397 // \lambda_3 = diag(1,1,1,-3,..)/sqrt(6)/2
398 // \lambda_i = diag(1,.. ,-i,..)/sqrt(i(i+1)/2)/2
399 // ..
400 // \lambda_N-1 = diag(1,.. ,1,-(N-1))/sqrt(N(N-1)/2)/2
401 //
402 // Define \lambda's so that diagonals come first
403
404 /// expand algebra to matrix rep - antihermitean
405
406 static void generator_list(Alg_gen<N, T>(out_only &gen_list)[N_a]) {
407 // set gen_list to contain N_a=N^2-1 generators of su(N) as sparse matrices
408 // (sparse -> list of non-zero elements (ind1,ind2,val))
409 for (int i = 1; i < N; ++i) {
410 gen_list[i - 1].empty();
411 for (int j = 0; j < i; ++j) {
412 gen_list[i - 1].push(j, j, Complex<T>(0, 1.0 / sqrt(2.0 * (i * (i + 1)))));
413 }
414 gen_list[i - 1].push(i, i, Complex<T>(0, -i / sqrt(2.0 * (i * (i + 1)))));
415 }
416
417 int k = n_diag;
418 for (int i = 0; i < N - 1; i++) {
419 for (int j = i + 1; j < N; j++) {
420 gen_list[k].empty();
421 gen_list[k].push(i, j, Complex<T>(0.5, 0));
422 gen_list[k].push(j, i, Complex<T>(-0.5, 0));
423 ++k;
424 gen_list[k].empty();
425 gen_list[k].push(i, j, Complex<T>(0, 0.5));
426 gen_list[k].push(j, i, Complex<T>(0, 0.5));
427 ++k;
428 }
429 }
430 }
431
432 static void generator_product_list(const Alg_gen<N, T>(&gen_list)[N_a], Alg_gen<N, T>(out_only &gen_prod_list)[N_a][N_a]) {
433 // set gen_prod_list[i][j]=\lambda_i \lambda_j as sparse matrices
434 // (sparse -> list of non-zero elements (ind1,ind2,val))
436 int i1, i2, j1, j2;
437 for (i1 = 0; i1 < N * N - 1; ++i1) {
438 const auto &gen1 = gen_list[i1];
439 for (i2 = 0; i2 < N * N - 1; ++i2) {
440 temp = 0;
441 const auto &gen2 = gen_list[i2];
442 for (auto el1 = gen1.c; el1 != gen1.c + gen1.size; ++el1) {
443 for (auto el2 = gen2.c; el2 != gen2.c + gen2.size; ++el2) {
444 if(el1->ind2==el2->ind1) {
445 temp.e(el1->ind1, el2->ind2) += el1->val*el2->val;
446 }
447 }
448 }
449 for (j1 = 0; j1 < N; ++j1) {
450 for (j2 = 0; j2 < N; ++j2) {
451 if(temp.e(j1,j2)!=0) {
452 gen_prod_list[i1][i2].push(j1, j2, temp.e(j1, j2));
453 }
454 }
455 }
456 }
457 }
458 }
459
460 static void generator_product_list(Alg_gen<N, T>(out_only &gen_prod_list)[N_a][N_a]) {
461 // set gen_prod_list[i][j]=2 \lambda_i \lambda_j as sparse matrices
462 // (sparse -> list of non-zero elements (ind1,ind2,val))
463 Alg_gen<N, T> gen_list[N_a];
464 generator_list(gen_list);
465 generator_product_list(gen_list, gen_prod_list);
466 }
467
468 SU<N, T> expand() const {
469 SU<N, T> m;
470
471 Vector<N, T> d;
472
473 d.e(0) = (T)0;
474 for (int i = 1; i < N; i++) {
475 T r = this->c[i - 1] * sqrt(0.5 / (i * (i + 1)));
476 // the contributions from 1's above
477 for (int j = 0; j < i; j++)
478 d.e(j) += r;
479 // and set the negative element - no sum here, first contrib
480 d.e(i) = -i * r;
481 }
482
483 for (int i = 0; i < N; i++)
484 m.e(i, i) = Complex<T>(0, d.e(i));
485
486 int k = n_diag;
487 T inv2 = 0.5;
488 for (int i = 0; i < N - 1; i++)
489 for (int j = i + 1; j < N; j++) {
490 Complex<T> v(this->c[k] * inv2, this->c[k + 1] * inv2);
491 m.e(i, j) = v;
492 m.e(j, i) = -v.conj();
493 k += 2;
494 }
495
496 return m;
497 }
498
499 /// expand algebra to scaled matrix rep - antihermitian
500 SU<N, T> expand_scaled(T scf) const {
501 SU<N, T> m;
502
503 Vector<N, T> d;
504
505 d.e(0) = (T)0;
506 for (int i = 1; i < N; i++) {
507 T r = this->c[i - 1] * sqrt(0.5 / (i * (i + 1)));
508 // the contributions from 1's above
509 for (int j = 0; j < i; j++)
510 d.e(j) += r;
511 // and set the negative element - no sum here, first contrib
512 d.e(i) = -i * r;
513 }
514
515 for (int i = 0; i < N; i++)
516 m.e(i, i) = Complex<T>(0, scf * d.e(i));
517
518 int k = n_diag;
519 T inv2 = 0.5 * scf;
520 for (int i = 0; i < N - 1; i++)
521 for (int j = i + 1; j < N; j++) {
522 Complex<T> v(this->c[k] * inv2, this->c[k + 1] * inv2);
523 m.e(i, j) = v;
524 m.e(j, i) = -v.conj();
525 k += 2;
526 }
527
528 return m;
529 }
530
531
532 /// Produce gaussian random distributed algebra
533 /// element.
534 /// Set default normalisation so that the algebra matrix
535 /// ah = i h = i xi_i \lambda_i
536 /// is from distribution
537 /// exp(-Tr h^2 ) = exp(- xi_i^2 / 2 )
538 /// I.E. the coefficients of the generators have
539 /// < xi_i^2 > = 1
540 ///
541 /// Now the off-diag elements have
542 /// <|od|^2> = 1/2 = <od.re^2> + <od.im^2> = 1/4 + 1/4
543 /// 1/4 (<xi_a^2> + <xi_b^2>)
544 ///
545 /// With this convention the inherited method from Vector
546 /// is fine and the code below is not needed
547
548 // Algebra &gaussian_random() out_only {
549 //
550 // for (int i=0; i<N_a; i++) {
551 // a.e(i) = hila::gaussrand();
552 // }
553 //
554 // return *this;
555 // }
556 // Wrapper for base class' gaussian_random with appropriate
557 // default gaussian width for chosen algebra normalization
558 Algebra &gaussian_random(T width = sqrt(2.0)) out_only {
559 Matrix_t<N * N - 1, 1, T, Algebra<SU<N, T>>>::gaussian_random(width);
560 return *this;
561 }
562
563 // dot product of two Algebra vectors
564 T dot(const Algebra &rhs) const {
565 T r = 0.0;
566 for (int i = 0; i < N_a; ++i) {
567 r += this->e(i) * rhs.e(i);
568 }
569 return r * 0.5;
570 }
571};
572
573template <int N, typename T>
574SU<N, T> exp(const Algebra<SU<N, T>> &a) {
575 SU<N, T> m = a.expand();
576 return exp(m);
577
578 // SU<N,T> m = a.expand() * (-I); // make hermitean
579 // SquareMatrix<N,Complex<T>> D;
580 // Vector<N,T> ev;
581 // m.eigen_jacobi(ev,D);
582 // Vector<N,Complex<T>> expv;
583
584 // for (int i=0; i<N; i++) expv[i] = exp(I*ev[i]);
585 // for (int i=0; i<N; i++) for (int j=0; j<N; j++) {
586 // m.e(i,j) = D.e(i,0) * expv[0] * D.e(j,0).conj();
587 // for (int k=1; k<N; k++)
588 // m.e(i,j) += D.e(i,k) * expv[k] * D.e(j,k).conj();
589 // }
590 // return m;
591}
592
593
594// overload of matrix exponential with iterative Cayley-Hamilton (ch) defined in matrix.h.
595template <int N, typename T>
596SU<N, T> chexp(const Algebra<SU<N, T>> &a) {
597 SU<N, T> m = a.expand();
598 return chexp(m);
599}
600
601
602// overload of matrix exponential with iterative Cayley-Hamilton using
603// "chs" implementation (defined in matrix.h) which needs less temporary
604// memory, but is a bit slower.
605template <int N, typename T>
606SU<N, T> chsexp(const Algebra<SU<N, T>> &a) {
607 SU<N, T> m = a.expand();
608 return chsexp(m);
609}
610
611
612// logarithm of SU(N) matrix with iterative Cayley-Hamilton
613template <int N, typename T>
614Algebra<SU<N, T>> log(const SU<N, T> &a) {
615 int maxit = 5 * N;
616 T fprec = fp<T>::epsilon * 10.0 * Algebra<SU<N, T>>::N_a;
618
619 SU<N, T> tmat = a, tmat2;
620 Algebra<SU<N, T>> res = 0, tres;
621 T trn, rn;
622 int it, i;
623 for (it = 0; it < maxit; ++it) {
624 tres = tmat.project_to_algebra(trn);
625 rn = 0;
626 for (i = 0; i < Algebra<SU<N, T>>::N_a; ++i) {
627 res.e(i) -= tres.e(i);
628 rn += abs(res.e(i));
629 }
630 if (trn < fprec * (rn + 1.0)) {
631 break;
632 }
633 tmat = res.expand();
634 chexp(tmat, tmat2, pl);
635 mult(a, tmat2, tmat);
636 }
637
638 return -res;
639}
640
641template <int N, typename T, typename MT, typename fT = hila::arithmetic_type<T>>
642void project_to_algebra_bilinear(const Matrix_t<N, N, T, MT> &w1, const Matrix_t<N, N, T, MT> &w2,
644 const Alg_gen<N, fT> (&genlist)[N * N - 1]) {
645 // computes real matrix outmat[i][j] = 2 * Tr(\lambda_i^{\dagger} * w1 * lambda_j * w2)
646 // where the list of algebra generators is provided by genlist[]
647 int i1, i2;
648 fT temp;
649 for (i1 = 0; i1 < N * N - 1; ++i1) {
650 const auto &gen1 = genlist[i1];
651 for (i2 = 0; i2 < N * N - 1; ++i2) {
652 temp = 0;
653 const auto &gen2 = genlist[i2];
654 for (auto el1 = gen1.c; el1 != gen1.c + gen1.size; ++el1) {
655 for (auto el2 = gen2.c; el2 != gen2.c + gen2.size; ++el2) {
656 temp += real(el1->val * w1.e(el1->ind2, el2->ind1) * el2->val *
657 w2.e(el2->ind2, el1->ind1));
658 }
659 }
660 omat.e(i1, i2) = -2.0 * temp;
661 }
662 }
663}
664
665template <int N, typename T, typename MT, typename fT = hila::arithmetic_type<T>>
666void project_to_algebra_bilinear(const Matrix_t<N, N, T, MT> &w1, const Matrix_t<N, N, T, MT> &w2,
667 out_only Matrix<N * N - 1, N * N - 1, fT> &omat) {
668 // computes real matrix outmat[i][j] = 2 * Tr(\lambda_i^{\dagger} * w1 * lambda_j * w2)
669 Alg_gen<N, fT> genlist[N * N - 1];
670 Algebra<SU<N, fT>>::generator_list(genlist);
671 project_to_algebra_bilinear(w1, w2, omat, genlist);
672}
673
674template <int N, typename T, typename MT, typename fT = hila::arithmetic_type<T>>
675void project_to_algebra_bilinear(const Matrix_t<N, N, T, MT> &w1,
677 const Alg_gen<N, fT> (&genprodlist)[N * N - 1][N * N - 1]) {
678 // computes real matrix outmat[i][j] = 2 * ReTr(\lambda_i^{\dagger} * w1 * lambda_j)
679 // where the list of algebra generator products is provided by genprodlist[][]
680 int i1, i2;
681 fT temp;
682 for (i1 = 0; i1 < N * N - 1; ++i1) {
683 for (i2 = 0; i2 < N * N - 1; ++i2) {
684 const auto &gen = genprodlist[i2][i1];
685 temp = 0;
686 for (auto el1 = gen.c; el1 != gen.c + gen.size; ++el1) {
687 temp += real(el1->val * w1.e(el1->ind2, el1->ind1));
688 }
689 omat.e(i1, i2) = -2.0 * temp;
690 }
691 }
692}
693
694template <int N, typename T, typename MT, typename fT = hila::arithmetic_type<T>>
695void project_to_algebra_bilinear(const Matrix_t<N, N, T, MT> &w1,
696 out_only Matrix<N * N - 1, N * N - 1, fT> &omat) {
697 // computes real matrix outmat[i][j] = 2 * ReTr(\lambda_i^{\dagger} * w1 * lambda_j)
698 Alg_gen<N, fT> genprodlist[N * N - 1][N * N - 1];
699 Algebra<SU<N, fT>>::generator_product_list(genprodlist);
700 project_to_algebra_bilinear(w1, omat, genprodlist);
701}
702
703template <const int N, typename T, typename MT>
704void project_to_algebra_bilinear(const MT (&w)[N][N],
705 out_only Matrix<N * N - 1, N * N - 1, T> &omat,
706 const Alg_gen<N, T> (&genlist)[N * N - 1]) {
707 // computes real matrix outmat[i][j] = 2 * Re(Tr(\lambda_i^{\dagger} * w1[k][l]) *
708 // \lambda_j[l][k]) where the list of algebra generators is provided by genlist[]
709 int i1, i2;
710 T temp;
711 for (i1 = 0; i1 < N * N - 1; ++i1) {
712 const auto &gen1 = genlist[i1];
713 for (i2 = 0; i2 < N * N - 1; ++i2) {
714 temp = 0;
715 const auto &gen2 = genlist[i2];
716 for (auto el1 = gen1.c; el1 != gen1.c + gen1.size; ++el1) {
717 for (auto el2 = gen2.c; el2 != gen2.c + gen2.size; ++el2) {
718 temp +=
719 real(el1->val * w[el2->ind1][el2->ind2].e(el1->ind2, el1->ind1) * el2->val);
720 }
721 }
722 omat.e(i1, i2) = -2.0 * temp;
723 }
724 }
725}
726
727template <int N, typename T, typename MT>
728void project_to_algebra_bilinear(const MT (&w)[N][N],
729 out_only Matrix<N * N - 1, N * N - 1, T> &omat) {
730 // computes real matrix outmat[i][j] = 2 * Re(Tr(\lambda_i^{\dagger} * w1[k][l]) *
731 // \lambda_j[l][k])
732 Alg_gen<N, T> genlist[N * N - 1];
733 Algebra<SU<N, T>>::generator_list(genlist);
734 project_to_algebra_bilinear(w, omat, genlist);
735}
736
737namespace hila {
738
739///
740/// Function hila::random(SU<N,T> & m), equivalent to m.random()
741// template <int N, typename T>
742// void random(out_only SU<N, T> &m) {
743// m.random();
744// }
745
746
747} // namespace hila
748#endif
Array< n, m, T > exp(Array< n, m, T > a)
Exponential.
Definition array.h:1059
Array< n, m, T > cos(Array< n, m, T > a)
Cosine.
Definition array.h:1089
Array< n, m, T > sqrt(Array< n, m, T > a)
Square root.
Definition array.h:1039
Array< n, m, T > sin(Array< n, m, T > a)
Sine.
Definition array.h:1079
Array< n, m, hila::arithmetic_type< T > > real(const Array< n, m, T > &arg)
Return real part of Array.
Definition array.h:688
SU< N, T > expand_scaled(T scf) const
expand algebra to scaled matrix rep - antihermitian
Definition sun_matrix.h:500
static void generator_list(Alg_gen< N, T >(&gen_list)[N_a])
expand algebra to matrix rep - antihermitean
Definition sun_matrix.h:406
Algebra & gaussian_random(T width=sqrt(2.0))
Definition sun_matrix.h:558
Definition su2.h:7
Complex definition.
Definition cmplx.h:56
Complex< T > conj() const
Compute conjugate of Complex number.
Definition cmplx.h:282
T arg() const
Compute argument of Complex number.
Definition cmplx.h:270
The main matrix type template Matrix_t. This is a base class type for "useful" types which are deriv...
Definition matrix.h:106
void mult_by_2x2_left(int p, int q, const Matrix_t< 2, 2, R, Mt > &M)
Multiply -matrix from the left by matrix defined by sub matrix.
Definition matrix.h:1473
hila::arithmetic_type< T > norm() const
Calculate vector norm - sqrt of squarenorm.
Definition matrix.h:1133
Matrix_t()=default
Define default constructors to ensure std::is_trivial.
SU< N, T > conj() const
Returns complex conjugate of Matrix.
Definition matrix.h:986
Complex< T > det() const
determinant function - if matrix size is < 5, use Laplace, otherwise LU
auto abs() const
Returns absolute value of Matrix.
Definition matrix.h:1031
Mtype & gaussian_random(base_type width=1.0)
Fills Matrix with gaussian random elements.
Definition matrix.h:1314
T e(const int i, const int j) const
Standard array indexing operation for matrices and vectors.
Definition matrix.h:286
hila::arithmetic_type< Complex< T > > squarenorm() const
Calculate square norm - sum of squared elements.
Definition matrix.h:1117
Matrix class which defines matrix operations.
Definition matrix.h:1620
Class for SU(N) matrix.
Definition sun_matrix.h:110
const SU & random(int nhits=16)
Generate random SU(N) matrix.
Definition sun_matrix.h:211
const SU & reunitarize()
Reunitarize SU(N) matrix.
Definition sun_matrix.h:193
const SU & fix_det()
Fix determinant.
Definition sun_matrix.h:174
Algebra< SU< N, T > > project_to_algebra() const
Definition sun_matrix.h:281
const SU & make_unitary()
Makes the matrix unitary by orthogonalizing the rows.
Definition sun_matrix.h:137
T abs(const Complex< T > &a)
Return absolute value of Complex number.
Definition cmplx.h:1187
Definition of Matrix types.
Matrix_t< n, m, T, MT > chsexp(const Matrix_t< n, m, T, MT > &mat)
Calculate exp of a square matrix.
Definition matrix.h:3672
int chexp(const Matrix_t< n, m, T, MT > &mat, Matrix_t< n, m, T, MT > &omat, Mt(&pl)[n])
Calculate exp of a square matrix.
Definition matrix.h:2933
void mult(const Mt1 &a, const Mt2 &b, Mt3 &res)
compute product of two matrices and write result to existing matrix
Definition matrix.h:2327
Implement hila::swap for gauge fields.
Definition array.h:981
logger_class log
Now declare the logger.