Python으로 구현하는 시공간 대수
기하 대수는 선형대수를 매우 멋지게 재정식화한 대안으로, 기하학적 변환과 물리 현상을 표현하는 간결한 체계를 제공합니다. 제가 가장 좋아하는 책 중 하나는 Leo Dorst, Daniel Fontijne, Stephen Mann이 쓴 *컴퓨터 과학을 위한 기하 대수(Geometric Algebra for Computer Science)*입니다. 이 책은 기하 대수를 시각화하는 매우 멋진 환경인 GAViewer라는 언어로 코드를 구현하지만, 저는 개념을 제대로 이해하기 위해 Python으로 직접 구현해 보고 싶었습니다.
- 블레이드(Blades): 기하 대수에서 방향이 있는 부분공간을 나타내는 기본 구성 요소입니다. 예를 들면 다음과 같습니다.
- 스칼라(0-블레이드)는 점입니다.
- 벡터(1-블레이드)는 방향이 있는 직선을 나타냅니다.
- 바이벡터(2-블레이드)는 특정 방향으로 향한 평면 조각을 나타냅니다.
- 멀티벡터(Multivectors): 서로 다른 블레이드의 선형 결합이며, 다양한 기하학적 양을 나타낼 수 있습니다.
서로 다른 블레이드(스칼라, 벡터, 바이벡터)와 멀티벡터를 캡슐화하여 덧셈, 뺄셈, 기하곱 같은 연산을 할 수 있게 하는 클래스 구조를 만들겠습니다.
먼저 기본 블레이드 클래스를 정의해 봅시다.
import numpy as np
class Blade:
def __add__(self, other):
return Multivector([self, other])
def __sub__(self, other):
return Multivector([self, -other])
def __neg__(self):
return -1 * self # Negation
class Scalar(Blade):
def __init__(self, value):
self.value = value
def __repr__(self):
return f"{self.value}"
class Vector(Blade):
def __init__(self, components):
self.components = np.array(components)
def __repr__(self):
return f"Vector({self.components})"
def magnitude(self):
return np.linalg.norm(self.components)
class Bivector(Blade):
def __init__(self, vector1, vector2):
self.vector1 = vector1
self.vector2 = vector2
def __repr__(self):
return f"Bivector({self.vector1}, {self.vector2})"
Multivector 클래스는 블레이드의 임의의 선형 결합을 나타냅니다.
class Multivector:
def __init__(self, blades=[]):
self.blades = blades
def __repr__(self):
return f"Multivector({self.blades})"
def add(self, other):
self.blades.extend(other.blades)
def scale(self, scalar):
for blade in self.blades:
blade.value *= scalar
벡터와 바이벡터에 대해 기하곱 같은 연산을 구현할 수 있습니다. Vector 클래스와 Bivector 클래스 안에 연산을 정의해 봅시다.
class Vector(Blade):
def __init__(self, components):
self.components = np.array(components)
# Other methods as before...
def __or__(self, other):
""" Vector wedge product (bivector) """
return Bivector(self, other)
def __and__(self, other):
""" Scalar product (dot product) """
return Scalar(np.dot(self.components, other.components))
class Bivector(Blade):
def __init__(self, vector1, vector2):
self.vector1 = vector1
self.vector2 = vector2
def __repr__(self):
return f"Bivector({self.vector1}, {self.vector2})"
def dual(self):
""" Returns the dual of a bivector as a vector """
return Vector(np.cross(self.vector1.components, self.vector2.components))
이제 구현한 코드를 사용해 벡터 몇 개를 만들고, 그 곱을 계산하고, 기하 대수의 개념을 시연해 봅시다.
# Create instances of Scalars, Vectors, and Bivectors
s1 = Scalar(5)
v1 = Vector([1, 0, 0])
v2 = Vector([0, 1, 0])
biv = v1 | v2 # Wedge product (Bivector)
# Output representations
print("Scalar:", s1)
print("Vector 1:", v1)
print("Vector 2:", v2)
print("Bivector (v1 wedge v2):", biv)
# Vector dot product
dot_product = v1 & v2
print("Dot Product (v1 · v2):", dot_product)
# Vector wedge product to get a bivector
biv_product = v1 | v2
print("Wedge Product Bivector (v1 ∧ v2):", biv_product)
지금까지 다진 기반 위에서 구현을 시공간 대수(Space-Time Algebra, STA)로 확장할 수 있습니다. STA는 시간을 공간과 나란한 하나의 차원으로 통합하므로, 4차원 맥락(공간 3차원과 시간 1차원)에서 개체와 변환을 표현할 수 있습니다.
STA에서는 시간 벡터라는 개념을 도입하여 공간과 시간 모두에서 사건과 변환을 다룰 수 있습니다. 공간 성분과 시간 성분을 연관 짓기 위해 시간 단위를 정의하겠습니다(상대론적 맥락에서 일관성을 위해 흔히 광속인 로 나타냅니다).
Vector 클래스를 수정하여 시간을 하나의 성분으로 포함하도록 하고, 공간 3차원과 시간 1차원을 아우르는 SpaceTimeVector 클래스를 만들겠습니다.
class SpaceTimeVector(Blade):
def __init__(self, components):
# Expecting components in the form [x, y, z, t]
assert len(components) == 4, "SpaceTimeVector must have four components: [x, y, z, t]."
self.components = np.array(components)
def __repr__(self):
return f"SpaceTimeVector({self.components})"
def magnitude(self):
""" Calculate the Minkowski norm (using (-,+,+,+) signature) """
return np.sqrt(-self.components[3]**2 + np.sum(self.components[:3]**2))
def __add__(self, other):
return SpaceTimeVector(self.components + other.components)
def __sub__(self, other):
return SpaceTimeVector(self.components - other.components)
def __or__(self, other):
""" Wedge product (resulting in a bivector in 3D + time) """
return SpaceTimeBivector(self, other)
def __and__(self, other):
""" Scalar product (dot product, returns a scalar) """
return Scalar(np.dot(self.components, other.components))
SpaceTimeBivector 클래스는 두 SpaceTimeVector 인스턴스의 기하곱을 나타냅니다.
class SpaceTimeBivector(Blade):
def __init__(self, vector1, vector2):
self.vector1 = vector1
self.vector2 = vector2
def __repr__(self):
return f"SpaceTimeBivector({self.vector1}, {self.vector2})"
def dual(self):
""" Returns the dual of a bivector as a SpaceTimeVector """
return SpaceTimeVector(np.cross(self.vector1.components[:3], self.vector2.components[:3]))
이제 SpaceTimeVector의 인스턴스를 만들고 기능을 시연해 봅시다.
# Create space-time vectors
st_vector1 = SpaceTimeVector([1, 2, 3, 4]) # (x, y, z, t)
st_vector2 = SpaceTimeVector([4, 5, 6, 7]) # (x', y', z', t')
print("Space-Time Vector 1:", st_vector1)
print("Space-Time Vector 2:", st_vector2)
st_vector_sum = st_vector1 + st_vector2
print("Sum of Space-Time Vectors:", st_vector_sum)
st_vector_diff = st_vector1 - st_vector2
print("Difference of Space-Time Vectors:", st_vector_diff)
dot_product_st = st_vector1 & st_vector2
print("Dot Product of Space-Time Vectors:", dot_product_st)
# Wedge product to get a space-time bivector
st_bivector = st_vector1 | st_vector2
print("Wedge Product Space-Time Bivector:", st_bivector)
magnitude = st_vector1.magnitude()
print("Magnitude of Space-Time Vector 1:", magnitude)