Source code for tensortrax.math.special._special_tensor
"""
tensorTRAX: Math on (Hyper-Dual) Tensors with Trailing Axes.
"""
import numpy as np
from ..._helpers import Δ, Δδ, f, δ
from ..._tensor import Tensor
from .. import _math_array as array
from .._math_tensor import einsum, sqrt, stack, trace, transpose
from ..linalg import _linalg_tensor as linalg
def ddot(A, B):
return einsum("ij...,ij...->...", A, B)
[docs]
def dev(A):
"Deviatoric part of a Tensor."
dim = A.shape[0]
return A - trace(A) / dim * array.eye(A)
[docs]
def erf(z):
"The (Gauss) error function."
from scipy.special import erf
if isinstance(z, Tensor):
derf = 2 / np.sqrt(np.pi) * np.exp(-f(z) ** 2)
return Tensor(
x=erf(f(z)),
δx=derf * δ(z),
Δx=derf * Δ(z),
Δδx=-2 * f(z) * derf * δ(z) * Δ(z) + derf * Δδ(z),
ntrax=z.ntrax,
)
else:
return erf(z)
[docs]
def sym(A):
"Symmetric part of a Tensor."
return (A + transpose(A)) / 2
[docs]
def tresca(A):
"Tresca Invariant."
λ = linalg.eigvalsh(A)
return (λ[-1] - λ[0]) / 2
[docs]
def von_mises(A):
"Von Mises Invariant."
a = dev(A)
return sqrt(3 / 2 * ddot(a, a))
[docs]
def triu_1d(A):
"Flattened upper triangle entries of a Tensor."
return A[np.triu_indices(A.shape[0])]
def _from_triu_helper(A):
"Helper to recover full Tensor from upper triangle entries of a Tensor."
# length of triu-entries
# size_from_dim = [0, 1, 3, 6]
# size_from_dim[2] = 3
# size_from_dim[3] = 6
# ...
size_from_dim = np.array(
[len(np.triu_indices(d)[0]) for d in np.arange(4)], dtype=int
)
size = A.shape[0]
dim = np.where(size_from_dim == size)[0][0]
idx = np.zeros((dim, dim), dtype=int)
idx.T[np.triu_indices(dim)] = idx[np.triu_indices(dim)] = np.arange(size)
return idx, dim
[docs]
def from_triu_1d(A, like=None):
"Recover full Tensor from upper triangle entries of a Tensor."
idx, dim = _from_triu_helper(A)
out = sym(A[idx.ravel()].reshape(dim, dim, *A.shape[1:]))
if like is not None:
axes = len(out.shape)
if isinstance(A, Tensor):
axes += out.ntrax
if axes < (len(like.shape) + like.ntrax):
ones = np.ones(like.ndual, dtype=int)
out = out.reshape(dim, dim, *ones, *like.trax)
return out
[docs]
def from_triu_2d(A):
"Recover full Tensor from upper triangle entries of a Tensor."
idx, dim = _from_triu_helper(A)
return A[idx.ravel()][:, idx.ravel()].reshape(dim, dim, dim, dim, *A.shape[2:])
[docs]
def try_stack(arrays, fallback=None):
"""Try to unpack and stack the list of tensors/arrays and return the fallback array
otherwise."""
try:
return stack(
[A.x if isinstance(A, Tensor) else A for ary in arrays for A in ary]
)
except ValueError:
return fallback