using BenchmarkTools
using ConvexBodyProximityQueries
using CurveProximityQueries
using Plots
using StaticArrays
import Random: seed!

pgfplots()

function randomtraj(num)
    Bs = []
    xax = collect(0.0:0.2:1.0)'
    i1 = @SVector [-0.2, 0.5]
    i2 = @SVector [ 0.0, 0.5]
    e1 = @SVector [ 1.0, 0.5]
    e2 = @SVector [ 1.2, 0.5]
    for i = 1:num
        m1 = @SVector rand(2)
        m2 = @SVector rand(2)
        b = Bernstein(i1, i2, m1, m2, e1, e2)
        push!(Bs, b)
    end
    return Bs
end

import CurveProximityQueries:tolerance_verification
function tolerance_verification(obs::Array, traj::Curve, Δ::Real)
    ret = true
    for o in obs
        ret = ret && tolerance_verification(o, traj, Δ)
    end
    return ret
end

import CurveProximityQueries:collision_detection
function collision_detection(obs::Array, traj::Curve)
    ret = false
    for o in obs
        ret = ret || collision_detection(o, traj)
    end
    return ret
end

function counttv(obs, trajs)
    cnt = 0.0
    for t in trajs
        cnt += tolerance_verification(obs, t, 0.03)
    end
    return cnt
end

seed!(22)
obs = [randpoly([0.35, 0.6]; n=20, scale=0.2),
       randpoly([0.65, 0.4]; n=20, scale=0.2)]
trajs = randomtraj(1000)

#  @btime counttv($obs, $trajs)

plot()
plot!.(obs,
       fillalpha=1.0,
       fillcolor=Gray(0.7),
      )
cnt = zeros(3)
for t in trajs
    if tolerance_verification(obs, t, 0.03)
        cnt[1] += 1
        plot!(t,
              linecolor = RGBA(77/255,141/225,205/255,1.0),
              linewidth = 1.2)
    elseif !collision_detection(obs, t)
        cnt[2] += 1
        plot!(t,
              linecolor = RGBA(231/255,95/225,97/255,0.3),
              linewidth = 1.2)
    else
        cnt[3] += 1
        plot!(t,
              linecolor = GrayA(0.5, 0.05),
              linewidth = 0.5)
    end
end
plot!(xlim=(-0.3, 1.3), ylim=(0.0, 1.0))
savefig("out/fig12.pdf")


### A Pluto.jl notebook ###
# v0.17.1

using Markdown
using InteractiveUtils

# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error).
macro bind(def, element)
    quote
        local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end
        local el = $(esc(element))
        global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el)
        el
    end
end

# ╔═╡ c29521d1-6563-4c9f-9d06-656eb8b98a6f
begin
	using PlutoUI # user-interface do Pluto.jl
	using Plots   # Julia package para gráficos

end

# ╔═╡ c0e4d750-b9a4-11eb-2e0c-edaeaaf3f36a
html"<button onclick='present()'>present</button>"

# ╔═╡ 606ac8d7-7cd6-4da3-b83f-9889f6883190
md"""
# Máquina síncrona trifásica
Máquina síncrona sobre rede de potência infinita, (**pólos lisos**)
## Exercício sobre curvas "V" (curvas de Mordey)
"""

# ╔═╡ 4c9ce872-1164-4c7f-9a26-3af89b345c41
md"""
É dado um alternador síncrono sobre rede de potência infinita $$(U_f=200\mathrm V, f=50\mathrm Hz)$$ com $$X_s=4\Omega$$ e $$R_s\thickapprox 0\Omega$$.
"""

# ╔═╡ 9b3e08e0-7207-4099-96e4-c6e1e9892a1f
md"""
## a) Análise vectorial 💻

**Traçar as rectas de potência activa e reactiva correspondentes a:**

$$0;\quad 5;\quad 10;\quad 15;\quad 20;\quad \mathrm {kW, kVAr}$$

"""

# ╔═╡ 159419d5-0555-43a0-8320-9cb51e0b05ba
md"""
Conforme se verificou anteriormente, no traçado do diagrama P-Q para um alternador síncrono (Exercício 2), no diagrama vectorial de tensões, o vector da queda de tensão na reactância síncrona, $$jX_s\overline I$$, pode ser transformado no vector de potência aparente, $$\overline S= P+ jQ$$, se multiplicarmos por um factor de escala constante: $$\frac{3U}{X_s}$$.

Desta forma, a posição dos afixos dos vectores, $$jX_s\overline I$$ ou $$\overline{E}_0$$, representam, adequando a escala para potências, o ponto de funcionamento da máquina, $$(Q, P)$$, num sistemas de eixos de potência activa e reactiva representados a partir do afixo do vector da tensão, $$\overline U$$:
"""

# ╔═╡ df708c4d-443b-4190-b72d-779c4e1e1bb1
begin
	H1=("P", @bind P PlutoUI.Slider(0:5.0e3:20e3, default=0,show_value=true))
	H2=("Q", @bind Q PlutoUI.Slider(-20e3:5.0e3:20e3, default=0, show_value=true))
	H4=("linhas de Q constante", @bind z2 CheckBox())
	H3=("linhas de P constante", @bind z1 CheckBox())
	H1, H2, H4, H3
end

# ╔═╡ 66de4e49-ede7-44d1-b7b4-49ecb3ec2e53

# ╔═╡ 3d8c7f7e-e765-41d9-8191-aef5e52984fc
md"""
## b) Curvas "V"  💻

**Traçar as curvas em V das potências requeridas.**
"""

# ╔═╡ db0fc7c2-9e8c-415f-95c1-686dbfc56347
md"""
O traçado das curvas em "V", ou curvas de Mordey, corresponde a uma representação do mapa de funcionamento da máquina síncrona, traduzido num conjunto de isolinhas para a potência activa, que relacionam diferentes pares de valores $$(I_{exc}, I)$$ ou $$(E_0, I)$$ representando diferentes factores de potência.

Assim, partindo do diagrama vectorial de tensões, para os pontos de funcionamento $$(Q, P)$$ sobre a mesma linha de potência activa, são registados consecutivamente os pares de valores relativos aos módulos dos vectores da fem e da corrente do estator, $$E_0$$ e $$I$$.

Repare-se que para $$P=0\mathrm W$$, $$(I\cos\varphi=0)$$, verifica-se que os vectores de tensão: $$\overline U, jX_s\overline I$$ e $$\overline E_0$$ são colineares (estão em fase), por conseguinte:
"""

# ╔═╡ 6a1ee842-a2f1-4810-83d7-5ce931c47891
md"""
Como alternador, de: $$\quad\overline{E}_0=\overline{U}+jX_s\overline{I}\quad$$ tém-se,

$$E_0=U+X_sI \quad\mathrm{se} \quad\varphi = -90° \Rightarrow E_0>U$$

$$E_0=U-X_sI \quad\mathrm{se} \quad\varphi = +90° \Rightarrow U>E_0$$

o que resulta nas duas rectas representadas no gráfico em $$P=0\mathrm W$$, representadas pelas equações:

$$I=\frac{1}{X_s}E_0-\frac{1}{X_s}U \quad\mathrm{para} \quad\varphi = -90°$$

$$I=-\frac{1}{X_s}E_0+\frac{1}{X_s}U \quad\mathrm{para} \quad\varphi = +90°$$

"""

# ╔═╡ 19822397-18c5-4a88-bac1-f3adbfd2b235
#begin
#	p2 = contour(c_cosφ)
#	plot(p2)
#end

# ╔═╡ 594360d4-9bb8-4756-8f40-a5f0f9555aba
md"""
Assinale-se também para $$Q=0\mathrm {VAr}$$, $$(I\sin\varphi=0)$$, que a corrente do estator terá o valor mais baixo em cada isolinha de potência activa. Esses pontos de funcionamento são designados por **pontos de excitação óptima**.
"""

# ╔═╡ 1b4d9fbd-be46-416a-a1fe-163f5a0b37a3
md"""
!!! nota
	O estudante deverá procurar perceber onde se encontram os modos sobreexcitado e subexcitado, nos regimes de funcionamento alternador e motor, bem como os casos particulares da máquina a funcionar em vazio como compensador síncrono.
"""

# ╔═╡ 5db1fd70-0bf9-462b-b6d3-bfc3ed8890cb

# ╔═╡ 89222965-d320-4a46-a11a-b66b2ed9c11d
md"""
# Setup
"""

# ╔═╡ 750b6ab7-0b11-4b91-be34-ab7426625204
md"""
## Notação polar $$\angle$$. $$\quad$$ Operador $$j$$ $$\quad$$
"""

# ╔═╡ 026c8f3e-8ecd-459f-b496-511c38065cc6
begin
	∠(x) = cis(deg2rad(x))
	j(x) = (x)*im
end;

# ╔═╡ fb03a3aa-f94b-4b73-a21b-f05bc548dd9d
begin
	Xₛ=4
	U=200.0
	U_=(U)∠(0)
	Icosφ=P/(3U)
	Isenφ=-Q/(3U)
	I_=(Icosφ)+j(Isenφ)
	S_=P+j(Q)
	E₀_=U_+j(Xₛ)*I_
	S_, I_, E₀_
end

# ╔═╡ 41eac123-fa10-42c3-a801-8fb5f7bce7ae
begin
# eixos: kW, kVAr
	plot([0+j(0), 400+j(0)],
		label="eixo de potência reactiva (VAr)", arrow=:head,
		linecolor=:black, linewidth=2)
	plot!([200-j(200), 200+j(200)],
		label="eixo de potência activa (W)", arrow=:head,
		linestyle=:dash, linecolor=:black, linewidth=2)

# diagrama vectorial de tensões
	K=3 # para tornar a corrente visível na escala de tensões
	plot!([0, U_], arrow=:closed,
		legend=:bottomright, label="U∠0°", linewidth=2, linecolor=:blue)
	plot!([0, K*I_], arrow=:closed,
		label="I∠φ", linewidth=2, linecolor=:red)
	plot!([U_, U_+j(Xₛ)*I_], arrow=:closed,
		label="XₛI∠(φ+90°)", linewidth=2, linecolor=:purple)
	plot!([0, E₀_], arrow=:closed,
		minorticks=5, label="E₀∠δ", linewidth=2,
		ylims=(-200,200), xlims=(0,400),size=(600,600) )

# lugar geométrico de Q constante
	φ_locus=-90:1:90
	φ_locus=deg2rad.(φ_locus)
	I=abs(I_)
	φ=atan(-Q/(P+0.001))
	Isinφ_Qlocus_=K*I*cos.(φ_locus).+j(K*I*sin(φ))
	plot!(z2*Isinφ_Qlocus_,
		linestyle=:dash, linecolor=:blue, label="linha Isinφ constante")
	δ_locus=0:1:90
	δ_locus=deg2rad.(δ_locus)
	E₀=abs(E₀_)
	δ=angle(E₀_)
	E₀Q_locus_=E₀*cos(δ).+j.(E₀*sin.(δ_locus))
	plot!(z2*E₀Q_locus_,
		linestyle=:dashdot, linecolor=:blue, label="linha de E₀cosδ constante")

# lugar geométrico de P constante
	Isinφ_Plocus_=K*I*cos(φ).+j(K*I*sin.(φ_locus))
	plot!(z1*Isinφ_Plocus_,
		linestyle=:dash, label="linha de Icosφ constante", linecolor=:red)
	E₀P_locus_=E₀.*cos.(δ_locus).+j(E₀*sin(δ))
	plot!(z1*E₀P_locus_,
		linestyle=:dashdot, linecolor=:red, label="linha de E₀sinδ constante")
end

