"""
  function calculate_D(sMMProblem::SMMProblem, theta0::Array{Float64,1}; method::Symbol = :central)

Function to calculate the jacobian of the simulated moments.
If the simulation is long enough, this provideds a good approximation for
the expected value of the jacobian. The output is the "D" matrix in the terminology
of Gouriéroux and Monfort (1996).
"""
function calculate_D(sMMProblem::SMMProblem, theta0::Array{Float64,1}; method::Symbol = :central)

  Calculus.jacobian(x -> sMMProblem.simulate_empirical_moments_array(x), theta0, method)

end

"""
  calculate_Avar!(sMMProblem::SMMProblem, theta0::Array{Float64,1}; method::Symbol = :central)

Calculate the asymptotic variance of the SMM estimator using the sandwich formula.
This function assume that your model is simulating time series.
As a result, the asymptotic variance of the SMM estimator is (1+tau) times
the asymptotic variance of the GMM one, where tau is the ratio of the sample size
to the size of the simulated sample. See Duffie and Singleton (1993) and Gouriéroux and Monfort (1996).
"""
function calculate_Avar!(sMMProblem::SMMProblem, theta0::Array{Float64,1}, tData::Int64, tSimulation::Int64; method::Symbol = :central)

  # Safety Checks
  if sMMProblem.Sigma0 == Array{Float64}(0,0)
    Base.error("Please initialize sMMProblem.Sigma0 using the function set_Sigma0!.")
  end

  tau = tData/tSimulation

  # Jacobian matrix
  D = calculate_D(sMMProblem, theta0, method = method)

  # Weigthing matrix (only diagonal matrix for the moment)
  W = diagm([1/sMMProblem.empiricalMoments[k][2] for k in keys(sMMProblem.empiricalMoments)])

  Sigma1 = transpose(D)*W*D

  Sigma2 = transpose(D)*W*sMMProblem.Sigma0*W*D

  inv_Sigma1 = inv(Sigma1)

  # sandwich formula, where tau captures the extra noise introduced by simulation,
  # compared to the usual GMM estimator.
  # I use the function Symmetric, because otherwise a test issymmetric()
  # on the asymptotic variance will return "false" because of numerical approximations
  sMMProblem.Avar = Symmetric((1+tau)*inv_Sigma1*Sigma2*inv_Sigma1)

end

"""
  calculate_se(sMMProblem::SMMProblem, tData::Int64, tSimulation::Int64)

Function to calculate the standard error associated to the the ith parameter,
respecting the ordering given by the ordered dictionary sMMProblem.priors
"""
function calculate_se(sMMProblem::SMMProblem, tData::Int64, i::Int64)

  # Safety Checks
  if sMMProblem.Avar == Array{Float64}(0,0)
    Base.error("Please caclulate the asymptotic variance using the function calculate_Avar!.")
  end

  sqrt((1/tData)*sMMProblem.Avar[i,i])

end

"""
  calculate_t(sMMProblem::SMMProblem, tData::Int64, tSimulation::Int64)

Function to calculate the t-statistic associated to following test:
H0: theta_i = 0
H1: theta_i != 0
The ordering of parameters is the one given by the ordered dictionary sMMProblem.priors
"""
function calculate_t(sMMProblem::SMMProblem, theta0::Array{Float64,1}, tData::Int64, i::Int64)

  # Safety Checks
  if sMMProblem.Avar == Array{Float64}(0,0)
    Base.error("Please caclulate the asymptotic variance using the function calculate_Avar!.")
  end

  theta0[i]/calculate_se(sMMProblem, tData, i)

end

"""
  calculate_pvalue(sMMProblem::SMMProblem, tData::Int64, tSimulation::Int64)

Function to calculate the p-value associated to following test:
H0: theta_i = 0
H1: theta_i != 0
The ordering of parameters is the one given by the ordered dictionary sMMProblem.priors
"""
function calculate_pvalue(sMMProblem::SMMProblem, theta0::Array{Float64,1}, tData::Int64, i::Int64)

  # Safety Checks
  if sMMProblem.Avar == Array{Float64}(0,0)
    Base.error("Please caclulate the asymptotic variance using the function calculate_Avar!.")
  end

  t =  calculate_t(sMMProblem, theta0, tData, i)

  # asymptotically normally distributed N(0,1)
  d = Normal(0,1)

  # p-value  = 2 times area to the right of t
  pvalue = 2*(1.0 - cdf(d, t))

  return pvalue

end

"""
  calculate_CI(sMMProblem::SMMProblem, theta0::Array{Float64,1}, tData::Int64, i::Int64)

Function to calculate an alpha confidence interval for the ith parameter.
"""
function calculate_CI(sMMProblem::SMMProblem, theta0::Array{Float64,1}, tData::Int64, i::Int64, alpha::Float64)

  # Safety Checks
  if sMMProblem.Avar == Array{Float64}(0,0)
    Base.error("Please caclulate the asymptotic variance using the function calculate_Avar!.")
  end

  # standard error
  se = calculate_se(sMMProblem, tData, i)

  # asymptotically normally distributed N(0,1)
  d = Normal(0,1)

  critical_value = - quantile(d, alpha)

  #return lower and upper bound of the confidence interval
  return theta0[i] - se*critical_value, theta0[i] + se*critical_value

end

function summary_table(sMMProblem::SMMProblem, theta0::Array{Float64,1}, tData::Int64, alpha::Float64)

  # Safety Checks
  if sMMProblem.Avar == Array{Float64}(0,0)
    Base.error("Please caclulate the asymptotic variance using the function calculate_Avar!.")
  end

  df = DataFrame(Estimate = Float64[], StdError = Float64[], tValue = Float64[], pValue = Float64[], ConfIntervalLower = Float64[], ConfIntervalUpper = Float64[])

  for i = 1:length(theta0)

    se = calculate_se(sMMProblem, tData, i)
    t = calculate_t(sMMProblem, theta0, tData, i)
    p = calculate_pvalue(sMMProblem, theta0, tData, i)
    CI_lower, CI_upper = calculate_CI(sMMProblem, theta0, tData, i, alpha)

    push!(df, [theta0[i], se, t, p, CI_lower, CI_upper])

  end

  return df

end


using OrdinaryDiffEq, RecursiveArrayTools, DiffEqBase, Base.Test#, ParameterizedFunctions

f = function (t,u)
  - u + sin(t)
end

prob = ODEProblem(f,1.0,(0.0,10.0))

condition= function (t,u,integrator) # Event when event_f(t,u,k) == 0
  t - 2.95
end

affect! = function (integrator)
  integrator.u = integrator.u + 2
end

callback = ContinuousCallback(condition,affect!)

sol = solve(prob,Tsit5(),callback=callback)

f = function (t,u,du)
  du[1] = - u[1] + sin(t)
end

prob = ODEProblem(f,[1.0],(0.0,10.0))

condtion= function (t,u,integrator) # Event when event_f(t,u,k) == 0
  t - 2.95
end

affect! = function (integrator)
  integrator.u = integrator.u + 2
end

callback = ContinuousCallback(condtion,affect!)

sol = solve(prob,Tsit5(),callback=callback,abstol=1e-8,reltol=1e-6)

#=
f = @ode_def BallBounce begin
  dy =  v
  dv = -g
end g=9.81
=#

f = function (t,u,du)
  du[1] = u[2]
  du[2] = -9.81
end

condtion= function (t,u,integrator) # Event when event_f(t,u,k) == 0
  u[1]
end

affect! = nothing
affect_neg! = function (integrator)
  integrator.u[2] = -integrator.u[2]
end

callback = ContinuousCallback(condtion,affect!,affect_neg!,interp_points=100)

u0 = [50.0,0.0]
tspan = (0.0,15.0)
prob = ODEProblem(f,u0,tspan)

sol = solve(prob,Tsit5(),callback=callback,adaptive=false,dt=1/4)

condtion_single = function (t,u,integrator) # Event when event_f(t,u,k) == 0
  u
end

affect! = nothing
affect_neg! = function (integrator)
  integrator.u[2] = -integrator.u[2]
end

callback_single = ContinuousCallback(condtion_single,affect!,affect_neg!,interp_points=100,idxs=1)

u0 = [50.0,0.0]
tspan = (0.0,15.0)
prob = ODEProblem(f,u0,tspan)

sol = solve(prob,Tsit5(),callback=callback_single,adaptive=false,dt=1/4)

#plot(sol,denseplot=true)

sol = solve(prob,Vern6(),callback=callback)
#plot(sol,denseplot=true)
sol = solve(prob,BS3(),callback=callback)

sol33 = solve(prob,Vern7(),callback=callback)

bounced = ODEProblem(f,sol[8],(0.0,1.0))
sol_bounced = solve(bounced,Vern6(),callback=callback,dt=sol.t[9]-sol.t[8])
#plot(sol_bounced,denseplot=true)
sol_bounced(0.04) # Complete density
@test maximum(maximum.(map((i)->sol.k[9][i]-sol_bounced.k[2][i],1:length(sol.k[9])))) == 0

sol2= solve(prob,Vern6(),callback=callback,adaptive=false,dt=1/2^4)
#plot(sol2)

sol2= solve(prob,Vern6())

sol3= solve(prob,Vern6(),saveat=[.5])

## Saving callback

condtion = function (t,u,integrator)
  true
end
affect! = function (integrator) end

save_positions = (true,false)
saving_callback = DiscreteCallback(condtion,affect!,save_positions=save_positions)

sol4 = solve(prob,Tsit5(),callback=saving_callback)

@test sol2(3) ≈ sol(3)

affect! = function (integrator)
  u_modified!(integrator,false)
end
saving_callback2 = DiscreteCallback(condtion,affect!,save_positions=save_positions)
sol4 = solve(prob,Tsit5(),callback=saving_callback2)

cbs = CallbackSet(saving_callback,saving_callback2)
sol4_extra = solve(prob,Tsit5(),callback=cbs)

@test length(sol4_extra) == 2length(sol4) - 1

condtion= function (t,u,integrator)
  u[1]
end

affect! = function (integrator)
  terminate!(integrator)
end

terminate_callback = ContinuousCallback(condtion,affect!)

tspan2 = (0.0,Inf)
prob2 = ODEProblem(f,u0,tspan2)

sol5 = solve(prob2,Tsit5(),callback=terminate_callback)

@test sol5[end][1] < 3e-12
@test sol5.t[end] ≈ sqrt(50*2/9.81)

affect2! = function (integrator)
  if integrator.t >= 3.5
    terminate!(integrator)
  else
    integrator.u[2] = -integrator.u[2]
  end
end
terminate_callback2 = ContinuousCallback(condtion,nothing,affect2!,interp_points=100)

sol5 = solve(prob2,Vern7(),callback=terminate_callback2)

@test sol5[end][1] < 1e-12
@test sol5.t[end] ≈ 3*sqrt(50*2/9.81)

condtion= function (t,u,integrator) # Event when event_f(t,u,k) == 0
  t-4
end

affect! = function (integrator)
  terminate!(integrator)
end

terminate_callback3 = ContinuousCallback(condtion,affect!,interp_points=100)

bounce_then_exit = CallbackSet(callback,terminate_callback3)

sol6 = solve(prob2,Vern7(),callback=bounce_then_exit)

@test sol6[end][1] > 0
@test sol6.t[end] ≈ 4


"""
mutable struct InverseDistanceSurrogate{X,Y,P,C,L,U} <: AbstractSurrogate

The inverse distance weighting model is an interpolating method and the
unknown points are calculated with a weighted average of the sampling points.
p is a positive real number called the power parameter.
p > 1 is needed for the derivative to be continuous.

"""
mutable struct InverseDistanceSurrogate{X,Y,L,U,P} <: AbstractSurrogate
    x::X
    y::Y
    lb::L
    ub::U
    p::P
end

function InverseDistanceSurrogate(x,y,lb,ub;p::Number=1.0)
    return InverseDistanceSurrogate(x,y,lb,ub,p)
end

function (inverSurr::InverseDistanceSurrogate)(val)
    if val in inverSurr.x
        return inverSurr.y[findfirst(x->x==val,inverSurr.x)]
    else
        if length(inverSurr.lb) == 1
            num = sum(inverSurr.y[i]*(norm(val .- inverSurr.x[i]))^(-inverSurr.p) for i = 1:length(inverSurr.x))
            den = sum(norm(val .- inverSurr.x[i])^(-inverSurr.p) for i = 1:length(inverSurr.x))
            return num/den
        else
            βᵢ = [norm(val .- inverSurr.x[i])^(-inverSurr.p) for i = 1:length(inverSurr.x)]
            num = sum(inverSurr.y[i] * βᵢ[i] for i = 1:length(inverSurr.y))
            den = sum(βᵢ)
            return num/den
        end
    end
end

function add_point!(inverSurr::InverseDistanceSurrogate,x_new,y_new)
    if eltype(x_new) == eltype(inverSurr.x)
        #1D
        append!(inverSurr.x,x_new)
        append!(inverSurr.y,y_new)
    else
        #ND
        push!(inverSurr.x, x_new)
        push!(inverSurr.y, y_new)
    end
    nothing
end


"""
    hilbert_x(eb::Eigenbrot)
Return the Hilbert x-transform of `eb`.
"""
function hilbert_x(eb::Eigenbrot)
    nd = copy(eb)
    h, w = size(nd)
    centre_c = 1 + w >> 1
    centre_r = 1 + h >> 1
    for c in 1:w
        for r in 1:h
            sign = if c == centre_c
                r > centre_r ? im : -im
            elseif r == centre_r
                c > centre_c ? im : -im
            else
                c > centre_c ? im : -im
            end
            nd[r, c] *= sign
        end
    end
    return nd
end

"""
    hilbert_y(eb::Eigenbrot)
Return the Hilbert x-transform of `eb`.
"""
function hilbert_y(eb::Eigenbrot)
    nd = copy(eb)
    h, w = size(nd)
    centre_c = 1 + w >> 1
    centre_r = 1 + h >> 1
    for c in 1:w
        for r in 1:h
            sign = if c == centre_c
                r > centre_r ? im : -im
            elseif r == centre_r
                c > centre_c ? im : -im
            else
                r > centre_r ? im : -im
            end
            nd[r, c] *= sign
        end
    end
    return nd
end

"""
    fft_xshear(eb::Eigenbrot, xShear::Real, expand::Bool = true)
Shear `eb` by a factor 'xShear' in the x-direction using the Fourier
shift theorem, and return the result. If `expand` is true the input
is padded so that the shear doesn't wrap the data as a result of
aliasing in the Fourier domain.
"""
function fft_xshear(eb::Eigenbrot, xShear::Real, expand::Bool = true)
    xform = if expand
        extra = ceil(Int, abs(xShear) * height(eb) / 2)
        fftx(pad(eb, left = extra, right = extra), false)
    else
        fftx(eb, false)
    end
    h, w = size(xform)
    halfHeight = h / 2
    lim = iseven(w) ? w >> 1 : (w + 1) >> 1
    for row in 1:h
        δ = xShear * (halfHeight - row + 1)
        for i in 1:lim
            θ = (2.0 * π * δ * i) / w
            cs = cos(θ) + im * sin(θ)
            xform[row, i + 1] *= cs
            xform[row, w - i + 1] *= cs'
        end
        if iseven(w)
            i2 = trunc(Int, abs(δ))
            δ < 0 && (i2 = -i2)
            θ = (2.0 * π * δ * i2) / w
            xform[row, lim] *= cos(θ) + im * sin(θ)
        end
    end

    return fftx(xform, false)
