def sym_eig2x2(A, dt): """Compute the eigenvalues and right eigenvectors (Av=lambda v) of a 2x2 real symmetric matrix. Mathematical concept refers to https://en.wikipedia.org/wiki/Eigendecomposition_of_a_matrix. Args: A (ti.Matrix(2, 2)): input 2x2 symmetric matrix `A`. dt (DataType): date type of elements in matrix `A`, typically accepts ti.f32 or ti.f64. Returns: eigenvalues (ti.Vector(2)): The eigenvalues. Each entry store one eigen value. eigenvectors (ti.Matrix(2, 2)): The eigenvectors. Each column stores one eigenvector. """ tr = A.trace() det = A.determinant() gap = tr**2 - 4 * det lambda1 = (tr + ops.sqrt(gap)) * 0.5 lambda2 = (tr - ops.sqrt(gap)) * 0.5 eigenvalues = Vector([lambda1, lambda2], dt=dt) A1 = A - lambda1 * Matrix.identity(dt, 2) A2 = A - lambda2 * Matrix.identity(dt, 2) v1 = Vector.zero(dt, 2) v2 = Vector.zero(dt, 2) if all(A1 == Matrix.zero(dt, 2, 2)) and all(A1 == Matrix.zero(dt, 2, 2)): v1 = Vector([0.0, 1.0]).cast(dt) v2 = Vector([1.0, 0.0]).cast(dt) else: v1 = Vector([A2[0, 0], A2[1, 0]], dt=dt).normalized() v2 = Vector([A1[0, 0], A1[1, 0]], dt=dt).normalized() eigenvectors = Matrix.cols([v1, v2]) return eigenvalues, eigenvectors
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 eig2x2(A, dt): """Compute the eigenvalues and right eigenvectors (Av=lambda v) of a 2x2 real matrix. Mathematical concept refers to https://en.wikipedia.org/wiki/Eigendecomposition_of_a_matrix. Args: A (ti.Matrix(2, 2)): input 2x2 matrix `A`. dt (DataType): date type of elements in matrix `A`, typically accepts ti.f32 or ti.f64. Returns: eigenvalues (ti.Matrix(2, 2)): The eigenvalues in complex form. Each row stores one eigenvalue. The first number of the eigenvalue represents the real part and the second number represents the imaginary part. eigenvectors: (ti.Matrix(4, 2)): The eigenvectors in complex form. Each column stores one eigenvector. Each eigenvector consists of 2 entries, each of which is represented by two numbers for its real part and imaginary part. """ tr = A.trace() det = A.determinant() gap = tr**2 - 4 * det lambda1 = Vector.zero(dt, 2) lambda2 = Vector.zero(dt, 2) v1 = Vector.zero(dt, 4) v2 = Vector.zero(dt, 4) if gap > 0: lambda1 = Vector([tr + ops.sqrt(gap), 0.0], dt=dt) * 0.5 lambda2 = Vector([tr - ops.sqrt(gap), 0.0], dt=dt) * 0.5 A1 = A - lambda1[0] * Matrix.identity(dt, 2) A2 = A - lambda2[0] * Matrix.identity(dt, 2) if all(A1 == Matrix.zero(dt, 2, 2)) and all( A1 == Matrix.zero(dt, 2, 2)): v1 = Vector([0.0, 0.0, 1.0, 0.0]).cast(dt) v2 = Vector([1.0, 0.0, 0.0, 0.0]).cast(dt) else: v1 = Vector([A2[0, 0], 0.0, A2[1, 0], 0.0], dt=dt).normalized() v2 = Vector([A1[0, 0], 0.0, A1[1, 0], 0.0], dt=dt).normalized() else: lambda1 = Vector([tr, ops.sqrt(-gap)], dt=dt) * 0.5 lambda2 = Vector([tr, -ops.sqrt(-gap)], dt=dt) * 0.5 A1r = A - lambda1[0] * Matrix.identity(dt, 2) A1i = -lambda1[1] * Matrix.identity(dt, 2) A2r = A - lambda2[0] * Matrix.identity(dt, 2) A2i = -lambda2[1] * Matrix.identity(dt, 2) v1 = Vector([A2r[0, 0], A2i[0, 0], A2r[1, 0], A2i[1, 0]], dt=dt).normalized() v2 = Vector([A1r[0, 0], A1i[0, 0], A1r[1, 0], A1i[1, 0]], dt=dt).normalized() eigenvalues = Matrix.rows([lambda1, lambda2]) eigenvectors = Matrix.cols([v1, v2]) return eigenvalues, eigenvectors
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