# ╔═╡ d2ed65c3-24e3-42ee-ac6e-f743ef4b584d
begin
	#import GR
	Pᵥ=[0, 5, 10, 15, 20]
	Qᵥ=[-20, -15, -10, -5, 0, 5, 10, 15, 20]
	#Iᵥcosφ, Iᵥsinφ
	Iᵥcosφ=Pᵥ.*1e3./(3U)
	Iᵥsinφ=transpose(Qᵥ.*1e3./(3U))

	#Inicialização de matrizes:
	Iᵥ_=zeros(ComplexF64, 5, 9)
	E₀₁_=zeros(ComplexF64, 5, 9)
	Iᵥ=zeros(5,9)
	φᵥ=zeros(5,9)
	P₁=zeros(5,9)
	c_cosφ=zeros(5,9)
	E₀₁=zeros(5,9)
	#δᵥ=zeros(5,9)
	for l in 1:5
		for c in 1:9
			Iᵥ_[l,c]=Iᵥcosφ[l,1]+j(Iᵥsinφ[1,c])
			Iᵥ[l,c]=abs(Iᵥ_[l,c])
			φᵥ[l,c]=angle(Iᵥ_[l,c])
			P₁[l,c]=3*U*Iᵥ[l,c]*cos(φᵥ[l,c])
			#c_cosφ[l,c]=cos(φᵥ[l,c])
			E₀₁_[l,c]=(U)∠(0)+j(Xₛ*Iᵥ_[l,c])
			E₀₁[l,c]=abs(E₀₁_[l,c])
			#δᵥ[l,c]=angle(E₀₁_[l,c])
			#δᵥ[l,c]=rad2deg(δᵥ[l,c])
		end
	end
	plot(E₀₁[1,:],Iᵥ[1,:],
		legend=:bottomright, label="P=0kW", linewidth=2,
		xlabel = "E₀(V)", ylabel="I(A)",)
	plot!(E₀₁[2,:],Iᵥ[2,:], label="P=5kW", linewidth=2)
	plot!(E₀₁[3,:],Iᵥ[3,:], label="P=10kW", linewidth=2)
	plot!(E₀₁[4,:],Iᵥ[4,:], label="P=15kW", linewidth=2)
	plot!(E₀₁[5,:],Iᵥ[5,:], label="P=20kW", linewidth=2)
	plot!([E₀], [I], markershape=:circle,markersize=7, label="Ponto (P, Q)")
end

# ╔═╡ f559622d-8bb3-4068-a4a8-b4f561960da1
md"""
## Índice
"""

# ╔═╡ e4374691-885a-487e-bee5-dac9092dd567
TableOfContents(title="📚 Índice, Exercício sobre curvas V")

# ╔═╡ 995e0deb-8044-4cd8-b802-0bda0ce093e3
md"""
!!! info
	No índice deste *notebook*, os tópicos assinalados com "💻" permitem interacção com o utilizador.
"""

# ╔═╡ 773eb541-f02a-4d61-8d20-9c79a49f6d85
md"""
## _Julia packages_
*Links to package help*: [Plots](http://docs.juliaplots.org/latest/), [PlutoUI](https://juliahub.com/docs/PlutoUI/abXFp/0.7.6/)
"""

# ╔═╡ acb69a29-d406-4f43-ab59-37c4516a460a
md"""
!!! info
	## Programação _Julia_ e _notebooks Pluto_
	Saber mais sobre: [_Julia_/_Pluto_](https://github.com/Ricardo-Luis/notebooks/blob/main/ME2/README.md)
"""

# ╔═╡ c5058f6d-d489-4308-b010-472ae048a6a7
version=VERSION;

# ╔═╡ 50da3fc1-b450-4c56-b179-1e6c36af7265
md"""
## _Notebook_

*Notebook* realizado em linguagem de programação *Julia* versão $(version) para a unidade curricular de Máquinas Elétricas 2 (ISEL\LEE).

Tempo de cálculo do *notebook* (1ª execução): até cerca de 5 min.

**Ricardo Luís** (Professor Adjunto, ISEL\DEEEA\GDME) \
ISEL, 29/Nov/2021
"""

# ╔═╡ da4138d9-2723-4274-8bd1-a0c9a89c1163
md"""
Este conteúdo possui licença [![](https://img.shields.io/badge/License-CC%20BY--SA%204.0-lightgrey.svg)](http://creativecommons.org/licenses/by-sa/4.0/).
"""

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8"

[compat]
Plots = "~1.24.2"
PlutoUI = "~0.7.20"
"""

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

[[AbstractPlutoDingetjes]]
deps = ["Pkg"]
git-tree-sha1 = "0bc60e3006ad95b4bb7497698dd7c6d649b9bc06"
uuid = "6e696c72-6542-2067-7265-42206c756150"
version = "1.1.1"

[[Adapt]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "84918055d15b3114ede17ac6a7182f68870c16f7"
uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e"
version = "3.3.1"

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

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

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

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

[[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 = "f2202b55d816427cd385a9a4f3ffb226bee80f99"
uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a"
version = "1.16.1+0"

[[ChainRulesCore]]
deps = ["Compat", "LinearAlgebra", "SparseArrays"]
git-tree-sha1 = "f885e7e7c124f8c92650d61b9477b9ac2ee607dd"
uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
version = "1.11.1"

[[ChangesOfVariables]]
deps = ["LinearAlgebra", "Test"]
git-tree-sha1 = "9a1d594397670492219635b35a3d830b04730d62"
uuid = "9e997f8a-9a97-42d5-a9f1-ce6bfc15e2c0"
version = "0.1.1"

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

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

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

[[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 = "dce3e3fea680869eaa0b774b2e8343e9ff442313"
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
version = "3.40.0"

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

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

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

[[DataStructures]]
deps = ["Compat", "InteractiveUtils", "OrderedCollections"]
git-tree-sha1 = "7d9d316f04214f7efdbb6398d545446e246eff02"
uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
version = "0.18.10"

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

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

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

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

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

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

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

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

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

[[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"

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

[[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"

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

[[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"

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

[[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"

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

[[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 = "fd75fa3a2080109a2c0ec9864a6e14c60cca3866"
uuid = "d2c73de3-f751-5644-a686-071e5b155ba9"
version = "0.62.0+0"

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

[[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"

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

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

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

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

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

[[Hyperscript]]
deps = ["Test"]
git-tree-sha1 = "8d511d5b81240fc8e6802386302675bdf47737b9"
uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91"
version = "0.0.4"

[[HypertextLiteral]]
git-tree-sha1 = "2b078b5a615c6c0396c77810d92ee8c6f470d238"
uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2"
version = "0.9.3"

[[IOCapture]]
deps = ["Logging", "Random"]
git-tree-sha1 = "f7be53659ab06ddc986428d3a9dcc95f6fa6705a"
uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89"
version = "0.2.2"

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

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

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

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

[[IterTools]]
git-tree-sha1 = "05110a2ab1fc5f932622ffea2a003221f4782c18"
uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e"
version = "1.3.0"

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

[[JLLWrappers]]
deps = ["Preferences"]
git-tree-sha1 = "642a199af8b68253517b80bd3bfd17eb4e84df6e"
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
version = "1.3.0"

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

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

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

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

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

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

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

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

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

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

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

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

[[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"

[[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"

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

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

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

[[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"

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

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

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

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

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

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

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

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

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

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

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

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

[[NaNMath]]
git-tree-sha1 = "bfe47e760d60b82b66b61d2d44128b62e3a369fb"
uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
version = "0.3.5"

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

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

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

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

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

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

[[Parsers]]
deps = ["Dates"]
git-tree-sha1 = "ae4bbcadb2906ccc085cf52ac286dc1377dceccc"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "2.1.2"

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

[[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"

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

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

[[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"]
git-tree-sha1 = "93f484f18848234ac2c1387c7e5263f840cdafe3"
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
version = "1.24.2"

[[PlutoUI]]
deps = ["AbstractPlutoDingetjes", "Base64", "Dates", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "Markdown", "Random", "Reexport", "UUIDs"]
git-tree-sha1 = "1e0cb51e0ccef0afc01aab41dc51a3e7f781e8cb"
uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
version = "0.7.20"

[[Preferences]]
deps = ["TOML"]
git-tree-sha1 = "00cfd92944ca9c760982747e9a1d0d5d86ab1e5a"
uuid = "21216c6a-2e73-6563-6e65-726566657250"
version = "1.2.2"

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

[[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"

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

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

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

[[RecipesPipeline]]
deps = ["Dates", "NaNMath", "PlotUtils", "RecipesBase"]
git-tree-sha1 = "7ad0dfa8d03b7bcf8c597f59f5292801730c55b8"
uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c"
version = "0.4.1"

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

[[Requires]]
deps = ["UUIDs"]
git-tree-sha1 = "4036a3bd08ac7e968e27c203d45f5fff15020621"
uuid = "ae029012-a4dd-5104-9daa-d747884805df"
version = "1.1.3"

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

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

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

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

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

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

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

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

[[StaticArrays]]
deps = ["LinearAlgebra", "Random", "Statistics"]
git-tree-sha1 = "3c76dde64d03699e074ac02eb2e8ba8254d428da"
uuid = "90137ffa-7385-5640-81b9-e52037218182"
version = "1.2.13"

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

[[StatsAPI]]
git-tree-sha1 = "0f2aa8e32d511f758a2ce49208181f7733a0936a"
uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0"
version = "1.1.0"

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

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

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

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

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

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

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

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

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

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

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

[[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"

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

[[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"

[[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"

[[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"

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

[[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"

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

[[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"

[[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"

[[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"

[[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"

[[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"

[[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"

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

[[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"

[[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"

[[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"

[[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"

[[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"

[[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"

[[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"

[[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"

[[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"

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

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

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

[[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"

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

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

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

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

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

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

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

[[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:
# ╟─c0e4d750-b9a4-11eb-2e0c-edaeaaf3f36a
# ╟─606ac8d7-7cd6-4da3-b83f-9889f6883190
# ╟─4c9ce872-1164-4c7f-9a26-3af89b345c41
# ╟─9b3e08e0-7207-4099-96e4-c6e1e9892a1f
# ╟─159419d5-0555-43a0-8320-9cb51e0b05ba
# ╠═fb03a3aa-f94b-4b73-a21b-f05bc548dd9d
# ╟─df708c4d-443b-4190-b72d-779c4e1e1bb1
# ╟─41eac123-fa10-42c3-a801-8fb5f7bce7ae
# ╟─66de4e49-ede7-44d1-b7b4-49ecb3ec2e53
# ╟─3d8c7f7e-e765-41d9-8191-aef5e52984fc
# ╟─db0fc7c2-9e8c-415f-95c1-686dbfc56347
# ╟─6a1ee842-a2f1-4810-83d7-5ce931c47891
# ╟─d2ed65c3-24e3-42ee-ac6e-f743ef4b584d
# ╟─19822397-18c5-4a88-bac1-f3adbfd2b235
# ╟─594360d4-9bb8-4756-8f40-a5f0f9555aba
# ╟─1b4d9fbd-be46-416a-a1fe-163f5a0b37a3
# ╟─5db1fd70-0bf9-462b-b6d3-bfc3ed8890cb
# ╟─89222965-d320-4a46-a11a-b66b2ed9c11d
# ╟─750b6ab7-0b11-4b91-be34-ab7426625204
# ╠═026c8f3e-8ecd-459f-b496-511c38065cc6
# ╟─f559622d-8bb3-4068-a4a8-b4f561960da1
# ╠═e4374691-885a-487e-bee5-dac9092dd567
# ╟─995e0deb-8044-4cd8-b802-0bda0ce093e3
# ╟─773eb541-f02a-4d61-8d20-9c79a49f6d85
# ╠═c29521d1-6563-4c9f-9d06-656eb8b98a6f
# ╟─acb69a29-d406-4f43-ab59-37c4516a460a
# ╟─50da3fc1-b450-4c56-b179-1e6c36af7265
# ╟─c5058f6d-d489-4308-b010-472ae048a6a7
# ╟─da4138d9-2723-4274-8bd1-a0c9a89c1163
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002


# ---
# title: 542. 01 Matrix
# id: problem542
# author: Indigo
# date: 2021-06-23
# difficulty: Medium
# categories: Depth-first Search, Breadth-first Search
# link: <https://leetcode.com/problems/01-matrix/description/>
# hidden: true
# ---
#
# Given a matrix consists of 0 and 1, find the distance of the nearest 0 for
# each cell.
#
# The distance between two adjacent cells is 1.
#
#
#
# **Example 1:**
#
#
#
#     Input:
#     [[0,0,0],
#      [0,1,0],
#      [0,0,0]]
#
#     Output:
#     [[0,0,0],
#      [0,1,0],
#      [0,0,0]]
#
#
# **Example 2:**
#
#
#
#     Input:
#     [[0,0,0],
#      [0,1,0],
#      [1,1,1]]
#
#     Output:
#     [[0,0,0],
#      [0,1,0],
#      [1,2,1]]
#
#
#
#
# **Note:**
#
#   1. The number of elements of the given matrix will not exceed 10,000.
#   2. There are at least one 0 in the given matrix.
#   3. The cells are adjacent in only four directions: up, down, left and right.
#
#
## @lc code=start
using LeetCode

function update_matrix(mat::Matrix{Int})
    m, n = size(mat)
    dist = fill(typemax(Int) >> 1, m, n)
    for I in CartesianIndices(mat)
        (mat[I] == 0) && (dist[I] = 0)
    end
    for i in 1:m, j in 1:n
        (i - 1 >= 1) && (dist[i, j] = min(dist[i, j], dist[i - 1, j] + 1))
        (j - 1 >= 1) && (dist[i, j] = min(dist[i, j], dist[i, j - 1] + 1))
    end
    for i in m:-1:1, j in n:-1:1
        (i + 1 <= m) && (dist[i, j] = min(dist[i, j], dist[i + 1, j] + 1))
        (j + 1 <= n) && (dist[i, j] = min(dist[i, j], dist[i, j + 1] + 1))
    end
    return dist
end
## @lc code=end


# Exercise 1-1
# 1. Leaving out () shows function information. Missing parenthesis will result in incomplete expression or error.
# 2. Similar to 1.
# 3. Putting + before numbers will just print the value of the number. 2 ++ 2 is not valid, but 2 + + 2 is valid.
# 4. Leading zeroes will be removed when printed as numbered values.
# 5. Invalid expression, eg. 2 2 is not valid.

# Exercise 1-2
println("Number of seconds in 42min 42s = ", 42*60 + 42, 's')
println("Number of miles in 10km = ", 10 * 1.41, " miles")
println("For a 10km race in 37min and 48s,")
println("Average pace = ", (37 * 60 + 48) / 10, " s/mile")
println("or ", (37 + 48/60) / 10, " min/mile")
println("Average speed = ", 10 / (37 + 48/60) / 60, " miles/hr")


export @evalpoly_derivative, @goertzel_deriv, @horner_deriv

"""
    evalpoly(::Type{T}, degrees, coefficients, var::Union{Symbol, Expr})