end

"""
    fft_yshear(eb::Eigenbrot, xShear::Real, expand::Bool = true)
Shear `eb` by a factor 'yShear' in the y-direction using the Fourier
shift theorem, and return the result. If `expand` is true the input
is padded so that the shear doesn't wrap the data as a result of
aliasing in the Fourier domain.
"""
function fft_yshear(eb::Eigenbrot, yShear::Real, expand::Bool = true)
    xform = if expand
        extra = ceil(Int, abs(yShear * width(eb) / 2))
        ffty(pad(eb, top = extra, bottom = extra), false)
    else
        ffty(eb, false)
    end
    h, w = size(xform)
    halfWidth = w / 2
    lim = iseven(h) ? h >> 1 : (h + 1) >> 1
    for col in 1:w
        δ = yShear * (halfWidth - col + 1)
        for i in 1:lim
            θ = (2.0 * π * δ * i) / h
            cs = cos(θ) + im * sin(θ)
            xform[i + 1, col] *= cs
            xform[h - i + 1, col] *= cs'
        end
        if iseven(h)
            i2 = trunc(Int, abs(δ))
            δ < 0.0 && (i2 = -i2)
            θ = (2.0 * π * i2 * lim) / h
            xform[lim + 1, col] *= cos(θ) + im * sin(θ)
        end
    end

    return ffty(xform, false)
end

"""
    rotate90(eb::Eigenbrot, n::Integer)
Return the result of rotating `eb` through an angle of
`n` * π /2 (i.e. `n` right angles).
"""
function rotate90(eb::Eigenbrot, n::Integer)
    if n == 0
        return copy(eb)
    elseif n == 1
        h, w = size(eb)
        e2 = Eigenbrot(w, h, eb.fft)
        for r in 1:w
            e2.vals[r, 1:h] = eb.vals[h:-1:1, r]
        end
        return e2
    elseif n == 2
        e2 = Eigenbrot(height(eb), width(eb), eb.fft)
        l = length(eb.vals)
        e2.vals[1:l] = eb.vals[l:-1:1]
        return e2
    elseif n == 3
        h, w = size(eb)
        e2 = Eigenbrot(w, h, eb.fft)
        for r in 1:w
            e2.vals[w - r + 1, h:-1:1] = eb.vals[h:-1:1, r]
        end
        return e2
    else
        return rotate90(eb, mod(n, 4))
    end
end

"""
    fourierRotation(eb::Eigenbrot, θ::Real, expand::Bool = true)
Return the result of rotating `eb` through an angle `θ`,
using the algorithm described by Larkin, Oldfield and Klemm
(Optics Communications 139 (1997) 99-106). If `expand` is true,
the size of the output image is increased to contain the rotated image,
otherwise the aliasing described in Larkin et al. occurs.
"""
function fourierRotation(eb::Eigenbrot, θ::Real, expand::Bool = true)
    h, w = size(eb)
    θ = -θ  # reverse rotation direction

    # Deconstruct θ as the sum of an integral number, n90,
    # of right angles, and a remainder, ϕ, with absolute
    # value less than π/4...
    n90, ϕ = divrem(θ, π / 2)
    if abs(ϕ) > π / 4
        s = sign(ϕ)
        n90 += s
        ϕ = ϕ - s * π / 2
    end
    n90 = trunc(Int, mod(n90, 4))
    result = rotate90(eb, n90)
    ϕ ≈ 0 && return result

    xshear = tan(ϕ / 2)
    yshear = -sin(ϕ)
    if expand
        hh, ww = size(result)
        hm, wm = 0, 0
        msx = [1.0 xshear; 0.0 1.0]
        msy = [1.0 0.0; yshear 1.0]
        cnrs = [0 ww 0 ww; 0 0 hh hh]
        for mm in [msx, msy, msx]
            cnrs = mm * cnrs
            wm = max(wm, maximum(cnrs[1, :]) - minimum(cnrs[1, :]))
            hm = max(hm, maximum(cnrs[2, :]) - minimum(cnrs[2, :]))
        end
        lr = ceil(Int, (wm - ww) / 2)
        tb = ceil(Int, (hm - hh) / 2)
        result = pad(result, left = lr, right = lr, top = tb, bottom = tb)
    end

    result = fft_xshear(result, xshear, false)
    result = fft_yshear(result, yshear, false)
    result = fft_xshear(result, xshear, false)
    return result
end


# SPDX-License-Identifier: X11
# 2020-11-05
# Trapezoid Sum (200pt)

sumto(n) = n * (n + 1) ÷ 2
sumfromto(n, m) = sumto(m) - sumto(n) + n

function main()
  N = parse(Int, readline())
  sum = 0
  for i ∈ 1:N
    A,B = parse.(Int, split(readline()))
    sum += sumfromto(A,B)
  end
  println(sum)
end

main()


"""
    HyperRectangle{N,T}

Hyperrectangle in `N` dimensions given by `low_corner::SVector{N,T}` and
`high_corner::SVector{N,T}`
"""
struct HyperRectangle{N,T}
    low_corner::SVector{N,T}
    high_corner::SVector{N,T}
end

# promote
HyperRectangle(l::Tuple,h::Tuple) = HyperRectangle(SVector(l),SVector(h))
HyperRectangle(l::SVector,h::SVector) = HyperRectangle(promote(l,h)...)
# 1d case
HyperRectangle(a::Number,b::Number) = HyperRectangle(SVector(a),SVector(b))

Base.:(==)(h1::HyperRectangle, h2::HyperRectangle) = (h1.low_corner == h2.low_corner) && (h1.high_corner == h2.high_corner)
Base.isapprox(h1::HyperRectangle,h2::HyperRectangle) = isapprox(h1.low_corner,h2.low_corner) && isapprox(h1.high_corner,h2.high_corner)
Base.in(point,h::HyperRectangle) = all(h.low_corner .<= point .<= h.high_corner)

Base.eltype(h::HyperRectangle{N,T}) where {N,T}     = T
ambient_dimension(h::HyperRectangle{N}) where {N}   = N
geometric_dimension(h::HyperRectangle{N}) where {N} = N

low_corner(r::HyperRectangle) = r.low_corner
high_corner(r::HyperRectangle) = r.high_corner

diameter(cub::HyperRectangle) = norm(cub.high_corner .- cub.low_corner,2)

function bounding_box(data)
    low_corner  = first(data)
    high_corner = first(data)
    for pt in data
        low_corner  = min.(low_corner,pt)
        high_corner = max.(high_corner,pt)
    end
    return HyperRectangle(low_corner,high_corner)
end

center(rec::HyperRectangle) = (rec.low_corner + rec.high_corner) / 2
radius(rec::HyperRectangle) = diameter(rec) / 2


function merge(A,B)
    C = promote_type(eltype(A), eltype(B))[]
    i, j = 1, 1
    n, m = 1, 1
    while i <= length(A)  || j <= length(B)
        while i <= length(A) && ( A[i] <= B[m] || j > length(B))
            push!(C, A[i])
            i += 1
            n += 1
        end
        if n > length(A)
            n -= 1
        end
        while j <= length(B) && (B[j] <= A[n] || i > length(A))
            push!(C,B[j])
            j += 1
            m += 1
        end
        if m > length(B)
            m -= 1
        end
    end

    return C
end

function merge1(A,B)
    C = Vector{promote_type(eltype(A), eltype(B))}(undef, length(A) + length(B))
    k = 1
    i, j = 1, 1
    n, m = 1, 1
    while i <= length(A)  || j <= length(B)
        while i <= length(A) && ( A[i] <= B[m] || j > length(B))
            C[k] = A[i]
            i += 1
            n += 1
            k += 1
        end
        if n > length(A)
            n -= 1
        end
        while j <= length(B) && (B[j] <= A[n] || i > length(A))
            C[k] = B[j]
            j += 1
            m += 1
            k += 1
        end
        if m > length(B)
            m -= 1
        end
    end

    return C
end

function merge!(A, B, C)
    i, j, k = 1, 1, 1
    D = promote_type(eltype(A), eltype(B),eltype(C))[]
    while i <= length(A) || j <= length(B) || k <= length(C)
        min_El = typemax(promote_type(eltype(A), eltype(B),eltype(C)))
        if i <= length(A) && A[i] <= min_El
            min_El = A[i]
            determinator = 1
        end
        if j <= length(B) && B[j] <= min_El
            min_El = B[j]
            determinator = 2
        end
        if k <= length(C) && C[k] <= min_El
            min_El = C[k]
            determinator = 3
        end
        push!(D, min_El)
        if determinator == 1
            i += 1
        elseif  determinator == 2
            j += 1
        else
            k += 1
        end
    end
    C = D
    return C
end


using Interpolations

"""Return the reduced BCS gap deltar = delta(T)/delta(T=0).

Parameters
----------
temp : float
    The reduced temperature temp = T/Tc, where Tc is the superconducting critical temperature.

Returns
-------
dr : float
    The reduced superconducting energy gap delta(T)/delta(T=0).

Note
----
Tabulated data from Muhlschlegel (1959).
Low-temperature analytic formula from Gao (2008).
"""
function deltar_bcs(temp)

    #The BCS gap factor
    const bcs = 1.764

    #These data points run from t=0.18 to t=1
    #in steps of 0.02 from Muhlschlegel (1959)
    delta_calc = [1.0, 0.9999, 0.9997, 0.9994, 0.9989,
           0.9982, 0.9971, 0.9957, 0.9938, 0.9915,
           0.9885, 0.985,  0.9809, 0.976,  0.9704,
           0.9641, 0.9569, 0.9488, 0.9399, 0.9299,
           0.919,  0.907,  0.8939, 0.8796, 0.864,
           0.8471, 0.8288, 0.8089, 0.7874, 0.764,
           0.7386, 0.711,  0.681,  0.648,  0.6117,
           0.5715, 0.5263, 0.4749, 0.4148, 0.3416,
           0.2436, 0.0]

    if 1.0 > temp >= 0.3
        #interpolate data from table
        #Get temperature "index"
        tindx = (temp-0.18)/0.02+1

        #Build interpolating object and get value
        interp_dr = interpolate(delta_calc, BSpline(Cubic(Flat())), OnGrid())
        dr = interp_dr[tindx]

    elseif temp >= 1.0 || temp < 0.0
        dr = 0.0
    elseif temp < 0.005
        dr = 1.0
    else
        #This expression does a nice job of smoothely connecting the table to zero temp
        #Taken from Gao 2008
        dr = exp(-sqrt(2*bcs*temp)*exp(-bcs/temp))
    end

    return dr
end

"""Return the approximated reduced BCS gap deltar = delta(T)/delta(T=0).

Parameters
----------
temp : float
    The reduced temperature temp = T/Tc, where Tc is the superconducting critical temperature.

Returns
-------
dr : float
    The reduced superconducting energy gap delta(T)/delta(T=0).

Note
----
Cosine approximation for gap taken from Pöpel (1989)."""
function deltar_cos(temp)
    if temp < 1
        return sqrt(cos(0.5*π*temp^2))
    else
        return 0.0
    end
end


# The order of the numerator polynomial in z = \omega^2 that we need to
# see if it has any zeros:
using Polynomials

function sturms_theorem(x)
n_lor = round(Int, length(x)/4)
pord = 2*(n_lor-1) + 1
# Compute coefficients in the numerator & denominator of PSD:
# The PSD is given by:
#
# \sum_i (a_i z +b_i)/(z^2 + c_i*z + d_i)
#
# where z = \omega^2
#
# We are computing the number of positive real zeros of this equation.
#

# Now, loop over coefficients:

a = zeros(n_lor)
b = zeros(n_lor)
c = zeros(n_lor)
d = zeros(n_lor)

for i=1:n_lor
  ar_j = x[(i-1)*4+1]
  ai_j = x[(i-1)*4+2]
  br_j = x[(i-1)*4+3]
  bi_j = x[(i-1)*4+4]
  a[i] = ar_j*br_j-ai_j*bi_j
  b[i] = (bi_j^2+br_j^2)*(ai_j*bi_j+ar_j*br_j)
  c[i] = 2*(br_j^2-bi_j^2)
  d[i] = (bi_j^2+br_j^2)^2
end

# Initialize a polynomial:
p0 = Poly(zeros(pord+1))
for i=1:n_lor
# The polynomial for the current Lorentzian term in the common-denominator expression:
  pcur = Poly([b[i],a[i]])
  for j=1:n_lor
# Only multiply by the denominators from the other Lorentzians:
    if j != i
      pcur *= Poly([d[j],c[j],1])
    end
  end
  p0 += pcur
end

# Compute the roots of this polynomial:
#poly_root = roots(p0)

# Now that we've computed coefficients of the polynomial, we just need
# to apply Sturm's theorem!

# Set up an array to hold signs of polynomial at zero & infinity:
f_of_0 = zeros(pord+1)
f_of_inf = zeros(pord+1)

# Take the derivative of the polynomial:
p1 = polyder(p0)
#println(p0)
#println(p1)
# Insert the coefficients of the z^0 term:
f_of_0[1] = p0(0)
f_of_0[2] = p1(0)
# Insert the coefficient of the z^(p_ord-i) term:
f_of_inf[1] = p0[pord]
f_of_inf[2] = p1[pord-1]

# Now, loop over the Sturm polynomial series:
for i=3:pord+1
  p2 = -rem(p0,p1)
# Check that round-off error hasn't left us with a polynomial
# that is the same order as p0 or p1, but with a small coefficient:
  if length(p2) >= length(p1)
    coeff = zeros(pord-i+2)
    for j=0:pord-i+1
      coeff[j+1]=p2[j]
    end
    p2 = Poly(coeff)
  end
# Insert the z^0 term:
  f_of_0[i]=p2(0)
# Insert the z -> \infty term:
  f_of_inf[i]=p2[pord-i+1]
# Now move promote these polynomials, readying them for recursion in the next step:
  p0=copy(p1)
  p1=copy(p2)
end

# Now we'll compute the number of sign changes at z=0:
sig_0 = 0
for i=1:pord
#  if f_of_0[i+1]*f_of_0[i] < 0 && abs(f_of_0[i+1]) > eps() && abs(f_of_0[i]) > eps()
  if sign(f_of_0[i+1]) != sign(f_of_0[i])
    sig_0 +=1
  end
end
# Next, compute the number of sign changes at z=\infty:
sig_inf = 0
for i=1:pord
#  if f_of_inf[i+1]*f_of_inf[i] < 0 && abs(f_of_inf[i+1]) > eps() && abs(f_of_inf[i]) > eps()
  if sign(f_of_inf[i+1]) != sign(f_of_inf[i])
    sig_inf +=1
  end
end

# The difference between z=0 & z=\infty gives the number of positive, real roots:
#println("Number of positive, real roots: ",sig_0-sig_inf)

# Print out the actual roots for inspection:
#println("Roots: ",poly_root)

# Now, determine which roots are positive & real from the numerial solver:
n_pos_real = sig_0-sig_inf
return n_pos_real
end


"""
    Double integrator
"""

struct DoubleIntegrator
    n::Int
    m::Int
    d::Int
end

