Smith  0.1
Smith is an implicit thermal structural mechanics simulation code.
tensor.hpp
Go to the documentation of this file.
1 // Copyright (c) Lawrence Livermore National Security, LLC and
2 // other Smith 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 smith {
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  SMITH_HOST_DEVICE constexpr auto& operator()(i_type i)
35  {
36  return data[i];
37  }
38  template <typename i_type>
39  SMITH_HOST_DEVICE constexpr auto& operator()(i_type i) const
40  {
41  return data[i];
42  }
43  template <typename i_type, typename... jklm_type>
44  SMITH_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  SMITH_HOST_DEVICE constexpr auto& operator()(i_type i, jklm_type... jklm) const
50  {
51  return data[i](jklm...);
52  }
53 
54  SMITH_HOST_DEVICE constexpr auto& operator[](int i) { return data[i]; }
55  SMITH_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  SMITH_HOST_DEVICE constexpr auto& operator()(i_type i)
64  {
65  return data[i];
66  }
67  template <typename i_type>
68  SMITH_HOST_DEVICE constexpr auto& operator()(i_type i) const
69  {
70  return data[i];
71  }
72  SMITH_HOST_DEVICE constexpr auto& operator[](int i) { return data[i]; }
73  SMITH_HOST_DEVICE constexpr const auto& operator[](int i) const { return data[i]; }
74 
76  SMITH_HOST_DEVICE constexpr operator T()
77  {
78  return data[0];
79  }
80 
82  SMITH_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  SMITH_HOST_DEVICE operator double() { return 0.0; }
125 
127  template <typename T, int... n>
128  SMITH_HOST_DEVICE operator tensor<T, n...>()
129  {
130  return tensor<T, n...>{};
131  }
132 
134  template <typename... T>
135  SMITH_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 
153 template <>
154 struct is_zero<zero> : std::true_type {};
155 
157 SMITH_HOST_DEVICE constexpr auto operator+(zero, zero) { return zero{}; }
158 
160 template <typename T>
161 SMITH_HOST_DEVICE constexpr auto operator+(zero, T other)
162 {
163  return other;
164 }
165 
167 template <typename T>
168 SMITH_HOST_DEVICE constexpr auto operator+(T other, zero)
169 {
170  return other;
171 }
172 
174 
176 SMITH_HOST_DEVICE constexpr auto operator-(zero) { return zero{}; }
177 
179 SMITH_HOST_DEVICE constexpr auto operator-(zero, zero) { return zero{}; }
180 
182 template <typename T>
183 SMITH_HOST_DEVICE constexpr auto operator-(zero, T other)
184 {
185  return -other;
186 }
187 
189 template <typename T>
190 SMITH_HOST_DEVICE constexpr auto operator-(T other, zero)
191 {
192  return other;
193 }
194 
196 
198 SMITH_HOST_DEVICE constexpr auto operator*(zero, zero) { return zero{}; }
199 
201 template <typename T>
202 SMITH_HOST_DEVICE constexpr auto operator*(zero, T /*other*/)
203 {
204  return zero{};
205 }
206 
208 template <typename T>
209 SMITH_HOST_DEVICE constexpr auto operator*(T /*other*/, zero)
210 {
211  return zero{};
212 }
213 
215 template <typename T>
216 SMITH_HOST_DEVICE constexpr auto operator/(zero, T /*other*/)
217 {
218  return zero{};
219 }
220 
222 template <typename T>
223 void operator/(T, zero)
224 {
225  static_assert(::detail::always_false<T>{}, "Error: Can't divide by zero!");
226 }
227 
229 SMITH_HOST_DEVICE constexpr auto operator+=(zero, zero) { return zero{}; }
230 
232 SMITH_HOST_DEVICE constexpr auto operator-=(zero, zero) { return zero{}; }
233 
235 template <int i>
237 {
238  return x;
239 }
240 
242 template <int i>
244 {
245  return zero{};
246 }
247 
249 template <typename T>
250 SMITH_HOST_DEVICE constexpr zero dot(const T&, zero)
251 {
252  return zero{};
253 }
254 
256 template <typename T>
257 SMITH_HOST_DEVICE constexpr zero dot(zero, const T&)
258 {
259  return zero{};
260 }
261 
263 template <typename T, int m, int... n>
265 {
266  return m;
267 }
268 
276 template <typename T, int n1, int n2 = 1>
277 using reduced_tensor = std::conditional_t<
278  (n1 == 1 && n2 == 1), double,
279  std::conditional_t<n1 == 1, tensor<T, n2>, std::conditional_t<n2 == 1, tensor<T, n1>, tensor<T, n1, n2>>>>;
280 
286 template <typename T, int... n>
287 SMITH_HOST_DEVICE constexpr auto tensor_with_shape(std::integer_sequence<int, n...>)
288 {
289  return tensor<T, n...>{};
290 }
291 
303 template <typename lambda_type>
304 SMITH_HOST_DEVICE constexpr auto make_tensor(lambda_type f)
305 {
306  using T = decltype(f());
307  return tensor<T>{f()};
308 }
309 
322 template <int n1, typename lambda_type>
323 SMITH_HOST_DEVICE constexpr auto make_tensor(lambda_type f)
324 {
325  using T = decltype(f(n1));
326  tensor<T, n1> A{};
327  for (int i = 0; i < n1; i++) {
328  A(i) = f(i);
329  }
330  return A;
331 }
332 
346 template <int n1, int n2, typename lambda_type>
347 SMITH_HOST_DEVICE constexpr auto make_tensor(lambda_type f)
348 {
349  using T = decltype(f(n1, n2));
350  tensor<T, n1, n2> A{};
351  for (int i = 0; i < n1; i++) {
352  for (int j = 0; j < n2; j++) {
353  A(i, j) = f(i, j);
354  }
355  }
356  return A;
357 }
358 
373 template <int n1, int n2, int n3, typename lambda_type>
374 SMITH_HOST_DEVICE constexpr auto make_tensor(lambda_type f)
375 {
376  using T = decltype(f(n1, n2, n3));
378  for (int i = 0; i < n1; i++) {
379  for (int j = 0; j < n2; j++) {
380  for (int k = 0; k < n3; k++) {
381  A(i, j, k) = f(i, j, k);
382  }
383  }
384  }
385  return A;
386 }
387 
403 template <int n1, int n2, int n3, int n4, typename lambda_type>
404 SMITH_HOST_DEVICE constexpr auto make_tensor(lambda_type f)
405 {
406  using T = decltype(f(n1, n2, n3, n4));
408  for (int i = 0; i < n1; i++) {
409  for (int j = 0; j < n2; j++) {
410  for (int k = 0; k < n3; k++) {
411  for (int l = 0; l < n4; l++) {
412  A(i, j, k, l) = f(i, j, k, l);
413  }
414  }
415  }
416  }
417  return A;
418 }
419 
428 template <typename S, typename T, int m, int... n>
430 {
431  tensor<decltype(S{} + T{}), m, n...> C{};
432  for (int i = 0; i < m; i++) {
433  C[i] = A[i] + B[i];
434  }
435  return C;
436 }
437 
444 template <typename T, int m, int... n>
446 {
447  tensor<T, m, n...> B{};
448  for (int i = 0; i < m; i++) {
449  B[i] = -A[i];
450  }
451  return B;
452 }
453 
462 template <typename S, typename T, int m, int... n>
464 {
465  tensor<decltype(S{} + T{}), m, n...> C{};
466  for (int i = 0; i < m; i++) {
467  C[i] = A[i] - B[i];
468  }
469  return C;
470 }
471 
480 template <typename S, typename T, int m, int... n>
482 {
483  for (int i = 0; i < m; i++) {
484  A[i] += B[i];
485  }
486  return A;
487 }
488 
489 #if 0
496 template <typename T>
497 SMITH_HOST_DEVICE constexpr auto& operator+=(tensor<T>& A, const T& B)
498 {
499  return A.data += B;
500 }
501 #endif
502 
509 template <typename T, int n>
511 {
512  for (int i = 0; i < n; i++) {
513  A.data[i][0] += B[i];
514  }
515  return A;
516 }
517 
524 template <typename T, int n>
526 {
527  for (int i = 0; i < n; i++) {
528  A.data[0][i] += B[i];
529  }
530  return A;
531 }
532 
539 template <typename T>
540 SMITH_HOST_DEVICE constexpr auto& operator+=(tensor<T, 1>& A, const T& B)
541 {
542  return A.data[0] += B;
543 }
544 
551 template <typename T>
552 SMITH_HOST_DEVICE constexpr auto& operator+=(tensor<T, 1, 1>& A, const T& B)
553 {
554  return A.data[0][0] += B;
555 }
556 
563 template <typename T, int... n>
565 {
566  return A;
567 }
568 
577 template <typename S, typename T, int m, int... n>
579 {
580  for (int i = 0; i < m; i++) {
581  A[i] -= B[i];
582  }
583  return A;
584 }
585 
592 template <typename T, int... n>
594 {
595  return A;
596 }
597 
602 template <typename T, int n>
603 SMITH_HOST_DEVICE constexpr auto outer(double A, tensor<T, n> B)
604 {
605  tensor<decltype(double{} * T{}), n> AB{};
606  for (int i = 0; i < n; i++) {
607  AB[i] = A * B[i];
608  }
609  return AB;
610 }
611 
616 template <typename T, int m>
617 SMITH_HOST_DEVICE constexpr auto outer(const tensor<T, m>& A, double B)
618 {
619  tensor<decltype(T{} * double{}), m> AB{};
620  for (int i = 0; i < m; i++) {
621  AB[i] = A[i] * B;
622  }
623  return AB;
624 }
625 
630 template <typename T, int n>
631 SMITH_HOST_DEVICE constexpr auto outer(zero, const tensor<T, n>&)
632 {
633  return zero{};
634 }
635 
640 template <typename T, int n>
641 SMITH_HOST_DEVICE constexpr auto outer(const tensor<T, n>&, zero)
642 {
643  return zero{};
644 }
645 
650 template <typename S, typename T, int m, int n>
651 SMITH_HOST_DEVICE constexpr auto outer(const tensor<S, m>& A, const tensor<T, n>& B)
652 {
653  tensor<decltype(S{} * T{}), m, n> AB{};
654  for (int i = 0; i < m; i++) {
655  for (int j = 0; j < n; j++) {
656  AB[i][j] = A[i] * B[j];
657  }
658  }
659  return AB;
660 }
661 
671 template <typename S, typename T, int m, int n>
672 SMITH_HOST_DEVICE constexpr auto inner(const tensor<S, m, n>& A, const tensor<T, m, n>& B)
673 {
674  decltype(S{} * T{}) sum{};
675  for (int i = 0; i < m; i++) {
676  for (int j = 0; j < n; j++) {
677  sum += A[i][j] * B[i][j];
678  }
679  }
680  return sum;
681 }
682 
687 template <typename S, typename T, int m>
688 SMITH_HOST_DEVICE constexpr auto inner(const tensor<S, m>& A, const tensor<T, m>& B)
689 {
690  decltype(S{} * T{}) sum{};
691  for (int i = 0; i < m; i++) {
692  sum += A[i] * B[i];
693  }
694  return sum;
695 }
696 
701 SMITH_HOST_DEVICE constexpr auto inner(double A, double B) { return A * B; }
702 
709 template <typename S, int m, int n>
711 {
712  return zero{};
713 }
714 
719 template <typename S, int m>
720 SMITH_HOST_DEVICE constexpr auto inner(const tensor<S, m>&, zero)
721 {
722  return zero{};
723 }
724 
729 SMITH_HOST_DEVICE constexpr auto inner(double, zero) { return zero{}; }
730 
737 template <typename T, int m, int n>
739 {
740  return zero{};
741 }
742 
747 template <typename T, int m>
748 SMITH_HOST_DEVICE constexpr auto inner(zero, const tensor<T, m>&)
749 {
750  return zero{};
751 }
752 
757 SMITH_HOST_DEVICE constexpr auto inner(zero, double) { return zero{}; }
758 
767 template <typename S, typename T, int m, int n, int p>
768 SMITH_HOST_DEVICE constexpr auto dot(const tensor<S, m, n>& A, const tensor<T, n, p>& B)
769 {
770  tensor<decltype(S{} * T{}), m, p> AB{};
771  for (int i = 0; i < m; i++) {
772  for (int j = 0; j < p; j++) {
773  for (int k = 0; k < n; k++) {
774  AB[i][j] = AB[i][j] + A[i][k] * B[k][j];
775  }
776  }
777  }
778  return AB;
779 }
780 
785 template <typename T, int m>
786 SMITH_HOST_DEVICE constexpr auto dot(const tensor<T, m>& A, double B)
787 {
788  return A * B;
789 }
790 
795 template <typename T, int m>
796 SMITH_HOST_DEVICE constexpr auto dot(double B, const tensor<T, m>& A)
797 {
798  return B * A;
799 }
800 
805 template <typename S, typename T, int m>
806 SMITH_HOST_DEVICE constexpr auto dot(const tensor<S, m>& A, const tensor<T, m>& B)
807 {
808  decltype(S{} * T{}) AB{};
809  for (int i = 0; i < m; i++) {
810  AB = AB + A[i] * B[i];
811  }
812  return AB;
813 }
814 
819 template <typename S, typename T, int m, int n>
820 SMITH_HOST_DEVICE constexpr auto dot(const tensor<S, m>& A, const tensor<T, m, n>& B)
821 {
822  tensor<decltype(S{} * T{}), n> AB{};
823  for (int i = 0; i < n; i++) {
824  for (int j = 0; j < m; j++) {
825  AB[i] = AB[i] + A[j] * B[j][i];
826  }
827  }
828  return AB;
829 }
830 
835 template <typename S, typename T, int m, int n, int p>
836 SMITH_HOST_DEVICE constexpr auto dot(const tensor<S, m>& A, const tensor<T, m, n, p>& B)
837 {
838  tensor<decltype(S{} * T{}), n, p> AB{};
839  for (int j = 0; j < m; j++) {
840  AB = AB + A[j] * B[j];
841  }
842  return AB;
843 }
844 
855 template <typename S, typename T, int m, int n, int p, int q>
856 SMITH_HOST_DEVICE constexpr auto dot(const tensor<S, m>& A, const tensor<T, m, n, p, q>& B)
857 {
858  tensor<decltype(S{} * T{}), n, p, q> AB{};
859  for (int j = 0; j < m; j++) {
860  AB = AB + A[j] * B[j];
861  }
862  return AB;
863 }
864 
869 template <typename S, typename T, int m, int n>
870 SMITH_HOST_DEVICE constexpr auto dot(const tensor<S, m, n>& A, const tensor<T, n>& B)
871 {
872  tensor<decltype(S{} * T{}), m> AB{};
873  for (int i = 0; i < m; i++) {
874  for (int j = 0; j < n; j++) {
875  AB[i] = AB[i] + A[i][j] * B[j];
876  }
877  }
878  return AB;
879 }
880 
885 template <typename S, typename T, int m, int n, int p, int q, int r>
886 SMITH_HOST_DEVICE constexpr auto dot(const tensor<S, m, n>& A, const tensor<T, n, p, q, r>& B)
887 {
888  tensor<decltype(S{} * T{}), m, p, q, r> AB{};
889  for (int i = 0; i < m; i++) {
890  for (int j = 0; j < n; j++) {
891  AB[i] = AB[i] + A[i][j] * B[j];
892  }
893  }
894  return AB;
895 }
896 
901 template <typename S, typename T, int m, int n, int p, int q>
902 SMITH_HOST_DEVICE constexpr auto dot(const tensor<S, m, n>& A, const tensor<T, n, p, q>& B)
903 {
904  tensor<decltype(S{} * T{}), m, p, q> AB{};
905  for (int i = 0; i < m; i++) {
906  for (int j = 0; j < n; j++) {
907  AB[i] = AB[i] + A[i][j] * B[j];
908  }
909  }
910  return AB;
911 }
912 
917 template <typename S, typename T, int m, int n, int p>
918 SMITH_HOST_DEVICE constexpr auto dot(const tensor<S, m, n, p>& A, const tensor<T, p>& B)
919 {
920  tensor<decltype(S{} * T{}), m, n> AB{};
921  for (int i = 0; i < m; i++) {
922  for (int j = 0; j < n; j++) {
923  for (int k = 0; k < p; k++) {
924  AB[i][j] += A[i][j][k] * B[k];
925  }
926  }
927  }
928  return AB;
929 }
930 
935 template <typename S, typename T, typename U, int m, int n>
936 SMITH_HOST_DEVICE constexpr auto dot(const tensor<S, m>& u, const tensor<T, m, n>& A, const tensor<U, n>& v)
937 {
938  decltype(S{} * T{} * U{}) uAv{};
939  for (int i = 0; i < m; i++) {
940  for (int j = 0; j < n; j++) {
941  uAv += u[i] * A[i][j] * v[j];
942  }
943  }
944  return uAv;
945 }
946 
948 template <typename S, typename T, int m, int n, int p, int q>
949 SMITH_HOST_DEVICE constexpr auto dot(const tensor<S, m, n, p, q>& A, const tensor<T, q>& B)
950 {
951  tensor<decltype(S{} * T{}), m, n, p> AB{};
952  for (int i = 0; i < m; i++) {
953  for (int j = 0; j < n; j++) {
954  for (int k = 0; k < p; k++) {
955  for (int l = 0; l < q; l++) {
956  AB[i][j][k] += A[i][j][k][l] * B[l];
957  }
958  }
959  }
960  }
961  return AB;
962 }
963 
965 template <typename T>
967 {
968  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),
969  A(0, 0) * A(1, 1) - A(1, 0) * A(0, 1)};
970 }
971 
973 template <typename T>
975 {
976  return tensor<T, 2>{v(1, 0), -v(0, 0)};
977 }
978 
980 template <typename T>
982 {
983  return tensor<T, 2>{v[1], -v[0]};
984 }
985 
987 template <typename S, typename T>
989 {
990  return tensor<decltype(S{} * T{}), 3>{u(1) * v(2) - u(2) * v(1), u(2) * v(0) - u(0) * v(2),
991  u(0) * v(1) - u(1) * v(0)};
992 }
993 
1005 template <typename S, typename T, int m, int n, int p, int q>
1007 {
1008  tensor<decltype(S{} * T{}), m, n> AB{};
1009  for (int i = 0; i < m; i++) {
1010  for (int j = 0; j < n; j++) {
1011  for (int k = 0; k < p; k++) {
1012  for (int l = 0; l < q; l++) {
1013  AB[i][j] += A[i][j][k][l] * B[k][l];
1014  }
1015  }
1016  }
1017  }
1018  return AB;
1019 }
1020 
1025 template <typename S, typename T, int m, int n, int p>
1027 {
1028  tensor<decltype(S{} * T{}), m> AB{};
1029  for (int i = 0; i < m; i++) {
1030  for (int j = 0; j < n; j++) {
1031  for (int k = 0; k < p; k++) {
1032  AB[i] += A[i][j][k] * B[j][k];
1033  }
1034  }
1035  }
1036  return AB;
1037 }
1038 
1043 template <typename S, typename T, int m, int n>
1044 constexpr auto double_dot(const tensor<S, m, n>& A, const tensor<T, m, n>& B)
1045 {
1046  decltype(S{} * T{}) AB{};
1047  for (int i = 0; i < m; i++) {
1048  for (int j = 0; j < n; j++) {
1049  AB += A[i][j] * B[i][j];
1050  }
1051  }
1052  return AB;
1053 }
1054 
1058 template <typename S, typename T, int... m, int... n>
1060 {
1061  return dot(A, B);
1062 }
1063 
1068 template <typename T, int m>
1070 {
1071  T total{};
1072  for (int i = 0; i < m; i++) {
1073  total += A[i] * A[i];
1074  }
1075  return total;
1076 }
1077 
1079 template <typename T, int m, int n>
1081 {
1082  T total{};
1083  for (int i = 0; i < m; i++) {
1084  for (int j = 0; j < n; j++) {
1085  total += A[i][j] * A[i][j];
1086  }
1087  }
1088  return total;
1089 }
1090 
1092 template <typename T, int... n>
1094 {
1095  T total{};
1096  for_constexpr<n...>([&](auto... i) { total += A(i...) * A(i...); });
1097  return total;
1098 }
1099 
1104 template <typename T, int... n>
1106 {
1107  using std::sqrt;
1108  return sqrt(squared_norm(A));
1109 }
1110 
1114 SMITH_HOST_DEVICE constexpr auto norm(zero) { return zero{}; }
1115 
1121 template <typename T, int... n>
1123 {
1124  return A / norm(A);
1125 }
1126 
1132 template <typename T>
1134 {
1135  tensor<T, 3, 3> output{};
1136  output[0][0] = A[0][0];
1137  output[0][1] = A[0][1];
1138  output[1][0] = A[1][0];
1139  output[1][1] = A[1][1];
1140  return output;
1141 }
1142 
1148 template <typename T, int n>
1149 SMITH_HOST_DEVICE constexpr auto tr(const tensor<T, n, n>& A)
1150 {
1151  T trA{};
1152  for (int i = 0; i < n; i++) {
1153  trA = trA + A[i][i];
1154  }
1155  return trA;
1156 }
1157 
1163 template <typename T, int n>
1164 SMITH_HOST_DEVICE constexpr auto sym(const tensor<T, n, n>& A)
1165 {
1166  tensor<T, n, n> symA{};
1167  for (int i = 0; i < n; i++) {
1168  for (int j = 0; j < n; j++) {
1169  symA[i][j] = 0.5 * (A[i][j] + A[j][i]);
1170  }
1171  }
1172  return symA;
1173 }
1174 
1180 template <typename T, int n>
1182 {
1183  tensor<T, n, n> antisymA{};
1184  for (int i = 0; i < n; i++) {
1185  for (int j = 0; j < n; j++) {
1186  antisymA[i][j] = 0.5 * (A[i][j] - A[j][i]);
1187  }
1188  }
1189  return antisymA;
1190 }
1191 
1199 template <typename T, int n>
1200 SMITH_HOST_DEVICE constexpr auto dev(const tensor<T, n, n>& A)
1201 {
1202  auto devA = A;
1203  auto trA = tr(A);
1204  for (int i = 0; i < n; i++) {
1205  devA[i][i] -= trA / n;
1206  }
1207  return devA;
1208 }
1209 
1216 template <typename T, int n>
1218 {
1219  tensor<T, n, n> D{};
1220  for (int i = 0; i < n; i++) {
1221  D[i][i] = A[i][i];
1222  }
1223  return D;
1224 }
1225 
1230 template <typename T, int n>
1232 {
1233  tensor<T, n, n> D{};
1234  for (int i = 0; i < n; i++) {
1235  D[i][i] = d[i];
1236  }
1237  return D;
1238 }
1239 
1244 template <typename T, int n>
1246 {
1247  tensor<T, n> d{};
1248  for (int i = 0; i < n; i++) {
1249  d[i] = D[i][i];
1250  }
1251  return d;
1252 }
1253 
1258 template <int dim>
1260 {
1262  for (int i = 0; i < dim; i++) {
1263  for (int j = 0; j < dim; j++) {
1264  I[i][j] = (i == j);
1265  }
1266  }
1267  return I;
1268 }
1269 
1274 template <typename T, int m, int n>
1276 {
1277  tensor<T, n, m> AT{};
1278  for (int i = 0; i < n; i++) {
1279  for (int j = 0; j < m; j++) {
1280  AT[i][j] = A[j][i];
1281  }
1282  }
1283  return AT;
1284 }
1285 
1290 template <typename T>
1291 SMITH_HOST_DEVICE constexpr auto I2(const tensor<T, 3, 3>& A)
1292 {
1293  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] -
1294  A[2][0] * A[0][2];
1295 }
1296 
1301 template <typename T>
1302 SMITH_HOST_DEVICE constexpr auto det(const tensor<T, 2, 2>& A)
1303 {
1304  return A[0][0] * A[1][1] - A[0][1] * A[1][0];
1305 }
1306 
1308 template <typename T>
1309 SMITH_HOST_DEVICE constexpr auto det(const tensor<T, 3, 3>& A)
1310 {
1311  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] -
1312  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];
1313 }
1314 
1325 template <typename T>
1327 {
1328  // From the Cayley-Hamilton theorem, we get that for any N by N matrix A,
1329  // det(A - I) - 1 = I1(A) + I2(A) + ... + IN(A),
1330  // where the In are the principal invariants of A.
1331  // We inline the definitions of the principal invariants to increase computational speed.
1332 
1333  // equivalent to tr(A) + det(A)
1334  return A(0, 0) - A(0, 1) * A(1, 0) + A(1, 1) + A(0, 0) * A(1, 1);
1335 }
1336 
1338 template <typename T>
1340 {
1341  // For notes on the implementation, see the 2x2 version.
1342 
1343  // clang-format off
1344  // equivalent to tr(A) + I2(A) + det(A)
1345  return A(0, 0) + A(1, 1) + A(2, 2)
1346  - A(0, 1) * A(1, 0) * (1 + A(2, 2))
1347  + A(0, 0) * A(1, 1) * (1 + A(2, 2))
1348  - A(0, 2) * A(2, 0) * (1 + A(1, 1))
1349  - A(1, 2) * A(2, 1) * (1 + A(0, 0))
1350  + A(0, 0) * A(2, 2)
1351  + A(1, 1) * A(2, 2)
1352  + A(0, 1) * A(1, 2) * A(2, 0)
1353  + A(0, 2) * A(1, 0) * A(2, 1);
1354  // clang-format on
1355 }
1356 
1365 template <typename T, int dim>
1367 {
1368  auto B = A;
1369  for (int i = 0; i < 15; i++) {
1370  B = 0.5 * (B + dot(A, inv(B)));
1371  }
1372  return B;
1373 }
1374 
1404 template <int i1, int i2, typename S, int m, int... n, typename T, int p, int q>
1406 {
1407  constexpr int Adims[] = {m, n...};
1408  constexpr int Bdims[] = {p, q};
1409  static_assert(sizeof...(n) < 3);
1410  static_assert(Adims[i1] == Bdims[i2], "error: incompatible tensor dimensions");
1411 
1412  // first, we have to figure out the dimensions of the output tensor
1413  constexpr int new_dim = (i2 == 0) ? q : p;
1414  constexpr int d1 = (i1 == 0) ? new_dim : Adims[0];
1415  constexpr int d2 = (i1 == 1) ? new_dim : Adims[1];
1416  constexpr int d3 = sizeof...(n) == 1 ? 0 : ((i1 == 2) ? new_dim : Adims[2]);
1417 
1418  // the type of the output tensor is easier to figure out
1419  using U = decltype(S{} * T{});
1420 
1421  auto C = []() {
1422  if constexpr (d3 == 0) return tensor<U, d1, d2>{};
1423  if constexpr (d3 != 0) return tensor<U, d1, d2, d3>{};
1424  }();
1425 
1426  if constexpr (d3 == 0) {
1427  for (int i = 0; i < d1; i++) {
1428  for (int j = 0; j < d2; j++) {
1429  U sum{};
1430  for (int k = 0; k < Adims[i1]; k++) {
1431  if constexpr (i1 == 0 && i2 == 0) sum += A(k, j) * B(k, i);
1432  if constexpr (i1 == 1 && i2 == 0) sum += A(i, k) * B(k, j);
1433  if constexpr (i1 == 0 && i2 == 1) sum += A(k, j) * B(i, k);
1434  if constexpr (i1 == 1 && i2 == 1) sum += A(i, k) * B(j, k);
1435  }
1436  C(i, j) = sum;
1437  }
1438  }
1439  } else {
1440  for (int i = 0; i < d1; i++) {
1441  for (int j = 0; j < d2; j++) {
1442  for (int k = 0; k < d3; k++) {
1443  U sum{};
1444  for (int l = 0; l < Adims[i1]; l++) {
1445  if constexpr (i1 == 0 && i2 == 0) sum += A(l, j, k) * B(l, i);
1446  if constexpr (i1 == 1 && i2 == 0) sum += A(i, l, k) * B(l, j);
1447  if constexpr (i1 == 2 && i2 == 0) sum += A(i, j, l) * B(l, k);
1448  if constexpr (i1 == 0 && i2 == 1) sum += A(l, j, k) * B(i, l);
1449  if constexpr (i1 == 1 && i2 == 1) sum += A(i, l, k) * B(j, l);
1450  if constexpr (i1 == 2 && i2 == 1) sum += A(i, j, l) * B(k, l);
1451  }
1452  C(i, j, k) = sum;
1453  }
1454  }
1455  }
1456  }
1457 
1458  return C;
1459 }
1460 
1462 template <int i1, int i2, typename T>
1463 SMITH_HOST_DEVICE auto contract(const zero&, const T&)
1464 {
1465  return zero{};
1466 }
1467 
1477 template <typename T, int... n>
1479 {
1480  return norm(A - B) / norm(A);
1481 }
1482 
1491 template <int n>
1492 SMITH_HOST_DEVICE bool is_symmetric(tensor<double, n, n> A, double tolerance = 1.0e-8)
1493 {
1494  for (int i = 0; i < n; ++i) {
1495  for (int j = i + 1; j < n; ++j) {
1496  if (std::abs(A(i, j) - A(j, i)) > tolerance) {
1497  return false;
1498  };
1499  }
1500  }
1501  return true;
1502 }
1503 
1513 {
1514  if (!is_symmetric(A)) {
1515  return false;
1516  }
1517  if (A(0, 0) < 0.0) {
1518  return false;
1519  }
1520  if (det(A) < 0.0) {
1521  return false;
1522  }
1523  return true;
1524 }
1527 {
1528  if (!is_symmetric(A)) {
1529  return false;
1530  }
1531  if (det(A) < 0.0) {
1532  return false;
1533  }
1534  auto subtensor = make_tensor<2, 2>([A](int i, int j) { return A(i, j); });
1535  if (!is_symmetric_and_positive_definite(subtensor)) {
1536  return false;
1537  }
1538  return true;
1539 }
1540 
1546 template <typename T, int n>
1551 };
1552 
1567 template <typename T, int n, int... m>
1569  const tensor<int, n>& P)
1570 {
1571  tensor<T, n, m...> y{};
1572  for (int i = 0; i < n; i++) {
1573  auto c = b[P[i]];
1574  for (int j = 0; j < i; j++) {
1575  c -= L[i][j] * y[j];
1576  }
1577  y[i] = c / L[i][i];
1578  }
1579  return y;
1580 }
1581 
1586 template <typename T, int n, int... m>
1588 {
1589  // no permutation provided, so just map each equation to itself
1590  // TODO make a convienience function for ranges like this
1591  // BT 05/09/2022
1592  tensor<int, n> P(make_tensor<n>([](auto i) { return i; }));
1593 
1594  return solve_lower_triangular(L, b, P);
1595 }
1596 
1607 template <typename T, int n, int... m>
1609 {
1610  tensor<T, n, m...> x{};
1611  for (int i = n - 1; i >= 0; i--) {
1612  auto c = y[i];
1613  for (int j = i + 1; j < n; j++) {
1614  c -= U[i][j] * x[j];
1615  }
1616  x[i] = c / U[i][i];
1617  }
1618  return x;
1619 }
1620 
1625 template <typename S, typename T, int n, int... m>
1626 SMITH_HOST_DEVICE constexpr auto linear_solve(const LuFactorization<S, n>& lu_factors, const tensor<T, n, m...>& b)
1627 {
1628  // Forward substitution
1629  // solve Ly = b
1630  const auto y = solve_lower_triangular(lu_factors.L, b, lu_factors.P);
1631 
1632  // Back substitution
1633  // Solve Ux = y
1634  return solve_upper_triangular(lu_factors.U, y);
1635 }
1636 
1641 template <typename T, int n>
1642 SMITH_HOST_DEVICE constexpr auto linear_solve(const LuFactorization<T, n>& /* lu_factors */, const zero /* b */)
1643 {
1644  return zero{};
1645 }
1646 
1653 {
1654  double inv_detA(1.0 / det(A));
1655 
1656  tensor<double, 2, 2> invA{};
1657 
1658  invA[0][0] = A[1][1] * inv_detA;
1659  invA[0][1] = -A[0][1] * inv_detA;
1660  invA[1][0] = -A[1][0] * inv_detA;
1661  invA[1][1] = A[0][0] * inv_detA;
1662 
1663  return invA;
1664 }
1665 
1671 {
1672  double inv_detA(1.0 / det(A));
1673 
1674  tensor<double, 3, 3> invA{};
1675 
1676  invA[0][0] = (A[1][1] * A[2][2] - A[1][2] * A[2][1]) * inv_detA;
1677  invA[0][1] = (A[0][2] * A[2][1] - A[0][1] * A[2][2]) * inv_detA;
1678  invA[0][2] = (A[0][1] * A[1][2] - A[0][2] * A[1][1]) * inv_detA;
1679  invA[1][0] = (A[1][2] * A[2][0] - A[1][0] * A[2][2]) * inv_detA;
1680  invA[1][1] = (A[0][0] * A[2][2] - A[0][2] * A[2][0]) * inv_detA;
1681  invA[1][2] = (A[0][2] * A[1][0] - A[0][0] * A[1][2]) * inv_detA;
1682  invA[2][0] = (A[1][0] * A[2][1] - A[1][1] * A[2][0]) * inv_detA;
1683  invA[2][1] = (A[0][1] * A[2][0] - A[0][0] * A[2][1]) * inv_detA;
1684  invA[2][2] = (A[0][0] * A[1][1] - A[0][1] * A[1][0]) * inv_detA;
1685 
1686  return invA;
1687 }
1693 template <typename T, int n>
1694 SMITH_HOST_DEVICE constexpr auto inv(const tensor<T, n, n>& A)
1695 {
1696  auto I = DenseIdentity<n>();
1697  return linear_solve(A, I);
1698 }
1699 
1708 template <typename T, int m, int... n>
1709 auto& operator<<(std::ostream& out, const tensor<T, m, n...>& A)
1710 {
1711  out << '{' << A[0];
1712  for (int i = 1; i < m; i++) {
1713  out << ", " << A[i];
1714  }
1715  out << '}';
1716  return out;
1717 }
1718 
1724 inline auto& operator<<(std::ostream& out, zero)
1725 {
1726  out << "zero";
1727  return out;
1728 }
1729 
1735 inline SMITH_HOST_DEVICE void print(double value) { printf("%f", value); }
1736 
1741 template <int m, int... n>
1743 {
1744  printf("{");
1745  print(A[0]);
1746  for (int i = 1; i < m; i++) {
1747  printf(",");
1748  print(A[i]);
1749  }
1750  printf("}");
1751 }
1752 
1757 template <int n>
1758 SMITH_HOST_DEVICE constexpr auto chop(const tensor<double, n>& A)
1759 {
1760  auto copy = A;
1761  for (int i = 0; i < n; i++) {
1762  if (copy[i] * copy[i] < 1.0e-20) {
1763  copy[i] = 0.0;
1764  }
1765  }
1766  return copy;
1767 }
1768 
1770 template <int m, int n>
1772 {
1773  auto copy = A;
1774  for (int i = 0; i < m; i++) {
1775  for (int j = 0; j < n; j++) {
1776  if (copy[i][j] * copy[i][j] < 1.0e-20) {
1777  copy[i][j] = 0.0;
1778  }
1779  }
1780  }
1781  return copy;
1782 }
1783 
1785 namespace detail {
1786 
1787 template <typename T1, typename T2>
1788 struct outer_prod;
1789 
1790 template <int... m, int... n>
1791 struct outer_prod<tensor<double, m...>, tensor<double, n...>> {
1792  using type = tensor<double, m..., n...>;
1793 };
1794 
1795 template <int... n>
1796 struct outer_prod<double, tensor<double, n...>> {
1797  using type = tensor<double, n...>;
1798 };
1799 
1800 template <int... n>
1801 struct outer_prod<tensor<double, n...>, double> {
1802  using type = tensor<double, n...>;
1803 };
1804 
1805 template <>
1806 struct outer_prod<double, double> {
1807  using type = tensor<double>;
1808 };
1809 
1810 template <typename T>
1811 struct outer_prod<zero, T> {
1812  using type = zero;
1813 };
1814 
1815 template <typename T>
1816 struct outer_prod<T, zero> {
1817  using type = zero;
1818 };
1819 
1820 } // namespace detail
1822 
1828 template <typename T1, typename T2>
1830 
1835 inline SMITH_HOST_DEVICE auto get_gradient(double /* arg */) { return zero{}; }
1836 
1842 template <int... n>
1843 SMITH_HOST_DEVICE constexpr auto get_gradient(const tensor<double, n...>& /* arg */)
1844 {
1845  return zero{};
1846 }
1847 
1851 SMITH_HOST_DEVICE constexpr auto chain_rule(const zero /* df_dx */, const zero /* dx */) { return zero{}; }
1852 
1857 template <typename T>
1858 SMITH_HOST_DEVICE constexpr auto chain_rule(const zero /* df_dx */, const T /* dx */)
1859 {
1860  return zero{};
1861 }
1862 
1867 template <typename T>
1868 SMITH_HOST_DEVICE constexpr auto chain_rule(const T /* df_dx */, const zero /* dx */)
1869 {
1870  return zero{};
1871 }
1872 
1877 SMITH_HOST_DEVICE constexpr auto chain_rule(const double df_dx, const double dx) { return df_dx * dx; }
1878 
1883 template <int... n>
1884 SMITH_HOST_DEVICE constexpr auto chain_rule(const tensor<double, n...>& df_dx, const double dx)
1885 {
1886  return df_dx * dx;
1887 }
1888 
1893 template <int... n>
1895 {
1896  double total{};
1897  for_constexpr<n...>([&](auto... i) { total += df_dx(i...) * dx(i...); });
1898  return total;
1899 }
1900 
1905 template <int m, int... n>
1907 {
1908  tensor<double, m> total{};
1909  for (int i = 0; i < m; i++) {
1910  total[i] = chain_rule(df_dx[i], dx);
1911  }
1912  return total;
1913 }
1914 
1919 template <int m, int n, int... p>
1921 {
1922  tensor<double, m, n> total{};
1923  for (int i = 0; i < m; i++) {
1924  for (int j = 0; j < n; j++) {
1925  total[i][j] = chain_rule(df_dx[i][j], dx);
1926  }
1927  }
1928  return total;
1929 }
1930 
1938 template <typename T, int... n>
1940 {
1941  return (n * ... * 1);
1942 }
1943 
1948 SMITH_HOST_DEVICE constexpr int size(const double&) { return 1; }
1949 
1951 SMITH_HOST_DEVICE constexpr int size(zero) { return 0; }
1952 
1961 template <int i, typename T, int... n>
1963 {
1964  constexpr int dimensions[] = {n...};
1965  return dimensions[i];
1966 }
1967 
1976 template <typename T, int m, int... n>
1978 {
1979  return m;
1980 }
1981 
1983 template <typename T, int... n>
1984 bool isnan(const tensor<T, n...>& A)
1985 {
1986  bool found_nan = false;
1987  for_constexpr<n...>([&](auto... i) { found_nan |= std::isnan(A(i...)); });
1988  return found_nan;
1989 }
1990 
1992 inline bool isnan(const zero&) { return false; }
1993 
1994 } // namespace smith
1995 
1996 #if 0
1997 
1998 inline float angle_between(const vec < 2 > & a, const vec < 2 > & b) {
1999  return acos(clip(dot(normalize(a), normalize(b)), -1.0f, 1.0f));
2000 }
2001 
2002 inline float angle_between(const vec < 3 > & a, const vec < 3 > & b) {
2003  return acos(clip(dot(normalize(a), normalize(b)), -1.0f, 1.0f));
2004 }
2005 
2006 // angle between proper orthogonal matrices
2007 inline float angle_between(const mat < 3, 3 > & U, const mat < 3, 3 > & V) {
2008  return acos(0.5f * (tr(dot(U, transpose(V))) - 1.0f));
2009 }
2010 
2011 inline mat < 2, 2 > rotation(const float theta) {
2012  return mat< 2, 2 >{
2013  {cos(theta), -sin(theta)},
2014  { sin(theta), cos(theta) }
2015  };
2016 }
2017 
2018 inline mat < 3, 3 > axis_to_rotation(const vec < 3 > & omega) {
2019 
2020  float norm_omega = norm(omega);
2021 
2022  if (fabs(norm_omega) < 0.000001f) {
2023 
2024  return eye< 3 >();
2025 
2026  } else {
2027 
2028  vec3 u = omega / norm_omega;
2029 
2030  float c = cos(norm_omega);
2031  float s = sin(norm_omega);
2032 
2033  return mat < 3, 3 >{
2034  {
2035  u[0]*u[0]*(1.0f - c) + c,
2036  u[0]*u[1]*(1.0f - c) - u[2]*s,
2037  u[0]*u[2]*(1.0f - c) + u[1]*s
2038  },{
2039  u[1]*u[0]*(1.0f - c) + u[2]*s,
2040  u[1]*u[1]*(1.0f - c) + c,
2041  u[1]*u[2]*(1.0f - c) - u[0]*s
2042  },{
2043  u[2]*u[0]*(1.0f - c) - u[1]*s,
2044  u[2]*u[1]*(1.0f - c) + u[0]*s,
2045  u[2]*u[2]*(1.0f - c) + c
2046  }
2047  };
2048 
2049  }
2050 
2051 }
2052 
2053 // assumes R is a proper-orthogonal matrix
2054 inline vec < 3 > rotation_to_axis(const mat < 3, 3 > & R) {
2055 
2056  float theta = acos(clip(0.5f * (tr(R) - 1.0f), -1.0f, 1.0f));
2057 
2058  float scale;
2059 
2060  // for small angles, prefer series expansion to division by sin(theta) ~ 0
2061  if (fabs(theta) < 0.00001f) {
2062  scale = 0.5f + theta * theta / 12.0f;
2063  }
2064  else {
2065  scale = 0.5f * theta / sin(theta);
2066  }
2067 
2068  return vec3{ R(2,1) - R(1,2), R(0,2) - R(2,0), R(1,0) - R(0,1) } *scale;
2069 
2070 }
2071 
2072 inline mat < 3, 3 > look_at(const vec < 3 > & direction, const vec < 3 > & up = vec3{ 0.0f, 0.0f, 1.0f }) {
2073  vec3 f = normalize(direction);
2074  vec3 u = normalize(cross(f, cross(up, f)));
2075  vec3 l = normalize(cross(u, f));
2076 
2077  return mat3{
2078  {f[0], l[0], u[0]},
2079  {f[1], l[1], u[1]},
2080  {f[2], l[2], u[2]}
2081  };
2082 }
2083 
2084 inline mat < 2, 2 > look_at(const vec < 2 > & direction) {
2085  vec2 f = normalize(direction);
2086  vec2 l = cross(f);
2087 
2088  return mat2{
2089  {f[0], l[0]},
2090  {f[1], l[1]},
2091  };
2092 }
2093 
2094 inline mat < 3, 3 > R3_basis(const vec3 & n) {
2095  float sign = (n[2] >= 0.0f) ? 1.0f : -1.0f;
2096  float a = -1.0f / (sign + n[2]);
2097  float b = n[0] * n[1] * a;
2098 
2099  return mat < 3, 3 >{
2100  {
2101  1.0f + sign * n[0] * n[0] * a,
2102  b,
2103  n[0],
2104  },{
2105  sign * b,
2106  sign + n[1] * n[1] * a,
2107  n[1]
2108  },{
2109  -sign * n[0],
2110  -n[1],
2111  n[2]
2112  }
2113  };
2114 }
2115 #endif
2116 
2118 
2119 #include "smith/numerics/functional/tuple_tensor_dual_functions.hpp"
This file contains the interface used for initializing/terminating any hardware accelerator-related f...
#define SMITH_SUPPRESS_NVCC_HOSTDEVICE_WARNING
Macro to turn off specific nvcc warnings.
Definition: accelerator.hpp:65
#define SMITH_HOST_DEVICE
Macro that evaluates to __host__ __device__ when compiling with nvcc or amdclang and does nothing on ...
Definition: accelerator.hpp:37
Implementation of isotropic tensor classes.
Utilities for C++ metaprogramming.
constexpr SMITH_HOST_DEVICE void for_constexpr(const lambda &f)
multidimensional loop tool that evaluates the lambda body inside the innermost loop.
Accelerator functionality.
Definition: smith.cpp:36
SMITH_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:1492
SMITH_HOST_DEVICE auto acos(dual< gradient_type > a)
implementation of acos for dual numbers
Definition: dual.hpp:373
SMITH_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:1526
constexpr SMITH_HOST_DEVICE auto antisym(const tensor< T, n, n > &A)
Returns the antisymmetric part of a square matrix.
Definition: tensor.hpp:1181
constexpr SMITH_HOST_DEVICE auto & operator+=(dual< gradient_type > &a, const dual< gradient_type > &b)
compound assignment (+) for dual numbers
Definition: dual.hpp:182
constexpr SMITH_HOST_DEVICE auto & operator-=(tensor< T, n... > &A, zero)
compound assignment (-) between a tensor and zero (no-op)
Definition: tensor.hpp:593
SMITH_SUPPRESS_NVCC_HOSTDEVICE_WARNING constexpr SMITH_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:304
constexpr T & get(variant< T0, T1 > &v)
Returns the variant member of specified type.
Definition: variant.hpp:338
constexpr SMITH_HOST_DEVICE int size(zero)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: tensor.hpp:1951
constexpr SMITH_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:1309
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:1478
constexpr SMITH_HOST_DEVICE int leading_dimension(tensor< T, m, n... >)
a function for querying the first dimension of a tensor
Definition: tensor.hpp:1977
constexpr SMITH_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:1843
constexpr SMITH_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:1059
SMITH_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:1463
FieldStateWeightedSum operator+(const FieldState &x, const FieldState &y)
add two FieldState
SMITH_HOST_DEVICE 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:988
SMITH_HOST_DEVICE auto chain_rule(const tensor< double, m, n, p... > &df_dx, const tensor< double, p... > &dx)
Definition: tensor.hpp:1920
constexpr SMITH_HOST_DEVICE auto I2(const tensor< T, 3, 3 > &A)
Returns the second invariant of a 3x3 matrix.
Definition: tensor.hpp:1291
SMITH_HOST_DEVICE auto sqrt(dual< gradient_type > x)
implementation of square root for dual numbers
Definition: dual.hpp:308
constexpr SMITH_HOST_DEVICE auto inner(zero, double)
Definition: tensor.hpp:757
constexpr SMITH_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:376
constexpr SMITH_HOST_DEVICE auto solve_lower_triangular(const tensor< T, n, n > &L, const tensor< T, n, m... > &b)
Definition: tensor.hpp:1587
constexpr SMITH_HOST_DEVICE auto norm(zero)
overload of Frobenius norm for zero type
Definition: tensor.hpp:1114
constexpr SMITH_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:1093
tensor< double, 3 > vec3
statically sized vector of 3 doubles
Definition: tensor.hpp:114
auto & operator<<(std::ostream &out, zero)
Write a zero out to an output stream.
Definition: tensor.hpp:1724
SMITH_HOST_DEVICE auto cos(dual< gradient_type > a)
implementation of cosine for dual numbers
Definition: dual.hpp:316
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:279
constexpr SMITH_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:1771
constexpr SMITH_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:1245
bool isnan(const zero &)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: tensor.hpp:1992
tensor(const T(&data)[n1]) -> tensor< T, n1 >
class template argument deduction guide for type tensor.
constexpr auto double_dot(const tensor< S, m, n > &A, const tensor< T, m, n > &B)
Definition: tensor.hpp:1044
constexpr SMITH_HOST_DEVICE auto inv(const tensor< T, n, n > &A)
Definition: tensor.hpp:1694
constexpr SMITH_HOST_DEVICE auto dev(const tensor< T, n, n > &A)
Calculates the deviator of a matrix (rank-2 tensor)
Definition: tensor.hpp:1200
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:1366
SMITH_HOST_DEVICE auto abs(dual< gradient_type > x)
Implementation of absolute value function for dual numbers.
Definition: dual.hpp:219
tensor(const T(&data)[n1][n2]) -> tensor< T, n1, n2 >
class template argument deduction guide for type tensor.
SMITH_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:1133
SMITH_HOST_DEVICE consteval int first_dim(const tensor< T, m, n... > &)
return the size of the leftmost tensor dimension
Definition: tensor.hpp:264
SMITH_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:1742
constexpr SMITH_HOST_DEVICE auto sym(const tensor< T, n, n > &A)
Returns the symmetric part of a square matrix.
Definition: tensor.hpp:1164
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:1829
constexpr SMITH_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:287
constexpr SMITH_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:949
constexpr SMITH_HOST_DEVICE auto outer(const tensor< S, m > &A, const tensor< T, n > &B)
Definition: tensor.hpp:651
constexpr SMITH_HOST_DEVICE auto & operator+=(tensor< T, n... > &A, zero)
compound assignment (+) between a tensor and zero (no-op)
Definition: tensor.hpp:564
constexpr SMITH_HOST_DEVICE auto linear_solve(const LuFactorization< T, n > &, const zero)
Definition: tensor.hpp:1642
tensor< double, 2 > vec2
statically sized vector of 2 doubles
Definition: tensor.hpp:113
constexpr SMITH_HOST_DEVICE int dimension(const tensor< T, n... > &)
a function for querying the ith dimension of a tensor
Definition: tensor.hpp:1962
FieldStateWeightedSum operator*(double a, const FieldState &b)
multiply scalar by a FieldState to get a temporary FieldStateWeightedSum which can cast back to a Fie...
tensor< double, 2, 2 > mat2
statically sized 2x2 matrix of doubles
Definition: tensor.hpp:116
constexpr SMITH_HOST_DEVICE auto transpose(const tensor< T, m, n > &A)
Returns the transpose of the matrix.
Definition: tensor.hpp:1275
constexpr SMITH_HOST_DEVICE tensor< double, dim, dim > DenseIdentity()
Obtains the identity matrix of the specified dimension.
Definition: tensor.hpp:1259
constexpr SMITH_HOST_DEVICE auto & operator-=(dual< gradient_type > &a, const dual< gradient_type > &b)
compound assignment (-) for dual numbers
Definition: dual.hpp:191
SMITH_HOST_DEVICE auto sin(dual< gradient_type > a)
implementation of sine for dual numbers
Definition: dual.hpp:324
SMITH_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:1122
constexpr SMITH_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:1339
constexpr SMITH_HOST_DEVICE auto tr(const tensor< T, n, n > &A)
Returns the trace of a square matrix.
Definition: tensor.hpp:1149
constexpr SMITH_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
constexpr SMITH_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:463
constexpr SMITH_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:1608
FieldStateWeightedSum operator-(const FieldState &x, const FieldState &y)
subtract two FieldState
constexpr SMITH_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
tensor< double, 3, 3 > mat3
statically sized 3x3 matrix of doubles
Definition: tensor.hpp:117
constexpr SMITH_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:1217
Representation of an LU factorization.
Definition: tensor.hpp:1547
tensor< T, n, n > U
Upper triangular factor.
Definition: tensor.hpp:1550
tensor< int, n > P
Row permutation indices due to partial pivoting.
Definition: tensor.hpp:1548
tensor< T, n, n > L
Lower triangular factor. Has ones on diagonal.
Definition: tensor.hpp:1549
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
SMITH_HOST_DEVICE auto operator()(T...) const
zero can be accessed like a multidimensional array
Definition: tensor.hpp:135
SMITH_HOST_DEVICE auto operator=(T)
anything assigned to zero does not change its value and returns zero
Definition: tensor.hpp:142