Evaluate the polynomial defined by the degrees and coefficients.
"""
function evalpoly(::Type{T}, degrees::AbstractVector, coefficients::AbstractVector, var) where T
    normalized_coeffs = normalized_coefficients(T, degrees, coefficients)

    if length(normalized_coeffs) == 1
        return normalized_coeffs[1]
    elseif length(normalized_coeffs) == 2
        a, b = normalized_coeffs
        :(muladd($b, $var, $a))
    else
        :(@evalpoly($var, $(normalized_coeffs...)))
    end

end

"""
    evalpoly_derivative!(exprs, ::Type{T}, degrees, coefficients, var::Union{Symbol, Expr})

Evaluate the polynomial and its derivative defined by the degrees and coefficients.
"""
function evalpoly_derivative!(exprs, ::Type{T}, degrees::AbstractVector, coefficients::AbstractVector, var) where T
    normalized_coeffs = normalized_coefficients(T, degrees, coefficients)

    if length(normalized_coeffs) == 1
        if isa(normalized_coeffs[1], Symbol)
            val = normalized_coeffs[1]
        else
            @gensym val
            push!(exprs, :($val = $(normalized_coeffs[1])))
        end
        # return zero directly
        dval = :(zero($T))
    elseif length(normalized_coeffs) == 2
        @gensym val
        a, b = normalized_coeffs
        push!(exprs, :($val = muladd($b, $var, $a)))
        if isa(b, Symbol)
            dval = b
        else
            @gensym dval
            push!(exprs, :($dval = $b))
        end
    else
        @gensym dval val
        push!(exprs, :(($val, $dval) = @evalpoly_derivative($var, $(normalized_coeffs...))))
    end

    return val, dval
end

"""
    @evalpoly_derivative(z, c...)

Evaluate the polynomial ``\\sum_k c[k] z^{k-1}`` for the coefficients `c[1]`, `c[2]`, ... and its derivative;
that is, the coefficients are given in ascending order by power of `z`.  This macro expands
to efficient inline code that uses either Horner's method or, for complex `z`, a more
efficient Goertzel-like algorithm.

```jldoctest
julia> @evalpoly(3, 1, 0, 1)
(10, 6)

julia> @evalpoly(2, 1, 0, 1)
(5, 4)

julia> @evalpoly(2, 1, 1, 1)
(7, 5)
```
"""
macro evalpoly_derivative(z, p...)
    R = Expr(:macrocall, Symbol("@horner_deriv"), (), :tt, map(esc, p)...)
    C = Expr(:macrocall, Symbol("@goertzel_deriv"), (), :tt, map(esc, p)...)
    :(let tt = $(esc(z))
          isa(tt, Complex) ? $C : $R
      end)
end

macro horner_deriv(x, p...)
    escaped_x = :($(esc(x)))
    escaped_p = map(esc, p)
    horner_deriv_impl(escaped_x, escaped_p)
end

function horner_deriv_impl(x, p)
    if length(p) == 1
        return :($(p[1]), zero($(p[1])))
    end

    exprs = Expr[]
    push!(exprs, :(val = $(p[end])))
    push!(exprs, :(dval = val))
    for k = length(p)-1:-1:1
        if k < length(p) - 1
            push!(exprs, :(dval = muladd(dval, $x, val)))
        end
        push!(exprs, :(val = muladd(val, $x, $(p[k]))))
    end

    Expr(:block,
        exprs...,
        :(val, dval))
end

macro goertzel_deriv(z, p...)
    escaped_z = :($(esc(z)))
    escaped_p = map(esc, p)
    goertzel_deriv_impl(escaped_z, escaped_p)
end

function goertzel_deriv_impl(z, p)
    if length(p) == 1
        return :($(p[end]), zero($(p[end])))
    end

    if length(p) == 2
        return :(
            muladd($(p[end]), $z, $(p[end-1])),
            $(p[end])
        )
    end

    exprs = Expr[]
    goertzel_setup!(exprs, z)
    goertzel_deriv_main!(exprs, z, p)

    Expr(:block, exprs...)
end

function goertzel_setup!(exprs, z)
    push!(exprs,
        :(x = real($z)),
        :(y = imag($z)),
        :(r = x + x),
        :(s = -muladd(x, x, y*y)))
end

function goertzel_deriv_main!(exprs, z, p)
    @assert length(p) > 2

    a = :($(p[end]))
    b = :($(p[end-1]))
    local c, d
    # d = b
    for i = length(p)-2:-1:1
        ei = Symbol("e", i)
        push!(exprs, :($ei = $a)) #e_i
        a = :(muladd(r, $ei, $b))
        b = :(muladd(s, $ei, $(p[i])))

        if i == length(p) - 2
            c = ei
        elseif i == length(p) - 3
            d = ei
        else
            fi = Symbol("f", i)
            push!(exprs, :($fi = $c)) #e_i
            c = :(muladd(r, $fi, $d))
            d = :(muladd(s, $fi, $ei))
        end
    end
    r1 = :r1 # r1
    push!(exprs, :($r1 = $a))
    r2 = b
    push!(exprs, :(val = muladd($r1, $z, $r2)))

    # we handle the cases that length(p) < 3 before this routines is called
    if length(p) == 3
        lm = :($(p[end]))
        push!(exprs, :(t = y + y))
        dval = quote
            if isa(r1, Complex)
                complex(real(r1) - t * imag($lm), imag(r1) + t * real($lm))
            else
                complex(r1 - t * imag($lm), t * real($lm))
            end
        end
        push!(exprs, :((val, $dval)))
    else
        dr1 = :dr1
        push!(exprs, :($dr1 = $c))
        dr0 = d
        push!(exprs, :(dr0 = muladd($dr1, $z, $dr0)))

        push!(exprs, :(t = y + y))
        dval = quote
            if isa(r1, Complex)
                complex(real(r1) - t * imag(dr0), imag(r1) + t * real(dr0))
            else
                complex(r1 - t * imag(dr0), t * real(dr0))
            end
        end
        push!(exprs, :((val, $dval)))
    end
end


using GtkInteract
using Plots
backend(:immerse)

## Manipulate can display text output in a label
@manipulate for n=1:10, x=1:10
   (n,x)
end

## Similary, a plot can be made. Here we use Immerse through Plots:
@manipulate for n=1:10
    plot(sin, 0, n*pi)
end

## Unicode works, as does passing along functions through Options.
@manipulate for ϕ = 0:π/16:4π, f = Dict(:sin => sin, :cos => cos)
   plot(x -> f(x + ϕ), 0, pi)
end

## Can use plot! for adding layers
@manipulate for n=1:10
    plot(sin, 0, n*pi)
    plot!(cos, 0, n*pi, color=:red)
end

## and we can combine (mimicing an example from Interact)
@manipulate for ϕ = 0:π/16:4π, f = Dict(:sin => sin, :cos => cos), both = false
    if both
        plot(θ -> sin(θ + ϕ), 0, 8)
	plot!(θ -> cos(θ + ϕ), 0, 8, color=:red)
    else
       plot(θ -> f(θ + ϕ), 0, 8)
    end
end

## immerse works as directly, as well. In this case, the immerse toolbar is available:

using Immerse
@manipulate for n=1:10
    Immerse.plot(x=rand(n*10), y=rand(n*10))
end

# Text output
## The basic text output uses a label.
## This allows for some PANGO markup
## (https://developer.gnome.org/pango/stable/PangoMarkupFormat.html)
@manipulate for n = 1:20
    x = n > 10 ? "$n" : string(n)
    "The value is $x"
end

## Sadly, no latex output widget. So this example fails to render nicely
using SymPy
x = Sym("x")
@manipulate for n=1:10
    a = diff(sin(x^2), x, n)
    a
    jprint(a)
end

# Output widgets

## There are controls for gathering input, and output widgets for display. These consist of
## cairographic, textarea, label, and progress
## These values are `push!`ed onto within the function call. The function call should return `nothing`,
## else the output will be displayed as well in either a label or plot container.

## The label can be replaced by a multiline text buffer. The syntax is
## a bit awkward.  output widgets have values `push!`ed onto them and a final
## value of `nothing` is used.
@manipulate for n=1:10, x=1:10, out=textarea()
    push!(out, (n,x))
    nothing
end

## The progres bar is another output widget
@manipulate for n=1:100, pb=progress()
    push!(pb, n)
    nothing
end

## We can have more than one output widget
@manipulate for n=1:10, cg1=cairographic(width=300, height=200), cg2=cairographic(width=300, height=200)
    push!(cg1, Plots.plot(cos, 0, n*pi))
    push!(cg2, Plots.plot(sin, 0, n*pi))
    nothing
end

## Control widgets can be used instead of their being derived from the argument. This
## gives some flexibility and allows the labels to be different than the variable
## name associated with the control.
@manipulate for rb=radiobuttons([1,2,3],label="rb"), cb=checkbox(true, label="checkbox")
    (rb, cb)
end

## An example of @vchuravy from https://github.com/JuliaLang/Interact.jl/issues/36
using Distributions
@manipulate for α in 1:100, β = 1:100
    Plots.plot(x -> pdf(Beta(α, β), x), 0, 1)
end

## An example by @stevengj (https://github.com/JuliaLang/Interact.jl/issues/36)

# n steps of Newton iteration for sqrt(a), starting at x
function newton(a, x, n)
    for i = 1:n
        x = 0.5 * (x + a/x)
    end
    return x
end

# output x as HTML, with digits matching x0 printed in bold
function matchdigits(x::Number, x0::Number)
    s = string(x)
    s0 = string(x0)
    buf = IOBuffer()
    matches = true
    i = 0
    print(buf, "")           # pango  matches HTML
    while (i += 1) <= length(s)
        i % 30 == 0 && print(buf, "\n") # not

        if matches && i <= length(s0) && isdigit(s[i])
            if s[i] == s0[i]
                print(buf, s[i])
                continue
            end
            print(buf, "")
            matches = false
        end
        print(buf, s[i])
    end
    matches && print(buf, "")
    takebuf_string(buf)
end

set_bigfloat_precision(1024)
sqrt2 = sqrt(big(2))

@manipulate for l=label("Number of steps"), n = slider(0:9, value=0, label="n")
   matchdigits(newton(big(2), 2, n), sqrt2)
end


export AUC, gini#, CrossEntropy

using DataFrames: groupby, combine, DataFrame, sort!
using CategoricalArrays: CategoricalVector

# import MLJBase: CrossEntropy
#
# CrossEntropy(x, y::CategoricalVector) = CrossEntropy(x, y.refs .- 1)

function AUC_plot_data(score, target::CategoricalVector;  kwargs...)
    @assert length(levels(target)) == 2
    _AUC_plot_data(score, 2 .- target.refs; kwargs...)
end

AUC_plot_data(score, target;  kwargs...) = _AUC_plot_data(score, target;  kwargs...)

function _AUC_plot_data(score, target;  plotauc = false)
    grp_df = groupby(DataFrame(score = score, target = target), :score)
    tmpdf = combine(grp_df,
        :target => sum => :ntarget,
        nrow => :n
    )
    sort!(tmpdf,:score)
    nrows = length(score)
    cutarget = accumulate(+, tmpdf[!,:ntarget]) ./ sum(tmpdf[!,:ntarget])
    cu = accumulate(+, tmpdf[!,:n]) ./ sum(tmpdf[!,:n])

    if plotauc
        plot(vcat(0,cu), vcat(0,cutarget))
        plot!([0,1],[0,1])
    end

    cu, cutarget
end

"""
    AUC(score, target; plotauc = false)