function fd(model::DoubleIntegrator, x⁺, x, u, w, h, t)
    x⁺ - [x[1] + x[2] + w[1]; x[2] + u[1] + w[2]]
end

function get_dynamics(model::DoubleIntegrator)
    A = @SMatrix [1.0 1.0; 0.0 1.0]
    B = @SMatrix [0.0; 1.0]

    return A, B
end

n, m, d = 2, 1, 2
model = DoubleIntegrator(n, m, d)


url = "http://vincentarelbundock.github.io/Rdatasets/csv/quantreg/engel.csv"
Data = CSV.read(download(url))

out_ip = qreg(@formula(foodexp~income), Data, IP())
out_irls = qreg(@formula(foodexp~income), Data, IRLS())

@test norm( out_ip.model.beta - [81.4822; 0.560181]) < 1e-4
@test norm( out_irls.model.beta - [81.4823; 0.560181]) < 1e-4

#=
...... Interior point ......
TableRegressionModel{QRegModel,Float64}:

Coefficients:
             Estimate Std.Error t value
(Intercept)   81.4822   14.6345 5.56783
income       0.560181 0.0131756 42.5164

.......... IRLS ............
TableRegressionModel{QRegModel,Float64}:

Coefficients:
             Estimate Std.Error t value
(Intercept)   81.4823   14.6345 5.56783
income       0.560181 0.0131756 42.5164
=#


"""
get_cost_matrix_separated(n, d; a=0, b=0)
n: number of discretization points along one dimension
a: left interval bound
b: right interval bound

returns cost matrix C in separated form as a dx(nxn) vector of matrices

TODO: non-cube-domains, different n along every dimension
"""
function get_cost_matrix_separated(n, d; a=zeros(d), b=ones(d))
    c = [zeros(n,n) for _ in 1:d]
    for k in 1:d
        x₁ = range(a[k],b[k],length=n)
        for i in 1:n
            for j in 1:n
                c[k][i,j] = sqeuclidean(x₁[i],x₁[j])
            end
        end
    end
    return c
end

function get_cost_matrix_separated_periodic(n, d; a=zeros(d), b=ones(d))
    c = [zeros(n,n) for _ in 1:d]
    for k in 1:d
        x₁ = range(a[k],b[k],length=n)
        for i in 1:n
            for j in 1:n
                c[k][i,j] = minimum([sqeuclidean(x₁[i],x₁[j]), sqeuclidean(x₁[i]+b[k]-a[k],x₁[j]),
                                        sqeuclidean(x₁[i]-b[k]+a[k],x₁[j])] )
            end
        end
    end
    return c
end

function get_cost_matrix_separated_halfperiodic(n, d; a=zeros(d), b=ones(d))
    c = [zeros(n,n) for _ in 1:2]
    for k in 1:2
        x₁ = range(a[k],b[k],length=n)
        for i in 1:n
            for j in 1:n
                if k == 1
                    c[k][i,j] = minimum([sqeuclidean(x₁[i],x₁[j]), sqeuclidean(x₁[i]+b[k]-a[k],x₁[j]),
                                        sqeuclidean(x₁[i]-b[k]+a[k],x₁[j])] )
                else
                    c[k][i,j] = sqeuclidean(x₁[i],x₁[j])
                end
            end
        end
    end
    return c
end

function get_gibbs_matrix(c::Vector{<: AbstractMatrix{T}}, ε) where T
    n = size(c[1],1)
    k = [zeros(T,n,n) for _ in 1:length(c)]
    for i in eachindex(c)
        k[i] .= get_gibbs_matrix(c[i], ε)
    end
    return k
end

"""
get_cost_matrix(c)

c: separated cost matrix as a dx(nxn) vector of matrices

returns cost matrix C in non-separated form as a NxN matrix

TODO: different n along every dimension, d > 2
"""
function get_cost_matrix(c)
    d = length(c)
    n, n = size(c[1])

    if d == 1
        return c[1]
    elseif d > 2
        error("unimplemented")
    else

        C = zeros(n^2,n^2)

        for i1 in 1:n
            for i2 in 1:n
                i = (i1-1)*n + i2
                for j1 in 1:n
                    for j2 in 1:n
                        j = (j1-1)*n + j2
                        C[i,j] = c[1][i1,j1] + c[2][i2,j2]
                    end
                end
            end
        end
        return C
    end
end

function get_gibbs_matrix(C::AbstractMatrix, ε)
    return exp.(-C./ε)
end

struct LazyCost{T,V,FT} <: AbstractMatrix{T}
    x::Matrix{T}
    y::Matrix{V}
    c::FT

    function LazyCost(x::Matrix{T}, y::Matrix{V}, c::FT = (x,y) -> sqeuclidean(x,y) ) where {T, V, FT <: Base.Callable}
        new{T,V,FT}(x,y,c)
    end
end

Base.getindex(C::LazyCost{T,V}, i, j) where {T,V} = @views C.c(C.x[i,:], C.y[j,:])::promote_type(T,V)
Base.size(C::LazyCost) = (size(C.x,1), size(C.y,1))


## Diversity Measures

function shannon(v::AbstractVector{T}) where T<:Real
    total = sum(v)
    relab = map(x-> x/total, v)
    return -sum([log(x^x) for x in relab])
end

function shannon(abt::AbstractComMatrix)
    return shannon.(eachcol(occurrences(abt)))
end

function ginisimpson(v::AbstractVector{T}) where T<:Real
    total = sum(v)
    relab = map(x-> x/total, v)
    return 1 - sum([x^2 for x in relab])
end

function ginisimpson(abt::AbstractComMatrix)
    return ginisimpson.(eachcol(occurrences(abt)))
end


function sel(n::Int64)
    return list -> list[n]
end

S1 = sel(1)
S2 = sel(2)
S3 = sel(3)

S1([1,2,3])

function larBernsteinBasis(u::Function, n::Int64)
    function map_fn(x::Array{Float64,1})
        bernstein(i, n, t::Float64) = binomial(n,i)*(1-t)^(n-i)*t^i
        return [bernstein(i, n, u(x)) for i in 0:n]
    end
    return map_fn
end

function larTensorProdSurface{F<:Function, T<:Real}(args::Array{F, 1},
                            controlpoints::Array{Array{Array{T, 1}, 1}, 1})
    ubasis , vbasis = args
    function map_fn(point::Array{Float64, 1})
        u, v = point
        U = ubasis([u])
        V = vbasis([v])
        target_dim = length(controlpoints[1][1])
        ret = zeros(Float64, target_dim)
        dim_u = length(U)
        dim_v = length(V)
        if (length(controlpoints)!= dim_u || length(controlpoints[1])!= dim_v)
            error("Invalid set of control points for those bases!")
        end
        for i in 1:dim_u
            for j in 1:dim_v
                #for M in 1:target_dim
                    for M in 1:target_dim
                        ret[M] += U[i]*V[j]*controlpoints[i][j][M]
                    end
                #end
            end
        end
        return ret
    end
    return map_fn
end

function larBilinearSurface(controlpoints)
   basis = larBernsteinBasis(sel(1), 1)
   return larTensorProdSurface([basis, basis], controlpoints)
end

function larBiquadraticSurface(controlpoints)
   basis1 = larBernsteinBasis(sel(1), 2)
   basis2 = larBernsteinBasis(sel(1), 2)
   return larTensorProdSurface([basis1,basis2], controlpoints)
end

function larBicubicSurface(controlpoints)
   basis1 = larBernsteinBasis(sel(1), 3)
   basis2 = larBernsteinBasis(sel(1), 3)
   return larTensorProdSurface([basis1, basis2], controlpoints)
end

function larBezier{T<:Real}(u::Function, controldata::Array{Array{T,1},1})
    n = length(controldata) - 1
    dim = length(controldata[1])
    function map_fn(point::Array{Float64, 1})
        t = u(point)
        out = zeros(Float64, dim)
        for i in 0:n
            weight = binomial(n,i)*(1-t)^(n-i)*t^i
            for k in 1:dim
                out[k] += weight*controldata[i+1][k]
            end
        end
        return out
     end
    return map_fn
end

function larBezierCurve(controlpoints)
   return larBezier(sel(1), controlpoints)
end

function larCoonsPatch{T<:Function}(args::Array{T, 1})
    su0_fn , su1_fn , s0v_fn , s1v_fn = args
    function map_fn(point)
        u, v = point
        su0 = su0_fn(point)
        su1 = su1_fn(point)
        s0v = s0v_fn(point)
        s1v = s1v_fn(point)
        ret = zeros(Float64, length(su0))
        for k in 1:length(ret)
            ret[k] = ((1-u)*s0v[k] + u*s1v[k]+(1-v)*su0[k] + v*su1[k] +
                     (1-u)*(1-v)*s0v[k] + (1-u)*v*s0v[k] + u*(1-v)*s1v[k] + u*v*s1v[k])
        end
        return ret
    end
    return map_fn
end

function bsplineBasis{T<:Real}(degree::Int64, knots::Array{T,1}, ncontrols::Int64)
    n = ncontrols - 1
    m = length(knots) - 1
    k = degree + 1
    tmin, tmax = knots[k-1], knots[n+1]
    if length(knots)!=(n+k+1)
        error("Invalid point/knots/degree for bspline!")
    end
    # de Boor coefficients
    function deBoor(i::Int64, k::Int64, t::Float64)
        # deBoor coefficient Ni1(t)
        if k == 1
            if(t >= knots[i] && t<knots[i+1]) || (t == tmax && t>=knots[i] && t<=knots[i+1])
                # t in [T_i, T_(i+1)) vel t=T_(n+1) in [T_i, T_(i+1)]
                return 1
            else
                return 0
            end
        end
        # deBoor coefficient Nik(t)
        ret = 0
        num1, div1 = t-knots[i], knots[i+k-1]-knots[i]
        if div1 != 0
            ret += (num1/div1) * deBoor(i,k-1,t)
        end
        num2, div2 = knots[i+k]-t, knots[i+k]-knots[i+1]
        if div2 != 0
            ret += (num2/div2) * deBoor(i+1,k-1,t)
        end
        return ret
    end
    # map function
    function map_fn{T<:Real}(point::Array{T, 1})
        t = point[1]
        return [deBoor(i,k,t) for i in 1:n+1]
    end
    return map_fn
end

function t_bspline{T<:Real, F<:Function}(u::Function, degree::Int64, knots::Array{T,1},
                                    points_fn::Array{F, 1})

    n = length(points_fn)-1
    m = length(knots)-1
    k = degree + 1
    tmin,tmax = knots[k-1], knots[n+1]

    # see http://www.na.iac.cnr.it/~bdv/cagd/spline/B-spline/bspline-curve.html
    if length(knots)!=(n+k+1)
        error("Invalid point/knots/degree for bspline!")
    end
    # de Boor coefficients
    function deBoor(i::Int64, k::Int64, t::Float64)
        # Ni1(t)
        if k == 1
            if(t>=knots[i] && t<knots[i+1]) || (t==tmax && t>=knots[i] && t<=knots[i+1])
                # i use strict inclusion for the max value
                return 1
            else
                return 0
            end
        end
        # Nik(t)
        ret = 0

        num1, div1 = t-knots[i], knots[i+k-1]-knots[i]
        if div1 != 0
            ret+=(num1/div1) * deBoor(i,k-1,t)
            # elif num1!=0: ret+=deBoor(i,k-1,t)
        end

        num2, div2 = knots[i+k]-t, knots[i+k]-knots[i+1]
        if div2!=0
            ret+=(num2/div2) * deBoor(i+1,k-1,t)
            # elif num2!=0: ret+=deBoor(i,k-1,t)
        end

        return ret
    end

    # map function
    function map_fn(point::Array{Float64, 1})
        t = u(point)
        # if control points are functions
        #points = point -> [f(point) for f in points_fn]    #POSSIBILE ERRORE QUI
        target_dim = length(points_fn[1](point))    #errore qui
        ret = zeros(Float64, target_dim)
        for i in 1:n+1
            coeff = deBoor(i,k,t)
            for m in 1:target_dim
                ret[m] += points_fn[i](point)[m] * coeff
            end
        end
        return ret
    end
    return map_fn
end

function t_nurbs{T<:Real, F<:Function}(u::Function, degree::Int64, knots::Array{T,1},
                                       points::Array{F, 1})
    bspline = t_bspline(u, degree, knots, points)
    function map_fn(point)          #eliminare
        ret = bspline(point)
        last = ret[end]  #last element in ret
        if last != 0
            ret = [value/last for value in ret]
        end
        ret = ret[1:end-1] #it slices off the last element (that is now 1)
        return ret
    end
    return map_fn
end


using ApproxFun, Test, DualNumbers
    import ApproxFun: eigs

@testset "Extras" begin
    @testset "Dual numbers" begin
        @test dual(1.5,1) ∈  Segment(dual(1.0,1),dual(2.0))

        f=Fun(exp,Segment(dual(1.0,1),dual(2.0)),20)
        @test Fun(h->Fun(exp,Segment(1.0+h,2.0)).coefficients[1],0..1)'(0.) ≈ DualNumbers.epsilon(f.coefficients[1])

        ud=let d= Segment(dual(0.0,1.0),1.0)
            B = ldirichlet(d)
            D = Derivative(d)
            a = Fun(exp,d)
            u = [B;D+dual(1.0,4.0)*a] \ [dual(1.0,2.0),0.0]
            u(0.5)
        end

        u0=let d= Segment(0.0,1.0)
            B = ldirichlet(d)
            D = Derivative(d)
            a = Fun(exp,d)
            u = [B;D+a] \ [1.0,0.0]
            u(0.5)
        end
        h=0.00001
        uh=let d= Segment(h,1.0)
            B = ldirichlet(d)
            D = Derivative(d)
            a = Fun(exp,d)
            u = [B;D+(1+4h)*a] \ [1.0+2h,0.0]
            u(0.5)
        end

        @test absdual(ud - dual(u0,(uh-u0)/h)) ≤ h

        let d=Segment(0.0,1.0)
            B = ldirichlet(d)
            D = Derivative(d)
            a = Fun(exp,d)
            u = [B;D+a] \ [dual(1.0,2.0),0.0]
            ur = [B;D+a] \ [1.0,0.0]
            ud = [B;D+a] \ [2.0,0.0]
            @test absdual(u(0.5)  - dual(ur(0.5),ud(0.5))) < 10eps()
        end
    end

    @testset "Eig test #336" begin
        d = 0..π
        A=Derivative(d)^2
        λ=eigvals(Dirichlet(d),A,100)
        @test sort(λ)[end-5:end] ≈ -(-6:-1).^2
        λ=eigvals(Dirichlet(), A, 100)
        @test sort(λ)[end-5:end] ≈ -(-6:-1).^2

        F = x->x^8
        d = Interval(0.0,1.0)
        f = Fun(F,d)
        ginf = Fun(x->exp(-x),d)
        gp = ginf'
        Af = Fun(x->x+f(x),d)
        transport_ = Fun(x-> x - 1,d)
        damping = Fun(x-> 1 - f(x),d)
        A = transport_*Derivative(d) + damping
        P = -DefiniteIntegral(Chebyshev(d))[LowRankFun((x,y)->gp(x)*(y+f(y)),d^2)];
        λ,V = eigs(A,100)
        @test norm(sort(real(filter(x->isreal(x),λ)))[1:5]-(0:4)) ≤ 100000eps()

        λ,V = eigs(A+P,100)
        @test sort(real(filter(x->isreal(x),λ)))[5] ≈ 3.93759261234502 atol=1E-3
    end

    @testset "Sampling" begin
        ff=(x,y)->(x-y)^2*exp(-x^2/2-y^2/2)

        f=Fun(ff,Domain(-4..4)^2)
        r=ApproxFun.sample(f,5000)

        #We can compare the histogram to the 1-point correlation
        g=sum(f,1)/sum(f)
        @test  g(0.1) ≈ 0.2004758624973169

        # check bisection inv
        f = Fun(x -> exp(-x^2/2),-5..5)
        g = cumsum(f)
        @test g(ApproxFun.bisectioninv(g,0.5)) ≈ 0.5
    end

    @testset "findmin/max" begin
        f = Fun(x -> exp(0.25x) + sin(x) + 0.5cos(10x), -4..4)
        @test [findmax(f)...] ≈ [3.0531164509549584, 1.886754631165656]
        @test [findmin(f)...] ≈ [-0.825047261209411, -1.5741041425422948]
    end
