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 
269 template <typename T, int n1, int n2 = 1>
270 using reduced_tensor = std::conditional_t<
271  (n1 == 1 && n2 == 1), double,
272  std::conditional_t<n1 == 1, tensor<T, n2>, std::conditional_t<n2 == 1, tensor<T, n1>, tensor<T, n1, n2>>>>;
273 
279 template <typename T, int... n>
280 SMITH_HOST_DEVICE constexpr auto tensor_with_shape(std::integer_sequence<int, n...>)
281 {
282  return tensor<T, n...>{};
283 }
284 
296 template <typename lambda_type>
297 SMITH_HOST_DEVICE constexpr auto make_tensor(lambda_type f)
298 {
299  using T = decltype(f());
300  return tensor<T>{f()};
301 }
302 
315 template <int n1, typename lambda_type>
316 SMITH_HOST_DEVICE constexpr auto make_tensor(lambda_type f)
317 {
318  using T = decltype(f(n1));
319  tensor<T, n1> A{};
320  for (int i = 0; i < n1; i++) {
321  A(i) = f(i);
322  }
323  return A;
324 }
325 
339 template <int n1, int n2, typename lambda_type>
340 SMITH_HOST_DEVICE constexpr auto make_tensor(lambda_type f)
341 {
342  using T = decltype(f(n1, n2));
343  tensor<T, n1, n2> A{};
344  for (int i = 0; i < n1; i++) {
345  for (int j = 0; j < n2; j++) {
346  A(i, j) = f(i, j);
347  }
348  }
349  return A;
350 }
351 
366 template <int n1, int n2, int n3, typename lambda_type>
367 SMITH_HOST_DEVICE constexpr auto make_tensor(lambda_type f)
368 {
369  using T = decltype(f(n1, n2, n3));
371  for (int i = 0; i < n1; i++) {
372  for (int j = 0; j < n2; j++) {
373  for (int k = 0; k < n3; k++) {
374  A(i, j, k) = f(i, j, k);
375  }
376  }
377  }
378  return A;
379 }
380 
396 template <int n1, int n2, int n3, int n4, typename lambda_type>
397 SMITH_HOST_DEVICE constexpr auto make_tensor(lambda_type f)
398 {
399  using T = decltype(f(n1, n2, n3, n4));
401  for (int i = 0; i < n1; i++) {
402  for (int j = 0; j < n2; j++) {
403  for (int k = 0; k < n3; k++) {
404  for (int l = 0; l < n4; l++) {
405  A(i, j, k, l) = f(i, j, k, l);
406  }
407  }
408  }
409  }
410  return A;
411 }
412 
421 template <typename S, typename T, int m, int... n>
423 {
424  tensor<decltype(S{} + T{}), m, n...> C{};
425  for (int i = 0; i < m; i++) {
426  C[i] = A[i] + B[i];
427  }
428  return C;
429 }
430 
437 template <typename T, int m, int... n>
439 {
440  tensor<T, m, n...> B{};
441  for (int i = 0; i < m; i++) {
442  B[i] = -A[i];
443  }
444  return B;
445 }
446 
455 template <typename S, typename T, int m, int... n>
457 {
458  tensor<decltype(S{} + T{}), m, n...> C{};
459  for (int i = 0; i < m; i++) {
460  C[i] = A[i] - B[i];
461  }
462  return C;
463 }
464 
473 template <typename S, typename T, int m, int... n>
475 {
476  for (int i = 0; i < m; i++) {
477  A[i] += B[i];
478  }
479  return A;
480 }
481 
482 #if 0
489 template <typename T>
490 SMITH_HOST_DEVICE constexpr auto& operator+=(tensor<T>& A, const T& B)
491 {
492  return A.data += B;
493 }
494 #endif
495 
502 template <typename T, int n>
504 {
505  for (int i = 0; i < n; i++) {
506  A.data[i][0] += B[i];
507  }
508  return A;
509 }
510 
517 template <typename T, int n>
519 {
520  for (int i = 0; i < n; i++) {
521  A.data[0][i] += B[i];
522  }
523  return A;
524 }
525 
532 template <typename T>
533 SMITH_HOST_DEVICE constexpr auto& operator+=(tensor<T, 1>& A, const T& B)
534 {
535  return A.data[0] += B;
536 }
537 
544 template <typename T>
545 SMITH_HOST_DEVICE constexpr auto& operator+=(tensor<T, 1, 1>& A, const T& B)
546 {
547  return A.data[0][0] += B;
548 }
549 
556 template <typename T, int... n>
558 {
559  return A;
560 }
561 
570 template <typename S, typename T, int m, int... n>
572 {
573  for (int i = 0; i < m; i++) {
574  A[i] -= B[i];
575  }
576  return A;
577 }
578 
585 template <typename T, int... n>
587 {
588  return A;
589 }
590 
595 template <typename T, int n>
596 SMITH_HOST_DEVICE constexpr auto outer(double A, tensor<T, n> B)
597 {
598  tensor<decltype(double{} * T{}), n> AB{};
599  for (int i = 0; i < n; i++) {
600  AB[i] = A * B[i];
601  }
602  return AB;
603 }
604 
609 template <typename T, int m>
610 SMITH_HOST_DEVICE constexpr auto outer(const tensor<T, m>& A, double B)
611 {
612  tensor<decltype(T{} * double{}), m> AB{};
613  for (int i = 0; i < m; i++) {
614  AB[i] = A[i] * B;
615  }
616  return AB;
617 }
618 
623 template <typename T, int n>
624 SMITH_HOST_DEVICE constexpr auto outer(zero, const tensor<T, n>&)
625 {
626  return zero{};
627 }
628 
633 template <typename T, int n>
634 SMITH_HOST_DEVICE constexpr auto outer(const tensor<T, n>&, zero)
635 {
636  return zero{};
637 }
638 
643 template <typename S, typename T, int m, int n>
644 SMITH_HOST_DEVICE constexpr auto outer(const tensor<S, m>& A, const tensor<T, n>& B)
645 {
646  tensor<decltype(S{} * T{}), m, n> AB{};
647  for (int i = 0; i < m; i++) {
648  for (int j = 0; j < n; j++) {
649  AB[i][j] = A[i] * B[j];
650  }
651  }
652  return AB;
653 }
654 
664 template <typename S, typename T, int m, int n>
665 SMITH_HOST_DEVICE constexpr auto inner(const tensor<S, m, n>& A, const tensor<T, m, n>& B)
666 {
667  decltype(S{} * T{}) sum{};
668  for (int i = 0; i < m; i++) {
669  for (int j = 0; j < n; j++) {
670  sum += A[i][j] * B[i][j];
671  }
672  }
673  return sum;
674 }
675 
680 template <typename S, typename T, int m>
681 SMITH_HOST_DEVICE constexpr auto inner(const tensor<S, m>& A, const tensor<T, m>& B)
682 {
683  decltype(S{} * T{}) sum{};
684  for (int i = 0; i < m; i++) {
685  sum += A[i] * B[i];
686  }
687  return sum;
688 }
689 
694 SMITH_HOST_DEVICE constexpr auto inner(double A, double B) { return A * B; }
695 
702 template <typename S, int m, int n>
704 {
705  return zero{};
706 }
707 
712 template <typename S, int m>
713 SMITH_HOST_DEVICE constexpr auto inner(const tensor<S, m>&, zero)
714 {
715  return zero{};
716 }
717 
722 SMITH_HOST_DEVICE constexpr auto inner(double, zero) { return zero{}; }
723 
730 template <typename T, int m, int n>
732 {
733  return zero{};
734 }
735 
740 template <typename T, int m>
741 SMITH_HOST_DEVICE constexpr auto inner(zero, const tensor<T, m>&)
742 {
743  return zero{};
744 }
745 
750 SMITH_HOST_DEVICE constexpr auto inner(zero, double) { return zero{}; }
751 
760 template <typename S, typename T, int m, int n, int p>
761 SMITH_HOST_DEVICE constexpr auto dot(const tensor<S, m, n>& A, const tensor<T, n, p>& B)
762 {
763  tensor<decltype(S{} * T{}), m, p> AB{};
764  for (int i = 0; i < m; i++) {
765  for (int j = 0; j < p; j++) {
766  for (int k = 0; k < n; k++) {
767  AB[i][j] = AB[i][j] + A[i][k] * B[k][j];
768  }
769  }
770  }
771  return AB;
772 }
773 
778 template <typename T, int m>
779 SMITH_HOST_DEVICE constexpr auto dot(const tensor<T, m>& A, double B)
780 {
781  return A * B;
782 }
783 
788 template <typename T, int m>
789 SMITH_HOST_DEVICE constexpr auto dot(double B, const tensor<T, m>& A)
790 {
791  return B * A;
792 }
793 
798 template <typename S, typename T, int m>
799 SMITH_HOST_DEVICE constexpr auto dot(const tensor<S, m>& A, const tensor<T, m>& B)
800 {
801  decltype(S{} * T{}) AB{};
802  for (int i = 0; i < m; i++) {
803  AB = AB + A[i] * B[i];
804  }
805  return AB;
806 }
807 
812 template <typename S, typename T, int m, int n>
813 SMITH_HOST_DEVICE constexpr auto dot(const tensor<S, m>& A, const tensor<T, m, n>& B)
814 {
815  tensor<decltype(S{} * T{}), n> AB{};
816  for (int i = 0; i < n; i++) {
817  for (int j = 0; j < m; j++) {
818  AB[i] = AB[i] + A[j] * B[j][i];
819  }
820  }
821  return AB;
822 }
823 
828 template <typename S, typename T, int m, int n, int p>
829 SMITH_HOST_DEVICE constexpr auto dot(const tensor<S, m>& A, const tensor<T, m, n, p>& B)
830 {
831  tensor<decltype(S{} * T{}), n, p> AB{};
832  for (int j = 0; j < m; j++) {
833  AB = AB + A[j] * B[j];
834  }
835  return AB;
836 }
837 
848 template <typename S, typename T, int m, int n, int p, int q>
849 SMITH_HOST_DEVICE constexpr auto dot(const tensor<S, m>& A, const tensor<T, m, n, p, q>& B)
850 {
851  tensor<decltype(S{} * T{}), n, p, q> AB{};
852  for (int j = 0; j < m; j++) {
853  AB = AB + A[j] * B[j];
854  }
855  return AB;
856 }
857 
862 template <typename S, typename T, int m, int n>
863 SMITH_HOST_DEVICE constexpr auto dot(const tensor<S, m, n>& A, const tensor<T, n>& B)
864 {
865  tensor<decltype(S{} * T{}), m> AB{};
866  for (int i = 0; i < m; i++) {
867  for (int j = 0; j < n; j++) {
868  AB[i] = AB[i] + A[i][j] * B[j];
869  }
870  }
871  return AB;
872 }
873 
878 template <typename S, typename T, int m, int n, int p, int q, int r>
879 SMITH_HOST_DEVICE constexpr auto dot(const tensor<S, m, n>& A, const tensor<T, n, p, q, r>& B)
880 {
881  tensor<decltype(S{} * T{}), m, p, q, r> AB{};
882  for (int i = 0; i < m; i++) {
883  for (int j = 0; j < n; j++) {
884  AB[i] = AB[i] + A[i][j] * B[j];
885  }
886  }
887  return AB;
888 }
889 
894 template <typename S, typename T, int m, int n, int p, int q>
895 SMITH_HOST_DEVICE constexpr auto dot(const tensor<S, m, n>& A, const tensor<T, n, p, q>& B)
896 {
897  tensor<decltype(S{} * T{}), m, p, q> AB{};
898  for (int i = 0; i < m; i++) {
899  for (int j = 0; j < n; j++) {
900  AB[i] = AB[i] + A[i][j] * B[j];
901  }
902  }
903  return AB;
904 }
905 
910 template <typename S, typename T, int m, int n, int p>
911 SMITH_HOST_DEVICE constexpr auto dot(const tensor<S, m, n, p>& A, const tensor<T, p>& B)
912 {
913  tensor<decltype(S{} * T{}), m, n> AB{};
914  for (int i = 0; i < m; i++) {
915  for (int j = 0; j < n; j++) {
916  for (int k = 0; k < p; k++) {
917  AB[i][j] += A[i][j][k] * B[k];
918  }
919  }
920  }
921  return AB;
922 }
923 
928 template <typename S, typename T, typename U, int m, int n>
929 SMITH_HOST_DEVICE constexpr auto dot(const tensor<S, m>& u, const tensor<T, m, n>& A, const tensor<U, n>& v)
930 {
931  decltype(S{} * T{} * U{}) uAv{};
932  for (int i = 0; i < m; i++) {
933  for (int j = 0; j < n; j++) {
934  uAv += u[i] * A[i][j] * v[j];
935  }
936  }
937  return uAv;
938 }
939 
941 template <typename S, typename T, int m, int n, int p, int q>
942 SMITH_HOST_DEVICE constexpr auto dot(const tensor<S, m, n, p, q>& A, const tensor<T, q>& B)
943 {
944  tensor<decltype(S{} * T{}), m, n, p> AB{};
945  for (int i = 0; i < m; i++) {
946  for (int j = 0; j < n; j++) {
947  for (int k = 0; k < p; k++) {
948  for (int l = 0; l < q; l++) {
949  AB[i][j][k] += A[i][j][k][l] * B[l];
950  }
951  }
952  }
953  }
954  return AB;
955 }
956 
958 template <typename T>
959 auto cross(const tensor<T, 3, 2>& A)
960 {
961  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),
962  A(0, 0) * A(1, 1) - A(1, 0) * A(0, 1)};
963 }
964 
966 template <typename T>
967 auto cross(const tensor<T, 2, 1>& v)
968 {
969  return tensor<T, 2>{v(1, 0), -v(0, 0)};
970 }
971 
973 template <typename T>
974 auto cross(const tensor<T, 2>& v)
975 {
976  return tensor<T, 2>{v[1], -v[0]};
977 }
978 
980 template <typename S, typename T>
981 auto cross(const tensor<S, 3>& u, const tensor<T, 3>& v)
982 {
983  return tensor<decltype(S{} * T{}), 3>{u(1) * v(2) - u(2) * v(1), u(2) * v(0) - u(0) * v(2),
984  u(0) * v(1) - u(1) * v(0)};
985 }
986 
998 template <typename S, typename T, int m, int n, int p, int q>
1000 {
1001  tensor<decltype(S{} * T{}), m, n> AB{};
1002  for (int i = 0; i < m; i++) {
1003  for (int j = 0; j < n; j++) {
1004  for (int k = 0; k < p; k++) {
1005  for (int l = 0; l < q; l++) {
1006  AB[i][j] += A[i][j][k][l] * B[k][l];
1007  }
1008  }
1009  }
1010  }
1011  return AB;
1012 }
1013 
1018 template <typename S, typename T, int m, int n, int p>
1020 {
1021  tensor<decltype(S{} * T{}), m> AB{};
1022  for (int i = 0; i < m; i++) {
1023  for (int j = 0; j < n; j++) {
1024  for (int k = 0; k < p; k++) {
1025  AB[i] += A[i][j][k] * B[j][k];
1026  }
1027  }
1028  }
1029  return AB;
1030 }
1031 
1036 template <typename S, typename T, int m, int n>
1037 constexpr auto double_dot(const tensor<S, m, n>& A, const tensor<T, m, n>& B)
1038 {
1039  decltype(S{} * T{}) AB{};
1040  for (int i = 0; i < m; i++) {
1041  for (int j = 0; j < n; j++) {
1042  AB += A[i][j] * B[i][j];
1043  }
1044  }
1045  return AB;
1046 }
1047 
1051 template <typename S, typename T, int... m, int... n>
1053 {
1054  return dot(A, B);
1055 }
1056 
1061 template <typename T, int m>
1063 {
1064  T total{};
1065  for (int i = 0; i < m; i++) {
1066  total += A[i] * A[i];
1067  }
1068  return total;
1069 }
1070 
1072 template <typename T, int m, int n>
1074 {
1075  T total{};
1076  for (int i = 0; i < m; i++) {
1077  for (int j = 0; j < n; j++) {
1078  total += A[i][j] * A[i][j];
1079  }
1080  }
1081  return total;
1082 }
1083 
1085 template <typename T, int... n>
1087 {
1088  T total{};
1089  for_constexpr<n...>([&](auto... i) { total += A(i...) * A(i...); });
1090  return total;
1091 }
1092 
1097 template <typename T, int... n>
1099 {
1100  using std::sqrt;
1101  return sqrt(squared_norm(A));
1102 }
1103 
1107 SMITH_HOST_DEVICE constexpr auto norm(zero) { return zero{}; }
1108 
1114 template <typename T, int... n>
1116 {
1117  return A / norm(A);
1118 }
1119 
1125 template <typename T>
1127 {
1128  tensor<T, 3, 3> output{};
1129  output[0][0] = A[0][0];
1130  output[0][1] = A[0][1];
1131  output[1][0] = A[1][0];
1132  output[1][1] = A[1][1];
1133  return output;
1134 }
1135 
1141 template <typename T, int n>
1142 SMITH_HOST_DEVICE constexpr auto tr(const tensor<T, n, n>& A)
1143 {
1144  T trA{};
1145  for (int i = 0; i < n; i++) {
1146  trA = trA + A[i][i];
1147  }
1148  return trA;
1149 }
1150 
1156 template <typename T, int n>
1157 SMITH_HOST_DEVICE constexpr auto sym(const tensor<T, n, n>& A)
1158 {
1159  tensor<T, n, n> symA{};
1160  for (int i = 0; i < n; i++) {
1161  for (int j = 0; j < n; j++) {
1162  symA[i][j] = 0.5 * (A[i][j] + A[j][i]);
1163  }
1164  }
1165  return symA;
1166 }
1167 
1173 template <typename T, int n>
1175 {
1176  tensor<T, n, n> antisymA{};
1177  for (int i = 0; i < n; i++) {
1178  for (int j = 0; j < n; j++) {
1179  antisymA[i][j] = 0.5 * (A[i][j] - A[j][i]);
1180  }
1181  }
1182  return antisymA;
1183 }
1184 
1192 template <typename T, int n>
1193 SMITH_HOST_DEVICE constexpr auto dev(const tensor<T, n, n>& A)
1194 {
1195  auto devA = A;
1196  auto trA = tr(A);
1197  for (int i = 0; i < n; i++) {
1198  devA[i][i] -= trA / n;
1199  }
1200  return devA;
1201 }
1202 
1209 template <typename T, int n>
1211 {
1212  tensor<T, n, n> D{};
1213  for (int i = 0; i < n; i++) {
1214  D[i][i] = A[i][i];
1215  }
1216  return D;
1217 }
1218 
1223 template <typename T, int n>
1225 {
1226  tensor<T, n, n> D{};
1227  for (int i = 0; i < n; i++) {
1228  D[i][i] = d[i];
1229  }
1230  return D;
1231 }
1232 
1237 template <typename T, int n>
1239 {
1240  tensor<T, n> d{};
1241  for (int i = 0; i < n; i++) {
1242  d[i] = D[i][i];
1243  }
1244  return d;
1245 }
1246 
1251 template <int dim>
1253 {
1255  for (int i = 0; i < dim; i++) {
1256  for (int j = 0; j < dim; j++) {
1257  I[i][j] = (i == j);
1258  }
1259  }
1260  return I;
1261 }
1262 
1267 template <typename T, int m, int n>
1269 {
1270  tensor<T, n, m> AT{};
1271  for (int i = 0; i < n; i++) {
1272  for (int j = 0; j < m; j++) {
1273  AT[i][j] = A[j][i];
1274  }
1275  }
1276  return AT;
1277 }
1278 
1283 template <typename T>
1284 SMITH_HOST_DEVICE constexpr auto I2(const tensor<T, 3, 3>& A)
1285 {
1286  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] -
1287  A[2][0] * A[0][2];
1288 }
1289 
1294 template <typename T>
1295 SMITH_HOST_DEVICE constexpr auto det(const tensor<T, 2, 2>& A)
1296 {
1297  return A[0][0] * A[1][1] - A[0][1] * A[1][0];
1298 }
1299 
1301 template <typename T>
1302 SMITH_HOST_DEVICE constexpr auto det(const tensor<T, 3, 3>& A)
1303 {
1304  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] -
1305  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];
1306 }
1307 
1318 template <typename T>
1320 {
1321  // From the Cayley-Hamilton theorem, we get that for any N by N matrix A,
1322  // det(A - I) - 1 = I1(A) + I2(A) + ... + IN(A),
1323  // where the In are the principal invariants of A.
1324  // We inline the definitions of the principal invariants to increase computational speed.
1325 
1326  // equivalent to tr(A) + det(A)
1327  return A(0, 0) - A(0, 1) * A(1, 0) + A(1, 1) + A(0, 0) * A(1, 1);
1328 }
1329 
1331 template <typename T>
1333 {
1334  // For notes on the implementation, see the 2x2 version.
1335 
1336  // clang-format off
1337  // equivalent to tr(A) + I2(A) + det(A)
1338  return A(0, 0) + A(1, 1) + A(2, 2)
1339  - A(0, 1) * A(1, 0) * (1 + A(2, 2))
1340  + A(0, 0) * A(1, 1) * (1 + A(2, 2))
1341  - A(0, 2) * A(2, 0) * (1 + A(1, 1))
1342  - A(1, 2) * A(2, 1) * (1 + A(0, 0))
1343  + A(0, 0) * A(2, 2)
1344  + A(1, 1) * A(2, 2)
1345  + A(0, 1) * A(1, 2) * A(2, 0)
1346  + A(0, 2) * A(1, 0) * A(2, 1);
1347  // clang-format on
1348 }
1349 
1358 template <typename T, int dim>
1360 {
1361  auto B = A;
1362  for (int i = 0; i < 15; i++) {
1363  B = 0.5 * (B + dot(A, inv(B)));
1364  }
1365  return B;
1366 }
1367 
1397 template <int i1, int i2, typename S, int m, int... n, typename T, int p, int q>
1399 {
1400  constexpr int Adims[] = {m, n...};
1401  constexpr int Bdims[] = {p, q};
1402  static_assert(sizeof...(n) < 3);
1403  static_assert(Adims[i1] == Bdims[i2], "error: incompatible tensor dimensions");
1404 
1405  // first, we have to figure out the dimensions of the output tensor
1406  constexpr int new_dim = (i2 == 0) ? q : p;
1407  constexpr int d1 = (i1 == 0) ? new_dim : Adims[0];
1408  constexpr int d2 = (i1 == 1) ? new_dim : Adims[1];
1409  constexpr int d3 = sizeof...(n) == 1 ? 0 : ((i1 == 2) ? new_dim : Adims[2]);
1410 
1411  // the type of the output tensor is easier to figure out
1412  using U = decltype(S{} * T{});
1413 
1414  auto C = []() {
1415  if constexpr (d3 == 0) return tensor<U, d1, d2>{};
1416  if constexpr (d3 != 0) return tensor<U, d1, d2, d3>{};
1417  }();
1418 
1419  if constexpr (d3 == 0) {
1420  for (int i = 0; i < d1; i++) {
1421  for (int j = 0; j < d2; j++) {
1422  U sum{};
1423  for (int k = 0; k < Adims[i1]; k++) {
1424  if constexpr (i1 == 0 && i2 == 0) sum += A(k, j) * B(k, i);
1425  if constexpr (i1 == 1 && i2 == 0) sum += A(i, k) * B(k, j);
1426  if constexpr (i1 == 0 && i2 == 1) sum += A(k, j) * B(i, k);
1427  if constexpr (i1 == 1 && i2 == 1) sum += A(i, k) * B(j, k);
1428  }
1429  C(i, j) = sum;
1430  }
1431  }
1432  } else {
1433  for (int i = 0; i < d1; i++) {
1434  for (int j = 0; j < d2; j++) {
1435  for (int k = 0; k < d3; k++) {
1436  U sum{};
1437  for (int l = 0; l < Adims[i1]; l++) {
1438  if constexpr (i1 == 0 && i2 == 0) sum += A(l, j, k) * B(l, i);
1439  if constexpr (i1 == 1 && i2 == 0) sum += A(i, l, k) * B(l, j);
1440  if constexpr (i1 == 2 && i2 == 0) sum += A(i, j, l) * B(l, k);
1441  if constexpr (i1 == 0 && i2 == 1) sum += A(l, j, k) * B(i, l);
1442  if constexpr (i1 == 1 && i2 == 1) sum += A(i, l, k) * B(j, l);
1443  if constexpr (i1 == 2 && i2 == 1) sum += A(i, j, l) * B(k, l);
1444  }
1445  C(i, j, k) = sum;
1446  }
1447  }
1448  }
1449  }
1450 
1451  return C;
1452 }
1453 
1455 template <int i1, int i2, typename T>
1456 SMITH_HOST_DEVICE auto contract(const zero&, const T&)
1457 {
1458  return zero{};
1459 }
1460 
1470 template <typename T, int... n>
1472 {
1473  return norm(A - B) / norm(A);
1474 }
1475 
1484 template <int n>
1485 SMITH_HOST_DEVICE bool is_symmetric(tensor<double, n, n> A, double tolerance = 1.0e-8)
1486 {
1487  for (int i = 0; i < n; ++i) {
1488  for (int j = i + 1; j < n; ++j) {
1489  if (std::abs(A(i, j) - A(j, i)) > tolerance) {
1490  return false;
1491  };
1492  }
1493  }
1494  return true;
1495 }
1496 
1506 {
1507  if (!is_symmetric(A)) {
1508  return false;
1509  }
1510  if (A(0, 0) < 0.0) {
1511  return false;
1512  }
1513  if (det(A) < 0.0) {
1514  return false;
1515  }
1516  return true;
1517 }
1520 {
1521  if (!is_symmetric(A)) {
1522  return false;
1523  }
1524  if (det(A) < 0.0) {
1525  return false;
1526  }
1527  auto subtensor = make_tensor<2, 2>([A](int i, int j) { return A(i, j); });
1528  if (!is_symmetric_and_positive_definite(subtensor)) {
1529  return false;
1530  }
1531  return true;
1532 }
1533 
1539 template <typename T, int n>
1544 };
1545 
1560 template <typename T, int n, int... m>
1562  const tensor<int, n>& P)
1563 {
1564  tensor<T, n, m...> y{};
1565  for (int i = 0; i < n; i++) {
1566  auto c = b[P[i]];
1567  for (int j = 0; j < i; j++) {
1568  c -= L[i][j] * y[j];
1569  }
1570  y[i] = c / L[i][i];
1571  }
1572  return y;
1573 }
1574 
1579 template <typename T, int n, int... m>
1581 {
1582  // no permutation provided, so just map each equation to itself
1583  // TODO make a convienience function for ranges like this
1584  // BT 05/09/2022
1585  tensor<int, n> P(make_tensor<n>([](auto i) { return i; }));
1586 
1587  return solve_lower_triangular(L, b, P);
1588 }
1589 
1600 template <typename T, int n, int... m>
1602 {
1603  tensor<T, n, m...> x{};
1604  for (int i = n - 1; i >= 0; i--) {
1605  auto c = y[i];
1606  for (int j = i + 1; j < n; j++) {
1607  c -= U[i][j] * x[j];
1608  }
1609  x[i] = c / U[i][i];
1610  }
1611  return x;
1612 }
1613 
1618 template <typename S, typename T, int n, int... m>
1619 SMITH_HOST_DEVICE constexpr auto linear_solve(const LuFactorization<S, n>& lu_factors, const tensor<T, n, m...>& b)
1620 {
1621  // Forward substitution
1622  // solve Ly = b
1623  const auto y = solve_lower_triangular(lu_factors.L, b, lu_factors.P);
1624 
1625  // Back substitution
1626  // Solve Ux = y
1627  return solve_upper_triangular(lu_factors.U, y);
1628 }
1629 
1634 template <typename T, int n>
1635 SMITH_HOST_DEVICE constexpr auto linear_solve(const LuFactorization<T, n>& /* lu_factors */, const zero /* b */)
1636 {
1637  return zero{};
1638 }
1639 
1646 {
1647  double inv_detA(1.0 / det(A));
1648 
1649  tensor<double, 2, 2> invA{};
1650 
1651  invA[0][0] = A[1][1] * inv_detA;
1652  invA[0][1] = -A[0][1] * inv_detA;
1653  invA[1][0] = -A[1][0] * inv_detA;
1654  invA[1][1] = A[0][0] * inv_detA;
1655 
1656  return invA;
1657 }
1658 
1664 {
1665  double inv_detA(1.0 / det(A));
1666 
1667  tensor<double, 3, 3> invA{};
1668 
1669  invA[0][0] = (A[1][1] * A[2][2] - A[1][2] * A[2][1]) * inv_detA;
1670  invA[0][1] = (A[0][2] * A[2][1] - A[0][1] * A[2][2]) * inv_detA;
1671  invA[0][2] = (A[0][1] * A[1][2] - A[0][2] * A[1][1]) * inv_detA;
1672  invA[1][0] = (A[1][2] * A[2][0] - A[1][0] * A[2][2]) * inv_detA;
1673  invA[1][1] = (A[0][0] * A[2][2] - A[0][2] * A[2][0]) * inv_detA;
1674  invA[1][2] = (A[0][2] * A[1][0] - A[0][0] * A[1][2]) * inv_detA;
1675  invA[2][0] = (A[1][0] * A[2][1] - A[1][1] * A[2][0]) * inv_detA;
1676  invA[2][1] = (A[0][1] * A[2][0] - A[0][0] * A[2][1]) * inv_detA;
1677  invA[2][2] = (A[0][0] * A[1][1] - A[0][1] * A[1][0]) * inv_detA;
1678 
1679  return invA;
1680 }
1686 template <typename T, int n>
1687 SMITH_HOST_DEVICE constexpr auto inv(const tensor<T, n, n>& A)
1688 {
1689  auto I = DenseIdentity<n>();
1690  return linear_solve(A, I);
1691 }
1692 
1701 template <typename T, int m, int... n>
1702 auto& operator<<(std::ostream& out, const tensor<T, m, n...>& A)
1703 {
1704  out << '{' << A[0];
1705  for (int i = 1; i < m; i++) {
1706  out << ", " << A[i];
1707  }
1708  out << '}';
1709  return out;
1710 }
1711 
1717 inline auto& operator<<(std::ostream& out, zero)
1718 {
1719  out << "zero";
1720  return out;
1721 }
1722 
1728 inline SMITH_HOST_DEVICE void print(double value) { printf("%f", value); }
1729 
1734 template <int m, int... n>
1736 {
1737  printf("{");
1738  print(A[0]);
1739  for (int i = 1; i < m; i++) {
1740  printf(",");
1741  print(A[i]);
1742  }
1743  printf("}");
1744 }
1745 
1750 template <int n>
1751 SMITH_HOST_DEVICE constexpr auto chop(const tensor<double, n>& A)
1752 {
1753  auto copy = A;
1754  for (int i = 0; i < n; i++) {
1755  if (copy[i] * copy[i] < 1.0e-20) {
1756  copy[i] = 0.0;
1757  }
1758  }
1759  return copy;
1760 }
1761 
1763 template <int m, int n>
1765 {
1766  auto copy = A;
1767  for (int i = 0; i < m; i++) {
1768  for (int j = 0; j < n; j++) {
1769  if (copy[i][j] * copy[i][j] < 1.0e-20) {
1770  copy[i][j] = 0.0;
1771  }
1772  }
1773  }
1774  return copy;
1775 }
1776 
1778 namespace detail {
1779 
1780 template <typename T1, typename T2>
1781 struct outer_prod;
1782 
1783 template <int... m, int... n>
1784 struct outer_prod<tensor<double, m...>, tensor<double, n...>> {
1785  using type = tensor<double, m..., n...>;
1786 };
1787 
1788 template <int... n>
1789 struct outer_prod<double, tensor<double, n...>> {
1790  using type = tensor<double, n...>;
1791 };
1792 
1793 template <int... n>
1794 struct outer_prod<tensor<double, n...>, double> {
1795  using type = tensor<double, n...>;
1796 };
1797 
1798 template <>
1799 struct outer_prod<double, double> {
1800  using type = tensor<double>;
1801 };
1802 
1803 template <typename T>
1804 struct outer_prod<zero, T> {
1805  using type = zero;
1806 };
1807 
1808 template <typename T>
1809 struct outer_prod<T, zero> {
1810  using type = zero;
1811 };
1812 
1813 } // namespace detail
1815 
1821 template <typename T1, typename T2>
1823 
1828 inline SMITH_HOST_DEVICE auto get_gradient(double /* arg */) { return zero{}; }
1829 
1835 template <int... n>
1836 SMITH_HOST_DEVICE constexpr auto get_gradient(const tensor<double, n...>& /* arg */)
1837 {
1838  return zero{};
1839 }
1840 
1844 SMITH_HOST_DEVICE constexpr auto chain_rule(const zero /* df_dx */, const zero /* dx */) { return zero{}; }
1845 
1850 template <typename T>
1851 SMITH_HOST_DEVICE constexpr auto chain_rule(const zero /* df_dx */, const T /* dx */)
1852 {
1853  return zero{};
1854 }
1855 
1860 template <typename T>
1861 SMITH_HOST_DEVICE constexpr auto chain_rule(const T /* df_dx */, const zero /* dx */)
1862 {
1863  return zero{};
1864 }
1865 
1870 SMITH_HOST_DEVICE constexpr auto chain_rule(const double df_dx, const double dx) { return df_dx * dx; }
1871 
1876 template <int... n>
1877 SMITH_HOST_DEVICE constexpr auto chain_rule(const tensor<double, n...>& df_dx, const double dx)
1878 {
1879  return df_dx * dx;
1880 }
1881 
1886 template <int... n>
1888 {
1889  double total{};
1890  for_constexpr<n...>([&](auto... i) { total += df_dx(i...) * dx(i...); });
1891  return total;
1892 }
1893 
1898 template <int m, int... n>
1900 {
1901  tensor<double, m> total{};
1902  for (int i = 0; i < m; i++) {
1903  total[i] = chain_rule(df_dx[i], dx);
1904  }
1905  return total;
1906 }
1907 
1912 template <int m, int n, int... p>
1914 {
1915  tensor<double, m, n> total{};
1916  for (int i = 0; i < m; i++) {
1917  for (int j = 0; j < n; j++) {
1918  total[i][j] = chain_rule(df_dx[i][j], dx);
1919  }
1920  }
1921  return total;
1922 }
1923 
1931 template <typename T, int... n>
1933 {
1934  return (n * ... * 1);
1935 }
1936 
1941 SMITH_HOST_DEVICE constexpr int size(const double&) { return 1; }
1942 
1944 SMITH_HOST_DEVICE constexpr int size(zero) { return 0; }
1945 
1954 template <int i, typename T, int... n>
1956 {
1957  constexpr int dimensions[] = {n...};
1958  return dimensions[i];
1959 }
1960 
1969 template <typename T, int m, int... n>
1971 {
1972  return m;
1973 }
1974 
1976 template <typename T, int... n>
1977 bool isnan(const tensor<T, n...>& A)
1978 {
1979  bool found_nan = false;
1980  for_constexpr<n...>([&](auto... i) { found_nan |= std::isnan(A(i...)); });
1981  return found_nan;
1982 }
1983 
1985 inline bool isnan(const zero&) { return false; }
1986 
1987 } // namespace smith
1988 
1989 #if 0
1990 
1991 inline float angle_between(const vec < 2 > & a, const vec < 2 > & b) {
1992  return acos(clip(dot(normalize(a), normalize(b)), -1.0f, 1.0f));
1993 }
1994 
1995 inline float angle_between(const vec < 3 > & a, const vec < 3 > & b) {
1996  return acos(clip(dot(normalize(a), normalize(b)), -1.0f, 1.0f));
1997 }
1998 
1999 // angle between proper orthogonal matrices
2000 inline float angle_between(const mat < 3, 3 > & U, const mat < 3, 3 > & V) {
2001  return acos(0.5f * (tr(dot(U, transpose(V))) - 1.0f));
2002 }
2003 
2004 inline mat < 2, 2 > rotation(const float theta) {
2005  return mat< 2, 2 >{
2006  {cos(theta), -sin(theta)},
2007  { sin(theta), cos(theta) }
2008  };
2009 }
2010 
2011 inline mat < 3, 3 > axis_to_rotation(const vec < 3 > & omega) {
2012 
2013  float norm_omega = norm(omega);
2014 
2015  if (fabs(norm_omega) < 0.000001f) {
2016 
2017  return eye< 3 >();
2018 
2019  } else {
2020 
2021  vec3 u = omega / norm_omega;
2022 
2023  float c = cos(norm_omega);
2024  float s = sin(norm_omega);
2025 
2026  return mat < 3, 3 >{
2027  {
2028  u[0]*u[0]*(1.0f - c) + c,
2029  u[0]*u[1]*(1.0f - c) - u[2]*s,
2030  u[0]*u[2]*(1.0f - c) + u[1]*s
2031  },{
2032  u[1]*u[0]*(1.0f - c) + u[2]*s,
2033  u[1]*u[1]*(1.0f - c) + c,
2034  u[1]*u[2]*(1.0f - c) - u[0]*s
2035  },{
2036  u[2]*u[0]*(1.0f - c) - u[1]*s,
2037  u[2]*u[1]*(1.0f - c) + u[0]*s,
2038  u[2]*u[2]*(1.0f - c) + c
2039  }
2040  };
2041 
2042  }
2043 
2044 }
2045 
2046 // assumes R is a proper-orthogonal matrix
2047 inline vec < 3 > rotation_to_axis(const mat < 3, 3 > & R) {
2048 
2049  float theta = acos(clip(0.5f * (tr(R) - 1.0f), -1.0f, 1.0f));
2050 
2051  float scale;
2052 
2053  // for small angles, prefer series expansion to division by sin(theta) ~ 0
2054  if (fabs(theta) < 0.00001f) {
2055  scale = 0.5f + theta * theta / 12.0f;
2056  }
2057  else {
2058  scale = 0.5f * theta / sin(theta);
2059  }
2060 
2061  return vec3{ R(2,1) - R(1,2), R(0,2) - R(2,0), R(1,0) - R(0,1) } *scale;
2062 
2063 }
2064 
2065 inline mat < 3, 3 > look_at(const vec < 3 > & direction, const vec < 3 > & up = vec3{ 0.0f, 0.0f, 1.0f }) {
2066  vec3 f = normalize(direction);
2067  vec3 u = normalize(cross(f, cross(up, f)));
2068  vec3 l = normalize(cross(u, f));
2069 
2070  return mat3{
2071  {f[0], l[0], u[0]},
2072  {f[1], l[1], u[1]},
2073  {f[2], l[2], u[2]}
2074  };
2075 }
2076 
2077 inline mat < 2, 2 > look_at(const vec < 2 > & direction) {
2078  vec2 f = normalize(direction);
2079  vec2 l = cross(f);
2080 
2081  return mat2{
2082  {f[0], l[0]},
2083  {f[1], l[1]},
2084  };
2085 }
2086 
2087 inline mat < 3, 3 > R3_basis(const vec3 & n) {
2088  float sign = (n[2] >= 0.0f) ? 1.0f : -1.0f;
2089  float a = -1.0f / (sign + n[2]);
2090  float b = n[0] * n[1] * a;
2091 
2092  return mat < 3, 3 >{
2093  {
2094  1.0f + sign * n[0] * n[0] * a,
2095  b,
2096  n[0],
2097  },{
2098  sign * b,
2099  sign + n[1] * n[1] * a,
2100  n[1]
2101  },{
2102  -sign * n[0],
2103  -n[1],
2104  n[2]
2105  }
2106  };
2107 }
2108 #endif
2109 
2111 
2112 #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:50
#define SMITH_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 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:1485
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:1519
constexpr SMITH_HOST_DEVICE auto antisym(const tensor< T, n, n > &A)
Returns the antisymmetric part of a square matrix.
Definition: tensor.hpp:1174
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:586
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:297
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:1944
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:1302
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:1471
constexpr SMITH_HOST_DEVICE int leading_dimension(tensor< T, m, n... >)
a function for querying the first dimension of a tensor
Definition: tensor.hpp:1970
constexpr SMITH_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
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:1836
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:1052
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:1456
SMITH_HOST_DEVICE auto chain_rule(const tensor< double, m, n, p... > &df_dx, const tensor< double, p... > &dx)
Definition: tensor.hpp:1913
constexpr SMITH_HOST_DEVICE auto I2(const tensor< T, 3, 3 > &A)
Returns the second invariant of a 3x3 matrix.
Definition: tensor.hpp:1284
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:750
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:1580
constexpr SMITH_HOST_DEVICE auto norm(zero)
overload of Frobenius norm for zero type
Definition: tensor.hpp:1107
constexpr SMITH_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 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:1086
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:1717
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:272
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:1764
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:1238
bool isnan(const zero &)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: tensor.hpp:1985
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:1037
constexpr SMITH_HOST_DEVICE auto inv(const tensor< T, n, n > &A)
Definition: tensor.hpp:1687
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:981
constexpr SMITH_HOST_DEVICE auto dev(const tensor< T, n, n > &A)
Calculates the deviator of a matrix (rank-2 tensor)
Definition: tensor.hpp:1193
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:1359
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:1126
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:1735
constexpr SMITH_HOST_DEVICE auto sym(const tensor< T, n, n > &A)
Returns the symmetric part of a square matrix.
Definition: tensor.hpp:1157
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:1822
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:280
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:942
constexpr SMITH_HOST_DEVICE auto outer(const tensor< S, m > &A, const tensor< T, n > &B)
Definition: tensor.hpp:644
constexpr SMITH_HOST_DEVICE auto & operator+=(tensor< T, n... > &A, zero)
compound assignment (+) between a tensor and zero (no-op)
Definition: tensor.hpp:557
constexpr SMITH_HOST_DEVICE auto linear_solve(const LuFactorization< T, n > &, const zero)
Definition: tensor.hpp:1635
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:1955
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:1268
constexpr SMITH_HOST_DEVICE tensor< double, dim, dim > DenseIdentity()
Obtains the identity matrix of the specified dimension.
Definition: tensor.hpp:1252
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:1115
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:1332
constexpr SMITH_HOST_DEVICE auto tr(const tensor< T, n, n > &A)
Returns the trace of a square matrix.
Definition: tensor.hpp:1142
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:456
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:1601
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:1210
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
Representation of an LU factorization.
Definition: tensor.hpp:1540
tensor< T, n, n > U
Upper triangular factor.
Definition: tensor.hpp:1543
tensor< int, n > P
Row permutation indices due to partial pivoting.
Definition: tensor.hpp:1541
tensor< T, n, n > L
Lower triangular factor. Has ones on diagonal.
Definition: tensor.hpp:1542
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