def _gauss_elimination_3x3(Ab, dt): for i in static(range(3)): max_row = i max_v = ops.abs(Ab[i, i]) for j in static(range(i + 1, 3)): if ops.abs(Ab[j, i]) > max_v: max_row = j max_v = ops.abs(Ab[j, i]) assert max_v != 0.0, "Matrix is singular in linear solve." if i != max_row: if max_row == 1: for col in static(range(4)): Ab[i, col], Ab[1, col] = Ab[1, col], Ab[i, col] else: for col in static(range(4)): Ab[i, col], Ab[2, col] = Ab[2, col], Ab[i, col] assert Ab[i, i] != 0.0, "Matrix is singular in linear solve." for j in static(range(i + 1, 3)): scale = Ab[j, i] / Ab[i, i] Ab[j, i] = 0.0 for k in static(range(i + 1, 4)): Ab[j, k] -= Ab[i, k] * scale # Back substitution x = Vector.zero(dt, 3) for i in static(range(2, -1, -1)): x[i] = Ab[i, 3] for k in static(range(i + 1, 3)): x[i] -= Ab[i, k] * x[k] x[i] = x[i] / Ab[i, i] return x
def _gauss_elimination_2x2(Ab, dt): if ops.abs(Ab[0, 0]) < ops.abs(Ab[1, 0]): Ab[0, 0], Ab[1, 0] = Ab[1, 0], Ab[0, 0] Ab[0, 1], Ab[1, 1] = Ab[1, 1], Ab[0, 1] Ab[0, 2], Ab[1, 2] = Ab[1, 2], Ab[0, 2] assert Ab[0, 0] != 0.0, "Matrix is singular in linear solve." scale = Ab[1, 0] / Ab[0, 0] Ab[1, 0] = 0.0 for k in static(range(1, 3)): Ab[1, k] -= Ab[0, k] * scale x = Vector.zero(dt, 2) # Back substitution x[1] = Ab[1, 2] / Ab[1, 1] x[0] = (Ab[0, 2] - Ab[0, 1] * x[1]) / Ab[0, 0] return x
def sym_eig3x3(A, dt): """Compute the eigenvalues and right eigenvectors (Av=lambda v) of a 3x3 real symmetric matrix using Cardano's method. Mathematical concept refers to https://www.mpi-hd.mpg.de/personalhomes/globes/3x3/. Args: A (ti.Matrix(3, 3)): input 3x3 symmetric matrix `A`. dt (DataType): date type of elements in matrix `A`, typically accepts ti.f32 or ti.f64. Returns: eigenvalues (ti.Vector(3)): The eigenvalues. Each entry store one eigen value. eigenvectors (ti.Matrix(3, 3)): The eigenvectors. Each column stores one eigenvector. """ M_SQRT3 = 1.73205080756887729352744634151 m = A.trace() dd = A[0, 1] * A[0, 1] ee = A[1, 2] * A[1, 2] ff = A[0, 2] * A[0, 2] c1 = A[0, 0] * A[1, 1] + A[0, 0] * A[2, 2] + A[1, 1] * A[2, 2] - (dd + ee + ff) c0 = A[2, 2] * dd + A[0, 0] * ee + A[1, 1] * ff - A[0, 0] * A[1, 1] * A[ 2, 2] - 2.0 * A[0, 2] * A[0, 1] * A[1, 2] p = m * m - 3.0 * c1 q = m * (p - 1.5 * c1) - 13.5 * c0 sqrt_p = ops.sqrt(ops.abs(p)) phi = 27.0 * (0.25 * c1 * c1 * (p - c1) + c0 * (q + 6.75 * c0)) phi = (1.0 / 3.0) * ops.atan2(ops.sqrt(ops.abs(phi)), q) c = sqrt_p * ops.cos(phi) s = (1.0 / M_SQRT3) * sqrt_p * ops.sin(phi) eigenvalues = Vector([0.0, 0.0, 0.0], dt=dt) eigenvalues[2] = (1.0 / 3.0) * (m - c) eigenvalues[1] = eigenvalues[2] + s eigenvalues[0] = eigenvalues[2] + c eigenvalues[2] = eigenvalues[2] - s t = ops.abs(eigenvalues[0]) u = ops.abs(eigenvalues[1]) if u > t: t = u u = ops.abs(eigenvalues[2]) if u > t: t = u if t < 1.0: u = t else: u = t * t Q = Matrix.zero(dt, 3, 3) Q[0, 1] = A[0, 1] * A[1, 2] - A[0, 2] * A[1, 1] Q[1, 1] = A[0, 2] * A[0, 1] - A[1, 2] * A[0, 0] Q[2, 1] = A[0, 1] * A[0, 1] Q[0, 0] = Q[0, 1] + A[0, 2] * eigenvalues[0] Q[1, 0] = Q[1, 1] + A[1, 2] * eigenvalues[0] Q[2, 0] = (A[0, 0] - eigenvalues[0]) * (A[1, 1] - eigenvalues[0]) - Q[2, 1] norm = Q[0, 0] * Q[0, 0] + Q[1, 0] * Q[1, 0] + Q[2, 0] * Q[2, 0] norm = ops.sqrt(1.0 / norm) Q[0, 0] *= norm Q[1, 0] *= norm Q[2, 0] *= norm Q[0, 1] = Q[0, 1] + A[0, 2] * eigenvalues[1] Q[1, 1] = Q[1, 1] + A[1, 2] * eigenvalues[1] Q[2, 1] = (A[0, 0] - eigenvalues[1]) * (A[1, 1] - eigenvalues[1]) - Q[2, 1] norm = Q[0, 1] * Q[0, 1] + Q[1, 1] * Q[1, 1] + Q[2, 1] * Q[2, 1] norm = ops.sqrt(1.0 / norm) Q[0, 1] *= norm Q[1, 1] *= norm Q[2, 1] *= norm Q[0, 2] = Q[1, 0] * Q[2, 1] - Q[2, 0] * Q[1, 1] Q[1, 2] = Q[2, 0] * Q[0, 1] - Q[0, 0] * Q[2, 1] Q[2, 2] = Q[0, 0] * Q[1, 1] - Q[1, 0] * Q[0, 1] return eigenvalues, Q
def __abs__(self): return ops.abs(self)