end


using Images

function filter_gauss_localsigma(image, mask_order::Number=3, c::Number=0.05)

  # Checks if the mask is right
  if mod(mask_order,2)!=1
    error("The input value for the mask order must be an odd number >=3.")
  end

  # Stores the input image's type and convert it into a matrix
  tipo = typeof(image)
  try
    image = convert(Array{Float32}, image)
  catch er
    error(er," --- Problem converting the single band image into an array.")
  end

  # Takes the image's dimensions and creates 'a' (a variable to help in the convolution)
  d = size(image)
  a = floor(Int,mask_order/2)

  # Variables to receive the masks created and the filtered image
  mask = Matrix(mask_order,mask_order)
  img1 = Matrix(d[1]-mask_order+1,d[2]-mask_order+1)

  # the convolution process itself
  for i = (a+1):(d[1]-a)
    for j = (a+1):(d[2]-a)

      ai=i-a;
      ia=i+a;
      aj=j-a;
      ja=j+a;

      σ = (c/std(image[ai:ia,aj:ja], corrected=true))^2

      if σ==0.0 || (1/(2*pi*σ^2))==0.0
        mask[:,:] = 0.0
        mask[a+1,a+1] = 1.0
      else
        for x=-a:a
          for y=-a:a
            mask[x+a+1,y+a+1] = convert(Float32,exp(-(x^2 + y^2)/(2*(σ^2))))
          end
        end
        mask = mask/sum(mask)
      end

      img1[i-a,j-a] = convert(Float32,sum(mask.*image[ai:ia,aj:ja]))

      if img1[i-a,j-a] > 1.0
          img1[i-a,j-a] = 1.0
      end
    end
  end

  # Converts the filtered image to the same input image type
  img1 = convert(tipo, img1)

  # Returns the result image and end of the function
  return(img1)
end


using FFTW
using LaTeXStrings
using Printf
using PyPlot

function dsdemo2()
    println("Discrete-Time Simulation")

    fig = figure(1)
    fig.clf()
    fig.canvas.set_window_title("Modulator Input & Output")

    OSR = 32
    H = synthesizeNTF(5, OSR, 1)
    N = 8192
    fB = ceil(Int, N/(2*OSR));
    ftest = floor(Int, 2/3*fB);
    u = 0.5 * sin.(2*pi*ftest/N * (0:N-1))
    v, = simulateDSM(u, H)
    t = 0:100

    step(t, u[t.+1], color="r", linewidth=1)
    step(t, v[t.+1], color="g", linewidth=1)
    axis([0, 100, -1.2, 1.2])
    xlabel("Sample Number")
    ylabel("u, v")

    print("paused")
    readline()

    fig = figure(2)
    fig.clf()
    fig.canvas.set_window_title("Output Spectrum")

    f = range(0, 0.5; length=N÷2+1)
    spec = fft(v .* ds_hann(N) / (N/4))

    plot(f, dbv(spec[1:N÷2+1]), color="b", linewidth=1)
    figureMagic([0, 0.5], 0.05, 2, [-120, 0], 20, 1)
    xlabel("Normalized Frequency")
    ylabel("dBFS")

    print("paused")
    readline()

    snr = calculateSNR(spec[3:fB+1], ftest-2)

    text(0.05, -10, @sprintf("SNR = %4.1fdB @ OSR = %d", snr, OSR))

    print("paused")
    readline()

    NBW = 1.5 / N
    Sqq = 4 * evalTF(H, exp.(2*im*pi*f)).^2 / 3

    plot(f, dbp(Sqq*NBW), color="m", linewidth=2)
    text(0.5, -90, string(@sprintf("NBW = %4.1E × ", NBW), L"f_s"), ha="right")
    legend(["Simulation", "Expected PSD"])

    print("paused")
    readline()

    fig = figure(3)
    fig.clf()
    fig.canvas.set_window_title("SQNR")

    snr_pred, amp_pred = predictSNR(H, OSR)
    snr, amp = simulateSNR(H, OSR)
    pk_snr, pk_amp = peakSNR(snr, amp)

    plot(amp_pred, snr_pred, linewidth=1)
    plot(amp, snr, color="g", linestyle="None", marker="o", markerfacecolor="none", markeredgewidth=0.5)
    text(-25, 85, @sprintf("peak SNR = %4.1fdB\n@ OSR = %d\n", pk_snr, OSR), ha="right")
    figureMagic([-100, 0], 10, 1, [0, 100], 10, 1)
    xlabel("Input Level (dBFS)")
    ylabel("SQNR (dB)")

    println("paused")
    readline()

    println("Bandpass Modulator")

    fig = figure(1)
    fig.clf()

    f0 = 1/8
    OSR = 64
    H = synthesizeNTF(8, OSR, 1, 1.5, f0)
    fB = ceil(Int, N/(2*OSR))
    ftest = round(Int, f0*N + 1/3*fB)
    u = 0.5 * sin.(2*pi*ftest/N * (0:N-1))   # half-scale sine-wave input
    v, = simulateDSM(u, H)
    t = 0:100

    step(t, u[t.+1], color="r", linewidth=1)
    step(t, v[t.+1], color="g", linewidth=1)
    axis([0, 100, -1.2, 1.2])
    xlabel("Sample Number")
    ylabel("u, v")

    fig.canvas.manager.window.raise_()

    print("paused")
    readline()

    fig = figure(2)
    fig.clf()

    f = range(0, 0.5; length=N÷2+1)
    spec = fft(v .* ds_hann(N) / (N/4))
    f1 = round(Int, (f0-0.25/OSR)*N)
    f2 = round(Int, (f0+0.25/OSR)*N)
    snr = calculateSNR(spec[f1:f2], ftest-f1+1)

    plot(f, dbv(spec[1:N÷2+1]), color="b", linewidth=1)
    text(0.15, -10, @sprintf("SNR = %4.1fdB @ OSR = %d", snr, OSR))
    figureMagic([0, 0.5], 0.05, 2, [-140, 0], 20, 1)
    xlabel("Normalized Frequency")
    ylabel("dBFS")

    fig.canvas.manager.window.raise_()

    print("paused")
    readline()

    NBW = 1.5/N
    Sqq = 4 * evalTF(H, exp.(2*im*pi*f)).^2 / 3

    plot(f, dbp(Sqq*NBW), color="m", linewidth=2)
    text(0.5, -90, string(@sprintf("NBW = %4.1E × ", NBW), L"f_s"), ha="right")
    legend(["Simulation", "Expected PSD"])

    print("paused")
    readline()

    fig = figure(3)
    fig.clf()

    snr_pred, amp_pred = predictSNR(H, OSR, [-120:10:-20; -15; -10:0], f0)
    snr, amp = simulateSNR(H, OSR, [-120:10:-20; -15; -10:0], f0)
    pk_snr, pk_amp = peakSNR(snr, amp)

    plot(amp_pred, snr_pred, linewidth=1)
    plot(amp, snr, color="g", linestyle="None", marker="o", markerfacecolor="none", markeredgewidth=0.5)
    text(-20, 95, @sprintf("peak SNR = %4.1fdB\n@ OSR = %d\n", pk_snr, OSR), ha="right")
    figureMagic([-110, 0], 10, 1, [0, 110], 10, 1)
    xlabel("Input Level (dBFS)")
    ylabel("SQNR (dB)")

    fig.canvas.manager.window.raise_()

    println("paused")
    readline()

    fig = figure(3)
    fig.clf()
    fig = figure(2)
    fig.clf()
    fig = figure(1)
    fig.clear()
    fig.canvas.set_window_title("Input & Output")
    fig.subplots_adjust(hspace=0.5)

    colors = ["m", "b"]
    Hinf_list = [2, 8]
    for i = 1:2
        Hinf = Hinf_list[i]
        col = colors[i]
        println("15-step 7th-order Lowpass")
        println("Hinf = $Hinf")

        fig = figure(1)

        OSR = 8
        M = 16
        H = synthesizeNTF(7, OSR, 1, Hinf)
        N = 8192
        fB = ceil(Int, N/(2*OSR))
        ftest = floor(Int, 2/7*fB)
        u = 0.5*M*sin.(2*pi*ftest/N*(0:N-1))
        v, = simulateDSM(u, H, M+1)
        t = 0:100

        subplot(2, 1, i)

        step(t, u[t.+1], color="g", linewidth=1)
        step(t, v[t.+1], color=col, linewidth=1)
        figureMagic([0, 100], 10, 2, [-M, M], 2, 4)
        xlabel("Sample Number")
        ylabel("u, v")

        fig.canvas.manager.window.raise_()

        print("paused")
        readline()

        fig = figure(2)

        f = range(0, 0.5; length=N÷2+1)
        spec = fft(v .* ds_hann(N) / (M*N/4))
        snr = calculateSNR(spec[3:fB+1], ftest-2)
        NBW = 1.5/N
        Sqq = 4 * evalTF(H, exp.(2*im*pi*f)).^2 / (3*M^2)

        plot(f, dbv(spec[1:N÷2+1]), color=col)
        plot(f, dbp(Sqq*NBW), color="c", linewidth=2)
        text(0.1, 10*(i-3), @sprintf("SNR = %4.1fdB @ OSR = %d", snr, OSR), color=col)
        if i == 1
            text(0.5, -110, string(@sprintf("NBW = %4.1E × ", NBW), L"f_s"), ha="right")
        end
        figureMagic([0, 0.5], 0.05, 2, [-160, 0], 20, 1)
        xlabel("Normalized Frequency")
        ylabel("dBFS")

        fig.canvas.manager.window.raise_()

        println("paused")
        readline()

        fig = figure(3)

        snr, amp = simulateSNR(H, OSR, vcat(-120:10:-20, -15, -10:0), 0, M+1)
        pk_snr, pk_amp = peakSNR(snr, amp)

        plot(amp, snr, color=col, linestyle="None", marker="o", markerfacecolor="none", markeredgewidth=0.5)
        plot(amp, snr, color=col, linestyle="--", linewidth=1)
        text(-13, pk_snr, @sprintf("peak SNR = %4.1fdB\n@ OSR = %d\n", pk_snr, OSR), fontsize=8, color=col, ha="right", va="top")
        figureMagic([-120, 0], 10, 2, [0, 120], 10, 2)
        xlabel("Input Level (dBFS)")
        ylabel("SQNR (dB)")

        fig.canvas.manager.window.raise_()
    end

    return nothing
end


include("euler/euler.jl")
using .Primes: prime_sieve

function compute()::Int
    sieve = prime_sieve(1_000_000)
    primes = findall(sieve)[5:end]
    truncatable, result = 0, 0
    for prime in primes
        p, is_truncatable = 10, true
        while p < prime
            if sieve[prime % p] && sieve[prime ÷ p]
                p *= 10
            else
                is_truncatable = false
                break
            end
        end
        if is_truncatable
            truncatable += 1
            result += prime
            if truncatable == 11
                break
            end
        end
    end
    return result
end


"""
    PlanarGradient <: NeutralLandscapeMaker

    PlanarGradient(; direction=360rand())
    PlanarGradient(direction)

This type is used to generate a planar gradient landscape, where values change
as a bilinear function of the *x* and *y* coordinates. The direction is
expressed as a floating point value, which will be in *[0,360]*. The inner
constructor takes the mod of the value passed and 360, so that a value that is
out of the correct interval will be corrected.
"""
@kwdef struct PlanarGradient <: NeutralLandscapeMaker
    direction::Float64 = 360rand()
    PlanarGradient(x::T) where {T <: Real} = new(mod(x, 360.0))
end

function _landscape!(mat, alg::PlanarGradient) where {IT <: Integer}
    eastness = sin(deg2rad(alg.direction))
    southness = -1cos(deg2rad(alg.direction))
    rows, cols = axes(mat)
    mat .= southness .* rows .+ (eastness .* cols)'
    return mat
end


@test all(CircleFit.BCD_to_abr(CircleFit.abr_to_BCD(3.0,4.0,6.0)...) .≈ (3.0,4.0,6.0))

x0 = 1.0
y0 = 2.0
n = 20
r0 = 5
p = r0 .*exp.(im.*range(0,2π,length=n))
x = real(p) .+ x0
y = imag(p) .+ y0
(a,b,r) = CircleFit.GRAF(x,y,[1.0,1.0,1.0])
@test a ≈ x0
@test b ≈ y0
@test r ≈ r0

(a,b,r) = coef(fit(Circle,x,y,alg=:graf))
@test a ≈ x0
@test b ≈ y0
@test r ≈ r0


# ---
# title: 1620. Coordinate With Maximum Network Quality
# id: problem1620
# author: Tian Jun
# date: 2020-10-31
# difficulty: Medium
# categories: Greedy
# link: <https://leetcode.com/problems/coordinate-with-maximum-network-quality/description/>
# hidden: true
# ---
#
# You are given an array of network towers `towers` and an integer `radius`,
# where `towers[i] = [xi, yi, qi]` denotes the `ith` network tower with location
# `(xi, yi)` and quality factor `qi`. All the coordinates are **integral
# coordinates** on the X-Y plane, and the distance between two coordinates is
# the **Euclidean distance**.
#
# The integer `radius` denotes the **maximum distance** in which the tower is
# **reachable**. The tower is **reachable** if the distance is less than or
# equal to `radius`. Outside that distance, the signal becomes garbled, and the
# tower is **not reachable**.
#
# The signal quality of the `ith` tower at a coordinate `(x, y)` is calculated
# with the formula `⌊qi / (1 + d)⌋`, where `d` is the distance between the tower
# and the coordinate. The **network quality** at a coordinate is the sum of the
# signal qualities from all the **reachable** towers.
#
# Return _the integral coordinate where the **network quality** is maximum_. If
# there are multiple coordinates with the same **network quality** , return _the
# lexicographically minimum coordinate_.
#
# **Note:**
#
#   * A coordinate `(x1, y1)` is lexicographically smaller than `(x2, y2)` if either `x1 < x2` or `x1 == x2` and `y1 < y2`.
#   * `⌊val⌋` is the greatest integer less than or equal to `val` (the floor function).
#
#
#
# **Example 1:**
#
# ![](https://assets.leetcode.com/uploads/2020/09/22/untitled-diagram.png)
#
#
#
#     Input: towers = [[1,2,5],[2,1,7],[3,1,9]], radius = 2
#     Output: [2,1]
#     Explanation:
#     At coordinate (2, 1) the total quality is 13
#     - Quality of 7 from (2, 1) results in ⌊7 / (1 + sqrt(0)⌋ = ⌊7⌋ = 7
#     - Quality of 5 from (1, 2) results in ⌊5 / (1 + sqrt(2)⌋ = ⌊2.07⌋ = 2
#     - Quality of 9 from (3, 1) results in ⌊9 / (1 + sqrt(1)⌋ = ⌊4.5⌋ = 4
#     No other coordinate has higher quality.
#
# **Example 2:**
#
#
#
#     Input: towers = [[23,11,21]], radius = 9
#     Output: [23,11]
#
#
# **Example 3:**
#
#
#
#     Input: towers = [[1,2,13],[2,1,7],[0,1,9]], radius = 2
#     Output: [1,2]
#
#
# **Example 4:**
#
#
#
#     Input: towers = [[2,1,9],[0,1,9]], radius = 2
#     Output: [0,1]
#     Explanation: Both (0, 1) and (2, 1) are optimal in terms of quality but (0, 1) is lexicograpically minimal.
#
#
#
#
# **Constraints:**
#
#   * `1 <= towers.length <= 50`
#   * `towers[i].length == 3`
#   * `0 <= xi, yi, qi <= 50`
#   * `1 <= radius <= 50`
#
#
## @lc code=start
using LeetCode

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


