diff --git a/_freeze/other/fun/heliocentric_geocentric/execute-results/html.json b/_freeze/other/fun/heliocentric_geocentric/execute-results/html.json
index f85a0f6..96bff3d 100644
--- a/_freeze/other/fun/heliocentric_geocentric/execute-results/html.json
+++ b/_freeze/other/fun/heliocentric_geocentric/execute-results/html.json
@@ -1,9 +1,10 @@
{
- "hash": "770c48e86d93b31c3c14b551fff8ef78",
+ "hash": "bedea6bcfab5ecec06e10dce0137384b",
"result": {
- "markdown": "---\ntitle: Heliocentrism vs Geocentrism\nauthor: Connor Robertson\nexecute:\n daemon: true\n---\n\n## Overview\nAnother fun little animation that I saw recently was the difference in the dynamics of the solar system when approaching the equations from a heliocentric (sun-centered) or geocentric (Earth-centered) perspective.\nAlthough it's clear now that we orbit the sun and a sun-centered model of the solar system is more correct, it wasn't always obvious.\nThis concept extends to systems that we have not yet nailed down completely.\nThis [simple animation](https://www.youtube.com/watch?v=7n7xaviepKM&t=556s) demonstrates that identifying the correct perspective when modeling a system can have a huge pay off in the simplicity of your result.\n\nI thought I'd try to recreate this little animation with `Makie.jl` as I did previously with the [polygon GIF](polygon_angles.qmd).\n\n## Setting up\nIn this animation, we'll be rotating some circular shapes around the point representing either the sun or the Earth and tracing their paths as they progress.\nFirst, let's plot the initial frame of the animation using a `Figure` with 2 `axes`:\n\n::: {.cell execution_count=1}\n``` {.julia .cell-code}\nusing Pkg;\nPkg.activate(\".\");\nusing CairoMakie;\n```\n:::\n\n\n::: {.cell execution_count=2}\n``` {.julia .cell-code}\nf = Figure(resolution=(800,400));\naxes = [Axis(f[1,1]);Axis(f[1,2])]\nfor ax in axes ax.limits=(-22,22,-22,22) end\nfunction remove_axis_decor!(ax)\n ax.topspinevisible = false; ax.bottomspinevisible = false\n ax.leftspinevisible = false; ax.rightspinevisible = false\n ax.xgridvisible = false; ax.ygridvisible = false\n ax.xticksvisible = false; ax.yticksvisible = false\n ax.xticklabelsvisible = false; ax.yticklabelsvisible = false\nend\nremove_axis_decor!.(axes)\n```\n:::\n\n\nWe can now layout the different planets via a simple scatter plot in each `axis`.\nOf course, we cannot use the correct proportions or distances or the plot would be hard to understand.\nInstead, I'll settle for simple size differences between the planets and the sun and a somewhat uniform distance between each.\n\n::: {.cell execution_count=3}\n``` {.julia .cell-code}\nnum_bodies = 9\nbody_locs1 = [(float(i),0.0) for i in 0:2:2(num_bodies-1)]\nbody_locs2 = [(float(i),0.0) for i in -6:2:2(num_bodies-1)-6]\nbody_sizes = 3 .* [9,3,3,4,2,5,6,4,4]\nbody_colors = [:yellow,:red,:red,:blue,:red,:red,:red,:red,:red]\ns1 = scatter!(axes[1], body_locs1, markersize=body_sizes, color=body_colors)\ns2 = scatter!(axes[2], body_locs2, markersize=body_sizes, color=body_colors)\ndisplay(f)\n```\n\n::: {.cell-output .cell-output-display}\n![](heliocentric_geocentric_files/figure-html/cell-4-output-1.svg){}\n:::\n:::\n\n\n## Animation\nOkay!\nEasy as that.\nNow, we can move on to animating the rotation of the bodies.\nEach planet will rotate at a different speed and will go until again lining up as they started.\n\n::: {.cell execution_count=4}\n``` {.julia .cell-code}\nbody_speeds = [0.0,47.87,35.02,29.78,24.077,13.07,9.69,6.81,5.43] ./ 200\nsun_speed2 = body_speeds[4]\norbit_radii1 = [bl[1] for bl in body_locs1]\norbit_radii2 = [bl[1] for bl in body_locs2]\n\n# Use Observable to add time dependence to planet locations\ntime_i = Observable(0.0)\nbody_xs1 = @lift(orbit_radii1 .* cos.(-1 .* body_speeds .* $time_i))\nbody_ys1 = @lift(orbit_radii1 .* sin.(-1 .* body_speeds .* $time_i))\nbody_xs2 = @lift(vcat(\n orbit_radii2[1]*cos(-sun_speed2*$time_i),\n orbit_radii2[1]*cos(-sun_speed2*$time_i) + orbit_radii1[2]*cos(-body_speeds[2]*$time_i),\n orbit_radii2[1]*cos(-sun_speed2*$time_i) + orbit_radii1[3]*cos(-body_speeds[3]*$time_i),\n 0.0,\n orbit_radii2[1]*cos(-sun_speed2*$time_i) .+ orbit_radii1[5:end] .* cos.(-1 .* body_speeds[5:end] .* $time_i)\n))\nbody_ys2 = @lift(vcat(\n orbit_radii2[1]*sin(-sun_speed2*$time_i),\n orbit_radii2[1]*sin(-sun_speed2*$time_i) + orbit_radii1[2]*sin(-body_speeds[2]*$time_i),\n orbit_radii2[1]*sin(-sun_speed2*$time_i) + orbit_radii1[3]*sin(-body_speeds[3]*$time_i),\n 0.0,\n orbit_radii2[1]*sin(-sun_speed2*$time_i) .+ orbit_radii1[5:end] .* sin.(-1 .* body_speeds[5:end] .* $time_i)\n))\n\nempty!(axes[1].scene.plots)\nempty!(axes[2].scene.plots)\ns1 = scatter!(axes[1], body_xs1, body_ys1, markersize=body_sizes, color=body_colors)\ns2 = scatter!(axes[2], body_xs2, body_ys2, markersize=body_sizes, color=body_colors)\n\n# Create GIF by iterating time\nsteps = 300\nrecord(f, \"gifs/heliocentric_geocentric1.gif\", 1:steps) do t\n time_i[] = t\nend\n```\n:::\n\n\n![](gifs/heliocentric_geocentric1.gif)\n\nNice! \nWe've got the two animations moving well.\nNote that since the animation was fairly straightforward and only required updating the scatter plot locations, we were able to use an `Observable` for time in `Makie`.\nThis object allows us to create the initial scatter plots where the scatter locations are wrapped with the `@lift` macro with the interpolating `$time_i`.\nNow, when our `Observable`, `time_i` is updated, the scatter points and subsequently the scatter plots are updated.\nUsing this nifty tool, our recording loop is very straightforward.\nHowever, using the `@lift` macro is not particularly intuitive and it took some trial and error to get the definition of the scatter points correctly wrapped in an `Observable`.\nHence, the definitions of `body_xs2` and `body_ys2` are so messy..\n\nOur next step is to add the path tracing of the planets to each plot.\nAgain, this is a fairly simple procedure that could be completed with an `Observable`.\n\n::: {.cell execution_count=5}\n``` {.julia .cell-code}\n# Line observables\nline_locs1 = [Observable([body_locs1[i]]) for i in 1:num_bodies]\nline_locs2 = [Observable([body_locs2[i]]) for i in 1:num_bodies]\n\nempty!(axes[1].scene.plots)\nempty!(axes[2].scene.plots)\nfor i in 1:num_bodies\n lines!(axes[1], line_locs1[i], color=body_colors[i])\n lines!(axes[2], line_locs2[i], color=body_colors[i])\nend\ns1 = scatter!(axes[1], body_xs1, body_ys1, markersize=body_sizes, color=body_colors)\ns2 = scatter!(axes[2], body_xs2, body_ys2, markersize=body_sizes, color=body_colors)\n\n# Create GIF by iterating time\nsteps = 300\nrecord(f, \"gifs/heliocentric_geocentric.gif\", 1:steps) do t\n time_i[] = t\n for i in 1:num_bodies\n line_locs1[i][] = push!(line_locs1[i][], (body_xs1[][i], body_ys1[][i]))\n line_locs2[i][] = push!(line_locs2[i][], (body_xs2[][i], body_ys2[][i]))\n end\nend\n```\n:::\n\n\n![](gifs/heliocentric_geocentric.gif)\n\nAlright!\nOur animation is now complete.\n\n",
+ "engine": "jupyter",
+ "markdown": "---\ntitle: Heliocentrism vs Geocentrism\nauthor: Connor Robertson\nexecute:\n daemon: true\n---\n\n## Overview\nAnother fun little animation that I saw recently was the difference in the dynamics of the solar system when approaching the equations from a heliocentric (sun-centered) or geocentric (Earth-centered) perspective.\nAlthough it's clear now that we orbit the sun and a sun-centered model of the solar system is more correct, it wasn't always obvious.\nThis concept extends to systems that we have not yet nailed down completely.\nThis [simple animation](https://www.youtube.com/watch?v=7n7xaviepKM&t=556s) demonstrates that identifying the correct perspective when modeling a system can have a huge pay off in the simplicity of your result.\n\nI thought I'd try to recreate this little animation with `Makie.jl` as I did previously with the [polygon GIF](polygon_angles.qmd).\n\n## Setting up\nIn this animation, we'll be rotating some circular shapes around the point representing either the sun or the Earth and tracing their paths as they progress.\nFirst, let's plot the initial frame of the animation using a `Figure` with 2 `axes`:\n\n::: {#99228082 .cell execution_count=1}\n``` {.julia .cell-code}\nusing Pkg;\nPkg.activate(\".\");\nusing CairoMakie;\n```\n:::\n\n\n::: {#d3dd1efb .cell execution_count=2}\n``` {.julia .cell-code}\nf = Figure(resolution=(800,400));\naxes = [Axis(f[1,1]);Axis(f[1,2])]\nfor ax in axes ax.limits=(-22,22,-22,22) end\nfunction remove_axis_decor!(ax)\n ax.topspinevisible = false; ax.bottomspinevisible = false\n ax.leftspinevisible = false; ax.rightspinevisible = false\n ax.xgridvisible = false; ax.ygridvisible = false\n ax.xticksvisible = false; ax.yticksvisible = false\n ax.xticklabelsvisible = false; ax.yticklabelsvisible = false\nend\nremove_axis_decor!.(axes)\n```\n:::\n\n\nWe can now layout the different planets via a simple scatter plot in each `axis`.\nOf course, we cannot use the correct proportions or distances or the plot would be hard to understand.\nInstead, I'll settle for simple size differences between the planets and the sun and a somewhat uniform distance between each.\n\n::: {#e02ab192 .cell execution_count=3}\n``` {.julia .cell-code}\nnum_bodies = 9\nbody_locs1 = [(float(i),0.0) for i in 0:2:2(num_bodies-1)]\nbody_locs2 = [(float(i),0.0) for i in -6:2:2(num_bodies-1)-6]\nbody_sizes = 3 .* [9,3,3,4,2,5,6,4,4]\nbody_colors = [:yellow,:red,:red,:blue,:red,:red,:red,:red,:red]\ns1 = scatter!(axes[1], body_locs1, markersize=body_sizes, color=body_colors)\ns2 = scatter!(axes[2], body_locs2, markersize=body_sizes, color=body_colors)\ndisplay(f)\n```\n\n::: {.cell-output .cell-output-display}\n![](heliocentric_geocentric_files/figure-html/cell-4-output-1.svg){}\n:::\n\n::: {.cell-output .cell-output-display execution_count=4}\n```\nCairoMakie.Screen{IMAGE}\n```\n:::\n:::\n\n\n## Animation\nOkay!\nEasy as that.\nNow, we can move on to animating the rotation of the bodies.\nEach planet will rotate at a different speed and will go until again lining up as they started.\n\n::: {#0fe7f588 .cell execution_count=4}\n``` {.julia .cell-code}\nbody_speeds = [0.0,47.87,35.02,29.78,24.077,13.07,9.69,6.81,5.43] ./ 200\nsun_speed2 = body_speeds[4]\norbit_radii1 = [bl[1] for bl in body_locs1]\norbit_radii2 = [bl[1] for bl in body_locs2]\n\n# Use Observable to add time dependence to planet locations\ntime_i = Observable(0.0)\nbody_xs1 = @lift(orbit_radii1 .* cos.(-1 .* body_speeds .* $time_i))\nbody_ys1 = @lift(orbit_radii1 .* sin.(-1 .* body_speeds .* $time_i))\nbody_xs2 = @lift(vcat(\n orbit_radii2[1]*cos(-sun_speed2*$time_i),\n orbit_radii2[1]*cos(-sun_speed2*$time_i) + orbit_radii1[2]*cos(-body_speeds[2]*$time_i),\n orbit_radii2[1]*cos(-sun_speed2*$time_i) + orbit_radii1[3]*cos(-body_speeds[3]*$time_i),\n 0.0,\n orbit_radii2[1]*cos(-sun_speed2*$time_i) .+ orbit_radii1[5:end] .* cos.(-1 .* body_speeds[5:end] .* $time_i)\n))\nbody_ys2 = @lift(vcat(\n orbit_radii2[1]*sin(-sun_speed2*$time_i),\n orbit_radii2[1]*sin(-sun_speed2*$time_i) + orbit_radii1[2]*sin(-body_speeds[2]*$time_i),\n orbit_radii2[1]*sin(-sun_speed2*$time_i) + orbit_radii1[3]*sin(-body_speeds[3]*$time_i),\n 0.0,\n orbit_radii2[1]*sin(-sun_speed2*$time_i) .+ orbit_radii1[5:end] .* sin.(-1 .* body_speeds[5:end] .* $time_i)\n))\n\nempty!(axes[1].scene.plots)\nempty!(axes[2].scene.plots)\ns1 = scatter!(axes[1], body_xs1, body_ys1, markersize=body_sizes, color=body_colors)\ns2 = scatter!(axes[2], body_xs2, body_ys2, markersize=body_sizes, color=body_colors)\n\n# Create GIF by iterating time\nsteps = 300\nrecord(f, \"gifs/heliocentric_geocentric1.gif\", 1:steps) do t\n time_i[] = t\nend\n```\n:::\n\n\n![](gifs/heliocentric_geocentric1.gif)\n\nNice!\nWe've got the two animations moving well.\nNote that since the animation was fairly straightforward and only required updating the scatter plot locations, we were able to use an `Observable` for time in `Makie`.\nThis object allows us to create the initial scatter plots where the scatter locations are wrapped with the `@lift` macro with the interpolating `$time_i`.\nNow, when our `Observable`, `time_i` is updated, the scatter points and subsequently the scatter plots are updated.\nUsing this nifty tool, our recording loop is very straightforward.\nHowever, using the `@lift` macro is not particularly intuitive and it took some trial and error to get the definition of the scatter points correctly wrapped in an `Observable`.\nHence, the definitions of `body_xs2` and `body_ys2` are so messy..\n\nOur next step is to add the path tracing of the planets to each plot.\nAgain, this is a fairly simple procedure that could be completed with an `Observable`.\n\n::: {#8a47b098 .cell execution_count=5}\n``` {.julia .cell-code}\n# Line observables\nline_locs1 = [Observable([body_locs1[i]]) for i in 1:num_bodies]\nline_locs2 = [Observable([body_locs2[i]]) for i in 1:num_bodies]\n\nempty!(axes[1].scene.plots)\nempty!(axes[2].scene.plots)\nfor i in 1:num_bodies\n lines!(axes[1], line_locs1[i], color=body_colors[i])\n lines!(axes[2], line_locs2[i], color=body_colors[i])\nend\ns1 = scatter!(axes[1], body_xs1, body_ys1, markersize=body_sizes, color=body_colors)\ns2 = scatter!(axes[2], body_xs2, body_ys2, markersize=body_sizes, color=body_colors)\n\n# Create GIF by iterating time\nsteps = 300\nrecord(f, \"gifs/heliocentric_geocentric.gif\", 1:steps) do t\n time_i[] = t\n for i in 1:num_bodies\n line_locs1[i][] = push!(line_locs1[i][], (body_xs1[][i], body_ys1[][i]))\n line_locs2[i][] = push!(line_locs2[i][], (body_xs2[][i], body_ys2[][i]))\n end\nend\n```\n:::\n\n\n![](gifs/heliocentric_geocentric.gif)\n\nAlright!\nOur animation is now complete.\n\n",
"supporting": [
- "heliocentric_geocentric_files"
+ "heliocentric_geocentric_files/figure-html"
],
"filters": [],
"includes": {}
diff --git a/_freeze/other/fun/heliocentric_geocentric/figure-html/cell-4-output-1.svg b/_freeze/other/fun/heliocentric_geocentric/figure-html/cell-4-output-1.svg
index 69a8ad6..3604e4d 100644
--- a/_freeze/other/fun/heliocentric_geocentric/figure-html/cell-4-output-1.svg
+++ b/_freeze/other/fun/heliocentric_geocentric/figure-html/cell-4-output-1.svg
@@ -1,26 +1,26 @@
diff --git a/_freeze/other/fun/polygon_angles/execute-results/html.json b/_freeze/other/fun/polygon_angles/execute-results/html.json
index 7694654..4f661c4 100644
--- a/_freeze/other/fun/polygon_angles/execute-results/html.json
+++ b/_freeze/other/fun/polygon_angles/execute-results/html.json
@@ -1,9 +1,10 @@
{
- "hash": "977df831168a6df17bbcd2ac5c6472d0",
+ "hash": "087b6dbe91a5f955ebee90f62b186fc3",
"result": {
- "markdown": "---\ntitle: The exterior angles of a polygon make a circle\nauthor: Connor Robertson\nexecute:\n daemon: true\n---\n\n## Overview\nI recently saw a [fun little GIF](https://gfycat.com/bluesecondblackwidowspider-geometry-math) from a weekly news email I get called the New Paper.\nIt shows a simple plot of the exterior angles of a few polygons.\nAs the polygons shrink, the exterior angles combine to eventually make a circle, which shows a simple graphical example of how the exterior angles of any polygon add to $2\\pi$.\n\n\n\n\n\nI thought I'd try to recreate this little GIF with my favorite plotting library `Makie.jl`.\n\n## Setting up\nBasically, we can start by getting the plots of each polygon set.\nWe can then animate the sides of the polygons shrinking.\n\nTo start we are going to need a `Figure` with 4 `axes`:\n\n::: {.cell execution_count=1}\n``` {.julia .cell-code}\nusing Pkg;\nPkg.activate(\".\");\nusing CairoMakie;\n```\n:::\n\n\n::: {.cell execution_count=2}\n``` {.julia .cell-code}\nf = Figure(resolution=(800,800));\naxes = [\n Axis(f[1,1]) Axis(f[1,2]);\n Axis(f[2,1]) Axis(f[2,2])\n]\nfor ax in axes ax.limits=(-6,6,-6,6) end\n```\n:::\n\n\nWe can now list the vertices for each polygon:\n\n::: {.cell execution_count=3}\n``` {.julia .cell-code}\npoly11 = [(-2.0,3.0),(3.0,-3.0),(-4.0,-2.0),(-2.0,3.0)];\npoly12 = [(-3.0,2.0),(1.0,1.0),(3.0,-2.0),(-4.0,-1.0),(-3.0,2.0)];\npoly21 = [(-1.0,3.0),(1.0,3.0),(3.0,-1.0),(1.0,-3.0),(-2.0,-2.0),(-3.0,1.0),(-1.0,3.0)];\npoly22 = [(-1.0,2.0),(1.0,2.0),(4.0,-1.0),(2.0,-3.0),(-4.0,-1.0),(-1.0,2.0)];\n```\n:::\n\n\nwhere `poly11` is the polygon in the 1st row and 1st column.\nPlotting these lines on each respective axis, we get:\n\n::: {.cell execution_count=4}\n``` {.julia .cell-code}\nlines!(axes[1,1],poly11,color=:black);\nlines!(axes[1,2],poly12,color=:black);\nlines!(axes[2,1],poly21,color=:black);\nlines!(axes[2,2],poly22,color=:black);\npoly!(axes[1,1],poly11,transparency=true,color=RGBAf(1.0,0.6,0.0,0.2));\npoly!(axes[1,2],poly12,transparency=true,color=RGBAf(0.0,0.0,1.0,0.2));\npoly!(axes[2,1],poly21,transparency=true,color=RGBAf(0.5,0.0,0.5,0.2));\npoly!(axes[2,2],poly22,transparency=true,color=RGBAf(0.0,0.5,0.0,0.2));\ndisplay(f)\n```\n\n::: {.cell-output .cell-output-display}\n![](polygon_angles_files/figure-html/cell-5-output-1.svg){}\n:::\n:::\n\n\nThese are obviously not exactly the polygons in the GIF, but they are generally similar and use nice easy vertex coordinates.\nNow, in order to accentuate the exterior angles, the GIF uses lines which extend beyond the vertices.\nTo achieve this, we can consider each line segment and shift the first vertex some distance in the opposite direction of the second vertex.\nTo do so, we should shift adjust our polygon representation to separate each line segment:\n\n::: {.cell execution_count=5}\n``` {.julia .cell-code}\nlpoly11 = [[poly11[i],poly11[i+1]] for i in 1:length(poly11)-1];\nlpoly12 = [[poly12[i],poly12[i+1]] for i in 1:length(poly12)-1];\nlpoly21 = [[poly21[i],poly21[i+1]] for i in 1:length(poly21)-1];\nlpoly22 = [[poly22[i],poly22[i+1]] for i in 1:length(poly22)-1];\ndisplay(lpoly11)\n```\n\n::: {.cell-output .cell-output-display}\n```\n3-element Vector{Vector{Tuple{Float64, Float64}}}:\n [(-2.0, 3.0), (3.0, -3.0)]\n [(3.0, -3.0), (-4.0, -2.0)]\n [(-4.0, -2.0), (-2.0, 3.0)]\n```\n:::\n:::\n\n\nWe can now the vector between the first and second indices of each line segment and shift our first vertex by the negative of that vector.\nThat is a mouthful but more easily written mathematically.\nIf we consider a single line segment with vertices $v_1$ and $v_2$, we can calculate the distance between them $d = v_2 - v_1$ such that $v_1 + d = v_2$ and then redefine our first vertex in the opposite direction as $v_1^* = v_1 - l\\frac{d}{\\|d\\|}$ where $l$ is the length of the external line.\nThis boils down to the following:\n\n::: {.cell execution_count=6}\n``` {.julia .cell-code}\nfunction shift_first_vertices!(lpoly, l=2)\n for line in lpoly\n v1 = collect(line[1]); v2 = collect(line[2])\n d = v2 - v1\n v1star = v1 - l*d/sqrt(d[1]^2+d[2]^2)\n line[1] = tuple(v1star...)\n end\nend\nshift_first_vertices!(lpoly11)\nshift_first_vertices!(lpoly12)\nshift_first_vertices!(lpoly21)\nshift_first_vertices!(lpoly22)\nfunction plot_line_segments!(ax,lpoly)\n lines = []\n for line in lpoly push!(lines,lines!(ax,line,color=:black)) end\n return lines\nend\nplot_line_segments!(axes[1,1],lpoly11)\nplot_line_segments!(axes[1,2],lpoly12)\nplot_line_segments!(axes[2,1],lpoly21)\nplot_line_segments!(axes[2,2],lpoly22)\ndisplay(f)\n```\n\n::: {.cell-output .cell-output-display}\n![](polygon_angles_files/figure-html/cell-7-output-1.svg){}\n:::\n:::\n\n\nOnce we have these lines in place, we can add the external angles.\nIronically, the best tool in Makie for these angle drawings is the `poly!` function which plots a filled polygon from some given vertices.\nThus, we need to compute the vertices of the arc for each angle of each polygon.\n\nThis computation can be done by taking two connected line segments $d_1$ and $d_2$, identifying the angle between them using the law of cosines $\\arccos(d_1 \\cdot d_2)$, and sampling points along the arc of given radius $l$.\nSampling the arc requires a little change of coordinates to center the points around the vertex connecting the two line segments and to rotate the standard $x$ and $y$ coordinates to align $x$ with $d_1$ and $y$ with $d_1^\\perp$.\nThis is, in my opinion, the most challenging part of the plot.\n\n::: {.cell execution_count=7}\n``` {.julia .cell-code}\nfunction angle_vertices(line1,line2,l=1)\n v1 = collect(line1[1])\n v2 = collect(line1[2]) # Shared vertex\n v3 = collect(line2[2])\n d1 = v2-v1\n d2 = v3-v2\n # Line segment directions (normalized\n d1 ./= sqrt(d1[1]^2+d1[2]^2)\n d2 ./= sqrt(d2[1]^2+d2[2]^2)\n d1perp = [d1[2],-d1[1]]\n vertex = tuple(v2...)\n # Computing angle between lines, then sampling arc points\n angle = acos(d1'*d2)\n angle = isnan(angle) ? 0.0 : angle\n angles = range(0, angle, length=10)\n # arc has radius l, origin at v2, \"x\"-direction is d1, \"y\"-direction is d1perp\n arc_points = [tuple(@.( v2 - l*(d1*cos(a) + d1perp*sin(a)))...) for a in angles]\n vertices = vcat(vertex,arc_points,vertex)\n return vertices\nend\nfunction plot_arcs!(ax,lpoly)\n arcs = []\n colors = to_colormap(:seaborn_colorblind)\n for i in 1:length(lpoly)\n if i+1 > length(lpoly) # The angle between the last line segment and first\n color = colors[i+1]\n arc_vertices = angle_vertices(lpoly[i],lpoly[1])\n else\n color = colors[i]\n arc_vertices = angle_vertices(lpoly[i],lpoly[i+1])\n end\n push!(arcs,poly!(ax,arc_vertices,color=color))\n end\n return arcs\nend\nplot_arcs!(axes[1,1],lpoly11)\nplot_arcs!(axes[1,2],lpoly12)\nplot_arcs!(axes[2,1],lpoly21)\nplot_arcs!(axes[2,2],lpoly22)\ndisplay(f)\n```\n\n::: {.cell-output .cell-output-display}\n![](polygon_angles_files/figure-html/cell-8-output-1.svg){}\n:::\n:::\n\n\nNow, removing the axes decorations, we have a clean plot of (almost) the first frame of the GIF:\n\n::: {.cell execution_count=8}\n``` {.julia .cell-code}\nfunction remove_axis_decor!(ax)\n ax.topspinevisible = false; ax.bottomspinevisible = false\n ax.leftspinevisible = false; ax.rightspinevisible = false\n ax.xgridvisible = false; ax.ygridvisible = false\n ax.xticksvisible = false; ax.yticksvisible = false\n ax.xticklabelsvisible = false; ax.yticklabelsvisible = false\nend\nremove_axis_decor!.(axes)\ndisplay(f)\n```\n\n::: {.cell-output .cell-output-display}\n![](polygon_angles_files/figure-html/cell-9-output-1.svg){}\n:::\n:::\n\n\n## Animating\n\nWith the initial plot now done, to complete the animation, it remains to shrink each polygon until the angles come together to form a circle.\nThis can be simply done (with slight error) by computing the center of each polygon via averaging, centering the vertices around that center, then shrinking the vertices proportional to the number of steps in the animation.\nPutting everything together:\n\n::: {.cell execution_count=9}\n``` {.julia .cell-code}\n# Initialize\nf = Figure(resolution=(800,800));\naxes = [\n Axis(f[1,1]) Axis(f[1,2]);\n Axis(f[2,1]) Axis(f[2,2])\n]\nfor ax in axes ax.limits = (-6,6,-6,6) end\nremove_axis_decor!.(axes)\npoly11 = [(-2.0,3.0),(3.0,-3.0),(-4.0,-2.0),(-2.0,3.0)];\npoly12 = [(-3.0,2.0),(1.0,1.0),(3.0,-2.0),(-4.0,-1.0),(-3.0,2.0)];\npoly21 = [(-1.0,3.0),(1.0,3.0),(3.0,-1.0),(1.0,-3.0),(-2.0,-2.0),(-3.0,1.0),(-1.0,3.0)];\npoly22 = [(-1.0,2.0),(1.0,2.0),(4.0,-1.0),(2.0,-3.0),(-4.0,-1.0),(-1.0,2.0)];\n# Polygon average centers\nfunction compute_center(poly)\n vec(sum(hcat(collect.(poly)...),dims=2)./length(poly))\nend\nc11 = compute_center(poly11)\nc12 = compute_center(poly12)\nc21 = compute_center(poly21)\nc22 = compute_center(poly22)\nfunction shrink_polygon(poly,c,step,steps)\n new_vertices = similar(poly)\n for i in eachindex(poly)\n vertex = collect(poly[i]) - c\n new_vertex = @. vertex*((steps-step)/(steps))\n new_vertices[i] = tuple((new_vertex + c)...)\n end\n return new_vertices\nend\n\n# Animation (somewhat inefficient since it doesn't use Observables)\nsteps = 120\nrecord(f, \"gifs/angle_gif.gif\", vcat(1:(steps-1),fill(steps-1,steps÷4),(steps-1):-1:1)) do t\n empty!(axes[1,1].scene.plots)\n empty!(axes[1,2].scene.plots)\n empty!(axes[2,1].scene.plots)\n empty!(axes[2,2].scene.plots)\n npoly11 = shrink_polygon(poly11,c11,t,steps)\n npoly12 = shrink_polygon(poly12,c12,t,steps)\n npoly21 = shrink_polygon(poly21,c21,t,steps)\n npoly22 = shrink_polygon(poly22,c22,t,steps)\n lpoly11 = [[npoly11[i],npoly11[i+1]] for i in 1:length(npoly11)-1];\n lpoly12 = [[npoly12[i],npoly12[i+1]] for i in 1:length(npoly12)-1];\n lpoly21 = [[npoly21[i],npoly21[i+1]] for i in 1:length(npoly21)-1];\n lpoly22 = [[npoly22[i],npoly22[i+1]] for i in 1:length(npoly22)-1];\n shift_first_vertices!(lpoly11)\n shift_first_vertices!(lpoly12)\n shift_first_vertices!(lpoly21)\n shift_first_vertices!(lpoly22)\n poly!(axes[1,1],npoly11,transparency=true,color=RGBAf(1.0,0.6,0.0,0.2));\n poly!(axes[1,2],npoly12,transparency=true,color=RGBAf(0.0,0.0,1.0,0.2));\n poly!(axes[2,1],npoly21,transparency=true,color=RGBAf(0.5,0.0,0.5,0.2));\n poly!(axes[2,2],npoly22,transparency=true,color=RGBAf(0.0,0.5,0.0,0.2));\n plot_arcs!(axes[1,1],lpoly11)\n plot_arcs!(axes[1,2],lpoly12)\n plot_arcs!(axes[2,1],lpoly21)\n plot_arcs!(axes[2,2],lpoly22)\n plot_line_segments!(axes[1,1],lpoly11)\n plot_line_segments!(axes[1,2],lpoly12)\n plot_line_segments!(axes[2,1],lpoly21)\n plot_line_segments!(axes[2,2],lpoly22)\nend\n```\n:::\n\n\n![](gifs/angle_gif.gif)\n\n",
+ "engine": "jupyter",
+ "markdown": "---\ntitle: The exterior angles of a polygon make a circle\nauthor: Connor Robertson\nexecute:\n daemon: true\n---\n\n## Overview\nI recently saw a [fun little GIF](https://gfycat.com/bluesecondblackwidowspider-geometry-math) from a weekly news email I get called the New Paper.\nIt shows a simple plot of the exterior angles of a few polygons.\nAs the polygons shrink, the exterior angles combine to eventually make a circle, which shows a simple graphical example of how the exterior angles of any polygon add to $2\\pi$.\n\n\n\n\n\nI thought I'd try to recreate this little GIF with my favorite plotting library `Makie.jl`.\n\n## Setting up\nBasically, we can start by getting the plots of each polygon set.\nWe can then animate the sides of the polygons shrinking.\n\nTo start we are going to need a `Figure` with 4 `axes`:\n\n::: {#b8e339e5 .cell execution_count=1}\n``` {.julia .cell-code}\nusing Pkg;\nPkg.activate(\".\");\nusing CairoMakie;\n```\n:::\n\n\n::: {#f0c63608 .cell execution_count=2}\n``` {.julia .cell-code}\nf = Figure(resolution=(800,800));\naxes = [\n Axis(f[1,1]) Axis(f[1,2]);\n Axis(f[2,1]) Axis(f[2,2])\n]\nfor ax in axes ax.limits=(-6,6,-6,6) end\n```\n:::\n\n\nWe can now list the vertices for each polygon:\n\n::: {#fd67803a .cell execution_count=3}\n``` {.julia .cell-code}\npoly11 = [(-2.0,3.0),(3.0,-3.0),(-4.0,-2.0),(-2.0,3.0)];\npoly12 = [(-3.0,2.0),(1.0,1.0),(3.0,-2.0),(-4.0,-1.0),(-3.0,2.0)];\npoly21 = [(-1.0,3.0),(1.0,3.0),(3.0,-1.0),(1.0,-3.0),(-2.0,-2.0),(-3.0,1.0),(-1.0,3.0)];\npoly22 = [(-1.0,2.0),(1.0,2.0),(4.0,-1.0),(2.0,-3.0),(-4.0,-1.0),(-1.0,2.0)];\n```\n:::\n\n\nwhere `poly11` is the polygon in the 1st row and 1st column.\nPlotting these lines on each respective axis, we get:\n\n::: {#cebbd1e0 .cell execution_count=4}\n``` {.julia .cell-code}\nlines!(axes[1,1],poly11,color=:black);\nlines!(axes[1,2],poly12,color=:black);\nlines!(axes[2,1],poly21,color=:black);\nlines!(axes[2,2],poly22,color=:black);\npoly!(axes[1,1],poly11,transparency=true,color=RGBAf(1.0,0.6,0.0,0.2));\npoly!(axes[1,2],poly12,transparency=true,color=RGBAf(0.0,0.0,1.0,0.2));\npoly!(axes[2,1],poly21,transparency=true,color=RGBAf(0.5,0.0,0.5,0.2));\npoly!(axes[2,2],poly22,transparency=true,color=RGBAf(0.0,0.5,0.0,0.2));\ndisplay(f)\n```\n\n::: {.cell-output .cell-output-display}\n![](polygon_angles_files/figure-html/cell-5-output-1.svg){}\n:::\n\n::: {.cell-output .cell-output-display execution_count=5}\n```\nCairoMakie.Screen{IMAGE}\n```\n:::\n:::\n\n\nThese are obviously not exactly the polygons in the GIF, but they are generally similar and use nice easy vertex coordinates.\nNow, in order to accentuate the exterior angles, the GIF uses lines which extend beyond the vertices.\nTo achieve this, we can consider each line segment and shift the first vertex some distance in the opposite direction of the second vertex.\nTo do so, we should shift adjust our polygon representation to separate each line segment:\n\n::: {#740fbe36 .cell execution_count=5}\n``` {.julia .cell-code}\nlpoly11 = [[poly11[i],poly11[i+1]] for i in 1:length(poly11)-1];\nlpoly12 = [[poly12[i],poly12[i+1]] for i in 1:length(poly12)-1];\nlpoly21 = [[poly21[i],poly21[i+1]] for i in 1:length(poly21)-1];\nlpoly22 = [[poly22[i],poly22[i+1]] for i in 1:length(poly22)-1];\ndisplay(lpoly11)\n```\n\n::: {.cell-output .cell-output-display}\n```\n3-element Vector{Vector{Tuple{Float64, Float64}}}:\n [(-2.0, 3.0), (3.0, -3.0)]\n [(3.0, -3.0), (-4.0, -2.0)]\n [(-4.0, -2.0), (-2.0, 3.0)]\n```\n:::\n:::\n\n\nWe can now the vector between the first and second indices of each line segment and shift our first vertex by the negative of that vector.\nThat is a mouthful but more easily written mathematically.\nIf we consider a single line segment with vertices $v_1$ and $v_2$, we can calculate the distance between them $d = v_2 - v_1$ such that $v_1 + d = v_2$ and then redefine our first vertex in the opposite direction as $v_1^* = v_1 - l\\frac{d}{\\|d\\|}$ where $l$ is the length of the external line.\nThis boils down to the following:\n\n::: {#486454cf .cell execution_count=6}\n``` {.julia .cell-code}\nfunction shift_first_vertices!(lpoly, l=2)\n for line in lpoly\n v1 = collect(line[1]); v2 = collect(line[2])\n d = v2 - v1\n v1star = v1 - l*d/sqrt(d[1]^2+d[2]^2)\n line[1] = tuple(v1star...)\n end\nend\nshift_first_vertices!(lpoly11)\nshift_first_vertices!(lpoly12)\nshift_first_vertices!(lpoly21)\nshift_first_vertices!(lpoly22)\nfunction plot_line_segments!(ax,lpoly)\n lines = []\n for line in lpoly push!(lines,lines!(ax,line,color=:black)) end\n return lines\nend\nplot_line_segments!(axes[1,1],lpoly11)\nplot_line_segments!(axes[1,2],lpoly12)\nplot_line_segments!(axes[2,1],lpoly21)\nplot_line_segments!(axes[2,2],lpoly22)\ndisplay(f)\n```\n\n::: {.cell-output .cell-output-display}\n![](polygon_angles_files/figure-html/cell-7-output-1.svg){}\n:::\n\n::: {.cell-output .cell-output-display execution_count=7}\n```\nCairoMakie.Screen{IMAGE}\n```\n:::\n:::\n\n\nOnce we have these lines in place, we can add the external angles.\nIronically, the best tool in Makie for these angle drawings is the `poly!` function which plots a filled polygon from some given vertices.\nThus, we need to compute the vertices of the arc for each angle of each polygon.\n\nThis computation can be done by taking two connected line segments $d_1$ and $d_2$, identifying the angle between them using the law of cosines $\\arccos(d_1 \\cdot d_2)$, and sampling points along the arc of given radius $l$.\nSampling the arc requires a little change of coordinates to center the points around the vertex connecting the two line segments and to rotate the standard $x$ and $y$ coordinates to align $x$ with $d_1$ and $y$ with $d_1^\\perp$.\nThis is, in my opinion, the most challenging part of the plot.\n\n::: {#4c2813f4 .cell execution_count=7}\n``` {.julia .cell-code}\nfunction angle_vertices(line1,line2,l=1)\n v1 = collect(line1[1])\n v2 = collect(line1[2]) # Shared vertex\n v3 = collect(line2[2])\n d1 = v2-v1\n d2 = v3-v2\n # Line segment directions (normalized\n d1 ./= sqrt(d1[1]^2+d1[2]^2)\n d2 ./= sqrt(d2[1]^2+d2[2]^2)\n d1perp = [d1[2],-d1[1]]\n vertex = tuple(v2...)\n # Computing angle between lines, then sampling arc points\n angle = acos(d1'*d2)\n angle = isnan(angle) ? 0.0 : angle\n angles = range(0, angle, length=10)\n # arc has radius l, origin at v2, \"x\"-direction is d1, \"y\"-direction is d1perp\n arc_points = [tuple(@.( v2 - l*(d1*cos(a) + d1perp*sin(a)))...) for a in angles]\n vertices = vcat(vertex,arc_points,vertex)\n return vertices\nend\nfunction plot_arcs!(ax,lpoly)\n arcs = []\n colors = to_colormap(:seaborn_colorblind)\n for i in 1:length(lpoly)\n if i+1 > length(lpoly) # The angle between the last line segment and first\n color = colors[i+1]\n arc_vertices = angle_vertices(lpoly[i],lpoly[1])\n else\n color = colors[i]\n arc_vertices = angle_vertices(lpoly[i],lpoly[i+1])\n end\n push!(arcs,poly!(ax,arc_vertices,color=color))\n end\n return arcs\nend\nplot_arcs!(axes[1,1],lpoly11)\nplot_arcs!(axes[1,2],lpoly12)\nplot_arcs!(axes[2,1],lpoly21)\nplot_arcs!(axes[2,2],lpoly22)\ndisplay(f)\n```\n\n::: {.cell-output .cell-output-display}\n![](polygon_angles_files/figure-html/cell-8-output-1.svg){}\n:::\n\n::: {.cell-output .cell-output-display execution_count=8}\n```\nCairoMakie.Screen{IMAGE}\n```\n:::\n:::\n\n\nNow, removing the axes decorations, we have a clean plot of (almost) the first frame of the GIF:\n\n::: {#2be48880 .cell execution_count=8}\n``` {.julia .cell-code}\nfunction remove_axis_decor!(ax)\n ax.topspinevisible = false; ax.bottomspinevisible = false\n ax.leftspinevisible = false; ax.rightspinevisible = false\n ax.xgridvisible = false; ax.ygridvisible = false\n ax.xticksvisible = false; ax.yticksvisible = false\n ax.xticklabelsvisible = false; ax.yticklabelsvisible = false\nend\nremove_axis_decor!.(axes)\ndisplay(f)\n```\n\n::: {.cell-output .cell-output-display}\n![](polygon_angles_files/figure-html/cell-9-output-1.svg){}\n:::\n\n::: {.cell-output .cell-output-display execution_count=9}\n```\nCairoMakie.Screen{IMAGE}\n```\n:::\n:::\n\n\n## Animating\n\nWith the initial plot now done, to complete the animation, it remains to shrink each polygon until the angles come together to form a circle.\nThis can be simply done (with slight error) by computing the center of each polygon via averaging, centering the vertices around that center, then shrinking the vertices proportional to the number of steps in the animation.\nPutting everything together:\n\n::: {#08549979 .cell execution_count=9}\n``` {.julia .cell-code}\n# Initialize\nf = Figure(resolution=(800,800));\naxes = [\n Axis(f[1,1]) Axis(f[1,2]);\n Axis(f[2,1]) Axis(f[2,2])\n]\nfor ax in axes ax.limits = (-6,6,-6,6) end\nremove_axis_decor!.(axes)\npoly11 = [(-2.0,3.0),(3.0,-3.0),(-4.0,-2.0),(-2.0,3.0)];\npoly12 = [(-3.0,2.0),(1.0,1.0),(3.0,-2.0),(-4.0,-1.0),(-3.0,2.0)];\npoly21 = [(-1.0,3.0),(1.0,3.0),(3.0,-1.0),(1.0,-3.0),(-2.0,-2.0),(-3.0,1.0),(-1.0,3.0)];\npoly22 = [(-1.0,2.0),(1.0,2.0),(4.0,-1.0),(2.0,-3.0),(-4.0,-1.0),(-1.0,2.0)];\n# Polygon average centers\nfunction compute_center(poly)\n vec(sum(hcat(collect.(poly)...),dims=2)./length(poly))\nend\nc11 = compute_center(poly11)\nc12 = compute_center(poly12)\nc21 = compute_center(poly21)\nc22 = compute_center(poly22)\nfunction shrink_polygon(poly,c,step,steps)\n new_vertices = similar(poly)\n for i in eachindex(poly)\n vertex = collect(poly[i]) - c\n new_vertex = @. vertex*((steps-step)/(steps))\n new_vertices[i] = tuple((new_vertex + c)...)\n end\n return new_vertices\nend\n\n# Animation (somewhat inefficient since it doesn't use Observables)\nsteps = 120\nrecord(f, \"gifs/angle_gif.gif\", vcat(1:(steps-1),fill(steps-1,steps÷4),(steps-1):-1:1)) do t\n empty!(axes[1,1].scene.plots)\n empty!(axes[1,2].scene.plots)\n empty!(axes[2,1].scene.plots)\n empty!(axes[2,2].scene.plots)\n npoly11 = shrink_polygon(poly11,c11,t,steps)\n npoly12 = shrink_polygon(poly12,c12,t,steps)\n npoly21 = shrink_polygon(poly21,c21,t,steps)\n npoly22 = shrink_polygon(poly22,c22,t,steps)\n lpoly11 = [[npoly11[i],npoly11[i+1]] for i in 1:length(npoly11)-1];\n lpoly12 = [[npoly12[i],npoly12[i+1]] for i in 1:length(npoly12)-1];\n lpoly21 = [[npoly21[i],npoly21[i+1]] for i in 1:length(npoly21)-1];\n lpoly22 = [[npoly22[i],npoly22[i+1]] for i in 1:length(npoly22)-1];\n shift_first_vertices!(lpoly11)\n shift_first_vertices!(lpoly12)\n shift_first_vertices!(lpoly21)\n shift_first_vertices!(lpoly22)\n poly!(axes[1,1],npoly11,transparency=true,color=RGBAf(1.0,0.6,0.0,0.2));\n poly!(axes[1,2],npoly12,transparency=true,color=RGBAf(0.0,0.0,1.0,0.2));\n poly!(axes[2,1],npoly21,transparency=true,color=RGBAf(0.5,0.0,0.5,0.2));\n poly!(axes[2,2],npoly22,transparency=true,color=RGBAf(0.0,0.5,0.0,0.2));\n plot_arcs!(axes[1,1],lpoly11)\n plot_arcs!(axes[1,2],lpoly12)\n plot_arcs!(axes[2,1],lpoly21)\n plot_arcs!(axes[2,2],lpoly22)\n plot_line_segments!(axes[1,1],lpoly11)\n plot_line_segments!(axes[1,2],lpoly12)\n plot_line_segments!(axes[2,1],lpoly21)\n plot_line_segments!(axes[2,2],lpoly22)\nend\n```\n:::\n\n\n![](gifs/angle_gif.gif)\n\n",
"supporting": [
- "polygon_angles_files"
+ "polygon_angles_files/figure-html"
],
"filters": [],
"includes": {}
diff --git a/_freeze/other/fun/polygon_angles/figure-html/cell-5-output-1.svg b/_freeze/other/fun/polygon_angles/figure-html/cell-5-output-1.svg
index a5b0ea2..d65be9e 100644
--- a/_freeze/other/fun/polygon_angles/figure-html/cell-5-output-1.svg
+++ b/_freeze/other/fun/polygon_angles/figure-html/cell-5-output-1.svg
@@ -1,9 +1,9 @@
diff --git a/_freeze/other/fun/polygon_angles/figure-html/cell-7-output-1.svg b/_freeze/other/fun/polygon_angles/figure-html/cell-7-output-1.svg
index 3323699..a605f73 100644
--- a/_freeze/other/fun/polygon_angles/figure-html/cell-7-output-1.svg
+++ b/_freeze/other/fun/polygon_angles/figure-html/cell-7-output-1.svg
@@ -1,9 +1,9 @@
diff --git a/_freeze/other/fun/polygon_angles/figure-html/cell-8-output-1.svg b/_freeze/other/fun/polygon_angles/figure-html/cell-8-output-1.svg
index 3b5586a..4fd427f 100644
--- a/_freeze/other/fun/polygon_angles/figure-html/cell-8-output-1.svg
+++ b/_freeze/other/fun/polygon_angles/figure-html/cell-8-output-1.svg
@@ -1,9 +1,9 @@
diff --git a/_freeze/other/fun/polygon_angles/figure-html/cell-9-output-1.svg b/_freeze/other/fun/polygon_angles/figure-html/cell-9-output-1.svg
index 9a45bf1..f9e0738 100644
--- a/_freeze/other/fun/polygon_angles/figure-html/cell-9-output-1.svg
+++ b/_freeze/other/fun/polygon_angles/figure-html/cell-9-output-1.svg
@@ -1,9 +1,9 @@
diff --git a/_freeze/other/mlseminar/fall_2022/workshop4_cnn/workshop4_cnn/execute-results/ipynb.json b/_freeze/other/mlseminar/fall_2022/workshop4_cnn/workshop4_cnn/execute-results/ipynb.json
new file mode 100644
index 0000000..f0060fa
--- /dev/null
+++ b/_freeze/other/mlseminar/fall_2022/workshop4_cnn/workshop4_cnn/execute-results/ipynb.json
@@ -0,0 +1,11 @@
+{
+ "hash": "f208d50a4b3fb4f84a72f85cc0d5b3bd",
+ "result": {
+ "engine": "jupyter",
+ "markdown": "---\nexecute:\n daemon: 500\nformat:\n html: default\n ipynb: default\ntitle: Machine Learning Workshop -- Convolutional Neural Network (CNN)\n---\n\n\n\n\n\n## Installing and loading some needed packages\n\n\n::: {#c4aa0e4c .cell execution_count=1}\n``` {.python .cell-code}\n# Needed package for plotting\nimport matplotlib.pyplot as plt\n%matplotlib inline \n\n# Needed package for getting the current working directory\nimport os\n\nos.environ[\"CUDA_VISIBLE_DEVICES\"] = \"-1\"\n# Needed package for builing the convolutional neural network\nimport tensorflow as tf\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Dense, Conv2D, Dropout, Flatten, MaxPooling2D\nfrom tensorflow.keras.utils import plot_model\n\n# Needed package for computer vision problems\nimport cv2\n```\n:::\n\n\n## Loading the MNIST data from keras library and split that into train and test dataset\n\n::: {#1304a2c5 .cell execution_count=2}\n``` {.python .cell-code}\n(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()\nimage_index = 0\nprint('The number for index = ' + str(image_index) + ' is ' + str(y_train[image_index])) \n```\n\n::: {.cell-output .cell-output-stdout}\n```\nDownloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz\n\r 8192/11490434 [..............................] - ETA: 0s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 40960/11490434 [..............................] - ETA: 14s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 114688/11490434 [..............................] - ETA: 10s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 221184/11490434 [..............................] - ETA: 8s \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 335872/11490434 [..............................] - ETA: 6s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 458752/11490434 [>.............................] - ETA: 6s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 573440/11490434 [>.............................] - ETA: 6s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 688128/11490434 [>.............................] - ETA: 5s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 802816/11490434 [=>............................] - ETA: 5s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 909312/11490434 [=>............................] - ETA: 5s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 1024000/11490434 [=>............................] - ETA: 5s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 1138688/11490434 [=>............................] - ETA: 5s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 1261568/11490434 [==>...........................] - ETA: 5s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 1376256/11490434 [==>...........................] - ETA: 5s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 1482752/11490434 [==>...........................] - ETA: 5s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 1589248/11490434 [===>..........................] - ETA: 4s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 1703936/11490434 [===>..........................] - ETA: 4s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 1835008/11490434 [===>..........................] - ETA: 4s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 1966080/11490434 [====>.........................] - ETA: 4s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 2097152/11490434 [====>.........................] - ETA: 4s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 2220032/11490434 [====>.........................] - ETA: 4s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 2334720/11490434 [=====>........................] - ETA: 4s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 2449408/11490434 [=====>........................] - ETA: 4s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 2572288/11490434 [=====>........................] - ETA: 4s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 2678784/11490434 [=====>........................] - ETA: 4s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 2809856/11490434 [======>.......................] - ETA: 4s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 2932736/11490434 [======>.......................] - ETA: 4s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 3055616/11490434 [======>.......................] - ETA: 4s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 3170304/11490434 [=======>......................] - ETA: 3s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 3276800/11490434 [=======>......................] - ETA: 3s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 3407872/11490434 [=======>......................] - ETA: 3s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 3538944/11490434 [========>.....................] - ETA: 3s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 3678208/11490434 [========>.....................] - ETA: 3s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 3809280/11490434 [========>.....................] - ETA: 3s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 3923968/11490434 [=========>....................] - ETA: 3s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 4063232/11490434 [=========>....................] - ETA: 3s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 4177920/11490434 [=========>....................] - ETA: 3s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 4325376/11490434 [==========>...................] - ETA: 3s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 4456448/11490434 [==========>...................] - ETA: 3s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 4587520/11490434 [==========>...................] - ETA: 3s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 4710400/11490434 [===========>..................] - ETA: 3s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 4857856/11490434 [===========>..................] - ETA: 3s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 4964352/11490434 [===========>..................] - ETA: 3s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 5095424/11490434 [============>.................] - ETA: 3s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 5226496/11490434 [============>.................] - ETA: 2s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 5357568/11490434 [============>.................] - ETA: 2s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 5488640/11490434 [=============>................] - ETA: 2s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 5611520/11490434 [=============>................] - ETA: 2s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 5742592/11490434 [=============>................] - ETA: 2s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 5865472/11490434 [==============>...............] - ETA: 2s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 6004736/11490434 [==============>...............] - ETA: 2s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 6127616/11490434 [==============>...............] - ETA: 2s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 6234112/11490434 [===============>..............] - ETA: 2s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 6365184/11490434 [===============>..............] - ETA: 2s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 6479872/11490434 [===============>..............] - ETA: 2s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 6594560/11490434 [================>.............] - ETA: 2s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 6709248/11490434 [================>.............] - ETA: 2s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 6823936/11490434 [================>.............] - ETA: 2s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 6930432/11490434 [=================>............] - ETA: 2s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 7053312/11490434 [=================>............] - ETA: 2s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 7184384/11490434 [=================>............] - ETA: 2s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 7307264/11490434 [==================>...........] - ETA: 1s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 7421952/11490434 [==================>...........] - ETA: 1s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 7536640/11490434 [==================>...........] - ETA: 1s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 7651328/11490434 [==================>...........] - ETA: 1s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 7757824/11490434 [===================>..........] - ETA: 1s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 7880704/11490434 [===================>..........] - ETA: 1s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 8011776/11490434 [===================>..........] - ETA: 1s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 8142848/11490434 [====================>.........] - ETA: 1s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 8273920/11490434 [====================>.........] - ETA: 1s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 8396800/11490434 [====================>.........] - ETA: 1s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 8519680/11490434 [=====================>........] - ETA: 1s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 8658944/11490434 [=====================>........] - ETA: 1s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 8773632/11490434 [=====================>........] - ETA: 1s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 8888320/11490434 [======================>.......] - ETA: 1s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 9019392/11490434 [======================>.......] - ETA: 1s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 9142272/11490434 [======================>.......] - ETA: 1s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 9281536/11490434 [=======================>......] - ETA: 1s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 9412608/11490434 [=======================>......] - ETA: 0s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 9535488/11490434 [=======================>......] - ETA: 0s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 9658368/11490434 [========================>.....] - ETA: 0s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 9789440/11490434 [========================>.....] - ETA: 0s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 9920512/11490434 [========================>.....] - ETA: 0s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r10059776/11490434 [=========================>....] - ETA: 0s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r10174464/11490434 [=========================>....] - ETA: 0s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r10305536/11490434 [=========================>....] - ETA: 0s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r10436608/11490434 [==========================>...] - ETA: 0s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r10567680/11490434 [==========================>...] - ETA: 0s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r10690560/11490434 [==========================>...] - ETA: 0s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r10829824/11490434 [===========================>..] - ETA: 0s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r10952704/11490434 [===========================>..] - ETA: 0s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r11083776/11490434 [===========================>..] - ETA: 0s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r11223040/11490434 [============================>.] - ETA: 0s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r11337728/11490434 [============================>.] - ETA: 0s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r11476992/11490434 [============================>.] - ETA: 0s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r11490434/11490434 [==============================] - 5s 0us/step\nThe number for index = 0 is 5\n```\n:::\n:::\n\n\n::: {#f051fc40 .cell execution_count=3}\n``` {.python .cell-code}\nplt.imshow(x_train[image_index], cmap='Greys')\n```\n\n::: {.cell-output .cell-output-display}\n![](workshop4_cnn_files/figure-ipynb/cell-4-output-1.png){}\n:::\n:::\n\n\n::: {#230a0ffa .cell execution_count=4}\n``` {.python .cell-code}\nx_train.shape\n```\n\n::: {.cell-output .cell-output-display execution_count=4}\n```\n(60000, 28, 28)\n```\n:::\n:::\n\n\n::: {#3195ff9d .cell execution_count=5}\n``` {.python .cell-code}\nx_train[image_index].shape\n```\n\n::: {.cell-output .cell-output-display execution_count=5}\n```\n(28, 28)\n```\n:::\n:::\n\n\n## Normalize data and put them into the correct format\n\n::: {#1739e941 .cell execution_count=6}\n``` {.python .cell-code}\nx_train = x_train.reshape(x_train.shape[0], 28, 28, 1)\nx_test = x_test.reshape(x_test.shape[0], 28, 28, 1)\ninput_shape = (28, 28, 1)\n# Making sure that the values are float so that we can get decimal points after division\nx_train = x_train.astype('float32')\nx_test = x_test.astype('float32')\n\nx_train /= 255\nx_test /= 255\nprint('x_train shape:', x_train.shape)\nprint('Number of images in x_train', x_train.shape[0])\nprint('Number of images in x_test', x_test.shape[0])\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nx_train shape: (60000, 28, 28, 1)\nNumber of images in x_train 60000\nNumber of images in x_test 10000\n```\n:::\n:::\n\n\n## Convolutional Neural Network (CNN) structure\n\n::: {#c61b4b0a .cell execution_count=7}\n``` {.python .cell-code}\nmodel = Sequential()\nmodel.add(Conv2D(32, kernel_size=(3,3), input_shape=input_shape))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\nmodel.add(Conv2D(32, kernel_size=(3,3), input_shape=input_shape))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\nmodel.add(Flatten()) \nmodel.add(Dense(256, activation=tf.nn.relu))\nmodel.add(Dropout(0.2))\nmodel.add(Dense(10,activation=tf.nn.softmax))\n```\n:::\n\n\n::: {#2e6428ac .cell execution_count=8}\n``` {.python .cell-code}\nmodel.summary()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nModel: \"sequential\"\n_________________________________________________________________\n Layer (type) Output Shape Param # \n=================================================================\n conv2d (Conv2D) (None, 26, 26, 32) 320 \n \n max_pooling2d (MaxPooling2 (None, 13, 13, 32) 0 \n D) \n \n conv2d_1 (Conv2D) (None, 11, 11, 32) 9248 \n \n max_pooling2d_1 (MaxPoolin (None, 5, 5, 32) 0 \n g2D) \n \n flatten (Flatten) (None, 800) 0 \n \n dense (Dense) (None, 256) 205056 \n \n dropout (Dropout) (None, 256) 0 \n \n dense_1 (Dense) (None, 10) 2570 \n \n=================================================================\nTotal params: 217194 (848.41 KB)\nTrainable params: 217194 (848.41 KB)\nNon-trainable params: 0 (0.00 Byte)\n_________________________________________________________________\n```\n:::\n:::\n\n\n## Training the CNN\n\n::: {#76c0b84e .cell execution_count=9}\n``` {.python .cell-code}\nmodel.compile(optimizer='adam', \n loss='sparse_categorical_crossentropy', \n metrics=['accuracy'])\nmodel.fit(x=x_train,y=y_train, epochs=5)\n```\n:::\n\n\n::: {#accafbc0 .cell execution_count=10}\n``` {.python .cell-code}\nmodel.evaluate(x_test, y_test)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n\r 1/313 [..............................] - ETA: 22s - loss: 0.0093 - accuracy: 1.0000\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 21/313 [=>............................] - ETA: 0s - loss: 0.0287 - accuracy: 0.9866 \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 43/313 [===>..........................] - ETA: 0s - loss: 0.0571 - accuracy: 0.9826\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 65/313 [=====>........................] - ETA: 0s - loss: 0.0610 - accuracy: 0.9822\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r 87/313 [=======>......................] - ETA: 0s - loss: 0.0658 - accuracy: 0.9817\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r108/313 [=========>....................] - ETA: 0s - loss: 0.0618 - accuracy: 0.9823\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r130/313 [===========>..................] - ETA: 0s - loss: 0.0611 - accuracy: 0.9825\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r156/313 [=============>................] - ETA: 0s - loss: 0.0658 - accuracy: 0.9820\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r179/313 [================>.............] - ETA: 0s - loss: 0.0576 - accuracy: 0.9843\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r204/313 [==================>...........] - ETA: 0s - loss: 0.0524 - accuracy: 0.9856\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r229/313 [====================>.........] - ETA: 0s - loss: 0.0508 - accuracy: 0.9864\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r256/313 [=======================>......] - ETA: 0s - loss: 0.0460 - accuracy: 0.9877\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r277/313 [=========================>....] - ETA: 0s - loss: 0.0441 - accuracy: 0.9883\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r299/313 [===========================>..] - ETA: 0s - loss: 0.0414 - accuracy: 0.9889\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r313/313 [==============================] - 1s 2ms/step - loss: 0.0418 - accuracy: 0.9888\n```\n:::\n\n::: {.cell-output .cell-output-display execution_count=10}\n```\n[0.04184215888381004, 0.9887999892234802]\n```\n:::\n:::\n\n\n::: {#17bb6063 .cell execution_count=11}\n``` {.python .cell-code}\nimage_index = 59\nplt.imshow(x_test[image_index].reshape(28, 28),cmap='Greys')\npred = model.predict(x_test[image_index].reshape(1, 28, 28, 1))\nprint(' For image_index = ' + str(image_index) + ' CNN predicted number = ' + str(pred.argmax()))\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n\r1/1 [==============================] - ETA: 0s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r1/1 [==============================] - 0s 48ms/step\n For image_index = 59 CNN predicted number = 5\n```\n:::\n\n::: {.cell-output .cell-output-display}\n![](workshop4_cnn_files/figure-ipynb/cell-12-output-2.png){}\n:::\n:::\n\n\n# In this part we are going to take a picture of your own handwriting and pass it into the CNN model, for doing that we need to do the following steps:\n\n## 1. Write a number in 6 different ways on a paper and transfer the picture into the same directory that your Jupyter Notebook is\n\n::: {#71eaf96a .cell execution_count=12}\n``` {.python .cell-code}\ncwd = os.getcwd()\nprint('current working directory is = ' + cwd)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\ncurrent working directory is = /Users/cjrobe/Software/cnrrobertson.github.io/other/mlseminar/fall_2022/workshop4_cnn\n```\n:::\n:::\n\n\n::: {#b9bc8c7c .cell execution_count=13}\n``` {.python .cell-code}\nfile = r'test_images/original_image.jpeg'\ntest_image_original = cv2.imread(file, cv2.IMREAD_GRAYSCALE)\n```\n:::\n\n\n::: {#de6c5ad6 .cell execution_count=14}\n``` {.python .cell-code}\nplt.imshow(test_image_original, cmap = 'gray')\n```\n\n::: {.cell-output .cell-output-display}\n![](workshop4_cnn_files/figure-ipynb/cell-15-output-1.png){}\n:::\n:::\n\n\n## 2. Take a picture of each of them individually -- you can have only one picture and then crop it into 6 different pieces\n\n::: {#b41808a6 .cell execution_count=15}\n``` {.python .cell-code}\nfig, axs = plt.subplots(2, 3)\n\n\ncounter = 1\nfor row_number in range(0, 2):\n for col_number in range(0,3):\n \n file = r'test_images/copy_' + str(counter) +'.jpeg'\n copy_image = cv2.imread(file, cv2.IMREAD_GRAYSCALE)\n axs[row_number, col_number].imshow(copy_image, cmap = 'gray')\n counter = counter + 1\n\n```\n\n::: {.cell-output .cell-output-display}\n![](workshop4_cnn_files/figure-ipynb/cell-16-output-1.png){}\n:::\n:::\n\n\n## 4. Change the format of the picture into a readable form for your CNN model\n\n::: {#6112db91 .cell execution_count=16}\n``` {.python .cell-code}\nfile = r'test_images/copy_5.jpeg'\ncopy_1 = cv2.imread(file, cv2.IMREAD_GRAYSCALE)\nplt.imshow(copy_1, cmap = 'gray')\n```\n\n::: {.cell-output .cell-output-display}\n![](workshop4_cnn_files/figure-ipynb/cell-17-output-1.png){}\n:::\n:::\n\n\n::: {#dbc0b544 .cell execution_count=17}\n``` {.python .cell-code}\n# copy_1_resized = cv2.resize(copy_1, (28, 28), interpolation = cv2.INTER_LINEAR)\ncopy_1_resized = cv2.resize(copy_1, (28, 28))\ncopy_1_resized = cv2.bitwise_not(copy_1_resized)\n\nplt.imshow(copy_1_resized, cmap = 'Greys')\n```\n\n::: {.cell-output .cell-output-display}\n![](workshop4_cnn_files/figure-ipynb/cell-18-output-1.png){}\n:::\n:::\n\n\n::: {#a8f29758 .cell execution_count=18}\n``` {.python .cell-code}\npred = model.predict(copy_1_resized.reshape(1, 28, 28, 1))\nprint('CNN predicted number = ' + str(pred.argmax()))\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n\r1/1 [==============================] - ETA: 0s\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r1/1 [==============================] - 0s 26ms/step\nCNN predicted number = 3\n```\n:::\n:::\n\n\n---\njupyter:\n kernelspec:\n display_name: Python 3 (ipykernel)\n language: python\n name: python3\n language_info:\n codemirror_mode:\n name: ipython\n version: 3\n file_extension: .py\n mimetype: text/x-python\n name: python\n nbconvert_exporter: python\n pygments_lexer: ipython3\n version: 3.11.8\n---\n",
+ "supporting": [
+ "workshop4_cnn_files/figure-ipynb"
+ ],
+ "filters": []
+ }
+}
\ No newline at end of file
diff --git a/_freeze/other/mlseminar/fall_2022/workshop4_cnn/workshop4_cnn/figure-ipynb/cell-12-output-2.png b/_freeze/other/mlseminar/fall_2022/workshop4_cnn/workshop4_cnn/figure-ipynb/cell-12-output-2.png
new file mode 100644
index 0000000..b564238
Binary files /dev/null and b/_freeze/other/mlseminar/fall_2022/workshop4_cnn/workshop4_cnn/figure-ipynb/cell-12-output-2.png differ
diff --git a/_freeze/other/mlseminar/fall_2022/workshop4_cnn/workshop4_cnn/figure-ipynb/cell-15-output-1.png b/_freeze/other/mlseminar/fall_2022/workshop4_cnn/workshop4_cnn/figure-ipynb/cell-15-output-1.png
new file mode 100644
index 0000000..4a4f426
Binary files /dev/null and b/_freeze/other/mlseminar/fall_2022/workshop4_cnn/workshop4_cnn/figure-ipynb/cell-15-output-1.png differ
diff --git a/_freeze/other/mlseminar/fall_2022/workshop4_cnn/workshop4_cnn/figure-ipynb/cell-16-output-1.png b/_freeze/other/mlseminar/fall_2022/workshop4_cnn/workshop4_cnn/figure-ipynb/cell-16-output-1.png
new file mode 100644
index 0000000..57e9805
Binary files /dev/null and b/_freeze/other/mlseminar/fall_2022/workshop4_cnn/workshop4_cnn/figure-ipynb/cell-16-output-1.png differ
diff --git a/_freeze/other/mlseminar/fall_2022/workshop4_cnn/workshop4_cnn/figure-ipynb/cell-17-output-1.png b/_freeze/other/mlseminar/fall_2022/workshop4_cnn/workshop4_cnn/figure-ipynb/cell-17-output-1.png
new file mode 100644
index 0000000..2ccf85f
Binary files /dev/null and b/_freeze/other/mlseminar/fall_2022/workshop4_cnn/workshop4_cnn/figure-ipynb/cell-17-output-1.png differ
diff --git a/_freeze/other/mlseminar/fall_2022/workshop4_cnn/workshop4_cnn/figure-ipynb/cell-18-output-1.png b/_freeze/other/mlseminar/fall_2022/workshop4_cnn/workshop4_cnn/figure-ipynb/cell-18-output-1.png
new file mode 100644
index 0000000..38649c5
Binary files /dev/null and b/_freeze/other/mlseminar/fall_2022/workshop4_cnn/workshop4_cnn/figure-ipynb/cell-18-output-1.png differ
diff --git a/_freeze/other/mlseminar/fall_2022/workshop4_cnn/workshop4_cnn/figure-ipynb/cell-4-output-1.png b/_freeze/other/mlseminar/fall_2022/workshop4_cnn/workshop4_cnn/figure-ipynb/cell-4-output-1.png
new file mode 100644
index 0000000..2736d4c
Binary files /dev/null and b/_freeze/other/mlseminar/fall_2022/workshop4_cnn/workshop4_cnn/figure-ipynb/cell-4-output-1.png differ
diff --git a/_freeze/other/mlseminar/fall_2022/workshop6_reinforcement/workshop6_reinforcement/execute-results/html.json b/_freeze/other/mlseminar/fall_2022/workshop6_reinforcement/workshop6_reinforcement/execute-results/html.json
index baa6eee..d556fbe 100644
--- a/_freeze/other/mlseminar/fall_2022/workshop6_reinforcement/workshop6_reinforcement/execute-results/html.json
+++ b/_freeze/other/mlseminar/fall_2022/workshop6_reinforcement/workshop6_reinforcement/execute-results/html.json
@@ -1,9 +1,10 @@
{
- "hash": "f3c4c044e9efc71fe3b89c7e72ec6c9f",
+ "hash": "e412f0d96b38317714ea9e12490bcd52",
"result": {
- "markdown": "---\nexecute:\n daemon: 500\nformat:\n html: default\n ipynb: default\ntitle: ❄️ Frozen Lake\n---\n\n\n\n\n\n **Frozen Lake** is a simple environment composed of tiles, where the AI has to **move from an initial tile to a goal**.\n\nTiles can be a safe frozen lake ✅, or a hole ❌ that gets you stuck forever. \n\nThe AI, or agent, has 4 possible actions: go **◀️ LEFT**, **🔽 DOWN**, **▶️ RIGHT**, or **🔼 UP**. \n\nThe agent must learn to avoid holes in order to reach the goal in a **minimal number of actions**.\n\n# Required Libraries \n\n\n::: {.cell execution_count=1}\n``` {.python .cell-code}\nimport gym\nimport random\nimport numpy as np\nfrom IPython.display import Image\nimport matplotlib.pyplot as plt\n```\n:::\n\n\n# Initialize the Environment\n\n::: {.cell execution_count=2}\n``` {.python .cell-code}\nenv = gym.make(\"FrozenLake-v1\", is_slippery = False) #in non-slippery version actions cannot be ignored\nenv.reset()\nenv.render()\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n\nSFFF\nFHFH\nFFFH\nHFFG\n```\n:::\n:::\n\n\n* S: starting point, safe\n* F: frozen surface, safe\n* H: hole, stuck forever\n* G: goal, safe\n\n::: {.cell execution_count=3}\n``` {.python .cell-code}\nImage(filename = \"FrozenLake.gif\", width=400)\n```\n\n::: {.cell-output .cell-output-display execution_count=3}\n```\n\n```\n:::\n:::\n\n\n::: {.cell execution_count=4}\n``` {.python .cell-code}\nImage(filename = \"Final.gif\", width=400)\n```\n\n::: {.cell-output .cell-output-display execution_count=4}\n```\n\n```\n:::\n:::\n\n\n# Reward\n\nReward schedule:\n\n* Reach goal(G): +1\n\n* Reach hole(H): 0\n\n* Reach frozen surface(F): 0\n\n# Size of Action and State Space\n\n::: {.cell execution_count=5}\n``` {.python .cell-code}\nprint(\"State space: \", env.observation_space.n)\nprint(\"Action space: \", env.action_space.n)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nState space: 16\nAction space: 4\n```\n:::\n:::\n\n\nIn Frozen Lake, there are **16 tiles**, which means our agent can be found in 16 different positions, called states. \n\nFor each state, there are **4 possible actions**: \n\n* ◀️ LEFT: **0**\n* 🔽 DOWN: **1**\n* ▶️ RIGHT: **2**\n* 🔼 UP: **3**\n\n# Initialize Q Table\n\n::: {.cell execution_count=6}\n``` {.python .cell-code}\nImage(filename = \"QTable.gif\", width=400)\n```\n\n::: {.cell-output .cell-output-display execution_count=6}\n```\n\n```\n:::\n:::\n\n\n::: {.cell execution_count=7}\n``` {.python .cell-code}\n# Our table has the following dimensions:\n# (rows x columns) = (states x actions) = (16 x 4)\n\nnb_states = env.observation_space.n # = 16\nnb_actions = env.action_space.n # = 4\nqtable = np.zeros((nb_states, nb_actions))\n\n# Let's see how it looks\nprint('Q-table =')\nprint(qtable)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nQ-table =\n[[0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]]\n```\n:::\n:::\n\n\n# Update Formula\n\n### $ Q_{new}(s_t, a_t) = Q(s_t, a_t) + \\alpha \\times (r_t + \\gamma \\times max_a Q(s_{t+1}, a) - Q(s_t, a_t)) $\n\n# Epsilon-Greedy Algorithm\n\nIn this method, we want to allow our agent to either:\n\n* Take the action with the highest value **(exploitation)**;\n* Choose a random action to try to find even better ones **(exploration)**.\n\n::: {.cell execution_count=8}\n``` {.python .cell-code}\nImage(filename = \"tradeoff.gif\", width=700)\n```\n\n::: {.cell-output .cell-output-display execution_count=8}\n```\n\n```\n:::\n:::\n\n\n# Hyperparameters\n\n::: {.cell execution_count=9}\n``` {.python .cell-code}\nepisodes = 1000 # Total number of episodes\nalpha = 0.5 # Learning rate\ngamma = 0.9 # Discount factor\nepsilon = 1.0 # Amount of randomness in the action selection\nepsilon_decay = 0.001 # Fixed amount to decrease\n```\n:::\n\n\n# Traning\n\n::: {.cell execution_count=10}\n``` {.python .cell-code}\n# List of outcomes to plot\noutcomes = []\n\nfor _ in range(episodes):\n \n state = env.reset()\n done = False\n\n # By default, we consider our outcome to be a failure\n outcomes.append(\"Failure\")\n \n # Until the agent gets stuck in a hole or reaches the goal, keep training it\n while not done:\n # Generate a random number between 0 and 1\n rnd = np.random.random()\n\n # If random number < epsilon, take a random action\n if rnd < epsilon:\n action = env.action_space.sample()\n # Else, take the action with the highest value in the current state\n else:\n action = np.argmax(qtable[state])\n \n # Implement this action and move the agent in the desired direction\n new_state, reward, done, info = env.step(action)\n\n # Update Q(s,a)\n qtable[state, action] = qtable[state, action] + \\\n alpha * (reward + gamma * np.max(qtable[new_state]) - qtable[state, action])\n \n # Update our current state\n state = new_state\n\n # If we have a reward, it means that our outcome is a success\n if reward:\n outcomes[-1] = \"Success\"\n\n # Update epsilon\n epsilon = max(epsilon - epsilon_decay, 0)\n```\n:::\n\n\n# Updated Q Table\n\n::: {.cell execution_count=11}\n``` {.python .cell-code}\nprint('===========================================')\nprint('Q-table after training:')\nprint(qtable)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n===========================================\nQ-table after training:\n[[0.531441 0.59049 0.59049 0.531441 ]\n [0.53144099 0. 0.6561 0.59048631]\n [0.59037976 0.729 0.59048952 0.65609994]\n [0.65609993 0. 0.50712647 0.57097084]\n [0.59049 0.6561 0. 0.531441 ]\n [0. 0. 0. 0. ]\n [0. 0.81 0. 0.65609609]\n [0. 0. 0. 0. ]\n [0.6561 0. 0.729 0.59049 ]\n [0.6561 0.81 0.81 0. ]\n [0.729 0.9 0. 0.729 ]\n [0. 0. 0. 0. ]\n [0. 0. 0. 0. ]\n [0. 0.80990302 0.9 0.72145318]\n [0.81 0.9 1. 0.81 ]\n [0. 0. 0. 0. ]]\n```\n:::\n:::\n\n\n# Plot Outcomes\n\n::: {.cell execution_count=12}\n``` {.python .cell-code}\nplt.figure(figsize=(12, 5))\nplt.xlabel(\"Run number\")\nplt.ylabel(\"Outcome\")\nax = plt.gca()\nax.set_facecolor('gainsboro')\nplt.bar(range(len(outcomes)), outcomes, color=\"navy\", width=1.0)\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](workshop6_reinforcement_files/figure-html/cell-13-output-1.png){width=994 height=429}\n:::\n:::\n\n\n# Evaluation \n\n::: {.cell execution_count=13}\n``` {.python .cell-code}\nepisodes = 1\nnb_success = 0\n\n\nstate = env.reset()\nenv.render()\ndone = False\n\n# Until the agent gets stuck or reaches the goal, keep training it\nwhile not done:\n \n # Choose the action with the highest value in the current state\n action = np.argmax(qtable[state])\n\n # Implement this action and move the agent in the desired direction\n new_state, reward, done, info = env.step(action)\n\n # Render the environment \n print()\n env.render()\n\n # Update our current state\n state = new_state\n\n # When we get a reward, it means we solved the game\n nb_success += reward\n\n# Let's check our success rate!\nprint()\nprint (f\"Success rate = {nb_success/episodes*100}%\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n\nSFFF\nFHFH\nFFFH\nHFFG\n\n (Down)\nSFFF\nFHFH\nFFFH\nHFFG\n\n (Down)\nSFFF\nFHFH\nFFFH\nHFFG\n\n (Right)\nSFFF\nFHFH\nFFFH\nHFFG\n\n (Right)\nSFFF\nFHFH\nFFFH\nHFFG\n\n (Down)\nSFFF\nFHFH\nFFFH\nHFFG\n\n (Right)\nSFFF\nFHFH\nFFFH\nHFFG\n\nSuccess rate = 100.0%\n```\n:::\n:::\n\n\n",
+ "engine": "jupyter",
+ "markdown": "---\nexecute:\n daemon: 500\nformat:\n html: default\n ipynb: default\ntitle: ❄️ Frozen Lake\n---\n\n\n\n\n\n **Frozen Lake** is a simple environment composed of tiles, where the AI has to **move from an initial tile to a goal**.\n\nTiles can be a safe frozen lake ✅, or a hole ❌ that gets you stuck forever.\n\nThe AI, or agent, has 4 possible actions: go **◀️ LEFT**, **🔽 DOWN**, **▶️ RIGHT**, or **🔼 UP**.\n\nThe agent must learn to avoid holes in order to reach the goal in a **minimal number of actions**.\n\n# Required Libraries\n\n\n::: {#8757466a .cell execution_count=1}\n``` {.python .cell-code}\nimport gymnasium as gym\nimport random\nimport numpy as np\nfrom IPython.display import Image\nimport matplotlib.pyplot as plt\n```\n:::\n\n\n# Initialize the Environment\n\n::: {#7853deca .cell execution_count=2}\n``` {.python .cell-code}\nenv = gym.make(\"FrozenLake-v1\", is_slippery = False) #in non-slippery version actions cannot be ignored\nenv.reset()\nenv.render()\n```\n\n::: {.cell-output .cell-output-stderr}\n```\n/Users/cjrobe/miniforge3/envs/website/lib/python3.11/site-packages/gymnasium/envs/toy_text/frozen_lake.py:328: UserWarning: WARN: You are calling render method without specifying any render mode. You can specify the render_mode at initialization, e.g. gym.make(\"FrozenLake-v1\", render_mode=\"rgb_array\")\n gym.logger.warn(\n```\n:::\n:::\n\n\n* S: starting point, safe\n* F: frozen surface, safe\n* H: hole, stuck forever\n* G: goal, safe\n\n::: {#783ece80 .cell execution_count=3}\n``` {.python .cell-code}\nImage(filename = \"FrozenLake.gif\", width=400)\n```\n\n::: {.cell-output .cell-output-display execution_count=3}\n```\n\n```\n:::\n:::\n\n\n::: {#2164297f .cell execution_count=4}\n``` {.python .cell-code}\nImage(filename = \"Final.gif\", width=400)\n```\n\n::: {.cell-output .cell-output-display execution_count=4}\n```\n\n```\n:::\n:::\n\n\n# Reward\n\nReward schedule:\n\n* Reach goal(G): +1\n\n* Reach hole(H): 0\n\n* Reach frozen surface(F): 0\n\n# Size of Action and State Space\n\n::: {#d92dfc86 .cell execution_count=5}\n``` {.python .cell-code}\nprint(\"State space: \", env.observation_space.n)\nprint(\"Action space: \", env.action_space.n)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nState space: 16\nAction space: 4\n```\n:::\n:::\n\n\nIn Frozen Lake, there are **16 tiles**, which means our agent can be found in 16 different positions, called states.\n\nFor each state, there are **4 possible actions**:\n\n* ◀️ LEFT: **0**\n* 🔽 DOWN: **1**\n* ▶️ RIGHT: **2**\n* 🔼 UP: **3**\n\n# Initialize Q Table\n\n::: {#7b73facd .cell execution_count=6}\n``` {.python .cell-code}\nImage(filename = \"QTable.gif\", width=400)\n```\n\n::: {.cell-output .cell-output-display execution_count=6}\n```\n\n```\n:::\n:::\n\n\n::: {#7e7eda1e .cell execution_count=7}\n``` {.python .cell-code}\n# Our table has the following dimensions:\n# (rows x columns) = (states x actions) = (16 x 4)\n\nnb_states = env.observation_space.n # = 16\nnb_actions = env.action_space.n # = 4\nqtable = np.zeros((nb_states, nb_actions))\n\n# Let's see how it looks\nprint('Q-table =')\nprint(qtable)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nQ-table =\n[[0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]]\n```\n:::\n:::\n\n\n# Update Formula\n\n### $ Q_{new}(s_t, a_t) = Q(s_t, a_t) + \\alpha \\times (r_t + \\gamma \\times max_a Q(s_{t+1}, a) - Q(s_t, a_t)) $\n\n# Epsilon-Greedy Algorithm\n\nIn this method, we want to allow our agent to either:\n\n* Take the action with the highest value **(exploitation)**;\n* Choose a random action to try to find even better ones **(exploration)**.\n\n::: {#df6e2dd6 .cell execution_count=8}\n``` {.python .cell-code}\nImage(filename = \"tradeoff.gif\", width=700)\n```\n\n::: {.cell-output .cell-output-display execution_count=8}\n```\n\n```\n:::\n:::\n\n\n# Hyperparameters\n\n::: {#a0f0d6ba .cell execution_count=9}\n``` {.python .cell-code}\nepisodes = 1000 # Total number of episodes\nalpha = 0.5 # Learning rate\ngamma = 0.9 # Discount factor\nepsilon = 1.0 # Amount of randomness in the action selection\nepsilon_decay = 0.001 # Fixed amount to decrease\n```\n:::\n\n\n# Training\n\n::: {#2bfbb3c8 .cell execution_count=10}\n``` {.python .cell-code}\n# List of outcomes to plot\noutcomes = []\n\nfor _ in range(episodes):\n\n state,info = env.reset()\n done = False\n\n # By default, we consider our outcome to be a failure\n outcomes.append(\"Failure\")\n\n # Until the agent gets stuck in a hole or reaches the goal, keep training it\n while not done:\n # Generate a random number between 0 and 1\n rnd = np.random.random()\n\n # If random number < epsilon, take a random action\n if rnd < epsilon:\n action = env.action_space.sample()\n # Else, take the action with the highest value in the current state\n else:\n action = np.argmax(qtable[state])\n\n # Implement this action and move the agent in the desired direction\n new_state, reward, done, _, info = env.step(action)\n\n # Update Q(s,a)\n qtable[state, action] = qtable[state, action] + \\\n alpha * (reward + gamma * np.max(qtable[new_state]) - qtable[state, action])\n\n # Update our current state\n state = new_state\n\n # If we have a reward, it means that our outcome is a success\n if reward:\n outcomes[-1] = \"Success\"\n\n # Update epsilon\n epsilon = max(epsilon - epsilon_decay, 0)\n```\n:::\n\n\n# Updated Q Table\n\n::: {#cdd0776a .cell execution_count=11}\n``` {.python .cell-code}\nprint('===========================================')\nprint('Q-table after training:')\nprint(qtable)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n===========================================\nQ-table after training:\n[[0.531441 0.59049 0.59048919 0.531441 ]\n [0.531441 0. 0.65609983 0.56212481]\n [0.50422703 0.72899998 0.12149802 0.61759207]\n [0.45242846 0. 0. 0. ]\n [0.59049 0.6561 0. 0.531441 ]\n [0. 0. 0. 0. ]\n [0. 0.81 0. 0.60486928]\n [0. 0. 0. 0. ]\n [0.6561 0. 0.729 0.59049 ]\n [0.6561 0.81 0.81 0. ]\n [0.72894994 0.9 0. 0.72001722]\n [0. 0. 0. 0. ]\n [0. 0. 0. 0. ]\n [0. 0.81 0.9 0.729 ]\n [0.81 0.9 1. 0.81 ]\n [0. 0. 0. 0. ]]\n```\n:::\n:::\n\n\n# Plot Outcomes\n\n::: {#fa67dc0c .cell execution_count=12}\n``` {.python .cell-code}\nplt.figure(figsize=(12, 5))\nplt.xlabel(\"Run number\")\nplt.ylabel(\"Outcome\")\nax = plt.gca()\nax.set_facecolor('gainsboro')\nplt.bar(range(len(outcomes)), outcomes, color=\"navy\", width=1.0)\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](workshop6_reinforcement_files/figure-html/cell-13-output-1.png){width=994 height=429}\n:::\n:::\n\n\n# Evaluation\n\n::: {#d8e87d7e .cell execution_count=13}\n``` {.python .cell-code}\nepisodes = 1\nnb_success = 0\n\n\nstate,info = env.reset()\nenv.render()\ndone = False\n\n# Until the agent gets stuck or reaches the goal, keep training it\nwhile not done:\n\n # Choose the action with the highest value in the current state\n action = np.argmax(qtable[state])\n\n # Implement this action and move the agent in the desired direction\n new_state, reward, done, _, info = env.step(action)\n\n # Render the environment\n print()\n env.render()\n\n # Update our current state\n state = new_state\n\n # When we get a reward, it means we solved the game\n nb_success += reward\n\n# Let's check our success rate!\nprint()\nprint (f\"Success rate = {nb_success/episodes*100}%\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n\n\n\n\n\n\n\nSuccess rate = 100.0%\n```\n:::\n:::\n\n\n",
"supporting": [
- "workshop6_reinforcement_files"
+ "workshop6_reinforcement_files/figure-html"
],
"filters": [],
"includes": {}
diff --git a/_freeze/other/mlseminar/fall_2022/workshop6_reinforcement/workshop6_reinforcement/execute-results/ipynb.json b/_freeze/other/mlseminar/fall_2022/workshop6_reinforcement/workshop6_reinforcement/execute-results/ipynb.json
new file mode 100644
index 0000000..1368419
--- /dev/null
+++ b/_freeze/other/mlseminar/fall_2022/workshop6_reinforcement/workshop6_reinforcement/execute-results/ipynb.json
@@ -0,0 +1,11 @@
+{
+ "hash": "e412f0d96b38317714ea9e12490bcd52",
+ "result": {
+ "engine": "jupyter",
+ "markdown": "---\nexecute:\n daemon: 500\nformat:\n html: default\n ipynb: default\ntitle: ❄️ Frozen Lake\n---\n\n\n\n\n\n **Frozen Lake** is a simple environment composed of tiles, where the AI has to **move from an initial tile to a goal**.\n\nTiles can be a safe frozen lake ✅, or a hole ❌ that gets you stuck forever.\n\nThe AI, or agent, has 4 possible actions: go **◀️ LEFT**, **🔽 DOWN**, **▶️ RIGHT**, or **🔼 UP**.\n\nThe agent must learn to avoid holes in order to reach the goal in a **minimal number of actions**.\n\n# Required Libraries\n\n\n::: {#9b8dceb9 .cell execution_count=1}\n``` {.python .cell-code}\nimport gymnasium as gym\nimport random\nimport numpy as np\nfrom IPython.display import Image\nimport matplotlib.pyplot as plt\n```\n:::\n\n\n# Initialize the Environment\n\n::: {#ad8f4932 .cell execution_count=2}\n``` {.python .cell-code}\nenv = gym.make(\"FrozenLake-v1\", is_slippery = False) #in non-slippery version actions cannot be ignored\nenv.reset()\nenv.render()\n```\n\n::: {.cell-output .cell-output-stderr}\n```\n/Users/cjrobe/miniforge3/envs/website/lib/python3.11/site-packages/gymnasium/envs/toy_text/frozen_lake.py:328: UserWarning: WARN: You are calling render method without specifying any render mode. You can specify the render_mode at initialization, e.g. gym.make(\"FrozenLake-v1\", render_mode=\"rgb_array\")\n gym.logger.warn(\n```\n:::\n:::\n\n\n* S: starting point, safe\n* F: frozen surface, safe\n* H: hole, stuck forever\n* G: goal, safe\n\n::: {#a34a3760 .cell execution_count=3}\n``` {.python .cell-code}\nImage(filename = \"FrozenLake.gif\", width=400)\n```\n\n::: {.cell-output .cell-output-display execution_count=3}\n```\n\n```\n:::\n:::\n\n\n::: {#830606bd .cell execution_count=4}\n``` {.python .cell-code}\nImage(filename = \"Final.gif\", width=400)\n```\n\n::: {.cell-output .cell-output-display execution_count=4}\n```\n\n```\n:::\n:::\n\n\n# Reward\n\nReward schedule:\n\n* Reach goal(G): +1\n\n* Reach hole(H): 0\n\n* Reach frozen surface(F): 0\n\n# Size of Action and State Space\n\n::: {#46f53586 .cell execution_count=5}\n``` {.python .cell-code}\nprint(\"State space: \", env.observation_space.n)\nprint(\"Action space: \", env.action_space.n)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nState space: 16\nAction space: 4\n```\n:::\n:::\n\n\nIn Frozen Lake, there are **16 tiles**, which means our agent can be found in 16 different positions, called states.\n\nFor each state, there are **4 possible actions**:\n\n* ◀️ LEFT: **0**\n* 🔽 DOWN: **1**\n* ▶️ RIGHT: **2**\n* 🔼 UP: **3**\n\n# Initialize Q Table\n\n::: {#3b73f093 .cell execution_count=6}\n``` {.python .cell-code}\nImage(filename = \"QTable.gif\", width=400)\n```\n\n::: {.cell-output .cell-output-display execution_count=6}\n```\n\n```\n:::\n:::\n\n\n::: {#ad2e3043 .cell execution_count=7}\n``` {.python .cell-code}\n# Our table has the following dimensions:\n# (rows x columns) = (states x actions) = (16 x 4)\n\nnb_states = env.observation_space.n # = 16\nnb_actions = env.action_space.n # = 4\nqtable = np.zeros((nb_states, nb_actions))\n\n# Let's see how it looks\nprint('Q-table =')\nprint(qtable)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nQ-table =\n[[0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]\n [0. 0. 0. 0.]]\n```\n:::\n:::\n\n\n# Update Formula\n\n### $ Q_{new}(s_t, a_t) = Q(s_t, a_t) + \\alpha \\times (r_t + \\gamma \\times max_a Q(s_{t+1}, a) - Q(s_t, a_t)) $\n\n# Epsilon-Greedy Algorithm\n\nIn this method, we want to allow our agent to either:\n\n* Take the action with the highest value **(exploitation)**;\n* Choose a random action to try to find even better ones **(exploration)**.\n\n::: {#530f638a .cell execution_count=8}\n``` {.python .cell-code}\nImage(filename = \"tradeoff.gif\", width=700)\n```\n\n::: {.cell-output .cell-output-display execution_count=8}\n```\n\n```\n:::\n:::\n\n\n# Hyperparameters\n\n::: {#6672b630 .cell execution_count=9}\n``` {.python .cell-code}\nepisodes = 1000 # Total number of episodes\nalpha = 0.5 # Learning rate\ngamma = 0.9 # Discount factor\nepsilon = 1.0 # Amount of randomness in the action selection\nepsilon_decay = 0.001 # Fixed amount to decrease\n```\n:::\n\n\n# Training\n\n::: {#f8b5c891 .cell execution_count=10}\n``` {.python .cell-code}\n# List of outcomes to plot\noutcomes = []\n\nfor _ in range(episodes):\n\n state,info = env.reset()\n done = False\n\n # By default, we consider our outcome to be a failure\n outcomes.append(\"Failure\")\n\n # Until the agent gets stuck in a hole or reaches the goal, keep training it\n while not done:\n # Generate a random number between 0 and 1\n rnd = np.random.random()\n\n # If random number < epsilon, take a random action\n if rnd < epsilon:\n action = env.action_space.sample()\n # Else, take the action with the highest value in the current state\n else:\n action = np.argmax(qtable[state])\n\n # Implement this action and move the agent in the desired direction\n new_state, reward, done, _, info = env.step(action)\n\n # Update Q(s,a)\n qtable[state, action] = qtable[state, action] + \\\n alpha * (reward + gamma * np.max(qtable[new_state]) - qtable[state, action])\n\n # Update our current state\n state = new_state\n\n # If we have a reward, it means that our outcome is a success\n if reward:\n outcomes[-1] = \"Success\"\n\n # Update epsilon\n epsilon = max(epsilon - epsilon_decay, 0)\n```\n:::\n\n\n# Updated Q Table\n\n::: {#459636fa .cell execution_count=11}\n``` {.python .cell-code}\nprint('===========================================')\nprint('Q-table after training:')\nprint(qtable)\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n===========================================\nQ-table after training:\n[[0.531441 0.59049 0.59049 0.531441 ]\n [0.531441 0. 0.6561 0.59049 ]\n [0.59049 0.729 0.59049 0.6561 ]\n [0.6561 0. 0.59047945 0.59045162]\n [0.59049 0.6561 0. 0.531441 ]\n [0. 0. 0. 0. ]\n [0. 0.81 0. 0.6561 ]\n [0. 0. 0. 0. ]\n [0.6561 0. 0.729 0.59049 ]\n [0.6561 0.81 0.81 0. ]\n [0.729 0.9 0. 0.729 ]\n [0. 0. 0. 0. ]\n [0. 0. 0. 0. ]\n [0. 0.80134387 0.9 0.72880834]\n [0.81 0.9 1. 0.81 ]\n [0. 0. 0. 0. ]]\n```\n:::\n:::\n\n\n# Plot Outcomes\n\n::: {#77bb4639 .cell execution_count=12}\n``` {.python .cell-code}\nplt.figure(figsize=(12, 5))\nplt.xlabel(\"Run number\")\nplt.ylabel(\"Outcome\")\nax = plt.gca()\nax.set_facecolor('gainsboro')\nplt.bar(range(len(outcomes)), outcomes, color=\"navy\", width=1.0)\nplt.show()\n```\n\n::: {.cell-output .cell-output-display}\n![](workshop6_reinforcement_files/figure-ipynb/cell-13-output-1.png){}\n:::\n:::\n\n\n# Evaluation\n\n::: {#f130fab4 .cell execution_count=13}\n``` {.python .cell-code}\nepisodes = 1\nnb_success = 0\n\n\nstate,info = env.reset()\nenv.render()\ndone = False\n\n# Until the agent gets stuck or reaches the goal, keep training it\nwhile not done:\n\n # Choose the action with the highest value in the current state\n action = np.argmax(qtable[state])\n\n # Implement this action and move the agent in the desired direction\n new_state, reward, done, _, info = env.step(action)\n\n # Render the environment\n print()\n env.render()\n\n # Update our current state\n state = new_state\n\n # When we get a reward, it means we solved the game\n nb_success += reward\n\n# Let's check our success rate!\nprint()\nprint (f\"Success rate = {nb_success/episodes*100}%\")\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n\n\n\n\n\n\n\nSuccess rate = 100.0%\n```\n:::\n:::\n\n\n---\njupyter:\n kernelspec:\n display_name: Python 3 (ipykernel)\n language: python\n name: python3\n language_info:\n codemirror_mode:\n name: ipython\n version: 3\n file_extension: .py\n mimetype: text/x-python\n name: python\n nbconvert_exporter: python\n pygments_lexer: ipython3\n version: 3.11.8\n---\n",
+ "supporting": [
+ "workshop6_reinforcement_files/figure-ipynb"
+ ],
+ "filters": []
+ }
+}
\ No newline at end of file
diff --git a/_freeze/other/mlseminar/fall_2022/workshop6_reinforcement/workshop6_reinforcement/figure-html/cell-13-output-1.png b/_freeze/other/mlseminar/fall_2022/workshop6_reinforcement/workshop6_reinforcement/figure-html/cell-13-output-1.png
index fe7a1b4..9253f21 100644
Binary files a/_freeze/other/mlseminar/fall_2022/workshop6_reinforcement/workshop6_reinforcement/figure-html/cell-13-output-1.png and b/_freeze/other/mlseminar/fall_2022/workshop6_reinforcement/workshop6_reinforcement/figure-html/cell-13-output-1.png differ
diff --git a/_freeze/other/mlseminar/fall_2022/workshop6_reinforcement/workshop6_reinforcement/figure-ipynb/cell-13-output-1.png b/_freeze/other/mlseminar/fall_2022/workshop6_reinforcement/workshop6_reinforcement/figure-ipynb/cell-13-output-1.png
new file mode 100644
index 0000000..c0990e0
Binary files /dev/null and b/_freeze/other/mlseminar/fall_2022/workshop6_reinforcement/workshop6_reinforcement/figure-ipynb/cell-13-output-1.png differ
diff --git a/_freeze/teaching/math340/Lab3_fixed_point/Lab3_fixed_points/execute-results/html.json b/_freeze/teaching/math340/Lab3_fixed_point/Lab3_fixed_points/execute-results/html.json
index e461e38..167b12b 100644
--- a/_freeze/teaching/math340/Lab3_fixed_point/Lab3_fixed_points/execute-results/html.json
+++ b/_freeze/teaching/math340/Lab3_fixed_point/Lab3_fixed_points/execute-results/html.json
@@ -1,7 +1,8 @@
{
- "hash": "8d98ddafb2fec637a32f6617890df401",
+ "hash": "0c760be4e9a4da449f389c5a255a6034",
"result": {
- "markdown": "---\ntitle: Lab 3 - Fixed point methods\nauthor: Connor Robertson\n---\n\n## Introduction\n\nOur goal is to find the fixed point of a function $g(x)$, that is, the value $x^*$ such that $x^*= g(x^*)$ (if it exists).\nIf $|g'(x^{*})|<1$, we can find the fixed point by iteration if we start sufficiently close to $x^*$.\n\nFor the example problem $g(x) = \\cos{(x)}$, we can begin with an initial guess $x_1=0.5$ and find the next point, $x_2$, by applying $g$: $x_2=g(x_1)$.\nWe repeat this process $n$ times to find $x_{n+1}=g(x_n)$.\nThis can be summarized in the following table:\n\n| n | $ x_n$ | $x_{n+1}=\\cos(x_n) $ | $ E_n=|x_n-x_{n+1}|$ |\n| :--:|:-----:| :-----: |:------:|\n| 1 | 0.5000 | 0.8775 | 0.3775 |\n| 2 | 0.8775 | 0.6390 | 0.2385 |\n| 3 | 0.6390 | 0.8026 | 0.1636 |\n| 4 | 0.8026 | 0.6947 | 0.1079 |\n| 5 | 0.6947 | 0.7681 | 0.0734 |\n| 6 | 0.7681 | 0.7191 | 0.0490 |\n| 7 | 0.7191 | 0.7523 | 0.0331 |\n| 8 | 0.7523 | 0.7300 | 0.0222 |\n| 9 | 0.7300 | 0.7451 | 0.0150 |\n| 10 | 0.7451 | 0.7350 | 0.0101 |\n| 11 | 0.7350 | 0.7418 | 0.0068 |\n\nThis table shows an iteration $n$, the $x$ value $x_n$, the result of the iteration $x_{n+1} = \\cos(x_n)$, and the difference between the current step and the next $E_n = |x_n - x_{n+1}|$.\nNote that the difference in $x_i$ between each step gets smaller and smaller as we iterate.\nThis shows that we are indeed approaching a fixed point.\nIn this case, if we continue we will eventually converge to the fixed point $x^*\\approx0.739085133$.\n\nThis process is only guaranteed to converge if $|g'(x^*)|<1$.\nIn this case, $g(x)$ is \"contracting\" around $x^*$.\nTo see this contraction visually, we can consider the following image:\n\n![[Code for the image](images/gen_im1.py)](images/img1)\n\nIn this image, the dashed line represents the line $y=x$, so the arrows go from $(x_1, g(x_1))\\to (x_2, x_2) \\to (x_2, g(x_2)) \\to \\ldots (x_4, g(x_4)$.\n\nIn practice, we do not know when we have arrived at the fixed point $x^*$, so we instead stop by looking at the difference between iterations: $E_n = |x_{n+1} - x_n|$.\nWhen this difference becomes sufficiently small, we can assume that we have the best answer that the fixed point method can give us.\n\nBelow is a program that performs fixed point iteration for a given function $g(x)$.\nThe convergence criterion for the program will be given by the error condition which can be written as:\n$$\n\\begin{align*}\n E_n={|x_{n+1} - x_n|} <\\text{ tol}\n\\end{align*}\n$$\nwhere tol is a given tolerance.\n\n::: {.callout-note}\nAlthough $|g'(x^*)|<1$ guarantees that the method will converge \\textit{in some interval around $x^*$}, in practice we usually do not know the interval.\nThus, if your initial guess for $x^*$ is not sufficiently close to the actual value of $x^*$ the method may not converge.\nInformed initial guesses and trial and error are common techniques for overcoming this shortcoming.\n:::\n\n## Newton's Method\n\nNewton's method is a fixed point iteration that converges to the root of a function $f(x)$.\nIt uses the iteration function:\n$$\n\\begin{align*}\n\tg(x) = x - \\frac{f(x)}{f'(x)}\n.\\end{align*}\n$$\nAnalyzing this function, we can see that the fixed point $x^*$ for $g(x)$ is also the root of $f(x)$:\n$$\n\\begin{align*}\n g(x^*) &= x^{*} \\\\\n x^* - \\frac{f(x^*)}{f'(x^*)}&= x^* \\\\\n - \\frac{f(x^*)}{f'(x^*)} &= 0 \\\\\n\tf(x^*) &= 0\n\\end{align*}\n$$\nas long as $f'(x^*) \\neq 0$.\n\n### Convergence\nThis method was published in 1685 but is still one of the state-of-the-art methods for root finding because it \"converges\" so quickly.\nThe idea of convergence is key to numerical methods and refers to the rate at which the error decreases as you perform more iterations.\nThe easiest way to illustrate convergence is to consider the Taylor series of our fixed point iteration centered at $x^*$:\n$$\n\\begin{align*}\n g(x_{n}) &= g(x^*) + g'(c)(x_{n}-x^*)\n\\end{align*}\n$$\nfor some $c \\in (x^*, x_{n})$.\nWe can then substitute $g(x_{n}) = x_{n+1}$ and rearrange to get:\n$$\n\\begin{align*}\n g(x_{n}) &= g(x^*) + g'(c)(x_{n}-x^*) \\\\\n\tx_{n+1} &= x^* + g'(c)(x_{n} - x^*) \\\\\n\t\\frac{x_{n+1} - x^*}{x_{n}-x^*} &= g'(c)\\\\\n\t\\frac{|x_{n+1} - x^*|}{|x_{n}-x^*|} &= |g'(c)| < 1\\\\\n\\end{align*}\n$$\nas long as $c$ is close enough to $x^*$.\nThus, we know that $|x_n - x^*|$ is larger than $|x_{n+1} - x^*|$ which means we are getting closer and closer to the fixed point with each iteration.\nWe also know that the error at step $n+1$ over the error at step $n$ is some constant $g'(c)$.\nIf $g'(c) \\neq 0$ and $g'(c) < 1$, then this is called \"first-order\" convergence.\nThis means, for example, if our error at step $n$ is $\\frac{1}{2}$ and our constant is $1$, our error will be reduced by $\\frac{1}{2}$ after 1 step.\n\nHowever, if our fixed point iteration has the property that $g'(x^*) = 0$, then we have to take a higher-order Taylor series:\n$$\n\\begin{align*}\n g(x_{n}) &= g(x^*) + g'(x^*)(x_{n}-x^*) +\\frac{1}{2} g\"(c)(x_{n}-x^*)^2 \\\\\n x_{n+1} &= x^* + \\frac{1}{2} g\"(c)(x_{n}-x^*)^2 \\\\\n \\frac{x_{n+1} - x^*}{(x_n - x^*)^2} &= \\frac{1}{2} g\"(c) \\\\\n \\frac{|x_{n+1} - x^*|}{|x_n - x^*|^2} &= \\frac{1}{2} |g\"(c)| = C\n.\\end{align*}\n$$\nNow, the error at step $n+1$ over the SQUARE of the error at the previous step is equal to a constant.\nThis is called \"second-order\" convergence.\nThis means, for example, if our error at step $n$ is $\\frac{1}{2}$ and the constant is $1$, then our error will be reduced by $\\frac{1}{2}^{2} = \\frac{1}{4}$ after 1 step.\nThus, it will take far fewer iterations to converge on the true answer.\nNewton's method is a \"second-order\" method.\n\nOne way to test this convergence is by assuming we are near the fixed point and considering:\n$$\n\\begin{align*}\n E_n = |x_{n} - x_{n-1}|\n\\end{align*}\n$$\nthen we can write the convergence definition approximately as:\n$$\n\\begin{align*}\n C = \\frac{|x_{n+1} - x^*|}{|x_n - x^*|^d} &\\approx \\frac{|x_{n+1} - x_n|}{|x_n - x_{n-1}|^d} \\\\\n &= \\frac{E_n}{(E_{n-1})^d}\n\\end{align*}\n$$\nwhere $C$ is some constant and $d$ is our order of convergence.\nThis approximation really only makes sense when $x_n$ and $x_{n-1}$ are close to $x^*$.\nHowever, we can check this version numerically by computing the error $E_n$ of our method and then trying $\\frac{E_n}{E_{n-1}^d}$ with different values of $d$ to see which one is roughly constant.\n\n## Examples\n\nThe following is a Matlab function that takes in a contraction function $g$, a starting value $x_1$, and an error tolerance \\texttt{tol}.\nIt outputs an array that contains all your iteration values: $x = [x_1, x_2, x_3, \\ldots, x_N]$.\nThe convergence criteria for the function is the error: $|x_{n+1} - x_n| < \\text{tol}$.\n\n::: {.cell execution_count=1}\n``` {.matlab .cell-code}\n%%file MyFixedPoint.m\nfunction [xs] = MyFixedPoint(g, x1, tol)\n xs = [x1];\n err = Inf;\n while err > tol\n xs = [xs g(xs(end))];\n err = abs(xs(end) - xs(end-1));\n end\nend\n```\n:::\n\n\nTesting this function on $g(x) = \\sin(x-5)$ with starting point $x_1 = 1$ and a tolerance of $10^{-7}$ is close to $0.847$:\n\n::: {.cell execution_count=2}\n``` {.matlab .cell-code}\ng = @(x) sin(x - 5);\np1 = MyFixedPoint(g, 1, 1e-7);\np1(end) \n```\n\n::: {.cell-output .cell-output-stdout}\n```\n\nans =\n\n 0.8474\n\n```\n:::\n:::\n\n\n### Newton's method\nConsider finding the root of the function $f(x) = x - \\cos(x) - 1$.\nTo find the root of this function with Newton's method, we need to reformulate it as a fixed point problem in which the fixed point is the root.\nThis can be easily done by considering:\n$$\n\\begin{align*}\n f'(x) &= 1 + sin(x) \\\\\n g(x) &= x - \\frac{f(x)}{f'(x)} \\\\\n &= x - \\frac{x - \\cos(x) -1 }{1 + \\sin(x)}\n\\end{align*}\n$$\nTo approximate the root of the function with an initial guess of $x_1 = 2.5$ and a tolerance of $10^{-10}$:\n\n::: {.cell execution_count=3}\n``` {.matlab .cell-code}\ng = @(x) x - ((x - 1 - cos(x))/ (1 + sin(x)));\n[xVec] = MyFixedPoint(@(x)g(x), 2.5, 1e-10);\nerrorVec = [0 abs(xVec(2:end) - xVec(1:end-1))];\nnVec=1:1:length(xVec);\np2_table = table(transpose(nVec), transpose(xVec), transpose(errorVec));\np2_table.Properties.VariableNames=[\"n\", \"x_n\", \"E_n\"]; disp(p2_table);\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n n x_n E_n \n```\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\n _ ______ __________\n\n```\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\n 1 2.5 0\n```\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\n 2 1.0604 1.4396\n 3 1.289 0.22862\n```\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\n 4 1.2834 0.0055993\n```\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\n 5 1.2834 2.2394e-06\n 6 1.2834 3.6282e-13\n```\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\n\n```\n:::\n:::\n\n\nIf we make a table with the ratios $\\frac{E_n}{E_{n-1}}$, $\\frac{E_n}{(E_{n-1})^2}$, and $\\frac{E_n}{(E_{n-1})^3}$ the preivous results, we can examine an approximate convergence rate for the method:\n\n::: {.cell execution_count=4}\n``` {.matlab .cell-code}\nerrorVec = [0 abs(xVec(2:end) - xVec(1:end-1))];\nratio1 = errorVec(2:end) ./ errorVec(1:end-1);\nratio2 = errorVec(2:end) ./ (errorVec(1:end-1) .^2);\nratio3 = errorVec(2:end) ./ (errorVec(1:end-1) .^3);\np2_table = table(ratio1', ratio2', ratio3');\np2_table.Properties.VariableNames=[\"E_n / E_n-1\", \"E_n / E_n-1^2\", \"E_n / E_n-1^3\"];\ndisp(p2_table);\n```\n\n::: {.cell-output .cell-output-stdout}\n```\n E_n / E_n-1 E_n / E_n-1^2 E_n / E_n-1^3\n```\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\n ___________ _____________ _____________\n\n```\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\n Inf Inf Inf \n```\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\n 0.15881 0.11032 0.07663 \n 0.024492 0.10713 0.46859 \n```\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\n 0.00039994 0.071426 12.756 \n```\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\n 1.6202e-07 0.07235 32308 \n```\n:::\n\n::: {.cell-output .cell-output-stdout}\n```\n\n```\n:::\n:::\n\n\nIn this, we can see that the second column (which represents a roughly quadratic convergence) is roughly constant, demonstrating that this ratio is holding true.\nOn the other hand, the first column decays to 0, showing that the errors \n\n### Stability of fixed points\nConsider the function $g(x) = 1.8x - x^2$ which has fixed points $x=0$ and $x=0.8$.\nIf we use an initial guess $x_1 = 0.1$ and tolerance $10^{-5}$:\n\n::: {.cell execution_count=5}\n``` {.matlab .cell-code}\ng = @(x) 1.8*x - x^2;\np3 = MyFixedPoint(g, .1, 1e-5);\ndisp(p3(end)) \n```\n\n::: {.cell-output .cell-output-stdout}\n```\n 0.8000\n\n```\n:::\n:::\n\n\nWe approach the fixed point $x=0.8$ because it is a stable (attracting) fixed point.\nOn the other hand, if we start at $x_1 = -0.1$:\n\n::: {.cell execution_count=6}\n``` {.matlab .cell-code}\ng = @(x) 1.8*x - x^2;\np3 = MyFixedPoint(g, -0.1, 1e-5);\ndisp(['Final answer: ', num2str(p3(end))])\n```\n\n::: {.cell-output .cell-output-stdout}\n```\nFinal answer: -Inf\n```\n:::\n:::\n\n\nWe are no longer in the basin of attraction of $x=0.8$ and so our iteration is expelled from the unstable fixed point $x=0$.\n\n",
+ "engine": "jupyter",
+ "markdown": "---\ntitle: Lab 3 - Fixed point methods\nauthor: Connor Robertson\n---\n\n## Introduction\n\nOur goal is to find the fixed point of a function $g(x)$, that is, the value $x^*$ such that $x^*= g(x^*)$ (if it exists).\nIf $|g'(x^{*})|<1$, we can find the fixed point by iteration if we start sufficiently close to $x^*$.\n\nFor the example problem $g(x) = \\cos{(x)}$, we can begin with an initial guess $x_1=0.5$ and find the next point, $x_2$, by applying $g$: $x_2=g(x_1)$.\nWe repeat this process $n$ times to find $x_{n+1}=g(x_n)$.\nThis can be summarized in the following table:\n\n| n | $ x_n$ | $x_{n+1}=\\cos(x_n) $ | $ E_n=|x_n-x_{n+1}|$ |\n| :--:|:-----:| :-----: |:------:|\n| 1 | 0.5000 | 0.8775 | 0.3775 |\n| 2 | 0.8775 | 0.6390 | 0.2385 |\n| 3 | 0.6390 | 0.8026 | 0.1636 |\n| 4 | 0.8026 | 0.6947 | 0.1079 |\n| 5 | 0.6947 | 0.7681 | 0.0734 |\n| 6 | 0.7681 | 0.7191 | 0.0490 |\n| 7 | 0.7191 | 0.7523 | 0.0331 |\n| 8 | 0.7523 | 0.7300 | 0.0222 |\n| 9 | 0.7300 | 0.7451 | 0.0150 |\n| 10 | 0.7451 | 0.7350 | 0.0101 |\n| 11 | 0.7350 | 0.7418 | 0.0068 |\n\nThis table shows an iteration $n$, the $x$ value $x_n$, the result of the iteration $x_{n+1} = \\cos(x_n)$, and the difference between the current step and the next $E_n = |x_n - x_{n+1}|$.\nNote that the difference in $x_i$ between each step gets smaller and smaller as we iterate.\nThis shows that we are indeed approaching a fixed point.\nIn this case, if we continue we will eventually converge to the fixed point $x^*\\approx0.739085133$.\n\nThis process is only guaranteed to converge if $|g'(x^*)|<1$.\nIn this case, $g(x)$ is \"contracting\" around $x^*$.\nTo see this contraction visually, we can consider the following image:\n\n![[Code for the image](images/gen_img1.py)](images/img1)\n\nIn this image, the dashed line represents the line $y=x$, so the arrows go from $(x_1, g(x_1))\\to (x_2, x_2) \\to (x_2, g(x_2)) \\to \\ldots (x_4, g(x_4)$.\n\nIn practice, we do not know when we have arrived at the fixed point $x^*$, so we instead stop by looking at the difference between iterations: $E_n = |x_{n+1} - x_n|$.\nWhen this difference becomes sufficiently small, we can assume that we have the best answer that the fixed point method can give us.\n\nBelow is a program that performs fixed point iteration for a given function $g(x)$.\nThe convergence criterion for the program will be given by the error condition which can be written as:\n$$\n\\begin{align*}\n E_n={|x_{n+1} - x_n|} <\\text{ tol}\n\\end{align*}\n$$\nwhere tol is a given tolerance.\n\n::: {.callout-note}\nAlthough $|g'(x^*)|<1$ guarantees that the method will converge \\textit{in some interval around $x^*$}, in practice we usually do not know the interval.\nThus, if your initial guess for $x^*$ is not sufficiently close to the actual value of $x^*$ the method may not converge.\nInformed initial guesses and trial and error are common techniques for overcoming this shortcoming.\n:::\n\n## Newton's Method\n\nNewton's method is a fixed point iteration that converges to the root of a function $f(x)$.\nIt uses the iteration function:\n$$\n\\begin{align*}\n\tg(x) = x - \\frac{f(x)}{f'(x)}\n.\\end{align*}\n$$\nAnalyzing this function, we can see that the fixed point $x^*$ for $g(x)$ is also the root of $f(x)$:\n$$\n\\begin{align*}\n g(x^*) &= x^{*} \\\\\n x^* - \\frac{f(x^*)}{f'(x^*)}&= x^* \\\\\n - \\frac{f(x^*)}{f'(x^*)} &= 0 \\\\\n\tf(x^*) &= 0\n\\end{align*}\n$$\nas long as $f'(x^*) \\neq 0$.\n\n### Convergence\nThis method was published in 1685 but is still one of the state-of-the-art methods for root finding because it \"converges\" so quickly.\nThe idea of convergence is key to numerical methods and refers to the rate at which the error decreases as you perform more iterations.\nThe easiest way to illustrate convergence is to consider the Taylor series of our fixed point iteration centered at $x^*$:\n$$\n\\begin{align*}\n g(x_{n}) &= g(x^*) + g'(c)(x_{n}-x^*)\n\\end{align*}\n$$\nfor some $c \\in (x^*, x_{n})$.\nWe can then substitute $g(x_{n}) = x_{n+1}$ and rearrange to get:\n$$\n\\begin{align*}\n g(x_{n}) &= g(x^*) + g'(c)(x_{n}-x^*) \\\\\n\tx_{n+1} &= x^* + g'(c)(x_{n} - x^*) \\\\\n\t\\frac{x_{n+1} - x^*}{x_{n}-x^*} &= g'(c)\\\\\n\t\\frac{|x_{n+1} - x^*|}{|x_{n}-x^*|} &= |g'(c)| < 1\\\\\n\\end{align*}\n$$\nas long as $c$ is close enough to $x^*$.\nThus, we know that $|x_n - x^*|$ is larger than $|x_{n+1} - x^*|$ which means we are getting closer and closer to the fixed point with each iteration.\nWe also know that the error at step $n+1$ over the error at step $n$ is some constant $g'(c)$.\nIf $g'(c) \\neq 0$ and $g'(c) < 1$, then this is called \"first-order\" convergence.\nThis means, for example, if our error at step $n$ is $\\frac{1}{2}$ and our constant is $1$, our error will be reduced by $\\frac{1}{2}$ after 1 step.\n\nHowever, if our fixed point iteration has the property that $g'(x^*) = 0$, then we have to take a higher-order Taylor series:\n$$\n\\begin{align*}\n g(x_{n}) &= g(x^*) + g'(x^*)(x_{n}-x^*) +\\frac{1}{2} g\"(c)(x_{n}-x^*)^2 \\\\\n x_{n+1} &= x^* + \\frac{1}{2} g\"(c)(x_{n}-x^*)^2 \\\\\n \\frac{x_{n+1} - x^*}{(x_n - x^*)^2} &= \\frac{1}{2} g\"(c) \\\\\n \\frac{|x_{n+1} - x^*|}{|x_n - x^*|^2} &= \\frac{1}{2} |g\"(c)| = C\n.\\end{align*}\n$$\nNow, the error at step $n+1$ over the SQUARE of the error at the previous step is equal to a constant.\nThis is called \"second-order\" convergence.\nThis means, for example, if our error at step $n$ is $\\frac{1}{2}$ and the constant is $1$, then our error will be reduced by $\\frac{1}{2}^{2} = \\frac{1}{4}$ after 1 step.\nThus, it will take far fewer iterations to converge on the true answer.\nNewton's method is a \"second-order\" method.\n\nOne way to test this convergence is by assuming we are near the fixed point and considering:\n$$\n\\begin{align*}\n E_n = |x_{n} - x_{n-1}|\n\\end{align*}\n$$\nthen we can write the convergence definition approximately as:\n$$\n\\begin{align*}\n C = \\frac{|x_{n+1} - x^*|}{|x_n - x^*|^d} &\\approx \\frac{|x_{n+1} - x_n|}{|x_n - x_{n-1}|^d} \\\\\n &= \\frac{E_n}{(E_{n-1})^d}\n\\end{align*}\n$$\nwhere $C$ is some constant and $d$ is our order of convergence.\nThis approximation really only makes sense when $x_n$ and $x_{n-1}$ are close to $x^*$.\nHowever, we can check this version numerically by computing the error $E_n$ of our method and then trying $\\frac{E_n}{E_{n-1}^d}$ with different values of $d$ to see which one is roughly constant.\n\n## Examples\n\nThe following is a Matlab function that takes in a contraction function $g$, a starting value $x_1$, and an error tolerance \\texttt{tol}.\nIt outputs an array that contains all your iteration values: $x = [x_1, x_2, x_3, \\ldots, x_N]$.\nThe convergence criteria for the function is the error: $|x_{n+1} - x_n| < \\text{tol}$.\n\n\n```{matlab}\n%| output: false\n%%file MyFixedPoint.m\nfunction [xs] = MyFixedPoint(g, x1, tol)\n xs = [x1];\n err = Inf;\n while err > tol\n xs = [xs g(xs(end))];\n err = abs(xs(end) - xs(end-1));\n end\nend\n```\n\n\nTesting this function on $g(x) = \\sin(x-5)$ with starting point $x_1 = 1$ and a tolerance of $10^{-7}$ is close to $0.847$:\n\n\n```{matlab}\ng = @(x) sin(x - 5);\np1 = MyFixedPoint(g, 1, 1e-7);\np1(end)\n```\n\n\n### Newton's method\nConsider finding the root of the function $f(x) = x - \\cos(x) - 1$.\nTo find the root of this function with Newton's method, we need to reformulate it as a fixed point problem in which the fixed point is the root.\nThis can be easily done by considering:\n$$\n\\begin{align*}\n f'(x) &= 1 + sin(x) \\\\\n g(x) &= x - \\frac{f(x)}{f'(x)} \\\\\n &= x - \\frac{x - \\cos(x) -1 }{1 + \\sin(x)}\n\\end{align*}\n$$\nTo approximate the root of the function with an initial guess of $x_1 = 2.5$ and a tolerance of $10^{-10}$:\n\n\n```{matlab}\ng = @(x) x - ((x - 1 - cos(x))/ (1 + sin(x)));\n[xVec] = MyFixedPoint(@(x)g(x), 2.5, 1e-10);\nerrorVec = [0 abs(xVec(2:end) - xVec(1:end-1))];\nnVec=1:1:length(xVec);\np2_table = table(transpose(nVec), transpose(xVec), transpose(errorVec));\np2_table.Properties.VariableNames=[\"n\", \"x_n\", \"E_n\"]; disp(p2_table);\n```\n\n\nIf we make a table with the ratios $\\frac{E_n}{E_{n-1}}$, $\\frac{E_n}{(E_{n-1})^2}$, and $\\frac{E_n}{(E_{n-1})^3}$ the preivous results, we can examine an approximate convergence rate for the method:\n\n\n```{matlab}\nerrorVec = [0 abs(xVec(2:end) - xVec(1:end-1))];\nratio1 = errorVec(2:end) ./ errorVec(1:end-1);\nratio2 = errorVec(2:end) ./ (errorVec(1:end-1) .^2);\nratio3 = errorVec(2:end) ./ (errorVec(1:end-1) .^3);\np2_table = table(ratio1', ratio2', ratio3');\np2_table.Properties.VariableNames=[\"E_n / E_n-1\", \"E_n / E_n-1^2\", \"E_n / E_n-1^3\"];\ndisp(p2_table);\n```\n\n\nIn this, we can see that the second column (which represents a roughly quadratic convergence) is roughly constant, demonstrating that this ratio is holding true.\nOn the other hand, the first column decays to 0, showing that the errors\n\n### Stability of fixed points\nConsider the function $g(x) = 1.8x - x^2$ which has fixed points $x=0$ and $x=0.8$.\nIf we use an initial guess $x_1 = 0.1$ and tolerance $10^{-5}$:\n\n\n```{matlab}\ng = @(x) 1.8*x - x^2;\np3 = MyFixedPoint(g, .1, 1e-5);\ndisp(p3(end))\n```\n\n\nWe approach the fixed point $x=0.8$ because it is a stable (attracting) fixed point.\nOn the other hand, if we start at $x_1 = -0.1$:\n\n\n```{matlab}\ng = @(x) 1.8*x - x^2;\np3 = MyFixedPoint(g, -0.1, 1e-5);\ndisp(['Final answer: ', num2str(p3(end))])\n```\n\n\nWe are no longer in the basin of attraction of $x=0.8$ and so our iteration is expelled from the unstable fixed point $x=0$.\n\n",
"supporting": [
"Lab3_fixed_points_files/figure-html"
],
diff --git a/docs/cv.html b/docs/cv.html
index 4c3448f..2161838 100644
--- a/docs/cv.html
+++ b/docs/cv.html
@@ -2,12 +2,12 @@
-
+
-Connor Robertson – cv
+Connor Robertson
@@ -48,7 +48,12 @@
"collapse-after": 3,
"panel-placement": "end",
"type": "textbox",
- "limit": 20,
+ "limit": 50,
+ "keyboard-shortcut": [
+ "f",
+ "/",
+ "s"
+ ],
"language": {
"search-no-results-text": "No results",
"search-matching-documents-text": "matching documents",
@@ -57,8 +62,10 @@
"search-more-match-text": "more match in this document",
"search-more-matches-text": "more matches in this document",
"search-clear-button-title": "Clear",
+ "search-text-placeholder": "",
"search-detached-cancel-button-title": "Cancel",
- "search-submit-button-title": "Submit"
+ "search-submit-button-title": "Submit",
+ "search-label": "Search"
}
}
@@ -70,29 +77,30 @@
-