using LinearAlgebra

inner_product(V1::Vector,V2::Vector,η::Matrix) = (adjoint(V2)*η*V1)[1]
inner_product(V::Vector,η::Matrix) = (adjoint(V)*η*V)[1]
function normalization!(V::Matrix,i::Int,η::Matrix)
    c = inner_product(V[:,i],η)
    if abs(c) < 1E-8
        nothing
    else
        V[:,i] .=  V[:,i]./sqrt(c)
    end
end

function gram_schmit(V::Matrix,s::Int,e::Int,η::Matrix)
    # V_1' = V_1
    normalization!(V,s,η)
    for i = s+1:1:e
        for j = s:1:i-1
            V[:,i] .-= inner_product(V[:,i],V[:,j],η).*V[:,j]
        end
        normalization!(V,i,η)
    end
    return V
end

generate_metric(N::Int) = diagm(vcat([1.0 for i=1:N],[-1.0 for i=1:N]))

function process_complex!(tS::Vector,tV::Matrix)
    tS .= real.(tS)
    flag = 1
    for i = 1:size(tV)[1]
        if sum(abs.(imag.(tV[:,i])))!=0
            if flag % 2 != 0
                tV[:,i] .= 2.0 .*real.(tV[:,i])
            else
                tV[:,i] .= 2.0 .*imag.(tV[:,i])
            end
            flag = flag+1
        end
    end
    tV .= real(tV)
end

function recanonicalize(h::Matrix,hamiltonian_type::String;tol=1E-10)
    N = Int(size(h)[1]/2)
    η = generate_metric(N)
    ih = η*h
    # S, V = eigen(h) # #TODO: EXPALIN IN MEETING S = [-3.454206332875306e-11, -3.4541994235883824e-11, 9.135733651675401e-8, 9.135733809775541e-8, 0.9999999999999786, 0.9999999999999795, 1.0000000000000218, 1.000000000000022]
    # @show S
    tS,tV = eigen(ih)  # this step will give complex tS and tV.... let's deal with them....
    process_complex!(tS,tV)
    tS,tV = real(tS),real(tV)
    S,V = copy(tS),copy(tV)
    for i = 1:N
        S[i] = tS[N+i]
        S[N+i] = tS[i]
        V[:,i] .= tV[:,N+i]
        V[:,N+i] .= tV[:,i]
    end #re sort eigen value from 0->large->0->small

    start_flag = 1
    end_flag = 1
    while start_flag <= N
        end_flag = start_flag
        for i = start_flag+1:N
            if real(S[start_flag]-S[i]) < tol
                end_flag = i
            else
                break
            end
        end
        if start_flag!= end_flag
            V = gram_schmit(V,start_flag,end_flag,η)
        else
            normalization!(V,start_flag,η)
        end
        start_flag = end_flag+1
    end

    if hamiltonian_type == "Symmetry"
        V[1:N,N+1:2N] .= conj.(V[N+1:2N,1:N])
        V[N+1:2N,N+1:2N] .= conj.(V[1:N,1:N])
        S[N+1:2N] .= S[1:N]
    elseif hamiltonian_type == "AntiSymmetry"
        V[1:N,N+1:2N] .= conj.(-V[N+1:2N,1:N])
        V[N+1:2N,N+1:2N] .= conj.(V[1:N,1:N])
        S[N+1:2N] .= S[1:N]
    else
        error("We do not support this type of hamiltonian~~~~~hahahah")
    end
    return S,V
end

# N = 2
# η = generate_metric(N)
# h = [1 1 1 1;1 1 1 1; 1 1 1 1; 1 1 1 1]*1.0
# S,V, = recanonicalize(h)
# display(S)
# display(V)


## File contains the fitting funcs with a parametric expansion...

using JuMP
using Gurobi
using Distributions
using Roots

#represent the desired funciton as a combination of features
#featureFuncs is itself a collection of function pointers
# phi : (prices, gdp) -> Real

#Cheapest way possible
function genFeaturesPoly(deg)
	features = Array(Any, binomial(deg + 3, deg))
	indx = 1
	for p1deg = 0:deg
		for p2deg = 0:deg
			for gdpdeg = 0:deg
				if p1deg + p2deg + gdpdeg <= deg
					features[indx] = (p1, p2, gdp) -> p1^p1deg * p2^p2deg * gdp^gdpdeg
					indx+=1
				end
			end
		end
	end
	features
end

function genFeaturesExp( rng )
	features = [(p1, p2, gdp)-> exp(r * p1) for r in rng]
	append!(features, [(p1, p2, gdp) -> exp(r * p2) for r in rng])
	append!(features, [(p1, p2, gdp) -> exp(r * gdp) for r in rng])
	append!(features, [(p1, p2, gdp) -> p1, (p1, p2, gdp) -> p2, (p1, p2, gdp) -> gdp, (p1, p2, gdp)-> 1])
	features
end

createfun(flambdas, features) =
	(prices, gdp) -> sum([flambdas[i] * features[i](prices..., gdp) for i=1:length(flambdas) ])

function setUpFitting(features)
	m = Model(solver=GurobiSolver(OutputFlag=false))
#	m = Model()
	N=length(features)
	@defVar(m, vlambdas1[1:N])
	@defVar(m, vlambdas2[1:N])
	return m, vlambdas1, vlambdas2
end

#Gens the exp features and coefficients imultaneously to constrain increasingness etc.
function setUpFitting( rng::Range{Float64} )
	N = 3*length(rng) + 4 # add linears and the constants
	features = genFeaturesExp(rng)
	m = Model(solver=GurobiSolver(OutputFlag=false))
	@defVar(m, vlambdas1[1:N])
	@defVar(m, vlambdas2[1:N])

	#require that MR(infty) -> -infty
	# for (ix, r) = enumerate(rng)
	# 	if r >= 0
	# 		@addConstraint(m, vlambdas1[ix] <= 0)
	# 		@addConstraint(m, vlambdas2[ix + length(rng)] <= 0)
	# 	end
	# 	# if r >= 0  #increasing functions
	# 	# 	@addConstraint(m, vlambdas1[ix] == 0)  #MR1 should be decreasing in p1
	# 	# 	@addConstraint(m, vlambdas1[ix + length(rng)] >=0 )  #MR1 should be increasing in p2
	# 	# 	@addConstraint(m, vlambdas2[ix] >= 0)  #MR2 should be increasing in p1
	# 	# 	@addConstraint(m, vlambdas2[ix + length(rng)] == 0)  #MR2 should be decreasing in p2
	# 	# elseif r <= 0  #decreasing functions
	# 	# 	@addConstraint(m, vlambdas1[ix] >= 0)   #MR1 should be decreasing in p1
	# 	# 	@addConstraint(m, vlambdas1[ix + length(rng)] == 0)   #MR1 should be increasing in p2
	# 	# 	@addConstraint(m, vlambdas2[ix] == 0)  #MR2 should be increasing in p1
	# 	# 	@addConstraint(m, vlambdas2[ix + length(rng)] >=0)  #MR2 should be decreasing in p2
	# 	# end
	# end

	#same increasing/decreasing for the linear terms
	# @addConstraint(m, vlambdas1[3 *length(rng) + 1] <= 0)
	# @addConstraint(m, vlambdas2[3 *length(rng) + 2] <= 0)
	# @addConstraint(m, vlambdas1[3 *length(rng) + 2] >= 0)
	# @addConstraint(m, vlambdas2[3 *length(rng) + 1] >= 0)

	#disallow the weirdness in the functional form
	for ix = 1:length(rng)
		@addConstraint(m, vlambdas1[ix + 2 *length(rng)] == 0)
		@addConstraint(m, vlambdas2[ix + 2 *length(rng)] == 0)
	end
	return m, vlambdas1, vlambdas2, features
end

#insist that the fitted function is decreasing on the data points for mean values of other stuff
function addDecreasingCnsts(m, vlambdas, features, otherP, meanGDP, price_data, pmax, ID)
	price_data = sort(price_data)
	sort_prices(myP, yourP) = ID == :1 ? (myP, yourP) : (yourP, myP)
	for j = 1:(length(price_data)- 1)
		prices_j = sort_prices(price_data[j], otherP)
		prices_jp = sort_prices(price_data[j+1], otherP)
		@addConstraint(m, sum{features[i](prices_j..., meanGDP) * vlambdas[i], i=1:length(vlambdas)} >=
		 					sum{features[i](prices_jp..., meanGDP) * vlambdas[i], i=1:length(vlambdas)} )
	end

	#add one last one for pmax in case its not achieved...
	prices_j = sort_prices(price_data[length(price_data)], otherP)
	prices_jp = sort_prices(pmax, otherP)
	@addConstraint(m, sum{features[i](prices_j..., meanGDP) * vlambdas[i], i=1:length(vlambdas)} >=
	 					sum{features[i](prices_jp..., meanGDP) * vlambdas[i], i=1:length(vlambdas)} )