include("../optimizers/linesearch.jl")
include("../utils/functions.jl")
include("../utils/plot.jl")

using Gadfly

# general function to plot the output of the algorithms
function plot_values(fx1, fx2, fx3, fx4, xlab, ylab, title)
    nsamps = length(fx1)
    nsamps2 = length(fx2)
    nsamps3 = length(fx3)
    nsamps4 = length(fx4)

    Gadfly.plot(layer(x=1:nsamps, y=fx1, Geom.line,
            Theme(default_color=color("blue"))),
        layer(x=1:nsamps2, y=fx2, Geom.line,
            Theme(default_color=color("red"))),
        layer(x=1:nsamps3, y=fx3, Geom.line,
            Theme(default_color=color("orange"))),
        layer(x=1:nsamps4, y=fx4, Geom.line,
            Theme(default_color=color("purple"))),
        Guide.xlabel(xlab), Guide.ylabel(ylab),
        Guide.title(title),
        Guide.manual_color_key("Legend",
            ["Newton", "steepest", "Newton-CG", "BFGS"],
            ["blue", "red", "orange", "purple"]),
        Scale.x_log10, Scale.y_log10)
end

@time xvals = line_search(fenton, [3.;4.],
    fenton_g, fenton_h, "newton", 1000);
@time svals = line_search(fenton, [3.;4.],
    fenton_g, fenton_h, "steepest", 1000);
@time cvals = line_search(fenton, [3.;4.],
    fenton_g, fenton_h, "newton_CG", 1000);
@time qvals = line_search(fenton, [3.;4.],
    fenton_g, fenton_h, "BFGS", 1000);

nsamps = length(xvals)
nsamps2 = length(svals)
nsamps3 = length(cvals)
nsamps4 = length(qvals)

fx = [fenton(xvals[i]) for i in 1:nsamps]
fx2 = [fenton(svals[i]) for i in 1:nsamps2]
fx3 = [fenton(cvals[i]) for i in 1:nsamps3]
fx4 = [fenton(qvals[i]) for i in 1:nsamps4]

plot_values(fx, fx2, fx3, fx4, "iteration", "f(x)", "Value of function")

grads = [norm(fenton_g(xvals[i]), 2) for i in 1:nsamps]
grads2 = [norm(fenton_g(svals[i]), 2) for i in 1:nsamps2]
grads3 = [norm(fenton_g(cvals[i]), 2) for i in 1:nsamps3]
grads4 = [norm(fenton_g(qvals[i]), 2) for i in 1:nsamps4]

r1 = compute_grad_ratio(grads)
r2 = compute_grad_ratio(grads2)
r3 = compute_grad_ratio(grads3)
r4 = compute_grad_ratio(grads4)

plot_values(r1, r2, r3, r4, "iteration",
    "gradient norm ratios", "gradient norm ratios")

plot_values(grads, grads2, grads3, grads4, "iteration",
    "gradient norms", "gradient norms")

@time xvals = line_search(rosenbrock, ones(100)*3, rosenbrock_g, rosenbrock_h,
    "newton", 2000, 1e-8);
@time svals = line_search(rosenbrock, ones(100)*3, rosenbrock_g, rosenbrock_h,
    "steepest", 5000, 1e-8);
@time cvals = line_search(rosenbrock, ones(100)*3, rosenbrock_g, rosenbrock_h,
    "newton_CG", 2000, 1e-8);
@time qvals = line_search(rosenbrock, ones(100)*3, rosenbrock_g, rosenbrock_h,
    "BFGS", 2000, 1e-8);

func = rosenbrock
func_g = rosenbrock_g

nsamps = length(xvals)
nsamps2 = length(svals)
nsamps3 = length(cvals)
nsamps4 = length(qvals)

fx = [func(xvals[i]) for i in 1:nsamps]
fx2 = [func(svals[i]) for i in 1:nsamps2]
fx3 = [func(cvals[i]) for i in 1:nsamps3]
fx4 = [func(qvals[i]) for i in 1:nsamps4]

plot_values(fx, fx2, fx3, fx4, "iteration", "f(x)", "Value of function")

nsamps = length(xvals)

grads = [norm(func_g(xvals[i]), 2) for i in 1:nsamps]
grads2 = [norm(func_g(svals[i]), 2) for i in 1:nsamps2]
grads3 = [norm(func_g(cvals[i]), 2) for i in 1:nsamps3]
grads4 = [norm(func_g(qvals[i]), 2) for i in 1:nsamps4]

r1 = compute_grad_ratio(grads)
r2 = compute_grad_ratio(grads2)
r3 = compute_grad_ratio(grads3)
r4 = compute_grad_ratio(grads4)

plot_values(r1, r2, r3, r4, "iteration", "gradient norm ratios",
    "gradient norm ratios")

plot_values(grads, grads2, grads3, grads4, "iteration", "gradient norms",
    "gradient norms")

@time xvals = line_search(cute, ones(100)*10, cute_g, cute_h, "newton",
    2000, 1e-8);
@time svals = line_search(cute, ones(100)*10, cute_g, cute_h, "steepest",
    2000, 1e-8);
@time cvals = line_search(cute, ones(100)*10, cute_g, cute_h, "newton_CG",
    2000, 1e-8);
@time qvals = line_search(cute, ones(100)*10, cute_g, cute_h, "BFGS",
    2000, 1e-8);

func = cute
func_g = cute_g

nsamps = length(xvals)
nsamps2 = length(svals)
nsamps3 = length(cvals)
nsamps4 = length(qvals)

fx = [func(xvals[i]) for i in 1:nsamps]
fx2 = [func(svals[i]) for i in 1:nsamps2]
fx3 = [func(cvals[i]) for i in 1:nsamps3]
fx4 = [func(qvals[i]) for i in 1:nsamps4]

plot_values(fx, fx2, fx3, fx4, "iteration", "f(x)", "Value of function")

grads = [norm(func_g(xvals[i]), 2) for i in 1:nsamps]
grads2 = [norm(func_g(svals[i]), 2) for i in 1:nsamps2]
grads3 = [norm(func(cvals[i]), 2) for i in 1:nsamps3]
grads4 = [norm(func_g(qvals[i]), 2) for i in 1:nsamps4]

r1 = compute_grad_ratio(grads)
r2 = compute_grad_ratio(grads2)
r3 = compute_grad_ratio(grads3)
r4 = compute_grad_ratio(grads4)

plot_values(r1, r2, r3, r4, "iteration", "gradient norm ratio",
    "gradient norm ratios")

plot_values(grads, grads2, grads3, grads4, "iteration", "gradient norm",
    "gradient norms")


##
## distance to ||⋅||_p ball of radius r
##
@with_kw mutable struct regularizer_distball <: Regularizer
    λ::Float64
    p::Float64
    r::Float64
end

function wholespace_manifold(reg::regularizer_distball, x)
    return Euclidean(size(x)...)
end

## 0th order
g(reg::regularizer_distball, x) = reg.λ * max(0.0, norm(x, reg.p) - reg.r)

## 1st order
function prox_αg!(reg::regularizer_distball, res, x, α)
    normxp = norm(x, reg.p)
    M = Euclidean(size(x)...)

    if normxp ≤ reg.r
        res .= x
    elseif reg.r < normxp ≤ reg.r + α
        res .= reg.r .* x ./ normxp
        M = PSphere(reg.p, reg.r, size(x)...)
    else
        res .= x .* (1 - α / normxp)
    end

    return M
end
function prox_αg(reg::regularizer_distball, x, α)
    res = zero(x)
    M = prox_αg!(reg, res, x, α)
    return res, M
end

# ∇M_g!(reg::regularizer_distball, ::l1Manifold, ∇M_g, x) = (@. ∇M_g = reg.λ * sign.(x))
# function ∇M_g(reg::regularizer_distball, M::l1Manifold, x)
#     ∇M_g = zeros(representation_size(M))
#     return ∇M_g!(reg, M, ∇M_g, x)
# end

# ## 2nd order
# ∇²M_g_ξ(::regularizer_distball, M::l1Manifold, x, ξ) = zeros(size(ξ))
# ∇²M_g_ξ!(::regularizer_distball, M::l1Manifold, res, x, ξ) = (res .= 0)


#=
Copyright (c) 2015, Intel Corporation
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice,
  this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
  this list of conditions and the following disclaimer in the documentation
  and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
=#

module TestKmeans
using ParallelAccelerator
using CompilerTools

#CompilerTools.OptFramework.set_debug_level(3)
#ParallelAccelerator.set_debug_level(3)
#ParallelAccelerator.DomainIR.set_debug_level(3)
#ParallelAccelerator.ParallelIR.set_debug_level(3)
#ParallelAccelerator.CGen.set_debug_level(3)

@acc function kmeans(iterations::Int64, points, numCenter)
    D,N = size(points) # number of features, instances
    centroids = Float64[convert(Float64,i+j) for i in 1:D, j in 1:numCenter]

    for l in 1:iterations
        dist::Array{Array{Float64,1},1} = [ Float64[sqrt(sum((points[:,i]-centroids[:,j]).^2)) for j in 1:numCenter] for i in 1:N]
        labels::Array{Int,1} = [indmin(dist[i]) for i in 1:N]
        centroids::Array{Float64,2} = [ sum(points[j,labels.==i])/sum(labels.==i) for j in 1:D, i in 1:numCenter]
    end
    return centroids
end

end

using Base.Test

points = [1. 2. 3. 4.; 4. 3. 2. 1.; 4. 5. 6. 7.]

println("Testing kmeans...")
@test_approx_eq TestKmeans.kmeans(10, points, 2) [1.5  3.5; 3.5  1.5; 4.5  6.5]
println("Done testing kmeans...")


using ApproxFun, LinearAlgebra, Plots

x = Fun(-20 .. 20)
V = abs(x)
D = Derivative()
S = ApproxFun.canonicalspace(space(V))
B = [Dirichlet(S); continuity(S,0:1)]
λ, v = ApproxFun.eigs(B, -D^2 + V, 500,tolerance=1E-10)

p = plot(V; legend=false)
    for k=1:20
        plot!(real(v[k]/norm(v[k]) + λ[k]))
    end
    p


using Gridap
using GridapGmsh

model = GmshDiscreteModel("demo/demo.msh")

order = 1
dirichlet_tags = ["boundary1","boundary2"]
u_boundary1(x) = 0.0
u_boundary2(x) = 1.0

reffe = ReferenceFE(lagrangian,Float64,order)
V = TestFESpace(model,reffe,dirichlet_tags=dirichlet_tags)
U = TrialFESpace(V,[u_boundary1,u_boundary2])

Ω = Triangulation(model)
dΩ = Measure(Ω,2*order)

a(u,v) = ∫( ∇(u)⋅∇(v) )dΩ
l(v) = 0

op = AffineFEOperator(a,l,U,V)
uh = solve(op)

writevtk(Ω,"demo",cellfields=["uh"=>uh])


module HeterogeneousAgentsContinuousTime

greet() = print("Hello World!")

using SparseArrays, LinearAlgebra, Plots

