# Copyright (c) 2013: Iain Dunning, Miles Lubin, and contributors
#
# Use of this source code is governed by an MIT-style license that can be found
# in the LICENSE.md file or at https://opensource.org/licenses/MIT.

module TestCWrapper

using Ipopt
using Test

function test_hs071()
    # hs071
    # min x1 * x4 * (x1 + x2 + x3) + x3
    # st  x1 * x2 * x3 * x4 >= 25
    #     x1^2 + x2^2 + x3^2 + x4^2 = 40
    #     1 <= x1, x2, x3, x4 <= 5
    # Start at (1,5,5,1)
    # End at (1.000..., 4.743..., 3.821..., 1.379...)

    function eval_f(x::Vector{Float64})
        return x[1] * x[4] * (x[1] + x[2] + x[3]) + x[3]
    end

    function eval_g(x::Vector{Float64}, g::Vector{Float64})
        # Bad: g    = zeros(2)  # Allocates new array
        # OK:  g[:] = zeros(2)  # Modifies 'in place'
        g[1] = x[1] * x[2] * x[3] * x[4]
        return g[2] = x[1]^2 + x[2]^2 + x[3]^2 + x[4]^2
    end

    function eval_grad_f(x::Vector{Float64}, grad_f::Vector{Float64})
        # Bad: grad_f    = zeros(4)  # Allocates new array
        # OK:  grad_f[:] = zeros(4)  # Modifies 'in place'
        grad_f[1] = x[1] * x[4] + x[4] * (x[1] + x[2] + x[3])
        grad_f[2] = x[1] * x[4]
        grad_f[3] = x[1] * x[4] + 1
        return grad_f[4] = x[1] * (x[1] + x[2] + x[3])
    end

    function eval_jac_g(
        x::Vector{Float64},
        rows::Vector{Int32},
        cols::Vector{Int32},
        values::Union{Nothing,Vector{Float64}},
    )
        if values === nothing
            # Constraint (row) 1
            rows[1] = 1
            cols[1] = 1
            rows[2] = 1
            cols[2] = 2
            rows[3] = 1
            cols[3] = 3
            rows[4] = 1
            cols[4] = 4
            # Constraint (row) 2
            rows[5] = 2
            cols[5] = 1
            rows[6] = 2
            cols[6] = 2
            rows[7] = 2
            cols[7] = 3
            rows[8] = 2
            cols[8] = 4
        else
            # Constraint (row) 1
            values[1] = x[2] * x[3] * x[4]  # 1,1
            values[2] = x[1] * x[3] * x[4]  # 1,2
            values[3] = x[1] * x[2] * x[4]  # 1,3
            values[4] = x[1] * x[2] * x[3]  # 1,4
            # Constraint (row) 2
            values[5] = 2 * x[1]  # 2,1
            values[6] = 2 * x[2]  # 2,2
            values[7] = 2 * x[3]  # 2,3
            values[8] = 2 * x[4]  # 2,4
        end
        return
    end

    function eval_h(
        x::Vector{Float64},
        rows::Vector{Int32},
        cols::Vector{Int32},
        obj_factor::Float64,
        lambda::Vector{Float64},
        values::Union{Nothing,Vector{Float64}},
    )
        if values === nothing
            # Symmetric matrix, fill the lower left triangle only
            idx = 1
            for row in 1:4
                for col in 1:row
                    rows[idx] = row
                    cols[idx] = col
                    idx += 1
                end
            end
        else
            # Again, only lower left triangle
            # Objective
            values[1] = obj_factor * (2 * x[4])  # 1,1
            values[2] = obj_factor * (x[4])  # 2,1
            values[3] = 0                      # 2,2
            values[4] = obj_factor * (x[4])  # 3,1
            values[5] = 0                      # 3,2
            values[6] = 0                      # 3,3
            values[7] = obj_factor * (2 * x[1] + x[2] + x[3])  # 4,1
            values[8] = obj_factor * (x[1])  # 4,2
            values[9] = obj_factor * (x[1])  # 4,3
            values[10] = 0                     # 4,4

            # First constraint
            values[2] += lambda[1] * (x[3] * x[4])  # 2,1
            values[4] += lambda[1] * (x[2] * x[4])  # 3,1
            values[5] += lambda[1] * (x[1] * x[4])  # 3,2
            values[7] += lambda[1] * (x[2] * x[3])  # 4,1
            values[8] += lambda[1] * (x[1] * x[3])  # 4,2
            values[9] += lambda[1] * (x[1] * x[2])  # 4,3

            # Second constraint
            values[1] += lambda[2] * 2  # 1,1
            values[3] += lambda[2] * 2  # 2,2
            values[6] += lambda[2] * 2  # 3,3
            values[10] += lambda[2] * 2  # 4,4
        end
        return
    end

    n = 4
    x_L = [1.0, 1.0, 1.0, 1.0]
    x_U = [5.0, 5.0, 5.0, 5.0]

    m = 2
    g_L = [25.0, 40.0]
    g_U = [2.0e19, 40.0]

    prob = Ipopt.CreateIpoptProblem(
        n,
        x_L,
        x_U,
        m,
        g_L,
        g_U,
        8,
        10,
        eval_f,
        eval_g,
        eval_grad_f,
        eval_jac_g,
        eval_h,
    )

    prob.x = [1.0, 5.0, 5.0, 1.0]
    solvestat = Ipopt.IpoptSolve(prob)

    @test solvestat == 0
    @test prob.x[1] ≈ 1.0000000000000000 atol = 1e-5
    @test prob.x[2] ≈ 4.7429996418092970 atol = 1e-5
    @test prob.x[3] ≈ 3.8211499817883077 atol = 1e-5
    @test prob.x[4] ≈ 1.3794082897556983 atol = 1e-5
    @test prob.obj_val ≈ 17.014017145179164 atol = 1e-5

    # This tests callbacks.
    function intermediate(
        alg_mod::Cint,
        iter_count::Cint,
        obj_value::Float64,
        inf_pr::Float64,
        inf_du::Float64,
        mu::Float64,
        d_norm::Float64,
        regularization_size::Float64,
        alpha_du::Float64,
        alpha_pr::Float64,
        ls_trials::Cint,
    )
        return iter_count < 1  # Interrupts after one iteration.
    end

    Ipopt.SetIntermediateCallback(prob, intermediate)

    solvestat = Ipopt.IpoptSolve(prob)

    @test solvestat == 5

    # Test setting some options
    # String option
    println("\nString option")
    Ipopt.AddIpoptStrOption(prob, "hessian_approximation", "exact")
    @test_throws(
        ErrorException,
        Ipopt.AddIpoptStrOption(prob, "hessian_approximation", "badoption"),
    )
    println("\nInt option")
    # Int option
    @test Ipopt.AddIpoptIntOption(prob, "file_print_level", 3) === nothing
    @test_throws(
        ErrorException,
        Ipopt.AddIpoptIntOption(prob, "file_print_level", -1),
    )
    # Double option
    println("\nFloat option")
    Ipopt.AddIpoptNumOption(prob, "derivative_test_tol", 0.5)
    @test_throws(
        ErrorException,
        Ipopt.AddIpoptNumOption(prob, "derivative_test_tol", -1.0),
    )

    # Test opening an output file
    Ipopt.OpenIpoptOutputFile(prob, "blah.txt", 5)
    finalize(prob) # Needed before the `rm` on Windows.
    # unlink the output file
    rm("blah.txt")
    return
end

end  # TestCWrapper

runtests(TestCWrapper)


"""
MLEPoisson(data::AbstractVector)
MLEPoisson estimates intensity of homogenous poisson process. Homogenous poisson process has one independent prameter, intensity $\lambda$, and the result of maximum likelihood shows following relationship
$$
\lambda = E[t_{i}-t_{i-1}].
$$
"""

function MLEPoisson(x::AbstractVector;data::AbstractVector = x)
    mu = diff(x)
    return 1/mean(mu)
end


using BenchmarkTools
using Distributions
import Cubature
import HCubature
import QuadGK

p(x::Float64) = exp(-0.5 * x^2) / √(2π)
p1(x) = p(x[1])
p2(xy) = p(xy[1]) * p(xy[2])
p3(xyz) = p(xyz[1]) * p(xyz[2]) * p(xyz[3])
p4(xyzw) = p(xyzw[1]) * p(xyzw[2]) * p(xyzw[3]) * p(xyzw[4])

function mybench(m::Module)
    @info "start bench $m"
    # 1 次元用のルーチン
    @btime $m.hquadrature(p, -10, 10)[1]
    # 多次元用のルーチンで試す
    @btime $m.hcubature(p1, [-10], [10])[1]
    @btime $m.hcubature(p2, [-10, -10], [10, 10])[1]
    @btime $m.hcubature(p3, [-10, -10, -10], [10, 10, 10])[1]
    @btime $m.hcubature(p4, [-10, -10, -10, -10], [10, 10, 10, 10])[1]
    @info "end bench $m"
end

mybench(Cubature)
mybench(HCubature)
@info "Appendix QuadGK"
# one-dimensional numerical integration
@btime QuadGK.quadgk(p, -10, 10)[1]


function jt11c()
#
#  test polynomial suggested by Jenkins and Traub
#
    m = 25;
    y = exp.((im*pi) .*  (1-m:m-1) ./ (2*m))
    z = 0.9*exp.((im*pi) .* (m:3*m) ./ (2*m))
    u = [y; z]
    p = poly(u)
    z = [u ones(length(u))]
    p, PolyZeros(z)
end


using LinearAlgebra

A = [1 2 3; 4 5 6; 7 8 9]

for t in [
Symmetric
Hermitian
UpperTriangular
LowerTriangular
Tridiagonal
Diagonal
]
    show(stdout, MIME("text/plain"), t(A))
    println()
end

A = [1, 2, 3]
B = [5, 6]
for t in [
SymTridiagonal
]
    show(stdout, MIME("text/plain"), t(A, B))
    println()
end

A = [1, 2, 3]
B = [5, 6]
for t in [
Bidiagonal
]
    show(stdout, MIME("text/plain"), t(A, B, :U))
    println()
    show(stdout, MIME("text/plain"), t(A, B, :L))
    println()
end

for t in [
UniformScaling
]
    println(t(2))
end

#=
3×3 Symmetric{Int64,Array{Int64,2}}:
 1  2  3
 2  5  6
 3  6  9
3×3 Hermitian{Int64,Array{Int64,2}}:
 1  2  3
 2  5  6
 3  6  9
3×3 UpperTriangular{Int64,Array{Int64,2}}:
 1  2  3
 ⋅  5  6
 ⋅  ⋅  9
3×3 LowerTriangular{Int64,Array{Int64,2}}:
 1  ⋅  ⋅
 4  5  ⋅
 7  8  9
3×3 Tridiagonal{Int64,Array{Int64,1}}:
 1  2  ⋅
 4  5  6
 ⋅  8  9
3×3 Diagonal{Int64,Array{Int64,1}}:
 1  ⋅  ⋅
 ⋅  5  ⋅
 ⋅  ⋅  9
