### A Pluto.jl notebook ###
# v0.14.6

using Markdown
using InteractiveUtils

# ╔═╡ af7d7414-fd27-428b-8d15-fe257171235a
begin
    import Pkg
    Pkg.activate(mktempdir())
    Pkg.add([
        Pkg.PackageSpec(name="Plots", version="1"),
        Pkg.PackageSpec(name="PlutoUI", version="0.7"),
	    Pkg.PackageSpec(name="DifferentialEquations", version="6"),
	    Pkg.PackageSpec(name="Parameters", version="0.12"),
        Pkg.PackageSpec(name="LabelledArrays", version="1"),
        Pkg.PackageSpec(name="Setfield", version="0.7"),
    ])
    using Plots, PlutoUI, LinearAlgebra, DifferentialEquations, Parameters, LabelledArrays, Setfield

	Plots.gr(fmt=:png, lw=2)

	PlutoUI.TableOfContents()
end

# ╔═╡ 31db8eee-bdcd-11eb-0551-550c86cfaf1d
md"""
# Figure 2.11-14 Model reduction
"""

# ╔═╡ d586f4bf-04ad-4a1d-9342-8be444b14cc0
md"""
## Figure 2.11 : Full model

The full biochemical reaction model
"""

# ╔═╡ 6e39ed5d-21e3-4c9d-8d4b-fb30c8bf555c
# Fig 2.11: Full model
function fullmodel!(du, u, p, t)
	@unpack K0, K1, KM1, K2 = p
	@unpack a, b = u
	vAB = K1 * a - KM1 * b
	du.a = K0 - vAB
	du.b = vAB - K2 * b
	return du
end

# ╔═╡ d0392260-fbf8-4caa-baaa-4b282c45be5c
# Fig 2.12: rapid equilibrium
function remodel!(du, u, p, t)
	@unpack K0, K1, KM1, K2 = p
	kb = K2 * K1 / (KM1 + K1)
	du.b = K0 - kb * u.b
end

# ╔═╡ f856c00b-af34-49b4-a4aa-c1f16aac26dc
# Figure 2.14: Quasi-steady state assumption(QSSA)
function qssmodel!(du, u, p, t)
	@unpack K0, K2 = p
	du.b = K0 - K2 * u.b
end

# ╔═╡ 1586dd9d-7bb7-41e0-90c3-fd9b5d25b1e6
p1 = (K0=0, K1=9, KM1=12, K2=2)

# ╔═╡ 995aabe8-1cb4-4c51-8d83-e57b64db61de
u0 = LVector(a=0.0, b=10.0)

# ╔═╡ 43e4e3fd-881d-4556-927b-3acf715a97a0
sol1 = solve(ODEProblem(fullmodel!, u0, 3.0, p1));

# ╔═╡ 09e0bd1f-8c5c-45cd-b15e-36a473cb8bb7
plot(sol1, xlabel="Time (arbitrary units)", ylabel="Concentration (arbitrary units)", title="Fig. 2.11 (Full model)", label=["A" "B"])

# ╔═╡ a5205bb5-5bd5-4481-b02d-a41b4fa1c0c4
md"""
## Figure 2.12 : Rapid equilibrium
"""

# ╔═╡ dad21a13-b6cd-42e9-9e91-7d1cad429a2f
u0re = LVector(b=sum(u0))

# ╔═╡ d081fbfb-38e5-41f3-a7df-15aeaad241d5
sol2 = solve(ODEProblem(remodel!, u0re, 3.0, p1));

# ╔═╡ e62303ee-bfc2-4739-937a-0b3dcfb2fd70
let tspan = 3.0
	ts = 0.0:0.1:tspan
	btilde = sol2(ts, idxs=1)
	pl2 = plot(sol1, line=(:dash, 1),label=["A (full solution)" "B (full solution)"])
	plot!(pl2, ts, (p1.KM1 / (p1.KM1 + p1.K1)) .* btilde, lab="A (rapid equilibrium)")
	plot!(pl2, ts, (p1.K1 / (p1.KM1 + p1.K1))  .* btilde, lab="B (rapid equilibrium)")
	plot!(pl2, title="Fig. 2.12 (Rapid equilibrium model)", xlabel="Time (arbitrary units)", ylabel="Concentration (arbitrary units)")
	pl2
end

# ╔═╡ 04c217c0-b45a-424d-9177-ba7572234683
md"""
## Figure 2.13: Rapid equilibrium

with another set of parameters
"""

# ╔═╡ 04496970-ea81-4e8c-b118-1a0be3333f43
p2 = (K0=9, K1=20, KM1=12, K2=2)

# ╔═╡ a6a3c147-ea6a-48c7-953e-658e66308c8c
u1 = LVector(a=8.0, b=4.0)

# ╔═╡ 1b7435f1-b60b-45d5-b647-d725c4f6d923
u1re = LVector(b=sum(u1))

# ╔═╡ fb63ca02-c5cd-4a1d-af76-9df041f0878a
sol3full = solve(ODEProblem(fullmodel!, u1, 3.0, p2));

# ╔═╡ 2c7610b1-6c25-40a3-8744-4ac561a8404a
sol3re = solve(ODEProblem(remodel!, u0re, 3.0, p2));

# ╔═╡ 7848a37a-ba43-4157-a2ce-97646ebf9e16
let tspan = 3.0
	ts = 0.0:0.1:tspan
	btilde = sol3re(ts, idxs=1)
	pl3 = plot(title="Fig. 2.13 Ref vs Fast equlibrium", xlabel="Time (arbitrary units)", ylabel="Concentration (arbitrary units)")
	plot!(pl3, sol3full, line=(:dash, 1),label=["A (full solution)" "B (full solution)"])
	plot!(pl3, ts, (p2.KM1 / (p2.KM1 + p2.K1)) .* btilde, lab="A (rapid equilibrium)")
	plot!(pl3, ts, (p2.K1 / (p2.KM1 + p2.K1))  .* btilde, lab="B (rapid equilibrium)")
	pl3
end

# ╔═╡ 626bdf4b-909d-42d3-aacd-6e30fc207494
md"""
## Figure 2.14 : QSSA

Quasi-steady state assumption on species A
"""

# ╔═╡ e4c8977b-5953-4155-bb10-b0da46080448
u1qss = LVector(b = (p2.K1 * sum(u1) - p2.K0) / (p2.K1 + p2.KM1))

# ╔═╡ 5dba1b2f-92fc-4790-b42d-44506f1e7c32
sol4 = solve(ODEProblem(qssmodel!, u1qss, 3.0, p2));

# ╔═╡ ef9ad709-6ba6-47f4-989d-d1e885b6b8a9
let tspan = 3.0
	ts = 0.0:0.1:tspan
	btilde = sol4(ts, idxs=1)
	pl4 = plot(sol3full, line=(:dash, 2), xlims=tspan,
     xlabel="Time (arbitrary units)",
     ylabel="Concentration (arbitrary units)",
     title="Figure 2.14: Ref vs QSSA")

	plot!(pl4, sol4, label="B (QSSA)", line=(2, :red))
	plot!(pl4, ts, (p2.K0 .+ p2.KM1 .* btilde) ./ p2.K1, label="A (QSSA)", line=(2, :blue))

	pl4
end

# ╔═╡ cd91c608-8b31-4fa3-9e22-176b58d89872
md"""
## Appendix
Running environment and some auxillary functions.

**You can use [this helper tool](https://fonsp.com/article-test-3/pkghelper.html) to generate these commands!**
"""

# ╔═╡ 3653bbec-0e6e-40de-b926-4bb757213ad8
begin
	# Convenience functions
    hill(x, k) = x / (x + k)
    hill(x, k, n) = hill(x^n, k^n)
    exprel(x) = ifelse(x≈zero(x), one(x), x / expm1(x))
end

# ╔═╡ Cell order:
# ╠═31db8eee-bdcd-11eb-0551-550c86cfaf1d
# ╠═d586f4bf-04ad-4a1d-9342-8be444b14cc0
# ╠═6e39ed5d-21e3-4c9d-8d4b-fb30c8bf555c
# ╠═d0392260-fbf8-4caa-baaa-4b282c45be5c
# ╠═f856c00b-af34-49b4-a4aa-c1f16aac26dc
# ╠═1586dd9d-7bb7-41e0-90c3-fd9b5d25b1e6
# ╠═995aabe8-1cb4-4c51-8d83-e57b64db61de
# ╠═43e4e3fd-881d-4556-927b-3acf715a97a0
# ╠═09e0bd1f-8c5c-45cd-b15e-36a473cb8bb7
# ╠═a5205bb5-5bd5-4481-b02d-a41b4fa1c0c4
# ╠═dad21a13-b6cd-42e9-9e91-7d1cad429a2f
# ╠═d081fbfb-38e5-41f3-a7df-15aeaad241d5
# ╠═e62303ee-bfc2-4739-937a-0b3dcfb2fd70
# ╠═04c217c0-b45a-424d-9177-ba7572234683
# ╠═04496970-ea81-4e8c-b118-1a0be3333f43
# ╠═a6a3c147-ea6a-48c7-953e-658e66308c8c
# ╠═1b7435f1-b60b-45d5-b647-d725c4f6d923
# ╠═fb63ca02-c5cd-4a1d-af76-9df041f0878a
# ╠═2c7610b1-6c25-40a3-8744-4ac561a8404a
# ╠═7848a37a-ba43-4157-a2ce-97646ebf9e16
# ╠═626bdf4b-909d-42d3-aacd-6e30fc207494
# ╠═e4c8977b-5953-4155-bb10-b0da46080448
# ╠═5dba1b2f-92fc-4790-b42d-44506f1e7c32
# ╠═ef9ad709-6ba6-47f4-989d-d1e885b6b8a9
# ╠═cd91c608-8b31-4fa3-9e22-176b58d89872
# ╠═3653bbec-0e6e-40de-b926-4bb757213ad8
# ╠═af7d7414-fd27-428b-8d15-fe257171235a


using Flora.RNN
using MLDatasets # FashionMNIST

# load full test set
test_x,  test_y  = FashionMNIST.testdata() # 10_000

picks = [
    [0, 3, 9], # 0 T-Shirt, 3 Dress, 9 Ankle boot
    [1, 2, 5],
]

for pick in picks
    p = load(:fashion, pick)
    tX, tY = prepare(test_x, test_y, pick)
    show_accuracy(p.m, p.pick, tX, tY)
end

#=
pick = [0, 3, 9]
mean(argmax(m(x)) .== argmax(y)) = 0.929
pick = [1, 2, 5]
mean(argmax(m(x)) .== argmax(y)) = 0.9866666666666667
=#


test_gage_principal_axes(
    [1. 1. 0.;
     0. 0. 0.;],
    [sqrt(2)/2. -sqrt(2)/2. 0.0;
     sqrt(2)/2. sqrt(2)/2. 0.0;
     0.0 0.0 1.0], "vector in the X-Y plane")


struct ControlComplementarity <: Constraints
    n
    ineq
    n_stage
end

function constraints!(c, Z, con::ControlComplementarity, model, idx, h, T)
    for t = 1:T-1
        x⁺ = view(Z, idx.x[t+1])
        q⁺ = view(x⁺, model.nq .+ (1:model.nq))
        u = view(Z, idx.u[t])

        c[(t - 1) * con.n_stage .+ (1:1)] = u[model.idx_s] - u[model.idx_u][1] * ϕ_func(model, q⁺)
        c[(t - 1) * con.n_stage + 1 .+ (1:1)] = u[model.idx_s] - u[model.idx_u][2] * ϕ_func(model, q⁺)
    end
    nothing
end

