Serac  0.1
Serac is an implicit thermal strucural mechanics simulation code.
tensor.hpp
Go to the documentation of this file.
1 // Copyright (c) Lawrence Livermore National Security, LLC and
2 // other Serac Project Developers. See the top-level LICENSE file for
3 // details.
4 //
5 // SPDX-License-Identifier: (BSD-3-Clause)
6 
13 #pragma once
14 
15 #include <cmath>
16 
19 
20 namespace serac {
21 
27 template <typename T, int... n>
28 struct tensor;
29 
31 template <typename T, int m, int... n>
32 struct tensor<T, m, n...> {
33  template <typename i_type>
34  SERAC_HOST_DEVICE constexpr auto& operator()(i_type i)
35  {
36  return data[i];
37  }
38  template <typename i_type>
39  SERAC_HOST_DEVICE constexpr auto& operator()(i_type i) const
40  {
41  return data[i];
42  }
43  template <typename i_type, typename... jklm_type>
44  SERAC_HOST_DEVICE constexpr auto& operator()(i_type i, jklm_type... jklm)
45  {
46  return data[i](jklm...);
47  }
48  template <typename i_type, typename... jklm_type>
49  SERAC_HOST_DEVICE constexpr auto& operator()(i_type i, jklm_type... jklm) const
50  {
51  return data[i](jklm...);
52  }
53 
54  SERAC_HOST_DEVICE constexpr auto& operator[](int i) { return data[i]; }
55  SERAC_HOST_DEVICE constexpr const auto& operator[](int i) const { return data[i]; }
56 
57  tensor<T, n...> data[m];
58 };
59 
60 template <typename T, int m>
61 struct tensor<T, m> {
62  template <typename i_type>
63  SERAC_HOST_DEVICE constexpr auto& operator()(i_type i)
64  {
65  return data[i];
66  }
67  template <typename i_type>
68  SERAC_HOST_DEVICE constexpr auto& operator()(i_type i) const
69  {
70  return data[i];
71  }
72  SERAC_HOST_DEVICE constexpr auto& operator[](int i) { return data[i]; }
73  SERAC_HOST_DEVICE constexpr const auto& operator[](int i) const { return data[i]; }
74 
76  SERAC_HOST_DEVICE constexpr operator T()
77  {
78  return data[0];
79  }
80 
82  SERAC_HOST_DEVICE constexpr operator T() const
83  {
84  return data[0];
85  }
86 
87  T data[m];
88 };
90 
99 template <typename T, int n1>
100 tensor(const T (&data)[n1]) -> tensor<T, n1>;
101 
110 template <typename T, int n1, int n2>
111 tensor(const T (&data)[n1][n2]) -> tensor<T, n1, n2>;
112 
115 
118 
122 struct zero {
124  SERAC_HOST_DEVICE operator double() { return 0.0; }
125 
127  template <typename T, int... n>
128  SERAC_HOST_DEVICE operator tensor<T, n...>()
129  {
130  return tensor<T, n...>{};
131  }
132 
134  template <typename... T>
135  SERAC_HOST_DEVICE auto operator()(T...) const
136  {
137  return zero{};
138  }
139 
141  template <typename T>
143  {
144  return zero{};
145  }
146 };
147 
149 template <typename T>
150 struct is_zero : std::false_type {
151 };
152 
154 template <>
155 struct is_zero<zero> : std::true_type {
156 };
157 
159 SERAC_HOST_DEVICE constexpr auto operator+(zero, zero) { return zero{}; }
160 
162 template <typename T>
163 SERAC_HOST_DEVICE constexpr auto operator+(zero, T other)
164 {
165  return other;
166 }
167 
169 template <typename T>
170 SERAC_HOST_DEVICE constexpr auto operator+(T other, zero)
171 {
172  return other;
173 }
174 
176 
178 SERAC_HOST_DEVICE constexpr auto operator-(zero) { return zero{}; }
179 
181 SERAC_HOST_DEVICE constexpr auto operator-(zero, zero) { return zero{}; }
182 
184 template <typename T>
185 SERAC_HOST_DEVICE constexpr auto operator-(zero, T other)
186 {
187  return -other;
188 }
189 
191 template <typename T>
192 SERAC_HOST_DEVICE constexpr auto operator-(T other, zero)
193 {
194  return other;
195 }
196 
198 
200 SERAC_HOST_DEVICE constexpr auto operator*(zero, zero) { return zero{}; }
201 
203 template <typename T>
204 SERAC_HOST_DEVICE constexpr auto operator*(zero, T /*other*/)
205 {
206  return zero{};
207 }
208 
210 template <typename T>
211 SERAC_HOST_DEVICE constexpr auto operator*(T /*other*/, zero)
212 {
213  return zero{};
214 }
215 
217 template <typename T>
218 SERAC_HOST_DEVICE constexpr auto operator/(zero, T /*other*/)
219 {
220  return zero{};
221 }
222 
224 template <typename T>
225 void operator/(T, zero)
226 {
227  static_assert(::detail::always_false<T>{}, "Error: Can't divide by zero!");
228 }
229 
231 SERAC_HOST_DEVICE constexpr auto operator+=(zero, zero) { return zero{}; }
232 
234 SERAC_HOST_DEVICE constexpr auto operator-=(zero, zero) { return zero{}; }
235 
237 template <int i>
239 {
240  return x;
241 }
242 
244 template <int i>
246 {
247  return zero{};
248 }
249 
251 template <typename T>
252 SERAC_HOST_DEVICE constexpr zero dot(const T&, zero)
253 {
254  return zero{};
255 }
256 
258 template <typename T>
259 SERAC_HOST_DEVICE constexpr zero dot(zero, const T&)
260 {
261  return zero{};
262 }
263 
271 template <typename T, int n1, int n2 = 1>
272 using reduced_tensor = std::conditional_t<
273  (n1 == 1 && n2 == 1), double,
274  std::conditional_t<n1 == 1, tensor<T, n2>, std::conditional_t<n2 == 1, tensor<T, n1>, tensor<T, n1, n2>>>>;
275 
281 template <typename T, int... n>
282 SERAC_HOST_DEVICE constexpr auto tensor_with_shape(std::integer_sequence<int, n...>)
283 {
284  return tensor<T, n...>{};
285 }
286 
298 template <typename lambda_type>
299 SERAC_HOST_DEVICE constexpr auto make_tensor(lambda_type f)
300 {
301  using T = decltype(f());
302  return tensor<T>{f()};
303 }
304 
317 template <int n1, typename lambda_type>
318 SERAC_HOST_DEVICE constexpr auto make_tensor(lambda_type f)
319 {
320  using T = decltype(f(n1));
321  tensor<T, n1> A{};
322  for (int i = 0; i < n1; i++) {
323  A(i) = f(i);
324  }
325  return A;
326 }
327 
341 template <int n1, int n2, typename lambda_type>
342 SERAC_HOST_DEVICE constexpr auto make_tensor(lambda_type f)
343 {
344  using T = decltype(f(n1, n2));
345  tensor<T, n1, n2> A{};
346  for (int i = 0; i < n1; i++) {
347  for (int j = 0; j < n2; j++) {
348  A(i, j) = f(i, j);
349  }
350  }
351  return A;
352 }
353 
368 template <int n1, int n2, int n3, typename lambda_type>
369 SERAC_HOST_DEVICE constexpr auto make_tensor(lambda_type f)
370 {
371  using T = decltype(f(n1, n2, n3));
373  for (int i = 0; i < n1; i++) {
374  for (int j = 0; j < n2; j++) {
375  for (int k = 0; k < n3; k++) {
376  A(i, j, k) = f(i, j, k);
377  }
378  }
379  }
380  return A;
381 }
382 
398 template <int n1, int n2, int n3, int n4, typename lambda_type>
399 SERAC_HOST_DEVICE constexpr auto make_tensor(lambda_type f)
400 {
401  using T = decltype(f(n1, n2, n3, n4));
403  for (int i = 0; i < n1; i++) {
404  for (int j = 0; j < n2; j++) {
405  for (int k = 0; k < n3; k++) {
406  for (int l = 0; l < n4; l++) {
407  A(i, j, k, l) = f(i, j, k, l);
408  }
409  }
410  }
411  }
412  return A;
413 }
414 
423 template <typename S, typename T, int m, int... n>
425 {
426  tensor<decltype(S{} + T{}), m, n...> C{};
427  for (int i = 0; i < m; i++) {
428  C[i] = A[i] + B[i];
429  }
430  return C;
431 }
432 
439 template <typename T, int m, int... n>
441 {
442  tensor<T, m, n...> B{};
443  for (int i = 0; i < m; i++) {
444  B[i] = -A[i];
445  }
446  return B;
447 }
448 
457 template <typename S, typename T, int m, int... n>
459 {
460  tensor<decltype(S{} + T{}), m, n...> C{};
461  for (int i = 0; i < m; i++) {
462  C[i] = A[i] - B[i];
463  }
464  return C;
465 }
466 
475 template <typename S, typename T, int m, int... n>
477 {
478  for (int i = 0; i < m; i++) {
479  A[i] += B[i];
480  }
481  return A;
482 }
483 
484 #if 0
491 template <typename T>
492 SERAC_HOST_DEVICE constexpr auto& operator+=(tensor<T>& A, const T& B)
493 {
494  return A.data += B;
495 }
496 #endif
497 
504 template <typename T, int n>
506 {
507  for (int i = 0; i < n; i++) {
508  A.data[i][0] += B[i];
509  }
510  return A;
511 }
512 
519 template <typename T, int n>
521 {
522  for (int i = 0; i < n; i++) {
523  A.data[0][i] += B[i];
524  }
525  return A;
526 }
527 
534 template <typename T>
535 SERAC_HOST_DEVICE constexpr auto& operator+=(tensor<T, 1>& A, const T& B)
536 {
537  return A.data[0] += B;
538 }
539 
546 template <typename T>
547 SERAC_HOST_DEVICE constexpr auto& operator+=(tensor<T, 1, 1>& A, const T& B)
548 {
549  return A.data[0][0] += B;
550 }
551 
558 template <typename T, int... n>
560 {
561  return A;
562 }
563 
572 template <typename S, typename T, int m, int... n>
574 {
575  for (int i = 0; i < m; i++) {
576  A[i] -= B[i];
577  }
578  return A;
579 }
580 
587 template <typename T, int... n>
589 {
590  return A;
591 }
592 
597 template <typename T, int n>
598 SERAC_HOST_DEVICE constexpr auto outer(double A, tensor<T, n> B)
599 {
600  tensor<decltype(double{} * T{}), n> AB{};
601  for (int i = 0; i < n; i++) {
602  AB[i] = A * B[i];
603  }
604  return AB;
605 }
606 
611 template <typename T, int m>
612 SERAC_HOST_DEVICE constexpr auto outer(const tensor<T, m>& A, double B)
613 {
614  tensor<decltype(T{} * double{}), m> AB{};
615  for (int i = 0; i < m; i++) {
616  AB[i] = A[i] * B;
617  }
618  return AB;
619 }
620 
625 template <typename T, int n>
626 SERAC_HOST_DEVICE constexpr auto outer(zero, const tensor<T, n>&)
627 {
628  return zero{};
629 }
630 
635 template <typename T, int n>
636 SERAC_HOST_DEVICE constexpr auto outer(const tensor<T, n>&, zero)
637 {
638  return zero{};
639 }
640 
645 template <typename S, typename T, int m, int n>
646 SERAC_HOST_DEVICE constexpr auto outer(const tensor<S, m>& A, const tensor<T, n>& B)
647 {
648  tensor<decltype(S{} * T{}), m, n> AB{};
649  for (int i = 0; i < m; i++) {
650  for (int j = 0; j < n; j++) {
651  AB[i][j] = A[i] * B[j];
652  }
653  }
654  return AB;
655 }
656 
666 template <typename S, typename T, int m, int n>
667 SERAC_HOST_DEVICE constexpr auto inner(const tensor<S, m, n>& A, const tensor<T, m, n>& B)
668 {
669  decltype(S{} * T{}) sum{};
670  for (int i = 0; i < m; i++) {
671  for (int j = 0; j < n; j++) {
672  sum += A[i][j] * B[i][j];
673  }
674  }
675  return sum;
676 }
677 
682 template <typename S, typename T, int m>
683 SERAC_HOST_DEVICE constexpr auto inner(const tensor<S, m>& A, const tensor<T, m>& B)
684 {
685  decltype(S{} * T{}) sum{};
686  for (int i = 0; i < m; i++) {
687  sum += A[i] * B[i];
688  }
689  return sum;
690 }
691 
696 SERAC_HOST_DEVICE constexpr auto inner(double A, double B) { return A * B; }
697 
704 template <typename S, int m, int n>
706 {
707  return zero{};
708 }
709 
714 template <typename S, int m>
715 SERAC_HOST_DEVICE constexpr auto inner(const tensor<S, m>&, zero)
716 {
717  return zero{};
718 }
719 
724 SERAC_HOST_DEVICE constexpr auto inner(double, zero) { return zero{}; }
725 
732 template <typename T, int m, int n>
734 {
735  return zero{};
736 }
737 
742 template <typename T, int m>
743 SERAC_HOST_DEVICE constexpr auto inner(zero, const tensor<T, m>&)
744 {
745  return zero{};
746 }
747 
752 SERAC_HOST_DEVICE constexpr auto inner(zero, double) { return zero{}; }
753 
762 template <typename S, typename T, int m, int n, int p>
763 SERAC_HOST_DEVICE constexpr auto dot(const tensor<S, m, n>& A, const tensor<T, n, p>& B)
764 {
765  tensor<decltype(S{} * T{}), m, p> AB{};
766  for (int i = 0; i < m; i++) {
767  for (int j = 0; j < p; j++) {
768  for (int k = 0; k < n; k++) {
769  AB[i][j] = AB[i][j] + A[i][k] * B[k][j];
770  }
771  }
772  }
773  return AB;
774 }
775 
780 template <typename T, int m>
781 SERAC_HOST_DEVICE constexpr auto dot(const tensor<T, m>& A, double B)
782 {
783  return A * B;
784 }
785 
790 template <typename T, int m>
791 SERAC_HOST_DEVICE constexpr auto dot(double B, const tensor<T, m>& A)
792 {
793  return B * A;
794 }
795 
800 template <typename S, typename T, int m>
801 SERAC_HOST_DEVICE constexpr auto dot(const tensor<S, m>& A, const tensor<T, m>& B)
802 {
803  decltype(S{} * T{}) AB{};
804  for (int i = 0; i < m; i++) {
805  AB = AB + A[i] * B[i];
806  }
807  return AB;
808 }
809 
814 template <typename S, typename T, int m, int n>
815 SERAC_HOST_DEVICE constexpr auto dot(const tensor<S, m>& A, const tensor<T, m, n>& B)
816 {
817  tensor<decltype(S{} * T{}), n> AB{};
818  for (int i = 0; i < n; i++) {
819  for (int j = 0; j < m; j++) {
820  AB[i] = AB[i] + A[j] * B[j][i];
821  }
822  }
823  return AB;
824 }
825 
830 template <typename S, typename T, int m, int n, int p>
831 SERAC_HOST_DEVICE constexpr auto dot(const tensor<S, m>& A, const tensor<T, m, n, p>& B)
832 {
833  tensor<decltype(S{} * T{}), n, p> AB{};
834  for (int j = 0; j < m; j++) {
835  AB = AB + A[j] * B[j];
836  }
837  return AB;
838 }
839 
850 template <typename S, typename T, int m, int n, int p, int q>
851 SERAC_HOST_DEVICE constexpr auto dot(const tensor<S, m>& A, const tensor<T, m, n, p, q>& B)
852 {
853  tensor<decltype(S{} * T{}), n, p, q> AB{};
854  for (int j = 0; j < m; j++) {
855  AB = AB + A[j] * B[j];
856  }
857  return AB;
858 }
859 
864 template <typename S, typename T, int m, int n>
865 SERAC_HOST_DEVICE constexpr auto dot(const tensor<S, m, n>& A, const tensor<T, n>& B)
866 {
867  tensor<decltype(S{} * T{}), m> AB{};
868  for (int i = 0; i < m; i++) {
869  for (int j = 0; j < n; j++) {
870  AB[i] = AB[i] + A[i][j] * B[j];
871  }
872  }
873  return AB;
874 }
875 
880 template <typename S, typename T, int m, int n, int p, int q, int r>
881 SERAC_HOST_DEVICE constexpr auto dot(const tensor<S, m, n>& A, const tensor<T, n, p, q, r>& B)
882 {
883  tensor<decltype(S{} * T{}), m, p, q, r> AB{};
884  for (int i = 0; i < m; i++) {
885  for (int j = 0; j < n; j++) {
886  AB[i] = AB[i] + A[i][j] * B[j];
887  }
888  }
889  return AB;
890 }
891 
896 template <typename S, typename T, int m, int n, int p, int q>
897 SERAC_HOST_DEVICE constexpr auto dot(const tensor<S, m, n>& A, const tensor<T, n, p, q>& B)
898 {
899  tensor<decltype(S{} * T{}), m, p, q> AB{};
900  for (int i = 0; i < m; i++) {
901  for (int j = 0; j < n; j++) {
902  AB[i] = AB[i] + A[i][j] * B[j];
903  }
904  }
905  return AB;
906 }
907 
912 template <typename S, typename T, int m, int n, int p>
913 SERAC_HOST_DEVICE constexpr auto dot(const tensor<S, m, n, p>& A, const tensor<T, p>& B)
914 {
915  tensor<decltype(S{} * T{}), m, n> AB{};
916  for (int i = 0; i < m; i++) {
917  for (int j = 0; j < n; j++) {
918  for (int k = 0; k < p; k++) {
919  AB[i][j] += A[i][j][k] * B[k];
920  }
921  }
922  }
923  return AB;
924 }
925 
930 template <typename S, typename T, typename U, int m, int n>
931 SERAC_HOST_DEVICE constexpr auto dot(const tensor<S, m>& u, const tensor<T, m, n>& A, const tensor<U, n>& v)
932 {
933  decltype(S{} * T{} * U{}) uAv{};
934  for (int i = 0; i < m; i++) {
935  for (int j = 0; j < n; j++) {
936  uAv += u[i] * A[i][j] * v[j];
937  }
938  }
939  return uAv;
940 }
941 
943 template <typename S, typename T, int m, int n, int p, int q>
944 SERAC_HOST_DEVICE constexpr auto dot(const tensor<S, m, n, p, q>& A, const tensor<T, q>& B)
945 {
946  tensor<decltype(S{} * T{}), m, n, p> AB{};
947  for (int i = 0; i < m; i++) {
948  for (int j = 0; j < n; j++) {
949  for (int k = 0; k < p; k++) {
950  for (int l = 0; l < q; l++) {
951  AB[i][j][k] += A[i][j][k][l] * B[l];
952  }
953  }
954  }
955  }
956  return AB;
957 }
958 
960 template <typename T>
961 auto cross(const tensor<T, 3, 2>& A)
962 {
963  return tensor<T, 3>{A(1, 0) * A(2, 1) - A(2, 0) * A(1, 1), A(2, 0) * A(0, 1) - A(0, 0) * A(2, 1),
964  A(0, 0) * A(1, 1) - A(1, 0) * A(0, 1)};
965 }
966 
968 template <typename T>
969 auto cross(const tensor<T, 2, 1>& v)
970 {
971  return tensor<T, 2>{v(1, 0), -v(0, 0)};
972 }
973 
975 template <typename T>
976 auto cross(const tensor<T, 2>& v)
977 {
978  return tensor<T, 2>{v[1], -v[0]};
979 }
980 
982 template <typename S, typename T>
983 auto cross(const tensor<S, 3>& u, const tensor<T, 3>& v)
984 {
985  return tensor<decltype(S{} * T{}), 3>{u(1) * v(2) - u(2) * v(1), u(2) * v(0) - u(0) * v(2),
986  u(0) * v(1) - u(1) * v(0)};
987 }
988 
1000 template <typename S, typename T, int m, int n, int p, int q>
1002 {
1003  tensor<decltype(S{} * T{}), m, n> AB{};
1004  for (int i = 0; i < m; i++) {
1005  for (int j = 0; j < n; j++) {
1006  for (int k = 0; k < p; k++) {
1007  for (int l = 0; l < q; l++) {
1008  AB[i][j] += A[i][j][k][l] * B[k][l];
1009  }
1010  }
1011  }
1012  }
1013  return AB;
1014 }
1015 
1020 template <typename S, typename T, int m, int n, int p>
1022 {
1023  tensor<decltype(S{} * T{}), m> AB{};
1024  for (int i = 0; i < m; i++) {
1025  for (int j = 0; j < n; j++) {
1026  for (int k = 0; k < p; k++) {
1027  AB[i] += A[i][j][k] * B[j][k];
1028  }
1029  }
1030  }
1031  return AB;
1032 }
1033 
1038 template <typename S, typename T, int m, int n>
1039 constexpr auto double_dot(const tensor<S, m, n>& A, const tensor<T, m, n>& B)
1040 {
1041  decltype(S{} * T{}) AB{};
1042  for (int i = 0; i < m; i++) {
1043  for (int j = 0; j < n; j++) {
1044  AB += A[i][j] * B[i][j];
1045  }
1046  }
1047  return AB;
1048 }
1049 
1053 template <typename S, typename T, int... m, int... n>
1055 {
1056  return dot(A, B);
1057 }
1058 
1063 template <typename T, int m>
1065 {
1066  T total{};
1067  for (int i = 0; i < m; i++) {
1068  total += A[i] * A[i];
1069  }
1070  return total;
1071 }
1072 
1074 template <typename T, int m, int n>
1076 {
1077  T total{};
1078  for (int i = 0; i < m; i++) {
1079  for (int j = 0; j < n; j++) {
1080  total += A[i][j] * A[i][j];
1081  }
1082  }
1083  return total;
1084 }
1085 
1087 template <typename T, int... n>
1089 {
1090  T total{};
1091  for_constexpr<n...>([&](auto... i) { total += A(i...) * A(i...); });
1092  return total;
1093 }
1094 
1099 template <typename T, int... n>
1101 {
1102  using std::sqrt;
1103  return sqrt(squared_norm(A));
1104 }
1105 
1109 SERAC_HOST_DEVICE constexpr auto norm(zero) { return zero{}; }
1110 
1116 template <typename T, int... n>
1118 {
1119  return A / norm(A);
1120 }
1121 
1127 template <typename T>
1129 {
1130  tensor<T, 3, 3> output{};
1131  output[0][0] = A[0][0];
1132  output[0][1] = A[0][1];
1133  output[1][0] = A[1][0];
1134  output[1][1] = A[1][1];
1135  return output;
1136 }
1137 
1143 template <typename T, int n>
1144 SERAC_HOST_DEVICE constexpr auto tr(const tensor<T, n, n>& A)
1145 {
1146  T trA{};
1147  for (int i = 0; i < n; i++) {
1148  trA = trA + A[i][i];
1149  }
1150  return trA;
1151 }
1152 
1158 template <typename T, int n>
1159 SERAC_HOST_DEVICE constexpr auto sym(const tensor<T, n, n>& A)
1160 {
1161  tensor<T, n, n> symA{};
1162  for (int i = 0; i < n; i++) {
1163  for (int j = 0; j < n; j++) {
1164  symA[i][j] = 0.5 * (A[i][j] + A[j][i]);
1165  }
1166  }
1167  return symA;
1168 }
1169 
1175 template <typename T, int n>
1177 {
1178  tensor<T, n, n> antisymA{};
1179  for (int i = 0; i < n; i++) {
1180  for (int j = 0; j < n; j++) {
1181  antisymA[i][j] = 0.5 * (A[i][j] - A[j][i]);
1182  }
1183  }
1184  return antisymA;
1185 }
1186 
1194 template <typename T, int n>
1195 SERAC_HOST_DEVICE constexpr auto dev(const tensor<T, n, n>& A)
1196 {
1197  auto devA = A;
1198  auto trA = tr(A);
1199  for (int i = 0; i < n; i++) {
1200  devA[i][i] -= trA / n;
1201  }
1202  return devA;
1203 }
1204 
1211 template <typename T, int n>
1213 {
1214  tensor<T, n, n> D{};
1215  for (int i = 0; i < n; i++) {
1216  D[i][i] = A[i][i];
1217  }
1218  return D;
1219 }
1220 
1225 template <typename T, int n>
1227 {
1228  tensor<T, n, n> D{};
1229  for (int i = 0; i < n; i++) {
1230  D[i][i] = d[i];
1231  }
1232  return D;
1233 }
1234 
1239 template <typename T, int n>
1241 {
1242  tensor<T, n> d{};
1243  for (int i = 0; i < n; i++) {
1244  d[i] = D[i][i];
1245  }
1246  return d;
1247 }
1248 
1253 template <int dim>
1255 {
1257  for (int i = 0; i < dim; i++) {
1258  for (int j = 0; j < dim; j++) {
1259  I[i][j] = (i == j);
1260  }
1261  }
1262  return I;
1263 }
1264 
1269 template <typename T, int m, int n>
1271 {
1272  tensor<T, n, m> AT{};
1273  for (int i = 0; i < n; i++) {
1274  for (int j = 0; j < m; j++) {
1275  AT[i][j] = A[j][i];
1276  }
1277  }
1278  return AT;
1279 }
1280 
1285 template <typename T>
1286 SERAC_HOST_DEVICE constexpr auto I2(const tensor<T, 3, 3>& A)
1287 {
1288  return +A[0][0] * A[1][1] + A[1][1] * A[2][2] + A[2][2] * A[0][0] - A[0][1] * A[1][0] - A[1][2] * A[2][1] -
1289  A[2][0] * A[0][2];
1290 }
1291 
1296 template <typename T>
1297 SERAC_HOST_DEVICE constexpr auto det(const tensor<T, 2, 2>& A)
1298 {
1299  return A[0][0] * A[1][1] - A[0][1] * A[1][0];
1300 }
1301 
1303 template <typename T>
1304 SERAC_HOST_DEVICE constexpr auto det(const tensor<T, 3, 3>& A)
1305 {
1306  return A[0][0] * A[1][1] * A[2][2] + A[0][1] * A[1][2] * A[2][0] + A[0][2] * A[1][0] * A[2][1] -
1307  A[0][0] * A[1][2] * A[2][1] - A[0][1] * A[1][0] * A[2][2] - A[0][2] * A[1][1] * A[2][0];
1308 }
1309 
1320 template <typename T>
1322 {
1323  // From the Cayley-Hamilton theorem, we get that for any N by N matrix A,
1324  // det(A - I) - 1 = I1(A) + I2(A) + ... + IN(A),
1325  // where the In are the principal invariants of A.
1326  // We inline the definitions of the principal invariants to increase computational speed.
1327 
1328  // equivalent to tr(A) + det(A)
1329  return A(0, 0) - A(0, 1) * A(1, 0) + A(1, 1) + A(0, 0) * A(1, 1);
1330 }
1331 
1333 template <typename T>
1335 {
1336  // For notes on the implementation, see the 2x2 version.
1337 
1338  // clang-format off
1339  // equivalent to tr(A) + I2(A) + det(A)
1340  return A(0, 0) + A(1, 1) + A(2, 2)
1341  - A(0, 1) * A(1, 0) * (1 + A(2, 2))
1342  + A(0, 0) * A(1, 1) * (1 + A(2, 2))
1343  - A(0, 2) * A(2, 0) * (1 + A(1, 1))
1344  - A(1, 2) * A(2, 1) * (1 + A(0, 0))
1345  + A(0, 0) * A(2, 2)
1346  + A(1, 1) * A(2, 2)
1347  + A(0, 1) * A(1, 2) * A(2, 0)
1348  + A(0, 2) * A(1, 0) * A(2, 1);
1349  // clang-format on
1350 }
1351 
1360 template <typename T, int dim>
1362 {
1363  auto B = A;
1364  for (int i = 0; i < 15; i++) {
1365  B = 0.5 * (B + dot(A, inv(B)));
1366  }
1367  return B;
1368 }
1369 
1399 template <int i1, int i2, typename S, int m, int... n, typename T, int p, int q>
1401 {
1402  constexpr int Adims[] = {m, n...};
1403  constexpr int Bdims[] = {p, q};
1404  static_assert(sizeof...(n) < 3);
1405  static_assert(Adims[i1] == Bdims[i2], "error: incompatible tensor dimensions");
1406 
1407  // first, we have to figure out the dimensions of the output tensor
1408  constexpr int new_dim = (i2 == 0) ? q : p;
1409  constexpr int d1 = (i1 == 0) ? new_dim : Adims[0];
1410  constexpr int d2 = (i1 == 1) ? new_dim : Adims[1];
1411  constexpr int d3 = sizeof...(n) == 1 ? 0 : ((i1 == 2) ? new_dim : Adims[2]);
1412 
1413  // the type of the output tensor is easier to figure out
1414  using U = decltype(S{} * T{});
1415 
1416  auto C = []() {
1417  if constexpr (d3 == 0) return tensor<U, d1, d2>{};
1418  if constexpr (d3 != 0) return tensor<U, d1, d2, d3>{};
1419  }();
1420 
1421  if constexpr (d3 == 0) {
1422  for (int i = 0; i < d1; i++) {
1423  for (int j = 0; j < d2; j++) {
1424  U sum{};
1425  for (int k = 0; k < Adims[i1]; k++) {
1426  if constexpr (i1 == 0 && i2 == 0) sum += A(k, j) * B(k, i);
1427  if constexpr (i1 == 1 && i2 == 0) sum += A(i, k) * B(k, j);
1428  if constexpr (i1 == 0 && i2 == 1) sum += A(k, j) * B(i, k);
1429  if constexpr (i1 == 1 && i2 == 1) sum += A(i, k) * B(j, k);
1430  }
1431  C(i, j) = sum;
1432  }
1433  }
1434  } else {
1435  for (int i = 0; i < d1; i++) {
1436  for (int j = 0; j < d2; j++) {
1437  for (int k = 0; k < d3; k++) {
1438  U sum{};
1439  for (int l = 0; l < Adims[i1]; l++) {
1440  if constexpr (i1 == 0 && i2 == 0) sum += A(l, j, k) * B(l, i);
1441  if constexpr (i1 == 1 && i2 == 0) sum += A(i, l, k) * B(l, j);
1442  if constexpr (i1 == 2 && i2 == 0) sum += A(i, j, l) * B(l, k);
1443  if constexpr (i1 == 0 && i2 == 1) sum += A(l, j, k) * B(i, l);
1444  if constexpr (i1 == 1 && i2 == 1) sum += A(i, l, k) * B(j, l);
1445  if constexpr (i1 == 2 && i2 == 1) sum += A(i, j, l) * B(k, l);
1446  }
1447  C(i, j, k) = sum;
1448  }
1449  }
1450  }
1451  }
1452 
1453  return C;
1454 }
1455 
1457 template <int i1, int i2, typename T>
1458 SERAC_HOST_DEVICE auto contract(const zero&, const T&)
1459 {
1460  return zero{};
1461 }
1462 
1472 template <typename T, int... n>
1474 {
1475  return norm(A - B) / norm(A);
1476 }
1477 
1486 template <int n>
1487 SERAC_HOST_DEVICE bool is_symmetric(tensor<double, n, n> A, double tolerance = 1.0e-8)
1488 {
1489  for (int i = 0; i < n; ++i) {
1490  for (int j = i + 1; j < n; ++j) {
1491  if (std::abs(A(i, j) - A(j, i)) > tolerance) {
1492  return false;
1493  };
1494  }
1495  }
1496  return true;
1497 }
1498 
1508 {
1509  if (!is_symmetric(A)) {
1510  return false;
1511  }
1512  if (A(0, 0) < 0.0) {
1513  return false;
1514  }
1515  if (det(A) < 0.0) {
1516  return false;
1517  }
1518  return true;
1519 }
1522 {
1523  if (!is_symmetric(A)) {
1524  return false;
1525  }
1526  if (det(A) < 0.0) {
1527  return false;
1528  }
1529  auto subtensor = make_tensor<2, 2>([A](int i, int j) { return A(i, j); });
1530  if (!is_symmetric_and_positive_definite(subtensor)) {
1531  return false;
1532  }
1533  return true;
1534 }
1535 
1541 template <typename T, int n>
1546 };
1547 
1562 template <typename T, int n, int... m>
1564  const tensor<int, n>& P)
1565 {
1566  tensor<T, n, m...> y{};
1567  for (int i = 0; i < n; i++) {
1568  auto c = b[P[i]];
1569  for (int j = 0; j < i; j++) {
1570  c -= L[i][j] * y[j];
1571  }
1572  y[i] = c / L[i][i];
1573  }
1574  return y;
1575 }
1576 
1581 template <typename T, int n, int... m>
1583 {
1584  // no permutation provided, so just map each equation to itself
1585  // TODO make a convienience function for ranges like this
1586  // BT 05/09/2022
1587  tensor<int, n> P(make_tensor<n>([](auto i) { return i; }));
1588 
1589  return solve_lower_triangular(L, b, P);
1590 }
1591 
1602 template <typename T, int n, int... m>
1604 {
1605  tensor<T, n, m...> x{};
1606  for (int i = n - 1; i >= 0; i--) {
1607  auto c = y[i];
1608  for (int j = i + 1; j < n; j++) {
1609  c -= U[i][j] * x[j];
1610  }
1611  x[i] = c / U[i][i];
1612  }
1613  return x;
1614 }
1615 
1620 template <typename S, typename T, int n, int... m>
1621 SERAC_HOST_DEVICE constexpr auto linear_solve(const LuFactorization<S, n>& lu_factors, const tensor<T, n, m...>& b)
1622 {
1623  // Forward substitution
1624  // solve Ly = b
1625  const auto y = solve_lower_triangular(lu_factors.L, b, lu_factors.P);
1626 
1627  // Back substitution
1628  // Solve Ux = y
1629  return solve_upper_triangular(lu_factors.U, y);
1630 }
1631 
1636 template <typename T, int n>
1637 SERAC_HOST_DEVICE constexpr auto linear_solve(const LuFactorization<T, n>& /* lu_factors */, const zero /* b */)
1638 {
1639  return zero{};
1640 }
1641 
1648 {
1649  double inv_detA(1.0 / det(A));
1650 
1651  tensor<double, 2, 2> invA{};
1652 
1653  invA[0][0] = A[1][1] * inv_detA;
1654  invA[0][1] = -A[0][1] * inv_detA;
1655  invA[1][0] = -A[1][0] * inv_detA;
1656  invA[1][1] = A[0][0] * inv_detA;
1657 
1658  return invA;
1659 }
1660 
1666 {
1667  double inv_detA(1.0 / det(A));
1668 
1669  tensor<double, 3, 3> invA{};
1670 
1671  invA[0][0] = (A[1][1] * A[2][2] - A[1][2] * A[2][1]) * inv_detA;
1672  invA[0][1] = (A[0][2] * A[2][1] - A[0][1] * A[2][2]) * inv_detA;
1673  invA[0][2] = (A[0][1] * A[1][2] - A[0][2] * A[1][1]) * inv_detA;
1674  invA[1][0] = (A[1][2] * A[2][0] - A[1][0] * A[2][2]) * inv_detA;
1675  invA[1][1] = (A[0][0] * A[2][2] - A[0][2] * A[2][0]) * inv_detA;
1676  invA[1][2] = (A[0][2] * A[1][0] - A[0][0] * A[1][2]) * inv_detA;
1677  invA[2][0] = (A[1][0] * A[2][1] - A[1][1] * A[2][0]) * inv_detA;
1678  invA[2][1] = (A[0][1] * A[2][0] - A[0][0] * A[2][1]) * inv_detA;
1679  invA[2][2] = (A[0][0] * A[1][1] - A[0][1] * A[1][0]) * inv_detA;
1680 
1681  return invA;
1682 }
1688 template <typename T, int n>
1689 SERAC_HOST_DEVICE constexpr auto inv(const tensor<T, n, n>& A)
1690 {
1691  auto I = DenseIdentity<n>();
1692  return linear_solve(A, I);
1693 }
1694 
1703 template <typename T, int m, int... n>
1704 auto& operator<<(std::ostream& out, const tensor<T, m, n...>& A)
1705 {
1706  out << '{' << A[0];
1707  for (int i = 1; i < m; i++) {
1708  out << ", " << A[i];
1709  }
1710  out << '}';
1711  return out;
1712 }
1713 
1719 inline auto& operator<<(std::ostream& out, zero)
1720 {
1721  out << "zero";
1722  return out;
1723 }
1724 
1730 inline SERAC_HOST_DEVICE void print(double value) { printf("%f", value); }
1731 
1736 template <int m, int... n>
1738 {
1739  printf("{");
1740  print(A[0]);
1741  for (int i = 1; i < m; i++) {
1742  printf(",");
1743  print(A[i]);
1744  }
1745  printf("}");
1746 }
1747 
1752 template <int n>
1753 SERAC_HOST_DEVICE constexpr auto chop(const tensor<double, n>& A)
1754 {
1755  auto copy = A;
1756  for (int i = 0; i < n; i++) {
1757  if (copy[i] * copy[i] < 1.0e-20) {
1758  copy[i] = 0.0;
1759  }
1760  }
1761  return copy;
1762 }
1763 
1765 template <int m, int n>
1767 {
1768  auto copy = A;
1769  for (int i = 0; i < m; i++) {
1770  for (int j = 0; j < n; j++) {
1771  if (copy[i][j] * copy[i][j] < 1.0e-20) {
1772  copy[i][j] = 0.0;
1773  }
1774  }
1775  }
1776  return copy;
1777 }
1778 
1780 namespace detail {
1781 
1782 template <typename T1, typename T2>
1783 struct outer_prod;
1784 
1785 template <int... m, int... n>
1786 struct outer_prod<tensor<double, m...>, tensor<double, n...>> {
1787  using type = tensor<double, m..., n...>;
1788 };
1789 
1790 template <int... n>
1791 struct outer_prod<double, tensor<double, n...>> {
1792  using type = tensor<double, n...>;
1793 };
1794 
1795 template <int... n>
1796 struct outer_prod<tensor<double, n...>, double> {
1797  using type = tensor<double, n...>;
1798 };
1799 
1800 template <>
1801 struct outer_prod<double, double> {
1802  using type = tensor<double>;
1803 };
1804 
1805 template <typename T>
1806 struct outer_prod<zero, T> {
1807  using type = zero;
1808 };
1809 
1810 template <typename T>
1811 struct outer_prod<T, zero> {
1812  using type = zero;
1813 };
1814 
1815 } // namespace detail
1817 
1823 template <typename T1, typename T2>
1825 
1830 inline SERAC_HOST_DEVICE auto get_gradient(double /* arg */) { return zero{}; }
1831 
1837 template <int... n>
1838 SERAC_HOST_DEVICE constexpr auto get_gradient(const tensor<double, n...>& /* arg */)
1839 {
1840  return zero{};
1841 }
1842 
1846 SERAC_HOST_DEVICE constexpr auto chain_rule(const zero /* df_dx */, const zero /* dx */) { return zero{}; }
1847 
1852 template <typename T>
1853 SERAC_HOST_DEVICE constexpr auto chain_rule(const zero /* df_dx */, const T /* dx */)
1854 {
1855  return zero{};
1856 }
1857 
1862 template <typename T>
1863 SERAC_HOST_DEVICE constexpr auto chain_rule(const T /* df_dx */, const zero /* dx */)
1864 {
1865  return zero{};
1866 }
1867 
1872 SERAC_HOST_DEVICE constexpr auto chain_rule(const double df_dx, const double dx) { return df_dx * dx; }
1873 
1878 template <int... n>
1879 SERAC_HOST_DEVICE constexpr auto chain_rule(const tensor<double, n...>& df_dx, const double dx)
1880 {
1881  return df_dx * dx;
1882 }
1883 
1888 template <int... n>
1890 {
1891  double total{};
1892  for_constexpr<n...>([&](auto... i) { total += df_dx(i...) * dx(i...); });
1893  return total;
1894 }
1895 
1900 template <int m, int... n>
1902 {
1903  tensor<double, m> total{};
1904  for (int i = 0; i < m; i++) {
1905  total[i] = chain_rule(df_dx[i], dx);
1906  }
1907  return total;
1908 }
1909 
1914 template <int m, int n, int... p>
1916 {
1917  tensor<double, m, n> total{};
1918  for (int i = 0; i < m; i++) {
1919  for (int j = 0; j < n; j++) {
1920  total[i][j] = chain_rule(df_dx[i][j], dx);
1921  }
1922  }
1923  return total;
1924 }
1925 
1933 template <typename T, int... n>
1935 {
1936  return (n * ... * 1);
1937 }
1938 
1943 SERAC_HOST_DEVICE constexpr int size(const double&) { return 1; }
1944 
1946 SERAC_HOST_DEVICE constexpr int size(zero) { return 0; }
1947 
1956 template <int i, typename T, int... n>
1958 {
1959  constexpr int dimensions[] = {n...};
1960  return dimensions[i];
1961 }
1962 
1971 template <typename T, int m, int... n>
1973 {
1974  return m;
1975 }
1976 
1978 template <typename T, int... n>
1979 bool isnan(const tensor<T, n...>& A)
1980 {
1981  bool found_nan = false;
1982  for_constexpr<n...>([&](auto... i) { found_nan |= std::isnan(A(i...)); });
1983  return found_nan;
1984 }
1985 
1987 inline bool isnan(const zero&) { return false; }
1988 
1989 } // namespace serac
1990 
1991 #if 0
1992 
1993 inline float angle_between(const vec < 2 > & a, const vec < 2 > & b) {
1994  return acos(clip(dot(normalize(a), normalize(b)), -1.0f, 1.0f));
1995 }
1996 
1997 inline float angle_between(const vec < 3 > & a, const vec < 3 > & b) {
1998  return acos(clip(dot(normalize(a), normalize(b)), -1.0f, 1.0f));
1999 }
2000 
2001 // angle between proper orthogonal matrices
2002 inline float angle_between(const mat < 3, 3 > & U, const mat < 3, 3 > & V) {
2003  return acos(0.5f * (tr(dot(U, transpose(V))) - 1.0f));
2004 }
2005 
2006 inline mat < 2, 2 > rotation(const float theta) {
2007  return mat< 2, 2 >{
2008  {cos(theta), -sin(theta)},
2009  { sin(theta), cos(theta) }
2010  };
2011 }
2012 
2013 inline mat < 3, 3 > axis_to_rotation(const vec < 3 > & omega) {
2014 
2015  float norm_omega = norm(omega);
2016 
2017  if (fabs(norm_omega) < 0.000001f) {
2018 
2019  return eye< 3 >();
2020 
2021  } else {
2022 
2023  vec3 u = omega / norm_omega;
2024 
2025  float c = cos(norm_omega);
2026  float s = sin(norm_omega);
2027 
2028  return mat < 3, 3 >{
2029  {
2030  u[0]*u[0]*(1.0f - c) + c,
2031  u[0]*u[1]*(1.0f - c) - u[2]*s,
2032  u[0]*u[2]*(1.0f - c) + u[1]*s
2033  },{
2034  u[1]*u[0]*(1.0f - c) + u[2]*s,
2035  u[1]*u[1]*(1.0f - c) + c,
2036  u[1]*u[2]*(1.0f - c) - u[0]*s
2037  },{
2038  u[2]*u[0]*(1.0f - c) - u[1]*s,
2039  u[2]*u[1]*(1.0f - c) + u[0]*s,
2040  u[2]*u[2]*(1.0f - c) + c
2041  }
2042  };
2043 
2044  }
2045 
2046 }
2047 
2048 // assumes R is a proper-orthogonal matrix
2049 inline vec < 3 > rotation_to_axis(const mat < 3, 3 > & R) {
2050 
2051  float theta = acos(clip(0.5f * (tr(R) - 1.0f), -1.0f, 1.0f));
2052 
2053  float scale;
2054 
2055  // for small angles, prefer series expansion to division by sin(theta) ~ 0
2056  if (fabs(theta) < 0.00001f) {
2057  scale = 0.5f + theta * theta / 12.0f;
2058  }
2059  else {
2060  scale = 0.5f * theta / sin(theta);
2061  }
2062 
2063  return vec3{ R(2,1) - R(1,2), R(0,2) - R(2,0), R(1,0) - R(0,1) } *scale;
2064 
2065 }
2066 
2067 inline mat < 3, 3 > look_at(const vec < 3 > & direction, const vec < 3 > & up = vec3{ 0.0f, 0.0f, 1.0f }) {
2068  vec3 f = normalize(direction);
2069  vec3 u = normalize(cross(f, cross(up, f)));
2070  vec3 l = normalize(cross(u, f));
2071 
2072  return mat3{
2073  {f[0], l[0], u[0]},
2074  {f[1], l[1], u[1]},
2075  {f[2], l[2], u[2]}
2076  };
2077 }
2078 
2079 inline mat < 2, 2 > look_at(const vec < 2 > & direction) {
2080  vec2 f = normalize(direction);
2081  vec2 l = cross(f);
2082 
2083  return mat2{
2084  {f[0], l[0]},
2085  {f[1], l[1]},
2086  };
2087 }
2088 
2089 inline mat < 3, 3 > R3_basis(const vec3 & n) {
2090  float sign = (n[2] >= 0.0f) ? 1.0f : -1.0f;
2091  float a = -1.0f / (sign + n[2]);
2092  float b = n[0] * n[1] * a;
2093 
2094  return mat < 3, 3 >{
2095  {
2096  1.0f + sign * n[0] * n[0] * a,
2097  b,
2098  n[0],
2099  },{
2100  sign * b,
2101  sign + n[1] * n[1] * a,
2102  n[1]
2103  },{
2104  -sign * n[0],
2105  -n[1],
2106  n[2]
2107  }
2108  };
2109 }
2110 #endif
2111 
2113 
2114 #include "serac/numerics/functional/tuple_tensor_dual_functions.hpp"
This file contains the interface used for initializing/terminating any hardware accelerator-related f...
#define SERAC_SUPPRESS_NVCC_HOSTDEVICE_WARNING
Macro to turn off specific nvcc warnings.
Definition: accelerator.hpp:50
#define SERAC_HOST_DEVICE
Macro that evaluates to __host__ __device__ when compiling with nvcc and does nothing on a host compi...
Definition: accelerator.hpp:38
Implementation of isotropic tensor classes.
Utilities for C++ metaprogramming.
constexpr SERAC_HOST_DEVICE void for_constexpr(const lambda &f)
multidimensional loop tool that evaluates the lambda body inside the innermost loop.
Accelerator functionality.
Definition: serac.cpp:36
constexpr SERAC_HOST_DEVICE auto inv(const tensor< T, n, n > &A)
Definition: tensor.hpp:1689
constexpr SERAC_HOST_DEVICE tensor< double, dim, dim > DenseIdentity()
Obtains the identity matrix of the specified dimension.
Definition: tensor.hpp:1254
typename detail::outer_prod< T1, T2 >::type outer_product_t
a type function that returns the tensor type of an outer product of two tensors
Definition: tensor.hpp:1824
constexpr SERAC_HOST_DEVICE tensor< T, n > diag(const tensor< T, n, n > &D)
Returns an array containing the diagonal entries of a square matrix.
Definition: tensor.hpp:1240
SERAC_HOST_DEVICE auto sin(dual< gradient_type > a)
implementation of sine for dual numbers
Definition: dual.hpp:324
constexpr SERAC_HOST_DEVICE auto operator-(const tensor< S, m, n... > &A, const tensor< T, m, n... > &B)
return the difference of two tensors
Definition: tensor.hpp:458
double relative_error(tensor< T, n... > A, tensor< T, n... > B)
computes the relative error (in the frobenius norm) between two tensors of the same shape
Definition: tensor.hpp:1473
constexpr SERAC_HOST_DEVICE auto dot(const isotropic_tensor< S, m, m > &I, const tensor< T, m, n... > &A)
dot product between an isotropic and (nonisotropic) tensor
SERAC_HOST_DEVICE bool is_symmetric(tensor< double, n, n > A, double tolerance=1.0e-8)
Return whether a square rank 2 tensor is symmetric.
Definition: tensor.hpp:1487
constexpr SERAC_HOST_DEVICE auto chop(const tensor< double, m, n > &A)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: tensor.hpp:1766
constexpr SERAC_HOST_DEVICE auto operator*(const dual< gradient_type > &a, double b)
multiplication of a dual number and a non-dual number
Definition: dual.hpp:108
tensor(const T(&data)[n1]) -> tensor< T, n1 >
class template argument deduction guide for type tensor.
SERAC_HOST_DEVICE auto cos(dual< gradient_type > a)
implementation of cosine for dual numbers
Definition: dual.hpp:316
Domain operator-(const Domain &a, const Domain &b)
create a new domain that is the set difference of a and b
Definition: domain.cpp:761
constexpr SERAC_HOST_DEVICE auto & operator+=(tensor< T, n... > &A, zero)
compound assignment (+) between a tensor and zero (no-op)
Definition: tensor.hpp:559
constexpr SERAC_HOST_DEVICE int size(zero)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: tensor.hpp:1946
constexpr SERAC_HOST_DEVICE int leading_dimension(tensor< T, m, n... >)
a function for querying the first dimension of a tensor
Definition: tensor.hpp:1972
constexpr T & get(variant< T0, T1 > &v)
Returns the variant member of specified type.
Definition: variant.hpp:338
constexpr SERAC_HOST_DEVICE auto dot(const tensor< S, m, n, p, q > &A, const tensor< T, q > &B)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: tensor.hpp:944
constexpr SERAC_HOST_DEVICE auto transpose(const tensor< T, m, n > &A)
Returns the transpose of the matrix.
Definition: tensor.hpp:1270
constexpr SERAC_HOST_DEVICE auto I2(const tensor< T, 3, 3 > &A)
Returns the second invariant of a 3x3 matrix.
Definition: tensor.hpp:1286
SERAC_HOST_DEVICE bool is_symmetric_and_positive_definite(tensor< double, 3, 3 > A)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: tensor.hpp:1521
SERAC_SUPPRESS_NVCC_HOSTDEVICE_WARNING constexpr SERAC_HOST_DEVICE auto make_tensor(lambda_type f)
Creates a tensor of requested dimension by subsequent calls to a functor Can be thought of as analogo...
Definition: tensor.hpp:299
constexpr SERAC_HOST_DEVICE auto get_gradient(const tensor< double, n... > &)
get the gradient of type tensor (note: since its stored type is not a dual number,...
Definition: tensor.hpp:1838
SERAC_HOST_DEVICE auto chain_rule(const tensor< double, m, n, p... > &df_dx, const tensor< double, p... > &dx)
Definition: tensor.hpp:1915
SERAC_HOST_DEVICE auto contract(const zero &, const T &)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: tensor.hpp:1458
constexpr SERAC_HOST_DEVICE auto linear_solve(const LuFactorization< T, n > &, const zero)
Definition: tensor.hpp:1637
SERAC_HOST_DEVICE auto sqrt(dual< gradient_type > x)
implementation of square root for dual numbers
Definition: dual.hpp:308
constexpr SERAC_HOST_DEVICE auto operator+(dual< gradient_type > a, double b)
addition of a dual number and a non-dual number
Definition: dual.hpp:59
constexpr SERAC_HOST_DEVICE auto det(const tensor< T, 3, 3 > &A)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: tensor.hpp:1304
constexpr SERAC_HOST_DEVICE auto dev(const tensor< T, n, n > &A)
Calculates the deviator of a matrix (rank-2 tensor)
Definition: tensor.hpp:1195
tensor< double, 2, 2 > mat2
statically sized 2x2 matrix of doubles
Definition: tensor.hpp:116
auto matrix_sqrt(const tensor< T, dim, dim > &A)
compute the matrix square root of a square, real-valued, symmetric matrix i.e. given A,...
Definition: tensor.hpp:1361
constexpr SERAC_HOST_DEVICE auto solve_upper_triangular(const tensor< T, n, n > &U, const tensor< T, n, m... > &y)
Solves an upper triangular system Ux = y.
Definition: tensor.hpp:1603
constexpr SERAC_HOST_DEVICE auto & operator-=(dual< gradient_type > &a, const dual< gradient_type > &b)
compound assignment (-) for dual numbers
Definition: dual.hpp:191
constexpr SERAC_HOST_DEVICE auto tensor_with_shape(std::integer_sequence< int, n... >)
Creates a tensor given the dimensions in a std::integer_sequence.
Definition: tensor.hpp:282
constexpr SERAC_HOST_DEVICE auto squared_norm(const tensor< T, n... > &A)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: tensor.hpp:1088
tensor< double, 3 > vec3
statically sized vector of 3 doubles
Definition: tensor.hpp:114
bool isnan(const zero &)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: tensor.hpp:1987
constexpr SERAC_HOST_DEVICE auto sym(const tensor< T, n, n > &A)
Returns the symmetric part of a square matrix.
Definition: tensor.hpp:1159
constexpr SERAC_HOST_DEVICE auto antisym(const tensor< T, n, n > &A)
Returns the antisymmetric part of a square matrix.
Definition: tensor.hpp:1176
SERAC_HOST_DEVICE auto abs(dual< gradient_type > x)
Implementation of absolute value function for dual numbers.
Definition: dual.hpp:219
constexpr SERAC_HOST_DEVICE auto inner(zero, double)
Definition: tensor.hpp:752
constexpr SERAC_HOST_DEVICE auto outer(const tensor< S, m > &A, const tensor< T, n > &B)
Definition: tensor.hpp:646
SERAC_HOST_DEVICE auto acos(dual< gradient_type > a)
implementation of acos for dual numbers
Definition: dual.hpp:373
constexpr SERAC_HOST_DEVICE int dimension(const tensor< T, n... > &)
a function for querying the ith dimension of a tensor
Definition: tensor.hpp:1957
auto & operator<<(std::ostream &out, zero)
Write a zero out to an output stream.
Definition: tensor.hpp:1719
constexpr auto double_dot(const tensor< S, m, n > &A, const tensor< T, m, n > &B)
Definition: tensor.hpp:1039
auto cross(const tensor< S, 3 > &u, const tensor< T, 3 > &v)
compute the (right handed) cross product of two 3-vectors
Definition: tensor.hpp:983
constexpr SERAC_HOST_DEVICE auto operator*(const tensor< S, m... > &A, const tensor< T, n... > &B)
this is a shorthand for dot(A, B)
Definition: tensor.hpp:1054
constexpr SERAC_HOST_DEVICE auto type(const tuple< T... > &values)
a function intended to be used for extracting the ith type from a tuple.
Definition: tuple.hpp:379
constexpr SERAC_HOST_DEVICE auto & operator-=(tensor< T, n... > &A, zero)
compound assignment (-) between a tensor and zero (no-op)
Definition: tensor.hpp:588
constexpr SERAC_HOST_DEVICE auto & operator+=(dual< gradient_type > &a, const dual< gradient_type > &b)
compound assignment (+) for dual numbers
Definition: dual.hpp:182
constexpr SERAC_HOST_DEVICE auto tr(const tensor< T, n, n > &A)
Returns the trace of a square matrix.
Definition: tensor.hpp:1144
SERAC_HOST_DEVICE auto normalize(const tensor< T, n... > &A)
Normalizes the tensor Each element is divided by the Frobenius norm of the tensor,...
Definition: tensor.hpp:1117
tensor< double, 2 > vec2
statically sized vector of 2 doubles
Definition: tensor.hpp:113
constexpr SERAC_HOST_DEVICE auto detApIm1(const tensor< T, 3, 3 > &A)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: tensor.hpp:1334
constexpr SERAC_HOST_DEVICE auto diagonal_matrix(const tensor< T, n, n > &A)
Returns a square matrix (rank-2 tensor) containing the diagonal entries of the input square matrix wi...
Definition: tensor.hpp:1212
tensor< double, 3, 3 > mat3
statically sized 3x3 matrix of doubles
Definition: tensor.hpp:117
tensor(const T(&data)[n1][n2]) -> tensor< T, n1, n2 >
class template argument deduction guide for type tensor.
SERAC_HOST_DEVICE void print(const tensor< double, m, n... > &A)
print a tensor using printf, so that it is suitable for use inside cuda kernels.
Definition: tensor.hpp:1737
SERAC_HOST_DEVICE tensor< T, 3, 3 > to_3x3(const tensor< T, 2, 2 > &A)
promotes a 2x2 matrix to a 3x3 matrix, by populating the upper left block, leaving zeroes in the thir...
Definition: tensor.hpp:1128
constexpr SERAC_HOST_DEVICE auto operator/(const dual< gradient_type > &a, double b)
division of a dual number by a non-dual number
Definition: dual.hpp:129
constexpr SERAC_HOST_DEVICE auto solve_lower_triangular(const tensor< T, n, n > &L, const tensor< T, n, m... > &b)
Definition: tensor.hpp:1582
std::conditional_t<(n1==1 &&n2==1), double, std::conditional_t< n1==1, tensor< T, n2 >, std::conditional_t< n2==1, tensor< T, n1 >, tensor< T, n1, n2 > >> > reduced_tensor
Removes 1s from tensor dimensions For example, a tensor<T, 1, 10> is equivalent to a tensor<T,...
Definition: tensor.hpp:274
constexpr SERAC_HOST_DEVICE auto norm(zero)
overload of Frobenius norm for zero type
Definition: tensor.hpp:1109
Representation of an LU factorization.
Definition: tensor.hpp:1542
tensor< T, n, n > U
Upper triangular factor.
Definition: tensor.hpp:1545
tensor< int, n > P
Row permutation indices due to partial pivoting.
Definition: tensor.hpp:1543
tensor< T, n, n > L
Lower triangular factor. Has ones on diagonal.
Definition: tensor.hpp:1544
checks if a type is zero
Definition: tensor.hpp:150
Arbitrary-rank tensor class.
Definition: tensor.hpp:28
A sentinel struct for eliding no-op tensor operations.
Definition: tensor.hpp:122
SERAC_HOST_DEVICE auto operator=(T)
anything assigned to zero does not change its value and returns zero
Definition: tensor.hpp:142
SERAC_HOST_DEVICE auto operator()(T...) const
zero can be accessed like a multidimensional array
Definition: tensor.hpp:135