using Distributed
addprocs(4);

function needles_seq(n::Integer)
  @assert n > 0
  hit = 0
  for i = 1:n
    mp = rand()
    phi = (rand() * pi) - pi / 2   # angle at which needle falls
    xright = mp + cos(phi)/2       # x-location of needle
    xleft = mp - cos(phi)/2
    # Does needle cross either x == 0 or x == 1?
    p = (xright >= 1 || xleft <= 0) ? 1 : 0
    hit += p
  end
  miss = n - hit
  piapprox = n / hit * 2
end
#-> needles_seq (generic function with 1 method)

function needles_par(n)
  hit = @distributed (+) for i = 1:n
    mp = rand()
    phi = (rand() * pi) - pi / 2
    xright = mp + cos(phi)/2
    xleft = mp - cos(phi)/2
    (xright >= 1 || xleft <= 0) ? 1 : 0
  end
  miss = n - hit
  piapprox = n / hit * 2
end
#-> needles_par (generic function with 1 method)

julia> @time needles_seq(100*10^6)
  4.280558 seconds (490.51 k allocations: 25.170 MiB, 0.12% gc time)
3.141853491224458

julia> @time needles_par(25*10^6)
  2.281972 seconds (1.90 M allocations: 96.490 MiB, 1.04% gc time)
3.1420477693063282

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

cd("PacktPub/Chp05");
jabber = "jabberwocky.txt";
proc = open(`./rev.pl $jabber`,"r+");
close(proc.in);

poem = readlines(proc.out);
close(proc.out)

poem

link <- "https://raw.githubusercontent.com/DavZim/Efficient_Frontier/master/data/fin_data.csv"

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

using Distributed
addprocs(4);

function needles_seq(n::Integer)
  @assert n > 0
  k = 0
  for i = 1:n
    rho = rand()
    phi = (rand() * pi) - pi / 2   # angle at which needle falls
    xr = rho + cos(phi)/2          # x-location of needle
    xl = rho - cos(phi)/2
    # Does needle cross either x == 0 or x == 1?
    k += (xr >= 1 || xl <= 0) ? 1 : 0
  end
  m = n - k
  mypi = n / k * 2
end
#-> needles_seq (generic function with 1 method)

function needles_par(n)
  k = @distributed (+) for i = 1:n
    rho = rand()
    phi = (rand() * pi) - pi / 2
    xr = rho + cos(phi)/2
    xl = rho - cos(phi)/2
    (xr >= 1 || xl <= 0) ? 1 : 0
  end
  m = n - k
  mypi = n / k * 2
end

julia> @time needles_seq(4*10^8)
 16.007432 seconds (7 allocations: 208 bytes)
3.1415283291067277

julia> @time needles_par(10^8)
  1.502410 seconds (816 allocations: 57.578 KiB)
3.141524369095122

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

bash-3.2$ cat parallel.jl
# start the following on the command line:
# julia -p n  # starts n processes on the local machine
# julia -p 8  # starts REPL with 8 workers
workers()
# 8-element Array{Int64,1}:
#   2
#   3
#   4
#   5
#   ⋮
#   8
#   9

# iterate over workers:
for pid in workers()
	# do something with pid
end
myid() # 1
addprocs(5)
# 5-element Array{Any,1}:
#  10
#  11
#  12
#  13
#  14
nprocs() # 14
rmprocs(3) #> Task (done) @0x0000000012f8f0f0
# worker with id 3 is removed

# cluster of computers:
# julia --machinefile machines driver.jl
# Run processes specified in driver.jl on hosts listed in machines

# primitive operations with processes:
r1 = remotecall(x -> x^2, 2, 1000) #> Future(2, 1, 15, nothing)
fetch(r1) #> 1000000

remotecall_fetch(sin, 5, 2pi) # -2.4492935982947064e-16

r2 = @spawnat 4 sqrt(2) #> Future(4, 1, 18, nothing)
# lets worker 4 calculate sqrt(2)
fetch(r2)  #> 1.4142135623730951
r = [@spawnat w sqrt(5) for w in workers()]
# or in a freshly started REPL:
# r = [@spawnat i sqrt(5) for i=1:length(workers())]
# 12-element Array{Future,1}:
#  Future(2, 1, 20, nothing)
#  Future(4, 1, 21, nothing)
#  Future(5, 1, 22, nothing)
#  Future(6, 1, 23, nothing)
#  Future(7, 1, 24, nothing)
#  Future(8, 1, 25, nothing)
#  Future(9, 1, 26, nothing)
#  Future(10, 1, 27, nothing)
#  Future(11, 1, 28, nothing)
#  Future(12, 1, 29, nothing)
#  Future(13, 1, 30, nothing)
#  Future(14, 1, 31, nothing)
r3 = @spawn sqrt(5) #> Future(2, 1, 32, nothing)
fetch(r3) #> 2.23606797749979

# using @everywhere to make functions available to all workers:
@everywhere w = 8
@everywhere println(myid()) # 1
# 1
#       From worker 14:   14
#       From worker 8:    8
#       From worker 10:   10
#       From worker 7:    7
#       From worker 2:    2
#       From worker 4:    4
#       From worker 12:   12
#       From worker 9:    9
#       From worker 11:   11
#       From worker 6:    6
#       From worker 13:   13
#       From worker 5:    5

x = 5 #> 5
@everywhere println(x) #> 5
#   # exception on worker 2: ERROR: UndefVarError: x not defined ...
#        ...and 11 more exception(s)

@everywhere include("defs.jl")
@everywhere function fib(n)
	if (n < 2) then
	return n
	else return fib(n-1) + fib(n-2)
	end
end
include("functions.jl")

# broadcast data to all workers:
d = "Julia"
for pid in workers()
   remotecall(x -> (global d; d = x; nothing), pid, d)

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

julia> using Distributed

julia> addprocs(4)
4-element Array{Int64,1}:
 2
 3
 4
 5

julia> for pid in workers()
    @show pid
end
pid = 2
pid = 3
pid = 4
pid = 5

julia> r1 = remotecall(x -> x^2, 2, π)
Future(2, 1, 6, nothing)

julia> wp = WorkerPool([3,4,5])
WorkerPool(Channel{Int64}(sz_max:9223372036854775807,sz_curr:3), Set([4, 3, 5]), RemoteChannel{Channel{Any}}(1, 1, 7))

julia> fetch(r1)
9.869604401089358

julia> remotecall_fetch(sin, 5, π/4)
0.7071067811865475

julia> r2 = @spawnat 4 sqrt(2)
Future(4, 1, 12, nothing)

julia> fetch(r2)
1.4142135623730951

j
julia> @everywhere fac(n::Integer) = (n < 2) ? 1 : n*fac(n-1)

julia> r = [@spawnat w fac(3 + 2*w) for w in workers()]
4-element Array{Future,1}:
 Future(2, 1, 38, nothing)
 Future(3, 1, 39, nothing)
 Future(4, 1, 40, nothing)
 Future(5, 1, 41, nothing)

julia> for id in r
	@show id, fetch(id)
end
(id, fetch(id)) = (Future(2, 1, 38, Some(5040)), 5040)
(id, fetch(id)) = (Future(3, 1, 39, Some(362880)), 362880)
(id, fetch(id)) = (Future(4, 1, 40, Some(39916800)), 39916800)
(id, fetch(id)) = (Future(5, 1, 41, Some(6227020800)), 6227020800)

