From 71c8a3adc44f7e31fb67bdf5a47f9ff1d6fdd842 Mon Sep 17 00:00:00 2001 From: "Kangwon Lee (Education)" Date: Mon, 10 Jun 2024 11:40:24 +0900 Subject: [PATCH] 60 / 150 : fix typo in minor description --- 60_linear_algebra_2/150_Inverse_matrix.ipynb | 4252 ++++++++++-------- 1 file changed, 2301 insertions(+), 1951 deletions(-) diff --git a/60_linear_algebra_2/150_Inverse_matrix.ipynb b/60_linear_algebra_2/150_Inverse_matrix.ipynb index 9efad583..f92a8b96 100644 --- a/60_linear_algebra_2/150_Inverse_matrix.ipynb +++ b/60_linear_algebra_2/150_Inverse_matrix.ipynb @@ -1,1953 +1,2303 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "view-in-github", - "colab_type": "text" - }, - "source": [ - "\"Open\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# This cell is for the Google Colaboratory\n", - "# https://stackoverflow.com/a/63519730\n", - "if 'google.colab' in str(get_ipython()):\n", - " path_py = '/content/nmisp_py'\n", - "\n", - " import os\n", - " if not os.path.exists(path_py):\n", - " import subprocess\n", - " subprocess.run(\n", - " ('git', 'clone', 'https://github.com/kangwonlee/nmisp_py')\n", - " )\n", - " assert os.path.exists(path_py)\n", - "\n", - " import sys\n", - " sys.path.insert(0, path_py)\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import numpy.linalg as nl\n", - "import numpy.random as nr\n", - "import sympy as sym\n", - "import IPython.display as disp\n", - "\n", - "sym.init_printing()\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The following function would visualize a numerical matrix using the [Hinton Diagram](https://matplotlib.org/stable/gallery/specialty_plots/hinton_demo.html).
\n", - "아래 함수는 행렬을 [힌튼 다이어그램](https://matplotlib.org/stable/gallery/specialty_plots/hinton_demo.html)으로 시각화할 것이다.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def hinton(matrix, max_weight=None, ax=None, fname=None):\n", - " '''\n", - " Draw Hinton diagram for visualizing a weight matrix.\n", - " https://matplotlib.org/stable/gallery/specialty_plots/hinton_demo.html\n", - " '''\n", - " ax = ax if ax is not None else plt.gca()\n", - "\n", - " if not max_weight:\n", - " max_weight = 2 ** np.ceil(np.log2(np.abs(matrix).max()))\n", - "\n", - " ax.patch.set_facecolor('gray')\n", - " ax.set_aspect('equal', 'box')\n", - "\n", - " ax.xaxis.set_major_locator(plt.NullLocator())\n", - " ax.yaxis.set_major_locator(plt.NullLocator())\n", - "\n", - " for (y, x), w in np.ndenumerate(matrix):\n", - " color = 'white' if w > 0 else 'black'\n", - " size = np.sqrt(abs(w) / max_weight)\n", - " rect = plt.Rectangle([x - size / 2, y - size / 2], size, size,\n", - " facecolor=color, edgecolor=color)\n", - " ax.add_patch(rect)\n", - "\n", - " ax.autoscale_view()\n", - " ax.invert_yaxis()\n", - "\n", - " if fname is None:\n", - " plt.show()\n", - " plt.close()\n", - " else:\n", - " plt.savefig(fname, dpi=300)\n", - " plt.close()\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "a, b, c, d = sym.symbols('a b c d')\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 역행렬
Inverse matrix\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 2x2\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "다음과 같은 2x2 행렬의 역행렬을 구하는 법은 이미 알고 있을 것이다.
\n", - "We know how we can find a 2x2 matrix as follows.\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "$$\n", - "A = \\begin{bmatrix}\n", - " a & b\\\\\n", - " c & d \\\\\n", - "\\end{bmatrix}\n", - "$$\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A = sym.Matrix([\n", - " [a, b],\n", - " [c, d]]\n", - ")\n", - "A\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "$$\n", - "A^{-1} = \\frac {1}{ad-bc}\\begin{bmatrix}\n", - " d & -b\\\\\n", - " -c & a \\\\\n", - "\\end{bmatrix}\n", - "$$\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "여기서 $ad-bc$ 는 해당 행렬의 *행렬식* 이다.
\n", - "Here $ad-bc$ is the *determinant* of the matrix.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def det22(matA):\n", - " assert (2, 2) == matA.shape\n", - " return matA[0, 0] * matA[1, 1] - matA[0, 1] * matA[1, 0]\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "그런데 행렬 부분은 어떠한가?
\n", - "What about the matrix part?\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "adjA = sym.Matrix([\n", - " [d, -b],\n", - " [-c, a]]\n", - ")\n", - "adjA\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "원래의 행렬과 곱해보자.
\n", - "Let's multiply with the original matrix.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A * adjA\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "결과는 어떠한 형태인가?
\n", - "What does the result look like?\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "임의의 크기의 행렬에 대해 그러한 행렬을 찾을 수 있을까?
\n", - "Can we find such matrix for a matrix of an arbitrary size?\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 행렬식
Determinant\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 3x3\n", - "\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "다음과 같은 3x3 행렬을 생각해 보자.
\n", - "Let's think about a 3x3 matrix as follows.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "e, f, g, h, i = sym.symbols(list('efghi'))\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "A = sym.Matrix([\n", - " [a, b, c],\n", - " [d, e, f,],\n", - " [g, h, i,],\n", - "])\n", - "A\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "해당 행렬의 행렬식을 구해보자.
\n", - "Let's find the determinant of the matrix.\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### 소행렬식
Minor\n", - "\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "$i$ $j$ 번째 행을 삭제한 행렬을 생각해 보자.
\n", - "Let's consider a matrix without $i$-th row and $j$-th column.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def row_col_del(matA, row_i, col_j):\n", - " result = sym.Matrix(matA)\n", - " result.row_del(row_i)\n", - " result.col_del(col_j)\n", - " return result\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A00 = row_col_del(A, 0, 0)\n", - "A00\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A01 = row_col_del(A, 0, 1)\n", - "A01\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A02 = row_col_del(A, 0, 2)\n", - "A02\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "행렬 $A_{ij}$ 는 $A$ 행렬에서 $i$행 $j$열을 제외한 $\\left(n-1\\right) \\times \\left(n-1\\right)$ 행렬이다 .
\n", - "Matrix $A_{ij}$ is a $\\left(n-1\\right) \\times \\left(n-1\\right)$ matrix excluding $i$-th row and $j$-th column of the matrix $A$.\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "행렬식은 다음과 같이 계산할 수 있다. 이를 *소행렬식* 이라 한다.
\n", - "We can calculate the determinant as follows. This is called the *Minor*.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "det1 = A[0, 0] * det22(A00) - A[0, 1] * det22(A01) + A[0, 2] * det22(A02)\n", - "det1\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "함수 형태로는 다음과 같다.
\n", - "We may write in a function as follows.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def det33(matA:np.ndarray) -> float:\n", - "\n", - " result = 0\n", - "\n", - " for j in range(matA.shape[1]):\n", - " result += ((-1) ** j) * matA[0, j] * det22(row_col_del(matA, 0, j))\n", - "\n", - " return result\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "리스트 줄여쓰기로 다음과 같이 구현할 수도 있다.
\n", - "We can implement as follows using the list comprehension.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def det33_list_comprehension(matA:np.ndarray) -> float:\n", - " return sum(\n", - " [((-1) ** j) * matA[0, j] * det22(row_col_del(matA, 0, j)) for j in range(matA.shape[1])]\n", - " )\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "아래 셀은 함수를 확인한다.
\n", - "Following cell checks the function.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "assert 0 == sym.simplify(det33(A) - det1)\n", - "assert 0 == sym.simplify(det33_list_comprehension(A) - det1)\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### n x n, n > 3\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "일반화 하면 다음과 같다.
\n", - "We can generalize as follows.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def det(matA:np.ndarray) -> float:\n", - " if 2 == matA.shape[0]:\n", - " result = det22(matA)\n", - " elif 2 < matA.shape[0]:\n", - " result = sum(\n", - " [((-1) ** j) * matA[0, j] * det(row_col_del(matA, 0, j)) for j in range(matA.shape[1])]\n", - " )\n", - " return result\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 여인수행렬
Cofactor matrix\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "행렬 $A_{ij}$ 의 행렬식, *소행렬식* 에 번갈아 부호를 붙인 것을 *여인수* $C_{ij}$ 라고 한다.
\n", - "The signed version of the *minor*, determinant of the matrix $A_{ij}$, is the *cofactor* $C_{ij}$.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def cofactor(A, i, j):\n", - " return det(row_col_del(A, i, j))\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "여인수로 이루어진 행렬을 생각해 보자.
\n", - "Let's think about the matrix of cofactors.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def cofactor_matrix(matA):\n", - " return sym.Matrix([[cofactor(matA, i, j) * ((-1) ** (i+j)) for j in range(matA.shape[1])] for i in range(matA.shape[0])])\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "cofactor_A = cofactor_matrix(A)\n", - "cofactor_A\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "*여인수행렬* 의 전치행렬을 *수반행렬* 이라고 한다.
\n", - "The transpose of a *cofactor matrix* is the *adjugate matrix*.\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "원래 행렬 $A$와 *수반행렬* 을 곱해 보자.
\n", - "Let's multiply the origitnal matrix $A$ and its *adjugate matrix*.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sym.simplify(A * cofactor_A.T)\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "위 행렬을 $A$의 행렬식으로 나누어 보자.
\n", - "Let's divide the matrix above with the determinant of $A$.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "sym.simplify(A * cofactor_A.T / det1)\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "위 결과는 어떠한가?
\n", - "How is the result above?\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 2x2 : Gauss Jordan Method\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "다음 비디오는 역행열 찾는 가우스 조단법을 소개한다.
\n", - "Following video introduces Gauss Jordan method finding the inverse matrix. (36:23 ~ 42:20)\n", - "\n", - "[![MIT OCW 18.06 Lecture 3 Multiplication and Inverse Matrices](https://i.ytimg.com/vi/FX4C-JpTFgY/hqdefault.jpg)](https://www.youtube.com/watch?v=FX4C-JpTFgY&list=PL221E2BBF13BECF6C&index=9&start=2183&end=2540)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "아래 2x2 행렬을 생각해 보자.
\n", - "Let's think about the 2x2 matrix.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A22 = np.array([\n", - " [1, 3],\n", - " [2, 7]\n", - "])\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A22\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "hinton(A22)\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "오른쪽에 같은 크기의 단위행렬을 붙여 보자.
\n", - "Let's augment an identity matrix of the same size.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "I22 = np.identity(2)\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "I22\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "AX22 = np.hstack([A22, I22])\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "AX22\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "hinton(AX22)\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "이제 왼쪽 2x2 부분을 단위행렬로 만들어 보자.
\n", - "Let's make the left 2x2 part an identity matrix.\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "첫 행에 2를 곱한 후 2행에서 빼 보자.
\n", - "Let's multipy 2 to the first row and then subtract from the second row.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "AX22[1, :] -= 2 * AX22[0, :]\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "AX22\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "hinton(AX22)\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "이번에는 2번째 행에 3을 곱해서 첫 행에서 빼 보자.
\n", - "Now let's multipy 3 to the second row and subtract from the first row.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "AX22[0, :] -= 3 * AX22[1, :]\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "AX22\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "hinton(AX22)\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "위 `AX22` 행렬에서 오른쪽 두 행을 따로 떼어 보자.
\n", - "Let's separate the right two columns of the `AX22` matrix above.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A22_inv = AX22[:, 2:]\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A22_inv\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "hinton(A22_inv)\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`A22` 행렬과 곱해보자.
\n", - "Let's multipy with the A matrix.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A22 @ A22_inv\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## `numpy`\n", - "\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`numpy.linalg.inv()` function is available.
\n", - "`numpy.linalg.inv()` 함수로 구할 수 있다.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A22_inv = nl.inv(A22)\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A22_inv\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A22_inv @ A22\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3x3\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "다음 비디오는 3x3 행렬에 가우스 조단법을 적용한다.
\n", - "Following video applies the Gauss Jordan method to invert a 3x3 matrix.\n", - "\n", - "[![Khan Academy inverting 3x3 matrix part 2](https://i.ytimg.com/vi/obts_JDS6_Q/hqdefault.jpg)](https://www.youtube.com/watch?v=obts_JDS6_Q)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "아래 행렬을 생각해 보자.
\n", - "Let's think about the following matrix.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A33_list = [\n", - " [1, 0, 1],\n", - " [0, 2, 1],\n", - " [1, 1, 1],\n", - "]\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A33_list\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "hinton(A33_list)\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A33 = np.array(A33_list)\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A33\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "hinton(A33)\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "마찬가지로, 오른쪽에 같은 크기의 단위행렬을 붙여 보자.
\n", - "Same as before, let's augment an identity matrix of the same size.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "I33 = np.identity(A33.shape[0])\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "I33\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "AX33 = np.hstack([A33, I33])\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "AX33\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "hinton(AX33)\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "이제 왼쪽 부분을 단위행렬로 만들어 보자.
\n", - "Let's make the left part an identity matrix.\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "첫 행을 3행에서 빼 보자.
\n", - "Let's subtract the first row from the third row.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "AX33[2, :] -= AX33[0, :]\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "AX33\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "hinton(AX33)\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "이번에는 2번째 행과 3번째 행을 바꾸자.
\n", - "Now let's swap the second and the third rows. ([ref](https://stackoverflow.com/a/54069951))\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "AX33[[1, 2]] = AX33[[2, 1]]\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": false - }, - "outputs": [], - "source": [ - "AX33\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "hinton(AX33)\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "두번째 행에 2를 곱해서 3행에서 빼 보자.
\n", - "Let's multiply 2 to the second row and subtract from the third row.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "AX33[2, :] -= 2 * AX33[1, :]\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "AX33\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "hinton(AX33)\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "첫번째 행에서 3번째 행을 빼 보자.
\n", - "Let's subtract the third row from the first row.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "AX33[0, :] -= AX33[2, :]\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "AX33\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "hinton(AX33)\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "위 `AX` 행렬에서 오른쪽 세 열을 따로 떼어 보자.
\n", - "Let's separate the right three columns of the `AX` matrix above.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A33_inv = AX33[:, 3:]\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A33_inv\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "hinton(A33_inv)\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`A33` 행렬과 곱해보자.
\n", - "Let's multipy with the `A33` matrix.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A33 @ A33_inv\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## `numpy`\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Please use `numpy.linlag.inv()`
`numpy.linlag.inv()`를 사용하자.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mat_A33_inv = nl.inv(A33)\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mat_A33_inv\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A33 @ mat_A33_inv\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 표준 기능으로 구현한 가우스 조단법
Gauss Jordan method in Standard library\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "다음 셀은 가우스 조단법을 표준기능 만으로 구현한다.
\n", - "Following cell implements the Gauss Jordan method with standard library only.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import typing\n", - "\n", - "Scalar = typing.Union[int, float]\n", - "Row = typing.Union[typing.List[Scalar], typing.Tuple[Scalar]]\n", - "Matrix = typing.Union[typing.List[Row], typing.Tuple[Row]]\n", - "\n", - "\n", - "def get_zero(n:int) -> Matrix:\n", - " return [\n", - " [0] * n for i in range(n)\n", - " ]\n", - "\n", - "\n", - "def get_identity(n:int) -> Matrix:\n", - " result = get_zero(n)\n", - " for i in range(n):\n", - " result[i][i] = 1\n", - "\n", - " return result\n", - "\n", - "\n", - "def augment_mats(A:Matrix, B:Matrix):\n", - " assert len(A) == len(B)\n", - " return [row_A + row_B for row_A, row_B in zip(A, B)]\n", - "\n", - "\n", - "def gauss_jordan(A:Matrix, b_hinton:bool=False, epsilon=1e-7, b_savefig=False) -> Matrix:\n", - " AX = augment_mats(A, get_identity(len(A)))\n", - "\n", - " counter = 0\n", - "\n", - " # pivot loop\n", - " for p in range(len(AX)):\n", - "\n", - " assert abs(AX[p][p]) > epsilon, (p, AX)\n", - " one_over_pivot = 1.0 / AX[p][p]\n", - "\n", - " # normalize a row with one_over_pivot\n", - " for j in range(len(AX[p])):\n", - " AX[p][j] *= one_over_pivot\n", - "\n", - " # row loop\n", - " for i in range(len(AX)):\n", - " if i != p:\n", - " # row operation\n", - " multiplier = - AX[i][p]\n", - "\n", - " # column loop\n", - " for j in range(0, len(AX[p])):\n", - " AX[i][j] += multiplier * AX[p][j]\n", - "\n", - " # visualize augmented matrix\n", - " if b_hinton:\n", - " if b_savefig:\n", - " hinton(AX, fname=f'GJ{len(A)}{len(A)}-{counter:04d}.png')\n", - " counter += 1\n", - " else:\n", - " hinton(AX)\n", - "\n", - " return [row[len(A):] for row in AX]\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "위 행렬의 예로 확인해 보자.
\n", - "Let's check with the matrix above.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "mat_A33_inv_GJ = gauss_jordan(A33_list, b_hinton=True, b_savefig=False)\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import pprint\n", - "pprint.pprint(mat_A33_inv_GJ, width=40)\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "np.array(mat_A33_inv_GJ) @ A33\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 4x4\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "아래 행렬을 생각해 보자.
\n", - "Let's think about the following matrix.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A44_list = [\n", - " [1, 0, 2, 0],\n", - " [1, 1, 0, 0],\n", - " [1, 2, 0, 1],\n", - " [1, 1, 1, 1],\n", - "]\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A44 = np.array(A44_list, dtype=float)\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A44\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "hinton(A44)\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "다음 셀은 넘파이 다차원 배열 `numpy.ndarray` 을 위해 구현한 가우스 조르단 소거법 함수를 불러들인다.
\n", - "Following cell imports an implementation of the Gauss Jordan Elimination for a `numpy.ndarray`.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import gauss_jordan as gj\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "위 행렬에 적용해 보자.
\n", - "Let's apply to the matrix above.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A44_inv_array = gauss_jordan(A44.tolist(), b_hinton=True, b_savefig=False)\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A44_inv_array\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A44_inv_array @ A44\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy.testing as nt\n", - "\n", - "\n", - "nt.assert_allclose(A44_inv_array @ A44, np.array(get_identity(len(A44_list))))\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### n x n\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "좀 더 큰 행렬의 경우, 여인수행렬과 비교해 보자.
\n", - "Let's compare with the cofactor matrix.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "n = 7\n", - "Ann = nr.random((n, n))\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "hinton(Ann)\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "inv1 = gauss_jordan(Ann.tolist(), b_hinton=True, b_savefig=False)\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%time inv1 = gauss_jordan(Ann.tolist())\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's compare the computation time with the cofactor matrix algorithm.
\n", - "여인수 행렬 알고리듬과 계산 시간을 비교해 보자.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%time inv2 = (1/det(Ann)) * cofactor_matrix(Ann).T\n", - "inv2_array = np.array(inv2.tolist(), dtype=float)\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy.testing as nt\n", - "nt.assert_allclose(inv1, inv2_array)\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 연습 문제
Exercise\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "위 가우스 조단법에서 메모리를 더 절약하는 방안을 제안해 보시오
\n", - "Regarding the Gauss Jordan implementation above, propose how we can save more memory.\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 소거행렬
Elimination Matrix\n", - "\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2x2\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "다시 한번 단위 행렬을 덧붙인 행렬을 생각해 보자.
\n", - "Let's think about the augmented matrix again.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "AX22 = np.hstack([A22, I22])\n", - "AX22\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "(1, 0) 위치의 요소를 0으로 만드는 소거 행렬을 생각해 보자.
\n", - "Let's think about the elimination matrix making element at (1, 0) location.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "E10 = np.identity(A22.shape[0])\n", - "E10[1, 0] = -AX22[1, 0] / AX22[0, 0]\n", - "E10\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "AX22 = E10 @ AX22\n", - "AX22\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "이번에는, (0, 1) 위치의 요소를 0으로 만드는 소거 행렬을 생각해 보자.
\n", - "Let's think about the elimination matrix making element at (0, 1) location.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "E01 = np.identity(A22.shape[0])\n", - "E01[0, 1] = -AX22[0, 1] / AX22[1, 1]\n", - "E01\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "AX22 = E01 @ AX22\n", - "AX22\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "지금까지의 소거행렬을 순서 대로 곱해보자.
\n", - "Let's multipy the elimination matrices in the order.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "E01 @ E10\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "위에서 구했던 역행렬도 다음과 같다.
\n", - "The inverse matrix we found above were as follows, too.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "A22_inv\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 참고문헌
References\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "* Gilbert Strang. 18.06 Linear Algebra. Spring 2010. Massachusetts Institute of Technology: MIT OpenCourseWare, https://ocw.mit.edu. License: Creative Commons BY-NC-SA.\n", - "* Marc Peter Deisenroth, A Aldo Faisal, and Cheng Soon Ong, Mathematics For Machine Learning, Cambridge University Press, 2020, ISBN 978-1108455145.\n", - "* Erwin Kreyszig, Advanced Engineering Mathematics, 5th Ed, John Wiley & Sons, 1983, ISBN 0-471-86251-7.\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Final Bell
마지막 종\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# stackoverfow.com/a/24634221\n", - "import os\n", - "os.system(\"printf '\\a'\");\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "colab": { - "include_colab_link": true, - "provenance": [] - }, - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 0 + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "pFG598RJAMGF" + }, + "outputs": [], + "source": [ + "# This cell is for the Google Colaboratory\n", + "# https://stackoverflow.com/a/63519730\n", + "if 'google.colab' in str(get_ipython()):\n", + " path_py = '/content/nmisp_py'\n", + "\n", + " import os\n", + " if not os.path.exists(path_py):\n", + " import subprocess\n", + " subprocess.run(\n", + " ('git', 'clone', 'https://github.com/kangwonlee/nmisp_py')\n", + " )\n", + " assert os.path.exists(path_py)\n", + "\n", + " import sys\n", + " sys.path.insert(0, path_py)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8wpZSj6pAMGH" + }, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import numpy.linalg as nl\n", + "import numpy.random as nr\n", + "import sympy as sym\n", + "import IPython.display as disp\n", + "\n", + "sym.init_printing()\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "XKIGFef8AMGI" + }, + "source": [ + "The following function would visualize a numerical matrix using the [Hinton Diagram](https://matplotlib.org/stable/gallery/specialty_plots/hinton_demo.html).
\n", + "아래 함수는 행렬을 [힌튼 다이어그램](https://matplotlib.org/stable/gallery/specialty_plots/hinton_demo.html)으로 시각화할 것이다.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "CdNGyq8MAMGJ" + }, + "outputs": [], + "source": [ + "def hinton(matrix, max_weight=None, ax=None, fname=None):\n", + " '''\n", + " Draw Hinton diagram for visualizing a weight matrix.\n", + " https://matplotlib.org/stable/gallery/specialty_plots/hinton_demo.html\n", + " '''\n", + " ax = ax if ax is not None else plt.gca()\n", + "\n", + " if not max_weight:\n", + " max_weight = 2 ** np.ceil(np.log2(np.abs(matrix).max()))\n", + "\n", + " ax.patch.set_facecolor('gray')\n", + " ax.set_aspect('equal', 'box')\n", + "\n", + " ax.xaxis.set_major_locator(plt.NullLocator())\n", + " ax.yaxis.set_major_locator(plt.NullLocator())\n", + "\n", + " for (y, x), w in np.ndenumerate(matrix):\n", + " color = 'white' if w > 0 else 'black'\n", + " size = np.sqrt(abs(w) / max_weight)\n", + " rect = plt.Rectangle([x - size / 2, y - size / 2], size, size,\n", + " facecolor=color, edgecolor=color)\n", + " ax.add_patch(rect)\n", + "\n", + " ax.autoscale_view()\n", + " ax.invert_yaxis()\n", + "\n", + " if fname is None:\n", + " plt.show()\n", + " plt.close()\n", + " else:\n", + " plt.savefig(fname, dpi=300)\n", + " plt.close()\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8UIHm-zkAMGK" + }, + "outputs": [], + "source": [ + "a, b, c, d = sym.symbols('a b c d')\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "eTg1b7HEAMGK" + }, + "source": [ + "# 역행렬
Inverse matrix\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "nQrEad2pAMGK" + }, + "source": [ + "## 2x2\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "VsR8_YjzAMGL" + }, + "source": [ + "다음과 같은 2x2 행렬의 역행렬을 구하는 법은 이미 알고 있을 것이다.
\n", + "We know how we can find a 2x2 matrix as follows.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "M_uAYh3JAMGL" + }, + "source": [ + "$$\n", + "A = \\begin{bmatrix}\n", + " a & b\\\\\n", + " c & d \\\\\n", + "\\end{bmatrix}\n", + "$$\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ekyiJYipAMGL" + }, + "outputs": [], + "source": [ + "A = sym.Matrix([\n", + " [a, b],\n", + " [c, d]]\n", + ")\n", + "A\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "YifSlmu_AMGM" + }, + "source": [ + "$$\n", + "A^{-1} = \\frac {1}{ad-bc}\\begin{bmatrix}\n", + " d & -b\\\\\n", + " -c & a \\\\\n", + "\\end{bmatrix}\n", + "$$\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ehFlEY-WAMGM" + }, + "source": [ + "여기서 $ad-bc$ 는 해당 행렬의 *행렬식* 이다.
\n", + "Here $ad-bc$ is the *determinant* of the matrix.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "NTTWxwBxAMGM" + }, + "outputs": [], + "source": [ + "def det22(matA):\n", + " assert (2, 2) == matA.shape\n", + " return matA[0, 0] * matA[1, 1] - matA[0, 1] * matA[1, 0]\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-iBrTk4rAMGM" + }, + "source": [ + "그런데 행렬 부분은 어떠한가?
\n", + "What about the matrix part?\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "xlPu_LDiAMGM" + }, + "outputs": [], + "source": [ + "adjA = sym.Matrix([\n", + " [d, -b],\n", + " [-c, a]]\n", + ")\n", + "adjA\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "OK4-7ShHAMGM" + }, + "source": [ + "원래의 행렬과 곱해보자.
\n", + "Let's multiply with the original matrix.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "cubZNlaPAMGN" + }, + "outputs": [], + "source": [ + "A * adjA\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-XoDNM85AMGN" + }, + "source": [ + "결과는 어떠한 형태인가?
\n", + "What does the result look like?\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "VNkStyLSAMGN" + }, + "source": [ + "임의의 크기의 행렬에 대해 그러한 행렬을 찾을 수 있을까?
\n", + "Can we find such matrix for a matrix of an arbitrary size?\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9_KkO7SeAMGN" + }, + "source": [ + "## 행렬식
Determinant\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4FjKgZPWAMGN" + }, + "source": [ + "### 3x3\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "JykRugL7AMGN" + }, + "source": [ + "다음과 같은 3x3 행렬을 생각해 보자.
\n", + "Let's think about a 3x3 matrix as follows.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_KwH09ynAMGN" + }, + "outputs": [], + "source": [ + "e, f, g, h, i = sym.symbols(list('efghi'))\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true, + "id": "reV68F3RAMGN" + }, + "outputs": [], + "source": [ + "A = sym.Matrix([\n", + " [a, b, c],\n", + " [d, e, f,],\n", + " [g, h, i,],\n", + "])\n", + "A\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "QuwNsywxAMGO" + }, + "source": [ + "해당 행렬의 행렬식을 구해보자.
\n", + "Let's find the determinant of the matrix.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "mxMZBAedAMGO" + }, + "source": [ + "#### 소행렬식
Minor\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BTI_uEcBAMGO" + }, + "source": [ + "$i$ 번째 행과 $j$번째 열을 삭제한 행렬을 생각해 보자.
\n", + "Let's consider a matrix without $i$-th row and $j$-th column.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "dtYQ7OBRAMGO" + }, + "outputs": [], + "source": [ + "def row_col_del(matA, row_i, col_j):\n", + " result = sym.Matrix(matA)\n", + " result.row_del(row_i)\n", + " result.col_del(col_j)\n", + " return result\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "UaKWakwuAMGO" + }, + "outputs": [], + "source": [ + "A00 = row_col_del(A, 0, 0)\n", + "A00\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "jD3nd_crAMGO" + }, + "outputs": [], + "source": [ + "A01 = row_col_del(A, 0, 1)\n", + "A01\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "98JqcjvpAMGO" + }, + "outputs": [], + "source": [ + "A02 = row_col_del(A, 0, 2)\n", + "A02\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Bcjg5EXaAMGO" + }, + "source": [ + "행렬 $A_{ij}$ 는 $A$ 행렬에서 $i$행 $j$열을 제외한 $\\left(n-1\\right) \\times \\left(n-1\\right)$ 행렬이다 .
\n", + "Matrix $A_{ij}$ is a $\\left(n-1\\right) \\times \\left(n-1\\right)$ matrix excluding $i$-th row and $j$-th column of the matrix $A$.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "G3senfbiAMGO" + }, + "source": [ + "행렬식은 다음과 같이 계산할 수 있다. 이를 *소행렬식* 이라 한다.
\n", + "We can calculate the determinant as follows. This is called the *Minor*.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true, + "id": "3bnX5hJEAMGP" + }, + "outputs": [], + "source": [ + "det1 = A[0, 0] * det22(A00) - A[0, 1] * det22(A01) + A[0, 2] * det22(A02)\n", + "det1\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DvJM8uq4AMGP" + }, + "source": [ + "함수 형태로는 다음과 같다.
\n", + "We may write in a function as follows.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "l_TMxRJyAMGP" + }, + "outputs": [], + "source": [ + "def det33(matA:np.ndarray) -> float:\n", + "\n", + " result = 0\n", + "\n", + " for j in range(matA.shape[1]):\n", + " result += ((-1) ** j) * matA[0, j] * det22(row_col_del(matA, 0, j))\n", + "\n", + " return result\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DukLFDKJAMGP" + }, + "source": [ + "리스트 줄여쓰기로 다음과 같이 구현할 수도 있다.
\n", + "We can implement as follows using the list comprehension.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "NLx9R46-AMGP" + }, + "outputs": [], + "source": [ + "def det33_list_comprehension(matA:np.ndarray) -> float:\n", + " return sum(\n", + " [((-1) ** j) * matA[0, j] * det22(row_col_del(matA, 0, j)) for j in range(matA.shape[1])]\n", + " )\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "lDyxlamWAMGP" + }, + "source": [ + "아래 셀은 함수를 확인한다.
\n", + "Following cell checks the function.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "D21WdQurAMGT" + }, + "outputs": [], + "source": [ + "assert 0 == sym.simplify(det33(A) - det1)\n", + "assert 0 == sym.simplify(det33_list_comprehension(A) - det1)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "N219Zx70AMGT" + }, + "source": [ + "### n x n, n > 3\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "wPz_YSPpAMGT" + }, + "source": [ + "일반화 하면 다음과 같다.
\n", + "We can generalize as follows.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "qCFIwa4_AMGT" + }, + "outputs": [], + "source": [ + "def det(matA:np.ndarray) -> float:\n", + " if 2 == matA.shape[0]:\n", + " result = det22(matA)\n", + " elif 2 < matA.shape[0]:\n", + " result = sum(\n", + " [((-1) ** j) * matA[0, j] * det(row_col_del(matA, 0, j)) for j in range(matA.shape[1])]\n", + " )\n", + " return result\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "fVO9oDwVAMGU" + }, + "source": [ + "## 여인수행렬
Cofactor matrix\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Hk-EeUZeAMGU" + }, + "source": [ + "행렬 $A_{ij}$ 의 행렬식, *소행렬식* 에 번갈아 부호를 붙인 것을 *여인수* $C_{ij}$ 라고 한다.
\n", + "The signed version of the *minor*, determinant of the matrix $A_{ij}$, is the *cofactor* $C_{ij}$.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "l6SZJuV5AMGU" + }, + "outputs": [], + "source": [ + "def cofactor(A, i, j):\n", + " return det(row_col_del(A, i, j))\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "J5kTyBfqAMGU" + }, + "source": [ + "여인수로 이루어진 행렬을 생각해 보자.
\n", + "Let's think about the matrix of cofactors.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "q_WtO8-mAMGU" + }, + "outputs": [], + "source": [ + "def cofactor_matrix(matA):\n", + " return sym.Matrix([[cofactor(matA, i, j) * ((-1) ** (i+j)) for j in range(matA.shape[1])] for i in range(matA.shape[0])])\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "uWWJRlLiAMGU" + }, + "outputs": [], + "source": [ + "cofactor_A = cofactor_matrix(A)\n", + "cofactor_A\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0PDGnqAGAMGU" + }, + "source": [ + "*여인수행렬* 의 전치행렬을 *수반행렬* 이라고 한다.
\n", + "The transpose of a *cofactor matrix* is the *adjugate matrix*.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9jNHoPniAMGU" + }, + "source": [ + "원래 행렬 $A$와 *수반행렬* 을 곱해 보자.
\n", + "Let's multiply the origitnal matrix $A$ and its *adjugate matrix*.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "fu-Uw10VAMGU" + }, + "outputs": [], + "source": [ + "sym.simplify(A * cofactor_A.T)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "OPLnHEaSAMGV" + }, + "source": [ + "위 행렬을 $A$의 행렬식으로 나누어 보자.
\n", + "Let's divide the matrix above with the determinant of $A$.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true, + "id": "liIcIl6fAMGV" + }, + "outputs": [], + "source": [ + "sym.simplify(A * cofactor_A.T / det1)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rsiapbvfAMGV" + }, + "source": [ + "위 결과는 어떠한가?
\n", + "How is the result above?\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Zo2Q_6J6AMGV" + }, + "source": [ + "## 2x2 : Gauss Jordan Method\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "AYBhCJzyAMGV" + }, + "source": [ + "다음 비디오는 역행열 찾는 가우스 조단법을 소개한다.
\n", + "Following video introduces Gauss Jordan method finding the inverse matrix. (36:23 ~ 42:20)\n", + "\n", + "[![MIT OCW 18.06 Lecture 3 Multiplication and Inverse Matrices](https://i.ytimg.com/vi/FX4C-JpTFgY/hqdefault.jpg)](https://www.youtube.com/watch?v=FX4C-JpTFgY&list=PL221E2BBF13BECF6C&index=9&start=2183&end=2540)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Bziir1KoAMGV" + }, + "source": [ + "아래 2x2 행렬을 생각해 보자.
\n", + "Let's think about the 2x2 matrix.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "F_7LLPcgAMGV" + }, + "outputs": [], + "source": [ + "A22 = np.array([\n", + " [1, 3],\n", + " [2, 7]\n", + "])\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "s109EV41AMGW" + }, + "outputs": [], + "source": [ + "A22\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "yoYc0IZ8AMGW" + }, + "outputs": [], + "source": [ + "hinton(A22)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "MczhFqkkAMGW" + }, + "source": [ + "오른쪽에 같은 크기의 단위행렬을 붙여 보자.
\n", + "Let's augment an identity matrix of the same size.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "DM7uLXwLAMGW" + }, + "outputs": [], + "source": [ + "I22 = np.identity(2)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "NSC2qjL8AMGW" + }, + "outputs": [], + "source": [ + "I22\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "o7QiXhPPAMGW" + }, + "outputs": [], + "source": [ + "AX22 = np.hstack([A22, I22])\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "89JSjcRYAMGW" + }, + "outputs": [], + "source": [ + "AX22\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "kBV59nKaAMGX" + }, + "outputs": [], + "source": [ + "hinton(AX22)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "AK3BQi-pAMGX" + }, + "source": [ + "이제 왼쪽 2x2 부분을 단위행렬로 만들어 보자.
\n", + "Let's make the left 2x2 part an identity matrix.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ggLRlRahAMGX" + }, + "source": [ + "첫 행에 2를 곱한 후 2행에서 빼 보자.
\n", + "Let's multipy 2 to the first row and then subtract from the second row.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "nSsFZnjWAMGX" + }, + "outputs": [], + "source": [ + "AX22[1, :] -= 2 * AX22[0, :]\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true, + "id": "OEHRfWoyAMGX" + }, + "outputs": [], + "source": [ + "AX22\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "INUdFInLAMGX" + }, + "outputs": [], + "source": [ + "hinton(AX22)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "TDv2jau-AMGX" + }, + "source": [ + "이번에는 2번째 행에 3을 곱해서 첫 행에서 빼 보자.
\n", + "Now let's multipy 3 to the second row and subtract from the first row.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "s3q21SD8AMGX" + }, + "outputs": [], + "source": [ + "AX22[0, :] -= 3 * AX22[1, :]\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true, + "id": "cttYyrMWAMGY" + }, + "outputs": [], + "source": [ + "AX22\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "CrY72tk5AMGY" + }, + "outputs": [], + "source": [ + "hinton(AX22)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "3rQFR9z9AMGY" + }, + "source": [ + "위 `AX22` 행렬에서 오른쪽 두 행을 따로 떼어 보자.
\n", + "Let's separate the right two columns of the `AX22` matrix above.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "HWPXEDQ6AMGY" + }, + "outputs": [], + "source": [ + "A22_inv = AX22[:, 2:]\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "fNBUXzgmAMGY" + }, + "outputs": [], + "source": [ + "A22_inv\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Ye_zwo9RAMGY" + }, + "outputs": [], + "source": [ + "hinton(A22_inv)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "pLtfhIleAMGY" + }, + "source": [ + "`A22` 행렬과 곱해보자.
\n", + "Let's multipy with the A matrix.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "U2A3vhmRAMGY" + }, + "outputs": [], + "source": [ + "A22 @ A22_inv\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "NlOOlWgxAMGZ" + }, + "source": [ + "## `numpy`\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Fd9Rt6DxAMGZ" + }, + "source": [ + "`numpy.linalg.inv()` function is available.
\n", + "`numpy.linalg.inv()` 함수로 구할 수 있다.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "aXx2Y58FAMGZ" + }, + "outputs": [], + "source": [ + "A22_inv = nl.inv(A22)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "a0Q1PNDBAMGZ" + }, + "outputs": [], + "source": [ + "A22_inv\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_s5EoAYdAMGZ" + }, + "outputs": [], + "source": [ + "A22_inv @ A22\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "7IGoXHyoAMGZ" + }, + "source": [ + "## 3x3\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "k2ZS4aLLAMGZ" + }, + "source": [ + "다음 비디오는 3x3 행렬에 가우스 조단법을 적용한다.
\n", + "Following video applies the Gauss Jordan method to invert a 3x3 matrix.\n", + "\n", + "[![Khan Academy inverting 3x3 matrix part 2](https://i.ytimg.com/vi/obts_JDS6_Q/hqdefault.jpg)](https://www.youtube.com/watch?v=obts_JDS6_Q)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "HNtyXDaeAMGZ" + }, + "source": [ + "아래 행렬을 생각해 보자.
\n", + "Let's think about the following matrix.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "frYXad45AMGZ" + }, + "outputs": [], + "source": [ + "A33_list = [\n", + " [1, 0, 1],\n", + " [0, 2, 1],\n", + " [1, 1, 1],\n", + "]\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "cMrauFdmAMGa" + }, + "outputs": [], + "source": [ + "A33_list\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "7IDZ8CQyAMGa" + }, + "outputs": [], + "source": [ + "hinton(A33_list)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "6tDpP4YsAMGa" + }, + "outputs": [], + "source": [ + "A33 = np.array(A33_list)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "5ZWRVqIGAMGa" + }, + "outputs": [], + "source": [ + "A33\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "SBA1u91oAMGa" + }, + "outputs": [], + "source": [ + "hinton(A33)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BMtd7Rt_AMGa" + }, + "source": [ + "마찬가지로, 오른쪽에 같은 크기의 단위행렬을 붙여 보자.
\n", + "Same as before, let's augment an identity matrix of the same size.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "z_KyGtbsAMGb" + }, + "outputs": [], + "source": [ + "I33 = np.identity(A33.shape[0])\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "-x_kEf4oAMGb" + }, + "outputs": [], + "source": [ + "I33\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wz71QSH2AMGb" + }, + "outputs": [], + "source": [ + "AX33 = np.hstack([A33, I33])\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "KQfSww7aAMGb" + }, + "outputs": [], + "source": [ + "AX33\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Rici_OEsAMGb" + }, + "outputs": [], + "source": [ + "hinton(AX33)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "n7AX4E2-AMGb" + }, + "source": [ + "이제 왼쪽 부분을 단위행렬로 만들어 보자.
\n", + "Let's make the left part an identity matrix.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "drm5oDgZAMGb" + }, + "source": [ + "첫 행을 3행에서 빼 보자.
\n", + "Let's subtract the first row from the third row.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ZMYrsjpwAMGb" + }, + "outputs": [], + "source": [ + "AX33[2, :] -= AX33[0, :]\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true, + "id": "j1MW5jvIAMGc" + }, + "outputs": [], + "source": [ + "AX33\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "fR5hDlVUAMGc" + }, + "outputs": [], + "source": [ + "hinton(AX33)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "j1YH7fc5AMGc" + }, + "source": [ + "이번에는 2번째 행과 3번째 행을 바꾸자.
\n", + "Now let's swap the second and the third rows. ([ref](https://stackoverflow.com/a/54069951))\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wheb2hkJAMGc" + }, + "outputs": [], + "source": [ + "AX33[[1, 2]] = AX33[[2, 1]]\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": false, + "id": "v3l3yxoJAMGc" + }, + "outputs": [], + "source": [ + "AX33\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wtw_uDU6AMGc" + }, + "outputs": [], + "source": [ + "hinton(AX33)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "76BDtUerAMGc" + }, + "source": [ + "두번째 행에 2를 곱해서 3행에서 빼 보자.
\n", + "Let's multiply 2 to the second row and subtract from the third row.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "HWzpn3ztAMGc" + }, + "outputs": [], + "source": [ + "AX33[2, :] -= 2 * AX33[1, :]\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true, + "id": "h40BZgX-AMGc" + }, + "outputs": [], + "source": [ + "AX33\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ORkzMKsyAMGd" + }, + "outputs": [], + "source": [ + "hinton(AX33)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "P-6Rbi7MAMGd" + }, + "source": [ + "첫번째 행에서 3번째 행을 빼 보자.
\n", + "Let's subtract the third row from the first row.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8fgxzdbDAMGd" + }, + "outputs": [], + "source": [ + "AX33[0, :] -= AX33[2, :]\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true, + "id": "C7O5--kiAMGd" + }, + "outputs": [], + "source": [ + "AX33\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "V4ZbtoGxAMGd" + }, + "outputs": [], + "source": [ + "hinton(AX33)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "QHSu8tXkAMGd" + }, + "source": [ + "위 `AX` 행렬에서 오른쪽 세 열을 따로 떼어 보자.
\n", + "Let's separate the right three columns of the `AX` matrix above.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "t5hZJSWgAMGd" + }, + "outputs": [], + "source": [ + "A33_inv = AX33[:, 3:]\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "vUEFvnrcAMGd" + }, + "outputs": [], + "source": [ + "A33_inv\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "zPKyPElwAMGd" + }, + "outputs": [], + "source": [ + "hinton(A33_inv)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "SzA5aOrUAMGe" + }, + "source": [ + "`A33` 행렬과 곱해보자.
\n", + "Let's multipy with the `A33` matrix.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "vPJ_Z6YXAMGe" + }, + "outputs": [], + "source": [ + "A33 @ A33_inv\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9Lu54jHUAMGe" + }, + "source": [ + "## `numpy`\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "AGXrIm-pAMGe" + }, + "source": [ + "Please use `numpy.linlag.inv()`
`numpy.linlag.inv()`를 사용하자.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_AQkZh1JAMGe" + }, + "outputs": [], + "source": [ + "mat_A33_inv = nl.inv(A33)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Hv4veKDQAMGe" + }, + "outputs": [], + "source": [ + "mat_A33_inv\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "G_QNuo5ZAMGe" + }, + "outputs": [], + "source": [ + "A33 @ mat_A33_inv\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4ZcNp5heAMGe" + }, + "source": [ + "## 표준 기능으로 구현한 가우스 조단법
Gauss Jordan method in Standard library\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ckY6B92qAMGe" + }, + "source": [ + "다음 셀은 가우스 조단법을 표준기능 만으로 구현한다.
\n", + "Following cell implements the Gauss Jordan method with standard library only.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "IsyHz5kCAMGf" + }, + "outputs": [], + "source": [ + "import typing\n", + "\n", + "Scalar = typing.Union[int, float]\n", + "Row = typing.Union[typing.List[Scalar], typing.Tuple[Scalar]]\n", + "Matrix = typing.Union[typing.List[Row], typing.Tuple[Row]]\n", + "\n", + "\n", + "def get_zero(n:int) -> Matrix:\n", + " return [\n", + " [0] * n for i in range(n)\n", + " ]\n", + "\n", + "\n", + "def get_identity(n:int) -> Matrix:\n", + " result = get_zero(n)\n", + " for i in range(n):\n", + " result[i][i] = 1\n", + "\n", + " return result\n", + "\n", + "\n", + "def augment_mats(A:Matrix, B:Matrix):\n", + " assert len(A) == len(B)\n", + " return [row_A + row_B for row_A, row_B in zip(A, B)]\n", + "\n", + "\n", + "def gauss_jordan(A:Matrix, b_hinton:bool=False, epsilon=1e-7, b_savefig=False) -> Matrix:\n", + " AX = augment_mats(A, get_identity(len(A)))\n", + "\n", + " counter = 0\n", + "\n", + " # pivot loop\n", + " for p in range(len(AX)):\n", + "\n", + " assert abs(AX[p][p]) > epsilon, (p, AX)\n", + " one_over_pivot = 1.0 / AX[p][p]\n", + "\n", + " # normalize a row with one_over_pivot\n", + " for j in range(len(AX[p])):\n", + " AX[p][j] *= one_over_pivot\n", + "\n", + " # row loop\n", + " for i in range(len(AX)):\n", + " if i != p:\n", + " # row operation\n", + " multiplier = - AX[i][p]\n", + "\n", + " # column loop\n", + " for j in range(0, len(AX[p])):\n", + " AX[i][j] += multiplier * AX[p][j]\n", + "\n", + " # visualize augmented matrix\n", + " if b_hinton:\n", + " if b_savefig:\n", + " hinton(AX, fname=f'GJ{len(A)}{len(A)}-{counter:04d}.png')\n", + " counter += 1\n", + " else:\n", + " hinton(AX)\n", + "\n", + " return [row[len(A):] for row in AX]\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DCKJx6LUAMGf" + }, + "source": [ + "위 행렬의 예로 확인해 보자.
\n", + "Let's check with the matrix above.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "DByO4HkzAMGf" + }, + "outputs": [], + "source": [ + "mat_A33_inv_GJ = gauss_jordan(A33_list, b_hinton=True, b_savefig=False)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "qPkgXe6dAMGf" + }, + "outputs": [], + "source": [ + "import pprint\n", + "pprint.pprint(mat_A33_inv_GJ, width=40)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "aOivyksvAMGf" + }, + "outputs": [], + "source": [ + "np.array(mat_A33_inv_GJ) @ A33\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IjbdlAqwAMGf" + }, + "source": [ + "## 4x4\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_3yskWPbAMGf" + }, + "source": [ + "아래 행렬을 생각해 보자.
\n", + "Let's think about the following matrix.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "1-CK6H2lAMGg" + }, + "outputs": [], + "source": [ + "A44_list = [\n", + " [1, 0, 2, 0],\n", + " [1, 1, 0, 0],\n", + " [1, 2, 0, 1],\n", + " [1, 1, 1, 1],\n", + "]\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "89npMXaAAMGg" + }, + "outputs": [], + "source": [ + "A44 = np.array(A44_list, dtype=float)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "nH5H3e9GAMGg" + }, + "outputs": [], + "source": [ + "A44\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "WF8QY9D5AMGg" + }, + "outputs": [], + "source": [ + "hinton(A44)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "TdqNEccwAMGg" + }, + "source": [ + "다음 셀은 넘파이 다차원 배열 `numpy.ndarray` 을 위해 구현한 가우스 조르단 소거법 함수를 불러들인다.
\n", + "Following cell imports an implementation of the Gauss Jordan Elimination for a `numpy.ndarray`.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "alkzBxFQAMGg" + }, + "outputs": [], + "source": [ + "import gauss_jordan as gj\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Yyc0uSG0AMGg" + }, + "source": [ + "위 행렬에 적용해 보자.
\n", + "Let's apply to the matrix above.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "FCBD0K4dAMGg" + }, + "outputs": [], + "source": [ + "A44_inv_array = gauss_jordan(A44.tolist(), b_hinton=True, b_savefig=False)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Gb6QhMTbAMGh" + }, + "outputs": [], + "source": [ + "A44_inv_array\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "A_eEau3jAMGh" + }, + "outputs": [], + "source": [ + "A44_inv_array @ A44\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "2WOXg1ztAMGh" + }, + "outputs": [], + "source": [ + "import numpy.testing as nt\n", + "\n", + "\n", + "nt.assert_allclose(A44_inv_array @ A44, np.array(get_identity(len(A44_list))))\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "bYS-qKE2AMGh" + }, + "source": [ + "### n x n\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "thV5KxIGAMGh" + }, + "source": [ + "좀 더 큰 행렬의 경우, 여인수행렬과 비교해 보자.
\n", + "Let's compare with the cofactor matrix.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Ht5HP_ITAMGh" + }, + "outputs": [], + "source": [ + "n = 7\n", + "Ann = nr.random((n, n))\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "1NFJ4f-_AMGh" + }, + "outputs": [], + "source": [ + "hinton(Ann)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ti2l6ExYAMGi" + }, + "outputs": [], + "source": [ + "inv1 = gauss_jordan(Ann.tolist(), b_hinton=True, b_savefig=False)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "8TokLutcAMGi" + }, + "outputs": [], + "source": [ + "%time inv1 = gauss_jordan(Ann.tolist())\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "aOFgkBVLAMGi" + }, + "source": [ + "Let's compare the computation time with the cofactor matrix algorithm.
\n", + "여인수 행렬 알고리듬과 계산 시간을 비교해 보자.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ad-YouSNAMGi" + }, + "outputs": [], + "source": [ + "%time inv2 = (1/det(Ann)) * cofactor_matrix(Ann).T\n", + "inv2_array = np.array(inv2.tolist(), dtype=float)\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Ib9bUSYVAMGi" + }, + "outputs": [], + "source": [ + "import numpy.testing as nt\n", + "nt.assert_allclose(inv1, inv2_array)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "WW7GKYgMAMGi" + }, + "source": [ + "## 연습 문제
Exercise\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "vjGGyERyAMGi" + }, + "source": [ + "위 가우스 조단법에서 메모리를 더 절약하는 방안을 제안해 보시오
\n", + "Regarding the Gauss Jordan implementation above, propose how we can save more memory.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "IeULb_SdAMGj" + }, + "source": [ + "## 소거행렬
Elimination Matrix\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dWgQhXUeAMGj" + }, + "source": [ + "### 2x2\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "NRp3Sqn3AMGj" + }, + "source": [ + "다시 한번 단위 행렬을 덧붙인 행렬을 생각해 보자.
\n", + "Let's think about the augmented matrix again.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "JZmKDGYpAMGj" + }, + "outputs": [], + "source": [ + "AX22 = np.hstack([A22, I22])\n", + "AX22\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "fCRzwUoTAMGk" + }, + "source": [ + "(1, 0) 위치의 요소를 0으로 만드는 소거 행렬을 생각해 보자.
\n", + "Let's think about the elimination matrix making element at (1, 0) location.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "AjyJp6ZOAMGk" + }, + "outputs": [], + "source": [ + "E10 = np.identity(A22.shape[0])\n", + "E10[1, 0] = -AX22[1, 0] / AX22[0, 0]\n", + "E10\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "hQVufIyUAMGk" + }, + "outputs": [], + "source": [ + "AX22 = E10 @ AX22\n", + "AX22\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Z1xbqK67AMGk" + }, + "source": [ + "이번에는, (0, 1) 위치의 요소를 0으로 만드는 소거 행렬을 생각해 보자.
\n", + "Let's think about the elimination matrix making element at (0, 1) location.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ubMeq1S-AMGk" + }, + "outputs": [], + "source": [ + "E01 = np.identity(A22.shape[0])\n", + "E01[0, 1] = -AX22[0, 1] / AX22[1, 1]\n", + "E01\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "YY3Ii4Z5AMGl" + }, + "outputs": [], + "source": [ + "AX22 = E01 @ AX22\n", + "AX22\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5YGeMPLWAMGl" + }, + "source": [ + "지금까지의 소거행렬을 순서 대로 곱해보자.
\n", + "Let's multipy the elimination matrices in the order.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "m1Ag_lFJAMGl" + }, + "outputs": [], + "source": [ + "E01 @ E10\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "TT6OKW9BAMGl" + }, + "source": [ + "위에서 구했던 역행렬도 다음과 같다.
\n", + "The inverse matrix we found above were as follows, too.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "YwslErxoAMGm" + }, + "outputs": [], + "source": [ + "A22_inv\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "S_YksCk9AMGm" + }, + "source": [ + "## 참고문헌
References\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "iHTeUS1GAMGm" + }, + "source": [ + "* Gilbert Strang. 18.06 Linear Algebra. Spring 2010. Massachusetts Institute of Technology: MIT OpenCourseWare, https://ocw.mit.edu. License: Creative Commons BY-NC-SA.\n", + "* Marc Peter Deisenroth, A Aldo Faisal, and Cheng Soon Ong, Mathematics For Machine Learning, Cambridge University Press, 2020, ISBN 978-1108455145.\n", + "* Erwin Kreyszig, Advanced Engineering Mathematics, 5th Ed, John Wiley & Sons, 1983, ISBN 0-471-86251-7.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "o6G_6wYeAMGm" + }, + "source": [ + "## Final Bell
마지막 종\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "RrOWKR4LAMGm" + }, + "outputs": [], + "source": [ + "# stackoverfow.com/a/24634221\n", + "import os\n", + "os.system(\"printf '\\a'\");\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "DuCkd0p_AMGm" + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "colab": { + "provenance": [], + "include_colab_link": true + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 } \ No newline at end of file