Return the AUC. To generate a plot set `plotauc=true`.
"""
function AUC(score, target; kwargs...)
    cu, cutarget = AUC_plot_data(score, target; kwargs...)
    sum((cutarget[2:end] .+ cutarget[1:end-1]).*(cu[2:end].-cu[1:end-1])./2)
end

"""
    gini(score, target; plotauc = false)

Return the `gini = (AUC - 0.5)/0.05 = 2AUC - 1`. AUC is the area under the curve while gini
is the ratio of (AUC minus the area of the bottom triangle) vs (Area of upper triangle).

For AUC a random model has AUC = 0.5 but for gini a random model has gini = 0.0

To generate a plot set `plotauc=true`.
"""
function gini(score, target; plotauc = false)
    auc = AUC(score,target; plotauc = plotauc)
    2*auc-1
end


using DrWatson
@quickactivate "VelocityMTD"

using PyCall

pushfirst!(PyVector(pyimport("sys")."path"), srcdir())
pypsd = pyimport("PSD")
pyimport("importlib")."reload"(pypsd)

"""
Plot the PSD and its fit on `ax`. Input is velocity timeseries (or the notes
to calculate the timeseries from, by averaging velocity).

`kwargs` are propagated into `Python.psd`, while `minsub, tpq` are
"""
function psdfit!(ax, notes::Notes, middle = nothing;
    minsub = 12, tpq = 960, kwargs...)

    t, v = timeseries(notes, :velocity, mean, 0:(1//minsub):1)
    v = [ismissing(vi) ? 0 : vi for vi in v]
    psdfit!(ax, v, middle; minsub = minsub, tpq = tpq, kwargs...)
end

function psdfit!(ax, v::Vector, middle = nothing;
    minsub = 12, tpq = 960, kwargs...)

    mindur = tpq÷minsub

    f2b = (f) -> @. mindur/f/tpq
    b2f = (b) -> @. mindur/b/tpq

    f, psd = pypsd.psd(v; kwargs...)
    lo, up, N = pypsd.chisquare_ci(get(kwargs, :overlap_factor, 20) - 1)

    beats = f2b.(f[2:end])

    ax.loglog(beats, psd[2:end], c= "C0", lw = 1.5, basex=2)
    ax.fill_between(beats, psd[2:end] .* up ./ N, psd[2:end] .* lo ./ N, color = "C0", alpha = 0.25)

    if isnothing(middle)
        fs1, sl1, slope1 = pypsd.fit_powerlaw(f, psd, mindur, tpq; upper = maximum(beats), lower = minimum(beats))
        ax.plot(f2b.(fs1), sl1, label = "\$\\beta\$ = $(round(slope1; digits=2))", c = "C5")
        slope2 = 0.0
    else
        fs1, sl1, slope1 = pypsd.fit_powerlaw(f, psd, mindur, tpq; upper = middle, lower = minimum(beats))
        fs2, sl2, slope2 = pypsd.fit_powerlaw(f, psd, mindur, tpq; upper = maximum(beats), lower = middle)
        ax.plot(f2b.(fs1), sl1, label = "\$\\delta\$ = $(round(slope1; digits=2))", c = "C2")
        ax.plot(f2b.(fs2), sl2, label = "\$\\beta\$ = $(round(slope2; digits=2))", c = "C5")
    end

    ax.legend()
    ax.set_xlabel("period (beats)")
    ax.grid()
    return slope1, slope2
end


# This file is part of the IntervalArithmetic.jl package; MIT licensed

"""
    widened(x)

widens the lowest and highest bounds of `x` to the previous and next representable floating-point numbers, respectively.

It implements `nextOut` from the IEEE 1788-2015 standard.
"""
widened(x::Interval{T}) where {T<:AbstractFloat} =
    unsafe_interval(prevfloat(x.lo), nextfloat(x.hi))
widened(x::EmptyInterval) = x

# unsafe method, only for use with checked input
signed_infinity(x::T) where {T<:AbstractFloat} = sign(x) * T(Inf) |>
    x -> unsafe_interval(prevfloat(x), nextfloat(x))

# common thin intervals
zero(a::I) where {T, I <: ValidInterval{T}} = unsafe_interval(zero(T))
zero(::Type{I}) where {T, I <: ValidInterval{T}} = unsafe_interval(zero(T))
one(a::I) where {T, I <: ValidInterval{T}} = unsafe_interval(one(T))
one(::Type{I}) where {T, I <: ValidInterval{T}} = unsafe_interval(one(T))
#eps(a::Interval) = unsafe_interval(max(eps(a.lo), eps(a.hi)))
eps(::Type{ValidInterval{T}}) where T = unsafe_interval(eps(T))

copysign(::ValidInterval{T}, ::ValidInterval{T}) where T = emptyinterval(T)
copysign(a::Interval{T}, b::Interval{T}) where T = abs(a) * sign(b)

"""
    valtype(::AbstractInterval{T}) where T = T

Returns the type of the bounds of the interval.

### Example

```julia
julia> valtype(Interval(1.0, 2.0))
Float64
julia> valtype(emptyinterval(Float32))
Float32
```
"""
valtype(::AbstractInterval{T}) where T = T

"""
Computes the integer hash code for an `Interval` using the method for composite types used in `AutoHashEquals.jl`
"""
hash(x::Interval, h::UInt) = hash(x.hi, hash(x.lo, hash(:Interval, h)))
hash(::EmptyInterval, h::UInt) = hash(:EmptyInterval, h)
hash(::NotAnInterval, h::UInt) = hash(:NotAnInterval, h)


export MorseBond

"""
    MorseBond(; D, α, r0)

A Morse potential bond between two atoms.
"""
struct MorseBond{T, A, R} <: SpecificInteraction
    D::T
    α::A
    r0::R
end

MorseBond(; D, α, r0) = MorseBond{typeof(D), typeof(α), typeof(r0)}(D, α, r0)

@inline @inbounds function force(b::MorseBond, coord_i, coord_j, box_size)
    dr = vector(coord_i, coord_j, box_size)
    r = norm(dr)
    ralp = exp(-b.α * (r - b.r0))
    c = 2 * b.D * b.α * (1 - ralp) * ralp
    f = c * normalize(dr)
    return SpecificForce2Atoms(f, -f)
end

@inline @inbounds function potential_energy(b::MorseBond, coord_i, coord_j, box_size)
    dr = vector(coord_i, coord_j, box_size)
    r = norm(dr)
    ralp = exp(-b.α * (r - b.r0))
    return b.D * (1 - ralp)^2
end


export
    qpdf,
    qpdf!

"""
    qpdf([T=Float64], d::GaussianStateBHD, θ::Real, x::Real)
    qpdf([T=Float64], d::GaussianStateBHD, θs::AbstractRange, xs::AbstractRange)
    qpdf([T=Float64], d::QuantumStateBHD, θ::Real, x::Real)
    qpdf([T=Float64], d::QuantumStateBHD, θs::AbstractRange, xs::AbstractRange)
    qpdf([T=Float64], ρ::AbstractArray, θ::Real, x::Real)
    qpdf([T=Float64], ρ::AbstractArray, θs::AbstractRange, xs::AbstractRange)

Quadrature prabability in intensity-to-measurement-phase quadrature coordinate.

## Arguments

* `T`: Data type, default as Float64.
* `state`: State can be `GaussianStateBHD` distribution, `QuantumStateBHD` distribution or density matrix.
* `θ`: Measurement phase, can be `Real` or `AbstractRange`.
* `x`: Intensity in quadrature coordinate, can be `Real` or `AbstractRange`.

``p(\\rho, \\theta, x) = tr(\\hat{\\Pi}(\\theta, x) \\rho)``
"""
qpdf(state, θ, x) = qpdf(Float64, state, θ, x)

function qpdf(T::Type{<:Real}, d::GaussianStateBHD, θ::Real, x::Real)
    μ = QuantumStateDistributions.mean(d, θ)
    σ = QuantumStateDistributions.std(d, θ)

    return T(pdf(Normal(μ, σ), x))
end

function qpdf(T::Type{<:Real}, d::GaussianStateBHD, θs::AbstractRange, xs::AbstractRange)
    m, n = length(θs), length(xs)

    μs = Vector{T}(undef, m)
    σs = Vector{T}(undef, m)
    gaussians = Vector{Normal}(undef, m)
    𝐩 = Matrix{T}(undef, m, n)

    return qpdf!(μs, σs, gaussians, 𝐩, d, θs, xs)
end

function qpdf!(μs, σs, gaussians, 𝐩, d::GaussianStateBHD, θs::AbstractRange, xs::AbstractRange)
    μs .= QuantumStateDistributions.mean(d, θs)
    σs .= QuantumStateDistributions.std(d, θs)

    gaussians .= Normal.(μs, σs)

    for i in 1:length(θs)
        for (j, x) in enumerate(xs)
		    𝐩[i, j] = pdf(gaussians[i], x)
        end
    end

    return 𝐩
end

qpdf(T::Type{<:Real}, d::QuantumStateBHD, θ, x) = qpdf(T, d.ρ, θ, x)

function qpdf(T::Type{<:Real}, ρ::AbstractMatrix, θ::Real, x::Real)
    dim = size(ρ, 1)
    𝛑̂_res = Matrix{Complex{T}}(undef, dim, dim)

    return qpdf!(𝛑̂_res, ρ, θ, x)
end

function qpdf!(𝛑̂_res::AbstractMatrix, ρ::AbstractMatrix, θ::Real, x::Real)
    dim = size(ρ, 1)

    return real_tr_mul(𝛑̂!(𝛑̂_res, θ, x, dim=dim), ρ)
end

function qpdf(T::Type{<:Real}, ρ::AbstractMatrix, θs::AbstractRange, xs::AbstractRange)
    dim = size(ρ, 1)
    𝛑̂_res_vec = [Matrix{Complex{T}}(undef, dim, dim) for _ in 1:Threads.nthreads()]
    𝐩 = Matrix{T}(undef, length(θs), length(xs))

    return qpdf!(𝛑̂_res_vec, 𝐩, ρ, θs, xs)
end

function qpdf!(
    𝛑̂_res_vec::AbstractVector{Matrix{Complex{T}}}, 𝐩::Matrix{T},
    ρ::AbstractMatrix, θs::AbstractRange, xs::AbstractRange
) where {T}
    @sync for (j, x) in enumerate(xs)
        for (i, θ) in enumerate(θs)
            Threads.@spawn 𝐩[i, j] = qpdf!(𝛑̂_res_vec[Threads.threadid()], ρ, θ, x)
        end
    end

    return 𝐩
end

##### for arb. state in intensity-to-measurement-phase quadrature coordinate #####

"""
    ψₙ(n::Integer, θ::Real, x::Real)

