본문으로 건너뛰기
2023. 2. 19·약 7분

행렬의 기본 연산과 곱셈 코딩 테스트

대괄호 안에서 3x3 파란 행렬과 3x3 분홍 행렬이 곱셈 기호를 사이에 두고 마주 보는 그림

들어가며​

행렬(Matrix)은 그래픽 처리, 데이터 분석, 머신러닝, 게임 개발 등에 쓰이며 코딩 테스트에도 등장합니다. 코드에서는 주로 2차원 배열로 표현하므로 행과 열을 순회하는 연습에도 알맞습니다. 이 글에서는 행렬의 종류와 기본 연산을 정리한 뒤 JavaScript로 행렬 곱셈을 구현합니다.



기본 용어​

행렬(matrix)은 숫자 또는 문자를 직사각형 형태로 배열한 것입니다. 가로줄을 행(row), 세로줄을 열(column) 이라고 합니다.

예시:

[132517]\begin{bmatrix} 1 & 3 & 2 \\ 5 & 1 & 7 \end{bmatrix}

위 행렬은 2×32 \times 3 행렬이라고 하며, 77은 (2,3)(2,3) 성분입니다.

행렬 표기​

행렬은 일반적으로 다음과 같이 나타냅니다.

A=[a11a12a13a21a22a23]A = \begin{bmatrix} a_{11} & a_{12} & a_{13} \\ a_{21} & a_{22} & a_{23} \end{bmatrix}

각 성분은 aija_{ij} 형태로 표기합니다.

[35−17]\begin{bmatrix} 3 & 5 \\ -1 & 7 \end{bmatrix}

위 행렬은 2×22 \times 2 행렬 또는 2차 정사각 행렬(square matrix) 입니다.



행렬의 종류​

전치 행렬 (Transpose Matrix)​

전치 행렬(transpose matrix)은 원래 행렬의 행과 열을 바꾼 행렬입니다. 보통 A⊤A^{\top} 또는 ATA^T로 표기합니다.

예시:

A=[124537]⇒AT=[152347]A = \begin{bmatrix} 1 & 2 & 4 \\ 5 & 3 & 7 \end{bmatrix} \Rightarrow A^T = \begin{bmatrix} 1 & 5 \\ 2 & 3 \\ 4 & 7 \end{bmatrix}

전치 행렬은 열벡터를 행벡터로 표현하거나, 행과 열의 배치를 연산에 맞게 바꿀 때 사용합니다.


대칭 행렬 (Symmetric Matrix)​

전치 행렬이 자기 자신과 같은 행렬을 대칭 행렬이라고 합니다: A=A⊤A = A^{\top}

A=[133a]⇒AT=[133a]A = \begin{bmatrix} 1 & 3 \\ 3 & a \end{bmatrix} \Rightarrow A^T = \begin{bmatrix} 1 & 3 \\ 3 & a \end{bmatrix}

대칭 행렬은 그래프 이론이나 공학에서 자주 사용되며, 물리학에서도 응력(stress)과 관련된 행렬로 활용됩니다.


대각 행렬 (Diagonal Matrix)​

정사각 행렬 중 대각 성분이 아닌 모든 성분이 00인 행렬을 대각 행렬(diagonal matrix) 이라고 합니다.

[100000003]\begin{bmatrix} 1 & 0 & 0 \\ 0 & 0 & 0 \\ 0 & 0 & 3 \end{bmatrix}

  • 대각 성분은 00이어도 상관없습니다.
  • 대각 행렬은 항상 대칭 행렬입니다.
  • 대각 원소만 저장하거나 계산하는 구현에서는 연산량과 저장 공간을 줄일 수 있습니다.

단위 행렬 (Identity Matrix)​

대각 성분만 11이고 나머지는 00인 행렬을 단위 행렬(identity matrix) 이라고 합니다. 단위 행렬 II는 행렬 곱셈에서 곱셈 항등원의 역할을 합니다.

I=[1001],I=[100010001]I = \begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}, \quad I = \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix}

A⋅In=Im⋅A=A(A는 m×n 행렬)A \cdot I_n = I_m \cdot A = A \quad (A \text{는 } m \times n \text{ 행렬})

이는 일반적인 수에서 11이 곱셈의 항등원 역할을 하는 것과 같은 개념입니다.


영행렬 (Zero Matrix)​

모든 성분이 00인 행렬을 영행렬(zero matrix) 이라고 합니다.

[0000],[000000000]\begin{bmatrix} 0 & 0 \\ 0 & 0 \end{bmatrix}, \quad \begin{bmatrix} 0 & 0 & 0 \\ 0 & 0 & 0 \\ 0 & 0 & 0 \end{bmatrix}