julia> (fac(7),fac(9),fac(11),fac(13)
(5040, 362880, 39916800, 6227020800)

julia> using DistributedArrays
julia> da = drandn(10,10,10,10);
julia> fieldnames(typeof(da))
(:id, :dims, :pids, :indices, :cuts, :localpart, :release)
julia> da.dims
(10, 10, 10, 10)

julia> da.indices
1×1×2×2 Array{NTuple{4,UnitRange{Int64}},4}:
[:, :, 1, 1] =
 (1:10, 1:10, 1:5, 1:5)

[:, :, 2, 1] =
 (1:10, 1:10, 6:10, 1:5)

[:, :, 1, 2] =
 (1:10, 1:10, 1:5, 6:10)

[:, :, 2, 2] =
 (1:10, 1:10, 6:10, 6:10)

@everywhere using DistributedArrays, Statistics

for ip in procs(da)
    rp = @spawnat ip mean(localpart(da))
    @show fetch(rp)
end

let mu = 0.0
  for ip in procs(da)
    rp = @spawnat ip mean(localpart(da))
    mu += fetch(rp)
  end
  @printf "Mean = %.3f ", mu/length(workers())
end

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Map reduce the Juila way

using DistributedArrays

julia> addprocs(3);
julia> d = drandn(300,300,300);

julia> fieldnames(typeof(d))
julia> d.dims
julia> d.indexes
julia> d.indices
1
julia> endof(d.pmap); # => 3

mu = reduce(+, map( fetch, {
		 @spawnat p mean(localpart(d))
			for p in procs(d) })) / endof(d.pmap)
-0.00012504848579078978

sigma = sqrt(reduce(+, map(fetch, {
		@spawnat d var(localpart(d))
			for p in procs(d) })) / endof(d.pmap))

for _ = 1:25, f = [x -> Int128(x^2 + 2x - 1)], opt = [+, *]
  A = rand(1:5, rand(2:30))
  DA = distribute(A)
  mapreduce(f, opt, DA)
  close(DA)
end

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

@everywhere using Distributed, DistributedArrays, SpecialFunctions

julia> aa = [rand() for i = 1:100,j = 1:100];
julia> da = distribute(aa);

julia> (da.dims, da.indices)
((100, 100), Tuple{UnitRange{Int64},UnitRange{Int64}}[(1:50, 1:50) (1:50, 51:100); (51:100, 1:50) (51:100, 51:100)])

julia> @elapsed map(x -> abs(bessely0(x)), aa)
0.03533777

julia> @elapsed map(x -> abs(bessely0(x)), da)
0.347106964

cd(string(ENV["HOME"],"/PacktPub/Chp05"))

try run(`wc $(readdir())`) catch end

macro traprun(c)
  quote
    if typeof($(esc(c))) == Cmd
      try
        run($(esc(c)))
     catch
     end
    end
  end
end

function filter(pat::Regex, dir=".")
  a = Any[]
  for f in readdir(dir)
    occursin(pat,f) && push!(a, f)
  end
  return a
end

julia> @traprun `wc $(filter(r"\.txt$"))`;
 734    4423   24491 hunting-the-snark.txt
 35     168     937 jabberwocky.txt
 769    4591   25428 total


using
  PyPlot,
  JLD2,
  Printf,
  FourierFlows

using FFTW: ifft

import PassiveTracerFlows.TracerAdvDiff

# Numerical parameters and time-stepping parameters
nx  = 128         # 2D resolution = nx^2
stepper = "RK4"   # timestepper
dt  = 0.02        # timestep
nsubs  = 200      # number of time-steps for plotting
nsteps = 4nsubs   # total number of time-steps (must be multiple of nsubs)

# Physical parameters
Lx  = 2π      # domain size
kap = 0.002   # diffusivity

gr = TwoDGrid(nx, Lx)
x, y = gridpoints(gr)

# streamfunction (for plotting) and (u,v) flow field
psiampl = 0.2
m, n = 1, 1
psiin = @. psiampl * cos(m*x) * cos(n*y)
uvel(x, y) = +psiampl * n * cos(m*x) * sin(n*y)
vvel(x, y) = -psiampl * m * sin(m*x) * cos(n*y)

prob = TracerAdvDiff.Problem(; steadyflow=true,
    nx=nx, Lx=Lx, kap=kap, u=uvel, v=vvel, dt=dt, stepper=stepper)

sol, cl, v, p, g = prob.sol, prob.clock, prob.vars, prob.params, prob.grid

# Initial condition c0 = c(x, y, t=0)
amplc0, sigc0 = 0.1, 0.1
c0func(x, y) = amplc0*exp(-(x^2+y^2)/(2sigc0^2))
c0 = @. c0func(x-0.2Lx, y)

TracerAdvDiff.set_c!(prob, c0)

"Plot the concentration field and the (u, v) streamlines."
function plotoutput(prob, fig, axs; drawcolorbar=false)
  cl, v, p, g = prob.clock, prob.vars, prob.params, prob.grid

  t = round(cl.t, digits=2)
  TracerAdvDiff.updatevars!(prob)

  cla()
  pcolormesh(x, y, v.c)

  if drawcolorbar; colorbar(); end

  contour(x, y, psiin, 15, colors="k", linewidths=0.7)
  axis("equal")
  axis("square")
  title("shading: \$c(x, y, t= $t )\$, contours: \$\\psi(x, y)\$")

  pause(0.001)

  nothing
end

fig, axs = subplots(ncols=1, nrows=1, figsize=(8, 8))
plotoutput(prob, fig, axs; drawcolorbar=true)

while cl.step < nsteps
  stepforward!(prob, nsubs)
  plotoutput(prob, fig, axs)
end


# Mask operator functions ##################################

struct opMaskFactored{T} <: AbstractLinearTransform{T} end
"""
    op = opMaskFactored(M::SparseMatrixCSC)

Create a masking linear operator that applies to factored matrices.

- forward mode: `op*(U,V)` returns a vector of the elements of the matrix `U*V'` indexed by the mask;

- adjoint mode: `op'*y` returns a sparse matrix with the elements of `y` scattered into the mask pattern.
"""
function opMaskFactored{T}(M::SparseMatrixCSC) where {T}

    # forward operation is a gather.
    function forward(nnzM, I, J, U, V)
        z = zeros(nnzM)
        for (u,v) in zip(eachcol(U), eachcol(V))
            z += [ u[i]*v[j] for (i,j) in zip(I, J) ]
        end
        return z
    end

    # Adjoint operation is scatter.
    adjoint(I, J, w) = sparse(I, J, w)

    dimsDomain = size(M)
    dimsRange = nnz(M)
    I, J = findnz(M)[1:2]
    prod = uv -> forward(nnz(M), I, J, uv[1], uv[2])
    tprod = w -> adjoint(I, J, w)
    LinearTransform{T}(dimsRange, dimsDomain, prod, tprod)
end
opMaskFactored(M::SparseMatrixCSC) = opMaskFactored{Float64}(M::SparseMatrixCSC)

struct opMask{T} <: AbstractLinearTransform{T} end
"""
    op = opMask(M::SparseMatrixCSC)

Create a masking linear operator.

- forward mode: `op*(X)` returns a vector of the elements of the matrix `X` indexed by the mask;

- adjoint mode: `op'*y` returns a sparse matrix with the elements of `y` scattered into the mask pattern.
"""
function opMask{T}(M::SparseMatrixCSC) where {T}
    dimsDomain = size(M)
    dimsRange = nnz(M)
    I, J = findnz(M)[1:2]
    prod = X -> [X[i,j] for (i,j) in zip(I,J)]
    tprod = w -> sparse(I, J, w, dimsDomain...)
    LinearTransform{T}(dimsRange, dimsDomain, prod, tprod)
end
opMask(M::SparseMatrixCSC) = opMask{Float64}(M)


@testset "Test SparseMatrixCOO" begin
    i = Int[1, 4, 2, 1]
    j = Int[1, 4, 2, 3]
    v = Float64[4, 5, 7, 8]
    coo = ms.SparseMatrixCOO(4, 4, i, j, v)
    coo_py = ms.to_python(coo)

    @test ms.to_sparse_csc(coo) == Float64[4 0 8 0;
                                           0 7 0 0;
                                           0 0 0 0;
                                           0 0 0 5]
    @test ms.to_full(coo) == Float64[4 0 8 0;
                                     0 7 0 0;
                                     0 0 0 0;
                                     0 0 0 5]
    @test coo_py["dot"]([1, 2, 3, 4]) == Float64[28, 14, 0, 20]
    @test coo_py["toarray"]() == Float64[4 0 8 0;
                                         0 7 0 0;
                                         0 0 0 0;
                                         0 0 0 5]
end

@testset "Test LinearOperator" begin
    i = Int[1, 4, 2, 1]
    j = Int[1, 4, 2, 3]
    v = Float64[4, 5, 7, 8]
    A = sparse(i, j, v, 4, 4)
    matvec(x) = A*x
    A_op = ms.LinearOperator(4, 4, matvec)
    A_py = ms.to_python(A_op)

    @test dot(A_op, [1, 2, 3, 4]) == Float64[28, 14, 0, 20]
    @test A_py["dot"]([1, 2, 3, 4]) == Float64[28, 14, 0, 20]
end


using LinearAlgebra, GeometricMultigrid, BenchmarkTools, Plots

function setup_2D(n=128,T::Type=Float64)
    L = zeros(T,n+2,n+2,2); L[3:n+1,2:n+1,1] .= 1; L[2:n+1,3:n+1,2] .= 1;
    x = T[i-1 for i ∈ 1:n+2, j ∈ 1:n+2]
    Poisson(L),FieldVector(x)
end

begin
    suite = BenchmarkGroup()
    nlist = 2 .^ (3:10)
    for n ∈ nlist
        A,x = setup_2D(n,Float32)
        suite["mg-gs",n] = @benchmarkable mg!(st) setup=(st=mg_state($A,zero($x),$A*$x))
#         suite["pseudo",n] = @benchmarkable mg!(st) setup=(st=mg_state($A,zero($x),$A*$x,pseudo=true))
    end
end

results = run(suite)

begin
    nlogn(n) = n*log(n)
    N = nlist.^2
    time = [minimum(results["mg-gs",n]).time for n ∈ nlist]
    ptime = [minimum(results["pseudo",n]).time for n ∈ nlist]
    plot(N,time[end]/N[end] .* N, color=:grey, label="N", legend=:bottomright)
    plot!(N,time[end]/nlogn(N[end]) .* nlogn.(N) , color=:black, label="NlogN")
    scatter!(N,time, xaxis=("length x",:log10), yaxis=("time (ns)",:log10), label="mg!")
    # scatter!(N,ptime, xaxis=("length x",:log10), yaxis=("time (ns)",:log10), label="pseudo=true")
end

savefig("MGscaling.png")

begin
    A,x = setup_2D()
    b = zero(x)
    st = SolveState(A,zero(x),A*x)
#     st.P = PseudoInv(A)
end
@btime norm($x)  # 5.3 μs
@btime dot($b,$x) # 7.8 μs
@btime dot($b,$A,$x) # 29.5 μs
@btime mul!($b,$A,$x) # 30.6 μs
@btime GeometricMultigrid.increment!($st)  # 45.4 μs
@btime GeometricMultigrid.GS!($st;inner=1) # 183 μs
@btime GeometricMultigrid.GS!($st;inner=2) # 306 μs
# @btime GeometricMultigrid.pseudo!($st)     # 150 μs


# roseplot

#JL Plots
using Random, Plots
Random.seed!(2018)

n = 24
R = rand(n+1)
θ = 0:2pi/n:2pi
Plots.plot(θ, R, proj=:polar, line=:steppre, lims=(0,1), c=:steelblue, linewidth=2)


x = range(-2, stop=2, length=20)
y1 = @. sin(exp(-x)) + 0.5
y2 = @. sin(exp(-x)) - 0.5
plot(x, y1; label="unsmoothed")
plot!(x, y2; smooth=true, label="smoothed")
legend()


function CRC.rrule(::typeof(logpdf), d::Exponential, x)
    v = logpdf(d, x)
    function pullback(y)
        g = @thunk(gradlogpdf(d, x))
        dθ = @thunk(
            if x < 0
                zero(x)
            else
                -inv(d.θ) + x * inv(d.θ^2)
            end
        )
        return (NO_FIELDS, g, dθ)
    end
    return (v, pullback)
end

function CRC.rrule(::typeof(logpdf), d::Normal, x)
    v = logpdf(d, x)
    function pullback(y)
        μ = mean(d)
        σ = std(d)
        g = @thunk(gradlogpdf(d, x))
        dμ = @thunk((x - μ) / σ^2)
        dσ = @thunk(-inv(σ) + abs2(x - μ) * σ^(-3))
        return (NO_FIELDS, g, dμ, dσ)
    end
    return (v, pullback)
end

function CRC.rrule(::typeof(logpdf), d::Arcsine, x)
    v = logpdf(d, x)
    function pullback(y)
        T = promote_type(typeof(x), partype(d))
        (a, b) = support(d)
        g = @thunk(gradlogpdf(d, x))
        da = if x > b || x < a
                zero(T)
            else
                inv(2 * (x - a))
            end

        db = if x > b || x < a
                zero(T)
            else
                -inv(2 * (b - x))
            end
        return (NO_FIELDS, g, da, db)
    end
    return (v, pullback)
end

function CRC.rrule(::typeof(logpdf), d::Beta, x)
    v = logpdf(d, x)
    function pullback(y)
        T = promote_type(typeof(x), partype(d))
        (α, β) = params(d)
        g = @thunk(gradlogpdf(d, x))
        dα = if !(0 ≤ x ≤ 1)
                zero(T)
            else
                log(x) - digamma(α) + digamma(α + β)
            end
        dβ = if !(0 ≤ x ≤ 1)
                zero(T)
            else
                log(1 - x) - digamma(β) + digamma(α + β)
            end
        return (NO_FIELDS, g, dα, dβ)
    end
    return (v, pullback)
end


using LazyBandedMatrices, FillArrays, BandedMatrices, BlockBandedMatrices, BlockArrays, ArrayLayouts, LazyArrays, Test
import BlockBandedMatrices: isbandedblockbanded, BandedBlockBandedStyle, BandedLayout
import LazyBandedMatrices: KronTravBandedBlockBandedLayout, BroadcastBandedLayout, arguments, FillLayout, OnesLayout, call
import BandedMatrices: BandedColumns

@testset "Banded kron" begin
    A = brand(5,5,2,2)
    B = brand(2,2,1,0)
    K = kron(A,B)
    @test K isa BandedMatrix
    @test bandwidths(K) == (5,4)
    @test Matrix(K) == kron(Matrix(A), Matrix(B))

    A = brand(3,4,1,1)
    B = brand(3,2,1,0)
    K = kron(A,B)
    @test K isa BandedMatrix
    @test bandwidths(K) == (7,2)
    @test Matrix(K) ≈ kron(Matrix(A), Matrix(B))
    K = kron(B,A)
    @test Matrix(K) ≈ kron(Matrix(B), Matrix(A))

    K = kron(A, B')
    K isa BandedMatrix
    @test Matrix(K) ≈ kron(Matrix(A), Matrix(B'))
    K = kron(A', B)
    K isa BandedMatrix
    @test Matrix(K) ≈ kron(Matrix(A'), Matrix(B))
    K = kron(A', B')
    K isa BandedMatrix
    @test Matrix(K) ≈ kron(Matrix(A'), Matrix(B'))

    A = brand(5,6,2,2)
    B = brand(3,2,1,0)
    K = kron(A,B)
    @test K isa BandedMatrix
    @test bandwidths(K) == (12,4)
    @test Matrix(K) ≈ kron(Matrix(A), Matrix(B))

    n = 10; h = 1/n
    D² = BandedMatrix(0 => Fill(-2,n), 1 => Fill(1,n-1), -1 => Fill(1,n-1))
    D_xx = kron(D², Eye(n))
    @test D_xx isa BandedMatrix
    @test bandwidths(D_xx) == (10,10)
    D_yy = kron(Eye(n), D²)
    @test D_yy isa BandedMatrix
    @test bandwidths(D_yy) == (1,1)
    Δ = D_xx + D_yy
    @test Δ isa BandedMatrix
    @test bandwidths(Δ) == (10,10)

    @testset "#87" begin
        @test kron(Diagonal([1,2,3]), Eye(3)) isa Diagonal{Float64,Vector{Float64}}
    end
end

@testset "DiagTrav" begin
    A = [1 2 3; 4 5 6; 7 8 9]
    @test DiagTrav(A) == [1, 4, 2, 7, 5, 3]
    A = [1 2 3; 4 5 6]
    @test DiagTrav(A) == [1, 4, 2, 5, 3]
    A = [1 2; 3 4; 5 6]
    @test DiagTrav(A) == [1, 3, 2, 5, 4]

    @test resize!(DiagTrav(A), Block(2)) == [1, 3,2]

    A = DiagTrav(randn(3,3,3))
    @test A[Block(1)] == A[1:1,1,1]
    @test A[Block(2)] == [A.array[2,1,1], A.array[1,2,1], A.array[1,1,2]]
    @test A[Block(3)] == [A.array[3,1,1], A.array[2,2,1], A.array[1,3,1],
                          A.array[2,1,2], A.array[1,2,2], A.array[1,1,3]]
    @test A == [A[Block(1)]; A[Block(2)]; A[Block(3)]]
end

@testset "BlockKron" begin
    n = 4
    Δ = BandedMatrix(1 => Ones(n-1), 0 => Fill(-2,n), -1 => Ones(n-1))
    A = BlockKron(Δ, Eye(n))
    @test isblockbanded(A)
    @test isbandedblockbanded(A)
    @test blockbandwidths(A) == (1,1)
    @test BandedBlockBandedMatrix(A) == A
end

@testset "KronTrav" begin
    @testset "vector" begin
        a = [1,2,3]
        b = [4,5,6]
        c = [7,8]
        @test KronTrav(a,b) == DiagTrav(b*a')
        @test KronTrav(a,c) == DiagTrav(c*a')
        @test KronTrav(c,a) == DiagTrav(a*c')
    end

    @testset "matrix" begin
        A = [1 2; 3 4]
        B = [5 6; 7 8]
        K = KronTrav(A,B)

        X = [9 10; 11 0]
        @test K*DiagTrav(X) == DiagTrav(B*X*A')

    end

    @testset "banded" begin
        n = 4
        Δ = BandedMatrix(1 => Ones(n-1), 0 => Fill(-2,n), -1 => Ones(n-1))
        A = KronTrav(Δ, Eye(n))
        B = KronTrav(Eye(n), Δ)

        X = triu!(randn(n,n))[:,end:-1:1]
        @test A * DiagTrav(X) == DiagTrav(X * Δ')
        @test B * DiagTrav(X) == DiagTrav(Δ * X)

        @test blockbandwidths(A) == blockbandwidths(B) == (1,1)
        @test subblockbandwidths(A) == (1,1)
        @test subblockbandwidths(B) == (0,0)
        @test isblockbanded(A)
        @test isbandedblockbanded(A)
        @test BandedBlockBandedMatrix(A) == A
        @test MemoryLayout(A) isa KronTravBandedBlockBandedLayout

        @test Base.BroadcastStyle(typeof(A)) isa BandedBlockBandedStyle
        @test A+B isa BandedBlockBandedMatrix
        @test A+B == Matrix(A) + Matrix(B)
    end

    @testset "Views" begin
        n = 4
        Δ = BandedMatrix(1 => Ones(n-1), 0 => Fill(-2,n), -1 => Ones(n-1))
        A = KronTrav(Δ, Eye(n))

        V = view(A, Block(2,2))
        @test MemoryLayout(V) isa BroadcastBandedLayout{typeof(*)}
        @test call(V) == *
        @test MemoryLayout.(arguments(V)) isa Tuple{BandedColumns{DenseColumnMajor},BandedColumns{OnesLayout}}
        @test BandedMatrix(V) == V == A[Block(2,2)]

        V = view(A, Block.(2:4), Block.(1:4))
        @test blockbandwidths(V) == (0,2)
        @test subblockbandwidths(V) == (1,1)
        @test BandedBlockBandedMatrix(V) == A[Block.(2:4), Block.(1:4)]
        @test A[Block.(2:4), Block.(1:4)] isa BandedBlockBandedMatrix
    end
end


include("sawtooth.jl")
include("clvs.jl")
include("lss.jl")
using Test
function test_dsawtooth()
	s = rand()
	m = 10
	u_trj = rand(m)
	eps = 1.e-4
	du_fd = (sawtooth(u_trj .+ eps,
						s, 1)[2,:] -
				sawtooth(u_trj .- eps,
						s, 1)[2,:])./(2*eps)
	du = dsawtooth(u_trj, s)
	@assert all(isapprox.(du_fd, du)) == 1
end
function test_les()
	s = 0.01
	m = 1
	n = 25000
	u0 = rand(m)
	u_trj = sawtooth(u0, s, n)[:,1]
	n = n+1
	du_trj = reshape(dsawtooth(u_trj, s),1,1,n)
	les, clv_trj = clvs(du_trj,1)
	println(les)
	@assert all(isapprox.(les, log(2),
						  rtol=1.e-1)) == 1
end
function test_lss()
	s = 0.01
    m = 1
    n = 5000
    u0 = rand(m)
	d = 1
    d_u = 1
	dJ = ones(d,n+1)
	n_samples = 10
	dJds = zeros(n_samples)
	vsh = zeros(d,n+1)

	for i=1:n_samples
		println("Starting LSS, sample ", i)
		u_trj = sawtooth(u0, s, n)[:,1]
		du_trj = reshape(dsawtooth(u_trj, s),d,d,n+1)
		X = reshape(perturbation(u_trj,s),d,n+1)
		f = zeros(1,n+1)
		J = u_trj
		u_trj = reshape(u_trj, n+1, d)
		y, dJds[i] = lss(u_trj,
						du_trj, X, f, J, dJ,
						  s, d_u)
		println(dJds[i])
		vsh .= y
		u0 .= u_trj[end,:]
	end
	println("Sensitivities are : ", dJds)
	@test isapprox((sum(dJds)/n_samples),-0.61,rtol=0.1)
	return vsh, dJds
end


function moi_sdplib(optimizer, path; verbose = false, test = false, scalar = false)

    if verbose
        println("running: $(path)")
    end
    MOI.empty!(optimizer)
    if test
        @test MOI.is_empty(optimizer)
    end

    n, m, F, c = sdplib_data(path)

    nvars = sympackedlen(n)

    X = MOI.add_variables(optimizer, nvars)
    vov = MOI.VectorOfVariables(X)
    cX = MOI.add_constraint(optimizer, vov, MOI.PositiveSemidefiniteConeTriangle(n))

    Xsq = Matrix{MOI.VariableIndex}(undef, n,n)
    ivech!(Xsq, X)
    Xsq = Matrix(Symmetric(Xsq,:U))

    # Objective function
    objf_t = [MOI.ScalarAffineTerm(F[0][idx...], Xsq[idx...])
        for idx in zip(findnz(F[0])[1:end-1]...)]
    MOI.set(optimizer, MOI.ObjectiveFunction{MOI.ScalarAffineFunction{Float64}}(), MOI.ScalarAffineFunction(objf_t, 0.0))
    MOI.set(optimizer, MOI.ObjectiveSense(), MOI.MIN_SENSE)

    # Linear equality constraints
    for k in 1:m
        ctr_k = [MOI.ScalarAffineTerm(F[k][idx...], Xsq[idx...])
            for idx in zip(findnz(F[k])[1:end-1]...)]
        if scalar
            MOI.add_constraint(optimizer, MOI.ScalarAffineFunction(ctr_k, 0.0), MOI.EqualTo(c[k]))
        else
            MOI.add_constraint(optimizer,
                MOI.VectorAffineFunction(MOI.VectorAffineTerm.([1], ctr_k), [-c[k]]), MOI.Zeros(1))
        end
    end

    MOI.optimize!(optimizer)

    objval = MOI.get(optimizer, MOI.ObjectiveValue())

    stime = -1.0
    try
        stime = MOI.get(optimizer, MOI.SolveTime())
    catch
        println("could not query time")
    end

    Xsq_s = MOI.get.(optimizer, MOI.VariablePrimal(), Xsq)
    minus_rank = length([eig for eig in eigen(Xsq_s).values if eig < -1e-4])
    if test
        @test minus_rank == 0
    end
    # @test tr(F[0] * Xsq_s) - obj < 1e-1
    # for i in 1:m
    #     @test abs(tr(F[i] * Xsq_s)-c[i]) < 1e-1
    # end

    verbose && sdplib_eval(F,c,n,m,Xsq_s)

    rank = -1
    status = 0
    if MOI.get(optimizer, MOI.TerminationStatus()) == MOI.OPTIMAL
        status = 1
    end
    return (objval, stime, rank, status)
end


function max_error(g_true, g_approx)
    n = length(g_true)
    @assert length(g_approx) == n
    err = 0.0
    for i in 1:n
        abs_err = g_true[i] - g_approx[i]
        err = max(err, abs(abs_err))
    end
    return err
end


"""
    Bridges{T}

A state type for the depth-first search that finds bridges in a graph.
"""
mutable struct Bridges{T<:Integer}
    low::Vector{T}
    depth::Vector{T}
    bridges::Vector{Edge{T}}
    id::T
end

function Bridges(g::AbstractGraph)
    n = nv(g)
    T = eltype(g)
    return Bridges(zeros(T, n), zeros(T, n), Edge{T}[], zero(T))
end

"""
    visit!(state, g, u, v)

Perform a depth first search storing the depth (in `depth`) and low-points
(in `low`) of each vertex.
"""
function visit!(state::Bridges, g::AbstractGraph, u::Integer, v::Integer)
    state.id += 1
    state.depth[v] = state.id
    state.low[v] = state.depth[v]

    @inbounds for w in outneighbors(g, v)
        if state.depth[w] == 0
            visit!(state, g, v, w)

            state.low[v] = min(state.low[v], state.low[w])
            if state.low[w] > state.depth[v]
                edge = v < w ? Edge(v, w) : Edge(w, v)
                push!(state.bridges, edge)
            end

        elseif w != u
            state.low[v] = min(state.low[v], state.depth[w])
        end
    end
end

"""
    bridges(g)

Compute the [bridges](https://en.m.wikipedia.org/wiki/Bridge_(graph_theory))
of a connected graph `g` and return an array containing all bridges, i.e edges
whose deletion increases the number of connected components of the graph.
# Examples
```jldoctest
julia> using LightGraphs

julia> bridges(StarGraph(5))
8-element Array{LightGraphs.SimpleGraphs.SimpleEdge{Int64},1}:
 Edge 1 => 2
 Edge 1 => 3
 Edge 1 => 4
 Edge 1 => 5

julia> bridges(PathGraph(5))
8-element Array{LightGraphs.SimpleGraphs.SimpleEdge{Int64},1}:
 Edge 4 => 5
 Edge 3 => 4
 Edge 2 => 3
 Edge 1 => 2
```
"""
function bridges end

@traitfn function bridges(g::AG::(!IsDirected)) where {T<:Integer, AG<:AbstractGraph{T}}
    state = Bridges(g)
    for u in vertices(g)
        if state.depth[u] == 0
            visit!(state, g, u, u)
        end
    end
    return state.bridges
end


function fit(x; axis = 1)　#this function dose only performs calculations.
    if axis == 2
        x = x'
    end
    if ndims(x) == 1
        p = [maximum(x), minimum(x)]
    else
        p = []
        for i in 1:size(x)[2]
            push!(p, [maximum(x[:, i]), minimum(x[:, i])])
        end
    end
    return p
end
function transform(x, p; axis = 1)　#Only transform is performed based on the calculation results of the'fit'function and'fit_transform'function.
    if axis == 2
        x = x'
    end
    if ndims(x) == 1
        t = (x .- p[2]) / (p[1] - p[2])
    else
        t = []
        for i in 1:size(x)[2]
            push!(t, (x[:, i] .- p[i][2]) / (p[i][1] - p[i][2]))
        end
    end
    return t
end
function inverse_transform(x, p; axis = 1)
    if axis == 2
        x = x'
    end
    if ndims(x) == 1
        t = (x * (p[1] - p[2])) .+ p[2]
    else
        t = []
        for i in 1:size(x)[2]
            push!(t, (x[:, i][1] * (p[i][1] - p[i][2])) .+ p[i][2])
        end
    end
    return t
end
function fit_transform(x; axis = 1)　#This function handles both the fit function and the transform function.
    if axis == 2
        x = x'
    end
    if ndims(x) == 1
        p = [maximum(x), minimum(x)]
        t = (x .- p[2]) / (p[1] - p[2])
    else
        p, t = [], []
        for i in 1:size(x)[2]
            push!(p, [maximum(x[:, i]), minimum(x[:, i])])
            push!(t, (x[:, i] .- p[i][2]) / (p[i][1] - p[i][2]))
        end
    end
    return t, p
end


### A Pluto.jl notebook ###
# v0.16.0

using Markdown
using InteractiveUtils

# ╔═╡ 6b29d3f0-fc09-11ea-15c9-313cd7403a39
using JuMP

# ╔═╡ 6df41780-fc09-11ea-2de3-d3dfe50b7484
using GLPK

# ╔═╡ fcb22520-fc09-11ea-2266-a3e9fc398b1b
using Plots

# ╔═╡ 0b001a12-fc0a-11ea-30e6-df8c0d22e8cd
using LaTeXStrings

# ╔═╡ 5f7ce0ee-fc0f-11ea-29cc-35c53dd304a1
using Tulip

# ╔═╡ 5fd1dfc0-fc04-11ea-1747-69f05b302ab0
md"# Linear Programming: Simplex Method"

# ╔═╡ dec71840-fc04-11ea-33f5-c353bc11b181
md"""## Karush-Kuhn-Tucker Conditions

We consider the linear program

```math
\begin{aligned}
\min &\vec{c}^\mathsf{T}\vec x\\
\textrm{ subject to } &\begin{cases}
\mathbf{A}\vec x=\vec b\\
\vec x\ge\vec 0
\end{cases}
\end{aligned}
```

and define the Lagrangian function

```math
\mathcal L\left(\vec x,\vec \lambda,\vec s\right) = \vec{c}^\mathsf{T}\vec x - \vec \lambda^\mathsf{T}\left(\mathbf A\vec x-\vec b\right) - \vec s^\mathsf{T}\vec x
```

where $\vec \lambda$ are the multipliers for the equality constraints and $\vec s$ are the multipliers for the bound constraints.

The Karush-Kuhn-Tucker condition states that to find the first-order necessary conditions for $\vec x^\star$ to be a solution of the problem, their exist $\vec \lambda^\star$ and $\vec s^\star$ such that

```math
\begin{aligned}
\mathbf A^\mathsf{T}\vec \lambda^\star+\vec s^\star&=\vec c\\
\mathbf A\vec x^\star&=\vec b\\
\vec x^\star&\ge\vec 0\\
\vec s^\star&\ge \vec 0\\
\left(\vec x^\star\right)^\mathsf{T}\vec s^\star&=0
\end{aligned}
```

The first eqation states that the gradient of the Lagrangian with respect to $\vec x$ must be zero and the last equation that at least $x_i$ or $s_i$ must be zero for each $i=1,2,\dots,n$.

It can be shown that these conditions are also sufficient."""

# ╔═╡ 35e94ee0-fc05-11ea-3183-d153786970b0
md"""## The Simplex Method Explained

As mentioned in the previous lecture, all iterates of the simplex method are basic feasible points and therefore vertices of the feasible polytope. Most steps consists of a move from one vertex to an adjacent one. On most steps (but not all), the value of the objective function $\vec{c}^\mathsf{T}\vec x$ is decreased. Another type of step occurs when the problem is unbounded: the step is an edge along which the objective funtion is reduced, and along which we can move infinitely far without reaching a vertex.

The major issue at each simplex iteration is to decide which index to remove from the basic index set $\mathcal B$. Unless the step is a direction of unboundness, a single index must be removed from $\mathcal B$ and replaced by another from outside $\mathcal B$. We can gain some insight into how this decision is made by looking again at the KKT conditions.

First, define the nonbasic index set $\mathcal N = \left\{1,2,\dots,n\right\} \setminus \mathcal B$. Just as $\mathbf B$ is the basic matrix, whose columns are $\mathbf A_i$ for $i\in\mathcal B$, we use $\mathbf N$ to denote the nonbasic matrix $\mathbf N=\left[\mathbf A_i\right]_{i\in\mathcal N}$. We also partition the vectors $\vec x$, $\vec s$ and $\vec c$ according to the index sets $\mathcal B$  and $\mathcal N$, using the notation

```math
\begin{aligned}
\vec x_\mathbf B=\left[\vec x_i \right]_{i\in\mathcal B},&\qquad\vec x_\mathbf N=\left[\vec x_i \right]_{i\in\mathcal N}\\
\vec s_\mathbf B=\left[\vec s_i \right]_{i\in\mathcal B},&\qquad\vec s_\mathbf N=\left[\vec s_i \right]_{i\in\mathcal N}\\
\vec c_\mathbf B=\left[\vec c_i \right]_{i\in\mathcal B},&\qquad\vec c_\mathbf N=\left[\vec c_i \right]_{i\in\mathcal N}
\end{aligned}
```

From the second KKT conditions, we have that

```math
\mathbf A \vec x= \mathbf B \vec x_\mathbf B + \mathbf N \vec x_\mathbf N=\vec b\,.
```

The _primal_ variable $\vec x$ for this simplex iterate is defined as

```math
\vec x_\mathbf B = \mathbf B^{-1}\vec b,\qquad \vec x_\mathbf N=\vec 0\,.
```

Since we are dealing only with basic feasible points, we know that $\mathbf B$ is nonsingular and that $\vec x_\mathbf B\ge\vec0$, so this choice of $\vec x$ satisfies two of the KKT conditions.

We choose $\vec s$ to satisfy the complimentary condition (the last one) by setting $\vec s_\mathbf B=\vec 0$. The remaining components $\vec \lambda$ and $\vec s_\mathbf N$ can be found by partitioning this condition into $\vec c_\mathbf B$ and $\vec c_\mathbf N$ components and using $\vec s_\mathbf B=\vec 0$ to obtain

```math
\mathbf B^\mathsf{T}\vec \lambda=\vec c_\mathbf B,\qquad \vec N^\mathsf{T}\vec\lambda+\vec s_\mathbf N = \vec c_\mathbf N\,.
```

Since $\mathbf B$ is square and nonsingular, the first equation uniquely defines $\vec \lambda$ as

```math
\vec \lambda = \left(\mathbf B^\mathsf{T}\right)^{-1}\vec c_\mathbf B\,.
```

The second equation implies a value for $\vec s_\mathbf N$:

```math
\vec s_\mathbf N = \vec c_\mathbf N - \mathbf N^\mathsf{T}\vec \lambda=\vec c_\mathbf N -\left(\mathbf B ^{-1}\mathbf N\right)^\mathsf{T}\vec c_\mathbf B\,.
```

Computation of the vector $\vec s_\mathbf N$ is often referred to as _pricing_. The components of $\vec s_\mathbf N$ are often called the _reduced costs_ of the nonbasic variables $\vec x_\mathbf N$.

The only KKT condition that we have not enforced explicitly is the nonnegativity condition $\vec s \ge \vec 0$. The basic components $\vec s_\mathbf B$ certainly satisfy this condition, by our choice $\vec s_\mathbf B = 0$. If the vector $\vec s_\mathbf N$ also satisfies $\vec s_\mathbf N \ge \vec 0$, we have found an optimal
vector triple $\left(\vec x^\star, \vec \lambda^\star, \vec s^\star\right)$, so the algorithm can terminate and declare success. Usually, however, one or more of the components of $\vec s_\mathbf N$ are negative. The new index to enter the basis index set $\mathcal B$ is chosen to be one of the indices $q \in \mathcal N$ for which $s_q < 0$. As we show below, the objective $\vec{c}^\mathsf{T}\vec x$ will decrease when we allow $x_q$ to become positive if and only if

1. ``s_q < 0`` and
2. it is possible to increase $x_q$ away from zero while maintaining feasibility of $\vec x$.

Our procedure for altering $\mathcal B$ and changing $\vec x$ and $\vec s$ can be described accordingly as follows:

- allow $x_q$ to increase from zero during the next step;
- fix all other components of $\vec x_\mathbf N$ at zero, and figure out the effect of increasing $x_q$ on the current basic vector $\vec x_\mathbf B$, given that we want to stay feasible with respect to the equality constraints $\mathbf{A}\vec x=\vec b$;
- keep increasing $x_q$ until one of the components of $\vec x_\mathbf B$ ($x_p$, say) is driven to zero, or determining that no such component exists (the unbounded case);
- remove index $p$ (known as the leaving index) from $\mathcal B$ and replace it with the entering index $q$.

This process of selecting entering and leaving indices, and performing the algebraic operations necessary to keep track of the values of the variables $\vec x$, $\vec \lambda$, and $\vec s$, is sometimes known as _pivoting_.

We now formalize the pivoting procedure in algebraic terms. Since both the new iterate $\vec x^+$ and the current iterate $\vec x$ should satisfy $\mathbf A\vec x=\vec b$, and since $\vec x_\mathbf N=\vec 0$ and $\vec x_i^{+}=0$ for $i\in\mathcal N\setminus\left\{q\right\}$ we have

```math
\mathbf A\vec x^+=\mathbf B\vec x_\mathbf B^+ +\vec A_q x_q^+=\vec b=\mathbf B\vec x_\mathbf B=\mathbf A\vec x\,.
```

By multiplying this expression by $\mathbf B^{-1}$ and rearranging, we obtain

```math
\vec x_\mathbf B^+=\vec x_\mathbf B-\mathbf B^{-1}\vec A_q x_q^+
```

Geometrically speaking, we move along an edge of the feasible polytope that decreases $\vec{c}^\mathsf{T}\vec x$. We continue to move along this edge until a new vertex is encountered. At this vertex, a new constraint $x_p \ge 0$ must have become active, that is, one of the components $x_p$, $p \in \mathbf B$, has decreased to zero. We then remove this index $p$ from the basis index set $\mathcal B$ and replace it by $q$.

It is possible that we can increase $x_q^+$ to $\infty$ without ever encountering a new vertex. In other words, the constraint $x_\mathbf B^+=x_\mathbf B-\mathbf B^{-1}\vec A_q\vec x_q^+\ge 0$ holds for all positive values of $x_q+$. When this happens, the linear program is unbounded; the simplex method has identified a
ray that lies entirely within the feasible polytope along which the objective $\vec{c}^\mathsf{T}\vec x$ decreases to $−\infty$.
"""

# ╔═╡ 71ce4140-fc05-11ea-3e86-913a7fbbdbc4
md"""## One Step of Simplex Algorithm

Given $\mathcal B$, $\mathcal N$, $x_\mathbf B=\mathbf B^{-1}\vec b\ge 0$,$\vec x_\mathbf N=\vec 0$;

1. Solve $\vec \lambda = \left(\mathbf B^\mathsf{T}\right)^{-1}\vec c_\mathbf B$, and  compute $\vec s_\mathbf N =\vec c_\mathbf N - \mathbf N^\mathsf{T} \vec \lambda$ (pricing);
2. If $\vec s_\mathbf N \ge \vec 0$ stop (optimal point found);
3. Select $q\in\mathcal N$ with $s_q<0$ and solve $\vec d=\mathbf B^{-1}\vec A_q$;
4. If $\vec d\le\vec 0$ stop (problem is unbounded);
5. Calculate $x_q^+=\min_{i|d_i>0}\frac{\left(x_\mathbf B\right)_i}{d_i}$, and use $p$ to denote the minimizing $i$;
6. Update $\vec x_\mathbf B^+=\vec x_\mathbf B-x_q^+\vec d$;
7. Change $\mathcal B$ by adding $q$ and removing the basic variable corresponding to column $p$ of $\mathbf B$.

We illustrate this procedure with a simple example.

Consider the problem

```math
\begin{aligned}
\min &-4x_1-2x_2\\
\textrm{ subject to }&
\begin{cases}
x_1+x_2+x_3&=5\\
2x_1+\frac{1}{2}x_2+x_4&=8\\
\vec x&\ge \vec 0
\end{cases}
\end{aligned}
```

Suppose we start with the basis index set $\mathcal B=\left\{3,4\right\}$, for which we have"""

# ╔═╡ 3178001e-fc07-11ea-382e-ad3800a90164
let B = [1 0;0 1], N = [1 1;2 0.5], b = [5;8], cB = [0;0], cN = [-4;-2]
	xB = inv(B)*b
	λ = inv(transpose(B))*cB
	sN = cN - transpose(N)*λ
	xB, λ, sN
end

# ╔═╡ b28dceae-fc07-11ea-1170-6dc3520cfafb
md"""```math
\vec x_\mathbf B =
\begin{pmatrix}
x_3\\
x_4
\end{pmatrix}
=
\begin{pmatrix}
5\\
8
\end{pmatrix}
\,\qquad\vec\lambda =
\begin{pmatrix}
0\\
0
\end{pmatrix}
\,\qquad\vec s_\mathbf N =
\begin{pmatrix}
s_1\\
s_2
\end{pmatrix}
=
\begin{pmatrix}
-4\\
-2
\end{pmatrix}
```

and an objective value of $\vec{c}^\mathsf{T}\vec x=0$. Since both elements of $\vec s_\mathbf N$ are negative, we could choose either 1 or 2 to be the entering variable. Suppose we choose $q=1$. We obtain

```math
\vec d = \begin{pmatrix}
1\\
2
\end{pmatrix}\,,
```

so we cannot (yet) conclude that the problem is unbounded. By performing the ratio calculation, we find that $p=2$ (corresponding to index 4) and $x_1^+=4$."""

# ╔═╡ d9164f2e-fc07-11ea-144c-f1056f14c202
let B = [1 0;0 1], N = [1 1;2 0.5], b = [5;8], cB = [0;0], cN = [-4;-2], xB = [5;8]
	q = 1
	Aq = [1;2]
	d = inv(B)*Aq
	ratio = xB./d
	xq = minimum(ratio)
	xB -= d * xq
	d, ratio, xq, xB
end

# ╔═╡ 2194cfbe-fc08-11ea-1b60-7992c45b8657
md"""We update the basic and nonbasic index sets to $\mathcal B=\left\{3,1\right\}$ and  $\mathcal N=\left\{4,2\right\}$, and move to the next iteration.

At the second iteration, we have"""

# ╔═╡ 3c9691a0-fc08-11ea-22d5-0f2f300742dd
let B = [1 1;0 2], N = [0 1;1 0.5], b = [5;8], cB = [0;-4], cN = [0;-2]
	xB = inv(B)*b
	λ = inv(transpose(B))*cB
	sN = cN - transpose(N)*λ
	xB, λ, sN
end

# ╔═╡ 5f50cc10-fc08-11ea-1685-7971cb0db6dc
md"""
```math
\vec x_\mathbf B =
\begin{pmatrix}
x_3\\
x_1
\end{pmatrix}
=
\begin{pmatrix}
1\\
4
\end{pmatrix}
\,\qquad\vec\lambda =
\begin{pmatrix}
0\\
-2
\end{pmatrix}
\,\qquad\vec s_\mathbf N =
\begin{pmatrix}
s_4\\
s_2
\end{pmatrix}
=
\begin{pmatrix}
2\\
-1
\end{pmatrix}
```

with an objective value of -16. We see that $\vec s_\mathbf N$ has one negative component, corresponding to the index $q=2$, se we select this index to enter the basis. We obtain
"""

# ╔═╡ 75854e70-fc08-11ea-1b6a-85041a569331
let B = [1 1;0 2], N = [0 1;1 0.5], b = [5;8], cB = [0;-4], cN = [0;-2], xB=[1;4]
	q = 2
	Aq = [1;0.5]
	d = inv(B)*Aq
	ratio = xB./d
	xq = minimum(ratio)
	xB -= d * xq
	d, ratio, xq, xB
end

# ╔═╡ f8c0e330-fc08-11ea-167e-5387081f0284
md"""```math
\vec d = \begin{pmatrix}
\frac{3}{4}\\
\frac{1}{4}
\end{pmatrix}\,,
```

so again we do not detect unboundedness. Continuing, we find that the minimum value of $x_2^+$ is $\frac{4}{3}$, and that $p=1$, which indicates that index 3 will leave the basic index set $\mathcal B$. We update the index sets to $\mathcal B=\left\{2,1\right\}$ and  $\mathcal N=\left\{4,3\right\}$ and continue.

At the start of the third iteration, we have
"""

# ╔═╡ 1d47ee60-fc09-11ea-3bf3-35d97f379156
let B = [1 1;0.5 2], N = [0 1;1 0], b = [5;8], cB = [-2;-4], cN = [0;0]
	xB = inv(B)*b
	λ = inv(transpose(B))*cB
	sN = cN - transpose(N)*λ
	xB, λ, sN
end

# ╔═╡ 38877c92-fc09-11ea-0968-a1ca7452e641
md"""```math
\vec x_\mathbf B =
\begin{pmatrix}
x_2\\
x_1
\end{pmatrix}
=
\begin{pmatrix}
\frac{4}{3}\\
\frac{11}{3}
\end{pmatrix}
\,\qquad\vec\lambda =
\begin{pmatrix}
-\frac{4}{3}\\
-\frac{4}{3}
\end{pmatrix}
\,\qquad\vec s_\mathbf N =
\begin{pmatrix}
s_4\\
s_3
\end{pmatrix}
=
\begin{pmatrix}
\frac{4}{3}\\
\frac{4}{3}
\end{pmatrix}
```

with an objective value of $-\frac{52}{3}$. We see that $\vec s_\mathbf N\ge\vec 0$, so the optimality test is satisfied, and we terminate.

We need to flesh out this procedure with specifics of three important aspects of the implementation:

- Linear algebra issues—maintaining an LU factorization of $\mathbf B$ that can be used to solve for $\vec \lambda$ and $\vec d$.
- Selection of the entering index $q$ from among the negative components of $\vec s_\mathbf N$. (In general, there are many such components.)
- Handling of degenerate bases and degenerate steps, in which it is not possible to choose a positive value of $x_q$ without violating feasibility.

Proper handling of these issues is crucial to the efficiency of a simplex implementation. We will use a software package handling these details."""

# ╔═╡ 875ac700-fc09-11ea-217b-0b38e80b750f
begin
	model = Model(GLPK.Optimizer)
	@variable(model, 0 <= x1)
	@variable(model, 0 <= x2)
	@objective(model, Min, -4*x1 -2*x2)
	@constraint(model, con1, x1 + x2 <= 5)
	@constraint(model, con2, 2*x1 + 0.5*x2 <= 8)
	model
end

# ╔═╡ d173e4c0-fc09-11ea-1fbe-d1194a0d0705
optimize!(model)

# ╔═╡ e1efb630-fc09-11ea-300d-916f043ea3a6
termination_status(model)

# ╔═╡ e6daddf0-fc09-11ea-21f5-d3f750fe3091
primal_status(model)

# ╔═╡ ec419e50-fc09-11ea-2878-292809bd19a9
objective_value(model)

# ╔═╡ f1f82c60-fc09-11ea-0422-0572134255d0
value(x1)

# ╔═╡ f7f8e2d0-fc09-11ea-0fe5-f3fe06bee660
value(x2)

# ╔═╡ 0a0dcad0-fc0a-11ea-152a-c97a915d6598
let
	x = -1:5
	plot(x, 5 .- x, linestyle=:dash, label=L"x_1+x_2=5")
	plot!(x, (8 .- 2 .* x) ./ 0.5, linestyle=:dash, label=L"2x_1+0.5x_2=8")
	plot!([0,4,11/3,0,0],[0,0,4/3,5,0], linewidth=2, label="constraints")
	plot!(x, -4 .* x ./ 2, label=L"f\left(x_1,x_2\right)=-4x_1-2x_2=0")
	plot!(x, (-16 .+ 4 .* x) ./ -2, label=L"f\left(x_1,x_2\right)=-4x_1-2x_2=-16")
	plot!(x, (-52/3 .+ 4 .* x) ./ -2, label=L"f\left(x_1,x_2\right)=-4x_1-2x_2=-52/3")
end

# ╔═╡ 209a3130-fc0a-11ea-3e4d-831b98ac933f
md"""## Where does the Simplex Method fit?

In linear programming, as in all optimization problems in which inequality constraints are present, the fundamental task of the algorithm is to determine which of these constraints are active at the solution and which are inactive. The simplex method belongs to a general class of algorithms for constrained optimization known as _active set methods_, which explicitly maintain estimates of the active and inactive index sets that are updated at each step of the algorithm. (At each iteration, the basis $\mathcal B$ is our current estimate of the inactive set, that is, the set of indices $i$ for which we suspect that $x_i > 0$ at the solution of the linear program.) Like most active set methods, the simplex method makes only modest changes to these index sets at each step; a single index is exchanged between $\mathcal B$ into $\mathcal N$.

One undesirable feature of the simplex method attracted attention from its earliest days. Though highly efficient on almost all practical problems (the method generally requires at most $2m$ to $3m$ iterations, where $m$ is the row dimension of the constraint matrix, there are pathological problems on which the algorithm performs very poorly. The complexity of the simplex method is _exponential_, roughly speaking, its running time may be an exponential function of the dimension of
the problem. For many years, theoreticians searched for a linear programming algorithm that has polynomial complexity, that is, an algorithm in which the running time is bounded by a polynomial function of the amount of storage required to define the problem.

In the mid-1980s, Karmarkar described a polynomial algorithm that approaches the solution through the interior of the feasible polytope rather than working its way around the boundary as the simplex method does."""

# ╔═╡ 276abac0-fc0a-11ea-3f72-97fec80d2b88
md"""# Linear Programming: Interiod Point Method

In the 1980s it was discovered that many large linear programs could be solved efficiently by using formulations and algorithms from nonlinear programming and nonlinear equations. One characteristic of these methods was that they required all iterates to satisfy the inequality constraints in the problem _strictly_, so they became known as interior-point methods. By the early 1990s, a subclass of interior-point methods known as primal-dual methods had distinguished themselves as the most efficient practical approaches, and proved to be strong competitors to the simplex method on large problems.

Interior-point methods arose from the search for algorithms with better theoretical properties than the simplex method. The simplex method can be inefficient on certain pathological problems. Roughly speaking, the time required to solve a linear program may be exponential in the size of the problem, as measured by the number
of unknowns and the amount of storage needed for the problem data. For almost all practical problems, the simplex method is much more efficient than this bound would suggest, but its poor worst-case complexity motivated the development of new algorithms with better guaranteed performance.

Interior-point methods share common features that distinguish them from the simplex method. Each interior-point iteration is expensive to compute and can make significant progress towards the solution, while the simplex method usually requires a larger number of inexpensive iterations. Geometrically speaking, the simplex method works its way around the boundary of the feasible polytope, testing a sequence of vertices in turn until it finds the optimal one. Interior-point methods approach the boundary of the feasible set only in the limit. They may approach the solution either from the interior or the exterior of the feasible region, but they never actually lie on the boundary of this region."""

# ╔═╡ c4b3f7f0-fc0b-11ea-2d9b-e9af94723e70
let
	model = Model(Tulip.Optimizer)
	@variable(model, 0 <= x1)
	@variable(model, 0 <= x2)
	@objective(model, Min, -4*x1 -2*x2)
	@constraint(model, con1, x1 + x2 <= 5)
	@constraint(model, con2, 2*x1 + 0.5*x2 <= 8)
	optimize!(model)
	value(x1), value(x2)
end

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
GLPK = "60bf3e95-4087-53dc-ae20-288a0d20c6a6"
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
Tulip = "6dd1b50a-3aae-11e9-10b5-ef983d2400fa"

[compat]
GLPK = "~0.14.14"
JuMP = "~0.21.10"
LaTeXStrings = "~1.2.1"
Plots = "~1.22.1"
Tulip = "~0.8.0"
"""

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

[[AMD]]
deps = ["Libdl", "LinearAlgebra", "SparseArrays", "Test"]
git-tree-sha1 = "fc66ffc5cff568936649445f58a55b81eaf9592c"
uuid = "14f7f29c-3bd6-536c-9a0b-7339e30b5a3e"
version = "0.4.0"

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

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

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

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

[[BenchmarkTools]]
deps = ["JSON", "Logging", "Printf", "Profile", "Statistics", "UUIDs"]
git-tree-sha1 = "61adeb0823084487000600ef8b1c00cc2474cd47"
uuid = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
version = "1.2.0"

[[BinaryProvider]]
deps = ["Libdl", "Logging", "SHA"]
git-tree-sha1 = "ecdec412a9abc8db54c0efc5548c64dfce072058"
uuid = "b99e7846-7c00-51b0-8f62-c81ae34c0232"
version = "0.5.10"

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

[[CEnum]]
git-tree-sha1 = "215a9aa4a1f23fbd05b92769fdd62559488d70e9"
uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82"
version = "0.4.1"

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

[[Calculus]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "f641eb0a4f00c343bbc32346e1217b86f3ce9dad"
uuid = "49dc2e85-a5d0-5ad3-a950-438e2897f1b9"
version = "0.5.1"

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

[[CodecBzip2]]
deps = ["Bzip2_jll", "Libdl", "TranscodingStreams"]
git-tree-sha1 = "2e62a725210ce3c3c2e1a3080190e7ca491f18d7"
uuid = "523fee87-0ab8-5b00-afb7-3ecf72e48cfd"
version = "0.7.2"

[[CodecZlib]]
deps = ["TranscodingStreams", "Zlib_jll"]
git-tree-sha1 = "ded953804d019afa9a3f98981d99b33e3db7b6da"
uuid = "944b1d66-785c-5afd-91f1-9de20f533193"
version = "0.7.0"

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

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

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

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

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

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

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

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

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

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

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

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

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

[[DiffRules]]
deps = ["NaNMath", "Random", "SpecialFunctions"]
git-tree-sha1 = "7220bc21c33e990c14f4a9a319b1d242ebc5b269"
uuid = "b552c78f-8df3-52c6-915a-8e097449b14b"
version = "1.3.1"

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

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

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

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

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

[[ExprTools]]
git-tree-sha1 = "b7e3d17636b348f005f11040025ae8c6f645fe92"
uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04"
version = "0.1.6"

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

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

[[FastClosures]]
git-tree-sha1 = "acebe244d53ee1b461970f8910c235b259e772ef"
uuid = "9aa1b823-49e4-5ca5-8b0f-3971ec8bab6a"
version = "0.3.2"

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

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

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

[[ForwardDiff]]
deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "NaNMath", "Printf", "Random", "SpecialFunctions", "StaticArrays"]
git-tree-sha1 = "b5e930ac60b613ef3406da6d4f42c35d8dc51419"
uuid = "f6369f11-7733-5829-9624-2563aa707210"
version = "0.10.19"

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

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

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

[[GLPK]]
deps = ["BinaryProvider", "CEnum", "GLPK_jll", "Libdl", "MathOptInterface"]
git-tree-sha1 = "833dbc8fbb0554e31186df509d67fc2f78f1bb09"
uuid = "60bf3e95-4087-53dc-ae20-288a0d20c6a6"
version = "0.14.14"

[[GLPK_jll]]
deps = ["Artifacts", "GMP_jll", "JLLWrappers", "Libdl", "Pkg"]
git-tree-sha1 = "01de09b070d4b8e3e1250c6542e16ed5cad45321"
uuid = "e8aa6df9-e6ca-548a-97ff-1f85fc5b8b98"
version = "5.0.0+0"

[[GMP_jll]]
deps = ["Artifacts", "Libdl"]
uuid = "781609d7-10c4-51f6-84f2-b8444358ff6d"

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

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

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

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

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

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

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

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

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

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

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

[[IrrationalConstants]]
git-tree-sha1 = "f76424439413893a832026ca355fe273e93bce94"
uuid = "92d709cd-6900-40b7-9082-c6be49f344b6"
version = "0.1.0"

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

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

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

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

[[JSONSchema]]
deps = ["HTTP", "JSON", "URIs"]
git-tree-sha1 = "2f49f7f86762a0fbbeef84912265a1ae61c4ef80"
uuid = "7d188eb4-7ad8-530c-ae41-71a32a6d4692"
version = "0.3.4"

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

[[JuMP]]
deps = ["Calculus", "DataStructures", "ForwardDiff", "JSON", "LinearAlgebra", "MathOptInterface", "MutableArithmetics", "NaNMath", "Printf", "Random", "SparseArrays", "SpecialFunctions", "Statistics"]
git-tree-sha1 = "4358b7cbf2db36596bdbbe3becc6b9d87e4eb8f5"
uuid = "4076af6c-e467-56ae-b986-b466b2749572"
version = "0.21.10"

[[Krylov]]
deps = ["LinearAlgebra", "Printf", "SparseArrays"]
git-tree-sha1 = "80ae66c445b8f058a2a79932ac076206493a4c5e"
uuid = "ba0b0d4f-ebba-5204-a429-3ac8c609bfb7"
version = "0.7.7"

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

[[LDLFactorizations]]
deps = ["AMD", "LinearAlgebra", "SparseArrays", "Test"]
git-tree-sha1 = "399bbe845e06e1c2d44ebb241f554d45eaf66788"
uuid = "40e66cde-538c-5869-a4ad-c39174c6795b"
version = "0.8.1"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

[[LinearOperators]]
deps = ["FastClosures", "LinearAlgebra", "Printf", "SparseArrays", "TimerOutputs"]
git-tree-sha1 = "a38cdb14141108634ca50305e65b13035c03be35"
uuid = "5c8ed15e-5a4c-59e4-a42b-c7e8811fb125"
version = "2.2.0"

[[LogExpFunctions]]
deps = ["ChainRulesCore", "DocStringExtensions", "IrrationalConstants", "LinearAlgebra"]
git-tree-sha1 = "34dc30f868e368f8a17b728a1238f3fcda43931a"
uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688"
version = "0.3.3"

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

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

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

[[MathOptInterface]]
deps = ["BenchmarkTools", "CodecBzip2", "CodecZlib", "JSON", "JSONSchema", "LinearAlgebra", "MutableArithmetics", "OrderedCollections", "SparseArrays", "Test", "Unicode"]
git-tree-sha1 = "575644e3c05b258250bb599e57cf73bbf1062901"
uuid = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
version = "0.9.22"

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

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

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

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

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

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

[[MutableArithmetics]]
deps = ["LinearAlgebra", "SparseArrays", "Test"]
git-tree-sha1 = "3927848ccebcc165952dc0d9ac9aa274a87bfe01"
uuid = "d8a4904e-b15c-11e9-3269-09a3773c0cb0"
version = "0.2.20"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

[[Profile]]
deps = ["Printf"]
uuid = "9abbd945-dff8-562f-b5e8-e1ebf5ef1b79"

[[QPSReader]]
deps = ["Logging", "Pkg"]
git-tree-sha1 = "374833c0c1fd5cc623278581bf0c8259d7b35f10"
uuid = "10f199a5-22af-520b-b891-7ce84a7b1bd0"
version = "0.2.1"

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

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

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

[[RecipesBase]]
git-tree-sha1 = "44a75aa7a527910ee3d1751d1f0e4148698add9e"
uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01"
version = "1.1.2"

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

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

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

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

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

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

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

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

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

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

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

[[SpecialFunctions]]
deps = ["ChainRulesCore", "LogExpFunctions", "OpenSpecFun_jll"]
git-tree-sha1 = "a322a9493e49c5f3a10b50df3aedaf1cdb3244b7"
uuid = "276daf66-3868-5448-9aa4-cd146d93841b"
version = "1.6.1"

[[StaticArrays]]
deps = ["LinearAlgebra", "Random", "Statistics"]
git-tree-sha1 = "3240808c6d463ac46f1c1cd7638375cd22abbccb"
uuid = "90137ffa-7385-5640-81b9-e52037218182"
version = "1.2.12"

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

[[StatsAPI]]
git-tree-sha1 = "1958272568dc176a1d881acb797beb909c785510"
uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0"
version = "1.0.0"

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

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

[[SuiteSparse]]
deps = ["Libdl", "LinearAlgebra", "Serialization", "SparseArrays"]
uuid = "4607b0f0-06f3-5cda-b6b1-a6196a1729e9"

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

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

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

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

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

[[TimerOutputs]]
deps = ["ExprTools", "Printf"]
git-tree-sha1 = "209a8326c4f955e2442c07b56029e88bb48299c7"
uuid = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f"
version = "0.5.12"

[[TranscodingStreams]]
deps = ["Random", "Test"]
git-tree-sha1 = "216b95ea110b5972db65aa90f88d8d89dcb8851c"
uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa"
version = "0.9.6"

[[Tulip]]
deps = ["CodecBzip2", "CodecZlib", "Krylov", "LDLFactorizations", "LinearAlgebra", "LinearOperators", "Logging", "MathOptInterface", "Printf", "QPSReader", "SparseArrays", "SuiteSparse", "Test", "TimerOutputs"]
git-tree-sha1 = "753c5bd161ca2a64da995a21900bcc177bd7d8e4"
uuid = "6dd1b50a-3aae-11e9-10b5-ef983d2400fa"
version = "0.8.0"

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

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

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

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

[[Wayland_protocols_jll]]
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll"]
git-tree-sha1 = "2839f1c1296940218e35df0bbb220f2a79686670"
uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91"
version = "1.18.0+4"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

# ╔═╡ Cell order:
# ╟─5fd1dfc0-fc04-11ea-1747-69f05b302ab0
# ╟─dec71840-fc04-11ea-33f5-c353bc11b181
# ╟─35e94ee0-fc05-11ea-3183-d153786970b0
# ╟─71ce4140-fc05-11ea-3e86-913a7fbbdbc4
# ╠═3178001e-fc07-11ea-382e-ad3800a90164
# ╟─b28dceae-fc07-11ea-1170-6dc3520cfafb
# ╠═d9164f2e-fc07-11ea-144c-f1056f14c202
# ╟─2194cfbe-fc08-11ea-1b60-7992c45b8657
# ╠═3c9691a0-fc08-11ea-22d5-0f2f300742dd
# ╟─5f50cc10-fc08-11ea-1685-7971cb0db6dc
# ╠═75854e70-fc08-11ea-1b6a-85041a569331
# ╟─f8c0e330-fc08-11ea-167e-5387081f0284
# ╠═1d47ee60-fc09-11ea-3bf3-35d97f379156
# ╟─38877c92-fc09-11ea-0968-a1ca7452e641
# ╠═6b29d3f0-fc09-11ea-15c9-313cd7403a39
# ╠═6df41780-fc09-11ea-2de3-d3dfe50b7484
# ╠═875ac700-fc09-11ea-217b-0b38e80b750f
# ╠═d173e4c0-fc09-11ea-1fbe-d1194a0d0705
# ╠═e1efb630-fc09-11ea-300d-916f043ea3a6
# ╠═e6daddf0-fc09-11ea-21f5-d3f750fe3091
# ╠═ec419e50-fc09-11ea-2878-292809bd19a9
# ╠═f1f82c60-fc09-11ea-0422-0572134255d0
# ╠═f7f8e2d0-fc09-11ea-0fe5-f3fe06bee660
# ╠═fcb22520-fc09-11ea-2266-a3e9fc398b1b
# ╠═0b001a12-fc0a-11ea-30e6-df8c0d22e8cd
# ╠═0a0dcad0-fc0a-11ea-152a-c97a915d6598
# ╟─209a3130-fc0a-11ea-3e4d-831b98ac933f
# ╟─276abac0-fc0a-11ea-3f72-97fec80d2b88
# ╠═5f7ce0ee-fc0f-11ea-29cc-35c53dd304a1
# ╠═c4b3f7f0-fc0b-11ea-2d9b-e9af94723e70
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002


"""
	RegularNetwork <: AbstractNetwork

A regular (ring) network.

# Fields
- N              :: Integer -> Number of nodes
- k              :: Integer -> Node connectivity
"""
mutable struct RegularNetwork <: AbstractNetwork
	N :: Integer
	k :: Integer

	_adjMat :: Union{AbstractMatrix, Nothing}
	_props :: NetworkProperties
end

"""
	RegularNetwork(N::Integer, k::Integer; directed::Bool=false)

Create a regular network with `N` nodes and node connectivity `k`.
"""
function RegularNetwork(N::Integer, k::Integer; directed::Bool=false)
	(N <= 0) && throw(ArgumentError("Number of nodes must be a positive integer!"))

	(k % 2 == 1) && (k -= 1)
	(k < 0) && (k = 0)
	(k >= N-1) && (k = N-1)

	RegularNetwork(N, k, nothing, NetworkProperties(N, directed))
end

function show(network::RegularNetwork)
	print(isdirected(network) ? "Directed " : "Undirected ")
	println("Regular network")
	println("- N = $(network.N)")
	println("- k = $(network.k)")
end


#Demo 2: Reflection coefficients
#-------------------------------------------------------------------------------
using InspectDR
using Colors
import Graphics: width, height

#==Input
===============================================================================#

#Constants
#-------------------------------------------------------------------------------
black = RGB24(0, 0, 0)
white = RGB24(1, 1, 1)
red = RGB24(1, 0, 0)
green = RGB24(0, 1, 0)
blue = RGB24(0, 0, 1)
μ0 = 4pi*1e-7 #F/m
ϵ0 = 8.854e-12 #H/m

#Input data
#-------------------------------------------------------------------------------
fmax = 10e9
fstep = 50e6
f = collect(0:fstep:fmax)
ℓ = 50e-3 #Meters
ZL = Float64[1e6, 377, 60.0]
_colors = [blue, red, green]

#==Equations
===============================================================================#
Γ(Z; Zref::Real=50.0) = (Z .- Zref) ./ (Z .+ Zref)
#ZC: Characteristic impedance
#ZL: Load impendance (termination)
function Zline(ℓ::Real, f::Vector, ZL::Number; ZC::Number=50.0, α::Real=0, μ::Real=μ0, ϵ::Real=ϵ0)
	j = im
	β = f*(2pi*sqrt(μ*ϵ))
	γ = α .+ j*β
	tanh_γℓ = tanh.(γ*ℓ)
	return ZC*(ZL .+ ZC*tanh_γℓ)./(ZC .+ ZL*tanh_γℓ)
end
function Γline(ℓ::Real, f::Vector, ZL::Number; ZC::Number=50.0, Zref::Number=50.0, α::Real=0, μ::Real=μ0, ϵ::Real=ϵ0)
	return Γ(Zline(ℓ, f, ZL; ZC=ZC, α=α, μ=μ, ϵ=ϵ), Zref=Zref)
end

#Calculations
#-------------------------------------------------------------------------------
Γload = []
for ZLi in ZL
	_Γ = Γline(ℓ, f, ZLi, ZC=40)
	push!(Γload, _Γ)
end

#==Generate plot
===============================================================================#
mplot = InspectDR.Multiplot(title="Transmission Line Example")
mplot.layout[:ncolumns] = 2

smithext = InspectDR.PExtents1D(min=-1.2,max=1.2) #Padded a bit

plot_linf = InspectDR.Plot2D(:lin, :dB20)
	graph_linf = plot_linf.strips[1]
	graph_linf.yext_full = InspectDR.PExtents1D(max=5)
#	plot_linf.layout[:enable_legend] = true

plot_logf = InspectDR.Plot2D(:log10, :dB20)
	graph_logf = plot_logf.strips[1]
	plot_logf.xext_full = InspectDR.PExtents1D(min=10e6) #Avoid issues with log scale
	graph_logf.yext_full = InspectDR.PExtents1D(max=5)
	graph_logf.grid = InspectDR.GridRect(vmajor=true, vminor=true, hmajor=true)
plot_ysmith = InspectDR.smithchart(:Y, title="Y-Smith Chart")
	graph_ysmith = plot_ysmith.strips[1]
	plot_ysmith.xext_full = smithext
	graph_ysmith.yext_full = smithext
	plot_ysmith.layout[:enable_legend] = true
plot_zsmith = InspectDR.smithchart(:Z, ref=50, title="Z-Smith Chart")
	graph_zsmith = plot_zsmith.strips[1]
	plot_zsmith.xext_full = smithext
	graph_zsmith.yext_full = smithext
	plot_zsmith.layout[:enable_legend] = true

let plot, a #HIDEWARN_0.7
for plot in [plot_linf, plot_logf]
	a = plot.annotation
	a.title = "Reflection Coefficient (Γ)"
	a.xlabel = "Frequency (Hz)"
	a.ylabels = ["Magnitude (dB)"]
end
end

#Select which plots to actually display:
plotlist = [plot_linf, plot_logf, plot_ysmith, plot_zsmith]
#plotlist = [plot_zsmith]

let plot, wfrm #HIDEWARN_0.7
for plot in plotlist
	for i in 1:length(Γload)
		wfrm = add(plot, f, Γload[i], id="ZL=$(ZL[i])")
		wfrm.line = line(color=_colors[i], width=2)
	end

	add(mplot, plot)
end
end

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

#==Save multi-plot to file
===============================================================================#

maximize_square = true
if maximize_square
	#Target plot size to get square Smith plots without gaps:
	#(HACK: Method not suggested)
	lyt = plot_zsmith.layout
		lyt[:halloc_data] = 500
		lyt[:valloc_data] = 500
	bb = InspectDR.plotbounds(lyt.values, InspectDR.grid1(plot_zsmith)) #Required
		mplot.layout[:halloc_plot] = width(bb)
		mplot.layout[:valloc_plot] = height(bb)
end

if false
	#Test several attributes:
	mplot.frame.line.style=:solid
	mplot.frame.line.width=30
	mplot.frame.line.color=red
	mplot.frame.fillcolor=white
end

InspectDR.write_png("export_multiplot.png", mplot)
InspectDR.write_svg("export_multiplot.svg", mplot)
InspectDR.write_eps("export_multiplot.eps", mplot)
InspectDR.write_pdf("export_multiplot.pdf", mplot)

:DONE


using ModelTES, PyPlot

#following equation 4
# https://doi.org/10.1063/1.4984065 Morgan et al 2017
type TwoFluidRIT <: ModelTES.AbstractRIT
  Ic0::Float64
  cI::Float64
  cR::Float64

end
function ModelTES.R(I,T, RIT::TwoFluidRIT, Tc, Rn)
  a=(1-min(T,Tc)/Tc)^1.5
  b=RIT.cI*RIT.Ic0/I
  c=(1-a*b)
  Rn*RIT.cR*c
end
ModelTES.transitionwidth(RIT::TwoFluidRIT) = 0.001 # I dont think this is used much
tfrit = TwoFluidRIT(0.00742, 0.84, 0.45)
Tbath = 0.055; L = 45e-9; Rl = 0.0; C = 0.25e-12; G=42e-12; n=2.5;
Rn = 0.010; Tc = 0.0714; k=G/n/Tc^(n-1)
R0 = 0.15*Rn; Rpara = 0.0
tes_param = TESParams(n,Tc,Tbath,k,C,L,Rl,Rpara,Rn,tfrit)
bt = BiasedTES(tes_param, R0)

out = pulse(12000,1e-7, bt, 1000, 2000);

plot(times(out), out.I[1]-out.I)


# Bias-correction Pope (1990)
function bias_correction(V::VAR)
  (T,K) = size(V.Y')
  A = get_VAR1_rep(V)
  SIGMA = [V.Σ zeros(K,K*V.p-K); zeros(K*V.p-K,K*V.p)]
  vecSIGMAY = (eye((K*V.p)^2)-kron(A,A))\vec(SIGMA)    # Lutkepohl p.29 (2.1.39)
  SIGMAY = reshape(vecSIGMAY, K*V.p, K*V.p)
  I = eye(K*V.p, K*V.p)
  B = A'
  peigen = eigvals(A)
  sumeig = zeros(K*V.p, K*V.p)
  for h in 1:K*V.p
    sumeig += (peigen[h].\(I - peigen[h]*B)) #***
  end
  bias = SIGMA*(inv(I - B) + B/(I-B^2) + sumeig)/(SIGMAY) #***
  Abias = - bias/T
  bcstab = 9           # Arbitrary default value > 1
  delta = 1            # Adjustment factor
  bcA = cell() #### if not working remove and put bcA as global
  while bcstab >= 1
    # Adjust bias-correction proportionately
    bcA = A-delta*Abias
    bcmod = abs(eigvals(bcA))
    any(bcmod.>= 1) ?  bcstab = 1 : bcstab = 0
    delta += - 0.01
    (delta <= 0) && (bcstab = 0)
  end
  return bcA
end


######## Stan diagnose example  ###########

using StanDiagnose, Test

bernoulli_model = "
data {
  int<lower=0> N;
  int<lower=0,upper=1> y[N];
}
parameters {
  real<lower=0,upper=1> theta;
}
model {
  theta ~ beta(1,1);
    y ~ bernoulli(theta);
}
"
bernoulli_data = Dict("N" => 10, "y" => [0, 1, 0, 1, 0, 0, 0, 0, 0, 1])

sm = DiagnoseModel("diagnose", bernoulli_model;
  method=StanDiagnose.Diagnose(StanDiagnose.Gradient(epsilon=1e-6)));

rc = stan_diagnose(sm; data=bernoulli_data);

if success(rc)
  diags = read_diagnose(sm)
  @test diags[:error][1] ≈ 0.0  atol=0.000001
end