Eigenstate of BHD measurement operator.

``\\psi_n(\\theta, x) = \\langle n | \\theta, x \\rangle``
"""
function ψₙ(n::Integer, θ::Real, x::Real)
    # |θ, x⟩ = ∑ₙ |n⟩ ⟨n|θ, x⟩ = ∑ₙ ψₙ(θ, x) |n⟩
    # ⟨n|θ, x⟩ = ψₙ(θ, x) = exp(im n θ) (2/π)^(1/4) exp(-x^2) Hₙ(√2 x)/√(2^n n!)

    return (2/π)^(1/4) * exp(im*n*θ - x^2) * hermiteh(n, sqrt(2)x) / sqrt(2^n * factorial(n))
end

"""
    𝛑̂(θ::Real, x::Real; dim::Integer)

BHD measurement operator.

``\\hat{\\Pi}_{m, n}(\\theta, x) = \\langle m | \\hat{\\Pi}(\\theta, x) | n \\rangle = \\langle m | \\theta, x \\rangle \\langle \\theta, x | n \\rangle``
"""
𝛑̂(θ::Real, x::Real; dim) = 𝛑̂(ComplexF64, θ, x, dim=dim)

function 𝛑̂(T::Type{<:Complex}, θ::Real, x::Real; dim)
    result = Matrix{T}(undef, dim, dim)

    return 𝛑̂!(result, θ, x, dim=dim)
end

function 𝛑̂!(result::AbstractMatrix{<:Complex}, θ::Real, x::Real; dim)
    view(result, :, 1) .= ψₙ.(big.(0:dim-1), θ, x)
    result .= view(result, :, 1) * view(result, :, 1)'

    return result
end

# #########
# # utils #
# #########

real_tr_mul(𝐚, 𝐛) = sum(real(𝐚[i, :]' * 𝐛[:, i]) for i in 1:size(𝐚, 1))


#using JuMP, Clp

function idm(d :: Array{Int64,1}, s=2.0 :: Float64, logspace=true :: Bool)
    n = length(d)
    p = zeros(2,n)
    p[1,:] = d
    p[2,:] = d .+ s
    p = p ./ (sum(d) .+ s)
    return logspace ? [log.(x) for x in p] : p
end

function lp(c :: Array{Float64,1}, p :: Array{Float64,2}, maximize=true :: Bool, logspace=true :: Bool)
    x = p[:,1]

    i = sortperm(c,rev=maximize)[1]
    x[i] = getindex(p[i,:], 2)
    return logspace ? c'*exp.(x) : c'*x
end

function add_missingness(data :: PlainXData{Bool,BitArray{2}} , ratio :: Float64)
    data2 = convert.(Int8,data.x)
    data2[rand(Float16,size(data.x)) .< ratio] .= -1
    return data2
end
#=
function minimi(coeff :: Array{Float64,1}, l_bounds :: Array{Float64,1}, u_bounds :: Array{Float64,1})
    my_model = Model(Clp.Optimizer)
    set_optimizer_attribute(my_model, "LogLevel", 0)
    set_optimizer_attribute(my_model, "Algorithm", 4)
    @variable(my_model, l_bounds[i] <= x[i = 1:length(l_bounds)]<= u_bounds[i])
    @objective(my_model,Min,coeff' *x) # perché anche * ?
    @constraint(my_model, normalization, ones(Float64, length(l_bounds))'x == 1)
    optimize!(my_model)
    return JuMP.objective_value(my_model)
end
=#


# MIT license
# Copyright (c) Microsoft Corporation. All rights reserved.
# See LICENSE in the project root for full license information.

function zernikelens()
    topsurface = leaf(AcceleratedParametricSurface(ZernikeSurface(9.5, zcoeff = [(1, 0.0), (4, -1.0), (7, 0.5)]), interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air)), translation(0.0, 0.0, 5.0))
    botsurface = leaf(Plane(0.0, 0.0, -1.0, 0.0, 0.0, -5.0, vishalfsizeu = 9.5, vishalfsizev = 9.5, interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air)))
    barrel = leaf(Cylinder(9.0, 20.0, interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, reflectance = zero(Float64), transmission = zero(Float64))))
    return (barrel ∩ topsurface ∩ botsurface)(Transform{Float64}(0.0, Float64(π), 0.0, 0.0, 0.0, -5.0))
end

function asphericlens()
    topsurface = leaf(AcceleratedParametricSurface(ZernikeSurface(9.5, aspherics = [(2, 0.0), (4, -0.001)]), interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air)), translation(0.0, 0.0, 5.0))
    botsurface = leaf(Plane(0.0, 0.0, -1.0, 0.0, 0.0, -5.0, vishalfsizeu = 9.5, vishalfsizev = 9.5, interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air)))
    barrel = leaf(Cylinder(9.0, 20.0, interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, reflectance = zero(Float64), transmission = zero(Float64))))
    return (barrel ∩ topsurface ∩ botsurface)(Transform{Float64}(0.0, Float64(π), 0.0, 0.0, 0.0, -5.0))
end

function coniclensZ()
    topsurface = leaf(AcceleratedParametricSurface(ZernikeSurface(9.5, radius = -15.0, conic = -5.0), interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air)), translation(0.0, 0.0, 5.0))
    botsurface = leaf(Plane(0.0, 0.0, -1.0, 0.0, 0.0, -5.0, vishalfsizeu = 9.5, vishalfsizev = 9.5, interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air)))
    barrel = leaf(Cylinder(9.0, 20.0, interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, reflectance = zero(Float64), transmission = zero(Float64))))
    return (barrel ∩ topsurface ∩ botsurface)(Transform{Float64}(0.0, Float64(π), 0.0, 0.0, 0.0, -5.0))
end

function coniclensQ()
    topsurface = leaf(AcceleratedParametricSurface(QTypeSurface(9.5, radius = -15.0, conic = -5.0), interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air)), translation(0.0, 0.0, 5.0))
    botsurface = leaf(Plane(0.0, 0.0, -1.0, 0.0, 0.0, -5.0, vishalfsizeu = 9.5, vishalfsizev = 9.5, interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air)))
    barrel = leaf(Cylinder(9.0, 20.0, interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, reflectance = zero(Float64), transmission = zero(Float64))))
    return (barrel ∩ topsurface ∩ botsurface)(Transform{Float64}(0.0, Float64(π), 0.0, 0.0, 0.0, -5.0))
end

function qtypelens()
    topsurface = leaf(AcceleratedParametricSurface(QTypeSurface(9.0, radius = -25.0, conic = 0.3, αcoeffs = [(1, 0, 0.3), (1, 1, 1.0)], βcoeffs = [(1, 0, -0.1), (2, 0, 0.4), (3, 0, -0.6)], normradius = 9.5), interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air)), translation(0.0, 0.0, 5.0))
    botsurface = leaf(Plane(0.0, 0.0, -1.0, 0.0, 0.0, -5.0, vishalfsizeu = 9.5, vishalfsizev = 9.5, interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air)))
    barrel = leaf(Cylinder(9.0, 20.0, interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, reflectance = zero(Float64), transmission = zero(Float64))))
    return (barrel ∩ topsurface ∩ botsurface)(Transform{Float64}(0.0, Float64(π), 0.0, 0.0, 0.0, -5.0))
end

function chebyshevlens()
    topsurface = leaf(AcceleratedParametricSurface(ChebyshevSurface(9.0, 9.0, [(1, 0, -0.081), (2, 0, -0.162), (0, 1, 0.243), (1, 1, 0.486), (2, 1, 0.081), (0, 2, -0.324), (1, 2, -0.405), (2, 2, -0.81)], radius = -25.0), interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air)), translation(0.0, 0.0, 5.0))
    botsurface = leaf(Plane(0.0, 0.0, -1.0, 0.0, 0.0, -5.0, vishalfsizeu = 9.5, vishalfsizev = 9.5, interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air)))
    barrel = leaf(Cylinder(9.0, 20.0, interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, reflectance = zero(Float64), transmission = zero(Float64))))
    return (barrel ∩ topsurface ∩ botsurface)(Transform{Float64}(0.0, Float64(π), 0.0, 0.0, 0.0, -5.0))
end

function gridsaglens()
    topsurface = leaf(AcceleratedParametricSurface(GridSagSurface{Float64}(joinpath(@__DIR__, "../../test/test.GRD"), radius = -25.0, conic = 0.4, interpolation = GridSagBicubic), interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air)), translation(0.0, 0.0, 5.0))
    botsurface = leaf(Plane(0.0, 0.0, -1.0, 0.0, 0.0, -5.0, vishalfsizeu = 9.5, vishalfsizev = 9.5, interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air)))
    barrel = leaf(Cylinder(9.0, 20.0, interface = FresnelInterface{Float64}(OpticSim.GlassCat.SCHOTT.N_BK7, OpticSim.GlassCat.Air, reflectance = zero(Float64), transmission = zero(Float64))))
    return (barrel ∩ topsurface ∩ botsurface)(Transform{Float64}(0.0, Float64(π), 0.0, 0.0, 0.0, -5.0))
end


# TODO: handling singularity

const quon_atol = 1e-8

function change_direction(α::Complex)
    is_zero(α) && return InfZero
    is_pi(α) && return InfPi
    return to_quon_const(log(-tanh(α/2)))
end

"""
    yang_baxter_param(α1, β1, γ1)

Return α2, β2, γ2 according to the Yang-Baxter equation:

    \\    /    |       |    \\    /
     \\  /     |       |     \\  /
      α1      |       |      α2
     |  \\    /         \\    /  |
     |   \\  /           \\  /   |
     |    β1      =      β2    |
     |   /  \\           /  \\   |
     |  /    \\         /    \\  |
      γ1      |       |      γ1
     /  \\     |       |     /  \\
    /    \\    |       |    /    \\
