Compare commits

..

4 Commits
master ... test

Author SHA1 Message Date
Szymon Parafiński
ff9b949305 remove line photo 2022-05-18 14:12:24 +02:00
Szymon Parafiński
2d6dd73960 minor improvments 2022-05-18 14:09:41 +02:00
1bde756004 final version 2022-05-18 12:44:39 +02:00
bddd173633 test 2022-05-18 11:54:15 +02:00

View File

@ -2,9 +2,10 @@
"cells": [ "cells": [
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 1,
"metadata": { "metadata": {
"pycharm": { "pycharm": {
"is_executing": true,
"name": "#%%\n" "name": "#%%\n"
} }
}, },
@ -13,7 +14,7 @@
"name": "stderr", "name": "stderr",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"/var/folders/8w/3c34c7kd2n144tvm764_pdbw0000gq/T/ipykernel_84713/1134982733.py:12: DeprecationWarning: Importing display from IPython.core.display is deprecated since IPython 7.14, please import from IPython display\n", "/var/folders/8w/3c34c7kd2n144tvm764_pdbw0000gq/T/ipykernel_3019/1657712203.py:16: DeprecationWarning: Importing display from IPython.core.display is deprecated since IPython 7.14, please import from IPython display\n",
" from IPython.core.display import display, HTML\n" " from IPython.core.display import display, HTML\n"
] ]
}, },
@ -31,6 +32,7 @@
} }
], ],
"source": [ "source": [
"import pandas as pd\n",
"import numpy as np\n", "import numpy as np\n",
"import matplotlib.pyplot as plt\n", "import matplotlib.pyplot as plt\n",
"from skimage import data\n", "from skimage import data\n",
@ -40,6 +42,9 @@
"import scipy.linalg as la\n", "import scipy.linalg as la\n",
"from PIL import Image\n", "from PIL import Image\n",
"from ipywidgets import interact\n", "from ipywidgets import interact\n",
"from numpy.linalg import eig\n",
"from math import isclose\n",
"import pprint\n",
"\n", "\n",
"# zmień szerokość komórki\n", "# zmień szerokość komórki\n",
"from IPython.core.display import display, HTML\n", "from IPython.core.display import display, HTML\n",
@ -48,7 +53,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 4, "execution_count": 2,
"metadata": { "metadata": {
"pycharm": { "pycharm": {
"name": "#%%\n" "name": "#%%\n"
@ -114,7 +119,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 5, "execution_count": 20,
"metadata": { "metadata": {
"pycharm": { "pycharm": {
"name": "#%%\n" "name": "#%%\n"
@ -157,7 +162,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 6, "execution_count": 4,
"metadata": { "metadata": {
"pycharm": { "pycharm": {
"name": "#%%\n" "name": "#%%\n"
@ -166,46 +171,86 @@
"outputs": [], "outputs": [],
"source": [ "source": [
"def calculate(A):\n", "def calculate(A):\n",
" m = A.shape[0]\n", " n = A.shape[0]\n",
" n = A.shape[1]\n", " m = A.shape[1]\n",
" S = np.zeros(n)\n", " S = np.zeros(n)\n",
"\n", "\n",
" # finding eigenvectors with biggest eigenvalues of A*transpose(A)\n",
" helper = np.matmul(A, np.transpose(A))\n", " helper = np.matmul(A, np.transpose(A))\n",
" eigenvalues, eigenvectors = la.eigh(helper)\n", " eigenvalues, eigenvectors = eig(helper)\n",
" # descending sort of all the eigenvectors according to their eigenvalues\n", " \n",
" index = eigenvalues.argsort()[::-1]\n", " index = eigenvalues.argsort()[::-1]\n",
" eigenvalues = np.real(eigenvalues)\n",
" eigenvectors = np.real(eigenvectors)\n",
" eigenvalues = eigenvalues[index]\n", " eigenvalues = eigenvalues[index]\n",
" eigenvectors = eigenvectors[:, index]\n", " eigenvectors = eigenvectors[:, index]\n",
" U = eigenvectors\n", " U = eigenvectors\n",
"\n", "\n",
" # S is a diagonal matrix that keeps square root of eigenvalues\n", " helper2 = np.matmul(np.transpose(A), A)\n",
" eigenvalues2, eigenvectors2 = eig(helper2)\n",
" index2 = eigenvalues2.argsort()[::-1]\n",
" eigenvalues2 = np.real(eigenvalues2)\n",
" eigenvectors2 = np.real(eigenvectors2)\n",
" eigenvalues2 = eigenvalues2[index2]\n",
" eigenvectors2 = eigenvectors2[:, index2]\n",
" V = np.transpose(eigenvectors2)\n",
" \n",
" j = 0\n", " j = 0\n",
" for i in eigenvalues:\n", " for i in eigenvalues2:\n",
" if j == S.size:\n", " if j == S.size:\n",
" break\n", " break\n",
" elif i >= 0:\n", " elif i >= 0:\n",
" S[j] = np.sqrt(i)\n", " S[j] = np.sqrt(i)\n",
" j += 1\n", " j += 1\n",
" # same finding process for transpose(A)*A\n",
" helper = np.matmul(np.transpose(A), A)\n",
" eigenvalues, eigenvectors = la.eigh(helper)\n",
" # descending sort of all the eigenvectors according to their eigenvalues\n",
" index = eigenvalues.argsort()[::-1]\n",
" eigenvalues = eigenvalues[index]\n",
" eigenvectors = eigenvectors[:, index]\n",
" V = np.transpose(eigenvectors)\n",
"\n", "\n",
" # sorting S in descending order\n",
" S[::-1].sort()\n", " S[::-1].sort()\n",
" # print_to_file(S)\n",
"\n", "\n",
" return U, S, V" " return U, S, V"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 7, "execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"def check_sign_V(V, builtin):\n",
" if builtin.shape[0] < builtin.shape[1]:\n",
" for i in range(0,builtin.shape[0]):\n",
" for j in range(0,builtin.shape[1]):\n",
" if builtin[j][i] < 0.0 and V[j][i] > 0.0:\n",
" V[j][i] *= -1\n",
" elif builtin[j][i] > 0.0 and V[j][i] < 0.0:\n",
" V[j][i] *= -1\n",
" else:\n",
" for i in range(0,builtin.shape[0]):\n",
" for j in range(0,builtin.shape[1]):\n",
" if builtin[i][j] < 0.0 and V[i][j] > 0.0:\n",
" V[i][j] *= -1\n",
" elif builtin[i][j] > 0.0 and V[i][j] < 0.0:\n",
" V[i][j] *= -1\n",
" return V\n",
"\n",
"def check_sign_U(U, builtin):\n",
" if builtin.shape[0] < builtin.shape[1]: \n",
" for i in range(0,builtin.shape[0]):\n",
" for j in range(0,builtin.shape[1]):\n",
" if builtin[j][i] < 0.0 and U[j][i] > 0.0:\n",
" U[j][i] *= -1\n",
" elif builtin[j][i] > 0.0 and U[j][i] < 0.0:\n",
" U[j][i] *= -1\n",
" else:\n",
" for i in range(0,builtin.shape[0]):\n",
" for j in range(0,builtin.shape[1]):\n",
" if builtin[i][j] < 0.0 and U[i][j] > 0.0:\n",
" U[i][j] *= -1\n",
" elif builtin[j][j] > 0.0 and U[i][j] < 0.0:\n",
" U[i][j] *= -1\n",
" return U"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": { "metadata": {
"pycharm": { "pycharm": {
"name": "#%%\n" "name": "#%%\n"
@ -217,13 +262,98 @@
" \"\"\"\n", " \"\"\"\n",
" Wykonaj dekompozycję SVD, a następnie okrojoną rekonstrukcję (przy użyciu k wartości/wektorów osobliwych)\n", " Wykonaj dekompozycję SVD, a następnie okrojoną rekonstrukcję (przy użyciu k wartości/wektorów osobliwych)\n",
" \"\"\"\n", " \"\"\"\n",
"# U,s,V = svd(image,full_matrices=False)\n", " image = np.real(image)\n",
" U,s,V = calculate(image)\n", " U,s,V = svd(image,full_matrices=False)\n",
" reconst_matrix = np.dot(U[:,:k],np.dot(np.diag(s[:k]),V[:k,:]))\n", " reconst_matrix = np.dot(U[:,:k],np.dot(np.diag(s[:k]),V[:k,:]))\n",
"\n", "\n",
" return reconst_matrix,s" " return reconst_matrix,s"
] ]
}, },
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Przykładowa macierz"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"scrolled": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Matrix U:\n",
" 0 1 2 3\n",
"0 0.0 0.0 1.0 0.0\n",
"1 0.0 1.0 0.0 0.0\n",
"2 0.0 0.0 0.0 -1.0\n",
"3 1.0 0.0 0.0 0.0\n",
"\n",
"Matrix V:\n",
" 0 1 2 3 4\n",
"0 0.000000 1.0 0.0 0.0 0.000000\n",
"1 0.000000 0.0 1.0 0.0 0.000000\n",
"2 0.447214 0.0 0.0 0.0 0.894427\n",
"3 0.000000 0.0 0.0 1.0 0.000000\n",
"4 -0.894427 0.0 0.0 0.0 0.447214\n",
"\n",
"Matrix s:\n",
" 0\n",
"0 4.000000\n",
"1 3.000000\n",
"2 2.236068\n",
"3 0.000000\n",
"\n",
"--------------------------------------\n",
"\n",
"Reconstructed matrix: \n",
"\n",
" 0 1 2 3 4\n",
"0 1.0 0.0 0.0 0.0 2.0\n",
"1 0.0 0.0 3.0 0.0 0.0\n",
"2 0.0 0.0 0.0 0.0 0.0\n",
"3 0.0 4.0 0.0 0.0 0.0\n"
]
}
],
"source": [
"a = np.array([[1, 0, 0, 0, 2], \n",
" [0, 0, 3, 0, 0],\n",
" [0, 0, 0, 0, 0],\n",
" [0, 4, 0, 0, 0]])\n",
"\n",
"U,s,V = calculate(a)\n",
"U1,s1,V1 = svd(a)\n",
"U = check_sign_U(U, U1)\n",
"V = check_sign_V(V, V1)\n",
"\n",
"U_dataframe = pd.DataFrame(U)\n",
"s_dataframe = pd.DataFrame(s)\n",
"V_dataframe = pd.DataFrame(V)\n",
"\n",
"print(\"Matrix U:\")\n",
"print(U_dataframe)\n",
"\n",
"print(\"\\nMatrix V:\")\n",
"print(V_dataframe)\n",
"\n",
"print(\"\\nMatrix s:\")\n",
"print(s_dataframe)\n",
"\n",
"print('\\n--------------------------------------\\n')\n",
"k = 4\n",
"reconst_matrix4 = np.dot(U[:,:k],np.dot(np.diag(s[:k]),V[:k,:]))\n",
"\n",
"recon_dataframe_matrix = pd.DataFrame(reconst_matrix4)\n",
"print('Reconstructed matrix: \\n')\n",
"print(recon_dataframe_matrix)"
]
},
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": { "metadata": {
@ -264,25 +394,10 @@
" # compression rate = 100% * (k * (height + width + k)) / (height + width)" " # compression rate = 100% * (k * (height + width + k)) / (height + width)"
] ]
}, },
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
},
"source": [
"W celu zbadania, jak jakość zrekonstruowanego obrazu zmienia się wraz z $k$ należy użyć poniższego interaktywnego widżetu."
]
},
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 9, "execution_count": 9,
"metadata": { "metadata": {},
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [], "outputs": [],
"source": [ "source": [
"def compute_k_max(img_name):\n", "def compute_k_max(img_name):\n",
@ -305,6 +420,17 @@
"list_widget.observe(update_k_max,'value')" "list_widget.observe(update_k_max,'value')"
] ]
}, },
{
"cell_type": "markdown",
"metadata": {
"pycharm": {
"name": "#%% md\n"
}
},
"source": [
"W celu zbadania, jak jakość zrekonstruowanego obrazu zmienia się wraz z $k$ należy użyć poniższego interaktywnego widżetu."
]
},
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 10, "execution_count": 10,
@ -325,18 +451,19 @@
" \n", " \n",
" image=gray_images[img_name]\n", " image=gray_images[img_name]\n",
" original_shape = image.shape\n", " original_shape = image.shape\n",
" print(f\"Input image dimensions. Width:{original_shape[1]} Height:{original_shape[0]}\")\n", " print(f\"Input image dimensions. Width:{original_shape[1]} Height:{original_shape[0]}\\n\")\n",
"\n", "\n",
"# U,s,V = svd(image,full_matrices=False)\n", " U,s,V = svd(image,full_matrices=False)\n",
" U,s,V = calculate(image)\n", "\n",
" print(f\"Shape of U matrix: {U[:,:k].shape}\")\n", " U_dataframe = pd.DataFrame(U[:,:k])\n",
" print(f\"U MATRIX: {U[:,:k]}\")\n", " print(f\"U MATRIX:\\n {U_dataframe}\\n\")\n",
" print('*' * 100)\n", " print('\\n', '*' * 100, '\\n')\n",
" print(f\"Shape of S matrix: {s[:k].shape}\")\n", " print(f\"\\nShape of S matrix: {s[:k].shape[0]}\\n\")\n",
" print(f\"S MATRIX: {np.diag(s[:k])}\")\n", " s_dataframe = pd.DataFrame(np.diag(s[:k]))\n",
" print('*' * 100)\n", " print(f\"S MATRIX:\\n {s_dataframe}\")\n",
" print(f\"Shape of V matrix: {V[:k,:].shape}\")\n", " print('\\n', '*' * 100, '\\n')\n",
" print(f\"V MATRIX: {V[:k,:]}\")\n" " V_dataframe = pd.DataFrame(V[:k,:].T)\n",
" print(f\"V MATRIX:\\n {V_dataframe}\")\n"
] ]
}, },
{ {
@ -351,12 +478,12 @@
{ {
"data": { "data": {
"application/vnd.jupyter.widget-view+json": { "application/vnd.jupyter.widget-view+json": {
"model_id": "5de39e03944b4f70a566d6fd4e0e747e", "model_id": "40f7f6318beb4d248fc1b3aa82096324",
"version_major": 2, "version_major": 2,
"version_minor": 0 "version_minor": 0
}, },
"text/plain": [ "text/plain": [
"interactive(children=(Dropdown(description='img_name', options=('cat', 'astro', 'camera', 'coin', 'clock', 'te…" "interactive(children=(Dropdown(description='img_name', options=('cat', 'astro', 'line', 'camera', 'coin', 'clo…"
] ]
}, },
"metadata": {}, "metadata": {},
@ -389,12 +516,12 @@
{ {
"data": { "data": {
"application/vnd.jupyter.widget-view+json": { "application/vnd.jupyter.widget-view+json": {
"model_id": "a7efd777338d4ccfb3ab75d50a448d13", "model_id": "3ec2852728b145a0b405eb6c24ef4e9b",
"version_major": 2, "version_major": 2,
"version_minor": 0 "version_minor": 0
}, },
"text/plain": [ "text/plain": [
"interactive(children=(Dropdown(description='img_name', options=('cat', 'astro', 'camera', 'coin', 'clock', 'te…" "interactive(children=(Dropdown(description='img_name', options=('cat', 'astro', 'line', 'camera', 'coin', 'clo…"
] ]
}, },
"metadata": {}, "metadata": {},
@ -434,7 +561,7 @@
" \"koala\": img_as_float(Image.open('koala.jpeg')),\n", " \"koala\": img_as_float(Image.open('koala.jpeg')),\n",
" \"orange\": img_as_float(Image.open('orange.jpeg')),\n", " \"orange\": img_as_float(Image.open('orange.jpeg')),\n",
" \"teacher\": img_as_float(Image.open('teacher.jpeg'))\n", " \"teacher\": img_as_float(Image.open('teacher.jpeg'))\n",
"}\n" "}"
] ]
}, },
{ {
@ -503,14 +630,18 @@
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def print_color_matrices(img_name,k):\n", "def compute_k_max_color_images(img_name):\n",
" \"\"\"\n", " image = color_images[img_name]\n",
" Wyświetlanie macierzy U V S wraz z wymiarami.\n", " original_shape = image.shape\n",
" \"\"\"\n", " return (original_shape[0]*original_shape[1]*original_shape[2])//(original_shape[0] + 3*original_shape[1] + 1)\n",
" image = color_images[img_name]\n", "\n",
" original_shape = image.shape\n", "\n",
" image_reconst_layers = [compress_svd(image[:,:,i],k)[0] for i in range(3)]\n", "list_widget_color = widgets.Dropdown(options=list(color_images.keys()))\n",
" print(image_reconst_layers)" "int_slider_widget = widgets.IntSlider(min=1,max=compute_k_max_color_images('cat'))\n",
"def update_k_max_color(*args):\n",
" img_name=list_widget_color.value\n",
" int_slider_widget.max = compute_k_max_color_images(img_name)\n",
"list_widget_color.observe(update_k_max_color,'value')"
] ]
}, },
{ {
@ -532,73 +663,11 @@
"name": "#%%\n" "name": "#%%\n"
} }
}, },
"outputs": [],
"source": [
"def compute_k_max_color_images(img_name):\n",
" image = color_images[img_name]\n",
" original_shape = image.shape\n",
" return (original_shape[0]*original_shape[1]*original_shape[2])//(original_shape[0] + 3*original_shape[1] + 1)\n",
"\n",
"\n",
"list_widget = widgets.Dropdown(options=list(color_images.keys()))\n",
"int_slider_widget = widgets.IntSlider(min=1,max=compute_k_max_color_images('cat'))\n",
"def update_k_max_color(*args):\n",
" img_name=list_widget.value\n",
" int_slider_widget.max = compute_k_max_color_images(img_name)\n",
"list_widget.observe(update_k_max_color,'value')"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [ "outputs": [
{ {
"data": { "data": {
"application/vnd.jupyter.widget-view+json": { "application/vnd.jupyter.widget-view+json": {
"model_id": "51461a1fc1b944a0a967b11590d02c7f", "model_id": "eaba6da4395e43d4ab429b4cca24ad3f",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"interactive(children=(Dropdown(description='img_name', options=('cat', 'astro', 'coffee', 'rocket', 'koala', '…"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"<function __main__.print_color_matrices(img_name, k)>"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"interact(print_color_matrices, img_name=list_widget, k=int_slider_widget)"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "2ac1906f3030426cab0f7d8e8f5be577",
"version_major": 2, "version_major": 2,
"version_minor": 0 "version_minor": 0
}, },
@ -611,7 +680,7 @@
} }
], ],
"source": [ "source": [
"interact(compress_show_color_images_reshape,img_name=list_widget,k=int_slider_widget);" "interact(compress_show_color_images_reshape,img_name=list_widget_color,k=int_slider_widget);"
] ]
}, },
{ {
@ -638,7 +707,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 19, "execution_count": 17,
"metadata": { "metadata": {
"pycharm": { "pycharm": {
"name": "#%%\n" "name": "#%%\n"
@ -653,7 +722,6 @@
" image = color_images[img_name]\n", " image = color_images[img_name]\n",
" original_shape = image.shape\n", " original_shape = image.shape\n",
" image_reconst_layers = [compress_svd(image[:,:,i],k)[0] for i in range(3)]\n", " image_reconst_layers = [compress_svd(image[:,:,i],k)[0] for i in range(3)]\n",
"# print(image_reconst_layers)\n",
" image_reconst = np.zeros(image.shape)\n", " image_reconst = np.zeros(image.shape)\n",
" for i in range(3):\n", " for i in range(3):\n",
" image_reconst[:,:,i] = image_reconst_layers[i]\n", " image_reconst[:,:,i] = image_reconst_layers[i]\n",
@ -676,7 +744,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 20, "execution_count": 18,
"metadata": { "metadata": {
"pycharm": { "pycharm": {
"name": "#%%\n" "name": "#%%\n"
@ -690,19 +758,18 @@
" return (original_shape[0]*original_shape[1]*original_shape[2])// (3*(original_shape[0] + original_shape[1] + 1))\n", " return (original_shape[0]*original_shape[1]*original_shape[2])// (3*(original_shape[0] + original_shape[1] + 1))\n",
"\n", "\n",
"\n", "\n",
"list_widget = widgets.Dropdown(options=list(color_images.keys()))\n", "list_widget_color = widgets.Dropdown(options=list(color_images.keys()))\n",
"int_slider_widget = widgets.IntSlider(min=1,max=compute_k_max_color_images_layers('cat'))\n", "int_slider_widget = widgets.IntSlider(min=1,max=compute_k_max_color_images_layers('cat'))\n",
"def update_k_max_color_layers(*args):\n", "def update_k_max_color_layers(*args):\n",
" img_name=list_widget.value\n", " img_name=list_widget_color.value\n",
" int_slider_widget.max = compute_k_max_color_images_layers(img_name)\n", " int_slider_widget.max = compute_k_max_color_images_layers(img_name)\n",
"list_widget.observe(update_k_max_color_layers,'value')" "list_widget_color.observe(update_k_max_color_layers,'value')"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 21, "execution_count": 19,
"metadata": { "metadata": {
"collapsed": true,
"pycharm": { "pycharm": {
"name": "#%%\n" "name": "#%%\n"
} }
@ -711,7 +778,7 @@
{ {
"data": { "data": {
"application/vnd.jupyter.widget-view+json": { "application/vnd.jupyter.widget-view+json": {
"model_id": "8c96b6ed413848f2ad0bcf849e6c54d0", "model_id": "5089ca8c1cb845478b279185787ad156",
"version_major": 2, "version_major": 2,
"version_minor": 0 "version_minor": 0
}, },
@ -724,48 +791,8 @@
} }
], ],
"source": [ "source": [
"interact(print_color_matrices,img_name=list_widget,k=int_slider_widget);" "interact(compress_show_color_images_layer,img_name=list_widget_color,k=int_slider_widget);"
] ]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {
"collapsed": true,
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "00696a30e8374ba2ba4ab98c3ba13a75",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"interactive(children=(Dropdown(description='img_name', options=('cat', 'astro', 'coffee', 'rocket', 'koala', '…"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"interact(compress_show_color_images_layer,img_name=list_widget,k=int_slider_widget);"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": []
} }
], ],
"metadata": { "metadata": {