function HJBequation(r0, lambda2)
    #This function solves the HJB equation using the implicit method in Achdou et al (2017)
    #r0 is the interest rate and lambda2 the probability to pass to state 2

    #Maximum iterations
    maxiter=100
    #Tolerance
    tol=1e-6
    #Delta to calculate vprime
    delta=100

    #Price
    #r=0.03
    r=r0

    #Discount
    ρ=0.05

    #Parameter for the CRRA
    σ=2.0
    #Inverse of the marginal utility
    uprimeinv(x)=x^(-1/σ)
    #utility
    u(x)=(x^(1-σ))/(1-σ)
    #marginal utility
    uprime(x)=x^(-σ)

    z=[0.1,0.2]#States of the stochastic process
    Nz=length(z)

    #λ=[1.2,1.2]#Transition probabilities
    λ=[0.6,lambda2]#Transition probabilities

    amin=-0.15
    amax=4.0
    Na=500 #number of points in a
    a=[range(amin,stop=amax,length=Na);]
    deltaa=(amax-amin)/(Na-1) #Assumes that a is equally spaced

    #Create big vector with z
    zVec=[]
    for j=1:Nz
        zVec=[zVec;z[j]*ones(Na)]
    end

    v0=zeros(eltype(a),Na*Nz)
    for j=1:Nz
        v0[(j-1)*Na+1:j*Na]=((z[j].+max(r,0.01).*a).^(1-σ))/(1-σ)/ρ
    end

    #definition of the positions that are different from zero in the matrix A
    rows=[1:Na;Na+1:2*Na;1:2*Na;2:Na;Na+2:2*Na;1:Na-1;Na+1:2*Na-1]#Positions of \lambda1 and \lambda 2. Positions of y. Positions for x1. Positions for x2. Positions for z1. Positions for z2
    cols=[Na+1:2*Na;1:Na;1:2*Na;1:Na-1;Na+1:2*Na-1;2:Na;Na+2:2*Na]#Positions of \lambda1 and \lambda 2. Positions of y. Positions for x1. Positions for x2. Positions for z1. Positions for z2
    #Initialization of A
    valsA=ones(eltype(v0),length(rows))
    A=sparse(rows,cols,valsA)

    v1=zeros(eltype(a),Na*Nz)
    c=zeros(eltype(a),Na*Nz)
    s=zeros(eltype(a),Na*Nz)

    for i=1:maxiter
        vprimeF=ones(eltype(a),Na*Nz)
        vprimeB=ones(eltype(a),Na*Nz)
        for j=1:Nz
            vprimeF[(j-1)*Na+1:j*Na-1]=(v0[(j-1)*Na+2:j*Na].-v0[(j-1)*Na+1:j*Na-1])./deltaa #In the last position the forward difference is not defined
            vprimeF[j*Na]=(z[j] + r.*amax).^(-σ) #Will never be used, but just in case
            vprimeB[(j-1)*Na+2:j*Na]=(v0[(j-1)*Na+2:j*Na].-v0[(j-1)*Na+1:j*Na-1])./deltaa #In the first position the backward difference is not defined
            vprimeB[(j-1)*Na+1]=(z[j] + r.*amin).^(-σ) #state constraint boundary condition
        end
        sF=zeros(eltype(vprimeF),Na*Nz)
        sB=zeros(eltype(vprimeB),Na*Nz)

        ######CAREFUL. SOMETIMES VPRIME IS NEGATIVE, THIS ENSURES THIS DOESN'T HAPPEN
        vprimeF[vprimeF.<=0].=tol
        vprimeB[vprimeB.<=0].=tol

        for j=1:Nz
            for k=1:Na
                sF[(j-1)*Na+k]=z[j]+r*a[k]-uprimeinv(vprimeF[(j-1)*Na+k])
                sB[(j-1)*Na+k]=z[j]+r*a[k]-uprimeinv(vprimeB[(j-1)*Na+k])
            end
        end
        vprime=similar(vprimeF)
        for j=1:Nz
            for k=1:Na
                if sF[(j-1)*Na+k]>0
                    vprime[(j-1)*Na+k]=vprimeF[(j-1)*Na+k]
                elseif sB[(j-1)*Na+k]<0
                    vprime[(j-1)*Na+k]=vprimeB[(j-1)*Na+k]
                else
                    vprime[(j-1)*Na+k]=uprime(z[j]+r*a[k])
                end
            end
        end
        #Consumption
        c=uprimeinv.(vprime)

        #Calculation of savings
        s=zVec+r*repeat(a,Nz,1)-c
        b=u.(c)+v0/delta

        x=-sB/deltaa
        x[x.<=0].=0
        w=sF/deltaa #This is the z that goes in the matrix A. It has a conflict with the stochastic process
        w[w.<=0].=0
        #Making the first element of x (for each value of z) 0
        for j=1:Nz
            x[(j-1)*Na+1]=0
        end
        for j=1:Nz
            w[j*Na]=0
        end
        #Definition of y without substracting the probability lambda
        y=-x-w
        #Adjusting y by the probability lambda
        for j=1:Nz
            y[(j-1)*Na+1:j*Na]=y[(j-1)*Na+1:j*Na].-λ[j]
        end

        #Creation of matrix a
        #THIS MATRIX ASSUMES LENGTH(Z)=2
        valsA=vec([λ[1]*ones(eltype(λ[1]),Na,1);λ[2]*ones(eltype(λ[1]),Na,1);y;x[2:Na];x[Na+2:2*Na];w[1:Na-1];w[Na+1:2*Na-1]]) #vector with the values of A. \lambda1 and \lambda 2. Positions of y. Positions for x1. Positions for x2. Positions for z1. Positions for z2
        A=sparse(rows,cols,valsA)

        B=(1/delta+ρ)*I-A
        v1=B\b

        if maximum(abs.(v1-v0))<tol
            break
        end
        v0=copy(v1)
    end

    #p1=plot(a,[s[1:Na] s[Na+1:2*Na]],xlabel="Wealth",title="Savings",label=["y1" "y2"])
    #p2=plot(a,[c[1:Na] c[Na+1:2*Na]],xlabel="Wealth",title="Consumption",label=["y1" "y2"],legend=:topleft)
    #display(plot(p1,p2,layout=(1,2)))

    return (a=a,z=z,c=c,s=s,A=A,v=v0)
end

function KF(a,z,A)
    Na=length(a)
    deltaa=(a[Na]-a[1])/(Na-1)
    Nz=length(z)
    g=zeros(eltype(a),Nz*Na)
    zeroVec=zeros(eltype(a),Nz*Na) #Zero vector in equation 20 of the Numerical appendix
    zeroVec[1]=0.1
    (rowsA,colsA,valsA)=findnz(A) #retrieving rows, columns and values
    m,n=size(A)
    rowsAt=[colsA;ones(n)] #the columns of A and a vector of ones to change first row
    colsAt=[rowsA;collect(1:n)]
    valsAt=[valsA;1;zeros(eltype(a),n-1)]
    At=sparse(rowsAt,colsAt,valsAt)
    gtilda=At\zeroVec
    g=gtilda/(deltaa*sum(gtilda))

    #p1=plot(a[1:Na],g[1:Na],xlabel="Wealth",title="Distribution of agents",label=["y1" "y2"])
    #p2=plot!(a,g[Na+1:2*Na])
    #display(plot(p1,p2))

    return g
end

function AssetSupply()

    #Values to iterate over r
    rmin=-0.05
    rmax=0.04
    Nr=20
    vecr=[range(rmin,stop=rmax,length=Nr);]

    #Supply function
    S=zeros(eltype(vecr),Nr)

    lambda2=0.5

    for i in eachindex(vecr)
        results=HJBequation(vecr[i],lambda2)
        g=KF(results.a,results.z,results.A)
        Na=length(results.a)
        deltaa=(results.a[Na]-results.a[1])/(Na-1)
        S[i]=deltaa*sum(g.*repeat(results.a,2,1))
    end
    plot(S,vecr,xlabel="Net demand", ylabel="r", title="Asset supply", legend=false)
    plot!([0], seriestype="vline")
    #@show vecr
end

function equilibriumR(lambda2)
    #Calculates the equilibrium interest rate

    #Maximum r to consider
    rmax=0.04
    #Minimum r to consider
    rmin=0.01
    #weight of previous r
    wr=0.5

    r0=0.03 #Initial guess

    #Maximum iterations
    itermax=100
    tol=1e-6

    #Excess demand
    S=0

    #Transition probability
    #lambda2=1.2

    for i=1:itermax
        results=HJBequation(r0,lambda2)
        g=KF(results.a,results.z,results.A)
        Na=length(results.a)
        deltaa=(results.a[Na]-results.a[1])/(Na-1)
        S=deltaa*sum(g.*repeat(results.a,2,1))#Total supply
        #@show r0 rmin rmax S
        #@show results.c[1:10]
        if S>tol/100 #&& (rmax-rmin)>tol
            rmax=copy(r0)
            r0=wr*r0+(1-wr)*rmin
        elseif S<-tol/100 #&& (rmax-rmin)>tol #Excess demand
            rmin=copy(r0)
            r0=wr*r0+(1-wr)*rmax
        else
            break
        end
    end
    return r0
    #println(r0, S)
end

function TimeHJBequation(rl, resultsT,T,lambda2)
    #Given a time path for r (rl) between t=0 and t=T, it computes the value and policy functions for each t
    #resultsT are a tuple given by HJBequation which contains the results for the steady state (t=T)
    Nt=length(rl)
    deltat=T/Nt

    #Maximum iterations
    maxiter=100
    #Tolerance
    tol=1e-6

    #Discount
    ρ=0.05

    #Parameter for the CRRA
    σ=2.0
    #Inverse of the marginal utility
    uprimeinv(x)=x^(-1/σ)
    #utility
    u(x)=(x^(1-σ))/(1-σ)
    #marginal utility
    uprime(x)=x^(-σ)

    z=[0.1,0.2]#States of the stochastic process
    Nz=length(z)

    λ=[0.6,lambda2]#Transition probabilities

    amin=-0.15
    amax=4.0
    Na=500 #number of points in a
    a=[range(amin,stop=amax,length=Na);]
    deltaa=(amax-amin)/(Na-1) #Assumes that a is equally spaced

    #Create big vector with z
    zVec=[]
    for j=1:Nz
        zVec=[zVec;z[j]*ones(Na)]
    end

    v=zeros(eltype(a),Na*Nz,Nt+1)

    #Last v is the stationary state value function

    v[:,Nt+1]=resultsT.v

    #definition of the positions that are different from zero in the matrix A
    rows=[1:2*Na;1:2*Na;2:Na;Na+2:2*Na;1:Na-1;Na+1:2*Na-1]#Positions of \lambda1 and \lambda 2. Positions of y. Positions for x1. Positions for x2. Positions for z1. Positions for z2
    cols=[Na+1:2*Na;1:Na;1:2*Na;1:Na-1;Na+1:2*Na-1;2:Na;Na+2:2*Na]#Positions of \lambda1 and \lambda 2. Positions of y. Positions for x1. Positions for x2. Positions for z1. Positions for z2
    #Initialization of A
    valsA=ones(eltype(v),length(rows))
    #In this version A is a vector of sparse matrices
    #A=zeros(2*Na,2*Na,Nt+1)

    A=[]
    push!(A,resultsT.A)
    #A[:,:,Nt+1]=resultsT.A

    #Initialization of Atemp
    #Atemp=sparse(rows,cols,valsA)

    c=zeros(eltype(a),Na*Nz,Nt)
    s=zeros(eltype(a),Na*Nz,Nt)

    for i=Nt:-1:1
        vprimeF=ones(eltype(a),Na*Nz)
        vprimeB=ones(eltype(a),Na*Nz)
        for j=1:Nz
            vprimeF[(j-1)*Na+1:j*Na-1]=(v[(j-1)*Na+2:j*Na,i+1].-v[(j-1)*Na+1:j*Na-1,i+1])./deltaa #In the last position the forward difference is not defined
            vprimeF[j*Na]=(z[j] + rl[i].*amax).^(-σ) #Will never be used, but just in case
            vprimeB[(j-1)*Na+2:j*Na]=(v[(j-1)*Na+2:j*Na,i+1].-v[(j-1)*Na+1:j*Na-1,i+1])./deltaa #In the first position the backward difference is not defined
            vprimeB[(j-1)*Na+1]=(z[j] + rl[i].*amin).^(-σ) #state constraint boundary condition
        end
        sF=zeros(eltype(vprimeF),Na*Nz)
        sB=zeros(eltype(vprimeB),Na*Nz)

        ######CAREFUL. SOMETIMES VPRIME IS NEGATIVE, THIS ENSURES THIS DOESN'T HAPPEN
        vprimeF[vprimeF.<=0].=tol
        vprimeB[vprimeB.<=0].=tol

        for j=1:Nz
            for k=1:Na
                sF[(j-1)*Na+k]=z[j]+rl[i]*a[k]-uprimeinv(vprimeF[(j-1)*Na+k])
                sB[(j-1)*Na+k]=z[j]+rl[i]*a[k]-uprimeinv(vprimeB[(j-1)*Na+k])
            end
        end
        vprime=similar(vprimeF)

        for j=1:Nz
            for k=1:Na
                if sF[(j-1)*Na+k]>0
                    vprime[(j-1)*Na+k]=vprimeF[(j-1)*Na+k]
                elseif sB[(j-1)*Na+k]<0
                    vprime[(j-1)*Na+k]=vprimeB[(j-1)*Na+k]
                else
                    vprime[(j-1)*Na+k]=uprime(z[j]+rl[i]*a[k])
                end
            end
        end
        #Consumption
        c[:,i]=uprimeinv.(vprime)

        #Calculation of savings
        s[:,i]=zVec+rl[i]*repeat(a,Nz,1)-c[:,i]
        b=u.(c[:,i])+v[:,i+1]/deltat

        x=-sB/deltaa
        x[x.<=0].=0
        w=sF/deltaa #This is the z that goes in the matrix A. It has a conflict with the stochastic process
        w[w.<=0].=0
        #Making the first element of x (for each value of z) 0
        for j=1:Nz
            x[(j-1)*Na+1]=0
        end
        for j=1:Nz
            w[j*Na]=0
        end
        #Definition of y without substracting the probability lambda
        y=-x-w
        #Adjusting y by the probability lambda
        for j=1:Nz
            y[(j-1)*Na+1:j*Na]=y[(j-1)*Na+1:j*Na].-λ[j]
        end

        #Creation of matrix a
        #THIS MATRIX ASSUMES LENGTH(Z)=2
        #valsA=vcat(λ[1]*ones(eltype(λ[1]),Na,1),λ[2]*ones(eltype(λ[1]),Na,1),y,x[2:Na],x[Na+2:2*Na],w[1:Na-1],w[Na+1:2*Na-1]) #vector with the values of A. \lambda1 and \lambda 2. Positions of y. Positions for x1. Positions for x2. Positions for z1. Positions for z2
        valsA=vec([λ[1]*ones(eltype(λ[1]),Na,1);λ[2]*ones(eltype(λ[1]),Na,1);y;x[2:Na];x[Na+2:2*Na];w[1:Na-1];w[Na+1:2*Na-1]]) #vector with the values of A. \lambda1 and \lambda 2. Positions of y. Positions for x1. Positions for x2. Positions for z1. Positions for z2
        Atemp=sparse(rows,cols,valsA)

        B=(1/deltat+ρ)*I-Atemp
        v[:,i]=B\b
        pushfirst!(A,Atemp)
    end
    #@show typeof(A[:,:,3])
    return (a=a,z=z,c=c,s=s,A=A[1:end-1],v=v[:,1:Nt])
end

function TimeKF(a,z,A,g0,rl,T)
    #Calculates distribution over time period implied by rl. Taking g0 as initial distribution and A as the matrices at each period in time
    Na=length(a)
    deltaa=(a[Na]-a[1])/(Na-1)
    Nz=length(z)
    Nt=length(rl)
    deltat=T/Nt

    g=zeros(eltype(a),Nz*Na,Nt+1)
    g[:,1]=g0

    for i=2:Nt+1
        Atemp1=A[i-1]
        (rowsA,colsA,valsA)=findnz(Atemp1) #retrieving rows, columns and values
        Atemp=sparse(colsA,rowsA,valsA)#Defining the tranpose
        g[:,i]=(I-deltat*sparse((Atemp)))\g[:,i-1]
    end
    return g
end

function shockSim()
    #Maximum iterations
    maxiter=100
    #Tolerance
    tol=0.001

    #Initial value of lambda2
    lambda2_0=0.5 #1.0
    #Final value of lambda2
    lambda2_T=0.9 #1.5

    r0=equilibriumR(lambda2_0)
    results0=HJBequation(r0, lambda2_0)
    a=results0.a
    Na=length(a)
    deltaa=(a[end]-a[1])/(Na-1)

    rT=equilibriumR(lambda2_T)
    resultsT=HJBequation(rT, lambda2_T)

    g0=KF(results0.a,results0.z,results0.A)
    gT=KF(resultsT.a,resultsT.z,resultsT.A)

    T=20
    #Number of points in the time interval
    N=100

    #Matrix to save g
    g=repeat(g0,1,N+1)

    #speed of updating the interest rate. Taken directly from  Moll's code
    xi = 20*(exp.(-0.05*(1:N)) .- exp.(-0.05*N))

    #First guess on the path of r
    rl0=rT*ones(eltype(rT),N)
    rl1=copy(rl0)
    @show r0 rT

    for i=1:maxiter
        results=TimeHJBequation(rl0, resultsT,T, lambda2_T)
        g=TimeKF(results0.a,results0.z,results.A,g0,rl0,T)
        S=deltaa.*sum(g.*repeat(a,2,N+1),dims=1)
        diffS=S[2:end]-S[1:end-1]
        #@show maximum(abs.(diffS))
        rl1=rl0-xi.*diffS
        #@show maximum(abs.(rl1-rl0))
        if maximum(abs.(diffS))<tol || maximum(abs.(rl1-rl0))<tol
            break
        end
        #println(rl1)
        rl0=copy(rl1)
    end
    #@show rl0
    p1=plot([range(-5*T/N,stop=T,length=N+5);],[r0*ones(5); rl1],xlabel="T",ylabel="r",legend=false)
    p2=plot(a[1:100], [g[1:100,1] g[Na+1:Na+100,1] g[1:100,3] g[Na+1:Na+100,3]],xlabel="Wealth",title="t=0.06",label=["y1 t=0" "y2  t=0" "y1 t=0.06" "y2  t=0.06"],linecolor=["red" "blue" "red" "blue"],linestyle=[:solid :solid :dash :dash])
    p3=plot(a[1:100], [g[1:100,1] g[Na+1:Na+100,1] g[1:100,N+1] g[Na+1:Na+100,N+1]],xlabel="Wealth",title="Long run",label=["y1 t=0" "y2  t=0" "y1 t=T" "y2  t=T"],linecolor=["red" "blue" "red" "blue"],linestyle=[:solid :solid :dash :dash])
    display(plot(p1,p2,p3,layout=(1,3)))
