행렬의 아다마르 곱
📂행렬대수행렬의 아다마르 곱
정의
두 행렬 A,B∈Mm×n의 아다마르 곱Hadamard product A⊙B를 다음과 같이 정의한다.
A⊙B=a11⋮am1⋯⋱⋯a1n⋮amn⊙b11⋮bm1⋯⋱⋯b1n⋮bmn:=a11b11⋮am1bm1⋯⋱⋯a1nb1n⋮amnbmn
[A⊙B]ij:=[A]ij[B]ij
설명
⊙의 TEX 코드는 \odot
이다.
성분별 곱elementwise product이라고도 많이 부른다. 행렬 곱과는 다르게, 크기가 같아야 정의되고 교환법칙도 성립한다.
- A⊙B=B⊙A
- (A⊙B)⊙C=A⊙(B⊙C)
- A⊙(B+C)=A⊙B+A⊙C
- k(A⊙B)=(kA)⊙B=A⊙(kB)
벡터의 아다마르 곱
두 벡터 x, y∈Rn의 아다마르 곱을 다음과 같이 정의한다.
x⊙y=x1y1⋮xnyn
정의 자체는 행렬의 아다마르 곱에서 n×1 행렬에 대한 특별한 경우이다. 대각행렬에 대해서 다음과 같은 식이 성립한다.
x⊙y=diag(x)y=diag(y)x
벡터와 행렬의 아다마르 곱
벡터 x∈Rn와 행렬 Y=∣y1∣⋯∣yn∣사이의 아다마르 곱을 다음과 같이 정의한다.
x⊙Y=∣x⊙y1∣⋯∣x⊙yn∣
쉽게 말해서 행렬의 각 열에 벡터와의 아다마르 곱을 취하는 것이다. 정의로부터 바로 아래의 식을 얻는다.
x⊙Y=diag(x)Y
위의 두 정의를 보면 벡터 x에 대해서 x⊙ 자체를 x⊙:=diag(x)인 행렬이라고 정의해도 무리없음을 알 수 있다.
프로그래밍 언어에서
이와 같은 성분별pointwise 연산은 기존의 연산에 점point .
을 추가하는 식으로 구현되어있다. 이러한 표기는 굉장히 직관적인데, 가령 곱셈이 *
라면 점별 곱셈은 .*
이다.
줄리아
julia> A = [1 2 3; 4 5 6]
2×3 Matrix{Int64}:
1 2 3
4 5 6
julia> B = [2 2 2; 2 2 2]
2×3 Matrix{Int64}:
2 2 2
2 2 2
julia> A.*B
2×3 Matrix{Int64}:
2 4 6
8 10 12
매트랩
>> A = [1 2 3; 4 5 6]
A =
1 2 3
4 5 6
>> B = [2 2 2; 2 2 2]
B =
2 2 2
2 2 2
>> A.*B
ans =
2 4 6
8 10 12
다만 파이썬의 경우 과학계산을 위한 언어가 아니기 때문에 줄리아나 매트랩과 같이 구현되어있지않다. 곱셈 기호 *
가 성분별 곱셈을 의미하고, 행렬곱은 @
로 쓴다.
>>> import numpy
>>> A = np.array([[1, 2, 3], [4, 5, 6]])
>>> B = np.array([[2, 2, 2], [2, 2, 2]])
>>> A*B
array([[ 2, 4, 6],
[ 8, 10, 12]])
>>> import torch
>>> A = torch.tensor([[1, 2, 3],[4, 5, 6]])
>>> B = torch.tensor([[2, 2, 2],[2, 2, 2]])
>>> A*B
tensor([[ 2, 4, 6],
[ 8, 10, 12]])