"""
function yang_baxter_param(α1::Complex, β1::Complex, γ1::Complex)
    try
        if all(p -> (p isa QuonConst), to_quon_const.([α1, β1, γ1]))
            return yang_baxter_param(to_quon_const(α1), to_quon_const(β1), to_quon_const(γ1))
        end
        s1 = (α1+γ1)/2
        m1 = (α1-γ1)/2
        if !isapprox(cosh(s1), 0; atol = quon_atol)
            tanh_s2 = tanh(β1/2)*cosh(m1)/cosh(s1)
            @assert !(tanh_s2 ≈ 1)
            @assert !(tanh_s2 ≈ -1)
            s2 = atanh(tanh_s2)
        elseif !isapprox(cosh(m1)*sinh(β1), 0; atol = quon_atol)
            s2 = π*im/2
        else
            error("This case should not be handled here")
        end
        if !isapprox(sinh(s1), 0; atol = quon_atol)
            tanh_m2 = -tanh(β1/2)*sinh(m1)/sinh(s1)
            @assert !(tanh_m2 ≈ 1)
            @assert !(tanh_m2 ≈ -1)
            m2 = atanh(tanh_m2)
        elseif !isapprox(sinh(m1)*sinh(β1), 0; atol = quon_atol)
            m2 = π*im/2
        else
            error("This case should not be handled here")
        end

        α2 = s2+m2
        γ2 = s2-m2
        if !isapprox(cosh(m2), 0; atol = quon_atol) && !isapprox(cosh(s1), 0; atol = quon_atol)
            β2 = 2*atanh(tanh(s1)*cosh(s2)/cosh(m2))
        elseif !isapprox(sinh(m2), 0; atol = quon_atol) && !isapprox(cosh(m1), 0; atol = quon_atol)
            β2 = 2*atanh(tanh(m1)*sinh(s2)/sinh(-m2))
        else
            error("This case should not be handled here")
        end

        return to_quon_const(α2), to_quon_const(β2), to_quon_const(γ2)
    catch e
        error("$((α1, β1, γ1)) is a singular point of Yang-Baxter equation")
    end
end

function yang_baxter_param_inv(α2, β2, γ2)
    a2 = change_direction(α2)
    b2 = change_direction(β2)
    α1, c1, b1 = yang_baxter_param(b2, a2, γ2)
    β1 = change_direction(b1)
    γ1 = change_direction(c1)
    return α1, β1, γ1
end


using Catalyst
using DiffEqJump

rn = @reaction_network begin
    (γA, θA),   Da + A ↔ Dpa
    (γR, θR),   Dr + A ↔ Dpr
    αA,         Da → Da + Ma
    αR,         Dr → Dr + Mr
    αpA,        Dpa → Dpa + Ma
    αpR,        Dpr → Dpr + Mr
    βA,         Ma → Ma + A
    βR,         Mr → Mr + R
    γC,         A + R → C
    δA,         C → R
    δMA,        Ma → ∅
    δMR,        Mr → ∅
    δA,         A → ∅
    δR,         R → ∅
end αA αpA αR αpR βA βR δMA δMR δA δR γA γR γC θA θR

p = [50., 500., 0.01, 50., 50., 5., 10., 0.5, 1., 0.2, 1., 1., 2., 50., 100.]
u0 = [1, 0, 0, 1, 0, 0, 0, 0, 0]
tspan = (0., 200.)
prob_discrete = DiscreteProblem(rn, u0, tspan, p)
prob_jump = JumpProblem(rn, prob_discrete, Direct(), save_positions=(false, false))
for i = 1:100
    sol = solve(prob_jump, SSAStepper(), saveat=1.)
end


function getUpdatedFactoredVal_2D(HO::Bool,kappa_squared::Array{Float64,2},T::Array{EikTtype,2},Done::Array{Bool,2},loc1::Int64,
									loc2::Int64,h::Array{Float64,1},hinv::Array{Float64,1},src::Array{Int64,1},
									T0loc::Float64, G0loc::Array{Float64,1}, OpLoc::Array{Int8,1},A::Array{Float64,1},B::Array{Float64,1})
# op: -1 for backward. 1 for forward. -2/2 for 2nd order backward/forward.
# A and B are just containers for answers so we won't allocate tuples all the time....
if HO
	#answers are in A,B,OpLoc
	(t1,t1a) = calcDirectionHO_2D(1, kappa_squared, T, Done, loc1, loc2, h, hinv, src, T0loc, G0loc, OpLoc, A, B);
	(t2,t2a) = calcDirectionHO_2D(2, kappa_squared, T, Done, loc1, loc2, h, hinv, src, T0loc, G0loc, OpLoc, A, B);
else
	#answers are in A,B,OpLoc
	t1 = calcDirectionFO_2D(1, kappa_squared, T, Done, loc1, loc2, h, hinv, src, T0loc, G0loc, OpLoc, A, B);
	t2 = calcDirectionFO_2D(2, kappa_squared, T, Done, loc1, loc2, h, hinv, src, T0loc, G0loc, OpLoc, A, B);
end

#### Quadratic Solve
A1 = A[1]; A2 = A[2]; B1 = B[1]; B2 = B[2];
a = A1*A1 + A2*A2; b = -A1*B1-A2*B2; c = B1*B1 + B2*B2; # b is divided by 2 here for easing the quadratic solve.
T_loc = solvePiecewiseQuadratic(A1,B1,A2,B2,kappa_squared[loc1,loc2],a,b,c,OpLoc);

if FactoredEikonalFastMarching.imposeMonotonicity
	if (t1 > 0.0 && T_loc*T0loc < t1+1e-16)
		if OpLoc[1]==-1 || OpLoc[1]==1
			A1 = T0loc/h[1];
			B1 = t1/h[1];
		else
			A1 = (3.0*T0loc)/(2.0*h[1]);
			B1 = (4.0*t1 - t1a)/(2.0*h[1]);
		end
		a = A1*A1 + A2*A2; b = -A1*B1-A2*B2; c = B1*B1 + B2*B2; # b is divided by 2 here for easing the quadratic solve.
		T_loc = solvePiecewiseQuadratic(A1,B1,A2,B2,kappa_squared[loc1,loc2],a,b,c,OpLoc);
	elseif (t2 > 0.0 && T_loc*T0loc < t2+1e-16)
		if OpLoc[2]==-1 || OpLoc[2]==1
			A2 = T0loc/h[2];
			B2 = t2/h[2];
		else
			A2 = (3.0*T0loc)/(2.0*h[2]);
			B2 = (4.0*t2 - t2a)/(2.0*h[2]);
		end
		a = A1*A1 + A2*A2; b = -A1*B1-A2*B2; c = B1*B1 + B2*B2; # b is divided by 2 here for easing the quadratic solve.
		T_loc = solvePiecewiseQuadratic(A1,B1,A2,B2,kappa_squared[loc1,loc2],a,b,c,OpLoc);
	end
end
return T_loc;
end

function solveQuadratic(a::Float64,b::Float64,c::Float64,fsq::Float64)
# Solution of a quadratic equation based on:
# t = (-b/2 + sqrt(b^2/4 - ac))/a.
# b in the arguments is actually b/2 of the real equation.

c -= fsq;
in_sqrt = b*b - a*c;
if (in_sqrt > 0.0)
    T_loc = (-b + sqrt(in_sqrt))/(a);
else
    T_loc = 0.0;
end
return T_loc;
end

function solvePiecewiseQuadratic(A1::Float64,B1::Float64,A2::Float64,B2::Float64,fsq::Float64,
							a::Float64,b::Float64,c::Float64,OpLoc::Array{Int8,1})
T_loc = solveQuadratic(a,b,c,fsq);
g1 = (A1*T_loc - B1);
g2 = (A2*T_loc - B2);
if T_loc == 0.0 || g1 < 0.0 || g2 < 0.0
	val1 = (OpLoc[1]==0) ? Inf : B1/A1;
	val2 = (OpLoc[2]==0) ? Inf : B2/A2;
	if val1 < val2
		f = sqrt(fsq);
		T_loc = (f + B1) / A1;
		OpLoc[2] = 0;
	else
		f = sqrt(fsq);
		T_loc = (f + B2) / A2;
		OpLoc[1] = 0;
	end
end
return T_loc
end

function calcDirectionHO_2D(dim::Int64,kappa_squared::Array{Float64,2},T::Array{EikTtype,2},Done::Array{Bool,2},
							loc1::Int64,loc2::Int64,h::Array{Float64,1},hinv::Array{Float64,1},src::Array{Int64,1},
							T0loc::Float64,G0loc::Array{Float64,1},OpLoc::Array{Int8,1},A::Array{Float64,1},B::Array{Float64,1})
if dim==1
	loc1p1 = loc1 + 1;
	loc1m1 = loc1 - 1;
	loc1p2 = loc1 + 2;
	loc1m2 = loc1 - 2;
	loc2p1 = loc2m1 = loc2p2 = loc2m2 = loc2;
else # dim is assumed to be 2
	loc2p1 = loc2 + 1;
	loc2m1 = loc2 - 1;
	loc2p2 = loc2 + 2;
	loc2m2 = loc2 - 2;
	loc1p1 = loc1m1 = loc1p2 = loc1m2 = loc1;
end

tBWD = 0.0;
tFWD = 0.0;

ChooseBWD = getPaddedArr2D(Done,loc1m1,loc2m1);
if ChooseBWD
	tBWD = T[loc1m1,loc2m1]*T02D(h,src,loc1m1,loc2m1);
end
ChooseFWD = getPaddedArr2D(Done,loc1p1,loc2p1);
if ChooseFWD
	tFWD = T[loc1p1,loc2p1]*T02D(h,src,loc1p1,loc2p1)
end
if ChooseBWD && ChooseFWD
	ChooseFWD = tFWD < tBWD;
	ChooseBWD = !ChooseFWD;
end

A[dim] = B[dim] = 0.0;
OpLoc[dim] = 0;
t = T0loc*hinv[dim];
if ChooseBWD
	if getPaddedArr2D(Done,loc1m2,loc2m2) && tBWD > T[loc1m2,loc2m2]*T02D(h,src,loc1m2,loc2m2)
		@inbounds A[dim] = 1.5*t + G0loc[dim]; #going for second order!!!
        @inbounds B[dim] = (2.0*T[loc1m1,loc2m1] - 0.5*T[loc1m2,loc2m2])*t;
        @inbounds OpLoc[dim] = -2;
		return tBWD,T[loc1m2,loc2m2]*T02D(h,src,loc1m2,loc2m2);
	else # first order.
		@inbounds A[dim] = t + G0loc[dim];
		@inbounds B[dim] = T[loc1m1,loc2m1]*t;
		@inbounds OpLoc[dim] = -1; # Choosing N means backward derivative.
		return tBWD,0.0;
	end

elseif ChooseFWD
	@inbounds if getPaddedArr2D(Done,loc1p2,loc2p2) && tFWD > T[loc1p2,loc2p2]*T02D(h,src,loc1p2,loc2p2)
		@inbounds A[dim] = 1.5*t - G0loc[dim];
        @inbounds B[dim] = (2.0*T[loc1p1,loc2p1] - 0.5*T[loc1p2,loc2p2])*t;
        @inbounds OpLoc[dim] = 2;
		return tFWD,T[loc1p2,loc2p2]*T02D(h,src,loc1p2,loc2p2);
	else
		@inbounds A[dim] = t - G0loc[dim];
		@inbounds B[dim] = T[loc1p1,loc2p1]*t;
		@inbounds OpLoc[dim] = 1;
		return tFWD,0.0;
	end

end
return 0.0,0.0;
end

function calcDirectionFO_2D(dim::Int64,kappa_squared::Array{Float64,2},T::Array{EikTtype,2},Done::Array{Bool,2},loc1::Int64,loc2::Int64,
							h::Array{Float64,1},hinv::Array{Float64,1},src::Array{Int64,1},T0loc::Float64,G0loc::Array{Float64,1},
							OpLoc::Array{Int8,1},A::Array{Float64,1},B::Array{Float64,1})

if dim==1
	loc1p1 = loc1 + 1;
	loc1m1 = loc1 - 1;
	loc2p1 = loc2m1 = loc2;
else # dim is assumed to be 2
	loc2p1 = loc2 + 1;
	loc2m1 = loc2 - 1;
	loc1p1 = loc1m1 = loc1;
end

tBWD = 0.0;
tFWD = 0.0;

ChooseBWD = getPaddedArr2D(Done,loc1m1,loc2m1);
ChooseFWD = getPaddedArr2D(Done,loc1p1,loc2p1);

if ChooseBWD && ChooseFWD
	tBWD = T[loc1m1,loc2m1]*T02D(h,src,loc1m1,loc2m1);
	tFWD = T[loc1p1,loc2p1]*T02D(h,src,loc1p1,loc2p1)
	@inbounds ChooseFWD = tFWD < tBWD;
	ChooseBWD = !ChooseFWD;
elseif FactoredEikonalFastMarching.imposeMonotonicity
	if ChooseBWD
		tBWD = T[loc1m1,loc2m1]*T02D(h,src,loc1m1,loc2m1);
	end
	if ChooseFWD
		tFWD = T[loc1p1,loc2p1]*T02D(h,src,loc1p1,loc2p1)
	end
end

@inbounds A[dim] = B[dim] = 0.0;
OpLoc[dim] = 0;
t = T0loc*hinv[dim];
if ChooseBWD
	@inbounds A[dim] = t + G0loc[dim];
	@inbounds B[dim] = T[loc1m1,loc2m1]*t;
	@inbounds OpLoc[dim] = -1; # Choosing N means backward derivative.
	return tBWD;
elseif ChooseFWD
	@inbounds A[dim] = t - G0loc[dim];
	@inbounds B[dim] = T[loc1p1,loc2p1]*t;
	@inbounds OpLoc[dim] = 1;
	return tFWD;
end
return 0.0;
end


using IterTools

cd(dirname(@__FILE__))
lines = open("three.txt", "r") do f
    lines::Array{Array{Int64,1},1} = []
    for l in eachline(f)
        line = [(c == '#' ?  1 : 0) for c in l]
        push!(lines, line)
    end
    lines
end

function make_slide(right::Int64, down::Int64, m::Int64)
    function slide((x, y)::Tuple{Int64, Int64})::Tuple{Int64, Int64}
        x̂ = (x + right - 1) % m + 1 # OK, here it is really annoying that indices in Julia start at 1 ...
        ŷ = y + down
        x̂, ŷ
    end
end

route(x::Int64, y::Int64, r::Int64, d::Int64, m::Int64, l::Int64) =
    takewhile((_,y)::Tuple{Int64, Int64} -> y <= l, iterated(make_slide(r, d, m), (x, y)))

function make_tree(lines::Array{Array{Int64,1},1})
    tree((x, y)::Tuple{Int64, Int64})::Bool = lines[y][x]
end

trees(x::Int64, y::Int64, right::Int64, down::Int64, lines::Array{Array{Int64,1},1}) =
    sum(map(make_tree(lines), route(x, y, right, down, length(lines[1]), length(lines))))

t1 = trees(1, 1, 1, 1, lines)
t2 = trees(1, 1, 3, 1, lines)
t3 = trees(1, 1, 5, 1, lines)
t4 = trees(1, 1, 7, 1, lines)
t5 = trees(1, 1, 1, 2, lines)

println(t2)
println(t1*t2*t3*t4*t5)


workspace()
ENV["JuBrain_Mode"]="MPI"
using JuBrain

model=networkModel()
model.parameters="taupre=20;taupost=20;tmax=50"
model.equations="dapre/dt=-apre/taupre;dapost/dt=-apost/taupost;dW/dt=0"

model.groups=Groups(groupName=[1,2],groupSize=[100,100])
initialize(model,groups=1,expr="tspike=(i-1)*tmax/(100-1)")
initialize(model,groups=2,expr="tspike=(100-i)*tmax/(100-1)")
Connect(model,expr="apre=0.0")
Connect(model,expr="apost=0.0")
Connect(model,expr="W=0.0")
Connect(model,pre=1,post=2,condition="i==j",expr="Apre=0.01")
Connect(model,pre=1,post=2,condition="i==j",expr="Apost=-0.01*1.05")

model.spike="abs(t-tspike).<=0.5/2"
model.plasticity="apre[j,i]+=Apre[j,i];W[j,i]+=apost[j,i];apost[i,j]+=Apost[i,j];W[i,j]+=apre[i,j]"
model.dt=0.5;model.saveVars=["W","tspike"]

model.postProcs="""
@load("Hebbian_code.jld")
using MatlabPlot
index1=model.groups[1][:localindex];index2=model.groups[2][:localindex]
index=sub2ind(size(W),index2,index1)
mplot(tspike[index2]-tspike[index1],W[index])"""

buildnet(name="Hebbian_code",model=model,duration=100)


using LowRankModels
using Plotly

test_losses = Loss[
QuadLoss(),
L1Loss(),
HuberLoss(),
PeriodicLoss(1),
OrdinalHingeLoss(1,10),
WeightedHingeLoss()
LogisticLoss(),
]

#for test_iteration = 1:5
	# Create the configuration for the model (random losses)
	config = round(Int, abs(round(5*rand(length(test_losses)))));
	# config = [1,1,1,1,1,1,10]
	losses, doms = Array(Loss,1), Array(Domain,1);
	for (n,l) in zip(config, test_losses)
		for i=1:n
			push!(losses, l);
			push!(doms, l.domain);
		end
	end
	losses, doms = losses[2:end], doms[2:end]; # this is because the initialization leaves us with an #undef
	# losses = Array(Loss, 20)
	# fill!(losses, QuadLoss())
	# doms = Domain[l.domain for l in losses]

	# Make a low rank matrix as our data precursor
	m, n, true_k = 1000, length(doms), round(Int, round(length(losses)/2));
	X_real, Y_real = 2*randn(m,true_k), 2*randn(true_k,n);
	A_real = X_real*Y_real;

	# Impute over the low rank-precursor to make our heterogenous dataset
	A = impute(doms, losses, A_real);				# our imputed data

	p = Params(1, max_iter=1000, abs_tol=0.000001, min_stepsize=0.001);
	rx, ry = ZeroReg(), ZeroReg();

	skip = 5
	k0=skip
	model = GLRM(A, losses, rx, ry, k0, scale=false, offset=false);
	X_fit, Y_fit, ch = fit!(model, params=p, verbose=false);


function find_target!(m::Model, p::Pedestrian)
    #  find target based on selected target strategy
    find_target!(m.target_strategy, m, p)

    # checks wheter pedestrian is in exit
    if p.isexit && p.pos == p.target
        p.vel = (0., 0.)
        p.finished = true
        return
    end
end

"""
    Nearest <: TargetStrategy