영행렬은 행렬 덧셈의 항등원입니다. 크기가 같은 행렬에 영행렬을 더해도 원래 행렬이 그대로 남습니다.



행렬의 연산​

행렬의 비교: A=BA = B​

두 행렬의 크기가 같고 같은 위치의 성분이 모두 같을 때 A=BA = B 입니다.

[1x23]=[122y]\begin{bmatrix} 1 & x \\ 2 & 3 \end{bmatrix} = \begin{bmatrix} 1 & 2 \\ 2 & y \end{bmatrix}

이때, x=2,y=3x = 2, y = 3 입니다.


행렬의 실수배 (Scalar Multiplication)​

행렬의 모든 성분에 특정한 숫자(스칼라)를 곱하는 연산입니다. 아래 실수배와 덧셈·뺄셈 예제에서는 다음 두 행렬을 사용합니다.

A=[2153],B=[−1412]A = \begin{bmatrix} 2 & 1 \\ 5 & 3 \end{bmatrix}, \quad B = \begin{bmatrix} -1 & 4 \\ 1 & 2 \end{bmatrix}

3A=[63159]3A = \begin{bmatrix} 6 & 3 \\ 15 & 9 \end{bmatrix}


행렬의 덧셈 (Addition)과 뺄셈 (Subtraction)​

같은 크기의 행렬끼리만 가능합니다.

A+B=[1565]A + B = \begin{bmatrix} 1 & 5 \\ 6 & 5 \end{bmatrix}

A−B=[3−341]A - B = \begin{bmatrix} 3 & -3 \\ 4 & 1 \end{bmatrix}


행렬의 곱셈 (Matrix Multiplication)​

행렬 곱셈은 일반적인 덧셈이나 뺄셈과 다릅니다. 같은 위치에 있는 성분끼리 연산하는 것이 아니라, 왼쪽 행렬의 행과 오른쪽 행렬의 열을 대응시켜 계산합니다.

예제 1: 2×22 \times 2 행렬 곱셈​

[1234]×[5678]\begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix} \times \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix}

각 행과 열의 성분을 곱하고 합하여 새로운 행렬을 만듭니다.

=[(1⋅5+2⋅7)(1⋅6+2⋅8)(3⋅5+4⋅7)(3⋅6+4⋅8)]= \begin{bmatrix} (1 \cdot 5 + 2 \cdot 7) & (1 \cdot 6 + 2 \cdot 8) \\ (3 \cdot 5 + 4 \cdot 7) & (3 \cdot 6 + 4 \cdot 8) \end{bmatrix}

=[19224350]= \begin{bmatrix} 19 & 22 \\ 43 & 50 \end{bmatrix}

위 연산에서 결과 행렬의 각 성분은 왼쪽 행렬의 행과 오른쪽 행렬의 열을 곱한 값들의 합입니다.


예제 2: 2×22 \times 2 행렬과 2×12 \times 1 행렬의 곱셈​

[1234]×[56]\begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix} \times \begin{bmatrix} 5 \\ 6 \end{bmatrix}

이 경우, 결과 행렬의 크기는 (2×1)(2 \times 1)이 됩니다.

=[(1⋅5+2⋅6)(3⋅5+4⋅6)]= \begin{bmatrix} (1 \cdot 5 + 2 \cdot 6) \\ (3 \cdot 5 + 4 \cdot 6) \end{bmatrix}

=[1739]= \begin{bmatrix} 17 \\ 39 \end{bmatrix}


예제 3: 2×32 \times 3 행렬과 3×23 \times 2 행렬의 곱셈​

[4−21023]×[0−3−2114]\begin{bmatrix} 4&-2&1\\ 0&2&3\\ \end{bmatrix} \times \begin{bmatrix} 0&-3\\ -2&1\\ 1&4\\ \end{bmatrix}

=[(4⋅0+(−2)⋅(−2)+1⋅1)(4⋅(−3)+(−2)⋅1+1⋅4)(0⋅0+2⋅(−2)+3⋅1)(0⋅(−3)+2⋅1+3⋅4)]= \begin{bmatrix} (4 \cdot 0+(-2) \cdot (-2)+1 \cdot 1) & (4 \cdot (-3)+(-2) \cdot 1+1 \cdot 4) \\ (0 \cdot 0+2 \cdot (-2)+3 \cdot 1) & (0 \cdot (-3)+2 \cdot 1+3 \cdot 4) \\ \end{bmatrix}

=[5−10−114]= \begin{bmatrix} 5&-10\\ -1&14\\ \end{bmatrix}