end

function optimalh(a, ϕ, r, p, h,f)
    #Finds the optimal h given a value of wealth a. In this case the input a is a value, while h is a vector of possible values of h.
    #From the paper it should have this shape={0,[hmin,\infty]}
    #f is the function of housing in the utility function

    #Possible values of utility for all h
    temp=f.(h)
    temp[p*h.>ϕ*a].=-Inf
    #Position of the optimal h
    hopt=argmax(temp)
    #Value at optimum
    ftilda=f(h[hopt])

    return (ftilda,hopt)

end

function HJBequationHousing(r0, lambda2)
        #This function solves the HJB equation using the implicit method in Achdou et al (2017)
        #r0 is the interest rate and lambda2 the probability to pass to state 2

        #Maximum iterations
        maxiter=120
        #Tolerance
        tol=1e-6
        #Delta to calculate vprime
        delta=1000

        #Price
        #r=0.03
        r=r0

        #Discount
        ρ=0.05

        #Parameter for the CRRA
        σ=2.0
        #Inverse of the marginal utility
        uprimeinv(x)=x^(-1/σ)
        #utility
        u(x)=(x^(1-σ))/(1-σ)
        #marginal utility
        uprime(x)=x^(-σ)

        z=[0.1,0.135]#States of the stochastic process
        Nz=length(z)

        #λ=[1.2,1.2]#Transition probabilities
        λ=[0.5,lambda2]#Transition probabilities

        amin=0.0
        amax=3.0
        Na=500 #number of points in a
        a=[range(amin,stop=amax,length=Na);]
        deltaa=(amax-amin)/(Na-1) #Assumes that a is equally spaced

        #Create big vector with z
        zVec=[]
        for j=1:Nz
            zVec=[zVec;z[j]*ones(Na)]
        end

        #Housing parameters
        hmin=2.3
        p=1
        ϕ=2
        #Parameters of f
        α=1/3
        η=0.2
        #Utility of housing
        f(x)=η*(max(x-hmin,0))^α - r*p*x

        #Vector with possible values of housing
        Nh=10000
        h=[0;range(hmin,stop=amax*ϕ/p,length=(Nh-1));]

        #Finding optimal values for h given each value of a
        hopt=zeros(Float64,Na)
        fopt=zeros(eltype(h),Na)
        hopt=min.((r*p/(α*η))^(1/(α-1))+hmin,ϕ*a./p)
        hopt[hopt.<hmin].=0
        fopt=f.(hopt)
        #for i=1:Na
        #    (fopt[i],hopt[i])=optimalh(a[i], ϕ, r, p, h,f)
        #end
        #@show hopt
        v0=zeros(eltype(a),Na*Nz)
        for j=1:Nz
            v0[(j-1)*Na+1:j*Na]=((z[j].+max(r,0.01).*a).^(1-σ))/(1-σ)/ρ
        end

        #definition of the positions that are different from zero in the matrix A
        rows=[1:Na;Na+1:2*Na;1:2*Na;2:Na;Na+2:2*Na;1:Na-1;Na+1:2*Na-1]#Positions of \lambda1 and \lambda 2. Positions of y. Positions for x1. Positions for x2. Positions for z1. Positions for z2
        cols=[Na+1:2*Na;1:Na;1:2*Na;1:Na-1;Na+1:2*Na-1;2:Na;Na+2:2*Na]#Positions of \lambda1 and \lambda 2. Positions of y. Positions for x1. Positions for x2. Positions for z1. Positions for z2
        #Initialization of A
        valsA=ones(eltype(v0),length(rows))
        A=sparse(rows,cols,valsA)

        v1=zeros(eltype(a),Na*Nz)
        cx=zeros(eltype(a),Na*Nz)#This is defined as c+f(h)
        c=zeros(eltype(a),Na*Nz)
        s=zeros(eltype(a),Na*Nz)

        for i=1:maxiter
            vprimeF=ones(eltype(a),Na*Nz)
            vprimeB=ones(eltype(a),Na*Nz)
            for j=1:Nz
                vprimeF[(j-1)*Na+1:j*Na-1]=(v0[(j-1)*Na+2:j*Na].-v0[(j-1)*Na+1:j*Na-1])./deltaa #In the last position the forward difference is not defined
                vprimeF[j*Na]=(z[j] + fopt[Na] +r.*amax).^(-σ) #Will never be used, but just in case
                vprimeB[(j-1)*Na+2:j*Na]=(v0[(j-1)*Na+2:j*Na].-v0[(j-1)*Na+1:j*Na-1])./deltaa #In the first position the backward difference is not defined
                vprimeB[(j-1)*Na+1]=(z[j] + fopt[1] +r.*amin).^(-σ) #state constraint boundary condition
            end
            sF=zeros(eltype(vprimeF),Na*Nz)
            sB=zeros(eltype(vprimeB),Na*Nz)

            ######CAREFUL. SOMETIMES VPRIME IS NEGATIVE, THIS ENSURES THIS DOESN'T HAPPEN
            vprimeF[vprimeF.<=0].=10^(-10)
            vprimeB[vprimeB.<=0].=10^(-10)

            for j=1:Nz
                for k=1:Na
                    #@show j k
                    sF[(j-1)*Na+k]=z[j]+fopt[k]+r*a[k]-uprimeinv(vprimeF[(j-1)*Na+k])
                    sB[(j-1)*Na+k]=z[j]+fopt[k]+r*a[k]-uprimeinv(vprimeB[(j-1)*Na+k])
                end
            end
            vprime=similar(vprimeF)
            #vprime for the first value
            #for j=1:Nz
            #    if sF[(j-1)*Na+1]>0
            #        vprime[(j-1)*Na+1]=vprimeF[(j-1)*Na+1]
            #    else
            #        vprime[(j-1)*Na+1]=uprime(z[j]+r*amin)
            #    end
            #end
            #vprime for the last value
            #for j=1:Nz
            #    if sB[j*Na]<0
            #        vprime[j*Na]=vprimeB[j*Na]
            #    else
            #        vprime[j*Na]=uprime(z[j]+r*amax)
            #    end
            #end
            #vprime for intermediate values
            indexB=zeros(Int64,Na*Nz) #1 if using backward
            indexF=zeros(Int64,Na*Nz) #1 if using forward
            for j=1:Nz
                for k=1:Na
                    #utility plus continuation value forward
                    uF=u(uprimeinv(vprimeF[(j-1)*Na+k]))+vprimeF[(j-1)*Na+k]*sF[(j-1)*Na+k]
                    uB=u(uprimeinv(vprimeB[(j-1)*Na+k]))+vprimeB[(j-1)*Na+k]*sB[(j-1)*Na+k]
                    if ((sF[(j-1)*Na+k]>0) & (sB[(j-1)*Na+k]>=0)) | ((sF[(j-1)*Na+k]>0) & (sB[(j-1)*Na+k]<0) & (uF>=uB))
                        vprime[(j-1)*Na+k]=vprimeF[(j-1)*Na+k]
                        indexF[(j-1)*Na+k]=1
                    elseif ((sB[(j-1)*Na+k]<0) & (sF[(j-1)*Na+k]<=0)) | ((sB[(j-1)*Na+k]<0) & (sF[(j-1)*Na+k]>0) & (uB>=uF))
                        vprime[(j-1)*Na+k]=vprimeB[(j-1)*Na+k]
                        indexB[(j-1)*Na+k]=1
                    else
                        vprime[(j-1)*Na+k]=uprime(z[j]+fopt[k]+r*a[k])
                    end
                end
            end
            #Consumption
            cx=uprimeinv.(vprime)

            #Calculation of savings
            s=zVec+repeat(fopt,Nz,1)+r*repeat(a,Nz,1)-cx
            b=u.(cx)+v0/delta

            x=-sB/deltaa
            x[indexB.==0].=0
            #@show x
            w=sF/deltaa #This is the z that goes in the matrix A. It has a conflict with the stochastic process
            w[indexF.==0].=0
            #Making the first element of x (for each value of z) 0
            for j=1:Nz
                x[(j-1)*Na+1]=0
            end
            for j=1:Nz
                w[j*Na]=0
            end
            #Definition of y without substracting the probability lambda
            y=-x-w
            #Adjusting y by the probability lambda
            for j=1:Nz
                y[(j-1)*Na+1:j*Na]=y[(j-1)*Na+1:j*Na].-λ[j]
            end

            #Creation of matrix a
            #THIS MATRIX ASSUMES LENGTH(Z)=2
            #valsA=vcat(λ[1]*ones(eltype(λ[1]),Na,1),λ[2]*ones(eltype(λ[1]),Na,1),y,x[2:Na],x[Na+2:2*Na],w[1:Na-1],w[Na+1:2*Na-1]) #vector with the values of A. \lambda1 and \lambda 2. Positions of y. Positions for x1. Positions for x2. Positions for z1. Positions for z2
            valsA=vec([λ[1]*ones(eltype(λ[1]),Na,1);λ[2]*ones(eltype(λ[1]),Na,1);y;x[2:Na];x[Na+2:2*Na];w[1:Na-1];w[Na+1:2*Na-1]]) #vector with the values of A. \lambda1 and \lambda 2. Positions of y. Positions for x1. Positions for x2. Positions for z1. Positions for z2
            A=sparse(rows,cols,valsA)

            B=(1/delta+ρ)*I-A
            v1=B\b

            if maximum(abs.(v1-v0))<tol
                break
            end
            v0=copy(v1)
        end

        c=cx.-repeat(η*(max.(hopt.-hmin,0)).^α,Nz)

        #p1=plot(a,[s[1:Na] s[Na+1:2*Na]],xlabel="Wealth",title="Savings",label=["y1" "y2"],legend=:topright)
        #p2=plot(a,[v1[1:Na] v1[Na+1:2*Na]],legend=false)
        #p3=plot(a, hopt,xlabel="Wealth",title="Housing",legend=false)
        #p4=plot(a,[c[1:Na] c[Na+1:2*Na]],xlabel="Wealth",title="Consumption",label=["y1" "y2"],legend=:bottomright)
        #p5=plot(a,fopt,legend=false)
        #display(plot(p1,p3,p4,layout=(1,3)))
        #@show p*hmin/ϕ
        #@show h[hopt]
        return (a=a,z=z,c=c,s=s,h=hopt,A=A,v=v0)
end

function KFHousing(a,z,A)
    Na=length(a)
    deltaa=(a[Na]-a[1])/(Na-1)
    Nz=length(z)
    g=ones(eltype(a),Nz*Na)
    g=g/(deltaa*sum(g))
    gtilda=copy(g)
    N=1000#Number of times until convergence to distribution
    dt=10
    At=A'
    for i=1:N
        gtilda=(I - At*dt)\g
        g=copy(gtilda)
    end
    #g=gtilda/(deltaa*sum(gtilda))
    p1=plot(a[1:Na],g[1:Na],xlabel="Wealth",title="Distribution of agents",label=["y1" "y2"])
    p2=plot!(a,g[Na+1:2*Na])
    display(plot(p1,p2))

    return g
end

end # module


function solve()
    n, a, m = [parse(Int, x) for x in split(readline())]
    d = Dict{Int, Int}(a=>1)
    v = [a]
    i = 2
    while i ≤ n
        a = a^2 % m
        if a ∈ keys(d)
            break
        end
        d[a] = i
        push!(v, a)
        i += 1
    end
    if i > n
        sum(v)
    else
        cyclestart = d[a]
        cyclelen = i - cyclestart
        ret = sum(v[1:cyclestart-1])
        n = n - cyclestart
        ret += sum(v[cyclestart:end])* (n ÷ cyclelen)
        ret += sum(v[cyclestart:cyclestart+(n%cyclelen)])
    end
end

println(solve())


module Xu

@doc raw"""
    f(n,ℓ)

```math
f(n,\ell)=\begin{cases}
\displaystyle\sum_{m=0}^n \ell-m, & n\geq0\\
0, & n<0
\end{cases}
```
"""
f(n::I,ℓ::I) where {I<:Integer} = n >= 0 ? sum(ℓ-m for m in 0:n) : 0