Basic target strategy that selects nearest (euclidian distance) target.

# Fields

- p::Float64 = 0.5
- ε::Float64 = 0.0

"""
Base.@kwdef struct Nearest <: TargetStrategy
    p::Float64 = 0.5
    ε::Float64 = 0
end

function find_target!(s::Nearest, m::Model, p::Pedestrian)
    dist = Inf
    k = length(m.room.checkpoints)

    # find nearest checkpoint
    for (i, t) in enumerate(vcat(m.room.checkpoints, m.room.exits))
        t_pos = nearest(t, p.pos)
        p.pos[2] > t_pos[2] || continue

        d = distance(p.pos, t_pos)
        if d < dist || abs(d - dist) <= s.ε && rand() > s.p
            dist = d
            p.target = t_pos
            p.isexit = i > k
        end
    end
    return
end


using Base.Test
using MathProgBase

function mixintprogtest(solver=MathProgBase.defaultMIPsolver)
    println("Testing mixintprog with solver ", string(typeof(solver)))

    # integer knapsack problem
    sol = mixintprog(-[5,3,2,7,4],Float64[2 8 4 2 5],'<',10,:Int,0,1,solver)
    @test sol.status == :Optimal
    @test_approx_eq_eps sol.objval -16.0 1e-6
    @test_approx_eq_eps norm(sol.sol - [1.0, 0.0, 0.0, 1.0, 1.0]) 0.0 1e-4

    println("Done")
end


function loss()
    mse(ŷ, y, ∂) = loss_mse(ŷ, y, ∂)
    quadratic(ŷ, y, ∂ = false) = loss_quadratic(ŷ, y, ∂)
    ce(ŷ, y, ∂ = false) = loss_cross_entropy(ŷ, y, ∂)
    exp(ŷ, y, ∂ = false) = loss_exponential(ŷ, y, ∂)
    () -> (mse, quadratic, ce, exp)
end

function loss_mse(Ŷ, Y, ∂ = false)
    if ∂ == true
        if length(size(Y)) > 1
            return (2/size(Y)[2] * (Ŷ - Y))
        else
            return (2/size(Y)[1] * (Ŷ - Y))
        end
    else
        return 1/length(Y) * sum(abs2, Y .- Ŷ)
    end
end

function loss_quadratic(Ŷ, Y, ∂ = false)
    return 1/2 * sum(abs2, Y .- Ŷ)
end

function loss_cross_entropy(Ŷ, Y, ∂ = false)
    return 0
end

function loss_exponential(Ŷ, Y, ∂ = false)
    return 0
end


# PREAMBLE

# PKG_SETUP

# ## Setup

using DirectTrajectoryOptimization
using LinearAlgebra
using Plots

# ## horizon
T = 101

# ## acrobot
nx = 4
nu = 1
nw = 0

function acrobot(x, u, w)
    mass1 = 1.0
    inertia1 = 0.33
    length1 = 1.0
    lengthcom1 = 0.5

    mass2 = 1.0
    inertia2 = 0.33
    length2 = 1.0
    lengthcom2 = 0.5

    gravity = 9.81
    friction1 = 0.1
    friction2 = 0.1

    function M(x, w)
        a = (inertia1 + inertia2 + mass2 * length1 * length1
            + 2.0 * mass2 * length1 * lengthcom2 * cos(x[2]))

        b = inertia2 + mass2 * length1 * lengthcom2 * cos(x[2])

        c = inertia2

       return [a b; b c]
    end

    function τ(x, w)
        a = (-1.0 * mass1 * gravity * lengthcom1 * sin(x[1])
            - mass2 * gravity * (length1 * sin(x[1])
            + lengthcom2 * sin(x[1] + x[2])))

        b = -1.0 * mass2 * gravity * lengthcom2 * sin(x[1] + x[2])

        return [a; b]
    end

    function C(x, w)
        a = -2.0 * mass2 * length1 * lengthcom2 * sin(x[2]) * x[4]
        b = -1.0 * mass2 * length1 * lengthcom2 * sin(x[2]) * x[4]
        c = mass2 * length1 * lengthcom2 * sin(x[2]) * x[3]
        d = 0.0

        return [a b; c d]
    end

    function B(x, w)
        [0.0; 1.0]
    end

    q = view(x, 1:2)
    v = view(x, 3:4)

    qdd = M(q, w) \ (-1.0 * C(x, w) * v
            + τ(q, w) + B(q, w) * u[1] - [friction1; friction2] .* v)

    return [x[3]; x[4]; qdd[1]; qdd[2]]
end

function midpoint_implicit(y, x, u, w)
    h = 0.05 # timestep
    y - (x + h * acrobot(0.5 * (x + y), u, w))
end

# ## model
dt = Dynamics(midpoint_implicit, nx, nx, nu, nw=nw)
dyn = [dt for t = 1:T-1]
model = DynamicsModel(dyn)

# ## initialization
x1 = [0.0; 0.0; 0.0; 0.0]
xT = [0.0; π; 0.0; 0.0]

# ## objective
ot = (x, u, w) -> 0.1 * dot(x[3:4], x[3:4]) + 0.1 * dot(u, u)
oT = (x, u, w) -> 0.1 * dot(x[3:4], x[3:4])
ct = Cost(ot, nx, nu, nw, [t for t = 1:T-1])
cT = Cost(oT, nx, 0, nw, [T])
obj = [ct, cT]

# ## constraints
x_init = Bound(nx, nu, [1], xl=x1, xu=x1)
x_goal = Bound(nx, 0, [T], xl=xT, xu=xT)
cons = ConstraintSet([x_init, x_goal], [StageConstraint()])

# ## problem
trajopt = TrajectoryOptimizationProblem(obj, model, cons)
s = Solver(trajopt)

# ## initialize
x_interpolation = linear_interpolation(x1, xT, T)
u_guess = [1.0 * randn(nu) for t = 1:T-1]
z0 = zeros(s.p.num_var)
for (t, idx) in enumerate(s.p.trajopt.model.idx.x)
    z0[idx] = x_interpolation[t]
end
for (t, idx) in enumerate(s.p.trajopt.model.idx.u)
    z0[idx] = u_guess[t]
end
initialize!(s, z0)

# ## solve
@time solve!(s)

# ## solution
@show trajopt.x[1]
@show trajopt.x[T]

# ## state
plot(hcat(trajopt.x...)')

# ## control
plot(hcat(trajopt.u[1:end-1]..., trajopt.u[end-1])', linetype = :steppost)


struct DataMH{vType<:Real}
	h::Vector{vType}
	m::Vector{vType}
end

struct SwParticle{psiType<:Real}
	ψ::psiType
end

function gr!(storage, x, h::Float64, p::MVector)
    storage[1] = -0.5*sin(psi-x[1])+h*sin(x[1])
end

function apply_field(ψ, ϕ, h)
    energy(x) = 0.5*sin(ψ-x[1])^2- h*cos.(x[1])
    gradient(storage, x) = gr!(storage, x, h, p)
    #optimization_result = optimize(energy, [ϕ], Newton())
    optimization_result = optimize(energy,[ϕ], BFGS())
    return Optim.minimizer(optimization_result)[1]
end

function obtain_hysteresis_loop(p::SwParticle)
	hstep = 0.01
    hmax = 2.0
    h = [collect(hmax:-hstep:-hmax); collect(-hmax:hstep:hmax)]
    len = length(h)
    m = zeros(len)

    ϕ = p.ψ
    for i=1:len
        ϕ = apply_field(p.ψ, ϕ, h[i])
        m[i] = cos(ϕ)
    end
	return DataMH(h, m)
end

function calculate_particles(psis, h)
    n = length(psis)
    len = length(h)
    phis = copy(psis)

    m = zeros(len, n)
    for p = 1:n
        for i = 1:len
            phis[p] = apply_field(psis[p], phis[p], h[i])
            m[i,p] = cos(phis[p])
        end
    end
    return m
end

@recipe function plot_one_sw_particle(data::DataMH)
	legend --> :none
	xlabel --> "Field"
	ylabel --> "Magnetization"
	xlim --> (-2.2, 2.2)
	ylim --> (-1.1,1.1)
    aspect_ratio --> [1 2]

    @series begin
        x = vcat((-2.2:0.01:2.2))
        y = vcat(zeros(441))
        linecolor --> :black
        linestyle --> :dash
        (x, y)
    end

    @series begin
        x = vcat(zeros(221))
        y = vcat((-1.1:0.01:1.1))
        linecolor --> :black
        linestyle --> :dash
        (x, y)
	end

	@series begin
        x = vcat((-1:0.01:1), ones(201), (1:-0.01:-1), -1*ones(201))
        y = vcat(ones(201), (1:-0.01:-1), -1*ones(201), (-1:0.01:1))
        linecolor --> :red
        linestyle --> :dash
        (x, y)
	end

    @series begin
        linecolor --> :blue
        linewidth --> 2
        (data.h, data.m)
	end
end


import TPT

using Base.Test

using Plots; pyplot()

println("--- Unit WCA ---")

#
# Single component: Liquid Na
# Ref: I. H. Umar et al.: J. Phys. F: Metal Phys., Vol. 4 (1974), 1691-1706.
#
σ_Na = 6.235

ahs = TPT.AHS(σ = 6.235, ρ = 3.564e-3)
wca = TPT.WCA(ahs, 373)
pseudo = TPT.Ashcroft(1.0, 1.67)
nfe = TPT.NFE(wca, pseudo)
sys = TPT.TPTSystem(wca, nfe, m = 4.191e+4)

residue = sys.ref.residue
σ_estim = TPT.hsdiameter_estimate(nfe, 373.)[1,1]
σ_wca = TPT.hsdiameter(sys.ref)[1,1]

B = TPT.blipfunction(sys.ref)[1,1]
plot(r -> B(r)*r^2, 4, 8, ylims=:auto)

g_ahs = TPT.paircorrelation(ahs)[1,1]
g_wca = TPT.paircorrelation(sys)[1,1]

plot([g_ahs, g_wca], 2, 20, labels = ["AHS" "WCA"], ylims=:auto)

S = TPT.entropy(sys)
U = TPT.internal(sys)
F = TPT.helmholtz(sys)

@testset "Unit WCA" begin
  @test isapprox(residue, 0, atol=1e-4)
  @test isapprox(σ_wca, 6.17, atol=1e-2)
  @test isapprox(S, 7.56, atol=1e-2)
  @test isapprox(U, -0.237, atol=1e-3)
  @test isapprox(F, -0.244, atol=1e-3)
end


in_channel = 3
out_channel = 5
N = 6
adj = [0. 2. 2. 0. 0. 0.;
       2. 0. 1. 0. 2. 0.;
       2. 1. 0. 5. 0. 2.;
       0. 0. 5. 0. 0. 0.;
       0. 2. 0. 0. 0. 0.;
       0. 0. 2. 0. 0. 0.]
deg = [4. 0. 0. 0. 0. 0.;
       0. 5. 0. 0. 0. 0.;
       0. 0. 10. 0. 0. 0.;
       0. 0. 0. 5. 0. 0.;
       0. 0. 0. 0. 2. 0.;
       0. 0. 0. 0. 0. 2.]
lap = [4. -2. -2. 0. 0. 0.;
       -2. 5. -1. 0. -2. 0.;
       -2. -1. 10. -5. 0. -2.;
       0. 0. -5. 5. 0. 0.;
       0. -2. 0. 0. 2. 0.;
       0. 0. -2. 0. 0. 2.]
norm_lap = [1. -2/sqrt(4*5) -2/sqrt(4*10) 0. 0. 0.;
            -2/sqrt(4*5) 1. -1/sqrt(5*10) 0. -2/sqrt(2*5) 0.;
            -2/sqrt(4*10) -1/sqrt(5*10) 1. -5/sqrt(5*10) 0. -2/sqrt(2*10);
            0. 0. -5/sqrt(5*10) 1. 0. 0.;
            0. -2/sqrt(2*5) 0. 0. 1. 0.;
            0. 0. -2/sqrt(2*10) 0. 0. 1.]

ug = SimpleWeightedGraph(6)
add_edge!(ug, 1, 2, 2); add_edge!(ug, 1, 3, 2); add_edge!(ug, 2, 3, 1)
add_edge!(ug, 3, 4, 5); add_edge!(ug, 2, 5, 2); add_edge!(ug, 3, 6, 2)

@testset "weightedgraphs" begin
    @testset "linalg" begin
        for T in [Int8, Int16, Int32, Int64, Int128]
            @test degree_matrix(adj, T, dir=:out) == T.(deg)
            @test degree_matrix(adj, T, dir=:out) == degree_matrix(adj, T, dir=:in)
            @test degree_matrix(adj, T, dir=:out) == degree_matrix(adj, T, dir=:both)
            @test laplacian_matrix(adj, T) == T.(lap)
        end
        for T in [Float16, Float32, Float64]
            @test degree_matrix(adj, T, dir=:out) == T.(deg)
            @test degree_matrix(adj, T, dir=:out) == degree_matrix(adj, T, dir=:in)
            @test degree_matrix(adj, T, dir=:out) == degree_matrix(adj, T, dir=:both)
            @test laplacian_matrix(adj, T) == T.(lap)
            @test normalized_laplacian(adj, T) ≈ T.(norm_lap)
        end
    end

    @testset "GCNConv" begin
        gc = GCNConv(ug, in_channel=>out_channel)
        @test size(gc.weight) == (out_channel, in_channel)
        @test size(gc.bias) == (out_channel,)
        @test graph(gc.graph)[] === ug
    end

    @testset "ChebConv" begin
        k = 4
        cc = ChebConv(ug, in_channel=>out_channel, k)
        @test size(cc.weight) == (out_channel, in_channel, k)
        @test size(cc.bias) == (out_channel,)
        @test size(cc.L̃) == (N, N)
        @test cc.k == k
        @test cc.in_channel == in_channel
        @test cc.out_channel == out_channel
    end

    @testset "GraphConv" begin
        gc = GraphConv(ug, in_channel=>out_channel)
        @test gc.adjlist == [[2,3], [1,3,5], [1,2,4,6], [3], [2], [3]]
        @test size(gc.weight1) == (out_channel, in_channel)
        @test size(gc.weight2) == (out_channel, in_channel)
        @test size(gc.bias) == (out_channel,)
    end

    @testset "GATConv" begin
        for heads = [1, 5]
            for concat = [true, false]
                gat = GATConv(ug, in_channel=>out_channel, heads=heads, concat=concat)
                @test gat.adjlist == [[2,3], [1,3,5], [1,2,4,6], [3], [2], [3]]
                @test size(gat.weight) == (out_channel * heads, in_channel)
                @test size(gat.bias) == (out_channel * heads,)
                @test size(gat.a) == (2*out_channel, heads, 1)
            end
        end
    end

    @testset "GatedGraphConv" begin
        num_layers = 3
        ggc = GatedGraphConv(ug, out_channel, num_layers)
        @test ggc.adjlist == [[2,3], [1,3,5], [1,2,4,6], [3], [2], [3]]
        @test size(ggc.weight) == (out_channel, out_channel, num_layers)
    end

    @testset "EdgeConv" begin
        ec = EdgeConv(ug, Dense(2*in_channel, out_channel))
        @test ec.adjlist == [[2,3], [1,3,5], [1,2,4,6], [3], [2], [3]]
    end
end


using Raytracing

using GeometryBasics
using Random
using CoordinateTransformations
using ColorTypes
using ColorVectorSpace
using StaticArrays
using Images
using ImageIO
using FileIO
using ImageMagick

function main()
    T = Float64
    origin = Point3{T}(0,0,1.5)
    lookat = Point3{T}(0,0,0)
    vup = Vec3{T}(0,1,0)
    aspectratio = T(16/9)
    vfov = T(40)
    camera = Raytracing.make_camera(origin, lookat, vup, vfov, aspectratio)

    #spheresdf = Raytracing.SphereSignedDistanceField{T}(0.5)

    mandelsdf = Raytracing.MandelBulbSignedDistanceField(50)
    boundingmandelspheresdf = Raytracing.SphereSignedDistanceField{T}(1.25)
    overshootfactor = T(1.5)
    boundingmandelsdf = Raytracing.BoundingVolumeSignedDistanceField(overshootfactor, boundingmandelspheresdf, mandelsdf)

    point = Point3{T}(0, 0, 1)
    mandelsdf(point)
    Raytracing.normalforwarddiff(mandelsdf, point)

    normalmat = Raytracing.NormalShading()

    id = IdentityTransformation()
    mandelalbedo = Vec{3, T}(0.8, 0.25, 0.25)

    #lambertianmat = Raytracing.Lambertian(mandelalbedo)

    #mandelshape = Raytracing.Shape(id, mandelsdf, lambertianmat)
    mandelshape = Raytracing.Shape(id, boundingmandelsdf, normalmat)
    #mandelshape = Raytracing.Shape(id, mandelsdf, normalmat)

    skyboxspheresdf = Raytracing.SphereSignedDistanceField{T}(100)
    skyboxsphereshape = Raytracing.Shape(id, skyboxspheresdf, normalmat)

    sceneshapes = (skyboxsphereshape, mandelshape)
    scene = Raytracing.Scene(sceneshapes)

    image_height = 100
    samples_per_pixel = 3
    max_bounces_per_ray = 1
    max_steps_per_bounce = 400
    distance_tolerance = 1e-4
    rng = MersenneTwister(1234)
    rat = 2.0 / 0.70
    len = 1.2
    camera3 = Raytracing.make_camera(Point3{T}(0.0, rat * len, 1/rat * len), lookat, vup, vfov, aspectratio)
    @time image = Raytracing.raytrace_image(scene, camera3, image_height, samples_per_pixel, max_bounces_per_ray, max_steps_per_bounce, distance_tolerance, rng)

    savename = "lofi_mandelbulb_50_normalshading.png"
    lofibig = Raytracing.supersample_crisp(image, 10)
    Raytracing.saveimage("$(savename)", lofibig)

end