설명:

  • 첫 번째 행과 첫 번째 열을 곱한 값이 첫 번째 행, 첫 번째 열의 성분이 됩니다.
    C11=A11⋅B11+A12⋅B21+A13⋅B31C_{11} = A_{11} \cdot B_{11} + A_{12} \cdot B_{21} + A_{13} \cdot B_{31}

  • 첫 번째 행과 두 번째 열을 곱한 값이 첫 번째 행, 두 번째 열의 성분이 됩니다.
    C12=A11⋅B12+A12⋅B22+A13⋅B32C_{12} = A_{11} \cdot B_{12} + A_{12} \cdot B_{22} + A_{13} \cdot B_{32}

  • 두 번째 행과 첫 번째 열을 곱한 값이 두 번째 행, 첫 번째 열의 성분이 됩니다.
    C21=A21⋅B11+A22⋅B21+A23⋅B31C_{21} = A_{21} \cdot B_{11} + A_{22} \cdot B_{21} + A_{23} \cdot B_{31}

  • 두 번째 행과 두 번째 열을 곱한 값이 두 번째 행, 두 번째 열의 성분이 됩니다.
    C22=A21⋅B12+A22⋅B22+A23⋅B32C_{22} = A_{21} \cdot B_{12} + A_{22} \cdot B_{22} + A_{23} \cdot B_{32}

이처럼 각 행과 열을 대응하여 곱하고 더하는 방식으로 행렬의 곱셈을 수행합니다.


행렬 곱셈의 일반적인 규칙​

  • 행렬 곱셈이 성립하려면 왼쪽 행렬의 열 개수와 오른쪽 행렬의 행 개수가 같아야 합니다.
  • 결과 행렬의 크기는 왼쪽 행렬의 행 개수 × 오른쪽 행렬의 열 개수가 됩니다.

즉, 다음과 같은 수식을 만족해야 합니다.

 

A(m×n)×B(n×r)=C(m×r)A (m \times n) \times B (n \times r) = C (m \times r)

이 규칙을 코드로 옮기면 세 개의 반복문으로 결과 행렬의 각 성분을 계산할 수 있습니다.



코딩테스트: 행렬의 곱셈​

 

이 문제는 2차원 배열을 순회하며 행과 열의 곱을 누적하는 과정을 코드로 옮기는 연습입니다.

문제

2차원 행렬 AA와 BB를 입력받아 행렬 AA에 행렬 BB를 곱한 결과를 반환하는 solution() 함수를 완성하세요.

제약조건

  • 행렬 AA, BB의 행과 열의 길이는 2 이상 100 이하입니다.
  • 행렬 AA, BB의 데이터는 -10 이상 20 이하인 정수입니다.

문제 풀이 (JavaScript)

function solution(A, B) {
// A의 행(row) 개수
const m = A.length;
// A의 열(column) 개수 (B의 행 개수와 같아야 함)
const n = A[0].length;
// B의 열(column) 개수 (결과 행렬의 열 개수)
const p = B[0].length;

// 행렬 곱셈이 가능한지 확인 (A의 열 개수와 B의 행 개수가 일치해야 함)
if (n !== B.length) throw new Error("행렬의 곱이 성립되지 않음");

// 결과 행렬 C 초기화 (m x p 크기의 2차원 배열, 0으로 채워진 상태)
const C = Array.from({ length: m }, () => new Array(p).fill(0));

// 행렬 곱셈 수행
for (let i = 0; i < m; i++) {
// A의 행을 반복
for (let j = 0; j < p; j++) {
// B의 열을 반복
for (let k = 0; k < n; k++) {
// A의 열과 B의 행을 반복 (곱셈 연산)
C[i][j] += A[i][k] * B[k][j]; // A의 i행 k열 원소와 B의 k행 j열 원소를 곱한 값을 더함
}
}
}

// 결과 행렬 반환
return C;
}

코드 설명

  1. m,n,pm, n, p는 각각 AA의 행 개수, AA의 열 개수(BB의 행 개수), BB의 열 개수를 나타냅니다.

  2. n !== B.length 조건으로 행렬 곱셈이 가능한지 확인합니다.

  3. 결과 행렬 CC를 m×pm \times p 크기의 0으로 채운 배열로 초기화합니다.

  4. 세 개의 for 문으로 행렬 곱셈을 수행합니다.

    • i는 AA의 행 인덱스입니다.
    • j는 BB의 열 인덱스입니다.
    • k는 AA의 열과 BB의 행을 연결하는 인덱스입니다.
    • C[i][j] += A[i][k] * B[k][j]로 성분의 곱을 누적합니다.
  5. 계산을 마친 CC를 반환합니다.


좋은 사람들과 재미있는 일을 하며 열정적이고 즐겁게 살고 싶은 개발자