14 static constexpr
bool value =
false;
18 template <
typename T,
int... n>
20 static constexpr
bool value =
true;
31 template <
typename S,
typename T,
int m,
int... n,
35 tensor<decltype(S{} * T{}), m, n...> C{};
36 for (
int i = 0; i < m; i++) {
50 template <
typename S,
typename T,
int m,
int... n,
51 typename = std::enable_if_t<std::is_arithmetic_v<S> || is_dual_number<S>::value>>
54 tensor<decltype(T{} * S{}), m, n...> C{};
55 for (
int i = 0; i < m; i++) {
69 template <
typename S,
typename T,
int m,
int... n,
70 typename = std::enable_if_t<std::is_arithmetic_v<S> || is_dual_number<S>::value>>
73 tensor<decltype(S{} * T{}), n...> C{};
74 for (
int i = 0; i < m; i++) {
88 template <
typename S,
typename T,
int m,
int... n,
89 typename = std::enable_if_t<std::is_arithmetic_v<S> || is_dual_number<S>::value>>
92 tensor<decltype(T{} * S{}), m, n...> C{};
93 for (
int i = 0; i < m; i++) {
100 template <
int i,
typename S,
typename T>
101 struct one_hot_helper;
103 template <
int i,
int... I,
typename T>
104 struct one_hot_helper<i, std::integer_sequence<int, I...>, T> {
105 using type = tuple<std::conditional_t<i == I, T, zero>...>;
108 template <
int i,
int n,
typename T>
109 struct one_hot :
public one_hot_helper<i, std::make_integer_sequence<int, n>, T> {
119 template <
int i,
int n,
typename T>
123 template <
int i,
int N>
136 template <
int i,
int N>
141 arg_dual.
value = arg;
142 serac::get<i>(arg_dual.gradient) = 1.0;
153 template <
int i,
int N,
typename T,
int... n>
159 arg_dual(j...).value = arg(j...);
160 serac::get<i>(arg_dual(j...).gradient)(j...) = 1.0;
182 template <
typename T0,
typename T1>
185 return tuple{make_dual_helper<0, 2>(get<0>(args)), make_dual_helper<1, 2>(get<1>(args))};
189 template <
typename T0,
typename T1,
typename T2>
192 return tuple{make_dual_helper<0, 3>(get<0>(args)), make_dual_helper<1, 3>(get<1>(args)),
193 make_dual_helper<2, 3>(get<2>(args))};
203 template <
bool dualify,
typename T>
206 if constexpr (dualify) {
209 if constexpr (!dualify) {
222 template <
bool dualify,
typename T,
int n>
225 if constexpr (dualify) {
226 using return_type = decltype(
make_dual(T{}));
228 for (
int i = 0; i < n; i++) {
233 if constexpr (!dualify) {
239 template <
int n,
typename... T,
int... i>
268 template <
int n,
typename... T>
271 return make_dual_helper<n>(args, std::make_integer_sequence<
int,
static_cast<int>(
sizeof...(T))>{});
283 template <
typename T1,
typename T2,
int n>
287 for (
int i = 0; i < n; i++) {
298 template <
typename... T>
309 template <
typename... T>
316 template <
typename... T,
int... n>
321 for_constexpr<
sizeof...(T)>([&](
auto j) { serac::get<j>(g)(i...) = serac::get<j>(arg(i...).gradient); });
327 template <
typename... T>
343 A_dual(i...).value = A(i...);
344 A_dual(i...).gradient(i...) = 1.0;
358 template <
typename T,
int n>
361 constexpr
auto abs = [](
double x) {
return (x < 0) ? -x : x; };
362 constexpr
auto swap = [](
auto& x,
auto& y) {
373 for (
int i = 0; i < n; i++) {
382 for (
int i = 0; i < n; i++) {
387 for (
int j = i + 1; j < n; j++) {
389 if (
abs(U_ji) > max_val) {
395 swap(P[max_row], P[i]);
396 swap(U[max_row], U[i]);
399 for (
int i = 0; i < n; i++) {
402 for (
int j = i + 1; j < n; j++) {
403 auto c = U[j][i] / U[i][i];
419 template <
typename S,
typename T,
int n,
int... m>
439 if constexpr (
is_zero<decltype(dx)>{}) {
449 template <
typename T,
int n>
452 return make_tensor<n>([&](
int i) {
return dual<T>{x[i], dx[i]}; });
458 template <
typename T,
int m,
int n>
461 return make_tensor<m, n>([&](
int i,
int j) {
return dual<T>{x[i][j], dx[i][j]}; });
473 template <
typename gradient_type,
int n>
477 return make_tensor<n, n>([&](
int i,
int j) {
478 auto value = invA[i][j];
479 gradient_type gradient{};
480 for (
int k = 0; k < n; k++) {
481 for (
int l = 0; l < n; l++) {
482 gradient -= invA[i][k] * A[k][l].gradient * invA[l][j];
493 template <
typename T,
int... n>
496 tensor<double, n...> value{};
497 for_constexpr<n...>([&](
auto... i) { value(i...) = arg(i...).value; });
509 for_constexpr<n...>([&](
auto... i) { g(i...) = arg(i...).gradient; });
514 template <
int... n,
int... m>
517 tensor<double, n..., m...> g{};
518 for_constexpr<n...>([&](
auto... i) { g(i...) = arg(i...).gradient; });
570 template <
typename function,
typename... ParamTypes>
572 ParamTypes... params)
575 double fl = f(lower_bound,
get_value(params)...);
576 double fh = f(upper_bound,
get_value(params)...);
578 SLIC_ERROR_ROOT_IF(fl * fh > 0,
"solve_scalar_equation: root not bracketed by input bounds.");
580 unsigned int iterations = 0;
581 bool converged =
false;
587 }
else if (fh == 0) {
597 double xl = lower_bound;
598 double xh = upper_bound;
605 if (x0 < lower_bound || x0 > upper_bound) {
606 x0 = 0.5 * (lower_bound + upper_bound);
610 double delta_x_old =
std::abs(upper_bound - lower_bound);
611 double delta_x = delta_x_old;
617 if (iterations == options.
max_iter) {
618 SLIC_WARNING(
"solve_scalar_equation failed to converge in allotted iterations.");
623 if ((x - xh) * df_dx - fval > 0 || (x - xl) * df_dx - fval < 0 ||
625 delta_x_old = delta_x;
626 delta_x = 0.5 * (xh - xl);
628 converged = (x == xl);
630 delta_x_old = delta_x;
631 delta_x = fval / df_dx;
634 converged = (x == temp);
664 constexpr
bool contains_duals =
666 if constexpr (contains_duals) {
667 auto [fval, df] = f(x, params...);
668 auto dx = -df / df_dx;
672 if constexpr (!contains_duals) {
673 auto fval = f(x, params...);
675 return tuple{x, status};
691 template <
typename function,
int n>
695 "error: f(x) must have the same number of equations as unknowns");
697 double epsilon = 1.0e-8;
698 int max_iterations = 10;
702 for (
int k = 0; k < max_iterations; k++) {
705 if (
norm(r) < epsilon)
break;
721 template <
typename T,
int size>
726 for (
int i = 0; i <
size; i++) {
727 for (
int j = 0; j <
size; j++) {
729 matA(i, j) = A[i][j].value;
731 matA(i, j) = A[i][j];
737 mfem::DenseMatrixEigensystem eig_sys(matA);
742 for (
int k = 0; k <
size; k++) {
744 output[k] = eig_sys.Eigenvalue(k);
749 auto dA = make_tensor<size, size>([&](
int i,
int j) {
return A(i, j).gradient; });
750 output[k].gradient =
dot(phi, dA, phi);
#define SERAC_HOST_DEVICE
Macro that evaluates to __host__ __device__ when compiling with nvcc and does nothing on a host compi...
This file contains the declaration of a dual number class.
Accelerator functionality.
constexpr SERAC_HOST_DEVICE auto make_dual(double x)
promote a value to a dual number of the appropriate type
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
constexpr SERAC_HOST_DEVICE auto dot(const isotropic_tensor< S, m, m > &I, const tensor< T, m, n... > &A)
dot product between an isotropic and (nonisotropic) tensor
SERAC_HOST_DEVICE auto apply(lambda f, tuple< T... > &args)
a way of passing an n-tuple to a function that expects n separate arguments
constexpr SERAC_HOST_DEVICE auto operator*(const dual< gradient_type > &a, double b)
multiplication of a dual number and a non-dual number
SERAC_HOST_DEVICE auto promote_each_to_dual_when(const tensor< T, n > &x)
a function that optionally (decided at compile time) converts a list of values to their dual types
auto find_root(function &&f, tensor< double, n > x0)
Finds a root of a vector-valued nonlinear function.
constexpr SERAC_HOST_DEVICE auto make_dual_helper(zero)
This is an overloaded member function, provided for convenience. It differs from the above function o...
constexpr auto make_dual_wrt(const serac::tuple< T... > &args)
take a tuple of values, and promote the nth one to a one-hot dual number of the appropriate type
SERAC_HOST_DEVICE auto promote_to_dual_when(const T &x)
a function that optionally (decided at compile time) converts a value to its dual type
constexpr SERAC_HOST_DEVICE int size(const tensor< T, n... > &)
returns the total number of stored values in a tensor
constexpr SERAC_HOST_DEVICE auto linear_solve(const LuFactorization< S, n > &lu_factors, const tensor< T, n, m... > &b)
SERAC_HOST_DEVICE tuple< T... > make_tuple(const T &... args)
helper function for combining a list of values into a tuple
constexpr SERAC_HOST_DEVICE auto get_value(const T &arg)
return the "value" part from a given type. For non-dual types, this is just the identity function
SERAC_HOST_DEVICE auto abs(dual< gradient_type > x)
Implementation of absolute value function for dual numbers.
const ScalarSolverOptions default_solver_options
Default options for solve_scalar_equation.
auto solve_scalar_equation(function &&f, double x0, double lower_bound, double upper_bound, ScalarSolverOptions options, ParamTypes... params)
Solves a nonlinear scalar-valued equation and gives derivatives of solution to parameters.
constexpr SERAC_HOST_DEVICE auto type(const tuple< T... > &values)
a function intended to be used for extracting the ith type from a tuple.
constexpr SERAC_HOST_DEVICE auto norm(const isotropic_tensor< T, m, m > &I)
compute the Frobenius norm (sqrt(tr(dot(transpose(I), I)))) of an isotropic tensor
constexpr SERAC_HOST_DEVICE auto inv(const isotropic_tensor< T, m, m > &I)
return the inverse of an isotropic tensor
constexpr SERAC_HOST_DEVICE LuFactorization< T, n > factorize_lu(const tensor< T, n, n > &A)
Compute LU factorization of a matrix with partial pivoting.
auto eigenvalues(const serac::tensor< T, size, size > &A)
compute the eigenvalues of a symmetric matrix A
typename one_hot< i, n, T >::type one_hot_t
a tuple type with n entries, all of which are of type serac::zero, except for the i^{th} entry,...
constexpr SERAC_HOST_DEVICE auto get_gradient(dual< gradient_type > arg)
return the "gradient" part from a dual number type
constexpr SERAC_HOST_DEVICE auto operator/(const dual< gradient_type > &a, double b)
division of a dual number by a non-dual number
Representation of an LU factorization.
Settings for solve_scalar_equation.
unsigned int max_iter
maximum allowed number of iterations
double xtol
absolute tolerance on Newton correction
double rtol
absolute tolerance on absolute value of residual
Status and diagnostics of nonlinear equation solvers.
bool converged
converged Flag indicating whether solver converged to a solution or aborted.
double residual
Final value of residual.
unsigned int iterations
Number of iterations taken.
Dual number struct (value plus gradient)
double value
the actual numerical value
class for checking if a type is a dual number or not
class for checking if a type is a tensor of dual numbers or not
static constexpr bool value
whether or not type T is a dual number
Arbitrary-rank tensor class.
Type that mimics std::tuple.
Type that mimics std::tuple.
This is a class that mimics most of std::tuple's interface, except that it is usable in CUDA kernels ...
A sentinel struct for eliding no-op tensor operations.
Implementation of the tensor class used by Functional.
Implements a std::tuple-like object that works in CUDA kernels.