end

#insist that the fitted function is positive at zero for mean values
function addPositivity(m, vlambdas, features, otherP, myP, meanGDP, ID; TOL=0)
	if ID == :1
		@addConstraint(m, sum{features[i](myP, otherP, meanGDP) * vlambdas[i], i=1:length(vlambdas)} >= TOL)
	else
		@addConstraint(m, sum{features[i](otherP, myP, meanGDP) * vlambdas[i], i=1:length(vlambdas)} >= TOL)
	end
end

#insist that the MR at the mean point should be equal to given  quantity for each
function normalize(m, vlambdas1, vlambdas2, features, meanPs, meanGDP, MR1, MR2)
	N = length(vlambdas1)
	@addConstraint(m, MR1 == sum{features[i](meanPs..., meanGDP)*vlambdas1[i], i=1:N})
	@addConstraint(m, MR2 == sum{features[i](meanPs..., meanGDP)*vlambdas2[i], i=1:N})
end

function normalize(m, vlambdas, features, prices, error, MR)
	N = length(vlambdas)
	@addConstraint(m, MR == sum{features[i](prices..., error) * vlambdas[i], i=1:N})
end

#adds the constraints to the model for the residual for this observation
function addResids(m, vlambdas1, vlambdas2, prices_t, GDP_t, pmax, features)
	#add some supplementary variables for ease:
	x = [prices_t GDP_t]; N = length(vlambdas1)
	@defVar(m, MR[1:2])
	@addConstraint(m, MR[1] == sum{features[i](prices_t..., GDP_t)*vlambdas1[i], i=1:N})
	@addConstraint(m, MR[2] == sum{features[i](prices_t..., GDP_t)*vlambdas2[i], i=1:N})

	@defVar(m, resid >= 0)
	@defVar(m, y[1:2] >= 0)
	@addConstraint(m, y[1] >= MR[1])
	@addConstraint(m, y[2] >= MR[2])
	@addConstraint(m, pmax * (y[1] + y[2]) - prices_t[1] * MR[1] - prices_t[2] * MR[2] <= resid)
	return resid
end

#calc an out of sample residual.  may be a better way to do this.
function calcResid(flambdas1, flambdas2, prices, GDP, pmax, features)
	N = length(flambdas1); MR = Array(Float64, 2)
	MR[1] = sum([flambdas1[i]*features[i](prices..., GDP) for i = 1:N])
	MR[2] = sum([flambdas2[i]*features[i](prices..., GDP) for i = 1:N])

	y = Array(Float64, 2)
	y[1] = max(0, MR[1])
	y[2] = max(0, MR[2])

	return pmax * (y[1] + y[2]) - prices[1] * MR[1] - prices[2] * MR[2]
end

function bestResponsePrice(flambdas, features, prices, error, pmax, ID)
	fMR = createfun(flambdas, features)
	if ID == :1
		# pstar = newton(p-> fMR([p, prices[2]], error), prices[1])
		pstar = fzero(p-> fMR([p, prices[2]], error), prices[1])
		#pstar = customRoot(p-> fMR([p, prices[2]], error), pmax)  #works really well with exp features
	else
		# pstar = newton(p-> fMR([prices[1], p], error), prices[2])
		pstar = fzero(p-> fMR([prices[1], p], error), prices[2])
		# pstar = customRoot(p-> fMR([prices[1], p], error), pmax)   #works really well with exp features
	end
	# assert( pstar >= 0 )
	pstar = max(0, pstar)
	return min(pstar, pmax)
end

#assumes f(0) > 0 and we have decreasingness
function customRoot(f, pmax; MAX_BRACKET = 100)
	assert( f(1e-3) > 0 )  # this should be because of the positivity issue
	if f(pmax) > 0
		return pmax
	end
	return fzero(f, [1e-3, pmax])
end

