text:
### A Pluto.jl notebook ###
# v0.17.7

using Markdown
using InteractiveUtils

# ╔═╡ 6bcd5cd3-57c0-40a6-83eb-87ace39d50f9
begin
	using Plots
	using ForwardDiff
	using LaTeXStrings

	md"""
	# Homework 3

	Eric Nguyen
	"""
end

# ╔═╡ 9ce3d4d6-4a66-46ab-895e-13e03cd3990e
md"""
### Problem 1

The Taylor expansion of a function ``f`` about ``x_0`` is defined as

$f(x) = \sum_{n = 0}^∞ \frac{1}{n!} f^{(n)}(x_0)(x - x_0)^n$

First, we want to find the first three nonzero terms of the Taylor expansions about ``x = 0`` for ``\cosh{(x)}``.

$\cosh(x) = 1 + \frac{1}{2!} x^2 + \frac{1}{4!} x^4 + ⋯$

Next, for ``\sinh{(x)}``.

$\sinh(x) = x + \frac{1}{3!} x^3 + \frac{1}{5!} x^5 + ⋯$
"""

# ╔═╡ 05029d3c-bde7-4548-9f1d-9fd981e217d8
let
	f(x) = cosh(x)
	plot(f, label=L"\cosh(x)", title="Taylor expansion about $(L"x = 0") for $(L"\cosh{(x)}")")
	plot!(x -> 1, label="First term")
	plot!(x -> 1 + x^2 / factorial(2), label="Second term")
	plot!(x -> 1 + x^2 / factorial(2) + x^4 / factorial(4), label="Third term")
end

# ╔═╡ 9f7db206-54f8-4374-85af-00dc38ec00d6
let
	f(x) = sinh(x)
	plot(f, label=L"\sinh(x)", title="Taylor expansion about $(L"x = 0") for $(L"\sinh{(x)}")")
	plot!(x -> x, label="First term")
	plot!(x -> x + x^3 / factorial(3), label="Second term")
	plot!(x -> x + x^3 / factorial(3) + x^5 / factorial(5), label="Third term")
end

# ╔═╡ 751fa195-5e94-4f19-9b91-56c599d8c448
md"""
### Problem 2

**(a).**
For the point charge at ``+a/2``, the electric field at some ``z`` is

$E(z) = \frac{kq}{\left(z - \frac{a}{2}\right)^2}$

For the point charge at ``-a/2``, the electric field at some ``z`` is

$E(z) = -\frac{kq}{\left(z + \frac{a}{2}\right)^2}$

Then the electric field at some ``z`` by both point charges is

$\begin{align*}
E(z) &= \frac{kq}{\left(z - \frac{a}{2}\right)^2} - \frac{kq}{\left(z + \frac{a}{2}\right)^2} \\
&= \frac{kq \left[\left(z + \frac{a}{2}\right)^2 - \left(z - \frac{a}{2}\right)^2\right]}{\left(z - \frac{a}{2}\right)^2\left(z + \frac{a}{2}\right)^2} \\
&= \frac{kq\left(z^2 + za + \frac{a^2}{4} - z^2 + za - \frac{a^2}{4}\right)}{\left(z - \frac{a}{2}\right)^2\left(z + \frac{a}{2}\right)^2} \\
&= \frac{kq\left(2za\right)}{\left(z - \frac{a}{2}\right)^2\left(z + \frac{a}{2}\right)^2} \\
&≈ \frac{2zpk}{z^4} = \frac{1}{4\pi\epsilon_0} \frac{2p}{z^3}
\end{align*}$

The electric field from a dipole falls off faster since it decreases proportionally with ``z^3`` as opposed to it decreasing proportionally with ``z`` for an isolated electric charge.

**(b).**
The distance from the point charges to some ``x`` is given by

$r = \sqrt{x^2 + \frac{a^2}{4}}$

Then the electric field for a position on the ``x``-axis in the direction of the negative point charge is given by the parallel component of each electric field,

$E(x) = \frac{2kq}{x^2 + \frac{a^2}{4}} \cos{\theta}$

Using geometry, we can rewrite ``\cos{\theta}`` as

$\cos{\theta} = \frac{\frac{a}{2}}{r} = \frac{a}{2r}$

So ``E(x)`` is

$E(x) = \frac{kqa}{r \left(x^2 + \frac{a^2}{4}\right)} ≈ \frac{1}{4\pi\epsilon_0} \frac{p}{x^3}$

in the direction of the negative point charge.
The field from an electric dipole at some ``x`` position also falls off faster than that of an isolated electric charge.
"""

# ╔═╡ 7d31aca7-324c-4e17-8f0f-fc0dbbb92719
md"""
### Problem 3
"""

# ╔═╡ 2975571f-2562-4d63-a99e-fbb72a2c79d5
md"""
The value of ``x`` that maximizes ``f(x)`` is given by ``f'(x) = 0``,

$\frac{d}{dx} x^n e^{-x} = -x^n e^{-x} + nx^{n-1} e^{-x}$

$\begin{align*}
-x^n e^{-x} + nx^{n-1} e^{-x} &= 0 \\
-x^n + nx^{n-1} &= 0 \\
nx^{n-1} &= x^n \\
x &= n
\end{align*}$

The value of ``x`` that maximizes ``f(x)`` is ``n``.
"""

# ╔═╡ bc4fc99e-c732-4d21-8e75-226d1b0dac45
let
	n = 100
	f(x) = x^n * exp(-x)
	plot(f, xlims=[n-n/2,n+n/2])
end

# ╔═╡ 4e92fdc5-6f74-4f51-9d93-4821d86d00c8
md"""
$f(x) = (e^{\log{x}})^n e^{-e^{\log{x}}} = e^{n\log{x} - x}$

$y ≡ x-n \implies x = y+n$

$f(y) = e^{n\log{(y+n)} - n - y} = e^{n\log{n} + n \log{\left(1 + \frac{y}{n}\right)} - n - y}$

The Taylor series of the logarithm expression ``\log{\left(1 + \frac{y}{n}\right)}`` to second order about ``y = 0`` is

$\log{\left(1 + \frac{y}{n}\right)} = \log{(1)} + \frac{1}{n} (y) - \frac{1}{2} \frac{1}{n^2} (y)^2 = \frac{y}{n} - \frac{y^2}{2n^2}$

Gaussian integral

$∫_0^∞ x^n e^{-x} \,dx = n^n e^{-n} \sqrt{2 \pi n} = Γ(n + 1) ≈ n!$

In other words,

$n! ≈ \sqrt{2\pi n} \left(\frac{n}{e}\right)^n$
"""

# ╔═╡ 1dcd3bdc-7653-4ff7-ab41-03ae49ceb930
md"""
### Problem 4

To find ``\cos{3x}`` and ``\sin{3x}`` in terms of ``\cos{x}`` and ``\sin{x}`` we can apply Euler's formula and equate the real parts and imaginary parts.

$\begin{align*}
\cos{3x} + i \sin{3x} &= \cos{(x + x + x)} + i \sin{(x + x + x)} \\
&= (\cos{x} + i \sin{x})(\cos{x} + i \sin{x})(\cos{x} + i \sin{x}) \\
&= (\cos{x} + i \sin{x})^3 \qquad \text{Apply Binomial theorem} \\
&= (\cos{x})^3 + 3 (\cos{x})^2 (i \sin{x}) + 3 (\cos{x}) (i \sin{x})^2 + (i \sin{x})^3 \\
&= (\cos{x})^3 + 3 (\cos{x})^2 (i \sin{x}) - 3 (\cos{x}) (\sin{x})^2 - i(\sin{x})^3 \\
&= (\cos{x})^3 - 3 (\cos{x}) (\sin{x})^2 + 3 (\cos{x})^2 (i \sin{x}) - i(\sin{x})^3 \\
&= (\cos{x})^3 - 3 (\cos{x}) (\sin{x})^2 + i \left[3 (\cos{x})^2 (\sin{x}) - (\sin{x})^3\right] \\
\end{align*}$

Matching the real and imaginary parts, we see that

$\cos{3x} = (\cos{x})^3 - 3(\cos{x})(\sin{x})^2$

$\sin{3x} = 3(\cos{x})^2 (\sin{x}) - (\sin{x})^3$
"""

# ╔═╡ b61f60c0-967a-4b33-8590-87b77aa1f911
md"""
### Problem 5

For the first expression,

$e^{i (\pi/2)} = \cos{\frac{\pi}{2}} + i \sin{\frac{\pi}{2}} = i \implies i^i = (e^{i(\pi/2)})^i = e^{\pi/2}.$

For the second expression,

$\begin{align*}
\left(\frac{1 + i \sqrt{3}}{\sqrt{2} + i \sqrt{2}}\right)^{50} &= \left(\frac{2 \left(\frac{1}{2} + i \frac{\sqrt{3}}{2}\right)}{2 \left(\frac{\sqrt{2}}{2} + i \frac{\sqrt{2}}{2}\right)}\right)^{50} \\
&= \left(\frac{\cos{\frac{\pi}{3}} + i \sin{\frac{\pi}{3}}}{\cos{\frac{\pi}{4}} + i \sin{\frac{\pi}{4}}}\right)^{50} \\
&= \left(\frac{e^{i\pi/3}}{e^{i\pi/4}}\right)^{50} \\
&= e^{50(i\pi/3 - i\pi/4)} \\
&= e^{50i(\pi/12)} \\
&= e^{i (25\pi/6)} \\
&= \cos{\frac{25\pi}{6}} + i \sin{\frac{25\pi}{6}}
\end{align*}$

For the third expression,

$\begin{align*}
\sinh{(1 + i\pi / 2)} &= \frac{e^{1 + i\pi/2} - e^{-(1 + i\pi/2)}}{2} \\
&= \frac{e^{2(i\pi/2+1)} - 1}{2e^{i\pi/2+1}} \\
&= \frac{e^{i\pi+2} - 1}{2e^{i\pi/2+1}} \\
\end{align*}$

For the fourth expression,

$\begin{align*}
y &= \tanh^{-1}{x} \\
\tanh{y} &= x \\
\frac{e^y - e^{-y}}{e^y + e^{-y}} &= x \\
e^y - e^{-y} &= xe^y + xe^{-y} \\
\frac{e^{2y} - 1}{e^y} &= \frac{xe^{2y} + x}{e^y} \\
e^{2y} - 1 &= xe^{2y} + x \\
e^{2y} - xe^{2y} &= 1 + x \\
e^{2y} (1 - x) &= 1 + x \\
e^{2y} &= \frac{1 + x}{1 - x} \\
2y &= \log{\left(\frac{1 + x}{1 - x}\right)} \\
y &= \frac{1}{2} \log{\left(\frac{1 + x}{1 - x}\right)}
\end{align*}$

$\begin{align*}
e^{2 \tanh^{-1}{i}} &= e^{2 ⋅ \frac{1}{2} \log{\left(\frac{1 + i}{1 - i}\right)}} \\
&= \frac{1 + i}{1 - i} \\
&= \frac{1 + e^{i\pi/2}}{1 - e^{i\pi/2}}
\end{align*}$
"""

# ╔═╡ 049ebeb2-cf5e-47b6-bd42-4f5371b3ec73
(1 + im) / (1 - im)

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"

[compat]
ForwardDiff = "~0.10.25"
LaTeXStrings = "~1.3.0"
Plots = "~1.25.6"
"""

# ╔═╡ 00000000-0000-0000-0000-000000000002
PLUTO_MANIFEST_TOML_CONTENTS = """
# This file is machine-generated - editing it directly is not advised

julia_version = "1.7.1"
manifest_format = "2.0"

