단순 덧셈 연산가능한 2차원 벡터 만들기
2d 벡터니 x, y만 가짐
덧셈 연산 구현
class Vec2():
def __init__(self, x, y):
self.x = x
self.y = y
def add(self, v2):
return Vec2(self.x + v2.x, self.y + v2.y)
v = Vec2(3, 4)
w = v.add(Vec2(-2, 6))
print(w.x, w.y)
2차원 벡터에 스칼라곱, 동등 비교연산 추가
스칼라 곱, 비교 연산, 덧셈 연산 추가후
벡터와 스칼라간 곱 + 덧셈 연산 결과 repr이 없어주소가 반환됨
class Vec2():
def __init__(self, x, y):
self.x = x
self.y = y
def add(self, v2):
return Vec2(self.x + v2.x, self.y + v2.y)
def scale(self, scalar):
return Vec2(scalar * self.x, scalar * self.y)
def __eq__(self, other_vec : Vec2):
return self.x == other_vec.x and self.y == other_vec.y
def __add__(self, other_vec : Vec2):
return self.add(other_vec)
def __mul__(self, scalar):
return self.scale(scalar)
def __rmul__(self, scalar):
return self.scale(scalar)
2 * Vec2(2, 0) + 5 * Vec2(0, 2)
2d 벡터 repr 추가
2d 벡터 출력시 원하는 형태로 안나오고 주소가 나옴
repr 작성해서 잘 나오도록 수정
class Vec2():
def __init__(self, x, y):
self.x = x
self.y = y
def add(self, v2):
return Vec2(self.x + v2.x, self.y + v2.y)
def scale(self, scalar):
return Vec2(scalar * self.x, scalar * self.y)
def __eq__(self, other_vec : Vec2):
return self.x == other_vec.x and self.y == other_vec.y
def __add__(self, other_vec : Vec2):
return self.add(other_vec)
def __mul__(self, scalar):
return self.scale(scalar)
def __rmul__(self, scalar):
return self.scale(scalar)
def __repr__(self):
return "Vec2({},{})".format(self.x, self.y)
2 * Vec2(2, 0) + 5 * Vec2(0, 2)
3차원 벡터 정의하기
2d 때랑 거의 비슷, z만 추가
class Vec3():
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def add(self, v2):
return Vec3(self.x + v2.x, self.y + v2.y, self.z + v2.z)
def scale(self, scalar):
return Vec3(self.x * scalar, self.y * scalar, self.z * scalar)
def __add__(self, v2):
return self.add(v2)
def __eq__(self, v2):
return self.x == v2.x and self.y == v2.y and self.z == v2.z
def __mul__(self, scalar):
return self.scale(scalar)
def __rmul__(self, scalar):
return self.scale(scalar)
def __repr__(self):
return "Vec3({},{},{})".format(self.x, self.y, self.z)
2.0 * (Vec3(1, 0, 0) + Vec3(0, 1, 0))
메타 클래스 Vector를 만들고, 상속받는 클래스 vec2 정의하기
메타 클래스 Vector에선 vec2. vec3 둘다 __mul__, __add__ 같은 연산자 함수 포함되므로 다음과 같이 정의
실제 add, scale 수행되는 과정은 vec2와 vec3은 다르므로 추상 메서드로 비워둠
추가로 차연산은 + (우측 값 x -1)을 하면 되므로 구현
메타 클래스 Vector를 상속받는 Vec2를 구현하면서
산술 함수는 이미 Vector에서 구현했으므로 안해도되고,
실제 산술 동작 add, scale과 기타 필요한 함수들 구현해주면 됨
from abc import ABCMeta, abstractmethod
class Vector(metaclass=ABCMeta):
@abstractmethod
def scale(self, scalar):
pass
@abstractmethod
def add(self, toher):
pass
def __mul__(self, scalar):
return self.scale(scalar)
def __rmul__(self, scalar):
return self.scale(scalar)
def __add__(self, other):
return self.add(other)
def subtract(self, other):
return self.add(-1 * other)
def __sub__(self, other):
return self.subtract(other)
class Vec2(Vector):
def __init__(self, x, y):
self.x = x
self.y = y
def add(self, other):
return Vec2(self.x + other.x, self.y + other.y)
def scale(self, scalar):
return Vec2(self.x * scalar, self.y * scalar)
def __eq__(self, other):
return self.x == other.x and self.y == other.y and self.z == other.z
def __repr__(self):
return "Vec2({},{})".format(self.x, self.y)
Vec2(5, 5) - Vec2(1, 3)
메타클래스로 vec3 만들기
구현 과정은 방금 한 vec2랑 같음, z 내용만 추가
class Vec3(Vector):
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def add(self, other):
return Vec3(self.x + other.x, self.y + other.y, self.z + other.z)
def scale(self, scalar):
return Vec3(self.x * scalar, self.y * scalar, self.z * scalar)
def __eq__(self, other):
return self.x == other.x and self.y == other.y and self.z == other.z
def __repr__(self):
return "Vec3({},{},{})".format(self.x, self.y, self.z)
vec3 = Vec3(3, 2, 1) * 3
print(vec3)
좌표 벡터 만들기
지금까지 2, 3차원 벡터 다루는 클래스를 만들었지만 상위 차원을 다룰수 있도록 좌표 벡터를 만들면
__init__ coordinates를 가변인자로 받아 저장
add와 scale도 구현. 실제 내용은 vectors.py에 이런식으로 구현되있음
def add(*vectors):
return tuple(map(sum,zip(*vectors)))
def scale(scalar,v):
return tuple(scalar * coord for coord in v)
repr도 출력 형태도 구현
추상 프로퍼티와 추상 메서드 차이는 프로퍼티는 값. 추상 메서드는 동작 의미
from abc import abstractproperty
from vectors import add, scale
class CoordinateVector(Vector):
@abstractproperty
def dimension(self):
pass
def __init__(self, *coordinates):
self.coordinates = tuple(x for x in coordinates)
def add(self, other):
return self.__class__(*add(self.coordinates, other.coordinates))
def scale(self, scalar):
return self.__class__(*scale(scalar, self.coordinates))
def __repr__(self):
return "{}{}".format(self.__class__.__qualname__, self.coordinates)
좌표벡터 상속받는 vec6만들기
이미 좌표 벡터에서 내용 대부분 구현되있어서 이건 간단
추상 프로퍼티로 설정한 dimension만 구현해주면 된다.
print vec6하면 repr대로 출력
print vec6.coordinates는 튜플
print vec6.dimension은 인트값 6
덧셈 연산도 vectors.py에 구현된 add 대로 잘 동작
class Vec6(CoordinateVector):
def dimension(self):
return 6
print(Vec6(1, 1, 1, 1, 4, 5))
print(Vec6(1, 1, 1, 1, 4, 5).coordinates)
print(Vec6(1, 1, 1, 1, 4, 5).dimension())
Vec6(1, 1, 1, 1, 4, 5) + Vec6(1, 2, 3, 4, 5, 6)
영벡터를 추상 프로퍼티로 갖는 메타 클래스 벡터 만들기
지난번에 만든 벡터에 추상 프로퍼티로 추가해주면 됨
추가로 scale을 이용한 neg 연산도 추가
class Vector(metaclass=ABCMeta):
@abstractmethod
def scale(self, scalar):
pass
@abstractmethod
def add(self, other):
pass
def __add__(self, other):
return self.add(other)
def __mul__(self, scalar):
return self.scale(scalar)
def __rmul__(self, scalar):
return self.scale(scalar)
def substract(self, other):
return self.add(-1 * other)
def __sub__(self, other):
return self.substract(other)
@classmethod
@abstractproperty
def zero():
pass
def __neg__(self):
return self.scale(-1)
추상 프로퍼티 zero를 구현한 Vec2 만들기
기존의 vec2에다가 추상 프로퍼티 zero(영벡터 반환)를 구현
메타클레스에서 __neg__ 구현한 덕분에 -Vec2 연산이 가능해짐
class Vec2(Vector):
def __init__(self, x, y):
self.x = x
self.y = y
def scale(self, scalar):
return Vec2(self.x * scalar, self.y * scalar)
def add(self, other):
return Vec2(self.x + other.x, self.y + other.y)
def zero():
return Vec2(0, 0)
def __repr__(self):
return "Vec2({},{})".format(self.x, self.y)
def __eq__(self, other):
return self.x == other.x and self.y == other.y
print(Vec2.zero())
-Vec2(3, -4)
덧셈, 같은지 연산 전에 클래스 타입 확인하기
이전에 구현한 코드들은 vec2(1, 2) == vec3(1, 2, 3)은 같다로 반환하므로
덧셈, 같음 연산전에 클래스 타입 확인하도록 수정이 필요
add와 eq 리턴 전에 assert 해주면 됨
같은 클래스면 문제없이 동작하지만 다르면 assertion error 발생
class Vec2(Vector):
def __init__(self, x, y):
self.x = x
self.y = y
def add(self, other):
assert self.__class__ == other.__class__
return Vec2(self.x + other.x, self.y + other.y)
def scale(self, scalar):
return Vec2(self.x * scalar, self.y *scalar)
def __eq__(self, other):
assert self.__class__ == other.__class__
return self.x == other.x and self.y == other.y
def __repr__(self):
return "Vec2({},{})".format(self.x, self.y)
def zero(self):
return Vec2(0, 0)
print(Vec2(1, 2) == Vec2(1, 1))
print(Vec2(1, 2) + Vec2(3, 2))
Vec2(1, 2) == Vec3(1, 1, 1)
Vec2(1, 2) + Vec3(1, 1, 1)
메타클레스 벡터에 나누기 추가하기
추상 메서드로 덧셈, 스케일
추상 프로퍼티로 제로
그외는 덧셈, 그냥곱, 우측곱, 빼기, 부정 구현
추가된 나누기는 1.0/scalar를 곱하는 형태로 구현
class Vector(metaclass=ABCMeta):
@abstractmethod
def add(self, other):
pass
@abstractmethod
def scale(self, scalar):
pass
def __add__(self, other):
return self.add(other)
def __mul__(self, scalar):
return self.scale(scalar)
def __rmul__(self, scalar):
return self.scale(scalar)
def substract(self, other):
return self.add(-1 * other)
def __sub__(self, other):
return self.substract(other)
@classmethod
@abstractproperty
def zero():
pass
def __neg__(self):
return self.scale(-1)
def __truediv__(self, scalar):
return self.scale(1.0/scalar)
나눗셈 추가된 vec2 나누기 연산
나눗셈 연산은 vector에 추가되서 vec2에선 고칠게 없음
그냥 그대로 나눠보면 결과나옴
class Vec2(Vector):
def __init__(self, x, y):
self.x = x
self.y = y
def add(self, other):
assert self.__class__ == other.__class__
return Vec2(self.x + other.x and self.y + other.y)
def __eq__(self, other):
assert self.__class__ == other.__class__
return self.x == other.x and self.y == other.y
def scale(self, scalar):
return Vec2(scalar * self.x, scalar * self.y)
def zero():
return Vec2(0, 0)
def __repr__(self):
return "Vec2({},{})".format(self.x, self.y)
print(Vec2(2, 3)/2)
1차원 벡터 정의하기
2차원 벡터때보다 더단순하다
class Vec1(Vector):
def __init__(self, x):
self.x = x
def add(self, other):
assert self.__class__ == other.__class__
return Vec1(self.x + other.x)
def __eq__(self, other):
assert self.__class__ == other.__class__
return self.x == other.x
def scale(self, scalar):
return Vec1(self.x * scalar)
@classmethod
def zero(cls):
return Vec1(0)
def __repr__(self):
return "Vec1({})".format(self.x)
vec1_1 = Vec1(3)
vec1_2 = Vec1(5)
print(vec1_1)
print(vec1_1 * 3)
print(-vec1_2)
print(vec1_1/4)
print(Vec1.zero())
0벡터 다루기
담는 값이 없어서 더 단순
class Vec0(Vector):
def __init__(self):
pass
def add(self, other):
return Vec0()
def scale(self, scalar):
return Vec0()
def __eq__(self, other):
return self.__class__ == other.__class__ == Vec0
def __repr__(self):
return "Vec0()"
@classmethod
def zero(cls):
return Vec0()
print(-3.14 * Vec0())
print(Vec0() + Vec0() + Vec0())
'컴퓨터과학 > 응용수학' 카테고리의 다른 글
파이썬수학 - 6. 변화율기초 (0) | 2023.09.29 |
---|---|
파이썬수학 - 5.게임과 연립일차식 풀기 (0) | 2023.09.25 |
파이썬수학 - 3. 선형변환 (0) | 2023.09.24 |
파이썬수학 - 2. 3차원 다루기 (0) | 2023.09.23 |
파이썬수학 - 1. 2차원 드로잉 (0) | 2023.09.23 |