#solve for equilibrium prices.  True model is log with a random, firm dependent effect
function solveNashPrices(flambdas1, flambdas2, features, error, pmax; MAX_ITERS = 20, TOL=1e-6, trace=false,
		prices=fill(convert(Float64, pmax / 2), 2))
	dist = 0
	for i = 1:MAX_ITERS
		prices_old = copy(prices)
		prices[1] = bestResponsePrice(flambdas1, features, prices_old, error, pmax, :1)
		prices[2] = bestResponsePrice(flambdas2, features, prices_old, error, pmax, :2)
		dist = norm(prices - prices_old)
		if trace
			println([prices; dist]')
		end
		if dist < TOL
			return prices
		end
	end
	println("Warning: Max Iters Reached \t $dist")
	return prices
end


using Random

struct Gaussianθ
   A::Float64
   B::Float64
   C::Float64
   D::Float64
end

mutable struct Float64Particle
  x::Float64
  Float64Particle() = new()
end

function makeGaussianModel(θ::Gaussianθ, ys::Vector{Float64} = Vector{Float64}(undef, 0))
  n::Int64 = length(ys)
  sqrtB::Float64 = sqrt(θ.B)
  invDover2::Float64 = 0.5/θ.D
  logncG::Float64 = -0.5 * log(2 * π * θ.D)
  @inline function G(p::Int64, px::Float64Particle)
    @inbounds v::Float64 = θ.C * px.x - ys[p]
    lG::Float64 = logncG - v * invDover2 * v
    return exp(lG)
  end
  @inline function μ!(px::Float64Particle, rng::RNG) where RNG <: AbstractRNG
    px.x = θ.A + sqrtB*randn(rng)
  end
  @inline function simulate(px::Float64Particle, rng::RNG) where RNG <: AbstractRNG
    return θ.C*px.x + sqrt(θ.D)*randn(rng)
  end
  return Model(μ!, G, n, simulate, Float64Particle, Float64)
end

@inline function ldnorm(x, mu, var)
  lnc = -0.5*log(2*π*var)
  return lnc - 0.5/var*(x-mu)^2
end

function gaussianExactLL(θ::Gaussianθ, ys::Vector{Float64})
  n::Int64 = length(ys)
  v::Float64 = 0.0
  for p in 1:n
    v += ldnorm(ys[p], θ.A*θ.C, θ.C^2*θ.B+θ.D)
  end
  return v
end

# function defaultGaussianModel(n::Int64)
#   θ = Gaussianθ(0.0, 1.5, 2.5, 0.5)
#   model = makeGaussianModel(θ)
#   ys = simulateModel(model, n)
#   model = makeGaussianModel(θ, ys)
#   exactLL = gaussianExactLL(θ, ys)
#   return model, θ, ys, exactLL
# end


## karhunen_loeve.jl : approximate Gaussian random field generator using a Karhunen-Lo\`eve decomposition

"""
    KarhunenLoeve{n} <: GaussianRandomFieldGenerator

A [`GaussiandRandomFieldGenerator`](@ref) using a Karhunen-Lo\u00e8ve (KL) expansion with `n` terms.

# Examples
```jldoctest
julia> m = Matern(0.1,1.0)
Matérn (λ=0.1, ν=1.0, σ=1.0, p=2.0)

julia> c = CovarianceFunction(2,m)
2d Matérn covariance function (λ=0.1, ν=1.0, σ=1.0, p=2.0)

julia> pts1 = 0:0.02:1; pts2 = 0:0.02:1
0.0:0.02:1.0

julia> grf = GaussianRandomField(c,KarhunenLoeve(300),pts1,pts2)
Gaussian random field with 2d Matérn covariance function (λ=0.1, ν=1.0, σ=1.0, p=2.0) on a 51x51 structured grid, using a KL expansion with 300 terms

julia> plot_eigenvalues(grf) # plot the eigenvalue decay
[...]

julia> plot_eigenfunction(grf,4) # plots the fourth eigenfunction
[...]

```
The more terms are retained in the expansion, the better the approximation will be.
```jldoctest
julia> nterms = [1 2 5 10 20 50 100 200 500 1000]
1×10 Array{Int64,2}:
 1  2  5  10  20  50  100  200  500  1000

julia> for n in nterms
       grf = GaussianRandomField(c,KarhunenLoeve(n),pts1,pts2)
       @show rel_error(grf)
       end
rel_error(grf) = 0.7499982529722711
rel_error(grf) = 0.49999825591379987
rel_error(grf) = 0.4425751861338164
rel_error(grf) = 0.35789475278408045
rel_error(grf) = 0.16805079842673853
rel_error(grf) = 0.11187098338277579
rel_error(grf) = 0.05130466343704787
rel_error(grf) = 0.017343327476498027
rel_error(grf) = 0.0034278579378175245
rel_error(grf) = 0.0007216777927243623

```
The KL expansion is computed using the Nystrom method. Optional argument are the quadrature rule `quad` and the number of quadrature points in each direction `nq`. Possible values for `quad` are `GaussLegendre()`, `Midpoint()`, `Simpson()`, `Trapezoidal` and `EOLE()` (default). The total number of quadrature points must be larger than or equal to the requested number of terms. Default is `ceil(n^(1/d))`. This value is best left untouched.

```jldoctest
julia> grf = GaussianRandomField(c,KarhunenLoeve(300),pts1,pts2,quad=GaussLegendre())
Gaussian random field with 2d Matérn covariance function (λ=0.1, ν=1.0, σ=1.0, p=2.0) on a 51x51 structured grid, using a KL expansion with 300 terms

julia> grf = GaussianRandomField(c,KarhunenLoeve(300),pts1,pts2,quad=Simpson(),nq=20)
Gaussian random field with 2d Matérn covariance function (λ=0.1, ν=1.0, σ=1.0, p=2.0) on a 51x51 structured grid, using a KL expansion with 300 terms

```
See also: [`Cholesky`](@ref), [`Spectral`](@ref), [`CirculantEmbedding`](@ref)
"""
struct KarhunenLoeve{n} <: GaussianRandomFieldGenerator end

KarhunenLoeve(n::Integer) = n > 0 ? KarhunenLoeve{n}() : throw(ArgumentError("in KarhunenLoeve(n), number of terms n must be positive"))

const KarhunenLoeveGRF{n} = GaussianRandomField{C,KarhunenLoeve{n}} where {n,C}
const KL{n} = KarhunenLoeve{n}

function _GaussianRandomField(mean,cov::CovarianceFunction{d},method::KL{n},pts...;
                              nq::T=ceil(typeof(n),n^(1/d)), quad::QuadratureRule=EOLE()) where {d,n,T<:Integer}
    # check if number of terms and number of quadrature points are compatible
    nq = nq > 0 ? nq .* tuple(ones(T,d)...) : length.(pts)
    nq = prod(nq) == n ? nq.+1 : nq # adjustment for ARPACK error when looking for ALL eigenvalues
    prod(nq) < n && throw(ArgumentError("too many terms requested, increase nq or lower n"))

    # determine bounding box when irregular mesh
    is_irr = typeof(pts[1]) <: AbstractMatrix
    a = is_irr ? Tuple(minimum(pts[1],dims=2)) : minimum.(pts)
    b = is_irr ? Tuple(maximum(pts[1],dims=2)) : maximum.(pts)

    # compute quadrature nodes and weights
    struc = get_nodes_and_weights.(nq,a,b,Ref(quad))
    nodes = first.(struc)
    weights = last.(struc)

    # eigenvalue problem
    C = apply(cov,nodes,nodes)
    W = d == 1 ? diagm(0 => weights...) : diagm(0 => kron(weights...))
    Wsqrt = sqrt.(W)
    B = Symmetric(Wsqrt*C*Wsqrt) # should be symmetric and positive semi-definite
    isposdef(B) || warn("equivalent eigenvalue problem is not SPD, results may be wrong or inaccurate")

    # solve
    (eigenval,eigenfunc) = eigs(B,nev=n,ritzvec=true,which=:LM,v0=randn(size(B,1)))
 	N = find_last_positive(eigenval)
	N == length(eigenval) || warn("negative eigenvalue $(eigenval[N+1]) detected, Gaussian random field will be approximated (ignoring all negative eigenvalues)")

    # compute eigenfunctions in nodes
    K = apply(cov,pts,nodes)
    Λ = diagm(0 => 1 ./ eigenval)
    eigenfunc = K*Wsqrt*eigenfunc*Λ

    # store eigenvalues and eigenfunctions
    data = SpectralData(sqrt.(eigenval[1:N]),eigenfunc[:,1:N]) # note: store sqrt of eigenval for more efficient sampling

    GaussianRandomField{typeof(cov),KL{N},typeof(pts)}(mean,cov,pts,data)
end

# returns the required dimension of the random points
randdim(grf::KarhunenLoeveGRF{n}) where {n} = n

# relative error in the KL approximation
function rel_error(grf::KarhunenLoeveGRF)
    Leb = prod(maximum.(grf.pts).-minimum.(grf.pts))
	return (std(grf.cov)^2*Leb - sum(grf.data.eigenval.^2))/(std(grf.cov)^2*Leb)
end

# sample function for both Spectral() and KarhunenLoeve(n) type
function _sample(grf::Union{SpectralGRF,KarhunenLoeveGRF}, xi)
    grf.mean + std(grf.cov)*reshape(( grf.data.eigenfunc*diagm(0 => grf.data.eigenval) )*xi,size(grf.mean))
end

show(io::IO,::KarhunenLoeve{n}) where {n} = print(io,"KL expansion with $(n) terms")


@symbol_func function P_kappa(cur_reactor::AbstractReactor)
  cur_P = K_kappa(cur_reactor)

  cur_P *= cur_reactor.R_0 ^ 3

  cur_P *= cur_reactor.n_bar

  cur_P *= cur_reactor.T_bar

  cur_P /= tau_E(cur_reactor)

  cur_P
end


using CSV

input = CSV.read("./src/Day1/input.txt", Tuple, header = false)
inputarray = input[1]
# inputarray = [1721
# 979
# 366
# 299
# 675
# 1456]

for i in 1:(length(inputarray) - 1), j in (i+1):length(inputarray)
    sum = inputarray[i] + inputarray[j]
    if sum == 2020
        prod = inputarray[i] * inputarray[j]
        println(inputarray[i])
        println(inputarray[j])
        println(prod)
    end
end

function sumfinder(inputarray, numentries, target, currentsum, currentvals)
    if length(inputarray) < numentries
        # no solution is possible
        return nothing
    elseif length(inputarray) == numentries
        if sum(inputarray) + currentsum == target
            # solution found
            soln = vcat(currentvals, inputarray)
            return soln
        else
            # solution does not exist
            return nothing
        end
    elseif length(inputarray) == 0
        # solution does not exist
        return nothing
    elseif numentries <= 0
        if currentsum == target
            # solution found
            soln = currentvals
            return soln
        else
            # solution does not exist
            return nothing
        end
    else
        for i in 1:(length(inputarray) - numentries)
            picked = inputarray[i]
            newarray = inputarray[(i+1):end]
            newsum = currentsum + picked
            newvals = vcat(currentvals, picked)
            test = sumfinder(newarray, numentries - 1, target, newsum, newvals)
            if !isnothing(test)
                soln = test
                return soln
            end
        end
        return nothing
    end
end

a = sumfinder(inputarray, 3, 2020, 0, [])
prod(a)


# ---
# title: 1046. Last Stone Weight
# id: problem1046
# author: Tian Jun
# date: 2020-10-31
# difficulty: Easy
# categories: Heap, Greedy
# link: <https://leetcode.com/problems/last-stone-weight/description/>
# hidden: true
# ---
#
# We have a collection of stones, each stone has a positive integer weight.
#
# Each turn, we choose the two **heaviest**  stones and smash them together.
# Suppose the stones have weights `x` and `y` with `x <= y`.  The result of this
# smash is:
#
#   * If `x == y`, both stones are totally destroyed;
#   * If `x != y`, the stone of weight `x` is totally destroyed, and the stone of weight `y` has new weight `y-x`.
#
# At the end, there is at most 1 stone left.  Return the weight of this stone
# (or 0 if there are no stones left.)
#
#
#
# **Example 1:**
#
#
#
#     Input: [2,7,4,1,8,1]
#     Output: 1
#     Explanation:
#     We combine 7 and 8 to get 1 so the array converts to [2,4,1,1,1] then,
#     we combine 2 and 4 to get 2 so the array converts to [2,1,1,1] then,
#     we combine 2 and 1 to get 1 so the array converts to [1,1,1] then,
#     we combine 1 and 1 to get 0 so the array converts to [1] then that's the value of last stone.
#
#
#
# **Note:**
#
#   1. `1 <= stones.length <= 30`
#   2. `1 <= stones[i] <= 1000`
#
#
## @lc code=start
using LeetCode

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


# ---
# title: 587. Erect the Fence
# id: problem587
# author: Tian Jun
# date: 2020-10-31
# difficulty: Hard
# categories: Geometry
# link: <https://leetcode.com/problems/erect-the-fence/description/>
# hidden: true
# ---
#
# There are some trees, where each tree is represented by (x,y) coordinate in a
# two-dimensional garden. Your job is to fence the entire garden using the
# **minimum length** of rope as it is expensive. The garden is well fenced only
# if all the trees are enclosed. Your task is to help find the coordinates of
# trees which are exactly located on the fence perimeter.
#
#
#
# **Example 1:**
#
#
#
#     Input: [[1,1],[2,2],[2,0],[2,4],[3,3],[4,2]]
#     Output: [[1,1],[2,0],[4,2],[3,3],[2,4]]
#     Explanation:
#     ![](https://assets.leetcode.com/uploads/2018/10/12/erect_the_fence_1.png)
#
#
# **Example 2:**
#
#
#
#     Input: [[1,2],[2,2],[4,2]]
#     Output: [[1,2],[2,2],[4,2]]
#     Explanation:
#     ![](https://assets.leetcode.com/uploads/2018/10/12/erect_the_fence_2.png)
#     Even you only have trees in a line, you need to use rope to enclose them.
#
#
#
#
# **Note:**
#
#   1. All trees should be enclosed together. You cannot cut the rope to enclose trees that will separate them in more than one group.
#   2. All input integers will range from 0 to 100.
#   3. The garden has at least one tree.
#   4. All coordinates are distinct.
#   5. Input points have **NO** order. No order required for output.
#   6. input types have been changed on April 15, 2019. Please reset to default code definition to get new method signature.
#
#
## @lc code=start
using LeetCode

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


using MarketEquilibria
using DelimitedFiles
using Random
using Plots
using Plots.PlotMeasures

form = [:linear, :CES, :CES, :CES, :cobb_douglas,
        :CES, :CES, :CES, :CES, :CES, :leontief]
# Rho value ignored for anything other than :CES
rho = [000, .75, .5, .25, 000, -0.5,
       -1., -2, -5, -10, 000]
rho_label = ["Linear", "0.75", "0.5", "0.25",
             "Cobb–\nDouglas", "-0.5", "-1.0", "-2.0",
             "-5.0", "-10.0", "Leontief"]
samp = size(rho)[1]

m, n = 4, 6

# endowments =  1 .+ randexp(m)
# A = rand(m, n)
# A ./= sum(A, dims=2)
# supplies = 1 .+ rand(n)
#
# writedlm("examples/Fisher/in/endowments.dat", endowments)
# writedlm("examples/Fisher/in/A.dat", A)
# writedlm("examples/Fisher/in/supplies.dat", supplies)

endowments = reshape(readdlm("examples/Fisher/in/endowments.dat"), :)
A          = readdlm("examples/Fisher/in/A.dat")
supplies   = reshape(readdlm("examples/Fisher/in/supplies.dat"), :)

prices = zeros(n, samp)
X      = zeros(m, n, samp)

for i in 1:samp
    global X
    global prices
    X[:, :, i], prices[:, i] = homogeneousfisher(endowments, A, supplies, form[i], rho[i])
    prices[:, i] .*= -1.
    signal = isapprox(endowments, X[:, :, i] * prices[:, i], atol=1e-3)
    @assert signal "Something went wrong; rho = $(rho[i])"
end

writedlm("examples/Fisher/out/X.dat", X)
writedlm("examples/Fisher/out/prices.dat", prices)

#A_bar = sum(A, dims=1) / m
A_bar = round.(A' * endowments, digits=4)

p = plot(1:samp,
         prices',
         xticks=(1:samp, rho_label),
         xlabel="ρ",
         ylabel="price",
         linestyle=[:dash :dot :solid],
         title="Equilibrium price for homogeneous CES utility, $m players, $n resources",
         titlefontsize=12,
         legend=:topleft,
         label=reshape(["π$i, ā = $(A_bar[i])" for i in 1:n], 1, :))

savefig(p, "examples/Fisher/EqPlot.png")
savefig(p, "examples/Fisher/EqPlot.pdf")

X1 = X[1, :, :] ./ sum(X[1, :, :], dims = 1)
X1A = round.(A[1, :], digits=4)

q = plot(1:samp,
         cumsum(X1[end:-1:1, :], dims=1)'[:,end:-1:1],
         fill=0,
         xlim=(1, samp),
         right_margin=5mm,
         ylim=(0, 1),
         xticks=(1:samp, rho_label),
         xlabel="ρ",
         ylabel="Player 1’s optimal allocation",
         ls=:solid,
         lc=:black, lw=.5,
         title="Equilibrium allocation for homogeneous CES utility",
         titlefontsize=12,
         legend=:top,
         label=reshape(["x$i, a = $(X1A[i])" for i in 1:n], 1, :))

savefig(q, "examples/Fisher/XPlot.png")
savefig(q, "examples/Fisher/XPlot.pdf")


Text provided under a Creative Commons Attribution license, CC-BY.  All code is made available under the FSF-approved BSD-3 license.  (c) Lorena A. Barba, Gilbert F. Forsyth 2017. Thanks to NSF for support via CAREER award #1149784.
[@LorenaABarba](https://twitter.com/LorenaABarba)

12 steps to Navier–Stokes
=====
***

We continue our journey to solve the Navier–Stokes equation with Step 4. But don't continue unless you have completed the previous steps! In fact, this next step will be a combination of the two previous ones. The wonders of *code reuse*!

Step 4: Burgers' Equation
----
***

You can read about Burgers' Equation on its [wikipedia page](http://en.wikipedia.org/wiki/Burgers'_equation).

Burgers' equation in one spatial dimension looks like this:

$$\frac{\partial u}{\partial t} + u \frac{\partial u}{\partial x} = \nu \frac{\partial ^2u}{\partial x^2}$$

As you can see, it is a combination of non-linear convection and diffusion. It is surprising how much you learn from this neat little equation!

We can discretize it using the methods we've already detailed in Steps [1](./01_Step_1.ipynb) to [3](./04_Step_3.ipynb).  Using forward difference for time, backward difference for space and our 2nd-order method for the second derivatives yields:

$$\frac{u_i^{n+1}-u_i^n}{\Delta t} + u_i^n \frac{u_i^n - u_{i-1}^n}{\Delta x} = \nu \frac{u_{i+1}^n - 2u_i^n + u_{i-1}^n}{\Delta x^2}$$

As before, once we have an initial condition, the only unknown is $u_i^{n+1}$. We will step in time as follows:

$$u_i^{n+1} = u_i^n - u_i^n \frac{\Delta t}{\Delta x} (u_i^n - u_{i-1}^n) + \nu \frac{\Delta t}{\Delta x^2}(u_{i+1}^n - 2u_i^n + u_{i-1}^n)$$

### Initial and Boundary Conditions

To examine some interesting properties of Burgers' equation, it is helpful to use different initial and boundary conditions than we've been using for previous steps.

Our initial condition for this problem is going to be:

\begin{eqnarray}
u &=& -\frac{2 \nu}{\phi} \frac{\partial \phi}{\partial x} + 4 \\\
\phi &=& \exp \bigg(\frac{-x^2}{4 \nu} \bigg) + \exp \bigg(\frac{-(x-2 \pi)^2}{4 \nu} \bigg)
\end{eqnarray}

This has an analytical solution, given by:

\begin{eqnarray}
u &=& -\frac{2 \nu}{\phi} \frac{\partial \phi}{\partial x} + 4 \\\
\phi &=& \exp \bigg(\frac{-(x-4t)^2}{4 \nu (t+1)} \bigg) + \exp \bigg(\frac{-(x-4t -2 \pi)^2}{4 \nu(t+1)} \bigg)
\end{eqnarray}

Our boundary condition will be:

$$u(0) = u(2\pi)$$

This is called a *periodic* boundary condition. Pay attention! This will cause you a bit of headache if you don't tread carefully.

### Saving Time with SymPy

The initial condition we're using for Burgers' Equation can be a bit of a pain to evaluate by hand.  The derivative $\frac{\partial \phi}{\partial x}$ isn't too terribly difficult, but it would be easy to drop a sign or forget a factor of $x$ somewhere, so we're going to use SymPy to help us out.

[SymPy](http://sympy.org/en/) is the symbolic math library for Python.  It has a lot of the same symbolic math functionality as Mathematica with the added benefit that we can easily translate its results back into our Python calculations (it is also free and open source).

Start by loading the SymPy library, together with our favorite library, NumPy.

```python
import numpy
import sympy
```

We're also going to tell SymPy that we want all of its output to be rendered using $\LaTeX$. This will make our Notebook beautiful!

```python
from sympy import init_printing
init_printing(use_latex=True)
```

Start by setting up symbolic variables for the three variables in our initial condition and then type out the full equation for $\phi$.  We should get a nicely rendered version of our $\phi$ equation.

```python
x, nu, t = sympy.symbols('x nu t')
phi = (sympy.exp(-(x - 4 * t)**2 / (4 * nu * (t + 1))) +
       sympy.exp(-(x - 4 * t - 2 * sympy.pi)**2 / (4 * nu * (t + 1))))
phi
```

$$e^{- \frac{\left(- 4 t + x - 2 \pi\right)^{2}}{4 \nu \left(t + 1\right)}} + e^{- \frac{\left(- 4 t + x\right)^{2}}{4 \nu \left(t + 1\right)}}$$

It's maybe a little small, but that looks right.  Now to evaluate our partial derivative $\frac{\partial \phi}{\partial x}$ is a trivial task.

```python
phiprime = phi.diff(x)
phiprime
```

$$- \frac{e^{- \frac{\left(- 4 t + x\right)^{2}}{4 \nu \left(t + 1\right)}}}{4 \nu \left(t + 1\right)} \left(- 8 t + 2 x\right) - \frac{1}{4 \nu \left(t + 1\right)} \left(- 8 t + 2 x - 4 \pi\right) e^{- \frac{\left(- 4 t + x - 2 \pi\right)^{2}}{4 \nu \left(t + 1\right)}}$$

If you want to see the unrendered version, just use the Python print command.

```python
print(phiprime)
```

    -(-8*t + 2*x)*exp(-(-4*t + x)**2/(4*nu*(t + 1)))/(4*nu*(t + 1)) - (-8*t + 2*x - 4*pi)*exp(-(-4*t + x - 2*pi)**2/(4*nu*(t + 1)))/(4*nu*(t + 1))

### Now what?

Now that we have the Pythonic version of our derivative, we can finish writing out the full initial condition equation and then translate it into a usable Python expression.  For this, we'll use the *lambdify* function, which takes a SymPy symbolic equation and turns it into a callable function.

```python
from sympy.utilities.lambdify import lambdify

u = -2 * nu * (phiprime / phi) + 4
print(u)
```

    -2*nu*(-(-8*t + 2*x)*exp(-(-4*t + x)**2/(4*nu*(t + 1)))/(4*nu*(t + 1)) - (-8*t + 2*x - 4*pi)*exp(-(-4*t + x - 2*pi)**2/(4*nu*(t + 1)))/(4*nu*(t + 1)))/(exp(-(-4*t + x - 2*pi)**2/(4*nu*(t + 1))) + exp(-(-4*t + x)**2/(4*nu*(t + 1)))) + 4

### Lambdify

To lambdify this expression into a useable function, we tell lambdify which variables to request and the function we want to plug them in to.

```python
ufunc = lambdify((t, x, nu), u)
print(ufunc(1, 4, 3))
```

    3.49170664206

### Back to Burgers' Equation

Now that we have the initial conditions set up, we can proceed and finish setting up the problem.  We can generate the plot of the initial condition using our lambdify-ed function.

```python
from matplotlib import pyplot
%matplotlib inline

###variable declarations
nx = 101
nt = 100
dx = 2 * numpy.pi / (nx - 1)
nu = .07
dt = dx * nu

x = numpy.linspace(0, 2 * numpy.pi, nx)
un = numpy.empty(nx)
t = 0

u = numpy.asarray([ufunc(t, x0, nu) for x0 in x])
u
```

    array([ 4.        ,  4.06283185,  4.12566371,  4.18849556,  4.25132741,
            4.31415927,  4.37699112,  4.43982297,  4.50265482,  4.56548668,
            4.62831853,  4.69115038,  4.75398224,  4.81681409,  4.87964594,
            4.9424778 ,  5.00530965,  5.0681415 ,  5.13097336,  5.19380521,
            5.25663706,  5.31946891,  5.38230077,  5.44513262,  5.50796447,
            5.57079633,  5.63362818,  5.69646003,  5.75929189,  5.82212374,
            5.88495559,  5.94778745,  6.0106193 ,  6.07345115,  6.136283  ,
            6.19911486,  6.26194671,  6.32477856,  6.38761042,  6.45044227,
            6.51327412,  6.57610598,  6.63893783,  6.70176967,  6.76460125,
            6.82742866,  6.89018589,  6.95176632,  6.99367964,  6.72527549,
            4.        ,  1.27472451,  1.00632036,  1.04823368,  1.10981411,
            1.17257134,  1.23539875,  1.29823033,  1.36106217,  1.42389402,
            1.48672588,  1.54955773,  1.61238958,  1.67522144,  1.73805329,
            1.80088514,  1.863717  ,  1.92654885,  1.9893807 ,  2.05221255,
            2.11504441,  2.17787626,  2.24070811,  2.30353997,  2.36637182,
            2.42920367,  2.49203553,  2.55486738,  2.61769923,  2.68053109,
            2.74336294,  2.80619479,  2.86902664,  2.9318585 ,  2.99469035,
            3.0575222 ,  3.12035406,  3.18318591,  3.24601776,  3.30884962,
            3.37168147,  3.43451332,  3.49734518,  3.56017703,  3.62300888,
            3.68584073,  3.74867259,  3.81150444,  3.87433629,  3.93716815,  4.        ])

```python
pyplot.figure(figsize=(11, 7), dpi=100)
pyplot.plot(x, u, marker='o', lw=2)
pyplot.xlim([0, 2 * numpy.pi])
pyplot.ylim([0, 10]);
```

![png](output_23_0.png)

This is definitely not the hat function we've been dealing with until now. We call it a "saw-tooth function".  Let's proceed forward and see what happens.

### Periodic Boundary Conditions

One of the big differences between Step 4 and the previous lessons is the use of *periodic* boundary conditions.  If you experiment with Steps 1 and 2 and make the simulation run longer (by increasing `nt`) you will notice that the wave will keep moving to the right until it no longer even shows up in the plot.

With periodic boundary conditions, when a point gets to the right-hand side of the frame, it *wraps around* back to the front of the frame.

Recall the discretization that we worked out at the beginning of this notebook:

$$u_i^{n+1} = u_i^n - u_i^n \frac{\Delta t}{\Delta x} (u_i^n - u_{i-1}^n) + \nu \frac{\Delta t}{\Delta x^2}(u_{i+1}^n - 2u_i^n + u_{i-1}^n)$$

What does $u_{i+1}^n$ *mean* when $i$ is already at the end of the frame?

Think about this for a minute before proceeding.

```python
for n in range(nt):
    un = u.copy()
    for i in range(1, nx-1):
        u[i] = un[i] - un[i] * dt / dx *(un[i] - un[i-1]) + nu * dt / dx**2 *\
                (un[i+1] - 2 * un[i] + un[i-1])
    u[0] = un[0] - un[0] * dt / dx * (un[0] - un[-2]) + nu * dt / dx**2 *\
                (un[1] - 2 * un[0] + un[-2])
    u[-1] = u[0]

u_analytical = numpy.asarray([ufunc(nt * dt, xi, nu) for xi in x])
```

```python
pyplot.figure(figsize=(11, 7), dpi=100)
pyplot.plot(x,u, marker='o', lw=2, label='Computational')
pyplot.plot(x, u_analytical, label='Analytical')
pyplot.xlim([0, 2 * numpy.pi])
pyplot.ylim([0, 10])
pyplot.legend();
```

![png](output_27_0.png)

***

What next?
----

The subsequent steps, from 5 to 12, will be in two dimensions. But it is easy to extend the 1D finite-difference formulas to the partial derivatives in 2D or 3D. Just apply the definition — a partial derivative with respect to $x$ is the variation in the $x$ direction *while keeping $y$ constant*.

Before moving on to [Step 5](./07_Step_5.ipynb), make sure you have completed your own code for steps 1 through 4 and you have experimented with the parameters and thought about what is happening. Also, we recommend that you take a slight break to learn about [array operations with NumPy](./06_Array_Operations_with_NumPy.ipynb).

```python
from IPython.core.display import HTML
def css_styling():
    styles = open("../styles/custom.css", "r").read()
    return HTML(styles)
css_styling()
```

<link href='http://fonts.googleapis.com/css?family=Fenix' rel='stylesheet' type='text/css'>
<link href='http://fonts.googleapis.com/css?family=Alegreya+Sans:100,300,400,500,700,800,900,100italic,300italic,400italic,500italic,700italic,800italic,900italic' rel='stylesheet' type='text/css'>
<link href='http://fonts.googleapis.com/css?family=Source+Code+Pro:300,400' rel='stylesheet' type='text/css'>
<style>
    @font-face {
        font-family: "Computer Modern";
        src: url('http://mirrors.ctan.org/fonts/cm-unicode/fonts/otf/cmunss.otf');
    }
    div.cell{
        width:800px;
        margin-left:16% !important;
        margin-right:auto;
    }
    h1 {
        font-family: 'Alegreya Sans', sans-serif;
    }
    h2 {
        font-family: 'Fenix', serif;
    }
    h3{
		font-family: 'Fenix', serif;
        margin-top:12px;
        margin-bottom: 3px;
       }
	h4{
		font-family: 'Fenix', serif;
       }
    h5 {
        font-family: 'Alegreya Sans', sans-serif;
    }
    div.text_cell_render{
        font-family: 'Alegreya Sans',Computer Modern, "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
        line-height: 135%;
        font-size: 120%;
        width:600px;
        margin-left:auto;
        margin-right:auto;
    }
    .CodeMirror{
            font-family: "Source Code Pro";
			font-size: 90%;
    }
/*    .prompt{
        display: None;
    }*/
    .text_cell_render h1 {
        font-weight: 200;
        font-size: 50pt;
		line-height: 100%;
        color:#CD2305;
        margin-bottom: 0.5em;
        margin-top: 0.5em;
        display: block;
    }
    .text_cell_render h5 {
        font-weight: 300;
        font-size: 16pt;
        color: #CD2305;
        font-style: italic;
        margin-bottom: .5em;
        margin-top: 0.5em;
        display: block;
    }

    .warning{
        color: rgb( 240, 20, 20 )
        }
</style>
<script>
    MathJax.Hub.Config({
                        TeX: {
                           extensions: ["AMSmath.js"]
                           },
                tex2jax: {
                    inlineMath: [ ['$','$'], ["\\(","\\)"] ],
                    displayMath: [ ['$$','$$'], ["\\[","\\]"] ]
                },
                displayAlign: 'center', // Change this to 'center' to center equations.
                "HTML-CSS": {
                    styles: {'.MathJax_Display': {"margin": 4}}
                }
        });
</script>


### GROUP MEMBERS : Ashish Kumar, Pallavi Wats and Firat Melih Yilmaz

using Random
using LinearAlgebra
using BenchmarkTools
using Distributions
using JLD
using DataFrames
using CSV
using DelimitedFiles
using TypedTables
using Latexify
using LaTeXStrings
using FreqTables

############## Q1 ################
#1.(a)
Random.seed!(1234)
A = rand(Uniform(-1,2), 10,7)
B = rand(Normal(-2,15),10,7)
C = hcat(A[1:5,1:5],B[1:5,6:7])
D = similar(A)
for i in 1:7, j in 1:7
    if A[i,j] <= 0
        D[i,j]=A[i,j]
    else D[i,j]=0
    end
end

#1.(b)
#list the number of elements of the matrix
println(length(A))

#describe the size of the matrix
size(A)

#list of elements in A
for i in 1:10, j in 1:7
println(A[i,j])
end

#1.(c)
#number of unique elements in the matrix D
length(unique(D))

#list of unique elements of matrix D
vector_D = D[:];
println(unique(vector_D))

#1.(d)
#convert a matrix to a vector
#using reshape function
E = reshape(B,70)

#simpler way
E  = B[:]

#1.(e)
#creating a three-dimensional vector using A in the first column of the 3rd dimension and B in the second column of the 3rd dimension
F = cat(A,B,dims=3)

#1.(f)
#using permutedims to transform F from (10*7*2) to (2*10*7)
#F = permutedims(F,(2,10,7)) # not working

#using reshape
F = reshape(F,(2,10,7))

#1.(g)
#kronecker product of B and C
G = kron(A,B)

#kron(C,F)   ## kron does not work well for 3-D matrices

#1.(h)
#saving matrix A,B,C,D,E,F,G as a .jld file called matrixpractice

#saving all the matrices with their respective unique identifiers
save("/Users/prachi/Desktop/Econometrics6343/PS1/matrixpractice.jld","A",A,"B",B,"C",C,"D",D,"E",E,"F",F,"G",G)

#if I have to fetch only Matrix A
#load("/Users/prachi/Desktop/Econometrics6343/PS1/matrixpractice.jld","A")

#1.(i)
#save only the matrices A, B, C, and D as a .jld file called firstmatrix.
save("/Users/prachi/Desktop/Econometrics6343/PS1/firstmatrix.jld","A",A,"B",B,"C",C,"D",D)

#1.(j)
#export C as a .csv file called Cmatrix -- you will first need to transform C into a Dataframe
#converting to dataframe
C = convert(DataFrame,C)

#write a csv file
CSV.write("/Users/prachi/Desktop/Econometrics6343/PS1/Cmatrix.csv",C)

#1.(h)
#export D as a tab-delimited .dat file called Dmatrix -- you will first need to transform D into a DataFrame
D = convert(DataFrame,D)

#write a tab delimited .dat file
CSV.write("/Users/prachi/Desktop/Econometrics6343/PS1/Dmatrix.dat", D)

#1.(k)
#wrap it in function
function q1()
    Random.seed!(1234)
    A = rand(10,7) .* (10-(-5)).-5
    B = randn(10,7) .* (225-(-2)).-2
    C = hcat(A[1:5,1:5],B[1:5,6:7])
    D = similar(A)
    for i in 1:10, j = 1:7
        if A[i,j] <= 0
            D[i,j] = A[i,j]
        else
            D[i,j] = 0
        end
    end

    return A,B,C,D
end

A,B,C,D = q1()

############# Q2 #################
#2.(a)
#loop that computes element-by-element product of Matrix A and B, called AB
AB = zeros(10,7)
for i in 1:length(A)
    AB[i]=A[i]*B[i]
end

#without a loop element-by-element product of A and B
AB2 = A.*B

#2.(b)
#write a loop to create a column vector called Cprime which contains only elements of C that are between [-5,5]
Cprime = C[:]
for item in eachrow(C), i in item
    if -5<= i <= 5
        append!(Cprime,i)
    end
end

#do above without a loop
Cprime2 = C[-5 .≤ C .≤ 5];

#2.(c)
#use a loop to craete a 3D array X of dimension 15*169*5
X = zeros((15169,6,5))
for i in 1:size(X)[3], j in 1:size(X)[2]
    if j == 1
        X[:,j,i] .= 1
    elseif  j==2
        a2 = rand(Binomial(1,(0.75*(6-i))/5),15169)
        X[:,j,i] = a2
    elseif j==3
        a3 = rand(Normal(15+i-1,5*(i-1)),15169)
        X[:,j,i] = a3
    elseif j == 4
        a4 = rand(Normal((pi*(6-i))/3,1/ℯ),15169)
        X[:,j,i] = a4
    elseif  j == 5
        a5 = rand(Normal(12,2.19),15169)
        X[:,j,i] = a5
    elseif j == 6
        a6 = rand(Binomial(20,0.5),15169)
        X[:,j,i]  = a6
    end
end

#2.(d)
#use comprehension to create a matrix β (6*5) whose elements eveolve across time
K = 6
T = 5
β = zeros(K,T)
β[1,:] = [1:0.25:2;]
β[2,:] = [ log(x) for x in 1:T ]
β[3,:] = [-sqrt(x) for x in 1:T ]
β[4,:] = [ exp(x)-exp(x+1) for x in 1:T ]
β[5,:] = [x for x in 1:T]
β[6,:] = [x/3 for x in 1:T]

#2.(e)
#use comprehensions to create matrix Y (N*T) defined by ...

Y = zeros((15169,5,5))
for i in 1:5
    ϵ = rand(Normal(0,0.36),(15169,5))
    Y[:,:,i] = X[:,:,i]*β + ϵ
end

################ Q3 ######################
#3.(a)
#import nlsw88 as DataFrames
## first import nlsw as CSV file
nlsw = CSV.read("/Users/prachi/Desktop/Econometrics6343/PS1/nlsw88.csv")

#check if there are missing values
ismissing(nlsw)    #false -- no missing data

#convert nlsw88 into a DataFrame
df = convert(DataFrame, nlsw)

save("/Users/prachi/Desktop/Econometrics6343/PS1/nlsw88.jld", "df", df)

#make nullable
allowmissing!(df)

#describe data
describe(df)

#3.(b)
#what % of the sample have never been married?
m = freqtable(df, :never_married)

never_married = (sum(df["never_married"])/(sum(df["never_married"]) + sum(df["married"]))) * 100;
println("Percentage of the sample that has never been married: $never_married %")

#3.(c)
#use tabulate() to report what percentage of sample is in each race category
#using freqtable instead
race = prop(freqtable(df["race"]));

#3.(d)
#use the describe() function to create a matrix called summarystats which lists the mean, median, standard deviation, min, max, number of unique elements, and IQR
summarystats = describe(df);

#3.(e)
#show the joint distribution of industry and occupation using a cross-tabulation

joint_table = freqtable(df, :industry, :occupation);

#3.(g)
#wrap a function definition around all of the code for question 3
#call the function q3(). The function should have no inputs and no outputs
function q3()
    df = CSV.read("/Users/prachi/Desktop/Econometrics6343/PS1/nlsw88.csv");
    @save("nlsw88.jld", df)
    never_married = (sum(df["never_married"])/(sum(data["never_married"]) + sum(data["married"]))) * 100;
    race = prop(freqtable(df["race"]));
    summarystats = describe(df);
end

############## Q4 ###############
# Practice with functions

#4.(a)
#load firstmatrix.jld
load("/Users/prachi/Desktop/Econometrics6343/PS1/firstmatrix.jld")

#write a function called matrixops that takes as inputs the matrices A and B from question (a) of problem 1 and has three outputs: (i) the element-by-element product of the inputs,
# (ii) the product A′B, and (iii) the sum of all the elements of A + B.
#4.(d)
function matrixops(A, B)
    i = A .+ B
    ii = A' * B
    iii = sum(A + B)

    return i, ii, iii
end

matrixops(A,B);

#4.(c)
function matrixops(A, B)
    """
    Takes  matrix A and B as inputs and returns following outputs:

    i = A .+ B
    ii = A' * B
    iii = sum(A + B)
    """
    i = A .+ B
    ii = A' * B
    iii = sum(A + B)

    return i, ii, iii
end

#4.(e)
function matrixops(A, B)
    """
    Takes  matrix A and B as inputs and returns following outputs:

    i = A .+ B
    ii = A' * B
    iii = sum(A + B)
    """
    if size(A) != size(B)
        throw(DimensionMismatch("inputs must have the same size."))
    i = A .+ B
    ii = A' * B
    iii = sum(A + B)

    return i, ii, iii
end


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

using Markdown
using InteractiveUtils

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

	md"""
	# Homework 3

	Eric Nguyen
	"""
end

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

So ``E(x)`` is

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

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

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

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

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

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

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

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

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

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

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

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

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

Gaussian integral

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

In other words,

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

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

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

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

Matching the real and imaginary parts, we see that

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

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

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

For the first expression,

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

For the second expression,

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

For the third expression,

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

For the fourth expression,

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

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

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

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

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

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

julia_version = "1.7.1"
manifest_format = "2.0"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


### Hastings & Powell 1991
## Reproducing teacup figure (figure 2D)

#### FIGURES 2D
#### b1 = 3.0

u0 = [0.76, 0.16, 9.9]  #initial conditions for x,y,z
tspan = (0.0, 10000.0) #timespan
p_b3 = [5.0, 0.1, 3.0, 2.0, 0.4, 0.01] # parameter values (a1, a2, b1, b2, c1, c2)

# Solving the system of differential equations
prob_b3 = ODEProblem(parameterized_model!, u0, tspan, p_b3)
sol_b3 = solve(prob_b3, alg = RK4(), reltol = 1e-14) # RK4 algorithm

sol_x_b3 = sol_b3[1, :] # timeseries for x
sol_y_b3 = sol_b3[2, :] # timeseries for y
sol_z_b3 = sol_b3[3, :] # timeseries for z

# Teacup Figures 2D and 5E (Three-dimensional phase plot)
fig2d = plot(sol_x_b3, sol_y_b3, sol_z_b3, # sol_b3, vars = (1,2,3),
             linestyle = :dot,
             xlabel = "x", xflip = false, xlim = (0.0, 1.0), xticks = 0.0:0.5:1.0,
             ylabel = "y", yflip = true, ylim = (0.0, 0.5), yticks = 0.0:0.25:0.5,
             zlabel = "z", zflip = false, zlim = (7.5, 10.5), zticks = 7.5:1.5:10.5,
             tick_direction = :out, guidefontsize = 10, tickfontsize = 8,
             legend = :none, size = (600, 600), c = :black,
             right_margin = 5Plots.mm, left_margin = 2Plots.mm,
             )
# Seems like there's a bug with the axes labels when flipping y
# Only solution we could find was to substract y values from 0.5, then plot and replace labels
sol_y_b3_flip = copy(sol_y_b3)
sol_y_b3_flip = 0.5 .- sol_y_b3_flip
fig2d_flip = plot(sol_x_b3, sol_y_b3_flip, sol_z_b3, #sol_b3,vars=(1,2,3),
             linestyle = :dot,
             xlabel = "x", xflip = false, xlim = (0.0, 1.0), xticks = 0.0:0.5:1.0, xrotation = 30.0,
             ylabel = "y", yflip = false, ylim = (0.0, 0.5), yticks = (0.0:0.25:0.5, string.(0.5:-0.25:0.0)), yrotation=-10.0,
             zlabel = "z", zflip = false, zlim = (7.5, 10.5), zticks = 7.5:1.5:10.5, zrotation=0.0,
             tick_direction=:out, guidefontsize = 10, tickfontsize = 8,
             legend =:none, size = (600,600), c=:black,
             right_margin = 5Plots.mm, left_margin = 2Plots.mm,
             )
# Otherwise, it's also possible to use the pyplot backend (additionnal dependency)
#=
pyplot()
fig2d_pyplot = plot(sol_x_b3, sol_y_b3, sol_z_b3, #sol_b3,vars=(1,2,3),
             linewidth = 0.1,
             xlabel = "x", xflip = false, xlim = (0.0, 1.0), xticks = 0.0:0.5:1.0,
             ylabel = "y", yflip = true, ylim = (0.0, 0.5), yticks = 0.0:0.25:0.5,
             zlabel = "z", zflip = false, zlim = (7.5,10.5), zticks = 7.5:1.5:10.5,
             tick_direction = :out, guidefontsize = 12, tickfontsize = 12,
             legend = :none, size = (600,600), c = :black)
gr()
=#

# Export figures
# savefig(fig2d, joinpath("..", "article", "figures", "fig2d_misplaced"))
savefig(fig2d_flip, joinpath("..", "article", "figures", "fig2d.pdf"))
# savefig(fig2d_pyplot, joinpath("..", "article", "figures", "fig2d_pyplot"))


"""
    user-defined matrix generators
    to be populated with `include_generator` in user source code
"""
const USERMATRIXDICT = Dict{String,Function}()

"""
Associate names with matrix-generating functions
"""
const MATRIXDICT = Dict("hilb" => hilb, "hadamard" => hadamard,
                  "cauchy" => cauchy, "circul" => circul,
                  "dingdong" => dingdong, "frank" => frank,
                  "invhilb" => invhilb, "forsythe" => forsythe,
                  "magic" => magic, "grcar" => grcar,
                  "triw" => triw, "moler" => moler,
                  "pascal" => pascal, "kahan" => kahan,
                  "pei" => pei, "vand" => vand,
                  "invol" => invol, "chebspec" => chebspec,
                  "lotkin" => lotkin, "clement" => clement,
                  "fiedler" => fiedler, "minij" => minij,
                  "binomial" => binomialm, "tridiag" => tridiag,
                  "lehmer" => lehmer, "parter" => parter,
                  "chow" => chow, "randcorr" => randcorr,
                  "poisson" => poisson, "neumann" => neumann,
                  "rosser" => rosser, "sampling" => sampling,
                  "wilkinson" => wilkinson, "rando" => rando,
                  "randsvd" => randsvd, "rohess" => rohess,
                  "kms" => kms, "wathen" => wathen,
                  "oscillate" => oscillate, "toeplitz" => toeplitz,
                  "hankel" => hankel, "golub" => golub,
                  "companion" => companion,
                  "prolate" => prolate, "deriv2" => deriv2,
                  "shaw" => shaw, "wing" => wing,
                  "foxgood" => foxgood, "heat" => heat,
                  "baart" => baart, "phillips" => phillips,
                  "gravity" => gravity, "blur" => blur,
                  "spikes" => spikes, "ursell" => ursell,
                  "parallax" => parallax, "erdrey" => erdrey,
                  "gilbert" => gilbert, "smallworld" => smallworld
 )

"""
    predefined matrix classes (for the generated functions)
"""
const MATRIXCLASS = Dict(
            :symmetric => ["hilb", "cauchy", "circul", "dingdong",
                             "invhilb", "moler", "pascal", "pei",
                             "clement", "fiedler", "minij", "tridiag",
                             "lehmer", "randcorr", "poisson", "wilkinson",
                             "kms", "wathen", "oscillate", "prolate",
                             "hankel"],

            :inverse => ["hilb", "hadamard", "cauchy", "invhilb",
                           "forsythe", "magic", "triw", "moler", "pascal",
                           "kahan", "pei", "vand", "invol", "lotkin",
                           "clement", "fiedler", "minij", "tridiag",
                           "lehmer", "poisson", "kms" ],

            :illcond => ["hilb", "cauchy", "frank", "invhilb",
                            "forsythe", "triw", "moler", "pascal",
                            "kahan","pei", "vand", "invol", "lotkin",
                            "tridiag", "rosser", "randsvd", "kms",
                            "oscillate", "prolate", "golub"],

            :posdef => ["hilb", "cauchy", "circul", "invhilb",
                           "moler", "pascal", "pei", "minij", "tridiag",
                           "lehmer", "poisson", "kms", "wathen", "oscillate"],

            :eigen =>   ["hadamard", "circul", "dingdong", "frank",
                           "forsythe", "grcar", "pascal", "invol","chebspec",
                           "lotkin", "clement", "fiedler", "minij",
                           "tridiag", "parter", "chow", "poisson", "neumann",
                           "rosser", "sampling", "wilkinson","wathen",
                           "oscillate"],

             :sparse => ["poisson", "neumann", "wathen", "blur", "erdrey", "gilbert",
                          "smallworld"],

             :random => ["rosser", "rando", "randcorr", "randsvd", "rohess",
                          "wathen", "oscillate", "golub", "erdrey", "gilbert", "smallworld"],

             :regprob => ["deriv2", "shaw", "wing", "foxgood", "heat",
                           "baart", "phillips", "gravity", "blur",
                           "spikes", "ursell", "parallax"],

              :graph => ["erdrey", "gilbert", "smallworld"]
)

# remote parameters for several data sources
const TA_REMOTE = TURemoteType(RemoteParameters(
                    "https://sparse.tamu.edu/MM",
                    "https://sparse.tamu.edu/?per_page=All",
                    """<title>SuiteSparse Matrix Collection</title>""",
                    ("", """">Matrix Market""", 4, ".tar.gz", 2,
                     r"([^<]*)	"),
                    ".tar.gz"
                   ))

const UF_REMOTE = TURemoteType(RemoteParameters(
                    "https://www.cise.ufl.edu/research/sparse/MM",
                    "https://www.cise.ufl.edu/research/sparse/matrices/list_by_id.html",
                    """<title>UF Sparse Matrix Collection - sorted by id</title>""",
                    ("", """>MM""", 4, ".tar.gz", 2, r"([[:digit:]]*)	"),
                    ".tar.gz"
                   ))

const MM_REMOTE = MMRemoteType(RemoteParameters(
                    "ftp://math.nist.gov/pub/MatrixMarket2",
                    "http://math.nist.gov/MatrixMarket/matrices.html",
                    """<TITLE>The Matrix Market Matrices by Name</TITLE>""",
                    ("M", """<A HREF="/MatrixMarket/data/""", 2, ".html", 3, nothing),
                    ".mtx.gz"
                   ))

# preferred remote source for UF matrix collection (TAMU vs. UFl)
uf_remote = TA_REMOTE # may be altered
preferred(::Type{TURemoteType}) = uf_remote
preferred(::Type{MMRemoteType}) = MM_REMOTE
alternate(::Type{TURemoteType}) = uf_remote === TA_REMOTE ? UF_REMOTE : TA_REMOTE
alternate(::Type{MMRemoteType}) = MM_REMOTE
toggle_remote(T=TURemoteType) = begin global uf_remote = alternate(T) end
"""
    The place to store all matrix data in process
"""
const MATRIX_DB = MatrixDatabase()

# local storage directory
DATA_DIR = abspath(dirname(@__FILE__),"..", "data")
MY_DEPOT_DIR = abspath(dirname(@__FILE__), "..", "myMatrixDepot")


#!/usr/bin/env julia

using Test, McCormick
using ForwardDiff: Dual, Partials

# Create functions for comparing MC object to reference object and detail failures
function chk_ref_kernel(y::MC{N,T}, yref::MC{N,T}, mctol::Float64) where {N, T<:RelaxTag}
    pass_flag::Bool = true
    descr = "Failing Components: ("
    ~isapprox(y.cv, yref.cv; atol = mctol) && (descr = descr*" cv = $(y.cv)"; pass_flag = false)
    ~isapprox(y.cc, yref.cc; atol = mctol) && (descr = descr*" cc = $(y.cc) "; pass_flag = false)
    ~isapprox(y.Intv.lo, yref.Intv.lo; atol = mctol) && (descr = descr*" Intv.lo = $(y.Intv.lo) "; pass_flag = false)
    ~isapprox(y.Intv.hi, yref.Intv.hi; atol = mctol) && (descr = descr*" Intv.hi = $(y.Intv.hi) "; pass_flag = false)
    ~isapprox(y.cv_grad[1], yref.cv_grad[1]; atol = mctol) && (descr = descr*" cv_grad[1] = $(y.cv_grad[1]) "; pass_flag = false)
    ~isapprox(y.cv_grad[2], yref.cv_grad[2]; atol = mctol) && (descr = descr*" cv_grad[2] = $(y.cv_grad[2]) "; pass_flag = false)
    ~isapprox(y.cc_grad[1], yref.cc_grad[1]; atol = mctol) && (descr = descr*" cc_grad[1] = $(y.cc_grad[1]) "; pass_flag = false)
    ~isapprox(y.cc_grad[2], yref.cc_grad[2]; atol = mctol) && (descr = descr*" cc_grad[2] = $(y.cc_grad[2]) "; pass_flag = false)
    (descr !== "Failing Components: (") && println(descr*")")
    pass_flag
end
check_vs_ref1(f::Function, x::MC, yref::MC, mctol::Float64) = chk_ref_kernel(f(x), yref, mctol)
check_vs_ref2(f::Function, x::MC, y::MC, yref::MC, mctol::Float64) = chk_ref_kernel(f(x,y), yref, mctol)
check_vs_refv(f::Function, x::MC, c::Float64, yref::MC, mctol::Float64) = chk_ref_kernel(f(x, c), yref, mctol)
check_vs_refv(f::Function, x::MC, c::Int, yref::MC, mctol::Float64) = chk_ref_kernel(f(x, c), yref, mctol)
function check_vs_ref2(f::Function, x::MC, c::Float64, yref1::MC, yref2::MC, mctol::Float64)
    pass_flag = check_vs_ref_kernel(f(x, c), yref1, mctol)
    check_vs_ref_kernel(f(c, x), yref2, mctol) && pass_flag
end

include("forward_mccormick.jl")
include("implicit_mccormick.jl")


function pass_variables(m1, m2, f::MOI.AbstractFunction, map, tol::Number)
    vis = non_zero_variables(f, tol)
    pass_variables(m1, m2, vis, map)
    return
end

function pass_variables(m1, m2, vis, map)
    for vi in vis
        if !haskey(map, vi)
            vname = MOI.get(m1, MOI.VariableName(), vi)
            x = MOI.add_variable(m2)
            MOI.set(m2, MOI.VariableName(), x, vname)
            map[vi] = x
        end
    end
    return
end

is_approx_zero(lhs::MOI.EqualTo, tol = 1e-8) = abs(lhs.value) < tol
is_approx_zero(lhs::MOI.GreaterThan, tol = 1e-8) = abs(lhs.lower) < tol
is_approx_zero(lhs::MOI.LessThan, tol = 1e-8) = abs(lhs.upper) < tol
is_approx_zero(lhs::S, tol = 1e-8) where S<:MOI.AbstractSet = true

set_difference(lhs::S, rhs::S) where S = lhs
set_sum(lhs::S, rhs::S) where S = lhs

set_sum(lhs::MOI.EqualTo, rhs::MOI.EqualTo) = MOI.EqualTo(rhs.value + lhs.value)
set_difference(lhs::MOI.EqualTo, rhs::MOI.EqualTo) = MOI.EqualTo(lhs.value - rhs.value)

set_sum(lhs::MOI.GreaterThan, rhs::MOI.GreaterThan) = MOI.GreaterThan(rhs.lower + lhs.lower)
set_difference(lhs::MOI.GreaterThan, rhs::MOI.GreaterThan) = MOI.GreaterThan(lhs.lower - rhs.lower)

set_sum(lhs::MOI.LessThan, rhs::MOI.LessThan) = MOI.LessThan(rhs.upper + lhs.upper)
set_difference(lhs::MOI.LessThan, rhs::MOI.LessThan) = MOI.LessThan(lhs.upper - rhs.upper)

function non_zero_variables(f::MOI.ScalarAffineFunction, tol)
    vis = Set{VI}()
    to_stay = Int[]
    for i in 1:length(f.terms)
        if abs(MOI.coefficient(f.terms[i])) > tol
            push!(vis, f.terms[i].variable_index)
            push!(to_stay, i)
        end
    end
    f.terms = f.terms[to_stay]
    return vis
end
function non_zero_variables(f::MOI.SingleVariable, tol)
    vis = Set{VI}(f.variable)
    return vis
end

# TODO - Other functions
function unsafe_move_variables(set::Set, f1, f2)
    for i in set
        unsafe_move_variable(i, f1, f2)
    end
end
function unsafe_move_variable(vi, f1::MOI.ScalarAffineFunction, f2::MOI.ScalarAffineFunction) # suppose canonical
    for i in 1:length(f1.terms)
        if MOIU._hasvar(f1.terms[i], vi)
            push!(f2.terms, f1.terms[i])
            deleteat!(f1.terms, i) # suppose canonical
            return true
        end
    end
    return false
end