3×3 SymTridiagonal{Int64,Array{Int64,1}}:
 1  5  ⋅
 5  2  6
 ⋅  6  3
3×3 Bidiagonal{Int64,Array{Int64,1}}:
 1  5  ⋅
 ⋅  2  6
 ⋅  ⋅  3
3×3 Bidiagonal{Int64,Array{Int64,1}}:
 1  ⋅  ⋅
 5  2  ⋅
 ⋅  6  3
UniformScaling{Int64}
2*I
=#


function toh01()
#
#  generalization of K.C. Toh and L. N. Trefethen
#
    k = [(-10:9)...]
    z = 2.0 .* (k .+ 0.5) ./ 19 + im .* sin.((2*pi) .* (k .+ 0.5) ./ 19)
    p = poly(z)
    z = [z ones(20)]

    p, PolyZeros(z)
end


"""
A reservoir Outlet should always have the following:
    - An elevation field z
    - A discharge function.

The discharge function depends on the hydralic head measured from the elevation
of the outlet (z) to the reservoir water surface.
"""

abstract type Outlet end

discharge(o::Outlet; z) = z > o.z ? discharge(o, z - o.z) : 0.0

discharge(o::Outlet, h) =
    error("Please implement a discharge function for type ", typeof(o))

Base.@kwdef struct Orifice <: Outlet
    C::Float64
    A::Float64
    z::Float64
    g::Float64 = 9.81
end

discharge(o::Orifice, h) = o.C * o.A * √(2.0 * o.g * h)

Base.@kwdef struct Weir <: Outlet
    C::Float64
    B::Float64
    z::Float64
end

discharge(o::Weir, h) = o.C * o.B * h^1.5


module ContinuedFractions

import Base: start, done, next, length, eltype, collect

export ContinuedFraction, quotients, convergents, ConvergentIterator

immutable ContinuedFraction{T<:Integer}
	quotients::Vector{T}
end

quotients(cf::ContinuedFraction) = cf.quotients

immutable ConvergentIterator{T<:Integer}
    qs::Vector{T}
end

start(::ConvergentIterator) = 1
done(it::ConvergentIterator, state::Int) = state > length(it.qs)
length(it::ConvergentIterator) = length(it.qs)

function next(it::ConvergentIterator, state::Int)
    convergent = Rational(ContinuedFraction(it.qs[1:state]))
    convergent, state + 1
end

eltype(it::ConvergentIterator) = Rational{eltype(it.qs)}
collect(it::ConvergentIterator) = collect(eltype(it), it)

convergents(cf::ContinuedFraction) = convergents(quotients(cf))
convergents{T<:Integer}(qs::Vector{T}) = ConvergentIterator(qs)

function Base.Rational(cf::ContinuedFraction)
    qs = quotients(cf)
    isempty(qs) && return 0 // 1
    length(qs) == 1 && return qs[1] // 1

    remainder = qs[2:end]
    rat = Rational(ContinuedFraction(remainder))
    (qs[1] * rat.num + rat.den) // rat.num
end