function constraints_jacobian!(∇c, Z, con::ControlComplementarity, model, idx, h, T)

    shift = 0

    for t = 1:T-1
        x⁺ = view(Z, idx.x[t+1])
        q⁺ = view(x⁺, model.nq .+ (1:model.nq))
        u = view(Z, idx.u[t])

        cq1(y) = u[model.idx_s] - u[model.idx_u][1] * ϕ_func(model, y)
        cu1(y) = y[model.idx_s] - y[model.idx_u][1] * ϕ_func(model, q⁺)
        cq2(y) = u[model.idx_s] - u[model.idx_u][2] * ϕ_func(model, y)
        cu2(y) = y[model.idx_s] - y[model.idx_u][2] * ϕ_func(model, q⁺)

        r_idx = (t - 1) * con.n_stage .+ (1:1)

        c_idx = idx.x[t+1][model.nq .+ (1:model.nq)]
        len = length(r_idx) * length(c_idx)
        ForwardDiff.jacobian!(reshape(view(∇c, shift .+ (1:len)),
            1, model.nq),
            cq1, q⁺)
        shift += len

        c_idx = idx.u[t]
        len = length(r_idx) * length(c_idx)
        ForwardDiff.jacobian!(reshape(view(∇c, shift .+ (1:len)),
            1, model.m),
            cu1, u)
        shift += len

        r_idx = (t - 1) * con.n_stage + 1 .+ (1:1)

        c_idx = idx.x[t+1][model.nq .+ (1:model.nq)]
        len = length(r_idx) * length(c_idx)
        ForwardDiff.jacobian!(reshape(view(∇c, shift .+ (1:len)),
            1, model.nq),
            cq2, q⁺)
        shift += len

        c_idx = idx.u[t]
        len = length(r_idx) * length(c_idx)
        ForwardDiff.jacobian!(reshape(view(∇c, shift .+ (1:len)),
            1, model.m),
            cu2, u)
        shift += len
    end

    return nothing
end

function constraints_sparsity(con::ControlComplementarity, model, idx, T;
    shift_row = 0, shift_col = 0)
    row = []
    col = []

    for t = 1:T-1

        r_idx = shift_row + (t - 1) * con.n_stage .+ (1:1)

        c_idx = shift_col .+ idx.x[t+1][model.nq .+ (1:model.nq)]
        row_col!(row, col, r_idx, c_idx)

        c_idx = shift_col .+ idx.u[t]
        row_col!(row, col, r_idx, c_idx)

        r_idx = shift_row + (t - 1) * con.n_stage + 1 .+ (1:1)

        c_idx = shift_col .+ idx.x[t+1][model.nq .+ (1:model.nq)]
        row_col!(row, col, r_idx, c_idx)

        c_idx = shift_col .+ idx.u[t]
        row_col!(row, col, r_idx, c_idx)
    end

    return collect(zip(row, col))
end


struct TreeData
    last_node_size::Int    # Number of points in the last node
    leafsize::Int          # Number of points in each leaf node (except last)
    n_leafs::Int           # Number of leafs
    n_internal_nodes::Int  # Number of non leaf nodes
    cross_node::Int
    offset::Int
    offset_cross::Int
    last_full_node::Int
end

function TreeData(data::AbstractVector{V}, leafsize) where V
    n_dim, n_p = length(V), length(data)

    # If number of points is zero
    n_p == 0 && return TreeData(0, 0, 0, 0, 0, 0, 0, 0)

    n_leafs =  ceil(Integer, n_p / leafsize)
    n_internal_nodes = n_leafs - 1
    leafrow = floor(Integer, log2(n_leafs))
    cross_node = 2^(leafrow + 1)
    last_node_size = n_p % leafsize
    if last_node_size == 0
        last_node_size = leafsize
    end

    # This only happens when n_p / leafsize is a power of 2?
    if cross_node >= n_internal_nodes + n_leafs
        cross_node = div(cross_node, 2)
    end

    offset = 2(n_leafs - 2^leafrow) - 1
    k1 = (offset - n_internal_nodes - 1) * leafsize + last_node_size + 1
    k2 = -cross_node * leafsize + 1
    last_full_node = n_leafs + n_internal_nodes

    TreeData(last_node_size, leafsize, n_leafs,
    n_internal_nodes, cross_node, k1, k2, last_full_node)
end


####
# This file shows how the ∞-dimensional QL decomposition can be used
# for spectral theory of Toeplitz operators. We investigate the
# QL decomposition on each of the examples in Trefethen & Embree.
#

using InfiniteLinearAlgebra, BandedMatrices, PyPlot

###
# Basic routines for plotting
###

function ℓ11(A,λ; kwds...)
    try
        abs(ql(A-λ*I; kwds...).L[1,1])
    catch DomainError
        -1.0
    end
end

function branch(k)
    function(λ)
        j = sortperm(λ)[end-k+1]
        λ[j], j
    end
end

