diff --git a/.jupyter_cache/executed/92eb2f6c7e8c6dd52a2e0f759d52a6fe/base.ipynb b/.jupyter_cache/executed/92eb2f6c7e8c6dd52a2e0f759d52a6fe/base.ipynb new file mode 100644 index 0000000..f682954 --- /dev/null +++ b/.jupyter_cache/executed/92eb2f6c7e8c6dd52a2e0f759d52a6fe/base.ipynb @@ -0,0 +1,465 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "16c57cd0", + "metadata": {}, + "outputs": [], + "source": [ + "import IJulia\n", + "import Base64\n", + "\n", + "# The julia kernel has built in support for Revise.jl, so this is the \n", + "# recommended approach for long-running sessions:\n", + "# https://github.com/JuliaLang/IJulia.jl/blob/9b10fa9b879574bbf720f5285029e07758e50a5e/src/kernel.jl#L46-L51\n", + "\n", + "# Users should enable revise within .julia/config/startup_ijulia.jl:\n", + "# https://timholy.github.io/Revise.jl/stable/config/#Using-Revise-automatically-within-Jupyter/IJulia-1\n", + "\n", + "# clear console history\n", + "IJulia.clear_history()\n", + "\n", + "fig_width = 7\n", + "fig_height = 5\n", + "fig_format = :retina\n", + "fig_dpi = 96\n", + "\n", + "# no retina format type, use svg for high quality type/marks\n", + "if fig_format == :retina\n", + " fig_format = :svg\n", + "elseif fig_format == :pdf\n", + " fig_dpi = 96\n", + " # Enable PDF support for IJulia\n", + " IJulia.register_mime(MIME(\"application/pdf\"))\n", + "end\n", + "\n", + "# convert inches to pixels\n", + "fig_width = fig_width * fig_dpi\n", + "fig_height = fig_height * fig_dpi\n", + "\n", + "# Intialize Plots w/ default fig width/height\n", + "try\n", + " import Plots\n", + "\n", + " # Plots.jl doesn't support PDF output for versions < 1.28.1\n", + " # so use png (if the DPI remains the default of 300 then set to 96)\n", + " if (Plots._current_plots_version < v\"1.28.1\") & (fig_format == :pdf)\n", + " Plots.gr(size=(fig_width, fig_height), fmt = :png, dpi = fig_dpi)\n", + " else\n", + " Plots.gr(size=(fig_width, fig_height), fmt = fig_format, dpi = fig_dpi)\n", + " end\n", + "catch e\n", + " # @warn \"Plots init\" exception=(e, catch_backtrace())\n", + "end\n", + "\n", + "# Initialize CairoMakie with default fig width/height\n", + "try\n", + " import CairoMakie\n", + "\n", + " # CairoMakie's display() in PDF format opens an interactive window\n", + " # instead of saving to the ipynb file, so we don't do that.\n", + " # https://github.com/quarto-dev/quarto-cli/issues/7548\n", + " if fig_format == :pdf\n", + " CairoMakie.activate!(type = \"png\")\n", + " else\n", + " CairoMakie.activate!(type = string(fig_format))\n", + " end\n", + " CairoMakie.update_theme!(resolution=(fig_width, fig_height))\n", + "catch e\n", + " # @warn \"CairoMakie init\" exception=(e, catch_backtrace())\n", + "end\n", + " \n", + "# Set run_path if specified\n", + "try\n", + " run_path = \"L2hvbWUvdml0dXJpL0RvY3VtZW50b3MvR2l0SHViL1REQV93b3Jrc2hvcF9FQlQyMDI0\"\n", + " if !isempty(run_path)\n", + " run_path = String(Base64.base64decode(run_path))\n", + " cd(run_path)\n", + " end\n", + "catch e\n", + " @warn \"Run path init:\" exception=(e, catch_backtrace())\n", + "end\n", + "\n", + "\n", + "# emulate old Pkg.installed beahvior, see\n", + "# https://discourse.julialang.org/t/how-to-use-pkg-dependencies-instead-of-pkg-installed/36416/9\n", + "import Pkg\n", + "function isinstalled(pkg::String)\n", + " any(x -> x.name == pkg && x.is_direct_dep, values(Pkg.dependencies()))\n", + "end\n", + "\n", + "# ojs_define\n", + "if isinstalled(\"JSON\") && isinstalled(\"DataFrames\")\n", + " import JSON, DataFrames\n", + " global function ojs_define(; kwargs...)\n", + " convert(x) = x\n", + " convert(x::DataFrames.AbstractDataFrame) = Tables.rows(x)\n", + " content = Dict(\"contents\" => [Dict(\"name\" => k, \"value\" => convert(v)) for (k, v) in kwargs])\n", + " tag = \"\"\n", + " IJulia.display(MIME(\"text/html\"), tag)\n", + " end\n", + "elseif isinstalled(\"JSON\")\n", + " import JSON\n", + " global function ojs_define(; kwargs...)\n", + " content = Dict(\"contents\" => [Dict(\"name\" => k, \"value\" => v) for (k, v) in kwargs])\n", + " tag = \"\"\n", + " IJulia.display(MIME(\"text/html\"), tag)\n", + " end\n", + "else\n", + " global function ojs_define(; kwargs...)\n", + " @warn \"JSON package not available. Please install the JSON.jl package to use ojs_define.\"\n", + " end\n", + "end\n", + "\n", + "\n", + "# don't return kernel dependencies (b/c Revise should take care of dependencies)\n", + "nothing\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "36d66f84", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1-element Vector{Int64}:\n", + " 2" + ] + }, + "execution_count": 28, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# calculate the intersection of two vectors/sets\n", + "[1, 2] ∩ [2, 3, 4]" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "08d21493", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "true" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# check if a value is in a vector/set\n", + "1 ∉ [2, 3]" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "851cc7c7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "28.274333882308138" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# define a function in one line\n", + "f(r) = π*r^2\n", + "\n", + "f(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "f573e790", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.0 + 0.0im" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Euler's identity\n", + "ℯ^(im * π) + 1 |> round" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "73e97f66", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4×4 Matrix{Int64}:\n", + " 0 1 2 3\n", + " 1 0 1 2\n", + " 2 1 0 1\n", + " 3 2 1 0" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# calculating the pairwise-distance between points in a set\n", + "X = [1, 2, 3, 4]\n", + "d(x, y) = abs(x - y)\n", + "[d(xᵢ, xⱼ) for xᵢ ∈ X, xⱼ ∈ X]" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "86361caf", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4-element Vector{Float64}:\n", + " 0.8414709848078965\n", + " 0.9092974268256817\n", + " 0.1411200080598672\n", + " -0.7568024953079282" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x = [1, 2, 3, 4]\n", + "\n", + "# broadcast\n", + "sin.(x)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "e99cbf7f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4-element Vector{Float64}:\n", + " 0.8414709848078965\n", + " 0.9092974268256817\n", + " 0.1411200080598672\n", + " -0.7568024953079282" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# mapping\n", + "map(sin, x)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "1c035179", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4-element Vector{Float64}:\n", + " 0.8414709848078965\n", + " 0.9092974268256817\n", + " 0.1411200080598672\n", + " -0.7568024953079282" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# list comprehension\n", + "[sin(x_i) for x_i ∈ x]" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "33a55665", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.5143952585235492" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sin(cos(1))" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "099079b1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.5143952585235492" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "1 |> cos |> sin" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "61e08b23", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3.7416573867739413" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x = [1, 2, 3]\n", + "\n", + "# define the norm of a Vector of Numbers\n", + "norm(x::Vector{<:Number}) = x.^2 |> sum |> sqrt\n", + "norm(x)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "b8c449f1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.45973976729801924" + ] + }, + "execution_count": 39, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "norm(f::Function; step_size = 0.0001) = \n", + " [f(x) * step_size for x ∈ 0:step_size:1] .|> \n", + " abs |> sum\n", + " \n", + "norm(sin)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "ac55ca10", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.45969769413186023" + ] + }, + "execution_count": 40, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "abs(cos(1) - cos(0))" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "544a5386", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "norm(s::AbstractString) = length(s)\n", + "norm(\"Hello!\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Julia 1.10.4", + "language": "julia", + "name": "julia-1.10", + "path": "/home/vituri/.local/share/jupyter/kernels/julia-1.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} \ No newline at end of file diff --git a/.jupyter_cache/executed/e30a6e8fe7d08c970fc893851d731117/base.ipynb b/.jupyter_cache/executed/e30a6e8fe7d08c970fc893851d731117/base.ipynb new file mode 100644 index 0000000..b67bd69 --- /dev/null +++ b/.jupyter_cache/executed/e30a6e8fe7d08c970fc893851d731117/base.ipynb @@ -0,0 +1,563 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "b36377a2", + "metadata": {}, + "outputs": [], + "source": [ + "import IJulia\n", + "import Base64\n", + "\n", + "# The julia kernel has built in support for Revise.jl, so this is the \n", + "# recommended approach for long-running sessions:\n", + "# https://github.com/JuliaLang/IJulia.jl/blob/9b10fa9b879574bbf720f5285029e07758e50a5e/src/kernel.jl#L46-L51\n", + "\n", + "# Users should enable revise within .julia/config/startup_ijulia.jl:\n", + "# https://timholy.github.io/Revise.jl/stable/config/#Using-Revise-automatically-within-Jupyter/IJulia-1\n", + "\n", + "# clear console history\n", + "IJulia.clear_history()\n", + "\n", + "fig_width = 7\n", + "fig_height = 5\n", + "fig_format = :retina\n", + "fig_dpi = 96\n", + "\n", + "# no retina format type, use svg for high quality type/marks\n", + "if fig_format == :retina\n", + " fig_format = :svg\n", + "elseif fig_format == :pdf\n", + " fig_dpi = 96\n", + " # Enable PDF support for IJulia\n", + " IJulia.register_mime(MIME(\"application/pdf\"))\n", + "end\n", + "\n", + "# convert inches to pixels\n", + "fig_width = fig_width * fig_dpi\n", + "fig_height = fig_height * fig_dpi\n", + "\n", + "# Intialize Plots w/ default fig width/height\n", + "try\n", + " import Plots\n", + "\n", + " # Plots.jl doesn't support PDF output for versions < 1.28.1\n", + " # so use png (if the DPI remains the default of 300 then set to 96)\n", + " if (Plots._current_plots_version < v\"1.28.1\") & (fig_format == :pdf)\n", + " Plots.gr(size=(fig_width, fig_height), fmt = :png, dpi = fig_dpi)\n", + " else\n", + " Plots.gr(size=(fig_width, fig_height), fmt = fig_format, dpi = fig_dpi)\n", + " end\n", + "catch e\n", + " # @warn \"Plots init\" exception=(e, catch_backtrace())\n", + "end\n", + "\n", + "# Initialize CairoMakie with default fig width/height\n", + "try\n", + " import CairoMakie\n", + "\n", + " # CairoMakie's display() in PDF format opens an interactive window\n", + " # instead of saving to the ipynb file, so we don't do that.\n", + " # https://github.com/quarto-dev/quarto-cli/issues/7548\n", + " if fig_format == :pdf\n", + " CairoMakie.activate!(type = \"png\")\n", + " else\n", + " CairoMakie.activate!(type = string(fig_format))\n", + " end\n", + " CairoMakie.update_theme!(resolution=(fig_width, fig_height))\n", + "catch e\n", + " # @warn \"CairoMakie init\" exception=(e, catch_backtrace())\n", + "end\n", + " \n", + "# Set run_path if specified\n", + "try\n", + " run_path = \"L2hvbWUvdml0dXJpL0RvY3VtZW50b3MvR2l0SHViL1REQV93b3Jrc2hvcF9FQlQyMDI0\"\n", + " if !isempty(run_path)\n", + " run_path = String(Base64.base64decode(run_path))\n", + " cd(run_path)\n", + " end\n", + "catch e\n", + " @warn \"Run path init:\" exception=(e, catch_backtrace())\n", + "end\n", + "\n", + "\n", + "# emulate old Pkg.installed beahvior, see\n", + "# https://discourse.julialang.org/t/how-to-use-pkg-dependencies-instead-of-pkg-installed/36416/9\n", + "import Pkg\n", + "function isinstalled(pkg::String)\n", + " any(x -> x.name == pkg && x.is_direct_dep, values(Pkg.dependencies()))\n", + "end\n", + "\n", + "# ojs_define\n", + "if isinstalled(\"JSON\") && isinstalled(\"DataFrames\")\n", + " import JSON, DataFrames\n", + " global function ojs_define(; kwargs...)\n", + " convert(x) = x\n", + " convert(x::DataFrames.AbstractDataFrame) = Tables.rows(x)\n", + " content = Dict(\"contents\" => [Dict(\"name\" => k, \"value\" => convert(v)) for (k, v) in kwargs])\n", + " tag = \"\"\n", + " IJulia.display(MIME(\"text/html\"), tag)\n", + " end\n", + "elseif isinstalled(\"JSON\")\n", + " import JSON\n", + " global function ojs_define(; kwargs...)\n", + " content = Dict(\"contents\" => [Dict(\"name\" => k, \"value\" => v) for (k, v) in kwargs])\n", + " tag = \"\"\n", + " IJulia.display(MIME(\"text/html\"), tag)\n", + " end\n", + "else\n", + " global function ojs_define(; kwargs...)\n", + " @warn \"JSON package not available. Please install the JSON.jl package to use ojs_define.\"\n", + " end\n", + "end\n", + "\n", + "\n", + "# don't return kernel dependencies (b/c Revise should take care of dependencies)\n", + "nothing\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "545b24e3", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1-element Vector{Int64}:\n", + " 2" + ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# calculate the intersection of two vectors/sets\n", + "[1, 2] ∩ [2, 3, 4]" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "555f3b8c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "true" + ] + }, + "execution_count": 45, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# check if a value is in a vector/set\n", + "1 ∉ [2, 3]" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "01ba53ca", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "28.274333882308138" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# define a function in one line\n", + "f(r) = π*r^2\n", + "\n", + "f(3)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "086901cc", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.0 + 0.0im" + ] + }, + "execution_count": 47, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Euler's identity\n", + "ℯ^(im * π) + 1 |> round" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "314de2f1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4×4 Matrix{Int64}:\n", + " 0 1 2 3\n", + " 1 0 1 2\n", + " 2 1 0 1\n", + " 3 2 1 0" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# calculating the pairwise-distance between points in a set\n", + "X = [1, 2, 3, 4]\n", + "d(x, y) = abs(x - y)\n", + "[d(xᵢ, xⱼ) for xᵢ ∈ X, xⱼ ∈ X]" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "cc2ef3f5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4-element Vector{Float64}:\n", + " 0.8414709848078965\n", + " 0.9092974268256817\n", + " 0.1411200080598672\n", + " -0.7568024953079282" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x = [1, 2, 3, 4]\n", + "\n", + "# broadcast\n", + "sin.(x)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "37ede2bc", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4-element Vector{Float64}:\n", + " 0.8414709848078965\n", + " 0.9092974268256817\n", + " 0.1411200080598672\n", + " -0.7568024953079282" + ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# mapping\n", + "map(sin, x)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "d325cdd0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4-element Vector{Float64}:\n", + " 0.8414709848078965\n", + " 0.9092974268256817\n", + " 0.1411200080598672\n", + " -0.7568024953079282" + ] + }, + "execution_count": 51, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# list comprehension\n", + "[sin(x_i) for x_i ∈ x]" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "e7b5d8ff", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.5143952585235492" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "sin(cos(1))" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "1e6e906d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.5143952585235492" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "1 |> cos |> sin" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "ecb006b6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3.7416573867739413" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "x = [1, 2, 3]\n", + "\n", + "# define the norm of a Vector of Numbers\n", + "norm(x::Vector{<:Number}) = x.^2 |> sum |> sqrt\n", + "norm(x)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "7990767d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.33338333500000006" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# norm on [0, 1]\n", + "norm(f::Function; step_size = 0.0001) = \n", + " [f(x) * step_size for x ∈ 0:step_size:1] .|> \n", + " abs |> sum\n", + "\n", + "square = x -> x^2\n", + " \n", + "norm(square)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "3879d64d", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "text/html": [ + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "using Plots;\n", + "plot(square, 0:0.1:1)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "1b86e5f1", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "6" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "norm(s::AbstractString) = length(s)\n", + "norm(\"Hello!\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Julia 1.10.4", + "language": "julia", + "name": "julia-1.10", + "path": "/home/vituri/.local/share/jupyter/kernels/julia-1.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} \ No newline at end of file diff --git a/.jupyter_cache/global.db b/.jupyter_cache/global.db index 58510cc..9031635 100644 Binary files a/.jupyter_cache/global.db and b/.jupyter_cache/global.db differ diff --git a/_freeze/index/execute-results/html.json b/_freeze/index/execute-results/html.json index 930db8d..e13b669 100644 --- a/_freeze/index/execute-results/html.json +++ b/_freeze/index/execute-results/html.json @@ -1,12 +1,16 @@ { - "hash": "cef7c1bb23e24b65ef73a122591b768d", + "hash": "1c33126d4c256416908a43587844f7cc", "result": { "engine": "jupyter", - "markdown": "---\nexecute:\n freeze: true # re-render only when source changes\n cache: true\n warning: false\n\njupyter: julia-1.10\n---\n\n\n\n\n\n# Introduction\n\n## Why Julia for topological data analysis?\n\nIn a world ruled by Python (and, in some areas, R), why use an exquisite and new language like Julia in this workshop? You can find some good reasons in the book [Julia Data Science](https://juliadatascience.io/programmers), but I will give some in the context of topology:\n\n::: {.callout-tip title=\"Reason 1\"}\n\nJulia is fast. You won't need to use another language to make some expensive computation.\n\n:::\n\nLet's say you read about a new algorithm to calculate the Vietoris-Rips. If you are a R/Python user, *your algorithm won't be written in R/Python* simply because R/Python is slow. Fast code in R/Python is written in C, C++, Fortran or Rust; this is called the [two language problem](https://juliadatascience.io/julia_accomplish#sec:two_language). Julia solves this because with enought knowledge about the compiler and the language, you will get performance nearly as good as if it was written in C. Optimize Julia code is not a trivial task, but is way easier than learning another language just to get good performance in some functions.\n\n![The famous deep learning package [`torch`](https://github.com/pytorch/pytorch) in Python has its core written mostly in C++. Python is just a \"glue\" interface.](images/intro/torch.png)\n\n![The deep learning package [`Flux.jl`](https://github.com/FluxML/Flux.jl) is 100% written in Julia.](images/intro/flux.png)\n\n::: {.callout-tip title=\"Reason 2\"}\n\nIt is easy to use another language inside Julia.\n\n:::\n\nEven though Julia is fast and has a robust ecosystem, Python and R have many more packages already good-to-go. You can use them easily with tools like [PythonCall](https://github.com/JuliaPy/PythonCall.jl) or [RCall](https://github.com/JuliaInterop/RCall.jl).\n\n::: {.callout-tip title=\"Reason 3\"}\n\nJulia looks like mathematics and has an elegant syntax.\n\n:::\n\n1) Being able to mix LaTeX symbols with code can make the code way more readable.\n\nYou can find many nice examples on [BeautifulAlgorithms.jl](https://github.com/mossr/BeautifulAlgorithms.jl). Below are some common Julia code:\n\n::: {#b8a53ca6 .cell execution_count=1}\n``` {.julia .cell-code}\n# calculate the intersection of two vectors/sets\n[1, 2] ∩ [2, 3, 4]\n```\n\n::: {.cell-output .cell-output-display execution_count=19}\n```\n1-element Vector{Int64}:\n 2\n```\n:::\n:::\n\n\n::: {#87f1a2a0 .cell execution_count=2}\n``` {.julia .cell-code}\n# check if a value is in a vector/set\n1 ∉ [2, 3]\n```\n\n::: {.cell-output .cell-output-display execution_count=20}\n```\ntrue\n```\n:::\n:::\n\n\n::: {#1d14942d .cell execution_count=3}\n``` {.julia .cell-code}\n# define a function in one line\nf(r) = π*r^2\n\nf(3)\n```\n\n::: {.cell-output .cell-output-display execution_count=21}\n```\n28.274333882308138\n```\n:::\n:::\n\n\n::: {#11d43ab3 .cell execution_count=4}\n``` {.julia .cell-code}\n# Euler's identity\nℯ^(im * π) + 1 |> round\n```\n\n::: {.cell-output .cell-output-display execution_count=22}\n```\n0.0 + 0.0im\n```\n:::\n:::\n\n\n::: {#1a2baa7a .cell execution_count=5}\n``` {.julia .cell-code}\n# calculating the pairwise-distance between points in a set\nX = [1, 2, 3, 4]\nd(x, y) = abs(x - y)\n[d(xᵢ, xⱼ) for xᵢ ∈ X, xⱼ ∈ X]\n```\n\n::: {.cell-output .cell-output-display execution_count=23}\n```\n4×4 Matrix{Int64}:\n 0 1 2 3\n 1 0 1 2\n 2 1 0 1\n 3 2 1 0\n```\n:::\n:::\n\n\n2) Easily apply a function to all elements of a vector/set:\n\n::: {#67c0cff5 .cell execution_count=6}\n``` {.julia .cell-code}\nx = [1, 2, 3, 4]\n\n# broadcast\nsin.(x)\n```\n\n::: {.cell-output .cell-output-display execution_count=24}\n```\n4-element Vector{Float64}:\n 0.8414709848078965\n 0.9092974268256817\n 0.1411200080598672\n -0.7568024953079282\n```\n:::\n:::\n\n\n::: {#6e4f4223 .cell execution_count=7}\n``` {.julia .cell-code}\n# mapping\nmap(sin, x)\n```\n\n::: {.cell-output .cell-output-display execution_count=25}\n```\n4-element Vector{Float64}:\n 0.8414709848078965\n 0.9092974268256817\n 0.1411200080598672\n -0.7568024953079282\n```\n:::\n:::\n\n\n::: {#09c069b0 .cell execution_count=8}\n``` {.julia .cell-code}\n# list comprehension\n[sin(x_i) for x_i ∈ x]\n```\n\n::: {.cell-output .cell-output-display execution_count=26}\n```\n4-element Vector{Float64}:\n 0.8414709848078965\n 0.9092974268256817\n 0.1411200080598672\n -0.7568024953079282\n```\n:::\n:::\n\n\n3) You can compose functions in the reading order \n\nInstead of writing\n\n::: {#fa85b971 .cell execution_count=9}\n``` {.julia .cell-code}\nsin(cos(1))\n```\n\n::: {.cell-output .cell-output-display execution_count=27}\n```\n0.5143952585235492\n```\n:::\n:::\n\n\nyou can \"pipe\" the functions as in\n\n::: {#30da4dd1 .cell execution_count=10}\n``` {.julia .cell-code}\n1 |> cos |> sin\n```\n\n::: {.cell-output .cell-output-display execution_count=28}\n```\n0.5143952585235492\n```\n:::\n:::\n\n\n4) Julia is a functional programming language with type hierarchy, which means that we have \"categories\" (types) and \"functors\" (functions) mapping between the types; moreover, its polimorphism means that the functions depend on the type of its arguments.\n\nFor example, suppose you want to define the norm of a vector:\n\n::: {#d9e11b94 .cell execution_count=11}\n``` {.julia .cell-code}\nx = [1, 2, 3]\n\n# define the norm of a Vector of Numbers\nnorm(x::Vector{<:Number}) = x.^2 |> sum |> sqrt\nnorm(x)\n```\n\n::: {.cell-output .cell-output-display execution_count=29}\n```\n3.7416573867739413\n```\n:::\n:::\n\n\nYou can also define the norm of a function $f$ as the approximate integral of $|f|$ on the interval $[0, 1]$:\n\n::: {#44923ce4 .cell execution_count=12}\n``` {.julia .cell-code}\nstep_size = 0.0001\nnorm(f::Function) = [abs(f(x) * step_size) for x ∈ 0:step_size:1] |> sum\nnorm(sin)\n```\n\n::: {.cell-output .cell-output-display execution_count=30}\n```\n0.45973976729801924\n```\n:::\n:::\n\n\nwhich is very close to\n\n::: {#e5875354 .cell execution_count=13}\n``` {.julia .cell-code}\nabs(cos(1) - cos(0))\n```\n\n::: {.cell-output .cell-output-display execution_count=31}\n```\n0.45969769413186023\n```\n:::\n:::\n\n\nWhy not define the norm of a text as the amount of characters?\n\n::: {#46dc926d .cell execution_count=14}\n``` {.julia .cell-code}\nnorm(s::AbstractString) = length(s)\nnorm(\"Hello!\")\n```\n\n::: {.cell-output .cell-output-display execution_count=32}\n```\n6\n```\n:::\n:::\n\n\n## Why TDA?\n\nTopological Data Analysis is a very curious field of mathematics that apply tools from topology and algebraic topology in the study of datasets. By \"datasets\", we almost always mean \"finite metric space\".\n\nThese tools can be divided in some broad categories:\n\n### Homological methods\n\nPersistence homology calculates the \"shape\" (homology groups) of a object on different scales, and compact this information into objects called \"barcodes\". This barcode can be vectorized and then inserted into machine learning models.\n\n### Graph reduction methods\n\nThe Mapper algorithm is the discrete version of the [Reeb graph](https://en.wikipedia.org/wiki/Reeb_graph). It captures the geometry of a dataset with respect to a given function (called \"filter\") and produce a graph of its pre-images clustered. There is also the Ball Mapper variant, which does not need a filter function and resembles the Vietoris-Rips filtration. These methods are useful to get a glimpse of the geometry (flares, holes) and areas of interest. For example: if your metric space is a dataset of measurements of patients with diabets, the Mapper graph can represent the patients and the shape of this graph can give insights about the type of diabetes one has.\n\n### Clustering methods\n\nAlgorithms like ToMATo are clustering algorithms: we have a metric space as input, and return a partition of this dataset. Clustering is useful whenever we need to \"group a set of objects in such a way that objects in the same group (called a cluster) are more similar to each other than to those in other groups (clusters)\"^[https://en.wikipedia.org/wiki/Cluster_analysis].\n\n## Why this minicourse?\n\nThis minicourse is a good opportunity for pure topologists to see how we can use TDA *in practice*. It will be even better for the applied mathematicians who can promptly recognize the tools and algorithms I am using.\n\n", + "markdown": "---\nexecute:\n freeze: true # re-render only when source changes\n cache: true\n warning: false\n\njupyter: julia-1.10\n---\n\n\n\n\n\n# Introduction\n\n## Why Julia for topological data analysis?\n\nIn a world ruled by Python (and, in some areas, R), why use an exquisite and new language like Julia in this workshop? You can find some good reasons in the book [Julia Data Science](https://juliadatascience.io/programmers), but I will give some in the context of topology:\n\n### Speed\n\n::: {.callout-tip title=\"\" appearance=\"simple\"}\n\nJulia is fast. You won't need to use another language to make some expensive computation.\n\n:::\n\nLet's say you read about a new algorithm to calculate the Vietoris-Rips. If you are a R/Python user, *your algorithm won't be written in R/Python* simply because R/Python is slow. Fast code in R/Python is written in C, C++, Fortran or Rust; this is called the [two language problem](https://juliadatascience.io/julia_accomplish#sec:two_language). Julia solves this because with enought knowledge about the compiler and the language, you will get performance nearly as good as if it was written in C. Optimize Julia code is not a trivial task, but is way easier than learning another language just to get good performance in some functions.\n\n![The famous deep learning package [`torch`](https://github.com/pytorch/pytorch) in Python has its core written mostly in C++. Python is just a \"glue\" interface.](images/intro/torch.png)\n\n![The deep learning package [`Flux.jl`](https://github.com/FluxML/Flux.jl) is 100% written in Julia.](images/intro/flux.png)\n\n### Use other languages\n\n::: {.callout-tip title=\"\" appearance=\"simple\"}\n\nIt is easy to use another language inside Julia.\n\n:::\n\nEven though Julia is fast and has a robust ecosystem, Python and R have many more packages already good-to-go. You can use them easily with tools like [PythonCall](https://github.com/JuliaPy/PythonCall.jl) or [RCall](https://github.com/JuliaInterop/RCall.jl).\n\n### Mathematical syntax\n\n::: {.callout-tip title=\"\" appearance=\"simple\"}\n\nJulia looks like mathematics and has an elegant syntax.\n\n:::\n\n#### LaTeX symbols\n\nBeing able to mix LaTeX symbols with code can make the code way more readable.\n\nYou can find many nice examples on [BeautifulAlgorithms.jl](https://github.com/mossr/BeautifulAlgorithms.jl). Below are some common Julia code:\n\n::: {#545b24e3 .cell execution_count=1}\n``` {.julia .cell-code}\n# calculate the intersection of two vectors/sets\n[1, 2] ∩ [2, 3, 4]\n```\n\n::: {.cell-output .cell-output-display execution_count=44}\n```\n1-element Vector{Int64}:\n 2\n```\n:::\n:::\n\n\n::: {#555f3b8c .cell execution_count=2}\n``` {.julia .cell-code}\n# check if a value is in a vector/set\n1 ∉ [2, 3]\n```\n\n::: {.cell-output .cell-output-display execution_count=45}\n```\ntrue\n```\n:::\n:::\n\n\n::: {#01ba53ca .cell execution_count=3}\n``` {.julia .cell-code}\n# define a function in one line\nf(r) = π*r^2\n\nf(3)\n```\n\n::: {.cell-output .cell-output-display execution_count=46}\n```\n28.274333882308138\n```\n:::\n:::\n\n\n::: {#086901cc .cell execution_count=4}\n``` {.julia .cell-code}\n# Euler's identity\nℯ^(im * π) + 1 |> round\n```\n\n::: {.cell-output .cell-output-display execution_count=47}\n```\n0.0 + 0.0im\n```\n:::\n:::\n\n\n::: {#314de2f1 .cell execution_count=5}\n``` {.julia .cell-code}\n# calculating the pairwise-distance between points in a set\nX = [1, 2, 3, 4]\nd(x, y) = abs(x - y)\n[d(xᵢ, xⱼ) for xᵢ ∈ X, xⱼ ∈ X]\n```\n\n::: {.cell-output .cell-output-display execution_count=48}\n```\n4×4 Matrix{Int64}:\n 0 1 2 3\n 1 0 1 2\n 2 1 0 1\n 3 2 1 0\n```\n:::\n:::\n\n\n#### Broadcasting\n\nEasily apply a function to all elements of a vector/set:\n\n::: {#cc2ef3f5 .cell execution_count=6}\n``` {.julia .cell-code}\nx = [1, 2, 3, 4]\n\n# broadcast\nsin.(x)\n```\n\n::: {.cell-output .cell-output-display execution_count=49}\n```\n4-element Vector{Float64}:\n 0.8414709848078965\n 0.9092974268256817\n 0.1411200080598672\n -0.7568024953079282\n```\n:::\n:::\n\n\n::: {#37ede2bc .cell execution_count=7}\n``` {.julia .cell-code}\n# mapping\nmap(sin, x)\n```\n\n::: {.cell-output .cell-output-display execution_count=50}\n```\n4-element Vector{Float64}:\n 0.8414709848078965\n 0.9092974268256817\n 0.1411200080598672\n -0.7568024953079282\n```\n:::\n:::\n\n\n::: {#d325cdd0 .cell execution_count=8}\n``` {.julia .cell-code}\n# list comprehension\n[sin(x_i) for x_i ∈ x]\n```\n\n::: {.cell-output .cell-output-display execution_count=51}\n```\n4-element Vector{Float64}:\n 0.8414709848078965\n 0.9092974268256817\n 0.1411200080598672\n -0.7568024953079282\n```\n:::\n:::\n\n\n#### Piping\n\nYou can compose functions in the reading order. Instead of writing:\n\n::: {#e7b5d8ff .cell execution_count=9}\n``` {.julia .cell-code}\nsin(cos(1))\n```\n\n::: {.cell-output .cell-output-display execution_count=52}\n```\n0.5143952585235492\n```\n:::\n:::\n\n\nyou can \"pipe\" the functions as in:\n\n::: {#1e6e906d .cell execution_count=10}\n``` {.julia .cell-code}\n1 |> cos |> sin\n```\n\n::: {.cell-output .cell-output-display execution_count=53}\n```\n0.5143952585235492\n```\n:::\n:::\n\n\n#### Functional programming\n\nJulia is a [functional programming language](https://en.wikipedia.org/wiki/Functional_programming) with type hierarchy, which means that we have \"categories\" (ie. types) and \"functors\" (ie. functions) mapping between the types; moreover, its polimorphism means that the functions depend on the type of its arguments.\n\nFor example, suppose you want to define the norm of a vector:\n\n::: {#ecb006b6 .cell execution_count=11}\n``` {.julia .cell-code}\nx = [1, 2, 3]\n\n# define the norm of a Vector of Numbers\nnorm(x::Vector{<:Number}) = x.^2 |> sum |> sqrt\nnorm(x)\n```\n\n::: {.cell-output .cell-output-display execution_count=54}\n```\n3.7416573867739413\n```\n:::\n:::\n\n\nYou can also define the norm of a function $f$ as the approximate integral of $|f|$ on the interval $[0, 1]$:\n\n::: {#7990767d .cell execution_count=12}\n``` {.julia .cell-code}\n# norm on [0, 1]\nnorm(f::Function; step_size = 0.0001) = \n [f(x) * step_size for x ∈ 0:step_size:1] .|> \n abs |> sum\n\nsquare = x -> x^2\n \nnorm(square)\n```\n\n::: {.cell-output .cell-output-display execution_count=55}\n```\n0.33338333500000006\n```\n:::\n:::\n\n\nwhich is very close to the real definite integral.\n\nPS: plotting is also as easy as:\n\n::: {#3879d64d .cell execution_count=13}\n``` {.julia .cell-code}\nusing Plots;\nplot(square, 0:0.1:1)\n```\n\n::: {.cell-output .cell-output-display execution_count=56}\n```{=html}\n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n \n \n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n```\n:::\n:::\n\n\nWhy not define the norm of a text as the amount of characters?\n\n::: {#1b86e5f1 .cell execution_count=14}\n``` {.julia .cell-code}\nnorm(s::AbstractString) = length(s)\nnorm(\"Hello!\")\n```\n\n::: {.cell-output .cell-output-display execution_count=57}\n```\n6\n```\n:::\n:::\n\n\n## Why TDA?\n\nTopological Data Analysis is a very curious field of mathematics that apply tools from topology and algebraic topology in the study of datasets. By \"datasets\", we almost always mean \"finite metric space\".\n\nThese tools can be divided in some broad categories:\n\n### Homological methods\n\nPersistence homology calculates the \"shape\" (homology groups) of a object on different scales, and compact this information into objects called \"barcodes\". This barcode can be vectorized and then inserted into machine learning models.\n\n### Graph reduction methods\n\nThe Mapper algorithm is the discrete version of the [Reeb graph](https://en.wikipedia.org/wiki/Reeb_graph). It captures the geometry of a dataset with respect to a given function (called \"filter\") and produce a graph of its pre-images clustered. There is also the Ball Mapper variant, which does not need a filter function and resembles the Vietoris-Rips filtration. These methods are useful to get a glimpse of the geometry (flares, holes) and areas of interest. For example: if your metric space is a dataset of measurements of patients with diabets, the Mapper graph can represent the patients and the shape of this graph can give insights about the type of diabetes one has.\n\n### Clustering methods\n\nAlgorithms like ToMATo are clustering algorithms: we have a metric space as input, and return a partition of this dataset. Clustering is useful whenever we need to \"group a set of objects in such a way that objects in the same group (called a cluster) are more similar to each other than to those in other groups (clusters)\"^[https://en.wikipedia.org/wiki/Cluster_analysis].\n\n## Why this minicourse?\n\nThis minicourse is a good opportunity for pure topologists to see how we can use TDA *in practice*. It will be even better for the applied mathematicians who can promptly recognize the tools and algorithms I am using.\n\n", "supporting": [ "index_files" ], "filters": [], - "includes": {} + "includes": { + "include-in-header": [ + "\n\n\n" + ] + } } } \ No newline at end of file diff --git a/_quarto.yml b/_quarto.yml index 42b16d0..f81f3c0 100644 --- a/_quarto.yml +++ b/_quarto.yml @@ -36,6 +36,9 @@ format: max-width: 90vw preview-links: true # code-fold: true + toc-depth: 4 + number-depth: 3 + toc-expand: true code-tools: true grid: sidebar-width: 300px diff --git a/docs/index.html b/docs/index.html index 6dffe31..4a581e6 100644 --- a/docs/index.html +++ b/docs/index.html @@ -58,7 +58,7 @@ - + @@ -102,6 +102,9 @@ "search-label": "Search" } } + + + @@ -200,13 +203,24 @@