Skip to content

Instantly share code, notes, and snippets.

@garrett361
Created August 16, 2025 15:47
Show Gist options
  • Select an option

  • Save garrett361/bb26470d1580d3483d42d9003c947229 to your computer and use it in GitHub Desktop.

Select an option

Save garrett361/bb26470d1580d3483d42d9003c947229 to your computer and use it in GitHub Desktop.
block decomposition test
R=tensor([[ 0.0673+0.j, -0.6867+0.j, 0.7238+0.j],
[-0.4553+0.j, -0.6666+0.j, -0.5901+0.j],
[ 0.8878+0.j, -0.2899+0.j, -0.3575+0.j]])
[email protected]=tensor([[ 1.0000e+00+0.j, -2.7138e-08+0.j, -2.7308e-08+0.j],
[-2.7138e-08+0.j, 1.0000e+00+0.j, -3.7264e-08+0.j],
[-2.9802e-08+0.j, -4.4703e-08+0.j, 1.0000e+00+0.j]])
eigvals=tensor([ 1.0000+1.4901e-08j, -0.9785+2.0648e-01j, -0.9785-2.0648e-01j])
eigvecs=tensor([[ 0.7270+0.0000e+00j, 0.2224+4.3161e-01j, 0.2224-4.3161e-01j],
[-0.3970+2.0183e-08j, 0.6490+0.0000e+00j, 0.6490+0.0000e+00j],
[ 0.5602-1.7749e-08j, 0.1713-5.6010e-01j, 0.1713+5.6010e-01j]])
R_decomp=tensor([[ 0.0673+2.7293e-08j, -0.6867-1.4903e-08j, 0.7238+2.1031e-08j],
[-0.4553+1.2540e-08j, -0.6666-6.8474e-09j, -0.5901+9.6627e-09j],
[ 0.8878-7.1945e-09j, -0.2899+3.9287e-09j, -0.3575-5.5440e-09j]])
C@C_inv=tensor([[ 1.0000e+00-1.2761e-15j, 9.7942e-09-4.0148e-16j,
1.2013e-08+3.6714e-16j],
[-7.1361e-09+0.0000e+00j, 1.0000e+00+0.0000e+00j,
-1.3310e-08+0.0000e+00j],
[-2.9802e-08+1.7764e-15j, -1.2653e-16+0.0000e+00j,
1.0000e+00+8.8818e-16j]])
[email protected]=tensor([[ 0.7643+0.0000e+00j, -0.1443+1.4674e-08j, 0.2036-1.2904e-08j],
[-0.1443+1.4674e-08j, 0.5788-1.6025e-08j, -0.1112+1.8354e-08j],
[ 0.2036-1.2904e-08j, -0.1112+1.8354e-08j, 0.6569-1.9887e-08j]])
[email protected] / ([email protected])[0, 0]=tensor([[ 1.0000+0.0000e+00j, -0.1888+1.9199e-08j, 0.2665-1.6884e-08j],
[-0.1888+1.9199e-08j, 0.7573-2.0968e-08j, -0.1455+2.4014e-08j],
[ 0.2665-1.6884e-08j, -0.1455+2.4014e-08j, 0.8595-2.6021e-08j]])
[Process exited 0]
import math
import torch
# https://en.wikipedia.org/wiki/Rotation_matrix
def get_3d_rotation_matrix(
theta_x: float, theta_y: float, theta_z: float
) -> torch.Tensor:
R_x = torch.tensor(
[
[1, 0, 0],
[0, math.cos(theta_x), -math.sin(theta_x)],
[0, math.sin(theta_x), math.cos(theta_x)],
],
dtype=torch.complex64,
)
R_y = torch.tensor(
[
[math.cos(theta_y), 0, math.sin(theta_y)],
[0, 1, 0],
[-math.sin(theta_y), 0, math.cos(theta_y)],
],
dtype=torch.complex64,
)
R_z = torch.tensor(
[
[math.cos(theta_z), -math.sin(theta_z), 0],
[math.sin(theta_z), math.cos(theta_z), 0],
[0, 0, 1],
],
dtype=torch.complex64,
)
return R_x @ R_y @ R_z
if __name__ == "__main__":
torch.manual_seed(42)
R = get_3d_rotation_matrix(*(2 * math.pi * torch.randn(3)))
print(f"{R=}\n")
# Verify in SO(3)
print(f"{[email protected]=}\n")
torch.testing.assert_close(R @ R.T, torch.eye(3, dtype=torch.complex64))
eigvals, eigvecs = torch.linalg.eig(R)
print(f"{eigvals=}\n")
print(f"{eigvecs=}\n")
for val, vec in zip(eigvals, eigvecs.T):
torch.testing.assert_close(R @ vec, val * vec)
# Build out the block diagonal decmoposition. The first
B = torch.tensor(
[
[torch.real(eigvals[1]), torch.imag(eigvals[1]), 0],
[-torch.imag(eigvals[1]), torch.real(eigvals[1]), 0],
[0, 0, eigvals[0]],
],
dtype=torch.complex64,
)
C = torch.stack(
[torch.real(eigvecs.T[1]), torch.imag(eigvecs.T[1]), eigvecs.T[0]], dim=-1
)
C_inv = torch.linalg.inv(C)
R_decomp = C @ B @ C_inv
# Verify decomposition
print(f"{R_decomp=}\n")
torch.testing.assert_close(R_decomp, R)
# Check if C is orthogonal
print(f"{C@C_inv=}\n")
print(f"{[email protected]=}\n")
# Also print with the [0, 0] component normalized to one, since C is only defined up to C -->
# lamba * C and C_inv --> C / lambda
print(f"{[email protected] / ([email protected])[0, 0]=}\n")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment