서브 행렬 개념

서브 행렬(sub-matrix)은 주어진 행렬에서 특정 행(row)과 열(column)을 선택하여 그들로 구성된 더 작은 행렬이다. 서브 행렬 추출은 대규모 행렬을 부분적으로 다루거나, 특정 영역만 필요할 때 매우 유용하다. Eigen 라이브러리에서 서브 행렬 추출은 다양한 방법으로 이루어지며, 각 방법에 따라 접근 방식이 달라질 수 있다.

Eigen 라이브러리에서 서브 행렬을 추출하는 기본적인 방법은 block() 함수를 사용하는 것이다. 이 함수는 주어진 행렬에서 특정 위치의 부분 행렬을 추출하는 역할을 한다. 수학적으로 말하면, 주어진 행렬 \mathbf{A} \in \mathbb{R}^{m \times n}에서 원하는 서브 행렬 \mathbf{B} \in \mathbb{R}^{p \times q}는 다음과 같이 추출된다:

\mathbf{B} = \mathbf{A}_{ij} = \mathbf{A}(i:i+p-1, j:j+q-1)

여기서 i는 서브 행렬의 시작 행(row), j는 서브 행렬의 시작 열(column), p는 서브 행렬의 행 크기, q는 서브 행렬의 열 크기이다.

Eigen에서 서브 행렬 추출

Eigen에서 서브 행렬을 추출하기 위해서는 block() 메서드를 사용할 수 있다. 이 함수는 4개의 인수를 받으며, 다음과 같이 구성된다:

예제 1: 기본 서브 행렬 추출

다음은 4x4 행렬에서 2x2 서브 행렬을 추출하는 예제이다.

#include <iostream>
#include <Eigen/Dense>

int main() {
    Eigen::Matrix4f mat;
    mat << 1, 2, 3, 4,
           5, 6, 7, 8,
           9, 10, 11, 12,
           13, 14, 15, 16;

    std::cout << "Original matrix:\n" << mat << "\n\n";
    Eigen::Matrix2f subMat = mat.block(1, 1, 2, 2);

    std::cout << "Submatrix (2x2 starting from position (1,1)):\n" << subMat << "\n";

    return 0;
}

위의 예제에서 행렬 mat은 다음과 같은 형태를 갖는다:

\mathbf{A} = \begin{bmatrix} 1 & 2 & 3 & 4 \\ 5 & 6 & 7 & 8 \\ 9 & 10 & 11 & 12 \\ 13 & 14 & 15 & 16 \end{bmatrix}

block(1, 1, 2, 2) 함수 호출은 \mathbf{A}에서 두 번째 행(인덱스 1)과 두 번째 열(인덱스 1)부터 시작하여 2x2 서브 행렬을 추출한다. 결과적으로 다음과 같은 서브 행렬이 반환된다:

\mathbf{B} = \begin{bmatrix} 6 & 7 \\ 10 & 11 \end{bmatrix}

이러한 방식으로 특정 위치에서 크기를 지정하여 서브 행렬을 추출할 수 있다.

서브 행렬의 다양한 활용

서브 행렬을 추출하는 방법은 다양한 응용에서 활용된다. 특히 대규모 행렬 연산에서 특정 영역의 행렬만 필요하거나, 블록 행렬 연산에서 특정 블록을 추출할 때 유용하다. 다음은 Eigen에서 서브 행렬 추출을 다양한 방식으로 활용하는 예시들이다.

예제 2: 행렬 수정과 서브 행렬

서브 행렬을 추출한 후, 해당 부분을 수정하거나 다른 값으로 교체할 수 있다. 다음은 서브 행렬을 수정하는 예제이다.

#include <iostream>
#include <Eigen/Dense>

int main() {
    Eigen::Matrix4f mat;
    mat << 1, 2, 3, 4,
           5, 6, 7, 8,
           9, 10, 11, 12,
           13, 14, 15, 16;

    std::cout << "Original matrix:\n" << mat << "\n\n";

    // 서브 행렬 추출 후 값 수정
    mat.block(1, 1, 2, 2) << 100, 101,
                             102, 103;

    std::cout << "Matrix after modifying submatrix (2x2 starting from position (1,1)):\n" << mat << "\n";

    return 0;
}

이 코드는 행렬 mat에서 2x2 서브 행렬을 추출한 후, 해당 서브 행렬의 값을 새롭게 할당한다. 수정된 행렬은 다음과 같다:

\mathbf{A} = \begin{bmatrix} 1 & 2 & 3 & 4 \\ 5 & 100 & 101 & 8 \\ 9 & 102 & 103 & 12 \\ 13 & 14 & 15 & 16 \end{bmatrix}

이 예제는 서브 행렬을 단순히 추출하는 것 외에도, 특정 영역의 값을 동적으로 수정할 수 있음을 보여준다.

예제 3: 변수 크기 서브 행렬 추출

서브 행렬의 크기를 동적으로 결정해야 하는 경우도 있다. Eigen에서는 이러한 요구를 충족하기 위해 동적으로 크기를 지정하는 block() 메서드를 지원한다.

#include <iostream>
#include <Eigen/Dense>

int main() {
    Eigen::MatrixXf mat(6, 6);
    mat.setRandom();

    std::cout << "Original matrix:\n" << mat << "\n\n";

    int startRow = 2, startCol = 2;
    int blockRows = 3, blockCols = 3;

    Eigen::MatrixXf subMat = mat.block(startRow, startCol, blockRows, blockCols);
    std::cout << "Submatrix (3x3 starting from position (2,2)):\n" << subMat << "\n";

    return 0;
}

이 예제에서 행렬 mat의 크기는 동적으로 할당되고, 서브 행렬의 크기도 변수로 지정된다. 사용자가 원하는 시작 위치와 크기를 변수로 할당하여 서브 행렬을 추출할 수 있다.

예제 4: 큰 행렬의 부분 행렬 작업

대규모 행렬을 다룰 때 서브 행렬을 추출하고 그 부분에만 연산을 수행하는 경우가 많다. 다음은 이러한 대규모 행렬에서 블록 연산을 수행하는 예제이다.

#include <iostream>
#include <Eigen/Dense>

int main() {
    Eigen::MatrixXd largeMat(100, 100);
    largeMat.setRandom();

    // 대규모 행렬의 일부 서브 행렬을 추출하고 연산
    Eigen::MatrixXd subMat = largeMat.block(10, 10, 20, 20);

    std::cout << "Submatrix (20x20 starting from position (10,10)):\n" << subMat << "\n";

    // 서브 행렬의 행렬 곱 연산
    Eigen::MatrixXd result = subMat * subMat.transpose();

    std::cout << "Result of submatrix * submatrix.transpose():\n" << result << "\n";

    return 0;
}

이 코드는 100x100의 대규모 행렬에서 20x20 서브 행렬을 추출한 후, 해당 서브 행렬에 대해 행렬 곱 연산을 수행한다. 대규모 데이터를 다룰 때 특정 블록에만 집중하여 연산 성능을 최적화할 수 있다.

예제 5: 행/열을 기준으로 서브 행렬 추출

Eigen 라이브러리에서는 block() 메서드 외에도 특정 행(row) 또는 열(column)을 추출하는 방법도 지원한다. 이를 통해 행렬에서 특정 행이나 열에 대한 연산을 쉽게 수행할 수 있다.

예제: 행과 열 추출

다음 예제는 행렬의 특정 행과 열을 추출하는 방법을 보여준다.

#include <iostream>
#include <Eigen/Dense>

int main() {
    Eigen::Matrix4f mat;
    mat << 1, 2, 3, 4,
           5, 6, 7, 8,
           9, 10, 11, 12,
           13, 14, 15, 16;

    std::cout << "Original matrix:\n" << mat << "\n\n";

    // 2번째 행 추출
    Eigen::Vector4f row = mat.row(1);
    std::cout << "Row 1 of matrix:\n" << row << "\n\n";

    // 3번째 열 추출
    Eigen::Vector4f col = mat.col(2);
    std::cout << "Column 2 of matrix:\n" << col << "\n";

    return 0;
}

위 예제에서는 row()col() 함수를 이용하여 주어진 행렬에서 특정 행과 열을 추출하고 있다. 결과적으로, 다음과 같은 출력을 얻게 된다.

예제 6: 서브 행렬을 이용한 대각선 추출

행렬에서 대각선 요소를 추출하는 것도 서브 행렬을 이용한 중요한 응용 중 하나이다. Eigen에서는 diagonal() 메서드를 사용하여 대각선을 추출할 수 있다. 서브 행렬의 특정 대각선만 추출하거나 연산을 수행할 때 유용하다.

예제: 대각선 추출
#include <iostream>
#include <Eigen/Dense>

int main() {
    Eigen::Matrix4f mat;
    mat << 1, 2, 3, 4,
           5, 6, 7, 8,
           9, 10, 11, 12,
           13, 14, 15, 16;

    std::cout << "Original matrix:\n" << mat << "\n\n";

    // 대각선 추출
    Eigen::Vector4f diag = mat.diagonal();
    std::cout << "Diagonal of matrix:\n" << diag << "\n";

    return 0;
}

이 코드에서 행렬의 대각선 요소는 다음과 같이 추출된다:

\mathbf{d} = [1, 6, 11, 16]

이러한 방식으로 대각선 요소를 추출하여 특수한 연산을 수행할 수 있다.

예제 7: 상위 및 하위 삼각 행렬 추출

서브 행렬 추출은 상위 삼각 행렬(upper triangular matrix) 또는 하위 삼각 행렬(lower triangular matrix)을 추출할 때도 유용하다. Eigen에서는 triangularView() 메서드를 통해 삼각 행렬을 쉽게 추출할 수 있다.

예제: 상위 삼각 행렬 추출
#include <iostream>
#include <Eigen/Dense>

int main() {
    Eigen::Matrix4f mat;
    mat << 1, 2, 3, 4,
           5, 6, 7, 8,
           9, 10, 11, 12,
           13, 14, 15, 16;

    std::cout << "Original matrix:\n" << mat << "\n\n";

    // 상위 삼각 행렬 추출
    Eigen::Matrix4f upperTriangular = mat.triangularView<Eigen::Upper>();
    std::cout << "Upper triangular part of matrix:\n" << upperTriangular << "\n";

    return 0;
}

이 코드는 행렬의 상위 삼각 요소를 추출하며, 결과적으로 다음과 같은 상위 삼각 행렬이 출력된다:

\mathbf{U} = \begin{bmatrix} 1 & 2 & 3 & 4 \\ 0 & 6 & 7 & 8 \\ 0 & 0 & 11 & 12 \\ 0 & 0 & 0 & 16 \end{bmatrix}

예제 8: 하위 삼각 행렬 추출

유사하게, 하위 삼각 행렬도 triangularView<Eigen::Lower>() 메서드를 사용하여 추출할 수 있다.

#include <iostream>
#include <Eigen/Dense>

int main() {
    Eigen::Matrix4f mat;
    mat << 1, 2, 3, 4,
           5, 6, 7, 8,
           9, 10, 11, 12,
           13, 14, 15, 16;

    std::cout << "Original matrix:\n" << mat << "\n\n";

    // 하위 삼각 행렬 추출
    Eigen::Matrix4f lowerTriangular = mat.triangularView<Eigen::Lower>();
    std::cout << "Lower triangular part of matrix:\n" << lowerTriangular << "\n";

    return 0;
}

결과적으로 다음과 같은 하위 삼각 행렬이 출력된다:

\mathbf{L} = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 5 & 6 & 0 & 0 \\ 9 & 10 & 11 & 0 \\ 13 & 14 & 15 & 16 \end{bmatrix}

이렇게 상위 또는 하위 삼각 행렬을 추출하여 특수한 목적에 맞게 연산을 수행할 수 있다.