function ContinuedFraction{T<:Integer}(rat::Rational{T})
    a = div(rat.num, rat.den)
    a * rat.den == rat.num && return ContinuedFraction(T[a])  # Exact!

    cf = ContinuedFraction(rat.den//(rat.num - a*rat.den))
    unshift!(quotients(cf), a) # insert at index 1
    cf
end

# let rationalize handle conversion from floating point
ContinuedFraction(x::BigFloat) = ContinuedFraction(rationalize(BigInt, x))
ContinuedFraction(x::AbstractFloat) = ContinuedFraction(rationalize(x))

ContinuedFraction(x::Integer) = ContinuedFraction([x])

end # module ContinuedFractions


module PDE

using GPUBenchmarks, BenchmarkTools, Primes

description = """
Kuramoto-Sivashinsky algorithm benchmark ([original benchmark](https://github.com/johnfgibson/julia-pde-benchmark/blob/master/1-Kuramoto-Sivashinksy-benchmark.ipynb)).

This benchmark is dominated by the cost of the FFT, leading to worse results for OpenCL with
CLFFT compared to the faster CUFFT.
Similarly the multithreaded backend doesn't improve much over base with the same FFT implementation.
Result of the benchmarked PDE:
![](https://github.com/JuliaGPU/GPUBenchmarks.jl/blob/master/results/plots/pde_result.png?raw=true)
"""

sq3(x) = Complex64(x * x * x) # cudanative doesn't like Complex64 directly broadcasted.

# source: http://nbviewer.jupyter.org/url/homepages.warwick.ac.uk/staff/C.Ortner/julia/PlaneWaves.ipynb
# an optimised implementation of CH_vectorised!

function inner_loop(
        nruns,
        planv, planw, planwi, u0, u, v, w, Â,
        c1, c2, c3, c4
    )
    u .= identity.(u0)
    w .= tocomplex64.(u0)
    for n = 1:nruns
        v .= sq3.(u)
        planv * v
        planw * w
        @. w = ((1f0+c1*Â)*w - (c2*Â)*v) / ((1f0+c3*Â+c4)*Â)
        planwi * w
        u .= real.(w)
    end
    synchronize(u)
    return u
end

function makeresult(bench, N, device, hardware, mdiff)
    BenchResult(
        "PDE",
        bench,
        N,
        Float32,
        string(device),
        hardware,
        @__FILE__,
        mdiff
    )
end

function execute2(device)
    hardware, array_type = init(device)
    T = Float32
    results = BenchResult[]
    for x in (4,)
        N = 2 ^ x
        # initialisations
        h = 2*π/N; epsn = h * 3; C = 2/epsn; tau = epsn * h
        k = [0:N/2; -N/2+1:-1]
        acpu = kron(k.^2, ones(1,N)) + kron(ones(N), k'.^2)
        ucpu = 2*(rand(N, N)-0.5)

        Â = array_type(T.(acpu))
        u = array_type(T.(ucpu))

        w = tocomplex64.(u)
        v = copy(w)
        c1 = (C*tau + tau/epsn)
        c2 = (tau / epsn)
        c3 = (epsn * tau)
        c4 = (C*tau)
        planv = plan_fft!(v)
        planw = plan_fft!(w)
        planwi = plan_ifft!(w)
        nruns = 5
        u0 = copy(u)
        bench = @benchmark $(inner_loop)(
                $nruns,
                $planv, $planw, $planwi,$u0, $u, $v, $w, $Â,
                $c1, $c2, $c3, $c4
        )
        wcpu = tocomplex64.(ucpu)
        vcpu = copy(wcpu)
        planvcpu = plan_fft!(vcpu)
        planwcpu = plan_fft!(wcpu)
        planwicpu = plan_ifft!(wcpu)
        inner_loop(
                nruns,
                planvcpu, planwcpu, planwicpu, copy(ucpu), ucpu, vcpu, wcpu, acpu,
                c1, c2, c3, c4
        )
        println(Array(ucpu))
        # mdiff = meandifference(ucpu, u)
        # @show mdiff
        # push!(results, makeresult(bench, N, device, hardware, mdiff))
        # free(Â); free(u0); free(u); free(v); free(w)
    end
    results
end

# execute(Float32, 512, :opencl)

function CH_memory_af!(nruns, N, AT)
    # initialisations
    h = Float32(2*π/N); epsn = Float32(h * 3); C = Float32(2/epsn); tau = Float32(epsn * h)
    k = [0:N/2; -N/2+1:-1]
    Â = AT((Float32.(kron(k.^2, ones(1,N)) + kron(ones(N), k'.^2))))
    u = AT(Float32.((2*(rand(N, N)-0.5))))

    # ============= ACTUAL CODE THAT IS BEING TESTED ======================
    # allocate arrays and define constants
    w = AT{Complex64}(u)
    v = copy(w)
    c1 = (C*tau + tau/epsn)
    c2 = (tau / epsn)
    c3 = (epsn * tau)
    c4 = (C*tau)
    tic()
    for n = 1:nruns
        v .= complex.(u .* u .* u)
        v = fft(v)
        w = fft(w)
        w .= (( (1f0 + c1) .* Â) .* w .- (c2 .* Â) .* v) ./ ((1f0 + c3 .* Â .+ c4) .* Â)
        w = ifft(w)
        u .= real.(w)
    end
    GPUArrays.synchronize(u)
    toc()
    # ======================================================================
    u
end

# source: https://github.com/johnfgibson/julia-pde-benchmark/blob/master/1-Kuramoto-Sivashinksy-benchmark.ipynb
function inner_ks(IFFT!, FFT!, Nt, Nn, Nn1, u, G, A_inv, B, dt2, dt32)
    for n = 1:Nt
        Nn1 .= Nn       # shift nonlinear term in time
        Nn .= u         # put u into Nn in prep for comp of nonlinear term

        IFFT! * Nn
            # transform Nn to gridpt values, in place
        Nn .= Nn .* Nn   # collocation calculation of u^2
        FFT!*Nn        # transform Nn back to spectral coeffs, in place

        Nn .= G .* Nn    # compute Nn == -1/2 d/dx (u^2) = -u u_x

        # loop fusion! Julia translates the folling line of code to a single for loop.
        u .= A_inv .* (B .* u .+ dt32 .* Nn .- dt2 .* Nn1)
    end
    synchronize(u)
end

function makeresult(bench, N, device, hardware, mdiff)
    BenchResult(
        "PDE",
        bench,
        N,
        Complex64,
        string(device),
        hardware,
        @__FILE__,
        mdiff
    )
end
function execute(device)
    hardware, AT = init(device)
    results = BenchResult[]
    is_gpuarrays(device) || device == :julia_base || return results
    T = Float32
    for i = 1:7
        N = 10^i
        Lx = T(64*pi)
        Nx = T(N)
        dt = T(1/16)
        Nt = 50

        x = Lx*(0:Nx-1)/Nx
        u = T.(cos.(x) + 0.1*sin.(x/8) + 0.01*cos.((2*pi/Lx)*x))

        u = AT((T(1)+T(0)im)*u)             # force u to be complex
        Nx = length(u)                      # number of gridpoints
        kx = T.(vcat(0:Nx/2-1, 0:0, -Nx/2+1:-1))# integer wavenumbers: exp(2*pi*kx*x/L)
        alpha = T(2)*pi*kx/Lx                  # real wavenumbers:    exp(alpha*x)

        D = T(1)im*alpha                       # spectral D = d/dx operator

        L = alpha.^2 .- alpha.^4            # spectral L = -D^2 - D^4 operator

        G = AT(T(-0.5) .* D)               # spectral -1/2 D operator, to eval -u u_x = 1/2 d/dx u^2

        # convenience variables
        dt2  = T(dt/2)
        dt32 = T(3*dt/2)
        A_inv = AT((ones(T, Nx) - dt2*L).^(-1))
        B = AT(ones(T, Nx) + dt2*L)

        # compute in-place FFTW plans
        FFT! = plan_fft!(u)
        IFFT! = plan_ifft!(u)

        # compute nonlinear term Nn == -u u_x
        powed = u .* u
        Nn = G .* fft(powed);    # Nn == -1/2 d/dx (u^2) = -u u_x
        Nn1 = copy(Nn);        # Nn1 = Nn at first time step
        FFT! * u;

        # timestepping loop
        bench = @benchmark $inner_ks($(IFFT!), $(FFT!), $Nt, $Nn, $Nn1, $u, $G, $A_inv, $B, $dt2, $dt32)
        push!(results, makeresult(bench, N, device, hardware, 0.0))
    end
    results
end

function ksintegrateNaive(u, Lx, dt, Nt, nsave)
    Nx = length(u)                  # number of gridpoints
    x = collect(0:(Nx-1)/Nx)*Lx
    kx = vcat(0:Nx/2-1, 0, -Nx/2+1:-1)  # integer wavenumbers: exp(2*pi*kx*x/L)
    alpha = 2*pi*kx/Lx              # real wavenumbers:    exp(alpha*x)
    D = 1im*alpha;                  # D = d/dx operator in Fourier space
    L = alpha.^2 - alpha.^4         # linear operator -D^2 - D^4 in Fourier space
    G = -0.5*D                      # -1/2 D operator in Fourier space

    Nsave = div(Nt, nsave)+1        # number of saved time steps, including t=0
    t = (0:Nsave)*(dt*nsave)        # t timesteps
    U = zeros(Nsave, Nx)            # matrix of u(xⱼ, tᵢ) values
    U[1,:] = u                      # assign initial condition to U
    s = 2                           # counter for saved data

    dt2  = dt/2
    dt32 = 3*dt/2;
    A_inv = (ones(Nx) - dt2*L).^(-1)
    B     =  ones(Nx) + dt2*L

    Nn  = G.*fft(u.*u) # -u u_x (spectral), notation Nn = N^n     = N(u(n dt))
    Nn1 = copy(Nn)     #                   notation Nn1 = N^{n-1} = N(u((n-1) dt))
    u  = fft(u)        # transform u to spectral

    # timestepping loop
    for n = 1:Nt
        Nn1 = copy(Nn)                 # shift nonlinear term in time: N^{n-1} <- N^n
        Nn  = G.*fft(real(ifft(u)).^2) # compute Nn = -u u_x

        u = A_inv .* (B .* u + dt32*Nn - dt2*Nn1)

        if mod(n, nsave) == 0
            U[s,:] = real(ifft(u))
            s += 1
        end
    end
    t,U
end
#
# using FileIO, Interpolations, Colors, GPUBenchmarks, GPUArrays, ColorVectorSpace, FixedPointNumbers
# Lx = 64*pi
# Nx = 1024
# dt = 1/16
# nsave = 8
# Nt = 3200
#
# x = Lx*(0:Nx-1)/Nx
# u = cos.(x) + 0.1*sin.(x/8) + 0.01*cos.((2*pi/Lx)*x);
# t,U = ksintegrateNaive(u, Lx, dt, Nt, nsave)
# cn = 100
# cmap = interpolate(colormap("Oranges", cn), BSpline(Linear()), OnCell());
# mini, maxi = extrema(U)
# img_color = map(U) do val
#     val = (val - mini) / (maxi - mini)
#     val = 1 - clamp(val, 0f0, 1f0);
#     idx = (val * (cn - 1)) + 1.0
#     RGB{N0f8}(cmap[idx])
# end
# save(GPUBenchmarks.dir("results", "plots", "pde_result.png"), img_color)

end


# define exceptions for stopping conditions in algorithm
type OptimalPointFound <: Exception end
type UnboundedFunctionException <: Exception end

function get_min(x, d, assts)
    n = length(assts)
    e = zeros(n)
    e[assts] = d
    ratios = []
    for i in 1:n
        if (assts[i]) & (e[i] > 0)
            push!(ratios, (x[i]/e[i], i))
        end
    end

    try
        return minimum(ratios)
    catch
        println(ratios)
    end
end

function get_q(s_N, assts)
    n = length(assts)
    e = zeros(n)
    e[!assts] = s_N

    try
        return indmax(e.<0)
    catch
            print e
    end
end

# a single iteration of the simplex algorithm
function simplex_iteration(assts, x, A, b, c)
    """
    We have a linear program of the form: min c^T x s.t. Ax = b

    arguments:
        assts: true indicates the element belongs to the basic set and false to the nonbasic set
        x: the vector x as given above in the LP
        A: constraint matrix, of the form Ax = b
        b: solutions of constraints
        c: coefficients of the LP function
    """

    B = A[:,assts]
    N = A[:,!assts]

    x_B = x[assts]
    x_N = x[!assts]

    # solve B^T lambda = c_B for lambda
    lambda = B' \ c[assts]

    # compute s_N = c_N - N^\top \lambda
    s_N = c[!assts] - N' * lambda

    # check if all elements of s_N are >= 0
    if all(s_N .>= 0)
        throw(OptimalPointFound())
    end

    # select q \in N with s_q < 0 as entering index
    q = get_q(s_N, assts) # here we always choose the first negative element

    # solve Bd = A_q for d
    d = B \ A[:,q]

    # check d
    if all(s_N .>= 0)
        throw(UnboundedFunctionException())
    end

    # calculate x_q+
    x_q, p = get_min(x, d, assts)

    # update x
    x[assts] = x[assts] - d * x_q
    x[q] = x_q

    # update the assts
    assts[p] = !assts[p]
    assts[q] = !assts[q]

    # returns new assts, x
    return assts, x

end

function run_simplex(assts, x, A, b, c, num_iters, verbose=false)

    for i in 1:num_iters
        #println("Starting iteration: ", i)

        try
            assts, x = simplex_iteration(assts, x, A, b, c)

            if verbose
                println("Resulting x, assts: \n\t", (x,assts))
            end

        catch err
            if isa(err, UnboundedFunctionException)

                println("Unbounded function exception!")
                return assts, x

            elseif isa(err, OptimalPointFound)

                println("Optimal point found!")

                if verbose
                    println("Optimal x, assts: \n\t", (x,assts))
                end

                return assts, x
            else
                println(err)

                throw(err)
            end
        end

    end
    return assts, x
end

function get_starting_values(A, b)
    """
    given a LP min c'x s.t. Ax = b, we want to create the new LP e'z s.t. Ax + Ez = b, where x=0, e=ones(.)

    A: the original constraint matrix
    b: the original b

    returns new A, x, c, assts to pass into simplex algorithm
    """
    nrows, ncols = size(A)
    # init x, c
    x = zeros(ncols + nrows)
    c = zeros(ncols + nrows)

    # add z to x
    x[ncols+1:ncols+nrows,:] = abs(b')
    c[ncols+1:ncols+nrows,:] = 1.

    # assignments are non-zero elements of x
    assts = (x .!= 0)

    E = zeros(nrows, nrows)
    vals = b .> 0

    for i in 1:nrows
        if vals[i]
            E[i,i] = 1
        else
            E[i,i] = -1
        end
    end

    return [A E], x, c, assts

end

function run_two_stage_simplex(A, b, c, num_iters)
    time1 = time()
    A0, x0, c0, assts0 = get_starting_values(A, b)

    nrows, ncols = size(A)
    l = length(x0)

    println("\nRunning Phase I of simplex algorithm\n")
    # run phase I
    assts_start, x_start = run_simplex(assts0,x0,A0,b,c0,num_iters)

    # run phase II
    try
        @assert x_start[l] == 0
    catch err
        println("No feasible solution for m=", size(A)[2])
    end

    # discard z
    xnew = x_start[1:l-nrows]
    assts_new = assts_start[1:l-nrows]

    println("\nRunning Phase II of simplex algorithm \n")

    x, assts = run_simplex(assts_new,xnew,A,b,c,num_iters)

    time2 = time()

    @printf("\nTime: %.5f (s)", time2-time1)

    return x, assts, (time2-time1)

end

#run_two_stage_simplex(A, b, c, 10)

function solve_subproblem(assts, x_k, G, c, A, b)
    g_k = G * x_k + c

    ## if all assignments are false
    if all(assts .== false)
        return G \ -g_k

    else
        dimx = length(x_k)
        A_w = A[assts,:]
        k,k = size(G)
        m,n = size(A_w)

        # construct matrix
        mat = [G A_w'; A_w zeros(k+m - n,k+m - n)]

        # pad with 0's
        d, = size(g_k)
        answ = [-g_k; zeros(k+m - d)]

        # compute solution and get x
        sol = mat \ answ
        x = sol[1:dimx,:]

        return x
    end
end

function compute_multipliers(assts, x_k, G, c, A)
    g = G * x_k + c
    lambda = A[assts,:]' \ g

    n = length(assts)
    return lambda, (1:n)[assts]
end

function compute_step_length(A, b, x_k, p_k, assts)
    """
    Returns step length alpha_k and blocking constraint of choice -- if the latter is 0, then alpha_k = 1
    """
    n = length(b)

    # by default, return 1 with no blocking constraints
    min = 1
    blocking = 0

    for i in 1:n
        # if i is in the working set, continue
        if assts[i]
            continue
        end

        a_i = A[i,:] ## this is a row vector so no need to transpose
        prod = a_i * p_k
        @assert length(prod) == 1

        # if a_i^ p_k >= 0, continue
        if (prod)[1] >= 0
            continue
        end

        val = (b[i] - a_i * x_k) / (prod)
        @assert length(val) == 1
        if val[1] < min
            min = val[1]
            blocking = i
        end
    end

    return min, blocking
end

function active_set_iteration(assts, x_k, G, c, A, b)
    """
    assts: assignments of constraint indices to the working set -- 1's are in the working set, 0's are not
    x_k: the current value of x_k obtained from the previous iteration
    G: the matrix in the quadratic function, i.e., x^T G x + x^T c
    c: the c from the quadratic function above
    A: matrix, where each row is the a_i from the constraint
    b: vector where each index is the b_i corresponding to constraint i
    """
    # solve subproblem to find p_k
    p_k = solve_subproblem(assts, x_k, G, c, A, b)

    #if all(p_k == 0) sufficient close to 0
    if all(abs(p_k-0) .<= 1e-6)

        if all(assts .== false)
            throw(OptimalPointFound())
        else

            # compute lagrange multipliers lambda_i that satisfy
            lambda, inds = compute_multipliers(assts, x_k, G, c, A)
        end

        # if lambda_i >= 0 for all i in W_k \cap I
        if all(lambda .>= 0)
            # stop with solution x* = x_k
            throw(OptimalPointFound())

        # (not all lambda_i >= 0)
        else
            # index of most negative multiplier lambda_j
            j = inds[indmin(lambda)]

            # remove j from working set
            assts[j] = false
            x_new = x_k
        end

    # (p_k != 0)
    else
        # compute step length alpha_k
        alpha_k, blocking = compute_step_length(A, b, x_k, p_k, assts)

        # update x_{k} += alpha_k * p_k
        x_new = x_k + alpha_k * p_k

        # if there are blocking constraints, update W_k (assts) by adding one of them to W_k
        if blocking != 0
            assts[blocking] = true
        end
    end

    return assts, x_new

end

function run_active_set(num_iters, assts, x_0, G, c, A, b, verbose=true)
    x_k = x_0
    for i in 1:num_iters
        if verbose
            println("Iteration:\t", i)
        end
        try
            assts, x_k = active_set_iteration(assts, x_k, G, c, A, b)
            if verbose
                println("Resulting x, assts: \n\t", (x_k,assts))
            end
        catch err
            if isa(err, OptimalPointFound)

                println("Optimal point found!")

                if verbose
                    println("Optimal x, assts: \n\t", (x_k,assts))
                end

                return assts, x_k
            else
                println(err)
                throw(err)
            end
        end

    end
    return assts, x_k
end

function run_active_set_full(num_iters, assts, x_0, G, c, A, b, verbose=true)
    x_k = x_0
    vals = []
    for i in 1:num_iters
        if verbose
            println("Iteration:\t", i)
        end
        try
            assts, x_k = active_set_iteration(assts, x_k, G, c, A, b)

            val = 1/2 * x_k' * G * x_k + c' * x_k
            push!(vals, val)

            if verbose
                println("Resulting x, assts: \n\t", (x_k,assts))
            end
        catch err
            if isa(err, OptimalPointFound)

                println("Optimal point found!")

                if verbose
                    println("Optimal x, assts: \n\t", (x_k,assts))
                end

                return assts, x_k, vals
            else
                println(err)
                throw(err)
            end
        end

    end
    return assts, x_k, vals
end


@testset "cg" begin

#test cg.jl

#positive semidefinite matrix
A=randn(200,100);  A=A'*A;
xt=randn(100)
b=A*xt

#inexact
(x,flag,relres,iter1) = cg(A,b,tol=1e-5,maxIter=1000,out=0);
@test norm(A*x-b)/norm(b) <= 1e-5

#test if very accurate solution can be achieved
(x,flag,relres,iter) = cg(A,b,tol=1e-14,maxIter=1000,out=0);
@test norm(A*x-b)/norm(b) <= 1.01e-14

#test with very good initial guess
x=deepcopy(xt) .+ eps();
(x,flag,relres,iter2) = cg(A,b,tol=1e-5,maxIter=1000,x=x,out=0);
@test norm(A*x-b)/norm(b) <= 1e-5
@test iter2<iter1 #test if the very good initial guess reduced the number of iterations

#test if the output is the input when the initial guess is the true solution
x=deepcopy(xt);
(x,flag,relres,iter2) = cg(A,b,tol=1e-14,maxIter=1000,x=x,out=0);
@test norm(A*x-b)/norm(b) <= 1e-14
@test iter2==1
@test x==xt

#test if simple preconditioner reduces the number of iterations
A=diagm(0 => (1:1:100))
(x1,flag,relres1,iter1) = cg(A,b,tol=1e-12,maxIter=1000,out=0); #unpreconditioned cg
Prec(input) = input./diag(A); #Jacobi preconditioner
(x2,flag,relres2,iter2) = cg(A,b,tol=1e-12,maxIter=1000,M=Prec,out=0);
@test iter2<iter1

end


### 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

# ╔═╡ 6b359fc5-ec8d-47ec-89ec-b1b214a37a82
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

# ╔═╡ c7838496-100f-4901-abcf-0d4e59fbc4a9
html"<button onclick='present()'>present</button>"

# ╔═╡ 44201f7b-84df-4b8d-aeec-0f142ac2008b
md"""
# Máquinas de corrente contínua (Ex. 7)
Motores de corrente contínua, exercício 7:
"""

# ╔═╡ ed4846d5-70d2-4deb-9a4a-41cdc8c99bdd
md"""
**Considere um motor de corrente contínua, com a seguinte chapa de características:**
"""

# ╔═╡ 1301d1ad-89e8-4282-ab35-1a6b8214bea0
(Pᵤ, Uₙ, nₙ, ηₙ, Rᵢ, Rₛ, Ns, Rd, Nd)=(17e3, 250, 1200, 0.85, 0.6, 0.1, 12, 200, 3000)

# ╔═╡ 1a427cf6-b2d3-4d9b-9cb5-4682d5f49869
begin
	nmag=1200 # velocidade angular da característica magnética, rpm
	Iex=[0,0.0132,0.03,0.033,0.067,0.1,0.133,0.167,0.2,0.233,0.267,0.3,0.333,0.367,0.4,0.433,0.467,0.5,0.533,0.567,0.6,0.633,0.667,0.7,0.733,0.767,0.8,0.833,0.867,0.9,0.933,0.966,1,1.033,1.067,1.1,1.133,1.167,1.2,1.233,1.267,1.3,1.333,1.367,1.4,1.433,1.466,1.5]
	E₀=[5.40, 6.67,13.33,16,31.3,45.46,60.26,75.06,89.74,104.4,118.86,132.86,146.46,159.78,172.18,183.98,195.04,205.18,214.52,223.06,231.2,238,244.14,249.74,255.08,259.2,263.74,267.6,270.8,273.6,276.14,278,279.74,281.48,282.94,284.28,285.48,286.54,287.3,287.86,288.36,288.82,289.2,289.38,289.57,289.69,289.81,289.95]
	plot(Iex, E₀, title="E₀=f(Iₑₓ), n=1200rpm", xlabel = "Iₑₓ (A)", ylabel="E₀ (V)", ylims=(0,300), framestyle = :origin, minorticks=10, label=:none, linewidth=2)
end

# ╔═╡ e2fc78d6-480b-4fe0-b844-0d4329c0d572
md"""
## Influência de $$ΔE$$ 💻
"""

# ╔═╡ 8bde3ad9-2d03-4557-ab50-a89ac8e834a3
md"""
!!! nota
	No enunciado original não é considerada a existência de reacção magnética do induzido, $$(ΔE=0\rm V)$$.
	No entanto, na versão *notebook* para que se possa verificar a influência de $$ΔE$$, nas características de funcionamento do motor DC, para os diferentes tipos de excitação, uma curva de $$ΔE=f(I_i)$$ é considerada como uma opção de análise."""

# ╔═╡ 61238dc4-3c9d-4b59-9486-501988806c27
"Com ΔE?", @bind z CheckBox()

# ╔═╡ c4d5e3f9-7808-48f6-8d33-05607d8e5a4e
begin
	Iᵢ=[0.0:15:120;]
	#Iᵢ=[0.0, 15, 30, 45, 60, 75, 90, 105, 120]
	ΔE=[0.0, 1.5, 4, 7.5, 12, 17, 23, 30.5, 40]*z
	plot(Iᵢ, ΔE, title="ΔE=f(Iᵢ)", xlabel = "Iᵢ (A)", ylabel="ΔE (V)", xlims=(0,120), ylims=(0,40), framestyle = :origin, minorticks=5, label=:none, linewidth=2)
end

# ╔═╡ f6fcec56-b080-4016-baf0-0ab728f255f3
md"""
## **a) $$R_c$$ para condições nominais**
**Com o motor em excitação derivação, determine o valor do reóstato de campo, nas
condições nominais $$(U_n, I_n, n_n)$$**;
"""

# ╔═╡ d9e431c5-be62-40c8-b5d6-59d5808e4436
md"""
Para se ter a informação completa das condições nominais do motor, falta determinar o valor da corrente nominal, $$I_n$$.\
Da chapa de características do motor conhecem-se a potência útil (potência mecânica) e rendimento nominais, $$P_u$$ e $$\eta_n$$, respectivamente, o que permite obter a potência absorvida, $$P_{ab}=U_nI_n$$. Assim:
"""

# ╔═╡ cde4847b-6c38-4bc6-a869-514774630c89
md"""
$$I_n=\frac{P_n}{\eta U_n}$$
"""

# ╔═╡ 1c70002d-e3fb-4d81-b0f9-ed00d69173ff
Iₙ=Pᵤ/(ηₙ*Uₙ);

# ╔═╡ 5b4c1912-126d-4fe8-87c5-f65b299f3642
md"""
Calculando obtém-se $$I_n=$$ $(Iₙ)A
"""

# ╔═╡ d8d6a6e9-df8d-47d2-832a-0d2126ce760e
md"""
A velocidade, $$n$$, é dependente do fluxo magnético, $$kϕ_0$$, que por sua vez depende da corrente de excitação, $$I_d$$ e da característica magnética da máquina.\
Assim, a imagem do fluxo magnético presente na máquina é dada pela a força contra-electromotriz de vazio do motor, $$E_0^{'}$$:
"""

# ╔═╡ 0ff562ff-7af2-4749-87f5-8766cb695893
md"""
$$E_0^{'}=E^{'}+ΔE$$
Sendo a  a força contra-electromotriz efectiva, $$E^{'}$$, dada por:\
"""

# ╔═╡ cf0f089a-1901-4ad1-8fe9-b9028679b109
md"""
$$E^{'}=U-R_iI_i$$
"""

# ╔═╡ de954f1d-a3ac-4830-acd0-85e64afdf0cd
# forma computacional de consultar a curva de ΔE(Ii), por interpolação dos dados através do Pkg Dierckx.jl
begin
	ΔE_int=Spline1D(Iᵢ,ΔE)
	ΔEₙ=ΔE_int(Iₙ)
	ΔEₙ=round(ΔEₙ, digits=1)
end;

# ╔═╡ 68969be8-0bee-4cca-85de-7a8d2aa35ee2
md"""
O valor de $$ΔE$$ para $$I_n$$, consultando a sua curva de q.d.t é: $$ΔE=$$ $(ΔEₙ)V.
"""

# ╔═╡ 8f5b0bd5-7a65-4ba3-bdd1-7cc3128fa8d8
E=Uₙ-Rᵢ*Iₙ;

# ╔═╡ 7d6a01a4-4876-42dc-ab66-f7f736d41a32
E₀ₙ=E+ΔEₙ;

# ╔═╡ 0a35c6dc-0967-4f8a-9fff-904f9062eeab
md"""
Calculando as f.c.e.m., obtêm-se $$E^{'}=$$ $(E)V e $$E_0^{'}=$$ $(E₀ₙ)V.
"""

# ╔═╡ 9d82a20f-3a14-4796-88e9-e27720632bbd
md"""

Note que tomou-se a corrente do rotor aproximadamente igual à corrente absorvida, $$I_i\simeq I_n$$, sendo no entanto, $$I_i=I_n+I_d$$. Contudo, não se está a desprezar a corrente $$I_d$$, mas sim a q.d.t. em $$R_i$$ devido a $$I_d$$. Ou seja, $$R_iI_d\lll R_iI$$ para efeito de cálculo de $$E_0^{'}$$ e uma vez que $$I_d$$ ainda não está calculada.
"""

# ╔═╡ 04b517f9-ed9f-4a5d-929b-82b10de843b9
md"""
A característica magnética foi obtida à mesma velocidade inscrita na chapa de características da máquina, $$n_n$$, por conseguinte, obtém-se dela directamente a corrente de campo, $$I_d$$.
"""

# ╔═╡ cfc7844e-3974-46ef-a53a-ee6a1a85d7f3
# forma computacional de consultar a característica magnética, por interpolação dos dados através do Pkg Dierckx.jl
begin
	Id_int=Spline1D(E₀,Iex)
	Id=Id_int(E₀ₙ)
	Id=round(Id, digits=2)
end;

# ╔═╡ 71356175-ffe4-4c3a-a895-8a4be8713a44
md"""
Consultando a característica magnética a 1200rpm, verifica-se para $$E₀=$$ $(E₀ₙ)V $$\Rightarrow$$ $$I_d=$$ $(Id)A.
"""

# ╔═╡ d85a5505-1ab5-43d0-97ad-a0cb4a220c06
md"""
Assim, o reostato de campo para colocar o motor *shunt* nas condições nominais é dado por:
"""

# ╔═╡ 7c572ab7-2292-423c-b611-68573b289265
md"""
$$R_c=\frac{U_n}{I_d}-R_d$$
"""

# ╔═╡ 14ad0875-e27a-442e-81e9-29d1abaeac17
begin
	Rc=Uₙ/Id-Rd
	Rc=round(Rc, digits=1)
end;

# ╔═╡ 50022e39-c2f4-455f-8d26-7c9246190b11
md"""
Calculando, obtém-se $$R_c=$$ $(Rc)Ω
"""

# ╔═╡ 4bac08e5-7a7a-496f-8d67-aa2bc4b10236
md"""
> Poderá então observar as diferenças de cálculo relativas à presença de q.d.t. devido à reacção magnética do induzido, ou seja, uma máquina com pólos auxiliares (caso mais frequente), conduz a $$ΔE \neq 0$$V, variável em função da corrente do induzido. No caso de uma máquina com pólos auxiliares e enrolamentos de compensação, a reacção magnética do induzido estará compensada e assim tem-se:
"""

# ╔═╡ 5abe64cf-9291-48d6-bf60-7335551ee791
md"""
$$ΔE=0 \Rightarrow E_0^{'}=E^{'}$$
"""

# ╔═╡ ac32afe0-e30f-402e-995e-8b0cacf8af10

# ╔═╡ 4989ff81-ac16-446c-8d8a-e3cb9e5950b6
md"""
## **b) Motor shunt**
**Utilizando o reóstato de campo calculado na alínea anterior, determine as características de velocidade, binário e mecânica deste motor (excitação derivação);**
"""

# ╔═╡ 1d458a5a-545f-4ab6-900b-9d84ebbaf51d
md"""
> Na resolução computacional para o **motor de excitação derivação**, as grandezas calculadas estão identificadas como: k$$ϕ$$₀₁, n₁, E₁, ω₁, Td₁
"""

# ╔═╡ d25759bf-6e81-439c-a2c9-c19704379437
begin
	kϕ₀₁=E₀ₙ/nmag
	kϕ₀₁=round(kϕ₀₁, digits=3)
end;

# ╔═╡ 4652d9e4-e2c6-47c4-93d1-1e360ffb7e57
md"""
Tomando o valor calculado de $$R_c=$$ $(Rc)Ω, resulta $$I_d=$$ $(Id)A, o que permite calcular o fluxo magnético da máquina em vazio, $$kϕ₀$$, que no motor de excitação derivação permanece constante.
Assim, $$kϕ₀=$$ $(kϕ₀₁)V/rpm
"""

# ╔═╡ 4629c049-8882-4823-bdea-93e3d70cc901
md"""
A determinação da característica de velocidade $$n=f(I)$$ ou $$n=f(I_i)$$, uma vez que $$I_i\simeq I$$, consiste em sucessivamente realizar o cálculo da velocidade do motor para diferentes valores de corrente:
"""

# ╔═╡ ea81ca51-dccc-4187-b788-7ed64716e698
md"""
$$n=\frac{U-R_iI_i+\Delta E}{k\phi_0}$$ com $$n$$ em rpm, $$\Delta E=f(I_i)$$ e $$k\phi_0=$$constante, em V/rpm.
"""

# ╔═╡ 6030b931-51a0-42fc-9b74-5635b590e6f5
# Característica de velocidade:
begin
	I=0:1:1.5*Iₙ
	Ii=I.-Id
	ΔEᵢ=ΔE_int(Ii)
	n₁=(Uₙ.-Rᵢ*Ii.+ΔEᵢ)/kϕ₀₁
end;

# ╔═╡ d47a90f0-f8bc-44d0-b71c-c0bc59d0d23c
md"""
Similarmente, a característica de binário, $$T=f(I)$$ ou $$T=f(I_i)$$, podendo $$T$$ ser o binário desenvolvido, $$T_d$$, ou o binário útil, $$T_u$$, atendendo que: $$T_d=T_u+T_p$$, consiste em sucessivamente realizar o cálculo do binário para diferentes valores de corrente:
"""

# ╔═╡ 3c921729-6534-4eac-abb0-4eb362295b91
md"""
$$T_d=\frac{E^{'}}{ω}I_i\:\:\:;\:\:\:ω=\frac{2πn}{60}$$ com $$ω$$ em rad/s.
"""

# ╔═╡ 4da7f391-e3bf-4e12-aa6b-a7ef5e45d3b9
# Característica de binário:
begin
	E₁=Uₙ.-Rᵢ*Ii
	ω₁=2π.*n₁/60
	Td₁=(E₁./ω₁).*Ii
end;

# ╔═╡ df3609ef-80f2-464a-b522-f289ea9344b4

# ╔═╡ f499659c-b042-4002-bb27-980daf8502d4
md"""
## **c) Motor excitação composta**
**Idem, com excitação composta em longa derivação aditiva e subtrativa. Representar as características nos mesmos gráficos para comparação;**
"""

# ╔═╡ 72a079e6-0c41-4c50-9ee2-838d5cc60c85
md"""
No motor de excitação composta, o fluxo magnético depende da contribuição das forças magnetomotrizes de ambos os enrolamentos de excitação e da forma como estes estão ligados entre si (de forma aditiva ou subtractiva):
"""

# ╔═╡ 58e9df34-7471-4942-ac06-2505f52875f2
md"""
$$I_{ex}N_d=I_dN_d\pm I_sN_s$$
sendo $$I_s$$ a corrente que percorre o enrolamento de excitação série.
"""

# ╔═╡ f305c434-9d0c-497d-8335-bf25aa80e915
md"""
Assim, $$I_{ex}$$ é a corrente de campo que representa o fluxo total da máquina, sendo obtida por:
"""

# ╔═╡ 0ce81a6e-965c-4dc0-b9f3-f8c09143460e
md"""
$$I_{ex}=I_d \pm \frac{N_s}{N_d}I_s$$
"""

# ╔═╡ 1cd42258-7583-4288-9c6d-4d47facb69e1
md"""
Assim, a característica de velocidade para o motor de excitação composta em longa derivação é obtida por cálculo sucessivo da velocidade do motor para diferentes valores de corrente, através de:
"""

# ╔═╡ facb1900-1093-46c7-97b2-187b67e21294
md"""
$$n=\frac{U-(R_i+R_s)I_i+\Delta E}{k\phi_t}$$ com $$k\phi_t=k(\phi_d \pm 	\phi_s)$$, em V/rpm obtido através da característica magnética da máquina.
"""

# ╔═╡ 6aae7842-4889-4be6-bd1d-eab44c610af8

# ╔═╡ 7ad852d3-e3b8-4799-8aae-a52c1ebe34ac
md"""
> Na resolução computacional para o **motor de excitação composta aditiva**, as grandezas calculadas estão identificadas como: `Iex₂`, `E₀₂`, `kϕ₀₂`, `n₂`, `E₂`, `ω₂`, `Td₂`
"""

# ╔═╡ b4e5cbd1-c1c1-47e1-a8aa-8fc2ef628e87
begin
	Iex₂=Id.+(Ns/Nd)*Ii
	E₀_int1=Spline1D(Iex, E₀)  # função de interpolação para a caract. magnética
	E₀₂=E₀_int1(Iex₂) # fem que contém os fluxos derivação + série
	kϕ₀₂=E₀₂/nmag
	n₂=(Uₙ.-(Rᵢ+Rₛ)*Ii.+ΔEᵢ)./kϕ₀₂
	E₂=Uₙ.-(Rᵢ+Rₛ)*Ii
	ω₂=2π.*n₂/60
	Td₂=(E₂./ω₂).*Ii
end;

# ╔═╡ 55397202-48ae-4a3d-a053-9f46e6638560

# ╔═╡ 1a154f27-cd9a-4de8-b850-599b5e810811
md"""
> Na resolução computacional para o **motor de excitação composta subractiva**, as grandezas calculadas estão identificadas como: `Iex₃`, `E₀₃`, `kϕ₀₃`, `n₃`, `ω₃`, `Td₃`
"""

# ╔═╡ 626c5cab-64e2-446c-9d38-f01dde099d3e
begin
	Iex₃=Id.-(Ns/Nd)*Ii
	E₀₃=E₀_int1(Iex₃) #fem que contém os fluxos derivação - série
	kϕ₀₃=E₀₃/nmag
	n₃=(Uₙ.-(Rᵢ+Rₛ)*Ii.+ΔEᵢ)./kϕ₀₃
	ω₃=2π.*n₃/60
	Td₃=(E₂./ω₃).*Ii
end;

# ╔═╡ 1c659ae6-1b29-43a5-92f7-30b1f24c3696

# ╔═╡ 426c40b4-5fa1-4d8a-b03c-11f3008484f6
md"""
## **d) Motor série**
**Determinar as curvas características com o circuito de derivação desligado (motor série). Representar as características nos mesmos gráficos para comparação;**
"""

# ╔═╡ 8dfd7146-2e55-4ea0-8cf2-3557d89e96e1
md"""
> Na resolução computacional para o **motor de excitação série**, as grandezas calculadas estão identificadas como: Iex₄, E₀₄, k$$ϕ$$₀₄, n₄, ω₄, Td₄
"""

# ╔═╡ 4e4469c8-994d-42c6-b373-8f295768b8b0
begin
	Iex₄=(Ns/Nd)*Ii
	E₀₄=E₀_int1(Iex₄) #fem que contém apenas fluxo série
	kϕ₀₄=E₀₄/nmag
	n₄=(Uₙ.-(Rᵢ+Rₛ)*Ii.+ΔEᵢ)./kϕ₀₄
	ω₄=2π.*n₄/60
	Td₄=(E₂./ω₄).*Ii
end;

# ╔═╡ a45ad7c2-2f83-4e04-bdaf-8dcc30a150f5
# Características de velocidade, plots:
begin
	plot(I, n₁, linewidth=2, title="Características de velocidade", xlabel = "I (A)", ylabel="n (rpm)",  framestyle = :origin, minorticks=5, label="shunt")
	plot!(I,n₂, linewidth=2, label="comp. aditivo")
	plot!(I,n₃, linewidth=2, label="comp. subtractivo", legend=:bottomleft)
	plot!(I,n₄, linewidth=2, label="série", xlims=(0,120), ylims=(0,3000))
end

# ╔═╡ 5b866db3-ddd6-4bfd-b027-761c07d6755c
# Características de binário, plots:
begin
	plot(I, Td₁, linewidth=2, title="Características de binário", xlabel = "I (A)", ylabel="Td (Nm)",  framestyle = :origin, minorticks=5, label="shunt")
	plot!(I,Td₂, linewidth=2, label="comp. aditivo")
	plot!(I,Td₃, linewidth=2, label="comp. subtractivo", legend=:topleft)
	plot!(I,Td₄, linewidth=2, label="série", xlims=(0,120), ylims=(0,250))
end

# ╔═╡ 326135bd-24e3-492d-a7d5-1a14f065e80f
# Características mecânicas, plots:
begin
	plot(Td₁, n₁, linewidth=2, title="Características mecânicas", ylabel = "n (rpm)", xlabel="Td (Nm)",  framestyle = :origin, minorticks=5, label="shunt")
	plot!(Td₂, n₂, linewidth=2, label="comp. aditivo")
	plot!(Td₃, n₃, linewidth=2, label="comp. subtractivo", legend=:topright)
	plot!(Td₄, n₄, linewidth=2, label="série", xlims=(0,250), ylims=(0,3000))
end

# ╔═╡ 66e32f84-8b2a-4a3d-81fe-16437ecc3c18

# ╔═╡ 60db00b7-c78b-4c26-9530-c62fcfd1bfd2
md"""
## **e) MI: variação $$n=f(I)$$ 💻**
**Considere o motor com excitação independente (MI), Uexc = 240V , com o reóstato de campo calculado na alínea a). Explicite a variação da característica de velocidade nas situações:**
1. **aumento de tensão do induzido;**
2. **diminuição do reóstato de campo;**
3. **aumento da resistência adicional.**
"""

# ╔═╡ 4fdea2ae-3bf8-42cd-bf6f-411eaf8223c3
md"""
> Na resolução computacional para o **motor de excitação separada**, as grandezas calculadas estão identificadas como: `Ui`, `Iex5`, `E₀₅`, `kϕ₀₅`, `ΔEᵢᵢ`, `n₅`, `ω₅`, `Td₅`
"""

# ╔═╡ 36295cf6-19ba-4240-9806-745ec0bfdccd
begin
	H1=("Tensão do induzido, Ui", @bind Ui PlutoUI.Slider(150:1:350, default=250.0, show_value=true))
	H2=("Reostato de campo, Rc1", @bind Rc1 PlutoUI.Slider(0*Rc:0.01*Rc:2.5*Rc, default= Rc, show_value=true))
	H3=("Resistência adicional, Rad", @bind Rad PlutoUI.Slider(0:0.1:1.5, default=0.0, show_value=true))
	H1, H2, H3
end

# ╔═╡ e648310c-8172-4cf0-ab72-f40229ba2577
begin
	Uexc=240
	Iex₅=Uexc/(Rc1+Rd)
	E₀₅=E₀_int1(Iex₅) #fem para excitação separada
	kϕ₀₅=E₀₅/nmag
	ΔEᵢᵢ=ΔE_int(I)
	n₅=(Ui.-(Rᵢ+Rad)*I.+ΔEᵢᵢ)./kϕ₀₅
	E₅=Ui.-(Rᵢ+Rad)*I
	ω₅=2π.*n₅/60
	Td₅=(E₅./ω₅).*Ii
end;

# ╔═╡ 4919a95d-cd66-401c-af76-6155087462a3
# Característica de velocidade vs. variação de Ui, Rc1 ou Rad; plots:
begin
	plot(I, n₅, ylims=(0,3000),linewidth=2, framestyle = :origin, title="Variação da característica de velocidade", label=:none, xlabel = "I (A)", ylabel="n (rpm)", minorticks=5, xlims=(0,120))
end

# ╔═╡ 8ad59666-3801-44a3-b26a-197a8f60db02
md"""
!!! nota
	**Apresenta-se uma alínea f) idêntica à alínea anterior, mas considerando a característica de binário:**
"""

# ╔═╡ babc5b0b-3263-47d5-bd33-56917ece1e6b
md"""
## **f) MI: variação $$T=f(I)$$ 💻**
**Considere o motor com excitação independente (MI), Uexc = 240V , com o reóstato de campo calculado na alínea a). Explicite a variação da característica de binário nas situações:**
1. **aumento de tensão do induzido;**
2. **diminuição do reóstato de campo;**
3. **aumento da resistência adicional.**
"""

# ╔═╡ 49cc56bc-bd1e-4e07-9d9c-0ccfaa92e7b0
# Característica de binário vs. variação de Ui, Rc1 ou Rad; plots:
begin
	plot(I, Td₅, ylims=(0,250),linewidth=2, framestyle = :origin, title="Variação da característica de binário", label=:none, xlabel = "I (A)", ylabel="Td (Nm)", minorticks=5, xlims=(0,120))
end

# ╔═╡ 0bda0726-fcf9-491d-ad24-301521cb5892

# ╔═╡ f34820a6-bd96-463f-b747-2b910914d152
md"""
# Setup
"""

# ╔═╡ 50588330-7af4-4c41-af8d-ffbb4c074394
TableOfContents(title="📚 Índice, Exercício 7")

# ╔═╡ e99f40c0-1752-4096-8fc9-c4550ae86168
md"""
!!! info
	No índice deste *notebook*, os tópicos assinalados com "💻" permitem interacção com o utilizador.
"""

# ╔═╡ 8e683ba6-fe89-41d5-8f0a-5e3e59ca747c
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/)
"""

# ╔═╡ 80c412ed-1cc3-42c0-acf6-56248b5aa327
md"""
!!! info
	## Programação _Julia_ e _notebooks Pluto_
	Saber mais sobre: [_Julia_/_Pluto_](https://github.com/Ricardo-Luis/notebooks/blob/main/ME2/README.md)
"""

# ╔═╡ e88b50d7-bd66-4e3c-8740-b1c5e36b6b5f
version=VERSION;

# ╔═╡ a7d43c39-1780-446a-928a-1bc5cf841390
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, 23/Out/2021
"""

# ╔═╡ bfc8ce5b-3b3e-4448-bd60-23ed853a9ed9
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.6"
PlutoUI = "~0.7.16"
"""

# ╔═╡ 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"

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

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

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

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

[[Compat]]
deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"]
git-tree-sha1 = "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"

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

[[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 = "d189c6d2004f63fd3c91748c458b09f26de0efaa"
uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71"
version = "0.61.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"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

[[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 = "ba43b248a1f04a9667ca4a9f782321d9211aa68e"
uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
version = "1.22.6"

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

[[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", "LogExpFunctions", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"]
git-tree-sha1 = "eb35dcc66558b2dda84079b9a1be17557d32091a"
uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
version = "0.33.12"

[[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:
# ╟─c7838496-100f-4901-abcf-0d4e59fbc4a9
# ╟─44201f7b-84df-4b8d-aeec-0f142ac2008b
# ╟─ed4846d5-70d2-4deb-9a4a-41cdc8c99bdd
# ╠═1301d1ad-89e8-4282-ab35-1a6b8214bea0
# ╟─1a427cf6-b2d3-4d9b-9cb5-4682d5f49869
# ╟─e2fc78d6-480b-4fe0-b844-0d4329c0d572
# ╟─8bde3ad9-2d03-4557-ab50-a89ac8e834a3
# ╟─61238dc4-3c9d-4b59-9486-501988806c27
# ╟─c4d5e3f9-7808-48f6-8d33-05607d8e5a4e
# ╟─f6fcec56-b080-4016-baf0-0ab728f255f3
# ╟─d9e431c5-be62-40c8-b5d6-59d5808e4436
# ╟─cde4847b-6c38-4bc6-a869-514774630c89
# ╟─5b4c1912-126d-4fe8-87c5-f65b299f3642
# ╠═1c70002d-e3fb-4d81-b0f9-ed00d69173ff
# ╟─d8d6a6e9-df8d-47d2-832a-0d2126ce760e
# ╟─0ff562ff-7af2-4749-87f5-8766cb695893
# ╟─cf0f089a-1901-4ad1-8fe9-b9028679b109
# ╟─68969be8-0bee-4cca-85de-7a8d2aa35ee2
# ╠═de954f1d-a3ac-4830-acd0-85e64afdf0cd
# ╟─0a35c6dc-0967-4f8a-9fff-904f9062eeab
# ╠═8f5b0bd5-7a65-4ba3-bdd1-7cc3128fa8d8
# ╠═7d6a01a4-4876-42dc-ab66-f7f736d41a32
# ╟─9d82a20f-3a14-4796-88e9-e27720632bbd
# ╟─04b517f9-ed9f-4a5d-929b-82b10de843b9
# ╟─71356175-ffe4-4c3a-a895-8a4be8713a44
# ╠═cfc7844e-3974-46ef-a53a-ee6a1a85d7f3
# ╟─d85a5505-1ab5-43d0-97ad-a0cb4a220c06
# ╟─7c572ab7-2292-423c-b611-68573b289265
# ╟─50022e39-c2f4-455f-8d26-7c9246190b11
# ╠═14ad0875-e27a-442e-81e9-29d1abaeac17
# ╟─4bac08e5-7a7a-496f-8d67-aa2bc4b10236
# ╟─5abe64cf-9291-48d6-bf60-7335551ee791
# ╟─ac32afe0-e30f-402e-995e-8b0cacf8af10
# ╟─4989ff81-ac16-446c-8d8a-e3cb9e5950b6
# ╟─1d458a5a-545f-4ab6-900b-9d84ebbaf51d
# ╟─4652d9e4-e2c6-47c4-93d1-1e360ffb7e57
# ╠═d25759bf-6e81-439c-a2c9-c19704379437
# ╟─4629c049-8882-4823-bdea-93e3d70cc901
# ╟─ea81ca51-dccc-4187-b788-7ed64716e698
# ╠═6030b931-51a0-42fc-9b74-5635b590e6f5
# ╟─d47a90f0-f8bc-44d0-b71c-c0bc59d0d23c
# ╟─3c921729-6534-4eac-abb0-4eb362295b91
# ╠═4da7f391-e3bf-4e12-aa6b-a7ef5e45d3b9
# ╟─a45ad7c2-2f83-4e04-bdaf-8dcc30a150f5
# ╟─5b866db3-ddd6-4bfd-b027-761c07d6755c
# ╟─326135bd-24e3-492d-a7d5-1a14f065e80f
# ╟─df3609ef-80f2-464a-b522-f289ea9344b4
# ╟─f499659c-b042-4002-bb27-980daf8502d4
# ╟─72a079e6-0c41-4c50-9ee2-838d5cc60c85
# ╟─58e9df34-7471-4942-ac06-2505f52875f2
# ╟─f305c434-9d0c-497d-8335-bf25aa80e915
# ╟─0ce81a6e-965c-4dc0-b9f3-f8c09143460e
# ╟─1cd42258-7583-4288-9c6d-4d47facb69e1
# ╟─facb1900-1093-46c7-97b2-187b67e21294
# ╟─6aae7842-4889-4be6-bd1d-eab44c610af8
# ╟─7ad852d3-e3b8-4799-8aae-a52c1ebe34ac
# ╠═b4e5cbd1-c1c1-47e1-a8aa-8fc2ef628e87
# ╟─55397202-48ae-4a3d-a053-9f46e6638560
# ╟─1a154f27-cd9a-4de8-b850-599b5e810811
# ╠═626c5cab-64e2-446c-9d38-f01dde099d3e
# ╟─1c659ae6-1b29-43a5-92f7-30b1f24c3696
# ╟─426c40b4-5fa1-4d8a-b03c-11f3008484f6
# ╟─8dfd7146-2e55-4ea0-8cf2-3557d89e96e1
# ╠═4e4469c8-994d-42c6-b373-8f295768b8b0
# ╟─66e32f84-8b2a-4a3d-81fe-16437ecc3c18
# ╟─60db00b7-c78b-4c26-9530-c62fcfd1bfd2
# ╟─4fdea2ae-3bf8-42cd-bf6f-411eaf8223c3
# ╠═e648310c-8172-4cf0-ab72-f40229ba2577
# ╟─36295cf6-19ba-4240-9806-745ec0bfdccd
# ╟─4919a95d-cd66-401c-af76-6155087462a3
# ╟─8ad59666-3801-44a3-b26a-197a8f60db02
# ╟─babc5b0b-3263-47d5-bd33-56917ece1e6b
# ╟─49cc56bc-bd1e-4e07-9d9c-0ccfaa92e7b0
# ╠═0bda0726-fcf9-491d-ad24-301521cb5892
# ╟─f34820a6-bd96-463f-b747-2b910914d152
# ╠═50588330-7af4-4c41-af8d-ffbb4c074394
# ╟─e99f40c0-1752-4096-8fc9-c4550ae86168
# ╟─8e683ba6-fe89-41d5-8f0a-5e3e59ca747c
# ╠═6b359fc5-ec8d-47ec-89ec-b1b214a37a82
# ╟─80c412ed-1cc3-42c0-acf6-56248b5aa327
# ╟─a7d43c39-1780-446a-928a-1bc5cf841390
# ╟─e88b50d7-bd66-4e3c-8740-b1c5e36b6b5f
# ╟─bfc8ce5b-3b3e-4448-bd60-23ed853a9ed9
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002


# Goal: Implement Conways Game of Life in Julia
# author: Jay Jagtap

#=
Rules for Game of Life

 Now Neighbors           Next
#   --- ---------           --------------
#   1   0,1             ->  0  # Lonely
#   1   4,5,6,7,8       ->  0  # Overcrowded
#   1   2,3             ->  1  # Lives
#   0   3               ->  1  # It takes three to give birth!
#   0   0,1,2,4,5,6,7,8 ->  0  # Barren

=#

function nextGen(A)
  #=
    Function returns next Generation of Life based on above mentioned Rules
    param A: 2D matrix of previous Generation
    return next_Gen: 2D matrix derived from A(previous Generation)
  =#

  # Initializing next_Gen with all Zero Values
  next_Gen = zeros(Int, size(A,1), size(A,2))

  for i in 1:size(next_Gen, 1)
    for j in 1:size(next_Gen, 2)
      alive_count = get_no_of_alive_neighbors(A, i, j)
      if A[i,j] == 0
        if alive_count == 3
            next_Gen[i,j] = 1
        end
      else
        if alive_count == 2 || alive_count == 3
            next_Gen[i,j] = 1
        end
      end
    end
  end
  return next_Gen
end

function get_no_of_alive_neighbors(A, i, j)
    #=
    param A: 2D matrix
    i: row index
    j: column index
    return alive_count: Number of 1's(alive cells) in neighborhood
    =#

    # Collecting Neighborhood co-ordinates
    neighbor_coord = []
      for k in 1:3
        if k < 2
          push!(neighbor_coord , (i-1,j-1))
          push!(neighbor_coord , (i-1,j))
          push!(neighbor_coord , (i-1,j+1))
        elseif k > 2
          push!(neighbor_coord , (i+1,j-1))
          push!(neighbor_coord , (i+1,j))
          push!(neighbor_coord , (i+1,j+1))
        else
          push!(neighbor_coord , (i,j-1))
          push!(neighbor_coord , (i,j+1))
        end
      end

    # Deriving alive count from neighbors
    alive = 0
    for coord in neighbor_coord
        if (coord[1] >= 1 && coord[1] <= size(A,1) ) && (coord[2] >= 1 && coord[2] <= size(A,2))
            if A[coord[1] , coord[2]] == 1
                alive=alive+1
            end
        end
    end
    return alive
end

function main()
  initial_Gen =
  [  0 0 0 1 1 1 0 0;
     0 1 0 1 0 1 1 1;
     0 1 0 1 0 1 0 1;
     0 1 0 1 0 1 1 1;
     0 1 0 1 0 1 0 1;
     0 1 0 1 0 1 0 1;
     1 1 1 1 1 0 0 0;
     1 1 1 1 1 1 1 1]

 no_of_iterations = 20
 println("Generation: initial_Gen")
 display(initial_Gen)
 println()
 for i in 1:no_of_iterations
    println("Generation: " , i)
    current_Gen = nextGen(initial_Gen)
    display(current_Gen)
    println()
    initial_Gen = current_Gen
 end

end

main()


#   Copyright (c) 2020-2022 Velexi Corporation
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.

"""
subtract.jl defines methods for the -(x, y) function
"""

# --- Exports

import Base.:(-)

# --- Method definitions

-(M::AbstractMultivector, N::AbstractMultivector) = M + -N

# ------ Specializations involving a Pseudoscalar instance

# B::Pseudoscalar, C::Pseudoscalar
-(B::Pseudoscalar, C::Pseudoscalar) = Pseudoscalar(B, value=value(B) - value(C))

# ------ Specializations involving an AbstractScalar instance

# B::AbstractScalar, C::One
# B::One, C::AbstractScalar
-(B::AbstractScalar, C::One) = Scalar{typeof(value(B))}(value(B) - 1)
-(B::One, C::AbstractScalar) = Scalar{typeof(value(C))}(1 - value(C))

# B::AbstractScalar, C::Zero
# B::Zero, C::AbstractScalar
-(B::AbstractScalar, C::Zero) = B
-(B::Zero, C::AbstractScalar) = -C

# B::AbstractScalar, x::Real
# x::Real, B::AbstractScalar
-(B::AbstractScalar, x::Real) = Scalar{typeof(value(B))}(value(B) - x)
-(x::Real, B::AbstractScalar) = Scalar{typeof(value(B))}(x - value(B))

# ------ Specializations involving a Scalar instance

# B::Scalar, C::Scalar
-(B::Scalar, C::Scalar) = Scalar{typeof(value(B))}(value(B) - value(C))

# ------ Specializations involving a One instance

# B::One, C::One
-(B::One, C::One) = Zero{typeof(value(B))}()

# B::One, C::Zero
# B::Zero, C::One
-(B::One, C::Zero) = B
-(B::Zero, C::One) = -C

# ------ Specializations involving a Zero instance

# B::Zero, C::Zero
-(B::Zero, C::Zero) = B

# B::Zero, v::Vector
# v::Vector, B::Zero
-(B::Zero, v::Vector{<:Real}) = -v
-(v::Vector{<:Real}, B::Zero) = v


"""
    cl1(x::Float64)::Float64

Returns the value of the Clausen function ``\\operatorname{Cl}_1(x)``
for a real angle ``x`` of type `Float64`.  This function is defined as

```math
\\operatorname{Cl}_1(x) = \\Re[\\operatorname{Li}_1(e^{ix})] = \\Re[-\\log(1 - e^{ix})]
```

Note: ``\\operatorname{Cl}_1(x)`` is not defined for ``x=2n\\pi`` with
``n\\in\\mathbb{Z}``.

Author: Alexander Voigt

License: MIT

# Example
```jldoctest; setup = :(using ClausenFunctions), output = false
julia> cl1(1.0)
0.04201950582536895
```
"""
function cl1(x::Float64)::Float64
    x = range_reduce_odd(x)

    if x == zero(x)
        return Inf
    end

    -log(2.0*sin(0.5*x))
end


"""
    qbins(x, y, z, n)

Bins x into n quantiles, each xbin into n quantiles of y, return z quantile

# Examples
```julia-repl
julia> df = DataFrame(x=1:20, y=6:25, z=11:30)
julia> xmed, ymed, zmed = qbins(df.T, df.M, df.R, 3)
  xmed = [9, 9, 9, 15, 15, 15, 21, 21, 21]
  ymed = [12, 14, 16, 19, 20.5, 22, 25, 27, 29]
  zmed = [2, 4, 6, 8.5, 10.5, 15, 17, 19]
```
"""
function qbins(x, y, z, n)
  xq = quantile(x, 0:1/n:1)
  xmed = Float64[] # between quantiles x values
  ymed = Float64[] # between quantiles y values
  zmed = Float64[] # z median for each xy bins
  for i = 1:n # loop for each x between-quantile bin
    ybin = y[x .>= xq[i] .&& x .<= xq[i+1]]
    ybinq = quantile(ybin, 0:1/n:1)
    for j = 1:n # loop for each y between-quantile bin
      push!(xmed, (xq[i] + xq[i+1]) / 2)
      push!(ymed, (ybinq[j] + ybinq[j+1]) / 2)
      push!(zmed, median(z[x .>= xq[i] .&& x .<= xq[i+1] .&& y .>= ybinq[j] .&& y .<= ybinq[j+1]]))
    end
  end
  return xmed, ymed, zmed
end


using GlobalOptimizer, Test

@testset "Solve Ackley Function" begin
    # Define an objective function (using Ackley function here as an example)
    function ackley(x::AbstractVector{T}) where T<:Real
        arg1 = 0.0
        arg2 = 0.0
        dims = length(x)
        @inbounds for i in eachindex(x)
            arg1 += abs2(x[i])
            arg2 += cospi(2.0 * x[i])
        end
        arg1  = 0.2 * sqrt(arg1 / dims)
        arg2 /= dims
        return -20.0 * exp(-arg1) - exp(arg2) + ℯ + 20.0
    end

    nd  = 15
    lb  = ntuple(i -> -32.0, nd) # lower bounds
    ub  = ntuple(i -> +32.0, nd) # upper bounds
    obj = minimizer(nd)          # create an object for the optimization
    minimize!(obj, ackley, lb, ub, avgtimes=3)
    @test obj.xsol ≈ zeros(Float64, nd) atol=1e-12
end


using MultivariateSeries
X = @ring x0 x1 x2
d = 4
F = (x0+x1+x2)^d + 1.5*(x0+x1)^d -2.0*(x0-x2)^d
w, Xi = decompose(F)
F1 = tensor(w, Xi, X, d)
@assert norm(F-F1)<1.e-6


# code for Video 4.4:
fname = "iris.csv"
using DataFrames
data = readtable(fname, separator = ',')

###Distributions:
Pkg.add("Distributions")
using Distributions

typeof(Normal) # DataType
super(Normal) # Distributions.Distribution{Distributions.Univariate,Distributions.Continuous}
super(Poisson) # Distributions.Distribution{Distributions.Univariate,Distributions.Discrete}

n1 = Normal(10, 1.5) # Distributions.Normal(μ=10.0, σ=1.5)
params(n1) # (10.0,1.5)
fieldnames(n1) # 2-element Array{Symbol,1}:  :μ :σ

rand(n1, 100)
# 100-element Array{Float64,1}:
#   8.48529
#   7.90919
#  13.2968
#   6.55532
#   ...
 # 13.1982
 # 10.7262
 # 11.1575
 # 11.5623

randn(50)
50-element Array{Float64,1}:
  1.34669
 -1.73781
  0.801373
 -1.11795
 ...

b = Binomial(10, 0.7) # binomial distribution with 10 trials and succes rate 0.7
# Distributions.Binomial(n=10, p=0.7)
rand(b, 1000)
1000-element Array{Int64,1}:
 6
 9
 7
 7
 6
 6
 9

### Kernel density:
using Winston, KernelDensity
x = convert(Array, data[1:50, :sepal_width])
y = convert(Array, data[1:50, :sepal_length])
kx = kde(x) # kernel density function
ky = kde(y)
plot(kx.x, kx.density, "r--", ky.x, ky.density, "b;")

###
using Gadfly
set_default_plot_size(20cm, 12cm)
Gadfly.plot(data, x = "petal_length", y = "petal_width", color = "species", Geom.point)

### K-means Clustering
Pkg.add("Clustering")
using Clustering
features = convert(Array, data[:, 1:4])' # 4x150 Array{Float64,2}:
# group the data onto 3 clusters
initseeds(:rand, features, 3) # choose 3 random starting points (centroids)
# 3-element Array{Int64,1}:
#  36
#  93
#  41
result = kmeans( features, 3) # make 3 clusters
# Clustering.KmeansResult{Float64}(4x3 Array{Float64,2}:
#  5.006  5.90161  6.85
#  3.418  2.74839  3.07368
#  1.464  4.39355  5.74211
#  0.244  1.43387  2.07105,[1,1,1,1,1,1,1,1,1,1  …  3,3,
Gadfly.plot(data, x = "petal_length", y = "petal_width", color = result.assignments, Geom.point)

### HypothesisTests
Pkg.add("HypothesisTests")
using HypothesisTests
# test sepal_length I. setosa versus I. versicolor:
xset = convert(Array, data[1:50, :sepal_length])
xver = convert(Array, data[51:100, :sepal_length])

uneqtt = UnequalVarianceTTest(xset, xver)
# Two sample t-test (unequal variance)
# ------------------------------------
# Population details:
#     parameter of interest:   Mean difference
#     value under h_0:         0
#     point estimate:          -0.9299999999999997
#     95% confidence interval: (-1.1057073727210804,-0.7542926272789189)

# Test summary:
#     outcome with 95% confidence: reject h_0
#     two-sided p-value:           3.74674261398387e-17 (extremely significant)

# Details:
#     number of observations:   [50,50]
#     t-statistic:              -10.52098626754911
#     degrees of freedom:       86.53800179765493
#     empirical standard error: 0.08839475466938762

pvalue(uneqtt) # 3.74674261398387e-17
ci(uneqtt) # (-1.1057073727210804,-0.7542926272789189)


function courant(Δt, flux, mesh, w)
    c = zero(eltype(Δt))
    for i_face in inner_faces(mesh)
        c = max(c, courant(Δt, flux, mesh, w, i_face))
    end
    return c
end

function courant(Δt, flux, mesh, w, i_face)
    i_cell_1, i_cell_2 = cells_next_to_inner_face(mesh, i_face)
    n = normal_vector(mesh, i_face)
    w_mean = (w[i_cell_1] + w[i_cell_2])/2
    λ = eigvals(flux, w_mean, n)
    maxλ = maximum(abs.(λ))
    return maxλ * Δt * face_area(mesh, i_face) / min(cell_volume(mesh, i_cell_1), cell_volume(mesh, i_cell_2))
end

function courant(Δt, flux::AdvectionFlux, mesh, w, i_face)
    v = LinearAdvectionFlux(flux.velocity_at_face(mesh, i_face))
    return FiniteVolumes.courant(Δt, v, mesh, w, i_face)
end

# function courant(Δt, flux::LinearAdvectionFlux, mesh::AbstractCartesianMesh{1}, w)
#     return abs(flux.velocity[1]) * Δt / FiniteVolumes.CartesianMeshes.dx(mesh)[1]
# end

# function courant(Δt, flux::LinearAdvectionFlux, mesh::PeriodicRegularMesh2D, w)
#     vx, vy = model.velocity
#     return max(abs(vx) * Δt / dx(mesh), abs(vy) * Δt / dy(mesh))
# end


using Test
using PETSc, MPI, LinearAlgebra, SparseArrays
PETSc.initialize()

@testset "Tests" begin
  m,n = 20,20
  x = randn(n)
  V = PETSc.VecSeq(x)

  @test norm(x) ≈ norm(V) rtol=10eps()

  S = sprand(m,n,0.1) + I
  M = PETSc.MatSeqAIJ(S)

  @test norm(S) ≈ norm(M) rtol=10eps()

  w = M*x
  @test w ≈ S*x

  ksp = PETSc.KSP(M; ksp_rtol=1e-8, pc_type="jacobi", ksp_monitor=nothing)
  #PETSc.settolerances!(ksp; rtol=1e-8)

  @test PETSc.gettype(ksp) == "gmres" # default

  pc = PETSc.PC(ksp)
  @test PETSc.nrefs(pc) == 2
  @test PETSc.gettype(pc) == "jacobi"

  # create an extra handle, check ref count is incremented
  pc_extra = PETSc.PC(ksp)
  @test PETSc.nrefs(pc) == 3
  # destroy extra handle, check ptr is set to null, ref count is decremented
  PETSc.destroy(pc_extra)
  @test pc_extra.ptr == C_NULL
  @test PETSc.nrefs(pc) == 2

  # safe to call destroy on null pointer
  PETSc.destroy(pc_extra)

  # set new pc, check ref counts are modified by ksp
  pc_new = PETSc.PC{Float64}(MPI.COMM_SELF)
  @test PETSc.nrefs(pc_new) == 1
  PETSc.setpc!(ksp, pc_new)
  @test PETSc.nrefs(pc_new) == 2
  @test PETSc.nrefs(pc) == 1

  PETSc.setpc!(ksp, pc)
  @test PETSc.nrefs(pc_new) == 1
  @test PETSc.nrefs(pc) == 2

  y = ksp \ w
  @test S*y ≈ w  rtol=1e-8

  w = M'*x
  @test w ≈ S'*x

  y = ksp' \ w
  @test S'*y ≈ w rtol=1e-8

  f!(y,x) = y .= 2 .*x

  M = PETSc.MatShell{Float64}(f!,10,10)

  x = rand(10)

  @test M*x ≈ 2x
  @test PETSc.KSP(M) \ x ≈ x/2

  function F!(cfx, cx, a)
    x = PETSc.unsafe_localarray(Float64,cx)
    fx = PETSc.unsafe_localarray(Float64,cfx)
    fx[1] = x[1]^2 + x[1]*x[2] - 3
    fx[2] = x[1]*x[2] + x[2]^2 - 6
    Base.finalize(x)
    Base.finalize(fx)
  end

  J = zeros(2,2)
  PJ = PETSc.MatSeqDense(J)
  function updateJ!(cx, args...)
    x = PETSc.unsafe_localarray(Float64,cx)
    J[1,1] = 2x[1] + x[2]
    J[1,2] = x[1]
    J[2,1] = x[2]
    J[2,2] = x[1] + 2x[2]
    Base.finalize(x)
  end

  S = PETSc.SNES{Float64}(MPI.COMM_SELF; ksp_rtol=1e-4, pc_type="none")
  PETSc.setfunction!(S, F!, PETSc.VecSeq(zeros(2)))
  PETSc.setjacobian!(S, updateJ!, PJ, PJ)
  @test PETSc.solve!([2.0,3.0], S) ≈ [1.0,2.0] rtol=1e-4
end


"""
    haltonsequence(b, n)

Generate the first `n` numbers in Halton's sequence with base `b`.
"""
haltonsequence(b, n) = haltonnumber.(b, 1:n)

"""
    haltonnumber(base, index)

Generate the `n`-th Halton number in the sequence with base `b`.

# Note
    Implementation is based on the psudo code in:
        http://en.wikipedia.org/wiki/Halton_sequence
"""
function haltonnumber(base::Integer, index::Integer)
    res = 0
    f = 1 / base
    i = index

    while (i > 0)
        res += f * (i % base)
        i = floor(Integer, i / base)
        f = f / base
    end

    return res
end


using AffineArithmetic, IntervalArithmetic, Polynomials, StaticArrays
using Test

using AffineArithmetic: Aff

@testset "Construction from intervals" begin
    X = 1..3
    X_a = Affine(X)
    X_a isa Affine

    Y = 2..4
    Y_a = Affine(Y)
    @test Y_a.range == 2..4
    @test Y_a.affine == Aff(3.0, SVector{1, Float64}(1.0), 0..0)

    sum_a = X_a + Y_a
    @test sum_a.range == 3..7
    @test sum_a.affine == Aff(5.0, SVector{1, Float64}(2.0), 0..0)

    prod_a = X_a * Y_a
    @test prod_a.range == 2..12
    @test prod_a.affine == Aff(6.0, SVector{1, Float64}(5.0), 0..1)
end

@testset "Small powers and range" begin
    X = 1..3
    Y = Affine(X)

    f(x) = x^2 - x + 1

    @test range(f(X)) == -1..9
    @test range(f(Y)) == 0..7   # affine is a little better

    g(x) = (x - 1)^3

    @test range(g(X)) == 0..8
    @test range(g(Y)) == 0..8   # affine gives the same
end

reset_affine_index()

@testset "Matrix multiplication" begin
    A = 0.5 * [1 2; -1 1]

    X = Affine(-1..1)
    Y = Affine(-1..1)

    XX = [X, Y]
    @test XX == [Affine(Aff(0.0, SVector{1, Float64}(1.0), 0..0), -1..1),
                 Affine(Aff(0.0, SVector{1, Float64}(1.0), 0..0), -1..1)]

    @test A * XX == [Affine(Aff(0.0, SVector{1, Float64}(1.5), 0..0), -1.5 .. 1.5),
                     Affine(Aff(0.0, SVector{1, Float64}(0.0), 0..0), 0..0)]
end

reset_affine_index()

@testset "Range of polynomial" begin
    # example from Rump 2015
    p = Polynomial([-3, 1])   # x - 3
    p2 = p^8

    x = 4 ± 1e-4
    y = Affine(x)

    @test (-70..70) ⊆ range(p2(x))
    @test range(p2(y)) ⊆ 0.998..1.002   # affine is extremely much better!
end

@testset "Constructors with intervals" begin
    X = Affine(1..2)
    @test X isa Affine
    @test X - X == Affine(0..0)

    x, y = affine(1..2, 3..4)
    @test interval(x + y - x - y) == 0..0
end