[[deps.Adapt]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "af92965fb30777147966f58acb05da51c5616b5f"
uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
version = "3.3.3"

[[deps.ArgTools]]
uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"

[[deps.Artifacts]]
uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"

[[deps.Base64]]
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"

[[deps.Bzip2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "19a35467a82e236ff51bc17a3a44b69ef35185a2"
uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0"
version = "1.0.8+0"

[[deps.Cairo_jll]]
deps = ["Artifacts", "Bzip2_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"]
git-tree-sha1 = "4b859a208b2397a7a623a03449e4636bdb17bcf2"
uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a"
version = "1.16.1+1"

[[deps.ChainRulesCore]]
deps = ["Compat", "LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "54fc4400de6e5c3e27be6047da2ef6ba355511f8"
uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
version = "1.11.6"

[[deps.ChangesOfVariables]]
deps = ["ChainRulesCore", "LinearAlgebra", "Test"]
git-tree-sha1 = "bf98fa45a0a4cee295de98d4c1462be26345b9a1"
uuid = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0"
version = "0.1.2"

[[deps.ColorSchemes]]
deps = ["ColorTypes", "Colors", "FixedPointNumbers", "Random"]
git-tree-sha1 = "6b6f04f93710c71550ec7e16b650c1b9a612d0b6"
uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4"
version = "3.16.0"

[[deps.ColorTypes]]
deps = ["FixedPointNumbers", "Random"]
git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597"
uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f"
version = "0.11.0"

[[deps.Colors]]
deps = ["ColorTypes", "FixedPointNumbers", "Reexport"]
git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40"
uuid = "5ae59095-9a9b-59fe-a467-6f913c188581"
version = "0.12.8"

[[deps.CommonSubexpressions]]
deps = ["MacroTools", "Test"]
git-tree-sha1 = "7b8a93dba8af7e3b42fecabf646260105ac373f7"
uuid = "bbf7d656-a473-5ed7-a52c-81e309532950"
version = "0.3.0"

[[deps.Compat]]
deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"]
git-tree-sha1 = "44c37b4636bc54afac5c574d2d02b625349d6582"
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
version = "3.41.0"

[[deps.CompilerSupportLibraries_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae"

[[deps.Contour]]
deps = ["StaticArrays"]
git-tree-sha1 = "9f02045d934dc030edad45944ea80dbd1f0ebea7"
uuid = "d38c429a-6771-53c6-b99e-75d170b6e991"
version = "0.5.7"

[[deps.DataAPI]]
git-tree-sha1 = "cc70b17275652eb47bc9e5f81635981f13cea5c8"
uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a"
version = "1.9.0"

[[deps.DataStructures]]
deps = ["Compat", "InteractiveUtils", "OrderedCollections"]
git-tree-sha1 = "3daef5523dd2e769dad2365274f760ff5f282c7d"
uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
version = "0.18.11"

[[deps.DataValueInterfaces]]
git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6"
uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464"
version = "1.0.0"

[[deps.Dates]]
deps = ["Printf"]
uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"

[[deps.DelimitedFiles]]
deps = ["Mmap"]
uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab"

[[deps.DiffResults]]
deps = ["StaticArrays"]
git-tree-sha1 = "c18e98cba888c6c25d1c3b048e4b3380ca956805"
uuid = "163ba53b-c6d8-5494-b064-1a9d43ac40c5"
version = "1.0.3"

[[deps.DiffRules]]
deps = ["LogExpFunctions", "NaNMath", "Random", "SpecialFunctions"]
git-tree-sha1 = "9bc5dac3c8b6706b58ad5ce24cffd9861f07c94f"
uuid = "b552c78f-8df3-52c6-915a-8e097449b14b"
version = "1.9.0"

[[deps.Distributed]]
deps = ["Random", "Serialization", "Sockets"]
uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b"

[[deps.DocStringExtensions]]
deps = ["LibGit2"]
git-tree-sha1 = "b19534d1895d702889b219c382a6e18010797f0b"
uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
version = "0.8.6"

[[deps.Downloads]]
deps = ["ArgTools", "LibCURL", "NetworkOptions"]
uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"

[[deps.EarCut_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "3f3a2501fa7236e9b911e0f7a588c657e822bb6d"
uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5"
version = "2.2.3+0"

[[deps.Expat_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b3bfd02e98aedfa5cf885665493c5598c350cd2f"
uuid = "2e619515-83b5-522b-bb60-26c02a35a201"
version = "2.2.10+0"

[[deps.FFMPEG]]
deps = ["FFMPEG_jll"]
git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8"
uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a"
version = "0.4.1"

[[deps.FFMPEG_jll]]
deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "Pkg", "Zlib_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"]
git-tree-sha1 = "d8a578692e3077ac998b50c0217dfd67f21d1e5f"
uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5"
version = "4.4.0+0"

[[deps.FixedPointNumbers]]
deps = ["Statistics"]
git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc"
uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
version = "0.8.4"

[[deps.Fontconfig_jll]]
deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "21efd19106a55620a188615da6d3d06cd7f6ee03"
uuid = "a3f928ae-7b40-5064-980b-68af3947d34b"
version = "2.13.93+0"

[[deps.Formatting]]
deps = ["Printf"]
git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8"
uuid = "59287772-0a20-5a39-b81b-1366585eb4c0"
version = "0.4.2"

[[deps.ForwardDiff]]
deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "LogExpFunctions", "NaNMath", "Preferences", "Printf", "Random", "SpecialFunctions", "StaticArrays"]
git-tree-sha1 = "1bd6fc0c344fc0cbee1f42f8d2e7ec8253dda2d2"
uuid = "f6369f11-7733-5829-9624-2563aa707210"
version = "0.10.25"

[[deps.FreeType2_jll]]
deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "87eb71354d8ec1a96d4a7636bd57a7347dde3ef9"
uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7"
version = "2.10.4+0"

[[deps.FriBidi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91"
uuid = "559328eb-81f9-559d-9380-de523a88c83c"
version = "1.0.10+0"

[[deps.GLFW_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Pkg", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll"]
git-tree-sha1 = "0c603255764a1fa0b61752d2bec14cfbd18f7fe8"
uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89"
version = "3.3.5+1"

[[deps.GR]]
deps = ["Base64", "DelimitedFiles", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Pkg", "Printf", "Random", "RelocatableFolders", "Serialization", "Sockets", "Test", "UUIDs"]
git-tree-sha1 = "4a740db447aae0fbeb3ee730de1afbb14ac798a1"
uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71"
version = "0.63.1"

[[deps.GR_jll]]
deps = ["Artifacts", "Bzip2_jll", "Cairo_jll", "FFMPEG_jll", "Fontconfig_jll", "GLFW_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pixman_jll", "Pkg", "Qt5Base_jll", "Zlib_jll", "libpng_jll"]
git-tree-sha1 = "aa22e1ee9e722f1da183eb33370df4c1aeb6c2cd"
uuid = "d2c73de3-f751-5644-a686-071e5b155ba9"
version = "0.63.1+0"

[[deps.GeometryBasics]]
deps = ["EarCut_jll", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"]
git-tree-sha1 = "58bcdf5ebc057b085e58d95c138725628dd7453c"
uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326"
version = "0.4.1"

[[deps.Gettext_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"]
git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046"
uuid = "78b55507-aeef-58d4-861c-77aaff3498b1"
version = "0.21.0+0"

[[deps.Glib_jll]]
deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "a32d672ac2c967f3deb8a81d828afc739c838a06"
uuid = "7746bdde-850d-59dc-9ae8-88ece973131d"
version = "2.68.3+2"

[[deps.Graphite2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "344bf40dcab1073aca04aa0df4fb092f920e4011"
uuid = "3b182d85-2403-5c21-9c21-1e1f0cc25472"
version = "1.3.14+0"

[[deps.Grisu]]
git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2"
uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe"
version = "1.0.2"

[[deps.HTTP]]
deps = ["Base64", "Dates", "IniFile", "Logging", "MbedTLS", "NetworkOptions", "Sockets", "URIs"]
git-tree-sha1 = "0fa77022fe4b511826b39c894c90daf5fce3334a"
uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3"
version = "0.9.17"

[[deps.HarfBuzz_jll]]
deps = ["Artifacts", "Cairo_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "Graphite2_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg"]
git-tree-sha1 = "129acf094d168394e80ee1dc4bc06ec835e510a3"
uuid = "2e76f6c2-a576-52d4-95c1-20adfe4de566"
version = "2.8.1+1"

[[deps.IniFile]]
deps = ["Test"]
git-tree-sha1 = "098e4d2c533924c921f9f9847274f2ad89e018b8"
uuid = "83e8ac13-25f8-5344-8a64-a9f2b223428f"
version = "0.5.0"

[[deps.InteractiveUtils]]
deps = ["Markdown"]
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"

[[deps.InverseFunctions]]
deps = ["Test"]
git-tree-sha1 = "a7254c0acd8e62f1ac75ad24d5db43f5f19f3c65"
uuid = "3587e190-3f89-42d0-90ee-14403ec27112"
version = "0.1.2"

[[deps.IrrationalConstants]]
git-tree-sha1 = "7fd44fd4ff43fc60815f8e764c0f352b83c49151"
uuid = "92d709cd-6900-40b7-9082-c6be49f344b6"
version = "0.1.1"

[[deps.IterTools]]
git-tree-sha1 = "fa6287a4469f5e048d763df38279ee729fbd44e5"
uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e"
version = "1.4.0"

[[deps.IteratorInterfaceExtensions]]
git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856"
uuid = "82899510-4779-5014-852e-03e436cf321d"
version = "1.0.0"

[[deps.JLLWrappers]]
deps = ["Preferences"]
git-tree-sha1 = "22df5b96feef82434b07327e2d3c770a9b21e023"
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
version = "1.4.0"

[[deps.JSON]]
deps = ["Dates", "Mmap", "Parsers", "Unicode"]
git-tree-sha1 = "8076680b162ada2a031f707ac7b4953e30667a37"
uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
version = "0.21.2"

[[deps.JpegTurbo_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "d735490ac75c5cb9f1b00d8b5509c11984dc6943"
uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8"
version = "2.1.0+0"

[[deps.LAME_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c"
uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d"
version = "3.100.1+0"

[[deps.LZO_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6"
uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac"
version = "2.10.1+0"

[[deps.LaTeXStrings]]
git-tree-sha1 = "f2355693d6778a178ade15952b7ac47a4ff97996"
uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
version = "1.3.0"

[[deps.Latexify]]
deps = ["Formatting", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "Printf", "Requires"]
git-tree-sha1 = "a8f4f279b6fa3c3c4f1adadd78a621b13a506bce"
uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316"
version = "0.15.9"

[[deps.LibCURL]]
deps = ["LibCURL_jll", "MozillaCACerts_jll"]
uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"

[[deps.LibCURL_jll]]
deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"]
uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"

[[deps.LibGit2]]
deps = ["Base64", "NetworkOptions", "Printf", "SHA"]
uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"

[[deps.LibSSH2_jll]]
deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"

[[deps.Libdl]]
uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"

[[deps.Libffi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "0b4a5d71f3e5200a7dff793393e09dfc2d874290"
uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490"
version = "3.2.2+1"

[[deps.Libgcrypt_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll", "Pkg"]
git-tree-sha1 = "64613c82a59c120435c067c2b809fc61cf5166ae"
uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4"
version = "1.8.7+0"

[[deps.Libglvnd_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll", "Xorg_libXext_jll"]
git-tree-sha1 = "7739f837d6447403596a75d19ed01fd08d6f56bf"
uuid = "7e76a0d4-f3c7-5321-8279-8d96eeed0f29"
version = "1.3.0+3"

[[deps.Libgpg_error_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9"
uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8"
version = "1.42.0+0"

[[deps.Libiconv_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "42b62845d70a619f063a7da093d995ec8e15e778"
uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531"
version = "1.16.1+1"

[[deps.Libmount_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "9c30530bf0effd46e15e0fdcf2b8636e78cbbd73"
uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9"
version = "2.35.0+0"

[[deps.Libtiff_jll]]
deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Pkg", "Zlib_jll", "Zstd_jll"]
git-tree-sha1 = "340e257aada13f95f98ee352d316c3bed37c8ab9"
uuid = "89763e89-9b03-5906-acba-b20f662cd828"
version = "4.3.0+0"

[[deps.Libuuid_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "7f3efec06033682db852f8b3bc3c1d2b0a0ab066"
uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700"
version = "2.36.0+0"

[[deps.LinearAlgebra]]
deps = ["Libdl", "libblastrampoline_jll"]
uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"

[[deps.LogExpFunctions]]
deps = ["ChainRulesCore", "ChangesOfVariables", "DocStringExtensions", "InverseFunctions", "IrrationalConstants", "LinearAlgebra"]
git-tree-sha1 = "e5718a00af0ab9756305a0392832c8952c7426c1"
uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688"
version = "0.3.6"

[[deps.Logging]]
uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"

[[deps.MacroTools]]
deps = ["Markdown", "Random"]
git-tree-sha1 = "3d3e902b31198a27340d0bf00d6ac452866021cf"
uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
version = "0.5.9"

[[deps.Markdown]]
deps = ["Base64"]
uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"

[[deps.MbedTLS]]
deps = ["Dates", "MbedTLS_jll", "Random", "Sockets"]
git-tree-sha1 = "1c38e51c3d08ef2278062ebceade0e46cefc96fe"
uuid = "739be429-bea8-5141-9913-cc70e7f3736d"
version = "1.0.3"

[[deps.MbedTLS_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"

[[deps.Measures]]
git-tree-sha1 = "e498ddeee6f9fdb4551ce855a46f54dbd900245f"
uuid = "442fdcdd-2543-5da2-b0f3-8c86c306513e"
version = "0.3.1"

[[deps.Missings]]
deps = ["DataAPI"]
git-tree-sha1 = "bf210ce90b6c9eed32d25dbcae1ebc565df2687f"
uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28"
version = "1.0.2"

[[deps.Mmap]]
uuid = "a63ad114-7e13-5084-954f-fe012c677804"

[[deps.MozillaCACerts_jll]]
uuid = "14a3606d-f60d-562e-9121-12d972cd8159"

[[deps.NaNMath]]
git-tree-sha1 = "f755f36b19a5116bb580de457cda0c140153f283"
uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
version = "0.3.6"

[[deps.NetworkOptions]]
uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"

[[deps.Ogg_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "887579a3eb005446d514ab7aeac5d1d027658b8f"
uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051"
version = "1.3.5+1"

[[deps.OpenBLAS_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"]
uuid = "4536629a-c528-5b80-bd46-f80d51c5b363"

[[deps.OpenLibm_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "05823500-19ac-5b8b-9628-191a04bc5112"

[[deps.OpenSSL_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "648107615c15d4e09f7eca16307bc821c1f718d8"
uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95"
version = "1.1.13+0"

[[deps.OpenSpecFun_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1"
uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e"
version = "0.5.5+0"

[[deps.Opus_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720"
uuid = "91d4177d-7536-5919-b921-800302f37372"
version = "1.3.2+0"

[[deps.OrderedCollections]]
git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c"
uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
version = "1.4.1"

[[deps.PCRE_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b2a7af664e098055a7529ad1a900ded962bca488"
uuid = "2f80f16e-611a-54ab-bc61-aa92de5b98fc"
version = "8.44.0+0"

[[deps.Parsers]]
deps = ["Dates"]
git-tree-sha1 = "92f91ba9e5941fc781fecf5494ac1da87bdac775"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "2.2.0"

[[deps.Pixman_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "b4f5d02549a10e20780a24fce72bea96b6329e29"
uuid = "30392449-352a-5448-841d-b1acce4e97dc"
version = "0.40.1+0"

[[deps.Pkg]]
deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"

[[deps.PlotThemes]]
deps = ["PlotUtils", "Requires", "Statistics"]
git-tree-sha1 = "a3a964ce9dc7898193536002a6dd892b1b5a6f1d"
uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a"
version = "2.0.1"

[[deps.PlotUtils]]
deps = ["ColorSchemes", "Colors", "Dates", "Printf", "Random", "Reexport", "Statistics"]
git-tree-sha1 = "6f1b25e8ea06279b5689263cc538f51331d7ca17"
uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043"
version = "1.1.3"

[[deps.Plots]]
deps = ["Base64", "Contour", "Dates", "Downloads", "FFMPEG", "FixedPointNumbers", "GR", "GeometryBasics", "JSON", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "PlotThemes", "PlotUtils", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "UUIDs", "UnicodeFun", "Unzip"]
git-tree-sha1 = "db7393a80d0e5bef70f2b518990835541917a544"
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
version = "1.25.6"

[[deps.Preferences]]
deps = ["TOML"]
git-tree-sha1 = "2cf929d64681236a2e074ffafb8d568733d2e6af"
uuid = "21216c6a-2e73-6563-6e65-726566657250"
version = "1.2.3"

[[deps.Printf]]
deps = ["Unicode"]
uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"

[[deps.Qt5Base_jll]]
deps = ["Artifacts", "CompilerSupportLibraries_jll", "Fontconfig_jll", "Glib_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "OpenSSL_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libxcb_jll", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_keysyms_jll", "Xorg_xcb_util_renderutil_jll", "Xorg_xcb_util_wm_jll", "Zlib_jll", "xkbcommon_jll"]
git-tree-sha1 = "ad368663a5e20dbb8d6dc2fddeefe4dae0781ae8"
uuid = "ea2cea3b-5b76-57ae-a6ef-0a8af62496e1"
version = "5.15.3+0"

[[deps.REPL]]
deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"

[[deps.Random]]
deps = ["SHA", "Serialization"]
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"

[[deps.RecipesBase]]
git-tree-sha1 = "6bf3f380ff52ce0832ddd3a2a7b9538ed1bcca7d"
uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
version = "1.2.1"

[[deps.RecipesPipeline]]
deps = ["Dates", "NaNMath", "PlotUtils", "RecipesBase"]
git-tree-sha1 = "37c1631cb3cc36a535105e6d5557864c82cd8c2b"
uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c"
version = "0.5.0"

[[deps.Reexport]]
git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b"
uuid = "189a3867-3050-52da-a836-e630ba90ab69"
version = "1.2.2"

[[deps.RelocatableFolders]]
deps = ["SHA", "Scratch"]
git-tree-sha1 = "cdbd3b1338c72ce29d9584fdbe9e9b70eeb5adca"
uuid = "05181044-ff0b-4ac5-8273-598c1e38db00"
version = "0.1.3"

[[deps.Requires]]
deps = ["UUIDs"]
git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7"
uuid = "ae029012-a4dd-5104-9daa-d747884805df"
version = "1.3.0"

[[deps.SHA]]
uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"

[[deps.Scratch]]
deps = ["Dates"]
git-tree-sha1 = "0b4b7f1393cff97c33891da2a0bf69c6ed241fda"
uuid = "6c6a2e73-6563-6170-7368-637461726353"
version = "1.1.0"

[[deps.Serialization]]
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"

[[deps.SharedArrays]]
deps = ["Distributed", "Mmap", "Random", "Serialization"]
uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383"

[[deps.Showoff]]
deps = ["Dates", "Grisu"]
git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de"
uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f"
version = "1.0.3"

[[deps.Sockets]]
uuid = "6462fe0b-24de-5631-8697-dd941f90decc"

[[deps.SortingAlgorithms]]
deps = ["DataStructures"]
git-tree-sha1 = "b3363d7460f7d098ca0912c69b082f75625d7508"
uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c"
version = "1.0.1"

[[deps.SparseArrays]]
deps = ["LinearAlgebra", "Random"]
uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf"

[[deps.SpecialFunctions]]
deps = ["ChainRulesCore", "IrrationalConstants", "LogExpFunctions", "OpenLibm_jll", "OpenSpecFun_jll"]
git-tree-sha1 = "e08890d19787ec25029113e88c34ec20cac1c91e"
uuid = "276daf66-3868-5448-9aa4-cd146d93841b"
version = "2.0.0"

[[deps.StaticArrays]]
deps = ["LinearAlgebra", "Random", "Statistics"]
git-tree-sha1 = "2884859916598f974858ff01df7dfc6c708dd895"
uuid = "90137ffa-7385-5640-81b9-e52037218182"
version = "1.3.3"

[[deps.Statistics]]
deps = ["LinearAlgebra", "SparseArrays"]
uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"

[[deps.StatsAPI]]
git-tree-sha1 = "d88665adc9bcf45903013af0982e2fd05ae3d0a6"
uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0"
version = "1.2.0"

[[deps.StatsBase]]
deps = ["DataAPI", "DataStructures", "LinearAlgebra", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"]
git-tree-sha1 = "51383f2d367eb3b444c961d485c565e4c0cf4ba0"
uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
version = "0.33.14"

[[deps.StructArrays]]
deps = ["Adapt", "DataAPI", "StaticArrays", "Tables"]
git-tree-sha1 = "d21f2c564b21a202f4677c0fba5b5ee431058544"
uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a"
version = "0.6.4"

[[deps.TOML]]
deps = ["Dates"]
uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"

[[deps.TableTraits]]
deps = ["IteratorInterfaceExtensions"]
git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39"
uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c"
version = "1.0.1"

[[deps.Tables]]
deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "TableTraits", "Test"]
git-tree-sha1 = "bb1064c9a84c52e277f1096cf41434b675cd368b"
uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
version = "1.6.1"

[[deps.Tar]]
deps = ["ArgTools", "SHA"]
uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"

[[deps.Test]]
deps = ["InteractiveUtils", "Logging", "Random", "Serialization"]
uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[[deps.URIs]]
git-tree-sha1 = "97bbe755a53fe859669cd907f2d96aee8d2c1355"
uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4"
version = "1.3.0"

[[deps.UUIDs]]
deps = ["Random", "SHA"]
uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"

[[deps.Unicode]]
uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"

[[deps.UnicodeFun]]
deps = ["REPL"]
git-tree-sha1 = "53915e50200959667e78a92a418594b428dffddf"
uuid = "1cfade01-22cf-5700-b092-accc4b62d6e1"
version = "0.4.1"

[[deps.Unzip]]
git-tree-sha1 = "34db80951901073501137bdbc3d5a8e7bbd06670"
uuid = "41fe7b60-77ed-43a1-b4f0-825fd5a5650d"
version = "0.1.2"

[[deps.Wayland_jll]]
deps = ["Artifacts", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"]
git-tree-sha1 = "3e61f0b86f90dacb0bc0e73a0c5a83f6a8636e23"
uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89"
version = "1.19.0+0"

[[deps.Wayland_protocols_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "66d72dc6fcc86352f01676e8f0f698562e60510f"
uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91"
version = "1.23.0+0"

[[deps.XML2_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"]
git-tree-sha1 = "1acf5bdf07aa0907e0a37d3718bb88d4b687b74a"
uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a"
version = "2.9.12+0"

[[deps.XSLT_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"]
git-tree-sha1 = "91844873c4085240b95e795f692c4cec4d805f8a"
uuid = "aed1982a-8fda-507f-9586-7b0439959a61"
version = "1.1.34+0"

[[deps.Xorg_libX11_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll", "Xorg_xtrans_jll"]
git-tree-sha1 = "5be649d550f3f4b95308bf0183b82e2582876527"
uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc"
version = "1.6.9+4"

[[deps.Xorg_libXau_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4e490d5c960c314f33885790ed410ff3a94ce67e"
uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec"
version = "1.0.9+4"

[[deps.Xorg_libXcursor_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXfixes_jll", "Xorg_libXrender_jll"]
git-tree-sha1 = "12e0eb3bc634fa2080c1c37fccf56f7c22989afd"
uuid = "935fb764-8cf2-53bf-bb30-45bb1f8bf724"
version = "1.2.0+4"

[[deps.Xorg_libXdmcp_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4fe47bd2247248125c428978740e18a681372dd4"
uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05"
version = "1.1.3+4"

[[deps.Xorg_libXext_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "b7c0aa8c376b31e4852b360222848637f481f8c3"
uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3"
version = "1.3.4+4"

[[deps.Xorg_libXfixes_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "0e0dc7431e7a0587559f9294aeec269471c991a4"
uuid = "d091e8ba-531a-589c-9de9-94069b037ed8"
version = "5.0.3+4"

[[deps.Xorg_libXi_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXfixes_jll"]
git-tree-sha1 = "89b52bc2160aadc84d707093930ef0bffa641246"
uuid = "a51aa0fd-4e3c-5386-b890-e753decda492"
version = "1.7.10+4"

[[deps.Xorg_libXinerama_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll"]
git-tree-sha1 = "26be8b1c342929259317d8b9f7b53bf2bb73b123"
uuid = "d1454406-59df-5ea1-beac-c340f2130bc3"
version = "1.1.4+4"

[[deps.Xorg_libXrandr_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll"]
git-tree-sha1 = "34cea83cb726fb58f325887bf0612c6b3fb17631"
uuid = "ec84b674-ba8e-5d96-8ba1-2a689ba10484"
version = "1.5.2+4"

[[deps.Xorg_libXrender_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "19560f30fd49f4d4efbe7002a1037f8c43d43b96"
uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa"
version = "0.9.10+4"

[[deps.Xorg_libpthread_stubs_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "6783737e45d3c59a4a4c4091f5f88cdcf0908cbb"
uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74"
version = "0.1.0+3"

[[deps.Xorg_libxcb_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"]
git-tree-sha1 = "daf17f441228e7a3833846cd048892861cff16d6"
uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b"
version = "1.13.0+3"

[[deps.Xorg_libxkbfile_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"]
git-tree-sha1 = "926af861744212db0eb001d9e40b5d16292080b2"
uuid = "cc61e674-0454-545c-8b26-ed2c68acab7a"
version = "1.1.0+4"

[[deps.Xorg_xcb_util_image_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "0fab0a40349ba1cba2c1da699243396ff8e94b97"
uuid = "12413925-8142-5f55-bb0e-6d7ca50bb09b"
version = "0.4.0+1"

[[deps.Xorg_xcb_util_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll"]
git-tree-sha1 = "e7fd7b2881fa2eaa72717420894d3938177862d1"
uuid = "2def613f-5ad1-5310-b15b-b15d46f528f5"
version = "0.4.0+1"

[[deps.Xorg_xcb_util_keysyms_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "d1151e2c45a544f32441a567d1690e701ec89b00"
uuid = "975044d2-76e6-5fbe-bf08-97ce7c6574c7"
version = "0.4.0+1"

[[deps.Xorg_xcb_util_renderutil_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "dfd7a8f38d4613b6a575253b3174dd991ca6183e"
uuid = "0d47668e-0667-5a69-a72c-f761630bfb7e"
version = "0.3.9+1"

[[deps.Xorg_xcb_util_wm_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"]
git-tree-sha1 = "e78d10aab01a4a154142c5006ed44fd9e8e31b67"
uuid = "c22f9ab0-d5fe-5066-847c-f4bb1cd4e361"
version = "0.4.1+1"

[[deps.Xorg_xkbcomp_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxkbfile_jll"]
git-tree-sha1 = "4bcbf660f6c2e714f87e960a171b119d06ee163b"
uuid = "35661453-b289-5fab-8a00-3d9160c6a3a4"
version = "1.4.2+4"

[[deps.Xorg_xkeyboard_config_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xkbcomp_jll"]
git-tree-sha1 = "5c8424f8a67c3f2209646d4425f3d415fee5931d"
uuid = "33bec58e-1273-512f-9401-5d533626f822"
version = "2.27.0+4"

[[deps.Xorg_xtrans_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "79c31e7844f6ecf779705fbc12146eb190b7d845"
uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10"
version = "1.4.0+3"

[[deps.Zlib_jll]]
deps = ["Libdl"]
uuid = "83775a58-1f1d-513f-b197-d71354ab007a"

[[deps.Zstd_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "cc4bf3fdde8b7e3e9fa0351bdeedba1cf3b7f6e6"
uuid = "3161d3a3-bdf6-5164-811a-617609db77b4"
version = "1.5.0+0"

[[deps.libass_jll]]
deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "HarfBuzz_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "5982a94fcba20f02f42ace44b9894ee2b140fe47"
uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0"
version = "0.15.1+0"

[[deps.libblastrampoline_jll]]
deps = ["Artifacts", "Libdl", "OpenBLAS_jll"]
uuid = "8e850b90-86db-534c-a0d3-1478176c7d93"

[[deps.libfdk_aac_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "daacc84a041563f965be61859a36e17c4e4fcd55"
uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280"
version = "2.0.2+0"

[[deps.libpng_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"]
git-tree-sha1 = "94d180a6d2b5e55e447e2d27a29ed04fe79eb30c"
uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f"
version = "1.6.38+0"

[[deps.libvorbis_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"]
git-tree-sha1 = "b910cb81ef3fe6e78bf6acee440bda86fd6ae00c"
uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a"
version = "1.3.7+1"

[[deps.nghttp2_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"

[[deps.p7zip_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"

[[deps.x264_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "4fea590b89e6ec504593146bf8b988b2c00922b2"
uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a"
version = "2021.5.5+0"

[[deps.x265_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "ee567a171cce03570d77ad3a43e90218e38937a9"
uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76"
version = "3.5.0+0"

[[deps.xkbcommon_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll", "Wayland_protocols_jll", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"]
git-tree-sha1 = "ece2350174195bb31de1a63bea3a41ae1aa593b6"
uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd"
version = "0.9.1+5"
"""

# ╔═╡ Cell order:
# ╟─6bcd5cd3-57c0-40a6-83eb-87ace39d50f9
# ╟─9ce3d4d6-4a66-46ab-895e-13e03cd3990e
# ╠═05029d3c-bde7-4548-9f1d-9fd981e217d8
# ╠═9f7db206-54f8-4374-85af-00dc38ec00d6
# ╟─751fa195-5e94-4f19-9b91-56c599d8c448
# ╟─7d31aca7-324c-4e17-8f0f-fc0dbbb92719
# ╟─2975571f-2562-4d63-a99e-fbb72a2c79d5
# ╠═bc4fc99e-c732-4d21-8e75-226d1b0dac45
# ╟─4e92fdc5-6f74-4f51-9d93-4821d86d00c8
# ╟─1dcd3bdc-7653-4ff7-ab41-03ae49ceb930
# ╟─b61f60c0-967a-4b33-8590-87b77aa1f911
# ╠═049ebeb2-cf5e-47b6-bd42-4f5371b3ec73
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002


text:
gmsh = Sys.which("gmsh")

if gmsh === nothing
  s = """
  No gmsh installation found in the system.
  Install gmsh and make sure that the gmsh executable
  can be found via the PATH environment variable.
  """
  error(s)
end

gmsh_root = dirname(gmsh)[1:end-4]

gmsh_jl = joinpath(gmsh_root,"lib","gmsh.jl")
if ! isfile(gmsh_jl)
  error("File not found: $gmsh_jl")
end

@info "Using the gmsh Julia API found in $gmsh_jl"

open("deps.jl","w") do f
  println(f, "# This file is automatically generated")
  println(f, "# Do not edit")
  println(f)
  println(f, :(const gmsh_jl = $gmsh_jl))
end

ext: jl


text:
### ============================================================================
### A type related to doing lass, using the proximal gradient method for L2
### regression
### ============================================================================

mutable struct Lasso2NormProx <: LassoRoot
    ## It's just a collection of data.

    A::Matrix # Feature matrix
    y::Matrix # label vector/matrix
    μ::Matrix # feature mean
    u::Number # label mean
    Z::Matrix # Starndardized Matrix
    l::Matrix # Zero mean label

    proxOptim::ProximalGradient  # The package of ProximalGradient method stuff
    λ::Float64       # the regularization parameter.

    LassoPath::Union{Matrix, Nothing} # going along a fixed row is the fixing
    # the feature while varying the lambda quantity.
    λs::Union{Vector, Nothing} # the lambda values.

    # Paramters for the iterator
    Tol::Float64
    λMin::Float64

    function Lasso2NormProx(
            A::Matrix,
            y::Array,
            λ::Float64=0.0
        )
        Warn("This type has been deprecated due to performance issues. ")
        A = copy(A)
        m, _ = size(A)
        @assert size(y, 1) == m ""*
        "The rows of X should match of the columns of y, but the size of"*
        string("X, Y is: ", size(A), " ", size(y))
        y = copy(y)

        if ndims(y) == 1
            y = reshape(y, (length(y), 1))
        end
        μ = mean(A, dims=1)::Matrix
        u = mean(y)
        Z = A .- μ
        l = y .- u
        OptModel = BuildPG2NormLasso(Z, l, λ)
        this = new(A, y, μ, u, Z, l, OptModel, λ)
        this.Tol = -1
        this.λMin = 1e-8
        return this
    end
end

function Changeλ!(this::Lasso2NormProx, λ::Float64)
    """
        Change the Lasso regularizer of the current model
    """

    ChangeProximalGradientLassoλ!(this.proxOptim, λ)
    return
end

function SolveLasso(
            this::Lasso2NormProx;
            x0::T=nothing
        )::Vector{Float64} where {T <: Union{Vector{Float64}, Nothing}}
    """
        Solve for the weights of the current model,
        given the current configuration of the model.
    """

    if !(x0 === nothing)
        x0 = reshape(x0, this.proxOptim.solutionDim)
    end

    return reshape(OptimizeProximalGradient(this.proxOptim, x0), :)

end


text:
#=
Algorithm RSVD.
given a matrix A \in \reals^{m \times n}, a target rank k and an oversampling
      parameter p (e.g., p = 10 is a good choice).
stage A. Find an approximate range.
    1. form an n \times (k+p) Gaussian random matrix G.
    2. form the sample matrix Y = AG.
    3. orthonormalize the columns of Y via a QR factorization.
stage B. Form a specific factorization.
    4. form the (k+p) \times n matrix B = Q'A.
    5. form the SVD of the (small) matrix B as B = \hat{U} D V'.
    6. form U = Q \hat{U}.
return matrices U, D, and V as an approximate rank (k+p) SVD of A.
=#
using Random, LinearAlgebra, Plots, Statistics
# ---------------------------------------------------------------------------- #
function vignette_rsvd()
rng = Random.seed!(2);              # set seed for reproducibility
n_sims = 10;                        # number of simulations
n_subs = 25;                        # number of subsamples
m = 2000;                           # rows of matrix
n = 20*ceil(log(m));                # columns of matrix
# n_sims = 50; n_subs = 25; m = 1000; n = 15*ceil(log(m)); # alt. run parameters
# n_sims = 1;  n_subs = 25; m = 5000; n = 15*ceil(log(m)); # alt. run parameters
k = ceil(log(m));                   # target rank
p = max(ceil(log(m)), 10);          # oversampling parameter
n = Int16(n); k = Int16(k); p = Int16(p);   # convert floats to integers
# ---------------------------------------------------------------------------- #
times = zeros(n_sims, 2);           # bookkeeping for run times
fro_mean = zeros(n_sims, n_subs);   # bookkeeping for mean Frobenius norm
op_mean = zeros(n_sims, n_subs);    # bookkeeping for mean operator norm
norm_bound = zeros(n_sims, 2);      # bookkeeping for theoretrical norm
fro_lo = zeros(n_sims, 1);          # bookkeeping for Frobenius norm bound
op_lo = zeros(n_sims, 1);           # bookkeeping for operator norm bound
# ---------------------------------------------------------------------------- #
for j in 1:n_sims
    # "data" matrix
    A = [2*ones(m,2)+rand(m,2) randn(m, k-2) 0.01*randn(m, n-k)]/sqrt(m);
    # NOTE: the matrix A has k columns that lead to "important" singular values.
    # The remaing n-k columns correspond to fast-decaying singular values.
    for i in 1:n_subs
        # stage A of randomized SVD
        G = randn(n, k+p);                              # Gaussian random matrix
        Y = A*G;                                        # sample matrix
        F = qr(Y); Q = Matrix(F.Q);                     # orthonormalize Y
        # stage B of randomized SVD
        B = Q'*A;                                       # form small matrix
        U_B, D_B, V_B = svd(B);                         # SVD of B
        U = Q*U_B;                                      # rank k matrix
        # bookkeeping and comparisons
        U_A, D_A, V_A = svd(A);                         # SVD of A
        fro_mean[j,i] = norm(A - Q*Q'*A, 2);
        op_mean[j,i] = opnorm(A - Q*Q'*A);
    end # end of inner simulation loop (i.e., simulation for a fixed matrix A)
    fro_lo[j,1] = sum( D_A[k+1:min(m,n)].^2 )^0.5;
    op_lo[j,1] =  D_A[k+1];
    norm_bound[j, 1] = (1 + k / (p-1))^(0.5) * fro_lo[j,1];     # Frobenius
    norm_bound[j, 2] = (1 + sqrt(k / (p-1))) * op_lo[j,1] +     # operator
                            exp(1) * (sqrt(k+p) / p) * fro_lo[j,1];
end # end of outer simulation loop
# ---------------------------------------------------------------------------- #
# plot showing singular value decay
p3 = plot(D_A, yscale = :log10, linecolor = :blue,
            marker = :circle, markercolor = :blue, label = "full",
            title = "sing. value decay (final sim.)");
p4 = plot(D_A[1:k+p], yscale = :log10, linecolor = :blue,
            marker = :circle, markercolor = :blue, label = "full",
            title = "sing. value comparison (final sim.)")
plot!(D_B, yscale = :log10, linecolor = :red, linestyle = :dash,
            marker = :x, markerstrokecolor = :red, label = "randomized");

# ---------------------------------------------------------------------------- #
# plots of average Frobenius and operator norms vs. theoretical bounds
p1 = plot(norm_bound[:,1],linecolor = :blue, marker = :circle,
            markercolor = :blue, label = "upper",
            title = "E-Y bounds: Frobenius");
plot!(mean(fro_mean, dims = 2),linecolor = :red, linestyle = :dash,
     marker = :x, markerstrokecolor = :red, label = "mean");
     plot!(fro_lo, linecolor = :blue, linestyle = :dot,
           marker = :star8, markercolor = :blue, label = "lower",
           legend = :bottomright);
p2 = plot(norm_bound[:,2],linecolor = :blue, marker = :circle,
            markercolor = :blue, label = "upper",
            title = "E-Y bounds: operator");
plot!(mean(op_mean, dims = 2),linecolor = :red, linestyle = :dash,
     marker = :x, markerstrokecolor = :red, label = "mean");
plot!(op_lo,linecolor = :blue, linestyle = :dot,
      marker = :star8, markercolor = :blue, label = "lower",
      legend = :bottomright);
# return summary plot as "output" of the function
plot(p3, p4, p1, p2, layout=(2,2))
end # end of function
# ---------------------------------------------------------------------------- #
vignette_rsvd()

max_stars_repo_name: jakeknigge/randomized-algorithm-class

max_issues_repo_name: jakeknigge/randomized-algorithm-class

max_forks_repo_name: jakeknigge/randomized-algorithm-class


text:
struct SpectralNormalizer{U,V}
    left_singular_vector::U
    right_singular_vector::V
    iterations::Int
    norm_multiplier::Float32
end

function SpectralNormalizer(
    kernel_shape;
    iterations::Int = 1,
    norm_multiplier::Float32 = 0.95,
    init = glorot_uniform,
    device = cpu,
)
    # Necessary shapes
    # Expecting this to be of shape (out_dim, in_dim)
    # For Conv layers, we expect the shape to be (out_channels, :)
    # U and V vectors
    right_singular_vector = device(init((kernel_shape[1], 1)))
    left_singular_vector = device(init((prod(kernel_shape[2:end]), 1)))

    return SpectralNormalizer(
        left_singular_vector,
        right_singular_vector,
        iterations,
        norm_multiplier,
    )
end

function (snl::SpectralNormalizer)(kernel)
    # update
    v_hat = snl.left_singular_vector
    u_hat = snl.right_singular_vector
    for iteration = 1:snl.iterations
        # Update the left singular vector
        v_hat = u_hat' * kernel # shape - (1, in_dim)
        v_hat = v_hat ./ norm(v_hat) # shape - (1, in_dim)
        # Update the right singular vector
        u_hat = v_hat * kernel'
        u_hat = u_hat ./ norm(u_hat) # shape - (out_dim, 1)
    end

    # Update the left, right singular vectors in the struct
    Flux.Zygote.@ignore copyto!(snl.right_singular_vector, u_hat)
    Flux.Zygote.@ignore copyto!(snl.left_singular_vector, v_hat)

    sigma = u_hat * kernel * v_hat'
    # Bound the spectral norm
    bounded_kernel =
        all((snl.norm_multiplier ./ sigma) .< 1) ?
        (snl.norm_multiplier ./ sigma) .* kernel : kernel
    return bounded_kernel
end


text:
# Use baremodule to shave off a few KB from the serialized `.ji` file
baremodule Xorg_xcb_util_renderutil_jll
using Base
using Base: UUID
import JLLWrappers

JLLWrappers.@generate_main_file_header("Xorg_xcb_util_renderutil")
JLLWrappers.@generate_main_file("Xorg_xcb_util_renderutil", UUID("0d47668e-0667-5a69-a72c-f761630bfb7e"))
end  # module Xorg_xcb_util_renderutil_jll


text:
@show collect('a':'z')
@show join('a':'z')

max_stars_repo_name: ethansaxenian/RosettaDecode

max_issues_repo_name: ethansaxenian/RosettaDecode

max_forks_repo_name: ethansaxenian/RosettaDecode


text:
const NamedVar = Union{Symbol,GlobalRef}

## Phase 1: direct links

# There are 3 types of entities to track: ssavalues (line/statement numbers), slots, and named objects.
# Each entity can have a number of "predecessors" (forward edges), which can be any combination of these
# three entity types. Likewise, each entity can have a number of "successors" (backward edges), also any
# combination of these entity types.
struct Links
    ssas::Vector{Int}
    slots::Vector{Int}
    names::Vector{NamedVar}
end
Links() = Links(Int[], Int[], NamedVar[])

function Base.show(io::IO, l::Links)
    print(io, "ssas: ", showempty(l.ssas),
              ", slots: ", showempty(l.slots),
              ", names: ")
    print(IOContext(io, :typeinfo=>Vector{NamedVar}), showempty(l.names))
    print(io, ';')
end

struct CodeLinks
    ssapreds::Vector{Links}
    ssasuccs::Vector{Links}
    slotpreds::Vector{Links}
    slotsuccs::Vector{Links}
    slotassigns::Vector{Vector{Int}}
    namepreds::Dict{NamedVar,Links}
    namesuccs::Dict{NamedVar,Links}
    nameassigns::Dict{NamedVar,Vector{Int}}
end
function CodeLinks(nlines::Int, nslots::Int)
    makelinks(n) = [Links() for _ = 1:n]

    return CodeLinks(makelinks(nlines),
                     makelinks(nlines),
                     makelinks(nslots),
                     makelinks(nslots),
                     [Int[] for _ = 1:nslots],
                     Dict{NamedVar,Links}(),
                     Dict{NamedVar,Links}(),
                     Dict{NamedVar,Vector{Int}}())
end
function CodeLinks(src::CodeInfo)
    cl = CodeLinks(length(src.code), length(src.slotnames))
    direct_links!(cl, src)
end

function Base.show(io::IO, cl::CodeLinks)
    print(io, "CodeLinks:")
    print_slots(io, cl)
    print_names(io, cl)
    nstmts = length(cl.ssapreds)
    nd = ndigits(nstmts)
    print(io, "\nCode:")
    for i = 1:nstmts
        print(io, '\n', lpad(i, nd), " preds: ")
        show(io, cl.ssapreds[i])
        print(io, '\n', lpad(i, nd), " succs: ")
        show(io, cl.ssasuccs[i])
    end
end

function print_slots(io::IO, cl::CodeLinks)
    nslots = length(cl.slotpreds)
    nd = ndigits(nslots)
    for i = 1:nslots
        print(io, "\nslot ", lpad(i, nd), ':')
        print(io, "\n  preds: ")
        show(io, cl.slotpreds[i])
        print(io, "\n  succs: ")
        show(io, cl.slotsuccs[i])
        print(io, "\n  assign @: ")
        show(io, cl.slotassigns[i])
    end
end

function print_names(io::IO, cl::CodeLinks)
    ukeys = namedkeys(cl)
    for key in ukeys
        print(io, '\n', key, ':')
        if haskey(cl.namepreds, key)
            print(io, "\n  preds: ")
            show(io, cl.namepreds[key])
        end
        if haskey(cl.namesuccs, key)
            print(io, "\n  succs: ")
            show(io, cl.namesuccs[key])
        end
        if haskey(cl.nameassigns, key)
            print(io, "\n  assign @: ")
            show(io, cl.nameassigns[key])
        end
    end
end

const preprinter_sentinel = isdefined(Base.IRShow, :statementidx_lineinfo_printer) ? 0 : typemin(Int32)

if isdefined(Base.IRShow, :show_ir_stmt)
    function print_with_code(preprint, postprint, io::IO, src::CodeInfo)
        src = copy(src)
        JuliaInterpreter.replace_coretypes!(src; rev=true)
        if isdefined(JuliaInterpreter, :reverse_lookup_globalref!)
            JuliaInterpreter.reverse_lookup_globalref!(src.code)
        end
        io = IOContext(io, :displaysize=>displaysize(io))
        used = BitSet()
        cfg = Core.Compiler.compute_basic_blocks(src.code)
        for stmt in src.code
            Core.Compiler.scan_ssa_use!(push!, used, stmt)
        end
        line_info_preprinter = Base.IRShow.lineinfo_disabled
        line_info_postprinter = Base.IRShow.default_expr_type_printer
        preprint(io)
        bb_idx_prev = bb_idx = 1
        for idx = 1:length(src.code)
            preprint(io, idx)
            bb_idx = Base.IRShow.show_ir_stmt(io, src, idx, line_info_preprinter, line_info_postprinter, used, cfg, bb_idx)
            postprint(io, idx, bb_idx != bb_idx_prev)
            bb_idx_prev = bb_idx
        end
        max_bb_idx_size = ndigits(length(cfg.blocks))
        line_info_preprinter(io, " "^(max_bb_idx_size + 2), preprinter_sentinel)
        postprint(io)
        return nothing
    end
else
    function print_with_code(preprint, postprint, io::IO, src::CodeInfo)
        println(io, "No IR statement printer available on this version of Julia, just aligning statements.")
        preprint(io)
        for idx = 1:length(src.code)
            preprint(io, idx)
            print(io, src.code[idx])
            println(io)
            postprint(io, idx, false)
        end
        postprint(io)
    end
end

"""
    print_with_code(io, src::CodeInfo, cl::CodeLinks)

Interweave display of code and links.

!!! compat Julia 1.6
    This function produces dummy output if suitable support is missing in your version of Julia.
"""
function print_with_code(io::IO, src::CodeInfo, cl::CodeLinks)
    function preprint(io::IO)
        print(io, "Slots:")
        print_slots(io, cl)
        print(io, "\nNames:")
        print_names(io, cl)
        println(io)
    end
    preprint(::IO, ::Int) = nothing
    postprint(::IO) = nothing
    postprint(io::IO, idx::Int, bbchanged::Bool) = postprint_linelinks(io, idx, src, cl, bbchanged)

    print_with_code(preprint, postprint, io, src)
end

function postprint_linelinks(io::IO, idx::Int, src::CodeInfo, cl::CodeLinks, bbchanged::Bool)
    printstyled(io, bbchanged ? " " : "│", color=:light_black)
    printstyled(io, "             # ", color=:yellow)
    stmt = src.code[idx]
    if isexpr(stmt, :(=))
        lhs = stmt.args[1]
        if @issslotnum(lhs)
            # id = lhs.id
            # preds, succs = cl.slotpreds[id], cl.slotsuccs[id]
            printstyled(io, "see slot ", lhs.id, '\n', color=:yellow)
        else
            # preds, succs = cl.namepreds[lhs], cl.namesuccs[lhs]
            printstyled(io, "see name ", lhs, '\n', color=:yellow)
        end
    else
        preds, succs = cl.ssapreds[idx], cl.ssasuccs[idx]
        printstyled(io, "preds: ", preds, " succs: ", succs, '\n', color=:yellow)
    end
    return nothing
end

function namedkeys(cl::CodeLinks)
    ukeys = Set{NamedVar}()
    for c in (cl.namepreds, cl.namesuccs, cl.nameassigns)
        for k in keys(c)
            push!(ukeys, k)
        end
    end
    return ukeys
end

function direct_links!(cl::CodeLinks, src::CodeInfo)
    # Utility for when a stmt itself contains a CodeInfo
    function add_inner!(cl::CodeLinks, icl::CodeLinks, idx)
        for (name, _) in icl.nameassigns
            assigns = get(cl.nameassigns, name, nothing)
            if assigns === nothing
                cl.nameassigns[name] = assigns = Int[]
            end
            push!(assigns, idx)
        end
        for (name, _) in icl.namesuccs
            succs = get(cl.namesuccs, name, nothing)
            if succs === nothing
                cl.namesuccs[name] = succs = Links()
            end
            push!(succs.ssas, idx)
        end
    end

    P = Pair{Union{SSAValue,SlotNumber,NamedVar},Links}

    for (i, stmt) in enumerate(src.code)
        if isexpr(stmt, :thunk) && isa(stmt.args[1], CodeInfo)
            icl = CodeLinks(stmt.args[1])
            add_inner!(cl, icl, i)
            continue
        elseif isa(stmt, Expr) && stmt.head ∈ trackedheads
            if stmt.head === :method && length(stmt.args) === 3 && isa(stmt.args[3], CodeInfo)
                icl = CodeLinks(stmt.args[3])
                add_inner!(cl, icl, i)
            end
            name = stmt.args[1]
            if isa(name, Symbol)
                assign = get(cl.nameassigns, name, nothing)
                if assign === nothing
                    cl.nameassigns[name] = assign = Int[]
                end
                push!(assign, i)
                targetstore = get(cl.namepreds, name, nothing)
                if targetstore === nothing
                    cl.namepreds[name] = targetstore = Links()
                end
                target = P(name, targetstore)
                add_links!(target, stmt, cl)
            end
            rhs = stmt
            target = P(SSAValue(i), cl.ssapreds[i])
        elseif isexpr(stmt, :(=))
            # An assignment
            stmt = stmt::Expr
            lhs, rhs = stmt.args[1], stmt.args[2]
            if @issslotnum(lhs)
                lhs = lhs::AnySlotNumber
                id = lhs.id
                target = P(SlotNumber(id), cl.slotpreds[id])
                push!(cl.slotassigns[id], i)
            elseif isa(lhs, NamedVar)
                targetstore = get(cl.namepreds, lhs, nothing)
                if targetstore === nothing
                    cl.namepreds[lhs] = targetstore = Links()
                end
                target = P(lhs, targetstore)
                assign = get(cl.nameassigns, lhs, nothing)
                if assign === nothing
                    cl.nameassigns[lhs] = assign = Int[]
                end
                push!(assign, i)
            else
                error("lhs ", lhs, " not recognized")
            end
        else
            rhs = stmt
            target = P(SSAValue(i), cl.ssapreds[i])
        end
        add_links!(target, rhs, cl)
    end
    return cl
end

function add_links!(target::Pair{Union{SSAValue,SlotNumber,NamedVar},Links}, @nospecialize(stmt), cl::CodeLinks)
    _targetid, targetstore = target
    targetid = _targetid::Union{SSAValue,SlotNumber,NamedVar}
    # Adds bidirectional edges
    if @isssa(stmt)
        stmt = stmt::AnySSAValue
        push!(targetstore, SSAValue(stmt.id))    # forward edge
        push!(cl.ssasuccs[stmt.id], targetid)    # backward edge
    elseif @issslotnum(stmt)
        stmt = stmt::AnySlotNumber
        push!(targetstore, SlotNumber(stmt.id))
        push!(cl.slotsuccs[stmt.id], targetid)
    elseif isa(stmt, Symbol) || isa(stmt, GlobalRef)   # NamedVar
        push!(targetstore, stmt)
        namestore = get(cl.namesuccs, stmt, nothing)
        if namestore === nothing
            cl.namesuccs[stmt] = namestore = Links()
        end
        push!(namestore, targetid)
    elseif isa(stmt, Expr) && stmt.head !== :copyast
        stmt = stmt::Expr
        arng = 1:length(stmt.args)
        if stmt.head === :call
            f = stmt.args[1]
            if !@isssa(f) && !@issslotnum(f)
                # Avoid putting named callees on the namestore
                arng = 2:length(stmt.args)
            end
        end
        for i in arng
            add_links!(target, stmt.args[i], cl)
        end
    elseif is_GotoIfNot(stmt)
        add_links!(target, (stmt::Core.GotoIfNot).cond, cl)
    elseif is_ReturnNode(stmt)
        add_links!(target, (stmt::Core.ReturnNode).val, cl)
    end
    return nothing
end

function Base.push!(l::Links, id)
    if isa(id, SSAValue)
        k = id.id
        k ∉ l.ssas && push!(l.ssas, k)
    elseif isa(id, SlotNumber)
        k = id.id
        k ∉ l.slots && push!(l.slots, k)
    else
        id = id::NamedVar
        id ∉ l.names && push!(l.names, id)
    end
    return id
end

## Phase 2: replacing slot-links with statement-links (and adding name-links to statement-links)

# Now that we know the full set of dependencies, we can safely replace references to names
# by references to the relevant line numbers.

"""
`Variable` holds information about named variables.
Unlike SSAValues, a single Variable can be assigned from multiple code locations.

If `v` is a `Variable`, then
- `v.assigned` is a list of statement numbers on which it is assigned
- `v.preds` is the set of statement numbers upon which this assignment depends
- `v.succs` is the set of statement numbers which make use of this variable

`preds` and `succs` are short for "predecessors" and "successors," respectively.
These are meant in the sense of execution order, not statement number; depending on control-flow,
a variable may have entries in `preds` that are larger than the smallest entry in `assigned`.
"""
struct Variable
    assigned::Vector{Int}
    preds::Vector{Int}
    succs::Vector{Int}
end
Variable() = Variable(Int[], Int[], Int[])

function Base.show(io::IO, v::Variable)
    print(io, "assigned on ", showempty(v.assigned))
    print(io, ", depends on ", showempty(v.preds))
    print(io, ", and used by ", showempty(v.succs))
end

# This will be documented below at the "user-level" constructor.
# preds[i] is the list of predecessors for the `i`th statement in the CodeInfo
# succs[i] is the list of successors for the `i`th statement in the CodeInfo
# byname[name] summarizes this CodeInfo's dependence on Variable `name`.
struct CodeEdges
    preds::Vector{Vector{Int}}
    succs::Vector{Vector{Int}}
    byname::Dict{NamedVar,Variable}
end
CodeEdges(n::Integer) = CodeEdges([Int[] for i = 1:n], [Int[] for i = 1:n], Dict{Union{GlobalRef,Symbol},Variable}())

function Base.show(io::IO, edges::CodeEdges)
    println(io, "CodeEdges:")
    for (name, v) in edges.byname
        print(io, "  ", name, ": ")
        show(io, v)
        println(io)
    end
    n = length(edges.preds)
    nd = ndigits(n)
    for i = 1:n
        println(io, "  statement ", lpad(i, nd), " depends on ", showempty(edges.preds[i]), " and is used by ", showempty(edges.succs[i]))
    end
    return nothing
end

"""
    edges = CodeEdges(src::CodeInfo)

Analyze `src` and determine the chain of dependencies.

- `edges.preds[i]` lists the preceding statements that statement `i` depends on.
- `edges.succs[i]` lists the succeeding statements that depend on statement `i`.
- `edges.byname[v]` returns information about the predecessors, successors, and assignment statements
  for an object `v::$NamedVar`.
"""
function CodeEdges(src::CodeInfo)
    src.inferred && error("supply lowered but not inferred code")
    cl = CodeLinks(src)
    CodeEdges(src, cl)
end

function CodeEdges(src::CodeInfo, cl::CodeLinks)
    # The main task here is to elide the slot-dependencies and convert
    # everything to just ssas & names.

    # Replace/add named intermediates (slot & named-variable references) with statement numbers
    nstmts, nslots = length(src.code), length(src.slotnames)
    marked, slothandled = BitSet(), fill(false, nslots)  # working storage during resolution
    edges = CodeEdges(nstmts)
    emptylink = Links()
    emptylist = Int[]
    for (i, stmt) in enumerate(src.code)
        # Identify line predecents for slots and named variables
        if isexpr(stmt, :(=))
            stmt = stmt::Expr
            lhs = stmt.args[1]
            # Mark predecessors and successors of this line by following ssas & named assignments
            if @issslotnum(lhs)
                lhs = lhs::AnySlotNumber
                # This line assigns a slot. Mark all predecessors.
                id = lhs.id
                linkpreds, linksuccs, listassigns = cl.slotpreds[id], cl.slotsuccs[id], cl.slotassigns[id]
            else
                lhs = lhs::NamedVar
                linkpreds = get(cl.namepreds, lhs, emptylink)
                linksuccs = get(cl.namesuccs, lhs, emptylink)
                listassigns = get(cl.nameassigns, lhs, emptylist)
            end
        else
            linkpreds, linksuccs, listassigns = cl.ssapreds[i], cl.ssasuccs[i], emptylist
        end
        # Assign the predecessors
        # For "named" predecessors, we depend only on their assignments
        empty!(marked)
        fill!(slothandled, false)
        follow_links!(marked, linkpreds, cl.slotpreds, cl.slotassigns, slothandled)
        pushall!(marked, listassigns)
        for key in linkpreds.names
            pushall!(marked, get(cl.nameassigns, key, emptylist))
        end
        delete!(marked, i)
        append!(edges.preds[i], marked)
        # Similarly for successors
        empty!(marked)
        fill!(slothandled, false)
        follow_links!(marked, linksuccs, cl.slotsuccs, cl.slotassigns, slothandled)
        pushall!(marked, listassigns)
        for key in linksuccs.names
            pushall!(marked, get(cl.nameassigns, key, emptylist))
        end
        delete!(marked, i)
        append!(edges.succs[i], marked)
    end
    # Add named variables
    ukeys = namedkeys(cl)
    for key in ukeys
        assigned = get(cl.nameassigns, key, Int[])
        empty!(marked)
        linkpreds = get(cl.namepreds, key, emptylink)
        pushall!(marked, linkpreds.ssas)
        for j in linkpreds.slots
            pushall!(marked, cl.slotassigns[j])
        end
        for key in linkpreds.names
            pushall!(marked, get(cl.nameassigns, key, emptylist))
        end
        preds = append!(Int[], marked)
        empty!(marked)
        linksuccs = get(cl.namesuccs, key, emptylink)
        pushall!(marked, linksuccs.ssas)
        for j in linksuccs.slots
            pushall!(marked, cl.slotassigns[j])
            pushall!(marked, cl.slotsuccs[j].ssas)
        end
        for key in linksuccs.names
            pushall!(marked, get(cl.nameassigns, key, emptylist))
        end
        succs = append!(Int[], marked)
        edges.byname[key] = Variable(assigned, preds, succs)
    end

    return edges
end

# Follow slot links to their non-slot leaves
function follow_links!(marked, l::Links, slotlinks, slotassigns, slothandled)
    pushall!(marked, l.ssas)
    for id in l.slots
        slothandled[id] && continue
        slothandled[id] = true
        pushall!(marked, slotassigns[id])
        follow_links!(marked, slotlinks[id], slotlinks, slotassigns, slothandled)
    end
    return marked
end

"""
    print_with_code(io, src::CodeInfo, edges::CodeEdges)

Interweave display of code and edges.

!!! compat Julia 1.6
    This function produces dummy output if suitable support is missing in your version of Julia.
"""
function print_with_code(io::IO, src::CodeInfo, edges::CodeEdges)
    function preprint(io::IO)
        printstyled(io, "Names:", color=:yellow)
        for (name, var) in edges.byname
            print(io, '\n', name, ": ")
            show(io, var)
        end
        printstyled(io, "\nCode:\n", color=:yellow)
    end
    @static if isdefined(Base.IRShow, :show_ir_stmt)
        preprint(::IO, ::Int) = nothing
    else
        nd = ndigits(length(src.code))
        preprint(io::IO, i::Int) = print(io, lpad(i, nd), "  ")
    end
    postprint(::IO) = nothing
    postprint(io::IO, idx::Int, bbchanged::Bool) = postprint_lineedges(io, idx, edges, bbchanged)

    print_with_code(preprint, postprint, io, src)
end

function postprint_lineedges(io::IO, idx::Int, edges::CodeEdges, bbchanged::Bool)
    printstyled(io, bbchanged ? " " : "│", color=:light_black)
    printstyled(io, "             # ", color=:yellow)
    preds, succs = edges.preds[idx], edges.succs[idx]
    printstyled(io, "preds: ", showempty(preds), ", succs: ", showempty(succs), '\n', color=:yellow)
    return nothing
end

function terminal_preds(i::Int, edges::CodeEdges)
    function terminal_preds!(s, j, edges, covered)
        j ∈ covered && return s
        push!(covered, j)
        preds = edges.preds[j]
        if isempty(preds)
            push!(s, j)
        else
            for p in preds
                terminal_preds!(s, p, edges, covered)
            end
        end
        return s
    end
    s, covered = BitSet(), BitSet()
    push!(covered, i)
    for p in edges.preds[i]
        terminal_preds!(s, p, edges, covered)
    end
    return s
end

"""
    isrequired = lines_required(obj::$NamedVar, src::CodeInfo, edges::CodeEdges)
    isrequired = lines_required(idx::Int,                     src::CodeInfo, edges::CodeEdges)

Determine which lines might need to be executed to evaluate `obj` or the statement indexed by `idx`.
If `isrequired[i]` is `false`, the `i`th statement is *not* required.
In some circumstances all statements marked `true` may be needed, in others control-flow
will end up skipping a subset of such statements, perhaps while repeating others multiple times.

See also [`lines_required!`](@ref) and [`selective_eval!`](@ref).
"""
function lines_required(obj::NamedVar, src::CodeInfo, edges::CodeEdges; kwargs...)
    isrequired = falses(length(edges.preds))
    objs = Set{NamedVar}([obj])
    return lines_required!(isrequired, objs, src, edges; kwargs...)
end

function lines_required(idx::Int, src::CodeInfo, edges::CodeEdges; kwargs...)
    isrequired = falses(length(edges.preds))
    isrequired[idx] = true
    objs = Set{NamedVar}()
    return lines_required!(isrequired, objs, src, edges; kwargs...)
end

"""
    lines_required!(isrequired::AbstractVector{Bool}, src::CodeInfo, edges::CodeEdges;
                    norequire = ())

Like `lines_required`, but where `isrequired[idx]` has already been set to `true` for all statements
that you know you need to evaluate. All other statements should be marked `false` at entry.
On return, the complete set of required statements will be marked `true`.

`norequire` keyword argument specifies statements (represented as iterator of `Int`s) that
should _not_ be marked as a requirement.
For example, use `norequire = LoweredCodeUtils.exclude_named_typedefs(src, edges)` if you're
extracting method signatures and not evaluating new definitions.
"""
function lines_required!(isrequired::AbstractVector{Bool}, src::CodeInfo, edges::CodeEdges; kwargs...)
    objs = Set{NamedVar}()
    return lines_required!(isrequired, objs, src, edges; kwargs...)
end

function exclude_named_typedefs(src::CodeInfo, edges::CodeEdges)
    norequire = BitSet()
    i = 1
    nstmts = length(src.code)
    while i <= nstmts
        stmt = rhs(src.code[i])
        if istypedef(stmt) && !isanonymous_typedef(stmt::Expr)
            r = typedef_range(src, i)
            pushall!(norequire, r)
            i = last(r)+1
        else
            i += 1
        end
    end
    return norequire
end

function lines_required!(isrequired::AbstractVector{Bool}, objs, src::CodeInfo, edges::CodeEdges; norequire = ())
    # Mark any requested objects (their lines of assignment)
    objs = add_requests!(isrequired, objs, edges, norequire)

    # Compute basic blocks, which we'll use to make sure we mark necessary control-flow
    cfg = Core.Compiler.compute_basic_blocks(src.code)  # needed for control-flow analysis

    # We'll mostly use generic graph traversal to discover all the lines we need,
    # but structs are in a bit of a different category (especially on Julia 1.5+).
    # It's easiest to discover these at the beginning.
    typedefs = find_typedefs(src)

    changed = true
    iter = 0
    while changed
        changed = false

        # Handle ssa predecessors
        changed |= add_ssa_preds!(isrequired, src, edges, norequire)

        # Handle named dependencies
        changed |= add_named_dependencies!(isrequired, edges, objs, norequire)

        # Add control-flow
        changed |= add_control_flow!(isrequired, cfg, norequire)

        # So far, everything is generic graph traversal. Now we add some domain-specific information
        changed |= add_typedefs!(isrequired, src, edges, typedefs, norequire)

        iter += 1  # just for diagnostics
    end
    return isrequired
end

function add_requests!(isrequired, objs, edges::CodeEdges, norequire)
    objsnew = Set{NamedVar}()
    for obj in objs
        add_obj!(isrequired, objsnew, obj, edges, norequire)
    end
    return objsnew
end

function add_ssa_preds!(isrequired, src::CodeInfo, edges::CodeEdges, norequire)
    changed = false
    for idx = 1:length(src.code)
        if isrequired[idx]
            changed |= add_preds!(isrequired, idx, edges, norequire)
        end
    end
    return changed
end

function add_named_dependencies!(isrequired, edges::CodeEdges, objs, norequire)
    changed = false
    for (obj, uses) in edges.byname
        obj ∈ objs && continue
        if any(view(isrequired, uses.succs))
            changed |= add_obj!(isrequired, objs, obj, edges, norequire)
        end
    end
    return changed
end

function add_preds!(isrequired, idx, edges::CodeEdges, norequire)
    chngd = false
    preds = edges.preds[idx]
    for p in preds
        isrequired[p] && continue
        p ∈ norequire && continue
        isrequired[p] = true
        chngd = true
        add_preds!(isrequired, p, edges, norequire)
    end
    return chngd
end
function add_succs!(isrequired, idx, edges::CodeEdges, succs, norequire)
    chngd = false
    for p in succs
        isrequired[p] && continue
        p ∈ norequire && continue
        isrequired[p] = true
        chngd = true
        add_succs!(isrequired, p, edges, edges.succs[p], norequire)
    end
    return chngd
end
function add_obj!(isrequired, objs, obj, edges::CodeEdges, norequire)
    chngd = false
    for d in edges.byname[obj].assigned
        d ∈ norequire && continue
        isrequired[d] || add_preds!(isrequired, d, edges, norequire)
        isrequired[d] = true
        chngd = true
    end
    push!(objs, obj)
    return chngd
end

# Add control-flow. For any basic block with an evaluated statement inside it,
# check to see if the block has any successors, and if so mark that block's exit statement.
# Likewise, any preceding blocks should have *their* exit statement marked.
function add_control_flow!(isrequired, cfg, norequire)
    changed = false
    blocks = cfg.blocks
    nblocks = length(blocks)
    for (ibb, bb) in enumerate(blocks)
        r = rng(bb)
        if any(view(isrequired, r))
            if ibb != nblocks
                idxlast = r[end]
                idxlast ∈ norequire && continue
                changed |= !isrequired[idxlast]
                isrequired[idxlast] = true
            end
            for ibbp in bb.preds
                ibbp > 0 || continue # see Core.Compiler.compute_basic_blocks, near comment re :enter
                rpred = rng(blocks[ibbp])
                idxlast = rpred[end]
                idxlast ∈ norequire && continue
                changed |= !isrequired[idxlast]
                isrequired[idxlast] = true
            end
            for ibbs in bb.succs
                ibbs == nblocks && continue
                rpred = rng(blocks[ibbs])
                idxlast = rpred[end]
                idxlast ∈ norequire && continue
                changed |= !isrequired[idxlast]
                isrequired[idxlast] = true
            end
        end
    end
    return changed
end

# Do a traveral of "numbered" predecessors and find statement ranges and names of type definitions
function find_typedefs(src::CodeInfo)
    typedef_blocks, typedef_names = UnitRange{Int}[], Symbol[]
    i = 1
    nstmts = length(src.code)
    while i <= nstmts
        stmt = rhs(src.code[i])
        if istypedef(stmt) && !isanonymous_typedef(stmt::Expr)
            stmt = stmt::Expr
            r = typedef_range(src, i)
            push!(typedef_blocks, r)
            name = stmt.head === :call ? stmt.args[3] : stmt.args[1]
            if isa(name, QuoteNode)
                name = name.value
            end
            isa(name, Symbol) || @show src i r stmt
            push!(typedef_names, name::Symbol)
            i = last(r)+1
        else
            i += 1
        end
    end
    return typedef_blocks, typedef_names
end

# New struct definitions, including their constructors, get spread out over many
# statements. If we're evaluating any of them, it's important to evaluate *all* of them.
function add_typedefs!(isrequired, src::CodeInfo, edges::CodeEdges, (typedef_blocks, typedef_names), norequire)
    changed = false
    stmts = src.code
    idx = 1
    while idx < length(stmts)
        stmt = stmts[idx]
        isrequired[idx] || (idx += 1; continue)
        for (typedefr, typedefn) in zip(typedef_blocks, typedef_names)
            if idx ∈ typedefr
                ireq = view(isrequired, typedefr)
                if !all(ireq)
                    changed = true
                    ireq .= true
                    # Also mark any by-type constructor(s) associated with this typedef
                    var = get(edges.byname, typedefn, nothing)
                    if var !== nothing
                        for s in var.succs
                            s ∈ norequire && continue
                            stmt2 = stmts[s]
                            if isexpr(stmt2, :method) && (fname = (stmt2::Expr).args[1]; fname === false || fname === nothing)
                                isrequired[s] = true
                            end
                        end
                    end
                end
                idx = last(typedefr) + 1
                continue
            end
        end
        # Anonymous functions may not yet include the method definition
        if isanonymous_typedef(stmt)
            i = idx + 1
            while i <= length(stmts) && !ismethod3(stmts[i])
                i += 1
            end
            if i <= length(stmts) && (stmts[i]::Expr).args[1] == false
                tpreds = terminal_preds(i, edges)
                if minimum(tpreds) == idx && i ∉ norequire
                    changed |= !isrequired[i]
                    isrequired[i] = true
                end
            end
        end
        idx += 1
    end
    return changed
end

"""
    selective_eval!([recurse], frame::Frame, isrequired::AbstractVector{Bool}, istoplevel=false)

Execute the code in `frame` in the manner of `JuliaInterpreter.finish_and_return!`,
but skipping all statements that are marked `false` in `isrequired`.
See [`lines_required`](@ref). Upon entry, if needed the caller must ensure that `frame.pc` is
set to the correct statement, typically `findfirst(isrequired)`.
See [`selective_eval_fromstart!`](@ref) to have that performed automatically.

The default value for `recurse` is `JuliaInterpreter.finish_and_return!`.
`isrequired` pertains only to `frame` itself, not any of its callees.

This will return either a `BreakpointRef`, the value obtained from the last executed statement
(if stored to `frame.framedata.ssavlues`), or `nothing`.
Typically, assignment to a variable binding does not result in an ssa store by JuliaInterpreter.
"""
function selective_eval!(@nospecialize(recurse), frame::Frame, isrequired::AbstractVector{Bool}, istoplevel::Bool=false)
    pc = pcexec = pclast = frame.pc
    while isa(pc, Int)
        frame.pc = pc
        te = isrequired[pc]
        pclast = pcexec::Int
        if te
            pcexec = pc = step_expr!(recurse, frame, istoplevel)
        else
            pc = next_or_nothing!(frame)
        end
    end
    isa(pc, BreakpointRef) && return pc
    pcexec = (pcexec === nothing ? pclast : pcexec)::Int
    frame.pc = pcexec
    node = pc_expr(frame)
    is_return(node) && return lookup_return(frame, node)
    isassigned(frame.framedata.ssavalues, pcexec) && return frame.framedata.ssavalues[pcexec]
    return nothing
end
function selective_eval!(frame::Frame, isrequired::AbstractVector{Bool}, istoplevel::Bool=false)
    selective_eval!(finish_and_return!, frame, isrequired, istoplevel)
end

"""
    selective_eval_fromstart!([recurse], frame, isrequired, istoplevel=false)

Like [`selective_eval!`](@ref), except it sets `frame.pc` to the first `true` statement in `isrequired`.
"""
function selective_eval_fromstart!(@nospecialize(recurse), frame, isrequired, istoplevel::Bool=false)
    pc = findfirst(isrequired)
    pc === nothing && return nothing
    frame.pc = pc
    return selective_eval!(recurse, frame, isrequired, istoplevel)
end
function selective_eval_fromstart!(frame::Frame, isrequired::AbstractVector{Bool}, istoplevel::Bool=false)
    selective_eval_fromstart!(finish_and_return!, frame, isrequired, istoplevel)
end

"""
    print_with_code(io, src::CodeInfo, isrequired::AbstractVector{Bool})

Mark each line of code with its requirement status.

!!! compat Julia 1.6
    This function produces dummy output if suitable support is missing in your version of Julia.
"""
function print_with_code(io::IO, src::CodeInfo, isrequired::AbstractVector{Bool})
    nd = ndigits(length(isrequired))
    preprint(::IO) = nothing
    preprint(io::IO, idx::Int) = (c = isrequired[idx]; printstyled(io, lpad(idx, nd), ' ', c ? "t " : "f "; color = c ? :cyan : :plain))
    postprint(::IO) = nothing
    postprint(io::IO, idx::Int, bbchanged::Bool) = nothing

    print_with_code(preprint, postprint, io, src)
end

function print_with_code(io::IO, frame::Frame, obj)
    src = frame.framecode.src
    if isdefined(JuliaInterpreter, :reverse_lookup_globalref!)
        src = copy(src)
        JuliaInterpreter.reverse_lookup_globalref!(src.code)
    end
    print_with_code(io, src, obj)
end


text:
using LinearAlgebra

struct ISTA
    ∇f
    prox
    η::Real
    iterations::Integer

    absTol::Real
end

function ISTA(∇f; iterations=nothing, prox=(t,λ)->t, η::Real=1.0, absTol=1e2*eps())
    ISTA(∇f, prox, η, iterations, absTol)
end

# iterative shrinkage/thresholding algorithm
# solve a regularized convex optimization problem e.x. f(x) + g(x)
# ∇loss : gradient of loss function f(x)
# prox  : proximity function of g(x)
# x0    : initial value
# η     : step size of update

function (ista::ISTA)(x0; iterations=ista.iterations, verboseFunction::Function=(args...)->nothing)
    xₖ = x0
    errx = Inf
    len = length(x0)
    for k = 1:ista.iterations
        xₖ₋₁ = xₖ
        xₖ = ista.prox(xₖ - ista.η*ista.∇f(xₖ), ista.η)

        errx = norm(xₖ - xₖ₋₁)^2 / 2

        verboseFunction(k, xₖ, errx)

        if errx <= ista.absTol
            break
        end
    end
    (xₖ, ())
end

struct FISTA
    ∇f
    prox
    η::Real
    iterations::Integer

    absTol::Real
end

function FISTA(∇f; iterations=nothing, prox=(t,λ)->t, η::Real=1.0, absTol=1e2*eps())
    FISTA(∇f, prox, η, iterations, absTol)
end

function (fista::FISTA)(x0; iterations=fista.iterations, verboseFunction::Function=(itrs,tx,err)->nothing)
    xₖ = x0
    errx = Inf
    len = length(x0)
    y = x0
    tₖ = 1
    for k = 1:fista.iterations
        xₖ₋₁, tₖ₋₁ = xₖ, tₖ

        xₖ = fista.prox(y - fista.η*fista.∇f(y), fista.η)
        tₖ = (1 + sqrt(1+4*tₖ^2)) / 2
        t̂ = (tₖ₋₁ - 1) / tₖ
        y = xₖ + t̂*(xₖ - xₖ₋₁)

        errx = norm(xₖ - xₖ₋₁)^2 / 2

        verboseFunction(k, xₖ, errx)

        if errx <= fista.absTol
            break
        end
    end
    (xₖ, ())
end

max_stars_repo_name: nixir/MDCDL

max_issues_repo_name: nixir/MDCDL

max_forks_repo_name: nixir/MDCDL


text:
using MathOptInterface
using JuMP

const MOI = MathOptInterface
const MOIU = MathOptInterface.Utilities

"""
WIP

- is MOI.VariableIndex necessary ?: we should maybe use VariableIndex in our code to allow
easier use of it in the MathOptInterface (https://www.juliaopt.org/MathOptInterface.jl/dev/apireference/#Index-types-1)
Should create a new type of Variables here or change IntVar's implementation. Not sure atm.
- not sure if it is compulsory to return a constraint while coding add_constrained_variable

"""

include("types.jl")
include("optimizer_accessors.jl")
include("sets.jl")
include("supports.jl")
include("variables.jl")
include("constraints.jl")
include("objective.jl")
include("utilities.jl")
include("homemade_bridging.jl")

"""
    MOI.optimize!(model::Optimizer)

Launch the solving process of the solver.
"""
function MOI.optimize!(model::Optimizer)
    fill_cpmodel!(model)

    status = SeaPearl.solve!(model.cpmodel; variableHeuristic=model.variableselection, valueSelection=model.valueselection)

    if status == :Optimal
        model.terminationStatus = MOI.OPTIMAL
    elseif status == :Infeasible
        model.terminationStatus = MOI.INFEASIBLE
    elseif status == :NodeLimitStop
        model.terminationStatus = MOI.NODE_LIMIT
    elseif status == :SolutionLimitStop
        model.terminationStatus = MOI.SOLUTION_LIMIT
    else
        model.terminationStatus == MOI.OTHER_ERROR
    end

    model.primalStatus = !isempty(model.cpmodel.statistics.solutions) ? MOI.FEASIBLE_POINT : MOI.NO_SOLUTION

    # println(model.cpmodel.constraints)

    solution = nothing
    if !isempty(model.cpmodel.statistics.solutions)
        solution = last(model.cpmodel.statistics.solutions)
    end
    # println(model.cpmodel.statistics.solutions)
    return status, solution
end


text:
overlap(ts::Vararg{Vector, 1}) = (Base.OneTo(length(ts[1])),)

function overlap(ts::Vararg{Vector, N}) where {N}
    ret = ntuple(_ -> Int[], N)
    t1 = ts[1]

    for tidx in 2:N
        i = j = 1
        resize!(ret[1], 0)
        t2 = ts[tidx]
        while i <= length(t1) && j <= length(t2)
            if t1[i] > t2[j]
                j += 1
            elseif t1[i] < t2[j]
                i += 1
            else
                push!(ret[1], i)
                push!(ret[tidx], j)
                i += 1
                j += 1
            end
        end
    end
    ret
end

"""
    sorted_unique_merge(a, b) -> (c, idx_a, idx_b)

Merge two arrays of sorted unique elements a and b to new array c,
and calculate the indexes idx_a and idx_b mapping each element in a and b to their new locations in c.
"""
function sorted_unique_merge(::Type{IndexType}, a::Vector, b::Vector) where {IndexType}
    i, na, j, nb = 1, length(a), 1, length(b)
    c = similar(a, length(a) + length(b))
    idx_a = Vector{IndexType}(undef, length(a))
    idx_b = Vector{IndexType}(undef, length(b))
    k = 1
    @inbounds while (i <= na) && (j <= nb)
        if a[i] < b[j]
            c[k] = a[i]
            idx_a[i] = k
            i += 1
        elseif a[i] > b[j]
            c[k] = b[j]
            idx_b[j] = k
            j += 1
        else
            c[k] = a[i]
            idx_a[i] = k
            idx_b[j] = k
            i += 1
            j += 1
        end
        k += 1
    end
    @inbounds while i <= na
        c[k] = a[i]
        idx_a[i] = k
        i += 1
        k += 1
    end
    @inbounds while j <= nb
        c[k] = b[j]
        idx_b[j] = k
        j += 1
        k += 1
    end
    resize!(c, k - 1)
    return c, idx_a, idx_b
end

"""
    insertbyidx!(dst, src, dstidx, coloffset = 0)

For each column in src, insert elements from src[i, column] to dst[dstidx[i], column + coloffset].
"""
function insertbyidx!(dst::AbstractArray, src::AbstractArray, dstidx::Vector, coloffset::Int = 0)
    for c in 1:size(src, 2)
        cc = c + coloffset
        for i in 1:length(dstidx)
            @inbounds dst[dstidx[i], cc] = src[i, c]
        end
    end
    nothing
end

"""
    insertbyidx!(dst, src, dstidx, srcidx)

For each column in src, insert elements from src[srcidx[i], column] to dst[dstidx[i], column].
"""
function insertbyidx!(dst::AbstractArray, src::AbstractArray, dstidx::Vector, srcidx::Vector)
    for c in 1:size(src, 2)
        for i in 1:length(srcidx)
            @inbounds dst[dstidx[i], c] = src[srcidx[i], c]
        end
    end
    nothing
end

@inline function allequal(x)
    length(x) < 2 && return true
    e1 = x[1]

    @inbounds for i ∈ 2:length(x)
        x[i] == e1 || return false
    end

    true
end

# helper method for inner constructor
@inline function _issorted_and_unique(x)
    for i in 1:length(x)-1
        @inbounds !(x[i] < x[i + 1]) && return false
    end
    true
end

# helper method for inner constructor
function replace_dupes!(cnames::Vector{Symbol})
    n = 1
    while !allunique(cnames)
        ds = find_dupes_index(cnames)
        for d in ds
            if n == 1
                cnames[d] = Symbol(cnames[d], "_$n")
            else
                s = string(cnames[d])
                cnames[d] = Symbol(s[1:length(s)-length(string(n))-1], "_$n")
            end
        end
        n += 1
    end
    cnames
end

# helper method for inner constructor
find_dupes_index(A::Vector{Symbol}) =
    @inbounds [i for i in eachindex(A) if A[i] ∈ A[1:i-1]]

gen_colnames(n::Integer) = gen_colnames(Val{n}())

@generated function gen_colnames(v::Val{N}) where {N}
    ret = Vector{Symbol}(undef, N)

    s = ""
    for i ∈ 1:N
        s = carry_char(s)
        ret[i] = Symbol(s)
    end

    ret
end

const carry_char_cache = Dict{String,String}("" => "A")

function carry_char(s::String = "")
    ret = get(carry_char_cache, s, "")
    (ret != "") && return ret

    n = length(s)

    c = s[n] + 1

    ret = if c > 'Z'
        c = 'A'
        carry_char(s[1:n-1]) * c
    else
        s[1:n-1] * c
    end

    carry_char_cache[s] = ret
end

# helper method for `getindex`
"""
Return the first index of the given column names.
Raise `KeyError` if col name not found.
"""
findcol(ta::AbstractTimeSeries, s::Symbol) = findcol(colnames(ta), s)

@inline function findcol(cols::Vector{Symbol}, s::Symbol)
    i = findfirst(isequal(s), cols)
    (i === nothing) && throw(KeyError(s))
    i
end

"""
Unicode friendly rpad
"""
function _rpad(s::AbstractString, n::Integer)
  x = n - textwidth(s)
  (x ≤ 0) && return s
  s * (" "^x)
end

_rpad(s::Symbol, n::Integer) = _rpad(string(s), n::Integer)


text:
using Test
import Geometry

@testset "volume" begin

    solids = [
        (Geometry.Cylinder(1, 2), pi),
        (Geometry.Cone(1, [2]), 1.04720),
        (Geometry.Cube(4), 64.0),
        (Geometry.RectangularPrism(3, 5, 7), 105.0)
    ]

    for i in solids
        @test round(Geometry.volume(i[1]), digits=5) === round(i[2], digits=5)
    end

    # @test_throws MethodError foo(x, y)
end

@testset "lateralarea" begin

    solids = [
        (Geometry.Cylinder(1, 2), 6.28319),
        (Geometry.Cone(1, [2]), 4.44288),
        (Geometry.Cube(4), 64.0),
        (Geometry.RectangularPrism(3, 5, 7), 72)
    ]

    for i in solids
        @test round(Geometry.lateralarea(i[1]), digits=5) === round(i[2], digits=5)
    end

    # @test_throws MethodError foo(x, y)
end

@testset "surfacearea" begin

    solids = [
        (Geometry.Cylinder(1, 2), 12.56637),
        (Geometry.Cone(1, [2]), 7.58448),
        (Geometry.Cube(4), 6*4^2),
        (Geometry.RectangularPrism(3, 5, 7), 142.0)
    ]

    for i in solids
        @test round(Geometry.surfacearea(i[1]), digits=5) === round(i[2], digits=5)
    end

    # @test_throws MethodError foo(x, y)
end

# @testset "methods" begin
#     ms = [x.sig for x in Geometry.methods(Geometry.volume)]
#     for i in ms
#         println(i.parameters[2])
#     end
# end

# @testset "bar" begin
#     z = 4.
#     @test bar(z) == 1.
# end


text:
include("../src/components/damages_component.jl")

@testset "damages" begin

    Precision = 1.0e-11
    T = length(MimiDICE2010.model_years)
    f = readxlsx(joinpath(@__DIR__, "..", "data", "DICE2010_082710d.xlsx"))

    m = Model()

    set_dimension!(m, :time, MimiDICE2010.model_years)

    add_comp!(m, damages, :damages)

# Set the parameters that would normally be internal connection from their Excel values
    set_param!(m, :damages, :TATM, read_params(f, "B121:BI121", T))
    set_param!(m, :damages, :YGROSS, read_params(f, "B92:BI92", T))
    set_param!(m, :damages, :TotSLR, read_params(f, "B182:BI182", T))

# Load the rest of the external parameters
    p = dice2010_excel_parameters(joinpath(@__DIR__, "..", "data", "DICE2010_082710d.xlsx"))
    set_param!(m, :damages, :a1, p[:a1])
    set_param!(m, :damages, :a2, p[:a2])
    set_param!(m, :damages, :a3, p[:a3])
    set_param!(m, :damages, :b1, p[:b1])
    set_param!(m, :damages, :b2, p[:b2])
    set_param!(m, :damages, :b3, p[:b3])

# Run the one-component model
    run(m)

# Extract the generated variables
    DAMFRAC = m[:damages, :DAMFRAC]

# Extract the true values
    True_DAMFRAC    = read_params(f, "B93:BI93", T)

# Test that the values are the same
    @test maximum(abs, DAMFRAC .- True_DAMFRAC) ≈ 0. atol = Precision

end


text:
#Stress test for f1 acceleration
using InspectDR
using Colors

#==Input
===============================================================================#
#Constants
#-------------------------------------------------------------------------------
black = RGB24(0, 0, 0)
white = RGB24(1, 1, 1)
red = RGB24(1, 0, 0)
green = RGB24(0, 1, 0)
blue = RGB24(0, 0, 1)

#Input data
#-------------------------------------------------------------------------------
srand(33)
y = rand(100000)
x = collect(1:length(y))

#==Generate plot
===============================================================================#
plot = InspectDR.Plot2D(title="Random Data Stressor")
strip = plot.strips[1]
plot.xres = 30 #coarse resolution
#Δ = 1.323443/length(y)
#plot.xext_full = InspectDR.PExtents1D(Δ, x[end]-2*Δ)
plot.xext_full = InspectDR.PExtents1D(10, 2100)
#plot.layout.grid = grid(vmajor=true, vminor=true, hmajor=true)

style = :dashdot #solid/dashdot/...
wfrm = add(plot, x, y, id="rand")
#	wfrm.line = line(style=:none)
	wfrm.line = line(style=:solid, color=blue)
#	wfrm.glyph = glyph(shape=:o, size=10, color=blue)

a = plot.annotation
a.xlabel = "Time (s)"
a.ylabels = ["Signal Voltage (V)"]

gplot = display(InspectDR.GtkDisplay(), plot)

:Test_Complete