@doc raw"""
``A(N,\ell,\ell_b,M_S',M_L)`` obeys four different cases:

## Case 1

``M_S'=1``, ``|M_L|\leq\ell``, and ``N=1``:

```math
A(1,\ell,\ell_b,1,M_L) = 1
```

## Case 2

``\{M_S'\}={2-N,4-N,...,N-2}``, ``|M_L| \leq f\left(\frac{N-M_S'}{2}-1\right)+f\left(\frac{N+M_S'}{2}-1\right)``, and ``1<N\leq 2\ell+1``:

```math
\begin{aligned}
A(N,\ell,\ell,M_S',M_L) =
\sum_{M_{L-}\max\left\{-f\left(\frac{N-M_S'}{2}-1\right),M_L-f\left(\frac{N+M_S'}{2}-1\right)\right\}}
^{\min\left\{f\left(\frac{N-M_S'}{2}-1\right),M_L+f\left(\frac{N+M_S'}{2}-1\right)\right\}}
\Bigg\{A\left(\frac{N-M_S'}{2},\ell,\ell,\frac{N-M_S'}{2},M_{L-}\right)\\
\times
A\left(\frac{N+M_S'}{2},\ell,\ell,\frac{N+M_S'}{2},M_L-M_{L-}\right)\Bigg\}
\end{aligned}
```

## Case 3

``M_S'=N``, ``|M_L|\leq f(N-1)``, and ``1<N\leq 2\ell+1``:

```math
A(N,\ell,\ell_b,N,M_L) =
\sum_{M_{L_I} = \left\lfloor{\frac{M_L-1}{N}+\frac{N+1}{2}}\right\rfloor}
^{\min\{\ell_b,M_L+f(N-2)\}}
A(N-1,\ell,M_{L_I}-1,N-1,M_L-M_{L_I})
```

## Case 4

else:

```math
A(N,\ell,\ell_b,M_S',M_L) = 0
```
"""
function A(N::I, ℓ::I, ℓ_b::I, M_S′::I, M_L::I) where {I<:Integer}
    if M_S′ == 1 && abs(M_L) <= ℓ && N == 1
        1 # Case 1
    elseif 1 < N && N <= 2ℓ + 1
        # Cases 2 and 3
        # N ± M_S' is always an even number
        a = (N-M_S′) >> 1
        b = (N+M_S′) >> 1
        fa = f(a-1,ℓ)
        fb = f(b-1,ℓ)

        if M_S′ in 2-N:2:N-2 && abs(M_L) <= fa + fb
            mapreduce(+, max(-fa, M_L - fb):min(fa, M_L + fb)) do M_Lm
                A(a,ℓ,ℓ,a,M_Lm)*A(b,ℓ,ℓ,b,M_L-M_Lm)
            end
        elseif M_S′ == N && abs(M_L) <= f(N-1,ℓ)
            mapreduce(+, floor(Int, (M_L-1)//N + (N+1)//2):min(ℓ_b,M_L + f(N-2,ℓ))) do M_LI
                A(N - 1, ℓ, M_LI - 1, N - 1, M_L-M_LI)
            end
        else
            0 # Case 4
        end
    else
        0 # Case 4
    end
end

@doc raw"""
    X(N, ℓ, S′, L)

Calculate the multiplicity of the term ``^{2S+1}L`` (``S'=2S``) for
the orbital `ℓ` with occupancy `N`, according to the formula:

```math
\begin{aligned}
X(N, \ell, S', L) =&+ A(N, \ell,\ell,S',L)\\
&- A(N, \ell,\ell,S',L+1)\\
&+A(N, \ell,\ell,S'+2,L+1)\\
&- A(N, \ell,\ell,S'+2,L)
\end{aligned}
```

Note that this is not correct for filled (empty) shells, for which the
only possible term trivially is `¹S`.

# Examples

```jldoctest
julia> AtomicLevels.Xu.X(1, 0, 1, 0) # Multiplicity of ²S term for s¹
1

julia> AtomicLevels.Xu.X(3, 3, 1, 3) # Multiplicity of ²D term for d³
2
```

"""
X(N::I, ℓ::I, S′::I, L::I) where {I<:Integer} = A(N,ℓ,ℓ,S′,L) - A(N,ℓ,ℓ,S′,L+1) + A(N,ℓ,ℓ,S′+2,L+1) - A(N,ℓ,ℓ,S′+2,L)

end


using PyPlot, Statistics
# (c) Ludovic Raess (ludovic.rass@gmail.com)
@views function viscous_glacier2D()
	# physics - scales
	α       = 10.0                 # slope angle, degrees
	lx, ly  = 300.0, 100.0         # domain length X, Y, m
	ρg      = 900*9.8              # gravity acceleration, m/s^2
	μ       = 1e12                 # viscosity, Pa.s
	# numerics
	nx, ny  = 61, 21               # grid points X, Y
	niτ     = 14000                # number of iters
	# preprocessing
	dx, dy  = lx/(nx-1), ly/(ny-1) # grid spacing X, Y
	dτv     = min(dx,dy)^2/μ/4.1/2 # timestep
	dτp     = 4.1*μ/max(nx,ny)
	(xc, yc ) = (LinRange(-lx/2, lx/2, nx), LinRange(-ly/2, ly/2, ny))
	(Xc2,Yc2) = ([x for x=xc,y=yc], [y for x=xc,y=yc])
	(X2r,Y2r) = (Xc2*cosd(α) - sind(α)*Yc2, Xc2*sind(α) + cosd(α)*Yc2)
	# initial conditions
	Pt      = zeros(Float64, nx  ,ny  )
	∇V      = zeros(Float64, nx  ,ny  )
	Vx      = zeros(Float64, nx+1,ny  )
	Vy      = zeros(Float64, nx  ,ny+1)
	dVxdτ   = zeros(Float64, nx-1,ny-2)
	dVydτ   = zeros(Float64, nx-2,ny-1)
	σ_xx    = zeros(Float64, nx  ,ny  )
	σ_yy    = zeros(Float64, nx  ,ny  )
	τ_xy    = zeros(Float64, nx-1,ny-1)
	# action - iteration loop
	for iτ = 1:niτ
		# pressure and stress
		∇V    .= diff(Vx,dims=1)./dx .+ diff(Vy,dims=2)./dy
		Pt    .= Pt .- ∇V.*dτp
		σ_xx  .= 2.0*μ.*(diff(Vx,dims=1)./dx .- 1/3*∇V) .- Pt
		σ_yy  .= 2.0*μ.*(diff(Vy,dims=2)./dy .- 1/3*∇V) .- Pt
		τ_xy  .= μ.*(diff(Vx[2:end-1,:],dims=2)./dy .+ diff(Vy[:,2:end-1],dims=1)./dx)
		# free surface top boundary
		Pt[:,end]   .= 0
		σ_xx[:,end] .= 0
		τ_xy[:,end] .= 1/3*τ_xy[:,end-1]
		# flow velocities Vx and Vy
		dVxdτ .= diff(σ_xx[:,2:end-1],dims=1)./dx .+ diff(τ_xy,dims=2)./dy .- sind(α).*ρg
		dVydτ .= diff(σ_yy[2:end-1,:],dims=2)./dy .+ diff(τ_xy,dims=1)./dx .- cosd(α).*ρg
		Vx[2:end-1,2:end-1] .= Vx[2:end-1,2:end-1] .+ dVxdτ.*dτv
		Vy[2:end-1,2:end-1] .= Vy[2:end-1,2:end-1] .+ dVydτ.*dτv
		# no sliding bottom boundary
		Vy[:,1] .= -Vy[:,2]
		# visualisation
		if mod(iτ,1000)==0 err = maximum([mean(abs.(∇V[:,1:end-1])), mean(abs.(dVxdτ)), mean(abs.(dVydτ))]); println("error = $err") end
	end
	# visu
	figure("pyplot_figure",figsize=(5.7,5.5)), clf()
	st = 4; s2d = 60*60*24
	(Xp,  Yp ) = (X2r[1:st:end,1:st:end], Y2r[1:st:end,1:st:end])
	(Vxp, Vyp) = (0.5*(Vx[1:st:end-1,1:st:end  ]+Vx[2:st:end,1:st:end]), 0.5*(Vy[1:st:end  ,1:st:end-1]+Vy[1:st:end,2:st:end]))
	subplot(311), pcolor(X2r,Y2r, 1e-3*Pt), plt.axis("off"), plt.title("pressure [kPa]"), plt.colorbar(fraction=0.02, pad=0.03)
	quiver(Xp, Yp, Vxp, Vyp, pivot="mid", color="white")
	subplot(312), pcolor(X2r,Y2r, s2d*Vx[2:end,:]), plt.axis("off"), plt.title("Vel-x [m/d]"), plt.colorbar(fraction=0.02, pad=0.03)
	subplot(313), pcolor(X2r,Y2r, s2d*Vy[:,2:end]), plt.axis("off"), plt.title("Vel-y [m/d]"), plt.colorbar(fraction=0.02, pad=0.03)
	return
end
viscous_glacier2D()


using Observers
using DataFrames
using Test
using JLD2

@testset "Observer" begin
  # Series for π/4
  f(k) = (-1)^(k+1)/(2k-1)

  function my_iterative_function(niter; observer!, observe_step)
    π_approx = 0.0
    for n in 1:niter
      π_approx += f(n)
      if iszero(n % observe_step)
        update!(observer!; π_approx = 4π_approx, iteration = n)
      end
    end
    return 4π_approx
  end

  # Measure the relative error from π at each iteration
  err_from_π(; π_approx, kwargs...) = abs(π - π_approx) / π

  # Record which iteration we are at
  iteration(; iteration, kwargs...) = iteration

  obs = Observer(["Error" => err_from_π, "Iteration" => iteration])

  @test length(obs) == 2
  @test results(obs, "Error") == []
  @test results(obs, "Iteration") == []

  niter = 10000
  observe_step = 1000
  π_approx = my_iterative_function(niter; observer! = obs, observe_step = observe_step)

  for res in obs
    @test length(last(last(res))) == niter ÷ observe_step
  end

  save("outputdata.jld2", results(obs))
  obs_load = load("outputdata.jld2")

  for (k,v) in obs_load
    @test v ≈ last(obs[k])
  end

  obs = Observer(["Error" => err_from_π, "Iteration" => iteration])
  obs["nofunction"] = nothing

  niter = 10000
  observe_step = 1000
  π_approx = my_iterative_function(niter; observer! = obs, observe_step = observe_step)

  @test results(obs,"nofunction") == []

  #
  # List syntax
  #

  obs = Observer("Error" => err_from_π, "Iteration" => iteration)

  @test length(obs) == 2
  @test results(obs, "Error") == []
  @test results(obs, "Iteration") == []

  niter = 10000
  observe_step = 1000
  π_approx = my_iterative_function(niter; observer! = obs, observe_step = observe_step)

  for res in obs
    @test length(last(last(res))) == niter ÷ observe_step
  end

  #
  # Function list syntax
  #

  obs = Observer(err_from_π, iteration)

  @test length(obs) == 2
  @test results(obs, err_from_π) == []
  @test results(obs, "err_from_π") == []
  @test results(obs, iteration) == []
  @test results(obs, "iteration") == []

  niter = 10000
  observe_step = 1000
  π_approx = my_iterative_function(niter; observer! = obs, observe_step = observe_step)

  for res in obs
    @test length(last(last(res))) == niter ÷ observe_step
  end

  f1(x::Int) = x^2
  f2(x::Int, y::Float64) = x + y
  f3(_,_,t::Tuple) = first(t)
  f4(x::Int; a::Float64) = x * a
  f5(x::Int; a::Float64, b::Float64) = x * a + b

  function my_other_iterative_function(; observer!)
    k = 2
    x = k
    y = k * √2
    t = (x+2*y,0,0)
    a = y^2
    b = 3.0
    update!(observer!, x, y, t; a = a, b = b)
  end

  obs = Observer(["f1" => f1, "f2" => f2, "f3" => f3, "f4" => f4, "f5" => f5])

  my_other_iterative_function(; observer! = obs)

  @test results(obs,"f1")[1] ≈ 4.0
  @test results(obs,"f2")[1] ≈ 2.0 + 2*√2
  @test results(obs,"f3")[1] ≈ 2.0 + 4*√2
  @test results(obs,"f4")[1] ≈ 16.0
  @test results(obs,"f5")[1] ≈ 19.0
end

@testset "Observer constructed from functions" begin
  # Series for π/4
  f(k) = (-1)^(k+1)/(2k-1)

  function my_iterative_function(niter; observer!, observe_step)
    π_approx = 0.0
    for n in 1:niter
      π_approx += f(n)
      if iszero(n % observe_step)
        update!(observer!; π_approx = 4π_approx, iteration = n)
      end
    end
    return 4π_approx
  end

  # Measure the relative error from π at each iteration
  err_from_π(; π_approx, kwargs...) = abs(π - π_approx) / π

  # Record which iteration we are at
  iteration(; iteration, kwargs...) = iteration
  obs = Observer([err_from_π, iteration])

  @test length(obs) == 2
  @test results(obs, "err_from_π") == []
  @test results(obs, "iteration") == []

  niter = 10000
  observe_step = 1000
  π_approx = my_iterative_function(niter; observer! = obs, observe_step = observe_step)

  @test length(results(obs, "err_from_π")) == niter ÷ observe_step
  @test length(results(obs, "iteration")) == niter ÷ observe_step
  @test length(results(obs, err_from_π)) == niter ÷ observe_step
  @test length(results(obs, iteration)) == niter ÷ observe_step
  f1 = err_from_π
  f2 = iteration
  @test length(results(obs, f1)) == niter ÷ observe_step
  @test length(results(obs, f2)) == niter ÷ observe_step
  @test_throws KeyError results(obs, "f1")
  @test_throws KeyError results(obs, "f2")
end

@testset "save only last value" begin
  f(x::Int, y::Float64) = x + y
  g(x::Int) = x

  function Observers.update!(::typeof(g), results, result)
    empty!(results)
    push!(results, result)
  end

  function my_yet_another_iterative_function(niter::Int; observer!)
    for k in 1:niter
      x = k
      y = k * √2
      update!(observer!, x, y)
    end
  end

  obs = Observer(["g" => g, "f" => f])

  my_yet_another_iterative_function(100; observer! = obs)

  @test length( results(obs,"g")) == 1
  @test length( results(obs,"f")) == 100
end

@testset "empty" begin
  f(x) = 2x
  function iterative(niter; observer!)
    for k in 1:niter
      update!(observer!, k)
    end
  end
  obs0 = Observer(["f" => f])

  obs1 = copy(obs0)
  @test obs0 == obs1
  iterative(10; observer! = obs1)
  @test obs1 ≠ obs0
  empty_results!(obs1)
  @test obs1 == obs0

  iterative(10; observer! = obs1)
  obs1 = empty_results(obs0)
  @test obs1 == obs0
end

@testset "Test element types of Array" begin
  f(k, x::Int, y::Float64) = x + y
  g(k, x) = k < 20 ? 0 : exp(im * x)

  function iterative_function(niter::Int; observer!)
    for k in 1:niter
      x = k
      y = x * √2
      update!(observer!, k, x, y)
    end
  end

  obs = Observer(["f" => f, "g" => g])
  iterative_function(100; observer! = obs)
  res = results(obs)
  @test length(res["f"]) == 100
  @test length(res["g"]) == 100
  @test res["f"] isa Vector{Float64}
  @test res["g"] isa Vector{ComplexF64}

  obs = Observer(["f" => f, "g" => g])
  iterative_function(10; observer! = obs)
  res = results(obs)
  @test length(res["f"]) == 10
  @test length(res["g"]) == 10
  @test res["f"] isa Vector{Float64}
  @test res["g"] isa Vector{Int}
end

@testset "Conversion to DataFrames" begin
  f(k, x::Int, y::Float64) = x + y
  g(k, x) = k < 20 ? 0 : exp(im * x)
  function iterative_function(niter::Int; observer!)
    for k in 1:niter
      x = k
      y = x * √2
      update!(observer!, k, x, y)
    end
  end
  obs = Observer(["f" => f, "g" => g])
  iterative_function(100; observer! = obs)
  res = results(obs)
  df = DataFrame(results(obs))
  @test df.f == res["f"]
  @test df.g == res["g"]
  @test length(df.f) == 100
  @test length(df.g) == 100
  @test df.f isa Vector{Float64}
  @test df.g isa Vector{ComplexF64}
end


"""Check whether elements of a vector are increasing."""
function isincreasing(x::Vector)
    is_increasing = true
    for i in 2:length(x)
        is_increasing &= x[i] > x[i-1] ? true : false
    end
    return is_increasing
end

"""Set all negative entries in an array to zero."""
function clip_negatives!(A::AbstractArray{T}) where T
    @inbounds for i in eachindex(A)
        A[i] = max(A[i],zero(T))
    end
end

"""Returns an integer `m >= n` of argument `n` with only prime factors 2 and 3
to obtain an efficiently fourier-transformable number of longitudes.
    m = 2^i * 3^j >= n, with i>=0 but j = 0,1
"""
function roundup_fft(n::Int)
    lz = leading_zeros(n)                   # determine scale of n

    # create a mask that's 1 for all but the two most significant figures of n
    # for finding the next largest integer of n with factors 2 and 3
    mask = (1 << (8*sizeof(n)-lz-2))-1

    # round up by adding mask as offset and then masking all insignificant bits
    n_roundedup = (n + mask) & ~mask
    return n_roundedup
end