qlplot(A::AbstractMatrix; kwds...) = qlplot(BandedMatrix(A); kwds...)
function qlplot(A::BandedMatrix; branch=findmax, x=range(-4,4; length=200), y=range(-4,4;length=200), kwds...)
    z = ℓ11.(Ref(A), x' .+ y.*im; branch=branch)
    contourf(x,y,z; kwds...)
end

toepcoeffs(A::BandedMatrix) = InfiniteLinearAlgebra.rightasymptotics(A.data).args[1]
toepcoeffs(A::Adjoint) = reverse(toepcoeffs(A'))

function symbolplot(A::BandedMatrix; kwds...)
    l,u = bandwidths(A)
    a = toepcoeffs(A)
    θ = range(0,2π; length=1000)
    i = map(t -> dot(exp.(im.*(u:-1:-l).*t),a),θ)
    plot(real.(i), imag.(i); kwds...)
end

###
# Trefethen & Embree example
###

A = BandedMatrix(1 => Fill(2im,∞), 2 => Fill(-1,∞), 3 => Fill(2,∞), -2 => Fill(-4,∞), -3 => Fill(-2im,∞))
clf(); qlplot(A; x=range(-10,7; length=100), y=range(-7,8;length=100)); symbolplot(A; color=:black); title("Trefethen & Embree")
clf(); qlplot(transpose(A); x=range(-10,7; length=200), y=range(-7,8;length=200)); symbolplot(A; color=:black); title("Trefethen & Embree, transpose")

###
# limaçon
###

A = BandedMatrix(-2 => Fill(1.0,∞), -1 => Fill(1.0,∞), 1 => Fill(eps(),∞))
qlplot(A; x=range(-2,3; length=100), y=range(-2.5,2.5;length=100)); symbolplot(A; color=:black); title("Limacon")
clf(); qlplot(A; branch=findsecond, x=range(-2,3; length=100), y=range(-2.5,2.5;length=100)); symbolplot(A; color=:black); title("Limacon, second branch")
clf(); qlplot(transpose(A); x=range(-2,3; length=100), y=range(-2.5,2.5;length=100)); symbolplot(A; color=:black); title("Limacon, transpose")

###
# bull-head
###

A = BandedMatrix(-3 => Fill(7/10,∞), -2 => Fill(1,∞), 1 => Fill(2im,∞))
clf(); qlplot(A; x=range(-10,7; length=100), y=range(-7,8;length=100)); symbolplot(A; color=:black); title("Bull-head")
clf(); qlplot(transpose(A); x=range(-10,7; length=100), y=range(-7,8;length=100)); symbolplot(A; color=:black); title("Bull-head, transpose")

###
# Grcar
###

A = BandedMatrix(-3 => Fill(1,∞), -2 => Fill(1,∞), -1 => Fill(1,∞), 0 => Fill(1,∞), 1 => Fill(-1,∞))
clf(); qlplot(A; x=range(-4,5; length=100), y=range(-6,5;length=100)); symbolplot(A; color=:black); title("Grcar")
clf(); qlplot(A; branch=branch(2), x=range(-4,5; length=100), y=range(-6,5;length=100)); symbolplot(A; color=:black); title("Grcar, branch 2")
clf(); qlplot(A; branch=branch(3), x=range(-4,5; length=100), y=range(-6,5;length=100)); symbolplot(A; color=:black); title("Grcar, branch 3")
clf(); qlplot(transpose(A); x=range(-4,5; length=100), y=range(-6,5;length=100)); symbolplot(A; color=:black); title("Grcar, transpose")

###
# Triangle
###

A = BandedMatrix(-2 => Fill(1/4,∞), 1 => Fill(1,∞))
clf(); qlplot(A; x=range(-2,2; length=100), y=range(-2,2;length=100)); symbolplot(A; color=:black); title("Triangle")
clf(); qlplot(transpose(A); x=range(-2,2; length=100), y=range(-2,2;length=100)); symbolplot(A; color=:black); title("Triangle, transpose")
clf(); qlplot(transpose(A); branch=branch(2), x=range(-2,2; length=100), y=range(-2,2;length=100)); symbolplot(A; color=:black); title("Triangle, transpose, branch 2")

###
# Whale
###

A = BandedMatrix(-4 => Fill(im,∞), -3 => Fill(4,∞), -2 => Fill(3+im,∞), -1 => Fill(10,∞),
                    1 => Fill(1,∞), 2 => Fill(im,∞), 3 => Fill(-(3+2im),∞), 4=>Fill(-1,∞))

clf(); qlplot(A; x=range(-15,20; length=100), y=range(-20,20;length=100)); symbolplot(A; color=:black); title("Whale")
clf(); qlplot(transpose(A); x=range(-15,20; length=100), y=range(-20,20;length=100)); symbolplot(A; color=:black); title("Whale, transpose")

###
# Butterfly
###

A = BandedMatrix(-2 => Fill(1,∞), -1 => Fill(-im,∞), 1 => Fill(im,∞), 2 => Fill(-1,∞))
clf(); qlplot(A; x=range(-3,3; length=100), y=range(-3,3;length=100)); symbolplot(A; color=:black); title("Butterfly")
clf(); qlplot(A; branch=branch(2), x=range(-3,3; length=100), y=range(-3,3;length=100)); symbolplot(A; color=:black); title("Butterfly, branch 2")
clf(); qlplot(transpose(A); x=range(-3,3; length=100), y=range(-3,3;length=100)); symbolplot(A; color=:black); title("Butterfly")
clf(); qlplot(transpose(A); branch=branch(2), x=range(-3,3; length=100), y=range(-3,3;length=100)); symbolplot(A; color=:black); title("Butterfly")


@testset "Spatial domain" begin
  @testset "RegularGrid" begin
    grid = RegularGrid{Float32}(200,100)
    @test ndims(grid) == 2
    @test coordtype(grid) == Float32
    @test size(grid) == (200,100)
    @test npoints(grid) == 200*100
    @test coordinates(grid, 1) == [0.,0.]
    @test origin(grid) == (0f0, 0f0)
    @test spacing(grid) == (1f0, 1f0)

    grid = RegularGrid((200,100,50), (0.,0.,0.), (1.,1.,1.))
    @test ndims(grid) == 3
    @test coordtype(grid) == Float64
    @test size(grid) == (200,100,50)
    @test npoints(grid) == 200*100*50
    @test coordinates(grid, 1) == [0.,0.,0.]
    @test origin(grid) == (0.,0.,0.)
    @test spacing(grid) == (1.,1.,1.)

    grid = RegularGrid((-1.,-1.), (1.,1.), dims=(200,100))
    @test ndims(grid) == 2
    @test coordtype(grid) == Float64
    @test size(grid) == (200,100)
    @test npoints(grid) == 200*100
    @test coordinates(grid, 1) == [-1.,-1.]
    @test coordinates(grid, 200*100) == [1.,1.]
    @test origin(grid) == (-1.,-1.)

    grid = RegularGrid{Float64}(100,200)
    @test sprint(show, grid) == "100×200 RegularGrid{Float64,2}"
    @test sprint(show, MIME"text/plain"(), grid) == "RegularGrid{Float64,2}\n  dimensions: (100, 200)\n  origin:     (0.0, 0.0)\n  spacing:    (1.0, 1.0)"
  end

  @testset "PointSet" begin
    ps = PointSet([1. 0.; 0. 1.])
    @test npoints(ps) == 2
    @test coordinates(ps, 1) == [1., 0.]
    @test coordinates(ps, 2) == [0., 1.]

    @test sprint(show, ps) == "2×2 PointSet{Float64,2}"
    @test sprint(show, MIME"text/plain"(), ps) == "2×2 PointSet{Float64,2}\n 1.0  0.0\n 0.0  1.0"
  end
end


using BenchmarkTools
using DelimitedFiles

q = [0.001,0.002,0.003,0.003,0.004,0.004,0.005,0.007,0.009,0.011]
w = [0.05,0.07,0.08,0.10,0.14,0.20,0.20,0.20,0.10,0.04]
P = 100
S = 25000
r = 0.02

function npv1(q,w,P,S,r)
	inforce = [1.; cumprod(1 .- q .- w)[1:end-1]]
  	ncf = inforce .* P .- inforce .* q .* S
 	d = (1 ./ (1 + r)) .^ (1:length(ncf))
  	return sum(ncf .* d)
end

function npv2(q,w,P,S,r)
	inforce = append!([1.0],@view cumprod(1 .- q .- w)[1:end-1])
  	ncf = inforce .* P .- inforce .* q .* S
 	d = (1 ./ (1 + r)) .^ (1:length(ncf))
  	return sum(ncf .* d)
end

@inline function npv3(q,w,P,S,r,term=nothing)
    term = term === nothing ? length(q) + 1 : term + 1
    inforce = 1.0
    result = 0.0
    v = (1 / ( 1 + r))
    v_t = v

    for (t,(q,w)) in enumerate(zip(q,w))
        deaths = t < term ? inforce * q : 0.0
        lapses = t < term ? inforce * w : 0.0
        premiums = inforce * P
        claims = deaths * S
        ncf = premiums - claims
        result += ncf *  v_t
        v_t *= v
        inforce = inforce - deaths - lapses
    end

    return result
end

@inline function npv4(q,w,P,S,r,term=nothing)
    term = term === nothing ? length(q) : term
    inforce = 1.0
    result = 0.0
    v = (1 / ( 1 + r))
    v_t = v

    for (t,(q,w)) in enumerate(zip(q,w))
        t > term && return result
        result += inforce * (P - S * q) * v_t
        inforce -= inforce * q + inforce * w
        v_t *= v
    end

    return result
end

# suggested by Stefan Karpinski
@inline function npv5(q,w,P,S,r,term=nothing)
    term = term === nothing ? length(q) : term
    inforce = 1.0
    result = 0.0
    v = (1 / ( 1 + r))
    v_t = v
    for (q,w,_) in zip(q,w,1:term)
        result += inforce * (P - S * q) * v_t
        inforce -= inforce * q + inforce * w
        v_t *= v
    end
    return result
end

# suggested by Michael Abbott
@inline function npv6(qs,ws,P,S,r,term=length(qs))
    inforce, result = 1.0, 0.0
    v = 1 / ( 1 + r)
    v_t = v

    for t in 1:min(term, length(qs), length(ws))
        @inbounds q, w = qs[t], ws[t]
        result += inforce * (P - S * q) * v_t
        inforce -= inforce * (q + w)
        v_t *= v
    end

    return result
end

# suggested by Peter J
@inline function npv7(qs,ws,P,S,r,term=length(qs))
    inforce, result = 1.0, 0.0
    v = 1 / ( 1 + r)
    v_t = v

    for t in 1:min(term, length(qs), length(ws))
        @inbounds q, w = qs[t], ws[t]
        result += inforce * (P - S * q) * v_t
        inforce = inforce*(1 - (q + w))
        v_t *= v
    end

    return result
end

# suggested by Peter J
@inline function npv8(qs,ws,P,S,r,term=length(qs))
    inforce, result = 1.0, 0.0
    v = 1 / ( 1 + r)
    v_t = v
    @inbounds @simd for t in 1:min(term, length(qs), length(ws))
        q, w = qs[t], ws[t]
        result += inforce * (P - S * q) * v_t
        inforce = inforce*(1 - (q + w))
        v_t *= v
    end
    return result
end

# suggested by Michael Abbott
@inline function npv9(qs,ws,P,S,r,term=length(qs))
    inforce, result = 1.0, 0.0
    v = 1 / ( 1 + r)
    v_t = v
    @inbounds @fastmath for t in 1:min(term, length(qs), length(ws))
        q, w = qs[t], ws[t]
        result += inforce * (P - S * q) * v_t
        inforce = inforce*(1 - (q + w))
        v_t *= v
    end
    return result
end

results = map([npv1,npv2,npv3,npv4,npv5,npv6,npv7,npv8,npv9]) do f
    b = @benchmark $f($q,$w,$P,$S,$r)
    (f="$f",mean=mean(b),median=median(b))
end

writedlm("julia_results.csv",results, ',')


# ---
# title: 149. Max Points on a Line
# id: problem149
# author: Tian Jun
# date: 2020-10-31
# difficulty: Hard
# categories: Hash Table, Math
# link: <https://leetcode.com/problems/max-points-on-a-line/description/>
# hidden: true
# ---
#
# Given _n_ points on a 2D plane, find the maximum number of points that lie on
# the same straight line.
#
# **Example 1:**
#
#
#
#     Input: [[1,1],[2,2],[3,3]]
#     Output: 3
#     Explanation:
#     ^
#     |
#     |        o
#     |     o
#     |  o
#     +------------->
#     0  1  2  3  4
#
#
# **Example 2:**
#
#
#
#     Input: [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
#     Output: 4
#     Explanation:
#     ^
#     |
#     |  o
#     |     o        o
#     |        o
#     |  o        o
#     +------------------->
#     0  1  2  3  4  5  6
#
#
# **NOTE:**  input types have been changed on April 15, 2019. Please reset to
# default code definition to get new method signature.
#
#
## @lc code=start
using LeetCode

## add your code here:
## @lc code=end


module List
import Base: length, (:), map, iterate, reverse, filter
export list, cons, nil, linkedlist, (^)

# if generic:
# map(f, l :: nil{T} ) where T  = nil()

abstract type linkedlist end

struct cons <: linkedlist
    head
    tail :: linkedlist
end

struct nil <: linkedlist end

length(l :: nil) = 0
length(l :: cons) = 1 + length(l.tail)

head(l :: nil )   = nothing
head(l :: cons)   = l.head

tail(l :: nil )   = nothing
tail(l :: cons)   = l.tail

iter(f, l :: nil )  = nothing
iter(f, l :: cons)  = begin f(l.head); iter(f, l.tail) end

map(f, l :: nil )   = nil()
map(f, l :: cons)   = cons(f(l.head), map(f, l.tail))

(^)(hd, tl :: linkedlist) = cons(hd, tl)

function filter(f :: Function, l :: linkedlist)
    l2 = nil()
    for h in l
        if f(h)
          l2 = cons(h, l2)
        end
    end
    reverse(l2)
end

iterate(l :: linkedlist, ::nil) = nothing
function iterate(l :: linkedlist, state::cons = l)
    state.head, state.tail
end

function reverse(l :: linkedlist)
    l2 = nil()
    for hd in l
        l2 = cons(hd, l2)
    end
    l2
end

function list(xs...)
    l = nil()
    for i=length(xs):-1:1
        l = cons(xs[i], l)
    end
    l
end

end


### A Pluto.jl notebook ###
# v0.19.2

using Markdown
using InteractiveUtils

# ╔═╡ 22c33fe6-4efd-11ec-351c-25a9d73ec50a
# ╠═╡ show_logs = false
begin
	let
		using Pkg
		Pkg.activate(mktempdir())
		Pkg.Registry.update()
		Pkg.add("PlutoUI")
		Pkg.add("CairoMakie")
		Pkg.add("BenchmarkTools")
		Pkg.add(url="https://github.com/Dale-Black/DistanceTransforms.jl")
	end

	using PlutoUI
	using CairoMakie
	using BenchmarkTools
	using DistanceTransforms
end

# ╔═╡ 0095c4d9-e9d0-4769-83ff-fd7f4346be8f
md"""
## Import packages
First, let's import the most up-to-date version of DistanceTransforms.jl, which can be found on the main/master branch of the [GitHub repository](https://github.com/Dale-Black/DistanceTransforms.jl).

Because we are using the unregistered version (most recent) we will need to `Pkg.add` this explicitly, without using Pluto's built-in package manager. Be aware, this can take a long time, especially if this is the first time being downloaded. Future work on this package will focus on improving this.

To help with the formatting of this documentation we will also add [PlutoUI.jl](https://github.com/JuliaPluto/PlutoUI.jl).

Lastly, to visualize results and time the functions were going to add [Makie.jl](https://github.com/JuliaPlots/Makie.jl) and [BenchmarkTools.jl](https://github.com/JuliaCI/BenchmarkTools.jl).
"""

# ╔═╡ 7f2b1c79-d6dd-41f8-850e-32a18ba1b2a4
TableOfContents()

# ╔═╡ d70e8f0c-9052-47a4-bac7-af8362afda2c
md"""
## Quick start
Distance transforms are an important part of many computer vision-related tasks. Let's create some sample data and see how DistanceTransforms.jl can be used to apply efficient distance transform operations on arrays in Julia.
"""

# ╔═╡ 6c01894f-442a-497c-9519-dfc18b63be06
md"""
The quintessential distance transform operation in DistanceTransforms.jl is just a wrapper function combining the `feature_transform` and `distance_transform` functions from the excellent [ImageMorphology](https://github.com/JuliaImages/ImageMorphology.jl) package.

To utilize this in DistanceTransforms.jl all one must do is call `euclidean(x)`, where `x` is any boolean or integer array of ones and zeros
"""

# ╔═╡ 023529de-8f6b-4339-89a6-23d8b8fb881f
array1 = [
	1 0 0 1
	1 1 1 1
	0 0 1 1
]

# ╔═╡ cc17f05a-6e29-4a81-a45f-2dcfdedf2e88
euclidean(array1)

# ╔═╡ 0ad7423a-f2ff-417a-bfd1-e400a994e88c
md"""
As you can see, each element in the array is either zero, which remains zero, or is one that then gets replaced by the Euclidean distance to the nearest zero.

We can see this easily using Makie.jl.
"""

# ╔═╡ fde6da34-cd4d-4d97-aeb5-5a745cdffa13
heatmap(array1, colormap=:grays)

# ╔═╡ f629fb0b-530e-4a06-bfb0-81c27ae12301
heatmap(euclidean(array1); colormap=:grays)

# ╔═╡ 66ee23f9-9a36-427f-b062-306e513eea69
md"""
## `transform`s
The rest of the DistanceTransform.jl library is built around a common `transform` interface. Users can apply various distance transform algorithms to arrays all under one unified interface.

Let's examine two different options:
"""

# ╔═╡ 5fee8340-03ba-49a1-b0f6-975c7624e684
md"""
### `Chamfer`
This algorithm is based on the 3-4 Chamfer distance transform, as described by [Gunilla Borgefors](https://studentportalen.uu.se/uusp-filearea-tool/download.action?nodeId=214320&toolAttachmentId=64777)

To get started we need to initialize the type of algorithm or `tfm` we want to use, then we run this through the `transform` function. We can again use `array1` for this task.
"""

# ╔═╡ 22fa734b-73c0-4ccf-a646-af03e309c973
tfm = Chamfer(array1)

# ╔═╡ c7ba037e-5f85-44ec-8701-787f30cbfae3
chamfer_transform = transform(array1, tfm)

# ╔═╡ 04e19c33-992c-483b-9e4a-e728d1a507b9
md"""
Notice that the distance computed to the nearest backgroun `0` element is no longer a Euclidean distance, but instead follows the rules of the 3-4 Chamfer distance transform.
"""

# ╔═╡ 25c49c9f-4ad4-4d6d-8993-c6e6e6fd9303
md"""
### `SquaredEuclidean`
This algorithm is based on the squared Euclidean distance transform, as described by [Felzenszwalb and
Huttenlocher] (DOI: 10.4086/toc.2012.v008a019)

We will use a similar approach to get started, with one extra step; the array must either be designated as a boolean indicator (meaning zeros correspond to background and ones correspond to foreground) or ignored. Most of the time the array should be considered a boolean indicator:
"""

# ╔═╡ bacc8e48-40c6-4116-8f39-431fbebf065e
array2 = [
	0 1 1 0 1
	0 0 0 1 0
	1 1 0 0 0
]

# ╔═╡ 33e4022e-e7ff-467e-9f42-ed79b5fd2650
array2_bool = boolean_indicator(array2)

# ╔═╡ a4bd1fc3-ce53-41e9-a3e5-d4b767feafcc
tfm2 = SquaredEuclidean(array2_bool)

# ╔═╡ 0c625365-32ef-4261-a7b6-4c5002f0c464
sq_euc_transform = transform(array2_bool, tfm2)

# ╔═╡ 0c1e2872-f9a5-4697-b537-deac7f959a43
md"""
Notice that the initialization of the `SquaredEuclidean` transformation algorithm returns three separate arrays. This can be understood better by looking through the source code, but simply it's essential for utilizing this transformation algorithm in a similar way while taking advantage of multi-threading and/or GPU accelerated hardware.

It should also be clear to see that the `transform` returns the Euclidean distance, just squared. To find the true Euclidean distance, all one must do is return the take the square root of each element. In many cases, this is not necessary and can add time which is why it is left as optional.
"""

# ╔═╡ 926dadf5-38a6-4e77-bec9-0ac76005eb87
euc_transform = sqrt.(sq_euc_transform)

# ╔═╡ Cell order:
# ╟─0095c4d9-e9d0-4769-83ff-fd7f4346be8f
# ╠═22c33fe6-4efd-11ec-351c-25a9d73ec50a
# ╠═7f2b1c79-d6dd-41f8-850e-32a18ba1b2a4
# ╟─d70e8f0c-9052-47a4-bac7-af8362afda2c
# ╟─6c01894f-442a-497c-9519-dfc18b63be06
# ╠═023529de-8f6b-4339-89a6-23d8b8fb881f
# ╠═cc17f05a-6e29-4a81-a45f-2dcfdedf2e88
# ╟─0ad7423a-f2ff-417a-bfd1-e400a994e88c
# ╠═fde6da34-cd4d-4d97-aeb5-5a745cdffa13
# ╠═f629fb0b-530e-4a06-bfb0-81c27ae12301
# ╟─66ee23f9-9a36-427f-b062-306e513eea69
# ╟─5fee8340-03ba-49a1-b0f6-975c7624e684
# ╠═22fa734b-73c0-4ccf-a646-af03e309c973
# ╠═c7ba037e-5f85-44ec-8701-787f30cbfae3
# ╟─04e19c33-992c-483b-9e4a-e728d1a507b9
# ╟─25c49c9f-4ad4-4d6d-8993-c6e6e6fd9303
# ╠═bacc8e48-40c6-4116-8f39-431fbebf065e
# ╠═33e4022e-e7ff-467e-9f42-ed79b5fd2650
# ╠═a4bd1fc3-ce53-41e9-a3e5-d4b767feafcc
# ╠═0c625365-32ef-4261-a7b6-4c5002f0c464
# ╟─0c1e2872-f9a5-4697-b537-deac7f959a43
# ╠═926dadf5-38a6-4e77-bec9-0ac76005eb87


### A Pluto.jl notebook ###
# v0.16.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 el = $(esc(element))
        global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : missing
        el
    end
end

# ╔═╡ af807a43-e828-46e5-b50a-8da60591dec2
begin
	using PlutoUI # user-interface do Pluto.jl
	using Plots  # Julia package para gráficos
	using Dierckx  # Julia package para interpolação/extrapolação de dados
end

# ╔═╡ a417311b-4195-46ad-b106-a8f82057d292
html"<button onclick='present()'>present</button>"

# ╔═╡ 2d599785-a7a3-4e46-8394-276c444c2749
md"""
# Máquinas de corrente contínua (Ex. 4)
Geradores de corrente contínua, exercício 4:
"""

# ╔═╡ 8b049710-8cc2-11eb-33cf-ef396ec1944e
md"""
**Um gerador de excitação composta ligado em longa derivação e fluxo de excitação
série aditivo apresenta as seguintes características:**
"""

# ╔═╡ 70dcec10-8cc3-11eb-0ce1-15f38b9fb0f9
(Pn, Un, nₙ, Ri, Rs, Rd, Nd, Ns)=(8.75e3, 250, 1500, 1.3, 0.1, 223.0, 2000, 50)

# ╔═╡ 0786377e-8cc3-11eb-1413-e90fac064ffd
begin
	Iexc=[0.0, 0.2, 0.4, 0.6, 0.8, 0.9, 1.0, 1.1, 1.3, 1.5, 1.7]
	E₀_1500=[15.0, 100.0, 170.0, 220.0, 250.0, 260.0, 270.0, 280.0, 290.0, 300.0, 310.0]
	Iexc,E₀_1500
end

# ╔═╡ caeb9440-8cc3-11eb-0a47-e32ddfbb60df
md"""
**Considere ainda um interruptor em paralelo com o enrolamento indutor série.**
"""

# ╔═╡ f2e30e10-8cc3-11eb-3254-09eecb58cdd7
md"""
## a) recta de excitação 💻
**Calcule o valor da tensão em vazio sem reóstato de excitação. Explique se o estado do interruptor influencia o valor da tensão de vazio do gerador.**
"""

# ╔═╡ 666c6610-8d8c-11eb-1f12-536379ec8b3b
md"""
Em vazio a FMMs << FMMd logo o fluxo de excitação série é desprezável, não influenciando a FEM e por conseguinte a tensão de vazio, $$U_0$$.
"""

# ╔═╡ 0b45bb10-8cc4-11eb-2168-9bfabd9aea3b
begin
	H1=("Rexc", @bind Rexc PlutoUI.Slider(Rd:(E₀_1500[2,1]/Iexc[2,1]), default=Rd, show_value=true))
	H1
end

# ╔═╡ 29c3b5f0-8cc5-11eb-3b39-45ba828a66b0
begin
	#plotly()
	plot(Iexc,E₀_1500,title="U₀=f(Id), n=1500rpm", xflip=false, ylims=(0,350), xlabel = "Id(A)", ylabel="U₀(V)", xlims=(0,2), label=false, minorticks=0.1, minorgrid=true)
	plot!(Iexc,Rexc.*Iexc,label="Reta de excitação", legend=:bottomright)
	end

# ╔═╡ 720eea10-8d8c-11eb-0979-1b1316767fba
md"""
Para $$R_c=0Ω$$ verifica-se que a interseção da recta de excitação com a característica magnética se dá em (1.3A; 290V).
"""

# ╔═╡ 74552610-8cc7-11eb-3438-8d5790fb6fa1
md"""
## b)
**Com o interruptor desligado, calcule o valor da q.d.t. devido à reação magnética do induzido, sabendo que nas condições nominais se obtém uma regulação plana.**
"""

# ╔═╡ ba697470-8d77-11eb-01a1-05692e12dad7
md"""
Regulação plana, significa que a tensão em carga, $$U_{c}$$, é igual à tensão de vazio,  $$U_{0}$$. Por conseguinte, a regulação, $$\varepsilon$$, vem dada por:

$$\varepsilon= \frac{U_{0}-U_{c}  }{U_{n} } 100$$
"""

# ╔═╡ 89ab7d70-8cc7-11eb-0e2a-a99ca72b7067
begin
	U₀=Un; Uc=Un;
	reg=100(U₀-Uc)/Un
end;

# ╔═╡ 0d1c74a0-8d79-11eb-06ca-4f9339798195
md"""
Então, $$\varepsilon$$=$(reg)%
"""

# ╔═╡ 632a0760-8cff-11eb-2cbc-5b8728778ab4
Id0=Idc=0.8;

# ╔═╡ 40678f20-8d79-11eb-3ba3-2d7c17b7e853
md"""
Na situação de regulação plana verifica-se que $$I_{dc}=I_{d0}$$. Ou seja, para $$U_{0}=I_{c}=U_{n}$$, tem-se consultando a característica magnética, para $$E_{0}=250$$V, uma $$I_{dc}=I_{d0}$$=$(Id0)A
"""

# ╔═╡ 20c65f10-8d7a-11eb-0554-d3a401d3de0b
md"""
No entanto, o fluxo total da máquina, no ponto de funcionamente em carga, é caracterizado também pela contribuição de fluxo magnético criado no enrolamento de excitação série (montagem de excitação composta com fluxo aditivo). Assim, é necessário verificar a FMM do enrolamento série e a sua contribuição para a FEM, $$E_{0}$$, na situação de carga nominal, no presente caso:

$$I_{exc}=I_{d}+\frac{N_{s}}{N_{d}}I_{s}$$
"""

# ╔═╡ d7c5e840-8d00-11eb-103f-1d4805f37322
begin
	In=Pn/Un
	Ii=In+Idc
	Idserie=Ii*Ns/Nd
	Idserie=round(Idserie, digits=2)
	Iexcₜ=Idc+Idserie
end;

# ╔═╡ 522cbe90-8d7b-11eb-0547-1350c8c001f1
md"""
Verifica-se assim, que o fluxo total (derivação + série) é produzido por uma corrente de excitação equivalente, vista pelo enrolamento $$N_{d}$$ de: $$I_{exc}$$=$(Iexcₜ)A.
"""

# ╔═╡ 8aeb506e-8cc7-11eb-3b1f-53d9e2714ac1
md"""
## c) Influência de $$n$$ e $$R_c$$ em $$U=f(I)$$ 💻
**Com o interruptor desligado explicite qualitativamente a característica exterior do gerador.**

**Qual a variação do ponto de funcionamento da característica externa para uma dada
resistência de carga, nas seguintes situações:**
1. **aumento da velocidade de accionamento;**
2. **diminuição do reóstato de campo derivação.**
"""

# ╔═╡ ae5296e0-8d8f-11eb-2651-e5f054a07785
md"""
!!! info
	No enunciado original é considerado interruptor ligado, o que corrresponde ao gerador de excitação derivação. Nesta versão propõe-se a análise com o interruptor desligado, consequentemente o gerador encontra-se ligado com excitação composta.  \
	Analise a trajetória do ponto de funcionamento (característica externa), actuando na "carga" (corrente).
"""

# ╔═╡ 96ffd350-8ccb-11eb-36f7-b301d582a92d
begin
	H2=("Carga", @bind Icarga PlutoUI.Slider(0:1:In*1.4, default=In/2, show_value=false))
	H3=("Rcampo", @bind Rcampo PlutoUI.Slider(0:1:300, default=100, show_value=true))
	H4=("Velocidade", @bind rpm PlutoUI.Slider(500:2000, default=1500, show_value=true))
	H2, H3, H4
end

# ╔═╡ 56bcde02-8ccb-11eb-3c79-e1d6a15804a2
E₀ₙ=round.((rpm/nₙ).*E₀_1500, digits=1)

# ╔═╡ 457a92d0-8ccc-11eb-2c37-05033ffdb46f
begin
	FMMs=Ns*Icarga
	Id_=Ns*Icarga/Nd
end;

# ╔═╡ 6cbad1f0-8cc9-11eb-3671-892059ad8beb
begin
	I=0:1:60
	Id=0:0.001:2
	xx0=-Id_.+Id
	mxx0=(Rcampo+Rd).*xx0
	y=Icarga*(Ri+Rs).+mxx0
	E0n_i=Spline1D(Iexc,E₀ₙ)
	E0n_ii=E0n_i(Id)
	A=(E0n_ii-y)
	a=findall(i->(-1 < i < 1), A)
	Iex_fluxo=0.001*a[1,1]
	E0n_ex=Spline1D(Iexc,E₀ₙ)
	E0n_fluxo=E0n_ex(Iex_fluxo)
	Id_fluxo=Iex_fluxo-Id_
	U1p=(Rcampo+Rd)*Id_fluxo
	#plots
	P1=plot([Icarga], seriestype = :vline, linecolor=:red, ylabel="U(V)", ylims=(0,400), xlims=(0,60), label=false,linestyle=:dash)
	plot!(I, (Ri+Rs).*I, linewidth=2, linecolor=:green, legend=:none)
	plot!([Icarga*(Ri+Rs)], seriestype=:hline, linecolor=:green, ylims=(0,400), xlims=(0,60), label=false,linestyle=:dash, legend=:none)
	plot!([Icarga], [U1p],markershape=:circle, label=false, legend=:none)
	plot!([U1p], seriestype = :hline, xlims=(0,60),linestyle=:dashdot, linecolor=:purple, legend=:none)
	P2=plot(Iexc,E₀ₙ, xflip=true, ylims=(0,400), ylabel="U₀(V)", xlims=(0,2), linewidth=2, legend=:none)
	plot!(Id, (Rcampo+Rd).*Id, xlims=(0,2),ylims=(0,400), linecolor=:black, linewidth=2, label=false, legend=:none)
	plot!([Id_], seriestype = :vline, ylims=(0,400),linestyle=:dashdot, linewidth=2, linecolor=:red, label="Id_=$(Id_)A")
	plot!([Icarga*(Ri+Rs)], seriestype=:hline, linecolor=:green, ylims=(0,400), xlims=(0,2), label=false,linestyle=:dash, legend=:none)
	plot!(Id, y, linecolor=:black, ylims=(0,400), xlims=(0,2), label=false, linestyle=:dot, linewidth=2)
	plot!([Iex_fluxo], seriestype = :vline, ylims=(0,400),linestyle=:dashdot, linecolor=:purple, legend=:none)
	plot!([Id_fluxo], seriestype = :vline, ylims=(0,400),linestyle=:dashdot, linecolor=:purple, legend=:none)
	plot!([U1p], seriestype = :hline, xlims=(0,2),linestyle=:dashdot, linecolor=:purple, legend=:none)
	P3=plot(Id, Nd.*Id, yflip=true, xflip=true, linewidth=2, ylabel="FMMd(Acond)",xlims=(0,2), ylims=(0,3000), xlabel = "Id(A)", label=false, legend=:none)
	plot!([FMMs], seriestype=:hline, ylims=(0,3000), linecolor=:red, linestyle=:dash, label=false,legend=:none)
	plot!([Id_], seriestype = :vline, ylims=(0,3000),linestyle=:dashdot, linewidth=2, linecolor=:red,label=false, legend=:none)
	#plot!([Icarga], seriestype = :vline, xlabel = "I(A)", ylims=(0,3000), label=false,linestyle=:dash)

	P4=plot(I, Ns.*I, yflip=true, linewidth=2, ylabel="FMMs(Acond)",xlims=(0,60), label=false, legend=:none)
	plot!([FMMs], seriestype = :hline, ylims=(0,3000), linecolor=:red, linestyle=:dash, label=false)
	plot!([Icarga], seriestype = :vline, xlabel = "I(A)", ylims=(0,3000), label=false,linestyle=:dash, linecolor=:red, legend=:none)
	plot(P2, P1, P3, P4, layout = (2, 2))
end

# ╔═╡ f9817760-8d00-11eb-1611-377bc26b25bb
begin
	E0_est=Spline1D(Iexc,E₀_1500)
	E0_carga=E0n_i(Iexcₜ)
	E0_carga=round(E0_carga, digits=1)
end;

# ╔═╡ ada1fba0-8d7b-11eb-3ae0-6553fa34863e
md"""
Consultando a característica magnética verifica-se para $$I_{exc}$$ = $(Iexcₜ)A, uma FEM em carga de:

   $$E_{0}$$ = $(E0_carga)V"""

# ╔═╡ 4a66bc70-8d02-11eb-0534-b9a896d03598
begin
	ΔUₜ=E0_carga-Uc
	ΔE=ΔUₜ-(Ri+Rs)Ii
	ΔE=round(ΔE, digits=1)
end;

# ╔═╡ 98e72b80-8d7c-11eb-0848-330bcfa4e60e
md"""
Queda de tensão total dada por: $$\Delta U_t=E_0-U_c$$, permite por decomposição das q.d.t. presentes na máquina, determinar a q.d.t. devido à reacção magnética do induzido, com $$\Delta{E}$$:

$$\Delta{E}=\Delta U_{t}-\Delta U_{r}-\Delta U_{esc}$$
Na presente montagem (longa derivação), $$\Delta U_r=(R_i+R_s)I_i$$   e   $$\Delta U_{esc} \simeq {0}$$.

Resolvendo, obtém-se: $$\Delta {E}$$ = $(ΔE)V.
"""

# ╔═╡ 052779bc-3fb2-4482-83cd-e7113726e597

# ╔═╡ d3e64e5a-19ac-4858-b0d1-118e4fd40f16
md"""
# Setup
"""

# ╔═╡ a7f8c518-ea6c-4aab-b117-86fdbfba1414
TableOfContents(title="📚 Índice, Exercício 4")

# ╔═╡ 7c6183ee-93bc-4797-a92e-8c8c6f4be07c
md"""
!!! info
	No índice deste *notebook*, os tópicos assinalados com "💻" permitem interacção com o utilizador.
"""

# ╔═╡ 1984de4e-a917-441a-9617-bb5e6e4c69b8
md"""
## _Julia packages_
*Links to package help*: [Dierckx](https://github.com/kbarbary/Dierckx.jl), [Plots](http://docs.juliaplots.org/latest/), [PlutoUI](https://juliahub.com/docs/PlutoUI/abXFp/0.7.6/)
"""

# ╔═╡ bf6ede73-b315-4d89-a39c-10190c83fbc3
md"""
!!! info
	## Programação _Julia_ e _notebooks Pluto_
	Saber mais sobre: [_Julia_/_Pluto_](https://github.com/Ricardo-Luis/notebooks/blob/main/ME2/README.md)
"""

# ╔═╡ e618fc88-0095-46cb-a353-4098950a2f49
version=VERSION;

# ╔═╡ dbf9d2bc-a925-4649-94bd-2bf2a184fb6e
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) \
**Ricardo Luís** (Professor Adjunto, ISEL\DEEEA\GDME) \
ISEL, 12/Out/2021
"""

# ╔═╡ 91e58ccc-54a3-48f1-b70c-29a2cf0492aa
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]
Dierckx = "39dd38d3-220a-591b-8e3c-4c3a8c710a94"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8"

[compat]
Dierckx = "~0.5.1"
Plots = "~1.22.4"
PlutoUI = "~0.7.15"
"""

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

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

[[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 = "31d0151f5716b655421d9d75b7fa74cc4e744df2"
uuid = "34da2185-b29b-5c13-b0c7-acf172513d20"
version = "3.39.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"

[[Dierckx]]
deps = ["Dierckx_jll"]
git-tree-sha1 = "5fefbe52e9a6e55b8f87cb89352d469bd3a3a090"
uuid = "39dd38d3-220a-591b-8e3c-4c3a8c710a94"
version = "0.5.1"

[[Dierckx_jll]]
deps = ["CompilerSupportLibraries_jll", "Libdl", "Pkg"]
git-tree-sha1 = "a580560f526f6fc6973e8bad2b036514a4e3b013"
uuid = "cd4c43a9-7502-52ba-aa6d-59fb2a88580b"
version = "0.0.1+0"

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

[[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 = "dba1e8614e98949abfa60480b13653813d8f0157"
uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89"
version = "3.3.5+0"

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

[[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 = "cafe0823979a5c9bff86224b3b8de29ea5a44b2e"
uuid = "d2c73de3-f751-5644-a686-071e5b155ba9"
version = "0.61.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 = "14eece7a3308b4d8be910e265c724a6ba51a9798"
uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3"
version = "0.9.16"

[[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 = "f6532909bf3d40b308a0f360b6a0e626c0e263a8"
uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2"
version = "0.9.1"

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

[[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 = "c7f1c695e06c01b95a67f0cd1d34994f3e7db104"
uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
version = "1.2.1"

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

[[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 = "761a393aeccd6aa92ec3515e428c26bf99575b3b"
uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490"
version = "3.2.2+0"

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

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

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

[[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 = "a8709b968a1ea6abc2dc1967cb1db6ac9a00dfb6"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "2.0.5"

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

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

[[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 = "44a75aa7a527910ee3d1751d1f0e4148698add9e"
uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
version = "1.1.2"

[[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 = "1958272568dc176a1d881acb797beb909c785510"
uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0"
version = "1.0.0"

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

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

[[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", "Wayland_jll"]
git-tree-sha1 = "2839f1c1296940218e35df0bbb220f2a79686670"
uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91"
version = "1.18.0+4"

[[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:
# ╟─a417311b-4195-46ad-b106-a8f82057d292
# ╟─2d599785-a7a3-4e46-8394-276c444c2749
# ╟─8b049710-8cc2-11eb-33cf-ef396ec1944e
# ╠═70dcec10-8cc3-11eb-0ce1-15f38b9fb0f9
# ╠═0786377e-8cc3-11eb-1413-e90fac064ffd
# ╟─caeb9440-8cc3-11eb-0a47-e32ddfbb60df
# ╟─f2e30e10-8cc3-11eb-3254-09eecb58cdd7
# ╟─666c6610-8d8c-11eb-1f12-536379ec8b3b
# ╟─0b45bb10-8cc4-11eb-2168-9bfabd9aea3b
# ╟─29c3b5f0-8cc5-11eb-3b39-45ba828a66b0
# ╟─720eea10-8d8c-11eb-0979-1b1316767fba
# ╟─74552610-8cc7-11eb-3438-8d5790fb6fa1
# ╟─ba697470-8d77-11eb-01a1-05692e12dad7
# ╟─0d1c74a0-8d79-11eb-06ca-4f9339798195
# ╠═89ab7d70-8cc7-11eb-0e2a-a99ca72b7067
# ╟─40678f20-8d79-11eb-3ba3-2d7c17b7e853
# ╠═632a0760-8cff-11eb-2cbc-5b8728778ab4
# ╟─20c65f10-8d7a-11eb-0554-d3a401d3de0b
# ╟─522cbe90-8d7b-11eb-0547-1350c8c001f1
# ╠═d7c5e840-8d00-11eb-103f-1d4805f37322
# ╟─ada1fba0-8d7b-11eb-3ae0-6553fa34863e
# ╠═f9817760-8d00-11eb-1611-377bc26b25bb
# ╟─98e72b80-8d7c-11eb-0848-330bcfa4e60e
# ╠═4a66bc70-8d02-11eb-0534-b9a896d03598
# ╟─8aeb506e-8cc7-11eb-3b1f-53d9e2714ac1
# ╟─ae5296e0-8d8f-11eb-2651-e5f054a07785
# ╠═56bcde02-8ccb-11eb-3c79-e1d6a15804a2
# ╟─96ffd350-8ccb-11eb-36f7-b301d582a92d
# ╟─457a92d0-8ccc-11eb-2c37-05033ffdb46f
# ╟─6cbad1f0-8cc9-11eb-3671-892059ad8beb
# ╟─052779bc-3fb2-4482-83cd-e7113726e597
# ╟─d3e64e5a-19ac-4858-b0d1-118e4fd40f16
# ╠═a7f8c518-ea6c-4aab-b117-86fdbfba1414
# ╟─7c6183ee-93bc-4797-a92e-8c8c6f4be07c
# ╟─1984de4e-a917-441a-9617-bb5e6e4c69b8
# ╠═af807a43-e828-46e5-b50a-8da60591dec2
# ╟─bf6ede73-b315-4d89-a39c-10190c83fbc3
# ╟─dbf9d2bc-a925-4649-94bd-2bf2a184fb6e
# ╟─e618fc88-0095-46cb-a353-4098950a2f49
# ╟─91e58ccc-54a3-48f1-b70c-29a2cf0492aa
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002


module mcrosssection1
using FinEtools
using FinEtoolsFlexStructures.CrossSectionModule
using Test
function test()
    cs = CrossSectionModule.CrossSectionCircle(s -> 5.9910, s -> [0.0, 0.0, 1.0])
    par = cs.parameters(0.0)
    for (c, r) in zip((par.A, par.J, par.I1, par.I2, par.I3), (112.75829799164978, 2023.5649824692157, 2023.5649824692157, 1011.7824912346078, 1011.7824912346078))
        @test c ≈ r
    end
    true
end
end
using .mcrosssection1
mcrosssection1.test()

module mcrosssection1y
using FinEtools
using FinEtoolsFlexStructures.CrossSectionModule
using Test
function test()
    cs = CrossSectionModule.CrossSectionCircle(s -> 5.9910, s -> [0.0, 0.0, 1.0], 6/7)
    par = cs.parameters(0.0)
    for (c, r) in zip((par.A, par.J, par.I1, par.I2, par.I3), (112.75829799164978, 2023.5649824692157, 2023.5649824692157, 1011.7824912346078, 1011.7824912346078))
        @test c ≈ r
    end
    true
end
end
using .mcrosssection1y
mcrosssection1y.test()

module mcrosssection2y
using FinEtools
using FinEtoolsFlexStructures.CrossSectionModule
using Test
function test()
    ri, re = 3.9910, 5.9910
    cs = CrossSectionModule.CrossSectionHollowCircle(s -> 3.9910, s -> 5.9910, s -> [0.0, 0.0, 1.0])
    # @show pi*(re^2-ri^2)
    # @show pi*(re^4-ri^4)/4
    par = cs.parameters(0.0)
    # @show (par.A, par.J, par.I1, par.I2, par.I3)
    for (c, r) in zip((par.A, par.J, par.I1, par.I2, par.I3), (62.71875573626662, 1625.048041345883, 1625.048041345883, 812.5240206729414, 812.5240206729414))
        @test c ≈ r
    end
    true
end
end
using .mcrosssection2y
mcrosssection2y.test()

module mcrosssection2
using FinEtools
using FinEtoolsFlexStructures.CrossSectionModule
using Test
function test()
    cs = CrossSectionModule.CrossSectionRectangle(s -> 42.0, s -> 4.2, s -> [0.0, 0.0, 1.0])
    par = cs.parameters(0.0)
    for (c, r) in zip((par.A, par.J, par.I1, par.I2, par.I3), (176.4, 970.849152, 26190.108000000004, 259.30800000000005, 25930.800000000003))
        @test c ≈ r
    end
    true
end
end
using .mcrosssection2
mcrosssection2.test()

module mcrosssection3y
using FinEtools
using FinEtoolsFlexStructures.CrossSectionModule
using Test
function test()
    cs = CrossSectionModule.CrossSectionRectangle(s -> 42.0, s -> 4.2, s -> [0.0, 0.0, 1.0], 5/6)
    par = cs.parameters(0.0)
    @test par.A2s == par.A*5/6
    for (c, r) in zip((par.A, par.J, par.I1, par.I2, par.I3), (176.4, 970.849152, 26190.108000000004, 259.30800000000005, 25930.800000000003))
        @test c ≈ r
    end
    true
end
end
using .mcrosssection3y
mcrosssection3y.test()

module mcrosssection3
using FinEtools
using FinEtoolsFlexStructures.CrossSectionModule
using Test
function test()
    cs = CrossSectionModule.CrossSectionRectangle(s -> 1.3 * 4.2, s -> 4.2, s -> [0.0, 0.0, 1.0])
    par = cs.parameters(0.0)
    for (c, r) in zip((par.A, par.J, par.I1, par.I2, par.I3), (22.932000000000006, 71.66370760423138, 90.68000760000004, 33.71004000000001, 56.969967600000025))
         @test c ≈ r
    end
 true
end
end
using .mcrosssection3
mcrosssection3.test()

module mcrosssection4
using FinEtools
using FinEtoolsFlexStructures.CrossSectionModule
using Test
function test()
    R = 0.5
    cs = CrossSectionModule.CrossSectionCircle(s -> (1/2+2*s)*R, s -> [0.0, 0.0, 1.0])
    par = cs.parameters(0.0)
    for (c, r) in zip((par.A, par.J, par.I1, par.I2, par.I3), (0.19634954084936207, 0.006135923151542565, 0.006135923151542565, 0.0030679615757712823, 0.0030679615757712823))
        @test c ≈ r
    end
    true
end
end
using .mcrosssection4
mcrosssection4.test()


using OptimalEstimationProject
using LinearAlgebra
using AstroTime
using MATLAB

# Spacecraft simulator
t0      = TAIEpoch("2021-08-08T12:00:00")
scsim   = SpacecraftSim(t0.second)

# Initial state error variance
σr      = 0.1   # [km]
σv      = 0.01  # [km / s]
σm      = 1e-6  # [kg]
sqrtP0  = Diagonal([σr, σr, σr, σv, σv, σv, σm])
P0      = sqrtP0.^2

# Initial state estimate
(y0true, us) = OptimalEstimationProject.GetStateAndControl(scsim, t0.second)
xhat0   = y0true[1:7] + sqrtP0*randn(7)

# Measurement time stamps
Δt      = 60.0        # [sec]
gpsΔt   = 15*60     # [sec]
ts      = range(t0.second + Δt; step = Δt, stop = t0.second + scsim.ts[2]*86400)

# Measurement statistics
σρ      = 10.0e-3 # [km]     Pseudorange noise standard deviation
σr      = 5.0e-3  # [km]     GPS broadcast ephemeris standard deviation
σa      = 1.0e-6  # [km/s^2] Accelerometer noise standard deviation

# Process noise covariance
Q       = Diagonal([1.0e-16, 1.0e-16, 1.0e-16, 1.0e-12, 1.0e-12, 1.0e-12, 1.0e-3])

# GPS Simulation Span
startWeek   = 2170
startDay    = 0
endWeek     = 2174
endDay      = 6

# Create GPS simulation object
gpssim = GPSSim(startWeek, startDay, endWeek, endDay; σρ = σρ, σr = σr)

# Create IMU simulation object
imusim = IMUSim(σa)

# Create EKF
ukf = UKF(xhat0, P0, Q, (σρ^2 + 3*σr^2), σa^2, ts, gpsΔt, gpssim, imusim, scsim;
    lunaPerts = true, α = 1.0, β = 0.0, κ = 3.0+14.0);

@time runFilter!(ukf)

# Get true trajectory for plotting
xtrue = zeros(length(ukf.txp), 3)
for i in 1:length(ukf.txp)
    (y0l, us) = OptimalEstimationProject.GetStateAndControl(scsim, ukf.txp[i])
    xtrue[i, :] .= y0l[1:3]
end

# Plotting
plot(ukf, xtrue, length(ukf.txp))


using LinearAlgebra
using Roots
using Intervals

"""
    GammaEqn

Save data for solving for gamma
"""
struct GammaEqn{T}
    ϵ::T
    λ::Array{T, 1}
    m::Int
end
GammaEqn(e::Int, l::AbstractArray, m::Int) = GammaEqn(Float64(e), l, m)
function GammaEqn(ϵ::Union{Real, Int}, λ)
    if !all( λ .>= 0 )
        throw(ArgumentError("Eigenvalues must be nonnegative"))
    else
        return GammaEqn(ϵ, λ, length(λ))
    end
end
function (eq::GammaEqn)(expr, γ)
    ϵ = eq.ϵ
    λ = eq.λ
    m = eq.m
    z = γ[1]
    expr[1] = (ϵ^2 .- 0.5*sum(λ)) .* z - m + 0.5 * sum(sqrt.(z.^2 .* λ.^2 .+ 4 .* λ .* z))
end

"""
    WassersteinShrinkage(target, eps)

Computes the Wasserstein-DR precision matrix of X wrt the Stein loss logdet(C*P) - <C*P> - p with the radius eps.
"""
struct WassersteinShrinkage <:CovarianceEstimator
    eps::Float64
end

function cov(sre::WassersteinShrinkage, X::AbstractMatrix{<:Real};
             dims::Int=1, mean=nothing)
    inv_cov = prec(sre, X)
    return inv(inv_cov)
end

function prec(sre::WassersteinShrinkage, X::AbstractMatrix{<:Real};
        dims::Int=1, mean=nothing)
    return wasserstein_pm(X, sre.eps)
end

"""
    linear_shrinkage(::DiagonalUnitVariance, Xc, S, λ, n, p, corrected)

Compute the shrinkage estimator where the target is a `DiagonalUnitVariance`.
"""
function wasserstein_pm(X, ϵ)
    C = Symmetric(cov(X))
    λ, v = eigen(C)
    m = length(λ)
    λ = max.(1e-10, λ)
    eq = GammaEqn(ϵ, λ)
    ϕ(z) = (ϵ^2 .- 0.5*sum(λ)) .* z - m + 0.5 * sum(sqrt.(z.^2 .* λ.^2 .+ 4 .* λ .* z))
    bounds = γ_bounds(eq)
    ϕ.(bounds)
    γ = find_zero(ϕ, bounds, Roots.Bisection())
    u = λ*γ
    # x = γ .* (1 .- 2. ./ (1 .+ sqrt.(1 .+ 4 ./ u)))
    x = γ.*(1 .- 0.5 *(sqrt.(max.(0., u.^2 .+ 4*u)) .- u))
    for i = 1:length(λ)
        # NOTE: Numerically stable alternative for large values
        if λ[i]*γ > 1e8
            x[i] = γ .* (1 .- 2. ./ (1 .+ sqrt.(1 .+ 4 ./ λ[i]*γ)))
            # x[i] = γ*(1 - 0.5 *(sqrt((γ*λ[i])^2 + 4*λ[i]*γ)) - λ[i]*γ)
        end
    end
    est = v*diagm(x)*v'
    return Symmetric(est)
end
function γ_bounds(eq::GammaEqn)
    m = eq.m
    L = eq.λ[end]
    ϵ = eq.ϵ
    # NOTE: Lower bound from original paper has an error?
    lower = 1e-15
    upper = min(m/ϵ^2, 1/(ϵ + 1e-15)*sqrt(sum(eq.λ.^(-1))))
    return lower, upper
end


import Statistics
betterThanAverage(classPoints, yourPoints) = yourPoints > Statistics.mean(classPoints)


using LinearAlgebra

# Calculation of Intramolecular Force Fields from Second-Derivative Tensors
# Jorge M. Seminario

# Data struct
# Orca uses energy in Hartree units and length in Bohr
# 1 Hartee = 2625.5 kJ/mol; 1 Bohr = 0.0529177249 nm
# 1 [Hartee/Bohr^2] = 937582.935092 [kJ/mol/nm^2]
# 1 [Hartee/Bohr^2] = 2240.8815787 [kcal/mol/A^2]
#  xyz in angstrom; 1 A = 0.1 nm
struct Hess_data
    Hess::Matrix{Float64}
    xyz::Matrix{Float64}
    function Hess_data(Hess::Matrix{Float64}, xyz::Matrix{Float64})
        new(Hess*937582.935092 , 0.1*xyz)
    end
end

function bond_constant(atom1::Int64, atom2::Int64, MolSystem::Hess_data)
    # getting atom1-atom2 bond vector
    bond_vector = MolSystem.xyz[atom2, :] - MolSystem.xyz[atom1, :]
    bond_vector = bond_vector/norm(bond_vector)

    # getting submatrice of atom1-atom2 interaction
    HessAB = MolSystem.Hess[(3*atom1-2):(3*atom1), (3*atom2-2):3*atom2]
    eig, vec = eigen(-HessAB)

    # calculating bond force constant
    k = eig[1]*abs(dot(bond_vector, vec[:,1])) + eig[2]*abs(dot(bond_vector, vec[:,2])) + eig[3]*abs(dot(bond_vector, vec[:,3]))

    return(round(real(k), digits=3))

end

function angle_constant(atom1::Int64, atom2::Int64, atom3::Int64, MolSystem::Hess_data)
    # getting atom1-atom2; atom3-atom2 bond unit vectors ant their norms
    bond12_vector = MolSystem.xyz[atom2, :] - MolSystem.xyz[atom1, :]
    bond32_vector = MolSystem.xyz[atom2, :] - MolSystem.xyz[atom3, :]
    bond12_dist = norm(bond12_vector)
    bond32_dist = norm(bond32_vector)
    bond12_vector = bond12_vector/bond12_dist
    bond32_vector = bond32_vector/bond32_dist

    # getting submatrices of atom1-atom2 and atom2-atom3 interactions
    # calculating their eigen -values and -vectors
    Hess12 = MolSystem.Hess[(3*atom1-2):(3*atom1), (3*atom2-2):3*atom2]
    Hess32 = MolSystem.Hess[(3*atom3-2):(3*atom3), (3*atom2-2):3*atom2]
    eig12, vec12 = eigen(-Hess12)
    eig32, vec32 = eigen(-Hess32)

    # calculating direction vectors of small angle displacements
    normN_vector = cross(bond32_vector, bond12_vector)/norm(cross(bond32_vector, bond12_vector))
    disp12_vector = cross(normN_vector, bond12_vector)/norm(cross(normN_vector, bond12_vector))
    disp32_vector = cross(bond32_vector, normN_vector)/norm(cross(bond32_vector, normN_vector))

    # calculating angle force constant
    tempK1 = eig12[1]*abs(dot(disp12_vector, vec12[:,1])) + eig12[2]*abs(dot(disp12_vector, vec12[:,2])) + eig12[3]*abs(dot(disp12_vector, vec12[:,3]))
    tempK2 = eig32[1]*abs(dot(disp32_vector, vec32[:,1])) + eig32[2]*abs(dot(disp32_vector, vec32[:,2])) + eig32[3]*abs(dot(disp32_vector, vec32[:,3]))
    k = 1/(bond12_dist^2*tempK1) + 1/(bond32_dist^2*tempK2)
    k_theta = 1/k/2

    return(round(real(k_theta); digits=3))
end

function dihedral_constant(atom1::Int64, atom2::Int64, atom3::Int64, atom4::Int64,  MolSystem::Hess_data)
    # getting atom2-atom1; atom2-atom3; atom3-atom4; atom3-atom2 bond unit vectors ant their norms
    bond12_vector = MolSystem.xyz[atom2, :] - MolSystem.xyz[atom1, :]
    bond32_vector = MolSystem.xyz[atom2, :] - MolSystem.xyz[atom3, :]
    bond43_vector = MolSystem.xyz[atom3, :] - MolSystem.xyz[atom4, :]
    bond12_dist = norm(bond12_vector)
    bond32_dist = norm(bond32_vector)
    bond43_dist = norm(bond43_vector)
    bond12_vector = bond12_vector/bond12_dist
    bond32_vector = bond32_vector/bond32_dist
    bond43_vector = bond43_vector/bond43_dist
    bond23_vector = -bond32_vector/bond32_dist

    # getting submatrices of atom1-atom2 and atom3-atom4 interactions
    # calculating their eigen -values and -vectors
    Hess12 = MolSystem.Hess[(3*atom1-2):(3*atom1), (3*atom2-2):3*atom2]
    Hess34 = MolSystem.Hess[(3*atom3-2):(3*atom3), (3*atom4-2):3*atom4]
    eig12, vec12 = eigen(-Hess12)
    eig34, vec34 = eigen(-Hess34)

    # calculating unit normal vectors for planes atom1-atom2-atom3(ABC) and atom2-atom3-atom4(BCD)
    normNABC_vector = cross(bond32_vector, bond12_vector)
    normNBCD_vector = cross(bond43_vector, bond23_vector)
    normNABC_dist = norm(normNABC_vector)
    normNBCD_dist = norm(normNBCD_vector)
    normNABC_vector = normNABC_vector/normNABC_dist
    normNBCD_vector = normNBCD_vector/normNBCD_dist

    # calculating dihedral angle force constant
    tempK1 = eig12[1]*abs(dot(normNABC_vector, vec12[:,1])) + eig12[2]*abs(dot(normNABC_vector, vec12[:,2])) + eig12[3]*abs(dot(normNABC_vector, vec12[:,3]))
    tempK2 = eig34[1]*abs(dot(normNBCD_vector, vec34[:,1])) + eig34[2]*abs(dot(normNBCD_vector, vec34[:,2])) + eig34[3]*abs(dot(normNBCD_vector, vec34[:,3]))
    k = 1/((bond12_dist*normNABC_dist)^2*tempK1) + 1/((bond34_dist*normNBCD_dist)^2*tempK2)
    k_phi = 1/k

    return(abs(real(k_phi)))
end

function improper_constant(atom1::Int64, atom2::Int64, atom3::Int64, atom4::Int64,  MolSystem::Hess_data)
    # getting atom1-atom2; atom1-atom3; atom1-atom4 and atom4-atom3; atom2-atom3 bond unit vectors ant their norms
    # getting coordinates of central atom1 and atom2
    Atom1_point = MolSystem.xyz[atom1, :]
    Atom2_point = MolSystem.xyz[atom2, :]
    bond12_vector = Atom2_point - Atom1_point
    bond13_vector = MolSystem.xyz[atom3, :] - Atom1_point
    bond14_vector = MolSystem.xyz[atom4, :] - Atom1_point
    bond43_vector = MolSystem.xyz[atom3, :] - MolSystem.xyz[atom4, :]
    bond23_vector = MolSystem.xyz[atom3, :] - Atom2_point
    bond12_dist = norm(bond12_vector)
    bond13_dist = norm(bond13_vector)
    bond14_dist = norm(bond14_vector)
    bond43_dist = norm(bond43_vector)
    bond23_dist = norm(bond23_vector)
    bond12_vector = bond12_vector/bond12_dist
    bond13_vector = bond13_vector/bond13_dist
    bond14_vector = bond14_vector/bond14_dist
    bond43_vector = bond43_vector/bond43_dist
    bond23_vector = bond23_vector/bond23_dist

    # getting submatrices of atom1-atom2 and atom1-atom3 and atom1-atom4 interactions
    # calculating their eigen -values and -vectors
    Hess12 = MolSystem.Hess[(3*atom1-2):(3*atom1), (3*atom2-2):3*atom2]
    Hess13 = MolSystem.Hess[(3*atom1-2):(3*atom1), (3*atom3-2):3*atom3]
    Hess14 = MolSystem.Hess[(3*atom1-2):(3*atom1), (3*atom4-2):3*atom4]
    eig12, vec12 = eigen(-Hess12)
    eig13, vec13 = eigen(-Hess13)
    eig14, vec14 = eigen(-Hess14)

    # calculating unit normal vectors for planes atom2-atom3-atom4(BCD)
    normNBCD_vector = cross(bond43_vector, bond23_vector)
    normNBCD_dist = norm(normNBCD_vector)
    normNBCD_vector = normNBCD_vector/normNBCD_dist

    # calculating improper dihedral angle force constant

    # calculating in
    tempK1 = eig12[1]*abs(dot(normNBCD_vector , vec12[:,1])) + eig12[2]*abs(dot(normNBCD_vector , vec12[:,2])) + eig12[3]*abs(dot(normNBCD_vector , vec12[:,3]))
    tempK2 = eig13[1]*abs(dot(normNBCD_vector , vec13[:,1]))+ eig13[2]*abs(dot(normNBCD_vector , vec13[:,2])) + eig13[3]*abs(dot(normNBCD_vector , vec13[:,3]))
    tempK3 = eig14[1]*abs(dot(normNBCD_vector , vec14[:,1])) + eig14[2]*abs(dot(normNBCD_vector , vec14[:,2])) + eig14[3]*abs(dot(normNBCD_vector , vec14[:,3]))

    # calculating projection of altitude of triangle ABC into plane BCD
    # determinating altitude vector of altitude through system of linear equations
    # Statement 1: equation of line BC; Statement 2: dot product is 0 for (BC*altitude),  MatrCoef*r = x
    # BC is bond23_vector; Atom2_point is B point; Atom1_point is A point

    MatrCoef = [1/bond23_vector[1]   -1/bond23_vector[2]           0;
                          0           1/bond23_vector[2]   -1/bond23_vector[3];
                bond23_vector[1]        bond23_vector[2]    bond23_vector[3]]

    x = [(Atom2_point[1]/bond23_vector[1] - Atom2_point[2]/bond23_vector[2]);
         (Atom2_point[2]/bond23_vector[2] - Atom2_point[3]/bond23_vector[3]);
        -(dot(Atom1_point, bond23_vector))]

    HABC_vector = Atom1_point - MatrCoef\x
    normHABCD_dist = norm(HABC_vector - HABC_vector*dot(HABC_vector, normNBCD_vector))
    k_omega = normHABCD_dist^2*(tempK1 + tempK2 + tempK3)

    return(abs(real(k_omega)))
end


# computes the errors as outlined in the notes. Use these to generate
# moment conditions for estimation
function DSGEmoments(θ, data)
        # break out variables
        y = data[:,1]
        c = data[:,2]
        n = data[:,3]
        r = data[:,4]
        w = data[:,5]
        # break out params
        α = 0.33
        δ = 0.025
        β = θ[1]
        γ = θ[2]
        ρ_z = θ[3]
        σ_z = θ[4]
        ρ_η = θ[5]
        σ_η = θ[6]
        nss = θ[7]
        # recover ψ
        c1 = ((1.0/β + δ - 1.0)/α)^(1.0/(1.0-α))
        kss = nss/c1
        iss = δ*kss
        yss = kss^α * nss^(1-α)
        css = yss - iss
        ψ =  (css^(-γ)) * (1-α) * (kss^α) * (nss^(-α))
        # use MPL-MRS to get η, the preference shock
        η = log.(w) .- γ*log.(c) .- log.(ψ)
        u = (η[2:end]-η[1:end-1]*ρ_η)/σ_η
        e1 = η[1:end-1].*u
        e2 = u.^2.0 .- 1.0
        pref_shock = u
        # now the Euler eqn
        e3 = (100*((1.0 .+ r .- δ).*β.*(c.^(-γ)) .- lag(c,1).^(-γ)))[2:end]
        # recover K from MPK/MPL
        k = (α/(1.0-α))*n.*w./r
        # get z, the production shock, from the production function
        z = log.(y) - α*log.(k) - (1.0-α)*log.(n)
        u = (z[2:end]-z[1:end-1]*ρ_z)/σ_z
        e4 = z[1:end-1].*u
        e5 = u.^2.0 .- 1.0
        tech_shock = u
        # make moment conditions
        data = log.(data)[1:end-1,:]
        errors = [e1 e2 e3 e4 e5 pref_shock.*data tech_shock.*data data.*e3]
        return errors
end


function get_ball_contact_jacobian(q, body)
    xₜ = q[1]
    yₜ = q[2]
    θ  = q[3]
    D = body.l
    rad = D/2.

    xyc = [xₜ, yₜ-rad]
    ϕ = xyc[2]

    n = [0, 1]
    r = xyc - [xₜ, yₜ]
    rₓnᵤ = r[1]*n[2]; rᵤnₓ = r[2]*n[1]
    rₓnₓ = r[1]*n[1]; rᵤnᵤ = r[2]*n[2]

    J = [[n[2] n[1]];
         [-n[1] n[2]];
         [-rₓnₓ-rᵤnᵤ rₓnᵤ-rᵤnₓ]]

    return J, ϕ
end

function get_block_contact_jacobian(q, body)
    xₜ = q[1]
    yₜ = q[2]
    θ  = q[3]
    L = body.l

    l = sqrt(2* (0.5*L)^2)
    a = [xₜ+l*cos(θ+3π/4), yₜ+l*sin(θ+3π/4)]
    b = [xₜ+l*cos(θ+5π/4), yₜ+l*sin(θ+5π/4)]
    c = [xₜ+l*cos(θ+π/4), yₜ+l*sin(θ+π/4)]
    d = [xₜ+l*cos(θ+7π/4), yₜ+l*sin(θ+7π/4)]

    corners = [a, b, c, d]
    min_index = argmin([a[2], b[2], c[2], d[2]])
    xyc = corners[min_index]
    ϕ = xyc[2]

    n = [0, 1]
    r = xyc - [xₜ, yₜ]
    rₓnᵤ = r[1]*n[2]; rᵤnₓ = r[2]*n[1]
    rₓnₓ = r[1]*n[1]; rᵤnᵤ = r[2]*n[2]

    J = [[n[2] n[1]];
         [-n[1] n[2]];
         [-rₓnₓ-rᵤnᵤ rₓnᵤ-rᵤnₓ]]

    return J, ϕ
end


immutable FLSynapseParameter
end

@withkw type FLSynapse
    param::FLSynapseParameter = FLSynapseParameter()
    colptr::Vector{Int} # column pointer of sparse W
    I::Vector{Int}      # postsynaptic index of W
    W::Vector{Float}  # synaptic weight
    rI::Vector{Float} # postsynaptic rate
    rJ::Vector{Float} # presynaptic rate
    g::Vector{Float}  # postsynaptic conductance
    P::Vector{Float}  # <rᵢrⱼ>⁻¹
    q::Vector{Float}  # P * r
    u::Vector{Float} # force weight
    w::Vector{Float} # output weight
    f::Float = 0 # postsynaptic traget
    z::Float = 0.5randn()  # output z ≈ f
    records::Dict = Dict()
end

function FLSynapse(pre, post; σ = 1.5, p = 0.0, α = 1)
    w = σ * 1 / √(p * pre.N) * sprandn(post.N, pre.N, p)
    rowptr, colptr, I, J, index, W = dsparse(w)
    rI, rJ, g = post.r, pre.r, post.g
    P = α .* (I .== J)
    q = zeros(post.N)
    u = 2rand(post.N) - 1
    w = 1 / √post.N * (2rand(post.N) - 1)
    FLSynapse(;@symdict(colptr, I, W, rI, rJ, g, P, q, u, w)...)
end

@replace function forward!(c::FLSynapse, param::FLSynapseParameter)
    z = dot(w, rI)
    g .= z .* u
    fill!(q, zero(Float))
    @inbounds for j in 1:(length(colptr) - 1)
        rJj = rJ[j]
        for s = colptr[j]:(colptr[j+1] - 1)
            i = I[s]
            q[i] += P[s] * rJj
            g[i] += W[s] * rJj
        end
    end
end

@replace function plasticity!(c::FLSynapse, param::FLSynapseParameter, dt::Float, t::Float)
    C = 1 / (1 + dot(q, rI))
    BLAS.axpy!(C * (f - z), q, w)
    @inbounds for j in 1:(length(colptr) - 1)
        for s in colptr[j]:(colptr[j+1] - 1)
            P[s] += -C * q[I[s]] * q[j]
        end
    end
end


include("dipole.jl")

const c = 299792458.
const mu0 = 4*pi*1e-7
const eps0 = 1/(mu0*c^2)

#dipoles:
const N=1000;
const distance=1000+1000*rand(N)
const theta=2*acos(rand(N)-1)
const phi=2*pi*rand(N)
xyz = hcat(distance.*sin(theta).*cos(phi), distance.*sin(theta).*sin(phi), distance.*cos(theta))
#moments:
const th_dip=2*acos(rand(N)-1)
const phi_dip=2*pi*rand(N)

#dipole moment
#total time averaged radiated power P= 1 W dipole moment => |p|=sqrt(12πcP/µOω⁴)
const Pow=1
const amp_max=sqrt(12*pi*c*Pow/(mu0*(2*pi*freq)^4))/N
const amplitude=amp_max*rand(N)
const phase=2*pi*rand(N)
I=hcat(amplitude.*sin(th_dip).*cos(phi_dip), amplitude.*sin(th_dip).*sin(phi_dip), amplitude.*cos(th_dip))

const freq=1e9

#observation points
dx=0.01
dy=0.01
dz=0.01
nx=int(2/dx)
ny=int(2/dy)
const  x=linspace(0.,2.,nx)

const  y=linspace(0.,2.,ny)

z=0
println("Computing the radiation...")
Z=zeros(nx,ny)
Ez=zeros(nx,ny)
Bz=zeros(nx,ny)
for i=1:nx
  perc=round(i/nx*1000)/10
  println("$perc %")
  for j=1:ny
    r=[x[i],y[j],z]
    E=zeros(Complex128,3)
    B=zeros(Complex128,3)
    for m=1:N
      p=vec(I[m,:])
      R=vec(xyz[m,:])
      Ed,Bd=Hertz_dipole (r, p, R, phase[m], freq)
      E+=Ed
      B+=Bd
    end
    Z[i,j]=sqrt(sum(abs(E).^2))/sqrt(sum(abs(B).^2))*mu0 #real(E).^2#0.5*numpy.cross(E.T,conjugate(B.T))
    Ez[i,j]=abs(E[3])
    Bz[i,j]=abs(B[3])
  end
end

using PyPlot
figure(1)
title("\$E_z\$ (V/m)")
pcolor(x,y,Ez,cmap="jet")
clim(0,20)
colorbar()
axis("scaled")
xlim(0,L)
ylim(0,l)
xlabel("\$x\$/m")
ylabel("\$y\$/m")
savefig("Ez.png",bbox="tight")
clf()

figure(2)
title("\$H_z\$ (A/m)")
pcolor(x,y,Bz/mu0,cmap="jet")
#clim(0,.2)
colorbar()
axis("scaled")
xlim(0,L)
ylim(0,l)
xlabel("x/m")
ylabel("\$y\$/m")
savefig("Hz.png",bbox="tight")
clf()

figure(3)
title("\$Z\$ (\$ \\Omega\$)")
pcolor(x,y,Z,cmap="jet")
clim(0,1000)
colorbar(ticks=[0,100,200,300,120*pi,500,60*pi^2,700,800,900,1000])

axis("scaled")
xlim(0,L)
ylim(0,l)
#xlabel("x/m")
ylabel("\$y\$/m")
savefig("Z.png",bbox="tight")
clf()


import Random: randn
import JSON: json

# CIR process with parameters (a, b, σ, X_0) = (1.2, 3.1, 0.5, 2.2)
a = 1.2
b = 3.1
sigma = 0.5
x0 = 2.2

# generate samples
T = 10.0
times = LinRange(0.0, T, 2501)
count = 100
trajectories = zeros(length(times), count)
normals = randn(length(times)-1, count)
for i in 1:count
  trajectories[1,i] = x0
  for k in 2:length(times)
    dt = times[k] - times[k-1]
    dw = normals[k-1, i] * sqrt(dt)
    x = trajectories[k-1,i]
    trajectories[k,i] = x + a * (b - x) * dt + sigma * sqrt(abs(x)) * dw
  end
end

# export to json
write(
  "data.json",
  json(Dict(
    :a => a,
    :b => b,
    :sigma => sigma,
    :samples => map(
      i -> map(
        ((x, t), ) -> Dict(:xt => x, :t => t, :sample => i),
        zip(trajectories[:,i], times)
      ),
      1:count
    )
  ))
)


#include("../src/likelihood_v2.jl")
include("../src/likelihood_and_diff.jl")

using Distributions, TransformVariables

gamma_mv(mu,std) = Gamma(mu^2/std^2,std^2/mu)
gammainv_mv(mu,std) = Gamma(mu^2/std^2,(std^2/mu)^(-1))

prior_bet = Beta(100,1.01010101)
prior_epsilon = Normal(4,1.5)
prior_theta = Beta(3,1.5)
prior_sig = gamma_mv(2,0.5)
prior_phi = gamma_mv(2,0.5)
prior_phi_pi = gamma_mv(1,0.4)
prior_phi_y = gamma_mv(0.5/4,0.2)
prior_rho_v = Beta(0.88,0.88)
prior_s2 = InverseGamma(3.76,2.76)

#gammainv(alpha,mu) = InverseGamma(alpha,(alpha-1)*mu)

#Plots.plot(3.75:0.05:3.8, std.(gammainv.(3.75:0.05:3.8,1)))

# function posterior(par,data)
#     aa,bb,llh = log_like_dsge(par,data)
#     return llh+logpdf(prior_bet,par[2])+logpdf(prior_epsilon,par[3])+logpdf(prior_theta,par[4])+logpdf(prior_sig,par[5])+logpdf(prior_s2,par[6])+logpdf(prior_phi,par[7])+logpdf(prior_phi_pi,par[8])+logpdf(prior_phi_y,par[9])+logpdf(prior_rho_v,par[10])
# end


module NMF_VB

include("../Misc.jl")
using .Misc

using Distributions, SpecialFunctions

export standard_VB, online_VB

function standard_VB(X::Array{ℜ,2}, K::Ƶ ; μ::ℜ=nanmean(X), γ::ℜ=0.1, EPOCHS::Ƶ=1, ϵ::ℜ=1e-16) where {ℜ<:Real, Ƶ<:Int}
    I::Ƶ, J::Ƶ = size(X)

    a::ℜ, b::ℜ = I*J*γ, γ/μ
    α_K, α_JK, α_IK = fill(a/K,K), fill(a/(K*J),J,K), fill(a/(K*I),I,K)
    S₊ = sum(X)

    #log_λ = log(rand(Gamma(a,1.0/b)))
    log_λ = digamma(S₊ + a) - log(b + 1)
    log_θ_K = log.(rand(Dirichlet(α_K.+0.1)))
    log_θ_JK = reshape([log(θ_jk) for k=1:K for θ_jk=rand(Dirichlet(α_JK[:,k].+0.1))],J,K)
    log_θ_IK = reshape([log(θ_ik) for k=1:K for θ_ik=rand(Dirichlet(α_IK[:,k].+0.1))],I,K)

    S_K, S_JK, S_IK, S⁺::ℜ = zeros(ℜ,K), zeros(ℜ,J,K), zeros(ℜ,I,K), 0.0
    s, p, log_ρ, log_ρ₊ = Array{ℜ}(undef,K), Array{ℜ}(undef,K), Array{ℜ}(undef,K), 0.0

    ELBO::Array{ℜ} = zeros(ℜ,EPOCHS)
    X_full = similar(X)

    for eph=1:EPOCHS
        S_K .= 0.0
        S_JK .= 0.0
        S_IK .= 0.0
        S⁺ = 0.0

        for j=1:J, i=1:I #order of traversal is important
            log_ρ .= log_λ .+ log_θ_K .+ log_θ_JK[j,:] .+ log_θ_IK[i,:]
            log_ρ₊ = logsumexp(log_ρ)
            p .= exp.(log_ρ .- log_ρ₊)

            X_full[i,j] = isnan(X[i,j]) ? exp(log_ρ₊) : X[i,j]
            s .= X_full[i,j] .* p

            S_JK[j,:] .+= s
            S_IK[i,:] .+= s
            S_K[:] .+= s
            S⁺ += X_full[i,j]

            ELBO[eph] += isnan(X[i,j]) ? X_full[i,j] : X[i,j]*log_ρ₊ - lgamma(X[i,j] + 1.0)
        end
        ELBO[eph] += a*log(b) - (S⁺+a)*log(b+1.0) - sum(lgamma.(α_JK)) + sum(lgamma.(α_JK .+ S_JK))
        ELBO[eph] += sum(lgamma.(α_K)) - sum(lgamma.(α_IK)) - sum(lgamma.(α_K .+ S_K)) + sum(lgamma.(α_IK .+ S_IK))
        ELBO[eph] -= S⁺ * log_λ + sum(S_K .* log_θ_K) + sum(S_JK .* log_θ_JK) + sum(S_IK .* log_θ_IK)

        log_λ = digamma(S⁺+a) - log(b+1.0)
        log_θ_K .= digamma.(S_K.+α_K) .- digamma(S⁺+a)
        log_θ_JK .= digamma.(S_JK.+α_JK) .- digamma.(S_K.+α_K)'
        log_θ_IK .= digamma.(S_IK.+α_IK) .- digamma.(S_K.+α_K)'

    end

    return ELBO, X_full, log_λ, (log_θ_K, log_θ_IK, log_θ_JK)
end

function online_VB(X::Array{ℜ,2}, K::Ƶ, Ω::AbstractArray{ℜ,1}; μ::ℜ=nanmean(X), γ::ℜ=0.1, ϵ::ℜ=1e-16) where {ℜ<:Real, Ƶ<:Int}
    I::Ƶ, J::Ƶ = size(X)

    a::ℜ, b::ℜ = I*J*γ, γ/μ
    α_K, α_JK, α_IK = fill(a/K,K), fill(a/(K*J),J,K), fill(a/(K*I),I,K)

    log_λ = log(rand(Gamma(a,1.0/b)))
    log_θ_K = log.(rand(Dirichlet(α_K)))
    log_θ_JK = reshape([log(θ_jk) for k=1:K for θ_jk=rand(Dirichlet(α_JK[:,k]))],J,K)
    log_θ_IK = reshape([log(θ_ik) for k=1:K for θ_ik=rand(Dirichlet(α_IK[:,k]))],I,K)

    S_K, S_JK, S_IK, S⁺::ℜ = zeros(ℜ,K), zeros(ℜ,J,K), zeros(ℜ,I,K), 0.0
    s, p, log_ρ, log_ρ₊ = Array{ℜ}(undef,K), Array{ℜ}(undef,K), Array{ℜ}(undef,K), 0.0

    ELBO::Array{ℜ} = zeros(ℜ,length(Ω))
    X_full = similar(X)

    for (eph,ω) in enumerate(Ω)
        S_K .= 0.0
        S_JK .= 0.0
        S_IK .= 0.0
        S⁺ = 0.0

        for j=1:J, i=1:I #order of traversal is important
            log_ρ .= log_λ .+ log_θ_K .+ log_θ_JK[j,:] .+ log_θ_IK[i,:]
            log_ρ₊ = logsumexp(log_ρ)
            p .= exp.(log_ρ .- log_ρ₊)

            X_full[i,j] = isnan(X[i,j]) ? ω*exp(log_ρ₊) : rand(Binomial(Ƶ(X[i,j]),ω))
            s .= X_full[i,j] .* p

            S_JK[j,:] .+= s
            S_IK[i,:] .+= s
            S_K[:] .+= s
            S⁺ += X_full[i,j]

            ELBO[eph] += isnan(X[i,j]) ? X_full[i,j] : X[i,j]*log_ρ₊ - lgamma(X[i,j] + 1.0)
        end

        ELBO[eph] += a*log(b) - (S⁺+a)*log(b+1.0) - sum(lgamma.(α_JK)) + sum(lgamma.(α_JK .+ S_JK))
        ELBO[eph] += sum(lgamma.(α_K)) - sum(lgamma.(α_IK)) - sum(lgamma.(α_K .+ S_K)) + sum(lgamma.(α_IK .+ S_IK))
        ELBO[eph] -= S⁺ * log_λ + sum(S_K .* log_θ_K) + sum(S_JK .* log_θ_JK) + sum(S_IK .* log_θ_IK)

        log_λ = digamma(S⁺ + a) - log(b + ω) ## should be checked
        log_θ_K .= digamma.(S_K.+α_K) .- digamma(S⁺+a)
        log_θ_JK .= digamma.(S_JK.+α_JK) .- digamma.(S_K.+α_K)'
        log_θ_IK .= digamma.(S_IK.+α_IK) .- digamma.(S_K.+α_K)'

    end
    return ELBO, X_full, log_λ, (log_θ_K, log_θ_IK, log_θ_JK)
end

end


function gaussian_data(d, n, f; σ=1)
    X = rand(d, n)
    y = mapslices(f, X; dims=1) + rand(Normal(0, σ), 1, n)
    return X, y
end


"""
    one_side_group(G::SimpleGraph)

Let `A` be the adjacency matrix of `G`.
Return the `Set` of `Permutation`s `p` such that `A[p,:]` is an adjacency matrix.
"""
function one_side_group(G::SimpleGraph)::Set{Permutation}
    result = Set{Permutation}()
    n = NV(G)
    A = adjacency(G)
    allow = make_allow(A)
    perms = RPG(n, allow)
    @info "There are $(length(perms)) permutations to consider"
    PM = Progress(length(perms))

    for p in perms
        next!(PM)
        B = A[p, :]
        if is_adjacency(B)
            push!(result, Permutation(p))
        end
    end

    return result
end

export one_side_group