1 개요
\(m \times n\) 행렬 \(A\) 에는 자연스럽게 정의되는 네 개의 부분공간이 있다. 이를 Gilbert Strang은 네 개의 근본 부분공간(Four Fundamental Subspaces) 이라 부른다.
| 부분공간 | 기호 | 정의 | 포함 공간 |
|---|---|---|---|
| 열 공간 | \(C(A)\) | \(A\) 의 열들의 선형결합 | \(\mathbb{R}^m\) |
| 영공간 | \(N(A)\) | \(Ax = 0\) 의 해 집합 | \(\mathbb{R}^n\) |
| 행 공간 | \(C(A^T)\) | \(A^T\) 의 열(= \(A\) 의 행)의 선형결합 | \(\mathbb{R}^n\) |
| 좌영공간 | \(N(A^T)\) | \(A^T y = 0\) 의 해 집합 | \(\mathbb{R}^m\) |
이 절의 목표는 네 공간의 차원(dimension) 과 기저(basis) 를 소거법 하나로 모두 구하는 것이다.
핵심 결론:
\[ \dim C(A) = r, \quad \dim N(A) = n - r, \quad \dim C(A^T) = r, \quad \dim N(A^T) = m - r \]
그리고 이 네 공간 사이의 직교 관계가 Big Picture 를 이룬다.
2 열 공간 \(C(A)\) 와 행 공간 \(C(A^T)\) 의 차원이 같다
가장 먼저 확인할 사실은 열 공간의 차원과 행 공간의 차원이 모두 랭크 \(r\) 로 일치한다는 것이다.
열 공간: 피벗 열이 \(r\) 개 → \(\dim C(A) = r\)
행 공간: 피벗 행(비영 행)이 \(r\) 개 → \(\dim C(A^T) = r\)
왜 같은가? 피벗의 수는 행 소거와 열 선형독립 판정 모두에서 동시에 결정된다. 즉, “열 방향의 독립 수”와 “행 방향의 독립 수”가 같다는 것은 비자명한 사실이다.
직관: 행 랭크(row rank) = 열 랭크(column rank). 이 대칭성은 전치 연산으로도 알 수 있다. \(A\) 와 \(A^T\) 의 랭크는 같다.
3 네 부분공간의 기저 구하기 — 소거법
\(m \times n\) 행렬 \(A\) 를 소거하면 RREF \(R\) 을 얻는다. 이 과정에서 네 공간의 기저가 모두 드러난다.
3.1 행 공간 \(C(A^T)\) 의 기저
방법: \(R\) 의 영이 아닌 피벗 행들
소거는 행 연산(행의 선형결합)만 사용하므로, 행 공간이 보존된다.
\[ C(A^T) = C(R^T) \]
따라서 \(R\) 의 첫 \(r\) 개 행(피벗 행)이 행 공간의 기저가 된다. 이 행들은 이미 RREF이므로 선형 독립이다.
주의: \(A\) 의 행들을 직접 쓰면 안 된다. \(A\) 의 행들은 독립이지 않을 수 있다. \(R\) 의 피벗 행을 써야 한다.
3.2 열 공간 \(C(A)\) 의 기저
방법: \(A\) 의 피벗 위치 열들
\(R\) 의 피벗 열이 아니라 원래 행렬 \(A\) 의 피벗 위치 열을 사용한다.
이유: 소거 과정에서 행 연산이 열 공간을 바꾸기 때문이다. \(A\) 와 \(R\) 의 열 공간은 일반적으로 다르다.
\[ C(A) \neq C(R) \quad \text{(일반적으로)} \]
그러나 어떤 열이 피벗 위치인지는 \(R\) 에서 판단하고, 실제 기저 벡터는 \(A\) 에서 가져온다.
예시:
\[ A = \begin{bmatrix} 1 & 2 & 3 \\ 2 & 4 & 5 \\ 3 & 6 & 8 \end{bmatrix} \xrightarrow{\text{소거}} R = \begin{bmatrix} 1 & 2 & 0 \\ 0 & 0 & 1 \\ 0 & 0 & 0 \end{bmatrix} \]
피벗은 열 1, 열 3에 있으므로, \(C(A)\) 의 기저는 \(A\) 의 1열과 3열:
\[ \begin{bmatrix}1\\2\\3\end{bmatrix}, \quad \begin{bmatrix}3\\5\\8\end{bmatrix} \]
3.3 영공간 \(N(A)\) 의 기저
방법: \(Ax = 0\) 의 특수해(special solutions) — \(n - r\) 개
자유 변수를 하나씩 1로 놓고 나머지를 0으로 놓아 \(n - r\) 개의 특수해를 구한다.
위 예시에서 자유 변수는 열 2 (변수 \(x_2\)) 하나. \(x_2 = 1, x_3 = 0\) 으로 놓으면:
\[ x_1 + 2(1) = 0 \implies x_1 = -2 \]
특수해: \((-2, 1, 0)^T\).
\[ N(A) = \text{span}\{(-2, 1, 0)^T\}, \quad \dim N(A) = 1 = 3 - 2 \]
3.4 좌영공간 \(N(A^T)\) 의 기저
방법: \(A^T y = 0\) 풀기 — 또는 소거 과정에서 \(E\) 행렬 추적
\(A^T y = 0\) 은 \(y^T A = 0^T\) 와 동치다. 즉, \(y^T\) 는 \(A\) 의 행들과 모두 직교한다.
소거로 구하는 방법: 첨가 행렬 \([A \mid I_m]\) 에 소거를 적용한다.
\[ [A \mid I_m] \xrightarrow{\text{소거}} [R \mid E] \]
\(EA = R\) 이 되고, \(R\) 의 영 행(zero row)에 해당하는 \(E\) 의 행들이 \(N(A^T)\) 의 기저가 된다.
왜냐하면: \(R\) 의 \(i\) 번째 행이 영이면 \(e_i^T A = 0^T\) (여기서 \(e_i^T\) 는 \(E\) 의 \(i\) 번째 행)이므로, 이 \(e_i^T\) 가 \(N(A^T)\) 의 원소다.
위 예시에서 \(m = 3, r = 2\) 이므로 \(\dim N(A^T) = m - r = 1\) 이다.
\[ [A \mid I_3] = \begin{bmatrix} 1&2&3 & 1&0&0 \\ 2&4&5 & 0&1&0 \\ 3&6&8 & 0&0&1 \end{bmatrix} \xrightarrow{R_2 - 2R_1,\, R_3 - 3R_1} \begin{bmatrix} 1&2&3 & 1&0&0 \\ 0&0&-1 & -2&1&0 \\ 0&0&-1 & -3&0&1 \end{bmatrix} \xrightarrow{R_3 - R_2} \begin{bmatrix} 1&2&0 & -5&3&0 \\ 0&0&1 & 2&-1&0 \\ 0&0&0 & -1&-1&1 \end{bmatrix} \]
\(R\) 의 3번째 행이 영이므로 \(E\) 의 3번째 행 \((-1, -1, 1)\) 이 \(N(A^T)\) 의 기저다.
검증: \[ (-1, -1, 1) \begin{bmatrix}1&2&3\\2&4&5\\3&6&8\end{bmatrix} = (-1-2+3,\; -2-4+6,\; -3-5+8) = (0, 0, 0) \checkmark \]
4 핵심 차원 공식 — 랭크-영공간 정리 완성판
\[ \boxed{ \begin{aligned} \dim C(A) &= r \\ \dim N(A) &= n - r \\ \dim C(A^T) &= r \\ \dim N(A^T) &= m - r \end{aligned} } \]
검증: - \(\mathbb{R}^n\) 쪽: \(C(A^T)\) 와 \(N(A)\) 의 차원 합 = \(r + (n-r) = n\) ✓ - \(\mathbb{R}^m\) 쪽: \(C(A)\) 와 \(N(A^T)\) 의 차원 합 = \(r + (m-r) = m\) ✓
5 Big Picture — 네 공간의 관계
Strang의 “Big Picture”는 네 부분공간이 두 쌍으로 나뉘어 서로 직교함을 보여준다.
\[ \boxed{C(A^T) \perp N(A) \quad \text{in } \mathbb{R}^n} \qquad \boxed{C(A) \perp N(A^T) \quad \text{in } \mathbb{R}^m} \]
증명 (\(C(A^T) \perp N(A)\)):
\(x \in N(A)\) 이면 \(Ax = 0\) 이므로, 임의의 \(y \in C(A^T)\) 에 대해 \(y = A^T z\) (어떤 \(z\))라 하면:
\[ y^T x = (A^T z)^T x = z^T (Ax) = z^T \cdot 0 = 0 \]
따라서 행 공간의 모든 벡터는 영공간의 모든 벡터와 직교한다. \(\square\)
같은 방식으로 \(C(A) \perp N(A^T)\) 를 증명할 수 있다.
5.1 Big Picture 도식
R^n R^m
┌────────────────┐ ┌────────────────┐
│ C(A^T) dim r │ A ──→ │ C(A) dim r │
│ (행 공간) │ │ (열 공간) │
│ │ │ │
│ N(A) dim n-r │ A ──→ │ N(A^T) dim m-r│
│ (영공간) {0} │ │ (좌영공간) {0}│
└────────────────┘ └────────────────┘
- 행 공간의 벡터 \(x_r \in C(A^T)\) 는 \(A\) 에 의해 열 공간 \(C(A)\) 로 이동한다 (\(Ax_r \in C(A)\), 비자명)
- 영공간의 벡터 \(x_n \in N(A)\) 는 \(A\) 에 의해 \(0\) 으로 이동한다 (\(Ax_n = 0\))
- \(\mathbb{R}^n\) 의 임의의 벡터 \(x = x_r + x_n\) 으로 유일하게 분해된다
이것이 완전해 \(x = x_p + x_n\) 의 기하학적 근거다.
6 구체적 예시 — \(3 \times 4\) 행렬
\[ A = \begin{bmatrix} 1 & 1 & 0 & 0 \\ 0 & 0 & 1 & 1 \\ 1 & 1 & 1 & 1 \end{bmatrix}, \quad m=3, n=4 \]
소거:
\[ \xrightarrow{R_3 - R_1 - R_2} R = \begin{bmatrix} 1 & 1 & 0 & 0 \\ 0 & 0 & 1 & 1 \\ 0 & 0 & 0 & 0 \end{bmatrix} \]
피벗: 열 1, 열 3. 랭크 \(r = 2\).
| 공간 | 포함 | 차원 | 기저 |
|---|---|---|---|
| \(C(A^T)\) | \(\mathbb{R}^4\) | \(2\) | \(R\) 의 두 피벗 행: \((1,1,0,0),\;(0,0,1,1)\) |
| \(N(A)\) | \(\mathbb{R}^4\) | \(2\) | 특수해: \((-1,1,0,0)^T,\;(0,0,-1,1)^T\) |
| \(C(A)\) | \(\mathbb{R}^3\) | \(2\) | \(A\) 의 피벗 열: \((1,0,1)^T,\;(0,1,1)^T\) |
| \(N(A^T)\) | \(\mathbb{R}^3\) | \(1\) | \((-1,-1,1)^T\) |
직교 검증: - \(C(A^T) \perp N(A)\): \((1,1,0,0) \cdot (-1,1,0,0) = 0\) ✓, \((0,0,1,1) \cdot (-1,1,0,0) = 0\) ✓ - \(C(A) \perp N(A^T)\): \((1,0,1) \cdot (-1,-1,1) = 0\) ✓, \((0,1,1) \cdot (-1,-1,1) = 0\) ✓
7 정사각 가역 행렬의 특별한 경우
\(n \times n\) 가역 행렬 \(A\) 에서는 \(r = m = n\) 이다.
| 공간 | 차원 | 내용 |
|---|---|---|
| \(C(A)\) | \(n\) | \(= \mathbb{R}^n\) 전체 |
| \(N(A)\) | \(0\) | \(= \{0\}\) |
| \(C(A^T)\) | \(n\) | \(= \mathbb{R}^n\) 전체 |
| \(N(A^T)\) | \(0\) | \(= \{0\}\) |
영공간이 \(\{0\}\) 이면 \(Ax = 0 \implies x = 0\), 즉 역행렬이 존재한다. 네 공간이 두 쌍으로 전체 공간을 채운다 — 직교 여공간 분해.
8 직교 여공간 (Orthogonal Complement)
두 직교 부분공간이 합쳐서 전체 공간을 이루면 직교 여공간이라 한다.
\[ C(A^T) \oplus N(A) = \mathbb{R}^n \qquad \text{(직교 직합)} \]
“\(\oplus\)”는 두 공간이 직교하면서 차원 합이 \(n\) 임을 뜻한다 (\(r + (n-r) = n\)).
이 분해는 임의의 \(x \in \mathbb{R}^n\) 을 다음과 같이 유일하게 쓸 수 있다는 것을 보장한다.
\[ x = x_r + x_n, \quad x_r \in C(A^T), \; x_n \in N(A), \; x_r \perp x_n \]
\(Ax = Ax_r + Ax_n = Ax_r\) (오직 행 공간 성분만 살아남는다).
9 응용 요약
| 분야 | 활용 |
|---|---|
| 최소자승법 | \(N(A^T)\) 에 대한 \(b\) 의 직교 투영 = 잔차 방향 |
| SVD 준비 | 네 공간의 직교 기저 = \(U, V\) 의 열들 |
| PCA | 열 공간 = 주성분 방향, 영공간 = 정보 손실 방향 |
| 제어 이론 | \(N(A^T)\) = 관측 불가 상태 공간 |
| 네트워크 분석 | 근접 행렬의 \(N(A)\) = 순환 전류, \(C(A^T)\) = 트리 전위 |
| 신호 처리 | 신호 분해 = 행 공간 + 영공간 성분 |
10 Python 구현
#| label: four-subspaces
#| fig-cap: "네 근본 부분공간: 차원·기저·직교성 검증 및 시각화"
import numpy as np
from sympy import Matrix
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
# ── Step 1: 네 공간 기저 및 차원 계산 ───────────────────────
print("=" * 60)
print("Step 1: 네 근본 부분공간 기저 및 차원")
print("=" * 60)
A = Matrix([
[1, 1, 0, 0],
[0, 0, 1, 1],
[1, 1, 1, 1]
])
A_np = np.array(A.tolist(), dtype=float)
m, n = A_np.shape
R, pivots = A.rref()
r = len(pivots)
print(f"\nA ({m}×{n}), 랭크 r = {r}")
print(f"피벗 위치 (0-인덱스): {pivots}")
# 행 공간 C(A^T): R의 피벗 행
print(f"\n[1] 행 공간 C(A^T) dim = {r} (⊆ R^{n})")
for i in range(r):
row = np.array(R.row(i).tolist(), dtype=float).flatten()
print(f" 기저 {i+1}: {row}")
# 영공간 N(A): 특수해
ns_A = A.nullspace()
print(f"\n[2] 영공간 N(A) dim = {n-r} (⊆ R^{n})")
for i, v in enumerate(ns_A):
print(f" 기저 {i+1}: {np.array(v.tolist(), dtype=float).flatten()}")
# 열 공간 C(A): A의 피벗 열
print(f"\n[3] 열 공간 C(A) dim = {r} (⊆ R^{m})")
for j in pivots:
col = np.array(A.col(j).tolist(), dtype=float).flatten()
print(f" 기저 (열 {j+1}): {col}")
# 좌영공간 N(A^T): [A|I] 소거
AT = A.T
ns_AT = AT.nullspace()
print(f"\n[4] 좌영공간 N(A^T) dim = {m-r} (⊆ R^{m})")
for i, v in enumerate(ns_AT):
print(f" 기저 {i+1}: {np.array(v.tolist(), dtype=float).flatten()}")
# 차원 합 검증
print(f"\n검증:")
print(f" R^{n}: dim C(A^T) + dim N(A) = {r} + {n-r} = {n} ✓")
print(f" R^{m}: dim C(A) + dim N(A^T)= {r} + {m-r} = {m} ✓")
# ── Step 2: 직교성 검증 ─────────────────────────────────────
print("\n" + "=" * 60)
print("Step 2: 직교성 검증")
print("=" * 60)
# C(A^T)와 N(A)의 직교성
row_basis = [np.array(R.row(i).tolist(), dtype=float).flatten() for i in range(r)]
null_basis = [np.array(v.tolist(), dtype=float).flatten() for v in ns_A]
print("\nC(A^T) ⊥ N(A) 검증:")
for rv in row_basis:
for nv in null_basis:
dot = np.dot(rv, nv)
print(f" {np.round(rv,2)} · {np.round(nv,2)} = {dot:.6f}")
# C(A)와 N(A^T)의 직교성
col_basis = [np.array(A.col(j).tolist(), dtype=float).flatten() for j in pivots]
lnull_basis = [np.array(v.tolist(), dtype=float).flatten() for v in ns_AT]
print("\nC(A) ⊥ N(A^T) 검증:")
for cv in col_basis:
for lv in lnull_basis:
dot = np.dot(cv, lv)
print(f" {np.round(cv,2)} · {np.round(lv,2)} = {dot:.6f}")
# ── Step 3: Big Picture 시각화 ──────────────────────────────
print("\n" + "=" * 60)
print("Step 3: Big Picture 시각화")
print("=" * 60)
fig, ax = plt.subplots(1, 1, figsize=(10, 6))
ax.set_xlim(0, 10); ax.set_ylim(0, 6)
ax.axis('off')
ax.set_facecolor('#f8f9fa')
fig.patch.set_facecolor('#f8f9fa')
# 두 원(R^n, R^m)
circle_n = plt.Circle((2.5, 3), 2.2, fill=True, color='#e8f4f8', ec='steelblue', lw=2.5)
circle_m = plt.Circle((7.5, 3), 2.2, fill=True, color='#fef9e7', ec='coral', lw=2.5)
ax.add_patch(circle_n)
ax.add_patch(circle_m)
# 공간 레이블
ax.text(2.5, 5.5, f'$\\mathbb{{R}}^{n}$', ha='center', va='center',
fontsize=16, fontweight='bold', color='steelblue')
ax.text(7.5, 5.5, f'$\\mathbb{{R}}^{m}$', ha='center', va='center',
fontsize=16, fontweight='bold', color='coral')
# 행 공간
ax.add_patch(mpatches.FancyBboxPatch((1.0, 3.5), 3.0, 1.2,
boxstyle="round,pad=0.1", fc='#aed6f1', ec='steelblue', lw=1.5, alpha=0.8))
ax.text(2.5, 4.15, f'$C(A^T)$\ndim = {r}', ha='center', va='center',
fontsize=10, fontweight='bold', color='#1a5276')
# 영공간
ax.add_patch(mpatches.FancyBboxPatch((1.0, 1.2), 3.0, 1.2,
boxstyle="round,pad=0.1", fc='#d5e8d4', ec='seagreen', lw=1.5, alpha=0.8))
ax.text(2.5, 1.85, f'$N(A)$\ndim = {n-r}', ha='center', va='center',
fontsize=10, fontweight='bold', color='#1e8449')
# 열 공간
ax.add_patch(mpatches.FancyBboxPatch((6.0, 3.5), 3.0, 1.2,
boxstyle="round,pad=0.1", fc='#f9e79f', ec='goldenrod', lw=1.5, alpha=0.8))
ax.text(7.5, 4.15, f'$C(A)$\ndim = {r}', ha='center', va='center',
fontsize=10, fontweight='bold', color='#7d6608')
# 좌영공간
ax.add_patch(mpatches.FancyBboxPatch((6.0, 1.2), 3.0, 1.2,
boxstyle="round,pad=0.1", fc='#fadbd8', ec='crimson', lw=1.5, alpha=0.8))
ax.text(7.5, 1.85, f'$N(A^T)$\ndim = {m-r}', ha='center', va='center',
fontsize=10, fontweight='bold', color='#922b21')
# 화살표: 행 공간 → 열 공간
ax.annotate('', xy=(6.0, 4.1), xytext=(4.0, 4.1),
arrowprops=dict(arrowstyle='->', color='#2c3e50', lw=2.5))
ax.text(5.0, 4.4, '$Ax_r \\in C(A)$', ha='center', va='center',
fontsize=9, color='#2c3e50')
# 화살표: 영공간 → 0
ax.annotate('', xy=(6.0, 1.85), xytext=(4.0, 1.85),
arrowprops=dict(arrowstyle='->', color='seagreen', lw=2.5,
linestyle='dashed'))
ax.text(5.0, 2.15, '$Ax_n = 0$', ha='center', va='center',
fontsize=9, color='seagreen')
# 직교 표시
ax.text(2.5, 3.1, '$\\perp$', ha='center', va='center',
fontsize=18, color='gray')
ax.text(7.5, 3.1, '$\\perp$', ha='center', va='center',
fontsize=18, color='gray')
# 차원 합 표시
ax.text(2.5, 0.35, f'{r} + {n-r} = {n}', ha='center', va='center',
fontsize=11, color='steelblue',
bbox=dict(boxstyle='round', fc='white', ec='steelblue', alpha=0.8))
ax.text(7.5, 0.35, f'{r} + {m-r} = {m}', ha='center', va='center',
fontsize=11, color='coral',
bbox=dict(boxstyle='round', fc='white', ec='coral', alpha=0.8))
ax.set_title("Big Picture: 네 근본 부분공간의 관계", fontsize=13, fontweight='bold', pad=12)
plt.tight_layout()
plt.savefig('four_subspaces_big_picture.png', dpi=130, bbox_inches='tight')
plt.show()
print("시각화 완료.")11 관련 주제
- §3.5 Independence, Basis and Dimension: 기저와 차원의 기초 — 이 절의 선행 내용
- §4.1–4.2 Orthogonality: 두 직교 쌍 (\(C(A^T) \perp N(A)\), \(C(A) \perp N(A^T)\))의 심화
- §6.3 SVD: 네 공간의 직교 기저를 동시에 구하는 가장 강력한 도구
- §4.3 Least Squares: \(b \notin C(A)\) 일 때 열 공간 위로의 투영 = 최소자승해
- 최소 노름해: 행 공간에 속하는 특정해가 최소 노름을 가짐 (\(x_p \in C(A^T)\))