text:
# Can we approximate non-linear limb-darkening with
# polynomial?

include("/Users/ericagol/Computer/Julia/regress.jl")

nmu = 1000; mu = linspace(0,1,nmu)
fnon = sqrt.(mu).^3-mu
using PyPlot
for i=1:20
  fn = zeros(i,nmu)
  fn[1,:] = 1.0
  for j=2:i
    fn[j,:] =mu.^(j-1)
  end
  coeff,cov = regress(fn,fnon,ones(nmu))
  fmod = zeros(nmu)
  for j=1:i
    fmod += coeff[j]*fn[j,:]
  end
  clf()
  plot(mu,fnon+mu)
  plot(mu,fmod+mu)
  plot(mu,fmod-fnon)
  println("i: ",i," scatter: ",std(fmod-fnon)," max: ",maximum(abs,fmod-fnon))
  println("minimum: ",minimum(fmod+mu)," maximum: ",maximum(fmod+mu))
  read(STDIN,Char)
end

max_stars_repo_name: tagordon/limbdark

max_issues_repo_name: tagordon/limbdark

max_forks_repo_name: tagordon/limbdark


text:
using AdvancedPS, Test
cd(@__DIR__)
println("Starting main test file")
@testset "DE-MCMC Tests" begin
    include("DEMCMC_Tests.jl")
end

ext: jl


text:
gr_poly_line(points::Vector{Vec2f0}) = GR.polyline(first.(points), last.(points))
gr_poly_line(points::Vector{Vec3f0}) = GR.polyline(first.(points), getindex.(points, 2), last.(points))

"""
    `lines(x, y, z)` / `lines(x, y)` / `lines(positions)`

Creates a connected line plot for each element in `(x, y, z)`, `(x, y)` or `positions`.
"""
function draw(scene::Scene, plot::Lines)
    # TODO:
    # - Continuous color (`color = 1:10`)
    positions = map(plot[1][]) do pos
        # take camera from scene + model transformation matrix and apply it to pos
        project_position(scene, pos, plot[:model][])
    end

    c = if plot.color[] isa Symbol
            parse(Colorant, plot.color[])
        elseif plot.color[] isa Tuple{Symbol, Float64}
            RGBA(parse(Colorant, plot.color[][1]), plot.color[][2])
        else
            plot.color[]
        end
    # TODO change this to an array

    GR.settransparency(alpha(c))
    GR.setlinecolorind(gr_colorind(c))
    GR.setlinewidth(plot.linewidth[])
    gr_poly_line(positions)
    # broadcast_foreach(1:length(positions), plot.color[], plot.linewidth[], plot.linestyle[]) do i, c, lw, ls
        # GR.settransparency(alpha(c))
        # GR.setlinecolorind(gr_color(c))
    #     GR.polyline(x, y, )
    # end
end

"""
    linesegments(positions)

Plots a line for each pair of points in `positions`.

**Attributes**:
The same as for [`lines`](@ref)
"""
function draw(scene::Scene, plot::LineSegments)
    positions = map(plot[1][]) do pos
        # take camera from scene + model transformation matrix and apply it to pos
        project_position(scene, pos, plot[:model][])
    end
    @get_attribute(plot, (color, linewidth, linestyle))
    if color isa Union{RGBA, Symbol}
        color = fill(RGBA(color), length(positions))
    end
    if linewidth isa Number
        linewidth = fill(linewidth, length(positions))
    end
    #@show positions
    #@show color
    #@show linewidth
    #@show linestyle
    for i in 1:2:length(positions)
        GR.settransparency(alpha(color[i]))
        GR.setlinecolorind(gr_colorind(color[i]))
        GR.setlinewidth(linewidth[i])
        gr_poly_line(positions[i:(i+1)])
    end
end

"""
    text(string)

Plots a text.
"""
function draw(scene::Scene, plot::AbstractPlotting.Text)
    @get_attribute(plot, (textsize, color, font, align, rotation, model))
    txt = to_value(plot[1])
    position = plot.attributes[:position][]
    N = length(txt)
    broadcast_foreach(1:N, position, textsize, color, font, rotation) do i, p, ts, cc, f, r
        pos = project_position(scene, p, model)
        chup = r * Vec2f0(0, 1)
        GR.setcharup(chup[1], chup[2])
        GR.settextfontprec(233, 3)
        GR.setcharheight(0.018) # ts ???
        GR.settextcolorind(Int(GR.inqcolorfromrgb(cc.r, cc.g, cc.b)))
        GR.settransparency(cc.alpha)
        GR.settextalign(1, 4)
        GR.text(pos[1], pos[2], string(txt[i]))
    end
end

"""
    `scatter(x, y, z)` / `scatter(x, y)` / `scatter(positions)`

Plots a marker for each element in `(x, y, z)`, `(x, y)`, or `positions`.
"""
function draw(scene::Scene, plot::Scatter)
    fields = @get_attribute(plot, (color, colormap, colorrange, markersize, strokecolor, strokewidth, marker))
    model = plot[:model][]
    color isa AbstractVector && (color = to_image(float.(collect(color)), plot))
    broadcast_foreach(plot[1][], color, markersize, strokecolor, strokewidth, marker) do point, c, markersize, strokecolor, strokewidth, marker
        scale = project_scale(scene, markersize)[1] * 2500 / 6
        pos = project_position(scene, point, model)
        GR.setmarkertype(get(marker_translation_table, marker, GR.MARKERTYPE_SOLID_CIRCLE))
        GR.setmarkersize(scale)
        GR.setbordercolorind(gr_colorind(strokecolor))
        GR.setborderwidth(strokewidth)
        GR.setmarkercolorind(gr_colorind(c))
        GR.settransparency(alpha(c))
        GR.polymarker([pos[1]], [pos[2]])
    end
end

"""
    `image(x, y, image)` / `image(image)`

Plots an image on range `x, y` (defaults to dimensions).
"""
function draw(scene::Scene, plot::Image)
    @get_attribute plot (colormap, colorrange)
end

to_image(values::VecOrMat{<: Colorant}, attributes) = RGBA.(values)
function to_image(values::VecOrMat{<: Real}, attributes)
    AbstractPlotting.@get_attribute attributes (colormap, colorrange)
    return AbstractPlotting.interpolated_getindex.(Ref(colormap), values, (colorrange,))
end
# could be implemented via image, but might be optimized specifically by the backend
"""
    `heatmap(x, y, values)` or `heatmap(values)`

Plots a heatmap as an image on `x, y` (defaults to interpretation as dimensions).
"""
function draw(scene::Scene, plot::Heatmap)
    # TODO:
    # - get interpolation working consistently
    # - get levels to work, if they even do
    @get_attribute(plot, (colormap,colorrange,linewidth,levels,fxaa,interpolate))

    image = plot[3][]
    x, y = plot[1][], plot[2][]
    model = plot.model[]

    interp = plot.interpolate[]

    imsize = (AbstractPlotting.extrema_nan(x), AbstractPlotting.extrema_nan(y))

    _xy_min = project_position(scene, Point2f0(first.(imsize)), model)
    _xy_max = project_position(scene, Point2f0(last.(imsize)), model)

    if is_uniformly_spaced(x) && is_uniformly_spaced(y)

        xy_min = min.(_xy_min, _xy_max)
        xy_max = max.(_xy_min, _xy_max)

        colors = gr_color.(to_image(image, plot))

        # Main.@infiltrate

        GR.drawimage(
            xy_min[1],
            xy_max[1],
            xy_min[2],
            xy_max[2],
            size(image)[1],
            size(image)[2],
            colors
        )
    end
end

"""
    `volume(volume_data)`

Plots a volume. Available algorithms are:
* `:iso` => IsoValue
* `:absorption` => Absorption
* `:mip` => MaximumIntensityProjection
* `:absorptionrgba` => AbsorptionRGBA
* `:indexedabsorption` => IndexedAbsorptionRGBA
"""
function draw(scene::Scene, plot::Volume)
    @get_attribute(plot, (algorithm,absorption,isovalue,isorange,colormap,colorrange))

    x, y, z = plot[1][], plot[2][], plot[3][]
    if algorithm == AbstractPlotting.MaximumIntensityProjection

    end
end

"""
    `surface(x, y, z)`

Plots a surface, where `(x, y, z)` are supposed to lie on a grid.
"""
function draw(scene::Scene, plot::Surface)
    # TODO:
    # - transform x and y points into the screen's space
    @get_attribute(plot, (colormap,colorrange,shading))
    cmap = AbstractPlotting.to_colormap(colormap)

    x, y, z = plot[1][], plot[2][], plot[3][]

    GR.setcolormapfromrgb(red.(cmap), green.(cmap), blue.(cmap))

    if is_uniformly_spaced(x) && is_uniformly_spaced(y)
        x = ensure_vector(x; size = size(z)[1])
        y = ensure_vector(y; size = size(z)[2])
        # points = Point2f0.(x, y)
        # positions = map(points) do pos
        #     # take camera from scene + model transformation matrix and apply it to pos
        #     project_position(scene, pos, plot[:model][])
        # end
        # x, y = first.(positions), last.(positions)
        GR.surface(x, y, z, 4) # 4 => COLORED_MESH
    end
end

"""
    `mesh(x, y, z)`, `mesh(mesh_object)`, `mesh(x, y, z, faces)`, or `mesh(xyz, faces)`

Plots a 3D mesh.
"""
function draw(scene::Scene, plot::Mesh)
    @get_attribute(plot, (interpolate,shading,colormap,colorrange))
end

"""
    `meshscatter(x, y, z)` / `meshscatter(x, y)` / `meshscatter(positions)`

Plots a mesh for each element in `(x, y, z)`, `(x, y)`, or `positions` (similar to `scatter`).
`markersize` is a scaling applied to the primitive passed as `marker`
"""
function draw(scene::Scene, plot::MeshScatter)
    @get_attribute(plot, (marker,markersize,rotations,colormap,colorrange))
end

function setup_plot(scene)
    mwidth, mheight, width, height = GR.inqdspsize()
    size_factor = 0.25  # 25% of the display width
    w, h = scene.camera.resolution[]
    if w > h
        GR.setwsviewport(0, size_factor * mwidth, 0, size_factor * mwidth * h / w)
        GR.setwswindow(0, 1, 0, h / w)
    else
        GR.setwsviewport(0, size_factor * mheight * w / h, 0, size_factor * mheight)
        GR.setwswindow(0, w / h, 0, 1)
    end
    GR.selntran(0)
end

# The toplevel method - this sets up GR attributes, et cetera
function gr_draw(scene::Scene)
    setup_plot(scene)
    draw(scene)
end
# The main method - this draws all plots and child scenes
function draw(scene::Scene)
    foreach(plot-> draw(scene, plot), scene.plots)
    foreach(child-> draw(child), scene.children)
end
# The lower level method.  This dispatches on primitives, meaning that
# we have some guarantees about their attributes.
function draw(scene::Scene, primitive::AbstractPlotting.Combined)
    foreach(x-> draw(scene, x), filter(x -> x.visible[], primitive.plots))
end


text:
include("ow_tools.jl")
######################
######################
######################
######################
######################
######################
######################
######################
######################
######################
######################
######################
@doc """
    OWSingleFactorEstimator(data, dfm)

Description:
Estimate a single-factor DFM using the Otrok-Whiteman approach.
Both the latent factor and hyperparameters are estimated using the Bayesian approach outlined in Otrok and Whiteman (1998).

Inputs:
- data = Matrix with each column being a data series.
- dfm = Model structure specification.

Outputs:
- results = HDMF Bayesian estimator-generated MCMC posterior distribution samples and their means for latent factors and hyperparameters.
"""
function OW1LevelEstimator(data::Array{Float64,2}, dfm::DFMStruct)

    # nvar = number of variables including the variable with missing date
    # capt = length of data of complete dataset
    y = data
    capt, nvar = size(y)

    ndraws = dfm.ndraws         # number of monte carlo draws
    burnin = dfm.burnin         # number of initial draws to discard, total draws is undrws+burnin

    nfact = 1                   # number of factors to estimate
    arlag = dfm.factorlags      # autoregressive lags in the dynamic factors
    arterms = dfm.errorlags     # number of AR lags to include in each observable equation
    Size = nvar                 # number of variables each factor loads on
    nreg = 2                    # number of regressors in each observable equation, constant plus K factors

    ytemp = y
    y = ytemp - repeat(mean(ytemp, dims = 1), capt, 1)

    # set up some matricies for storage (optional)
    Xtsave = zeros(size(y)[1], ((ndraws + burnin) * nfact))    # just keep draw of factor, not all states (others are trivial)
    bsave = zeros(ndraws + burnin, nreg * nvar)          # observable equation regression coefficients
    ssave = zeros(ndraws + burnin, nvar)               # innovation variances
    psave = zeros(ndraws + burnin, nfact * arlag)        # factor autoregressive polynomials
    psave2 = zeros(ndraws + burnin, nvar * arterms)       # factor autoregressive polynomials

    ##### include a necessary procedure #####
    # set priors
    # priors for observable equations in factor model
    # priors for observable equations in factor model
    b0_ = ones(nreg, 1)             # prior mean of factor loading
    B0__ = 0.01 * I(nreg)           # prior precision of factor loading
    B0__[1, 1] = 1.0

    r0_ = zeros(arterms, 1)         # prior mean of phi (idiosyncratic AR polynomial)
    phipri = 0.25
    R0__ = phipri * I(arterms)          # prior precision of phi

    v0_ = ceil(capt * 0.05)    # inverted gamma parameters of for innovation variances
    d0_ = ones(1, 1) * 0.25^2               # v0 is an integer

    # prior for factor AR polynomial
    prem = [1; seqm(1, 0.85, arlag - 1)]
    phiprif = 1 ./ prem
    r0f_ = vec(zeros(arlag, 1))               # prior mean of phi
    R0f__ = diagrv(ident(arlag), phiprif)
    R0f__ = phipri * ident(arlag)

    # Normalize innovation variance for the factor, vector since diagonal,
    # variance set to 1
    sigU = [1; zeros(arlag - 1, 1)]

    for i = 2:nfact
        sigU = [sigU; 1; zeros(arlag - 1, 1)]
    end
    ############################################

    # Initialize and set up factor model
    SigE = ones(nvar, 1) * 0.0001
    phi = zeros(arlag, nfact)
    bold = zeros(nvar, nreg)         # starting value for regression coefficients
    phimat0 = zeros(arterms, nvar)      # observable equation AR coefficients

    facts = randn(capt, nfact)     # random starting factor
    facts[:, 1] = mean(y, dims = 2) |> transp_dbl

    ## Begin Monte Carlo Loop
    for dr = 1:ndraws+burnin

        nf = 1

        for i = 1:nvar

            # call arobs to draw observable coefficients
            xft = [ones(capt, 1) facts[:, 1]]

            b1, s21, phi1, facts = ar(y[:, i], xft, arterms, b0_, B0__, r0_, R0__, v0_, d0_, bold[i, :], SigE[i], phimat0[:, i], i, nf, facts, capt, nreg, Size)
            bold[i, 1:nreg] = b1'
            phimat0[:, i] = phi1
            SigE[i] = s21
            bsave[dr, ((i-1)*nreg)+1:i*nreg] = b1'
            ssave[dr, i] = s21
            psave2[dr, ((i-1)*arterms)+1:i*arterms] = phi1'

        end #end of loop for drawing the coefficients for each observable equation

        # draw factor AR coefficients
        i = 1
        phi = arfac(facts[:, i], arlag, r0f_, R0f__, phi[:, i], sigU[1, 1], capt)
        psave[dr, (i-1)*arlag+1:(i-1)*arlag+arlag] = phi

        #draw factor
        #take drawing of World factor
        sinvf1 = sigbig(phi, arlag, capt)
        f = zeros(capt, 1)
        H = ((1 / sigU[1]) * sinvf1' * sinvf1)

        for i = 1:nvar
            sinv1 = sigbig(phimat0[:, i], arterms, capt)
            H = H + ((bold[i, 2]^2 / (SigE[i])) * sinv1' * sinv1)
            f = f + (bold[i, 2] / SigE[i]) * sinv1' * sinv1 * (y[:, i])
        end

        Hinv = invpd(H)
        f = Hinv * f
        fact1 = sim_MvNormal(vec(f), Hinv)

        for i = 1:nfact
            Xtsave[:, (((dr-1)*nfact)+i)] = vec(fact1)
            facts[:, 1] = fact1
        end

        println(dr)
    end

    # Save results
    Xtsave = Xtsave[:, (burnin*nfact)+1:(burnin+ndraws)*nfact]
    bsave = bsave[burnin+1:burnin+ndraws, :]
    ssave = ssave[burnin+1:burnin+ndraws, :]
    psave = psave[burnin+1:burnin+ndraws, :]
    psave2 = psave2[burnin+1:burnin+ndraws, :]

    F = mean(Xtsave, dims = 2)
    B = mean(bsave, dims = 1)
    S = mean(ssave, dims = 1)
    P = mean(psave, dims = 1)
    P2 = mean(psave2, dims = 1)

    means = DFMMeans(F, B, S, P, P2)

    results = DFMResults(Xtsave, bsave, ssave, psave, psave2, means)

    return results
end;
######################
######################
######################
######################
######################
######################
######################
######################
######################
######################
######################
######################


text:
#
# Sets up global values for LLVM types, Julia types, external declarations, and other utilities.
#

const ctx = LLVM.Context(convert(LLVM.API.LLVMContextRef, cglobal(:jl_LLVMContext, Nothing)))

# Convert a Julia type to an LLVM type
# Note that LLVM.llvmtype returns the LLVM type of an LLVM value (could combine?)
llvmtype(x) =
    LLVMType(ccall(:julia_type_to_llvm, LLVM.API.LLVMTypeRef, (Any, Bool), x, false))

#
# Includes some external definitions to functions and constants in julia.h
#

#
# Types
#
const jl_value_t_ptr = llvmtype(Any)
const jl_value_t = eltype(jl_value_t_ptr)
const jl_value_t_ptr_ptr = LLVM.PointerType(jl_value_t_ptr)
# cheat on these for now:
const jl_datatype_t_ptr = jl_value_t_ptr
const jl_unionall_t_ptr = jl_value_t_ptr
const jl_typename_t_ptr = jl_value_t_ptr
const jl_sym_t_ptr = jl_value_t_ptr
const jl_svec_t_ptr = jl_value_t_ptr
const jl_module_t_ptr = jl_value_t_ptr
const jl_array_t_ptr = jl_value_t_ptr

const bool_t  = llvmtype(Bool)
const int1_t  = LLVM.Int1Type(ctx)
const int8_t  = llvmtype(Int8)
const int16_t = llvmtype(Int16)
const int32_t = llvmtype(Int32)
const int64_t = llvmtype(Int64)
const uint8_t  = llvmtype(UInt8)
const uint16_t = llvmtype(UInt16)
const uint32_t = llvmtype(UInt32)
const uint64_t = llvmtype(UInt64)
const float_t  = llvmtype(Float32)
const double_t = llvmtype(Float64)
const float32_t = llvmtype(Float32)
const float64_t = llvmtype(Float64)
const void_t    = llvmtype(Nothing)
const size_t    = llvmtype(Int)

const int8_t_ptr  = LLVM.PointerType(int8_t)
const void_t_ptr  = LLVM.PointerType(void_t)

function extern_global!(mod, name, typ)
    res = LLVM.GlobalVariable(mod, typ, string(name))
    LLVM.linkage!(res, LLVM.API.LLVMExternalLinkage)
    return res
end

function extern!(mod, name, rettyp, argtypes; vararg = false)
    res = LLVM.Function(mod, string(name), LLVM.FunctionType(rettyp, argtypes, vararg))
    LLVM.linkage!(res, LLVM.API.LLVMExternalLinkage)
    return res
end

function setup_externs!(mod)
    e = Dict{Symbol, Any}()
    #
    # Global variables, not including type definitions
    #

    e[:jl_main_module_g] = extern_global!(mod, "jl_main_module", jl_module_t_ptr)

    #
    # Functions
    #
    for s in [:int64, :int32, :int16, :int8, :uint64, :uint32, :uint16, :uint8, :float64, :float32]
        #e[:jl_box_int64] = extern!(mod, "jl_box_int64", jl_value_t_ptr, LLVMType[int64_t])
        e[Symbol(:jl_box_, s)] = extern!(mod, "jl_box_$s", jl_value_t_ptr, LLVMType[eval(Symbol(s, :_t))])
        # e[:jl_unbox_int64] = extern!(mod, "jl_unbox_int64", int64_t, LLVMType[jl_value_t_ptr])
        e[Symbol(:jl_unbox_, s)] = extern!(mod, "jl_unbox_$s", eval(Symbol(s, :_t)), LLVMType[jl_value_t_ptr])
    end
    e[:jl_box_bool]  = extern!(mod, "jl_box_bool", jl_value_t_ptr, LLVMType[uint8_t])
    e[:jl_unbox_bool]  = extern!(mod, "jl_unbox_bool", uint8_t, LLVMType[jl_value_t_ptr])
    e[:jl_box_ssavalue]  = extern!(mod, "jl_box_ssavalue", jl_value_t_ptr, LLVMType[size_t])
    e[:jl_box_slotnumber]  = extern!(mod, "jl_box_slotnumber", jl_value_t_ptr, LLVMType[size_t])
    e[:jl_box_voidpointer]  = extern!(mod, "jl_box_voidpointer", jl_value_t_ptr, LLVMType[size_t])
    e[:jl_unbox_voidpointer]  = extern!(mod, "jl_unbox_voidpointer", void_t_ptr, LLVMType[jl_value_t_ptr])

    e[:jl_apply_array_type] = extern!(mod, "jl_apply_array_type", jl_value_t_ptr, LLVMType[jl_value_t_ptr, int32_t])
    e[:jl_apply_tuple_type] = extern!(mod, "jl_apply_tuple_type", jl_value_t_ptr, LLVMType[jl_svec_t_ptr])
    e[:jl_new_struct_uninit] = extern!(mod, "jl_new_struct_uninit", jl_value_t_ptr, LLVMType[jl_datatype_t_ptr])
    e[:jl_new_struct] = extern!(mod, "jl_new_struct", jl_value_t_ptr, LLVMType[jl_datatype_t_ptr], vararg = true)
    e[:jl_new_bits] = extern!(mod, "jl_new_bits", jl_value_t_ptr, LLVMType[jl_value_t_ptr, jl_value_t_ptr])
    e[:jl_set_nth_field] = extern!(mod, "jl_set_nth_field", void_t, LLVMType[jl_value_t_ptr, int32_t, jl_value_t_ptr])
    e[:jl_pchar_to_string] = extern!(mod, "jl_pchar_to_string", jl_value_t_ptr, LLVMType[int8_t_ptr, uint32_t])

    e[:jl_pointerref] = extern!(mod, "jl_pointerref", jl_value_t_ptr, LLVMType[jl_value_t_ptr, jl_value_t_ptr, jl_value_t_ptr])
    e[:jl_pointerset] = extern!(mod, "jl_pointerset", jl_value_t_ptr, LLVMType[jl_value_t_ptr, jl_value_t_ptr, jl_value_t_ptr, jl_value_t_ptr])

    e[:jl_symbol] = extern!(mod, "jl_symbol", jl_sym_t_ptr, LLVMType[int8_t_ptr])
    e[:jl_svec] = extern!(mod, "jl_svec", jl_svec_t_ptr, LLVMType[], vararg = true)
    e[:jl_new_datatype] = extern!(mod, "jl_new_datatype", jl_datatype_t_ptr,
        LLVMType[jl_sym_t_ptr, jl_module_t_ptr, jl_datatype_t_ptr, jl_svec_t_ptr, jl_svec_t_ptr, jl_svec_t_ptr, int32_t, int32_t, int32_t])
    # For intrinsics
    e[:jl_array_len_] = extern!(mod, "jl_array_len_", jl_datatype_t_ptr, LLVMType[jl_array_t_ptr])
    for i in [Int8,Int16,Int32,Int64,Int128]
        li = llvmtype(i)
        for funsym in [:bswap,:ctpop]
            name = Symbol("llvm.", funsym, ".", li)
            e[name] = extern!(mod, string(name), li, LLVMType[li])
        end
        for funsym in [:sadd, :uadd, :ssub, :usub, :smul, :umul]
            name = Symbol("llvm.", funsym, ".with.overflow.", li)
            e[name] = extern!(mod, string(name), LLVM.StructType([li, int1_t], CodeGen.ctx), LLVMType[li, li])
        end
        name = Symbol("llvm.ctlz.", li)
        e[name] = extern!(mod, string(name), li, LLVMType[li, int1_t])
    end
    for fp in [Float32,Float64]
        lfp = llvmtype(fp)
        fps = fp == Float64 ? "f64" : "f32"
        for funsym in [:fabs,:ceil,:floor,:trunc,:rint,:sqrt]
            name = Symbol("llvm.", funsym, ".", fps)
            e[name] = extern!(mod, string(name), lfp, LLVMType[lfp])
        end
        name = Symbol("llvm.fmuladd.", fps)
        e[name] = extern!(mod, string(name), lfp, LLVMType[lfp, lfp, lfp])
    end

    return e
end

#
# Types
#

# TODO: fill in more
const type_g = Dict{Type, Symbol}(
    Nothing => :jl_void_type_g,
    Bool    => :jl_bool_type_g,
    Int8    => :jl_int8_type_g,
    Int16   => :jl_int16_type_g,
    Int32   => :jl_int32_type_g,
    Int64   => :jl_int64_type_g,
    UInt8   => :jl_uint8_type_g,
    UInt16  => :jl_uint16_type_g,
    UInt32  => :jl_uint32_type_g,
    UInt64  => :jl_uint64_type_g,
    Float16 => :jl_float16_type_g,
    Float32 => :jl_float32_type_g,
    Float64 => :jl_float64_type_g
)

function setup_types!(cg)
    d = Dict{Type, Any}()
    function setup_type!(typ, name, jltyp=nothing)
        symname = Symbol(name*"_g")
        g = extern_global!(cg.mod, name, typ)
        if jltyp != nothing
            d[jltyp] = g
        end
        cg.extern[symname] = g
    end
    setup_type!(jl_datatype_t_ptr, "jl_typeofbottom_type", Core.TypeofBottom)
    setup_type!(jl_datatype_t_ptr, "jl_datatype_type", DataType)
    setup_type!(jl_datatype_t_ptr, "jl_uniontype_type", Union)
    setup_type!(jl_datatype_t_ptr, "jl_unionall_type", UnionAll)
    setup_type!(jl_datatype_t_ptr, "jl_tvar_type"#= , TypeVar =#)
    setup_type!(jl_datatype_t_ptr, "jl_any_type", Any)
    setup_type!(jl_unionall_t_ptr, "jl_type_type", Type)
    setup_type!(jl_unionall_t_ptr, "jl_typetype_type", Type{Type})
    setup_type!(jl_value_t_ptr,    "jl_ANY_flag"#=, ANY =#)
    setup_type!(jl_datatype_t_ptr, "jl_typename_type", TypeName)
    setup_type!(jl_typename_t_ptr, "jl_type_typename", Type{TypeName})
    setup_type!(jl_datatype_t_ptr, "jl_sym_type", Symbol)
    setup_type!(jl_datatype_t_ptr, "jl_symbol_type", Symbol)
    setup_type!(jl_datatype_t_ptr, "jl_ssavalue_type", SSAValue)
    setup_type!(jl_datatype_t_ptr, "jl_abstractslot_type", Slot)
    setup_type!(jl_datatype_t_ptr, "jl_slotnumber_type", SlotNumber)
    setup_type!(jl_datatype_t_ptr, "jl_typedslot_type", TypedSlot)
    setup_type!(jl_datatype_t_ptr, "jl_simplevector_type", SimpleVector)
    setup_type!(jl_typename_t_ptr, "jl_tuple_typename", Tuple)
    setup_type!(jl_typename_t_ptr, "jl_vecelement_typename", VecElement)
    setup_type!(jl_datatype_t_ptr, "jl_anytuple_type", Tuple)
    setup_type!(jl_datatype_t_ptr, "jl_emptytuple_type", Tuple{})
    setup_type!(jl_unionall_t_ptr, "jl_anytuple_type_type")
    setup_type!(jl_unionall_t_ptr, "jl_vararg_type", Vararg)
    setup_type!(jl_typename_t_ptr, "jl_vararg_typename")
    setup_type!(jl_datatype_t_ptr, "jl_task_type", Task)
    setup_type!(jl_datatype_t_ptr, "jl_function_type", Function)
    setup_type!(jl_datatype_t_ptr, "jl_builtin_type", Core.Builtin)
    setup_type!(jl_value_t_ptr   , "jl_bottom_type")
    setup_type!(jl_datatype_t_ptr, "jl_method_instance_type", Core.MethodInstance)
    setup_type!(jl_datatype_t_ptr, "jl_code_info_type", CodeInfo)
    setup_type!(jl_datatype_t_ptr, "jl_method_type", Method)
    setup_type!(jl_datatype_t_ptr, "jl_module_type", Module)
    setup_type!(jl_unionall_t_ptr, "jl_abstractarray_type", AbstractArray)
    setup_type!(jl_unionall_t_ptr, "jl_densearray_type", DenseArray)
    setup_type!(jl_unionall_t_ptr, "jl_array_type", Array)
    setup_type!(jl_typename_t_ptr, "jl_array_typename")
    setup_type!(jl_datatype_t_ptr, "jl_weakref_type", WeakRef)
    setup_type!(jl_datatype_t_ptr, "jl_abstractstring_type", AbstractString)
    setup_type!(jl_datatype_t_ptr, "jl_string_type", String)
    setup_type!(jl_datatype_t_ptr, "jl_errorexception_type", ErrorException)
    setup_type!(jl_value_t_ptr,    "jl_argumenterror_type", ArgumentError)
    setup_type!(jl_datatype_t_ptr, "jl_loaderror_type", LoadError)
    setup_type!(jl_datatype_t_ptr, "jl_initerror_type", InitError)
    setup_type!(jl_datatype_t_ptr, "jl_typeerror_type", TypeError)
    setup_type!(jl_datatype_t_ptr, "jl_methoderror_type", MethodError)
    setup_type!(jl_datatype_t_ptr, "jl_undefvarerror_type", UndefVarError)
    setup_type!(jl_value_t_ptr, "jl_stackovf_exception", StackOverflowError)
    setup_type!(jl_value_t_ptr, "jl_memory_exception", OutOfMemoryError)
    setup_type!(jl_value_t_ptr, "jl_readonlymemory_exception")
    setup_type!(jl_value_t_ptr, "jl_diverror_exception", DivideError)
    setup_type!(jl_value_t_ptr, "jl_undefref_exception", UndefRefError)
    setup_type!(jl_value_t_ptr, "jl_interrupt_exception", InterruptException)
    setup_type!(jl_datatype_t_ptr, "jl_boundserror_type", BoundsError)
    setup_type!(jl_value_t_ptr, "jl_an_empty_vec_any")
    setup_type!(jl_datatype_t_ptr, "jl_bool_type", Bool)
    setup_type!(jl_datatype_t_ptr, "jl_char_type", Char)
    setup_type!(jl_datatype_t_ptr, "jl_int8_type", Int8)
    setup_type!(jl_datatype_t_ptr, "jl_uint8_type", UInt8)
    setup_type!(jl_datatype_t_ptr, "jl_int16_type", Int16)
    setup_type!(jl_datatype_t_ptr, "jl_uint16_type", UInt16)
    setup_type!(jl_datatype_t_ptr, "jl_int32_type", Int32)
    setup_type!(jl_datatype_t_ptr, "jl_uint32_type", UInt32)
    setup_type!(jl_datatype_t_ptr, "jl_int64_type", Int64)
    setup_type!(jl_datatype_t_ptr, "jl_uint64_type", UInt64)
    setup_type!(jl_datatype_t_ptr, "jl_float16_type", Float16)
    setup_type!(jl_datatype_t_ptr, "jl_float32_type", Float32)
    setup_type!(jl_datatype_t_ptr, "jl_float64_type", Float64)
    setup_type!(jl_datatype_t_ptr, "jl_floatingpoint_type", AbstractFloat)
    setup_type!(jl_datatype_t_ptr, "jl_number_type", Number)
    setup_type!(jl_datatype_t_ptr, "jl_void_type", Nothing)
    setup_type!(jl_datatype_t_ptr, "jl_signed_type", Signed)
    setup_type!(jl_datatype_t_ptr, "jl_voidpointer_type")
    setup_type!(jl_unionall_t_ptr, "jl_pointer_type", Ptr)
    setup_type!(jl_unionall_t_ptr, "jl_ref_type", Ref)
    setup_type!(jl_typename_t_ptr, "jl_pointer_typename")
    setup_type!(jl_value_t_ptr,    "jl_array_uint8_type")
    setup_type!(jl_value_t_ptr,    "jl_array_any_type")
    setup_type!(jl_value_t_ptr,    "jl_array_symbol_type")
    setup_type!(jl_datatype_t_ptr, "jl_expr_type")
    setup_type!(jl_datatype_t_ptr, "jl_globalref_type")
    setup_type!(jl_datatype_t_ptr, "jl_linenumbernode_type")
    setup_type!(jl_datatype_t_ptr, "jl_labelnode_type")
    setup_type!(jl_datatype_t_ptr, "jl_gotonode_type")
    setup_type!(jl_datatype_t_ptr, "jl_quotenode_type", QuoteNode)
    setup_type!(jl_datatype_t_ptr, "jl_newvarnode_type", NewvarNode)
    setup_type!(jl_datatype_t_ptr, "jl_intrinsic_type", Core.IntrinsicFunction)
    setup_type!(jl_datatype_t_ptr, "jl_methtable_type", MethodTable)
    setup_type!(jl_datatype_t_ptr, "jl_typemap_level_type", TypeMapLevel)
    setup_type!(jl_datatype_t_ptr, "jl_typemap_entry_type", TypeMapEntry)
    setup_type!(jl_svec_t_ptr,  "jl_emptysvec")
    setup_type!(jl_value_t_ptr, "jl_emptytuple")
    setup_type!(jl_value_t_ptr, "jl_true")
    setup_type!(jl_value_t_ptr, "jl_false")
    setup_type!(jl_value_t_ptr, "jl_nothing")
    setup_type!(jl_sym_t_ptr,   "jl_incomplete_sym")
    return d
end

#
# More utilities
#
has_terminator(bb::BasicBlock) =
    LLVM.API.LLVMGetBasicBlockTerminator(LLVM.blockref(bb)) != C_NULL


text:
function _pathway_from(id::I,
                       network::TransmissionNetwork;
                       depth::Real=Inf) where {I <: Integer}
  path = I[]
  if network.external[id] | any(network.internal[:, id])
    push!(path, id)
    path_lengths = [0]
    while (length(path) > path_lengths[end]) & (depth >= length(path_lengths))
      push!(path_lengths, length(path))
      for j in path[(path_lengths[end-1]+1):path_lengths[end]]
        append!(path, findall(network.internal[j, :]))
      end
    end
  end
  @debug "_pathway_from: transmission pathway from $id: $path"
  return path
end


text:
include("utils.jl")

M1 = Manifolds.SymmetricPositiveDefinite(3)
M2 = MetricManifold(Manifolds.SymmetricPositiveDefinite(3), Manifolds.LinearAffineMetric())
M3 = MetricManifold(Manifolds.SymmetricPositiveDefinite(3), Manifolds.LogCholeskyMetric())

types = [ Matrix{Float32},
        Matrix{Float64},
        MMatrix{3,3,Float32},
        # linear algebra in StataicArrays is a little too inaccurate for MMatrix{3,3,Float64}
        # MMatrix{3,3,Float64}
    ]
for M in [M1, M2, M3]
    @testset "$(typeof(M))" begin
        for T in types
            if M == M3 && T <: MMatrix
                #TODO fix the issue that causes this failure
                continue
            end
            A(α) = [1. 0. 0.; 0. cos(α) sin(α); 0. -sin(α) cos(α)]
            ptsF = [#
                [1. 0. 0.; 0. 1. 0.; 0. 0. 1],
                [2. 0. 0.; 0. 2. 0.; 0. 0. 1],
                A(π/6) * [1. 0. 0.; 0. 2. 0.; 0. 0. 1] * transpose(A(π/6)),
            ]
            pts = [convert(T, a) for a in ptsF]
            test_manifold(M, pts;
                test_vector_transport = true,
                test_forward_diff = false,
                test_reverse_diff = false,
                exp_log_atol_multiplier = 8
            )
        end
        @testset "Test Error cases in is_manifold_point and is_tangent_vector" begin
            pt1f = zeros(2,3); # wrong size
            pt2f = [1. 0. 0.; 0. 0. 0.; 0. 0. 1.]; # not positive Definite
            pt3f = [2. 0. 1.; 0. 1. 0.; 0. 0. 4.]; # not symmetric
            pt4 = [2. 1. 0.; 1. 2. 0.; 0. 0. 4.]
            @test !is_manifold_point(M,pt1f)
            @test !is_manifold_point(M,pt2f)
            @test !is_manifold_point(M,pt3f)
            @test is_manifold_point(M, pt4)
            @test !is_tangent_vector(M,pt4, pt1f)
            @test is_tangent_vector(M,pt4, pt2f)
            @test !is_tangent_vector(M,pt4, pt3f)
        end
    end
end


text:
module TestMultiplier

using Mimi
using Test

############################################
# adder component without a different name #
############################################

model1 = Model()
set_dimension!(model1, :time, 1:10)
add_comp!(model1, Mimi.multiplier)

x = collect(1:10)
y = collect(2:2:20)

update_param!(model1, :multiplier, :input, x)
update_param!(model1, :multiplier, :multiply, y)

run(model1)

@test model1[:multiplier, :output] == x.*y

##############################################
# test adder component with a different name #
##############################################

model2 = Model()
set_dimension!(model2, :time, 1:10)
add_comp!(model2, Mimi.multiplier, :compA)
update_param!(model2, :compA, :input, x)
update_param!(model2, :compA, :multiply, y)
run(model2)

@test model2[:compA, :output] == x.*y

end #module


text:
import RestrictedBoltzmannMachines as RBMs

using Test: @test, @testset
using Random: bitrand
using Statistics: mean
using LogExpFunctions: logsumexp

@testset "binary pseudolikelihood" begin
    n = (3,2)
    m = 2
    B = 3

    rbm = RBMs.RBM(RBMs.Binary(n...), RBMs.Gaussian(m...), randn(n..., m...) / √prod(n))
    v = bitrand(n..., B)

    E = RBMs.free_energy(rbm, v)

    ΔE = zeros(2, n..., B)
    for (k, x) in enumerate((false, true)), i in CartesianIndices(n)
        v_ = copy(v)
        v_[i, :] .= x
        ΔE[k, i, :] .= RBMs.free_energy(rbm, v_) - E
    end
    @test ΔE ≈ RBMs.substitution_matrix_exhaustive(rbm, v)
    lpl = -logsumexp(-ΔE; dims=1)
    @assert size(lpl) == (1, n..., B)
    @test RBMs.log_pseudolikelihood(rbm, v; exact=true) ≈ vec(mean(lpl; dims=(1,2,3)))

    ΔE = zeros(2, B)
    sites = [rand(CartesianIndices(n)) for _ in 1:B]

    for (k, x) in enumerate((false, true))
        v_ = copy(v)
        for (b, i) in enumerate(sites)
            v_[i, b] = x
        end
        ΔE[k, :] .= RBMs.free_energy(rbm, v_) - E
    end
    @test ΔE ≈ RBMs.substitution_matrix_sites(rbm, v, sites)
    lpl = -logsumexp(-ΔE; dims=1)
    @test RBMs.log_pseudolikelihood_sites(rbm, v, sites) ≈ vec(lpl)
end

@testset "spins pseudolikelihood" begin
    n = (3,2)
    m = 2
    B = 3

    rbm = RBMs.RBM(RBMs.Spin(n...), RBMs.Gaussian(m...), randn(n..., m...) / √prod(n))
    v = rand((-1, +1), n..., B)

    E = RBMs.free_energy(rbm, v)

    ΔE = zeros(2, n..., B)
    for (k, x) in enumerate((-1, 1)), i in CartesianIndices(n)
        v_ = copy(v)
        v_[i, :] .= x
        ΔE[k, i, :] .= RBMs.free_energy(rbm, v_) - E
    end
    @test ΔE ≈ RBMs.substitution_matrix_exhaustive(rbm, v)
    lpl = -logsumexp(-ΔE; dims=1)
    @assert size(lpl) == (1, n..., B)
    @test RBMs.log_pseudolikelihood(rbm, v; exact=true) ≈ vec(mean(lpl; dims=(1,2,3)))

    ΔE = zeros(2, B)
    sites = [rand(CartesianIndices(n)) for _ in 1:B]
    for (k, x) in enumerate((-1, 1))
        v_ = copy(v)
        for (b, i) in enumerate(sites)
            v_[i, b] = x
        end
        ΔE[k, :] .= RBMs.free_energy(rbm, v_) - E
    end
    @test ΔE ≈ RBMs.substitution_matrix_sites(rbm, v, sites)
    lpl = -logsumexp(-ΔE; dims=1)
    @test RBMs.log_pseudolikelihood_sites(rbm, v, sites) ≈ vec(lpl)
end

@testset "Potts pseudolikelihood" begin
    q = 3
    n = (3,2)
    m = 2
    B = 3

    rbm = RBMs.RBM(RBMs.Potts(q, n...), RBMs.Gaussian(m...), randn(q, n..., m...) / sqrt(q * prod(n)))
    v = falses(q, n..., B)
    for i in CartesianIndices(n), b in 1:B
        v[rand(1:q), i, b] = true
    end

    E = RBMs.free_energy(rbm, v)

    ΔE = zeros(q, n..., B)
    for x in 1:q, i in CartesianIndices(n)
        v_ = copy(v)
        v_[:, i, :] .= false
        v_[x, i, :] .= true
        ΔE[x, i, :] .= RBMs.free_energy(rbm, v_) - E
    end
    @test ΔE ≈ RBMs.substitution_matrix_exhaustive(rbm, v)
    lpl = -logsumexp(-ΔE; dims=1)
    @assert size(lpl) == (1, n..., B)
    @test RBMs.log_pseudolikelihood(rbm, v; exact=true) ≈ vec(mean(lpl; dims=(1,2,3)))

    ΔE = zeros(q, B)
    sites = [rand(CartesianIndices(n)) for _ in 1:B]
    for x in 1:q
        v_ = copy(v)
        for (b, i) in enumerate(sites)
            v_[:, i, b] .= false
            v_[x, i, b] = true
        end
        ΔE[x, :] .= RBMs.free_energy(rbm, v_) - E
    end
    @test ΔE ≈ RBMs.substitution_matrix_sites(rbm, v, sites)
    lpl = -logsumexp(-ΔE; dims=1)
    @test RBMs.log_pseudolikelihood_sites(rbm, v, sites) ≈ vec(lpl)
end


text:
# SiO2_Kischkat_1.54-14.3µm
# wavelength (micron) Re(n) Im(n)
const sio2_data = [1.53846 1.44325 2.0e-5
1.53941 1.44324 2.0e-5
1.54036 1.44323 2.0e-5
1.54131 1.44322 2.0e-5
1.54226 1.44321 2.0e-5
1.54321 1.4432 2.0e-5
1.54416 1.44319 2.0e-5
1.54512 1.44318 2.0e-5
1.54607 1.44317 2.0e-5
1.54703 1.44316 2.0e-5
1.54799 1.44315 2.0e-5
1.54895 1.44314 2.0e-5
1.54991 1.44313 2.0e-5
1.55087 1.44312 2.0e-5
1.55183 1.44311 2.0e-5
1.5528 1.44311 2.0e-5
1.55376 1.4431 2.0e-5
1.55473 1.44309 2.0e-5
1.55569 1.44308 2.0e-5
1.55666 1.44307 2.0e-5
1.55763 1.44306 2.0e-5
1.5586 1.44305 2.0e-5
1.55958 1.44304 2.0e-5
1.56055 1.44303 2.0e-5
1.56152 1.44302 2.0e-5
1.5625 1.44301 2.0e-5
1.56348 1.443 2.0e-5
1.56446 1.44299 2.0e-5
1.56544 1.44298 2.0e-5
1.56642 1.44297 2.0e-5
1.5674 1.44296 2.0e-5
1.56838 1.44295 2.0e-5
1.56937 1.44294 2.0e-5
1.57035 1.44293 2.0e-5
1.57134 1.44292 2.0e-5
1.57233 1.44291 2.0e-5
1.57332 1.4429 2.0e-5
1.57431 1.44289 2.0e-5
1.5753 1.44288 2.0e-5
1.57629 1.44287 2.0e-5
1.57729 1.44286 2.0e-5
1.57828 1.44285 2.0e-5
1.57928 1.44284 2.0e-5
1.58028 1.44283 2.0e-5
1.58128 1.44282 2.0e-5
1.58228 1.44281 2.0e-5
1.58328 1.4428 2.0e-5
1.58428 1.44279 2.0e-5
1.58529 1.44278 2.0e-5
1.58629 1.44277 2.0e-5
1.5873 1.44276 2.0e-5
1.58831 1.44275 2.0e-5
1.58932 1.44274 2.0e-5
1.59033 1.44273 2.0e-5
1.59134 1.44272 2.0e-5
1.59236 1.44271 2.0e-5
1.59337 1.4427 2.0e-5
1.59439 1.44269 2.0e-5
1.59541 1.44267 2.0e-5
1.59642 1.44266 2.0e-5
1.59744 1.44265 2.0e-5
1.59847 1.44264 2.0e-5
1.59949 1.44263 2.0e-5
1.60051 1.44262 2.0e-5
1.60154 1.44261 2.0e-5
1.60256 1.4426 2.0e-5
1.60359 1.44259 2.0e-5
1.60462 1.44258 2.0e-5
1.60565 1.44257 2.0e-5
1.60668 1.44256 2.0e-5
1.60772 1.44255 2.0e-5
1.60875 1.44254 2.0e-5
1.60979 1.44253 2.0e-5
1.61082 1.44252 2.0e-5
1.61186 1.4425 2.0e-5
1.6129 1.44249 2.0e-5
1.61394 1.44248 2.0e-5
1.61499 1.44247 2.0e-5
1.61603 1.44246 2.0e-5
1.61708 1.44245 2.0e-5
1.61812 1.44244 2.0e-5
1.61917 1.44243 2.0e-5
1.62022 1.44242 2.0e-5
1.62127 1.44241 2.0e-5
1.62232 1.4424 2.0e-5
1.62338 1.44239 2.0e-5
1.62443 1.44237 2.0e-5
1.62549 1.44236 2.0e-5
1.62655 1.44235 2.0e-5
1.6276 1.44234 2.0e-5
1.62866 1.44233 2.0e-5
1.62973 1.44232 2.0e-5
1.63079 1.44231 2.0e-5
1.63185 1.4423 2.0e-5
1.63292 1.44228 2.0e-5
1.63399 1.44227 2.0e-5
1.63506 1.44226 2.0e-5
1.63613 1.44225 2.0e-5
1.6372 1.44224 2.0e-5
1.63827 1.44223 2.0e-5
1.63934 1.44222 2.0e-5
1.64042 1.44221 2.0e-5
1.6415 1.44219 2.0e-5
1.64258 1.44218 2.0e-5
1.64366 1.44217 2.0e-5
1.64474 1.44216 2.0e-5
1.64582 1.44215 2.0e-5
1.6469 1.44214 2.0e-5
1.64799 1.44213 2.0e-5
1.64908 1.44211 2.0e-5
1.65017 1.4421 2.0e-5
1.65125 1.44209 2.0e-5
1.65235 1.44208 2.0e-5
1.65344 1.44207 2.0e-5
1.65453 1.44206 2.0e-5
1.65563 1.44204 2.0e-5
1.65673 1.44203 2.0e-5
1.65782 1.44202 2.0e-5
1.65893 1.44201 2.0e-5
1.66003 1.442 2.0e-5
1.66113 1.44199 2.0e-5
1.66223 1.44197 2.0e-5
1.66334 1.44196 2.0e-5
1.66445 1.44195 2.0e-5
1.66556 1.44194 2.0e-5
1.66667 1.44193 2.0e-5
1.66778 1.44191 2.0e-5
1.66889 1.4419 2.0e-5
1.67001 1.44189 2.0e-5
1.67112 1.44188 2.0e-5
1.67224 1.44187 2.0e-5
1.67336 1.44185 2.0e-5
1.67448 1.44184 2.0e-5
1.6756 1.44183 2.0e-5
1.67673 1.44182 2.0e-5
1.67785 1.4418 2.0e-5
1.67898 1.44179 2.0e-5
1.68011 1.44178 2.0e-5
1.68124 1.44177 2.0e-5
1.68237 1.44176 2.0e-5
1.6835 1.44174 2.0e-5
1.68464 1.44173 2.0e-5
1.68577 1.44172 2.0e-5
1.68691 1.44171 2.0e-5
1.68805 1.44169 2.0e-5
1.68919 1.44168 2.0e-5
1.69033 1.44167 2.0e-5
1.69147 1.44166 2.0e-5
1.69262 1.44164 2.0e-5
1.69377 1.44163 2.0e-5
1.69492 1.44162 2.0e-5
1.69607 1.44161 2.0e-5
1.69722 1.44159 2.0e-5
1.69837 1.44158 2.0e-5
1.69952 1.44157 2.0e-5
1.70068 1.44156 2.0e-5
1.70184 1.44154 2.0e-5
1.703 1.44153 2.0e-5
1.70416 1.44152 2.0e-5
1.70532 1.4415 2.0e-5
1.70648 1.44149 2.0e-5
1.70765 1.44148 2.0e-5
1.70882 1.44147 2.0e-5
1.70999 1.44145 2.0e-5
1.71116 1.44144 2.0e-5
1.71233 1.44143 2.0e-5
1.7135 1.44141 2.0e-5
1.71468 1.4414 2.0e-5
1.71585 1.44139 2.0e-5
1.71703 1.44137 2.0e-5
1.71821 1.44136 2.0e-5
1.71939 1.44135 2.0e-5
1.72058 1.44133 2.0e-5
1.72176 1.44132 2.0e-5
1.72295 1.44131 2.0e-5
1.72414 1.4413 2.0e-5
1.72533 1.44128 2.0e-5
1.72652 1.44127 2.0e-5
1.72771 1.44126 2.0e-5
1.72891 1.44124 2.0e-5
1.7301 1.44123 2.0e-5
1.7313 1.44121 2.0e-5
1.7325 1.4412 2.0e-5
1.7337 1.44119 2.0e-5
1.73491 1.44117 3.0e-5
1.73611 1.44116 3.0e-5
1.73732 1.44115 3.0e-5
1.73853 1.44113 3.0e-5
1.73974 1.44112 3.0e-5
1.74095 1.44111 3.0e-5
1.74216 1.44109 3.0e-5
1.74338 1.44108 3.0e-5
1.74459 1.44107 3.0e-5
1.74581 1.44105 3.0e-5
1.74703 1.44104 3.0e-5
1.74825 1.44102 3.0e-5
1.74948 1.44101 3.0e-5
1.7507 1.441 3.0e-5
1.75193 1.44098 3.0e-5
1.75316 1.44097 3.0e-5
1.75439 1.44095 3.0e-5
1.75562 1.44094 3.0e-5
1.75685 1.44093 3.0e-5
1.75809 1.44091 3.0e-5
1.75932 1.4409 3.0e-5
1.76056 1.44088 3.0e-5
1.7618 1.44087 3.0e-5
1.76305 1.44085 3.0e-5
1.76429 1.44084 3.0e-5
1.76554 1.44083 3.0e-5
1.76678 1.44081 3.0e-5
1.76803 1.4408 3.0e-5
1.76929 1.44078 3.0e-5
1.77054 1.44077 3.0e-5
1.77179 1.44075 3.0e-5
1.77305 1.44074 3.0e-5
1.77431 1.44073 3.0e-5
1.77557 1.44071 3.0e-5
1.77683 1.4407 3.0e-5
1.77809 1.44068 3.0e-5
1.77936 1.44067 3.0e-5
1.78063 1.44065 3.0e-5
1.7819 1.44064 3.0e-5
1.78317 1.44062 3.0e-5
1.78444 1.44061 3.0e-5
1.78571 1.44059 3.0e-5
1.78699 1.44058 3.0e-5
1.78827 1.44056 3.0e-5
1.78955 1.44055 3.0e-5
1.79083 1.44053 3.0e-5
1.79211 1.44052 3.0e-5
1.7934 1.4405 3.0e-5
1.79469 1.44049 3.0e-5
1.79598 1.44047 3.0e-5
1.79727 1.44046 3.0e-5
1.79856 1.44044 3.0e-5
1.79986 1.44043 3.0e-5
1.80115 1.44041 3.0e-5
1.80245 1.4404 3.0e-5
1.80375 1.44038 3.0e-5
1.80505 1.44037 3.0e-5
1.80636 1.44035 3.0e-5
1.80766 1.44034 3.0e-5
1.80897 1.44032 3.0e-5
1.81028 1.4403 3.0e-5
1.81159 1.44029 3.0e-5
1.81291 1.44027 3.0e-5
1.81422 1.44026 3.0e-5
1.81554 1.44024 3.0e-5
1.81686 1.44023 3.0e-5
1.81818 1.44021 3.0e-5
1.81951 1.4402 3.0e-5
1.82083 1.44018 3.0e-5
1.82216 1.44016 3.0e-5
1.82349 1.44015 3.0e-5
1.82482 1.44013 3.0e-5
1.82615 1.44012 3.0e-5
1.82749 1.4401 3.0e-5
1.82882 1.44008 3.0e-5
1.83016 1.44007 3.0e-5
1.8315 1.44005 3.0e-5
1.83284 1.44004 3.0e-5
1.83419 1.44002 3.0e-5
1.83554 1.44 3.0e-5
1.83688 1.43999 3.0e-5
1.83824 1.43997 3.0e-5
1.83959 1.43996 3.0e-5
1.84094 1.43994 3.0e-5
1.8423 1.43992 3.0e-5
1.84366 1.43991 3.0e-5
1.84502 1.43989 3.0e-5
1.84638 1.43987 3.0e-5
1.84775 1.43986 3.0e-5
1.84911 1.43984 3.0e-5
1.85048 1.43982 3.0e-5
1.85185 1.43981 3.0e-5
1.85322 1.43979 3.0e-5
1.8546 1.43977 3.0e-5
1.85598 1.43976 3.0e-5
1.85736 1.43974 3.0e-5
1.85874 1.43972 3.0e-5
1.86012 1.43971 3.0e-5
1.8615 1.43969 3.0e-5
1.86289 1.43967 3.0e-5
1.86428 1.43966 3.0e-5
1.86567 1.43964 3.0e-5
1.86706 1.43962 3.0e-5
1.86846 1.43961 3.0e-5
1.86986 1.43959 3.0e-5
1.87126 1.43957 3.0e-5
1.87266 1.43955 3.0e-5
1.87406 1.43954 3.0e-5
1.87547 1.43952 3.0e-5
1.87688 1.4395 3.0e-5
1.87829 1.43948 3.0e-5
1.8797 1.43947 3.0e-5
1.88111 1.43945 3.0e-5
1.88253 1.43943 3.0e-5
1.88395 1.43941 3.0e-5
1.88537 1.4394 3.0e-5
1.88679 1.43938 3.0e-5
1.88822 1.43936 3.0e-5
1.88964 1.43934 3.0e-5
1.89107 1.43933 3.0e-5
1.89251 1.43931 3.0e-5
1.89394 1.43929 3.0e-5
1.89538 1.43927 3.0e-5
1.89681 1.43925 3.0e-5
1.89825 1.43924 3.0e-5
1.8997 1.43922 3.0e-5
1.90114 1.4392 3.0e-5
1.90259 1.43918 3.0e-5
1.90404 1.43916 3.0e-5
1.90549 1.43915 3.0e-5
1.90694 1.43913 3.0e-5
1.9084 1.43911 3.0e-5
1.90985 1.43909 3.0e-5
1.91131 1.43907 3.0e-5
1.91278 1.43906 3.0e-5
1.91424 1.43904 3.0e-5
1.91571 1.43902 3.0e-5
1.91718 1.439 3.0e-5
1.91865 1.43898 3.0e-5
1.92012 1.43896 3.0e-5
1.9216 1.43894 3.0e-5
1.92308 1.43893 3.0e-5
1.92456 1.43891 3.0e-5
1.92604 1.43889 3.0e-5
1.92753 1.43887 3.0e-5
1.92901 1.43885 3.0e-5
1.9305 1.43883 3.0e-5
1.93199 1.43881 3.0e-5
1.93349 1.43879 3.0e-5
1.93498 1.43877 3.0e-5
1.93648 1.43875 4.0e-5
1.93798 1.43874 4.0e-5
1.93949 1.43872 4.0e-5
1.94099 1.4387 4.0e-5
1.9425 1.43868 4.0e-5
1.94401 1.43866 4.0e-5
1.94553 1.43864 4.0e-5
1.94704 1.43862 4.0e-5
1.94856 1.4386 4.0e-5
1.95008 1.43858 4.0e-5
1.9516 1.43856 4.0e-5
1.95313 1.43854 4.0e-5
1.95465 1.43852 4.0e-5
1.95618 1.4385 4.0e-5
1.95771 1.43848 4.0e-5
1.95925 1.43846 4.0e-5
1.96078 1.43844 4.0e-5
1.96232 1.43842 4.0e-5
1.96386 1.4384 4.0e-5
1.96541 1.43838 4.0e-5
1.96696 1.43836 4.0e-5
1.9685 1.43834 4.0e-5
1.97006 1.43832 4.0e-5
1.97161 1.4383 4.0e-5
1.97316 1.43828 4.0e-5
1.97472 1.43826 4.0e-5
1.97628 1.43824 4.0e-5
1.97785 1.43822 4.0e-5
1.97941 1.4382 4.0e-5
1.98098 1.43818 4.0e-5
1.98255 1.43816 4.0e-5
1.98413 1.43814 4.0e-5
1.9857 1.43812 4.0e-5
1.98728 1.4381 4.0e-5
1.98886 1.43808 4.0e-5
1.99045 1.43806 4.0e-5
1.99203 1.43803 4.0e-5
1.99362 1.43801 4.0e-5
1.99521 1.43799 4.0e-5
1.99681 1.43797 4.0e-5
1.9984 1.43795 4.0e-5
2.0 1.43793 4.0e-5
2.0016 1.43791 4.0e-5
2.00321 1.43789 4.0e-5
2.00481 1.43787 4.0e-5
2.00642 1.43784 4.0e-5
2.00803 1.43782 4.0e-5
2.00965 1.4378 4.0e-5
2.01126 1.43778 4.0e-5
2.01288 1.43776 4.0e-5
2.0145 1.43774 4.0e-5
2.01613 1.43771 4.0e-5
2.01776 1.43769 4.0e-5
2.01939 1.43767 4.0e-5
2.02102 1.43765 4.0e-5
2.02265 1.43763 4.0e-5
2.02429 1.4376 4.0e-5
2.02593 1.43758 4.0e-5
2.02758 1.43756 4.0e-5
2.02922 1.43754 4.0e-5
2.03087 1.43752 4.0e-5
2.03252 1.43749 4.0e-5
2.03417 1.43747 4.0e-5
2.03583 1.43745 4.0e-5
2.03749 1.43743 4.0e-5
2.03915 1.4374 4.0e-5
2.04082 1.43738 4.0e-5
2.04248 1.43736 4.0e-5
2.04415 1.43734 4.0e-5
2.04583 1.43731 4.0e-5
2.0475 1.43729 4.0e-5
2.04918 1.43727 4.0e-5
2.05086 1.43725 4.0e-5
2.05255 1.43722 4.0e-5
2.05423 1.4372 4.0e-5
2.05592 1.43718 4.0e-5
2.05761 1.43715 4.0e-5
2.05931 1.43713 4.0e-5
2.06101 1.43711 4.0e-5
2.06271 1.43708 4.0e-5
2.06441 1.43706 4.0e-5
2.06612 1.43704 4.0e-5
2.06782 1.43701 4.0e-5
2.06954 1.43699 4.0e-5
2.07125 1.43697 4.0e-5
2.07297 1.43694 4.0e-5
2.07469 1.43692 4.0e-5
2.07641 1.43689 4.0e-5
2.07814 1.43687 4.0e-5
2.07987 1.43685 4.0e-5
2.0816 1.43682 4.0e-5
2.08333 1.4368 4.0e-5
2.08507 1.43677 4.0e-5
2.08681 1.43675 4.0e-5
2.08855 1.43673 4.0e-5
2.0903 1.4367 4.0e-5
2.09205 1.43668 4.0e-5
2.0938 1.43665 4.0e-5
2.09556 1.43663 4.0e-5
2.09732 1.4366 4.0e-5
2.09908 1.43658 4.0e-5
2.10084 1.43655 4.0e-5
2.10261 1.43653 5.0e-5
2.10438 1.4365 5.0e-5
2.10615 1.43648 5.0e-5
2.10793 1.43645 5.0e-5
2.1097 1.43643 5.0e-5
2.11149 1.4364 5.0e-5
2.11327 1.43638 5.0e-5
2.11506 1.43635 5.0e-5
2.11685 1.43633 5.0e-5
2.11864 1.4363 5.0e-5
2.12044 1.43628 5.0e-5
2.12224 1.43625 5.0e-5
2.12404 1.43623 5.0e-5
2.12585 1.4362 5.0e-5
2.12766 1.43617 5.0e-5
2.12947 1.43615 5.0e-5
2.13129 1.43612 5.0e-5
2.13311 1.4361 5.0e-5
2.13493 1.43607 5.0e-5
2.13675 1.43604 5.0e-5
2.13858 1.43602 5.0e-5
2.14041 1.43599 5.0e-5
2.14225 1.43597 5.0e-5
2.14408 1.43594 5.0e-5
2.14592 1.43591 5.0e-5
2.14777 1.43589 5.0e-5
2.14961 1.43586 5.0e-5
2.15146 1.43583 5.0e-5
2.15332 1.43581 5.0e-5
2.15517 1.43578 5.0e-5
2.15703 1.43575 5.0e-5
2.15889 1.43573 5.0e-5
2.16076 1.4357 5.0e-5
2.16263 1.43567 5.0e-5
2.1645 1.43564 5.0e-5
2.16638 1.43562 5.0e-5
2.16826 1.43559 5.0e-5
2.17014 1.43556 5.0e-5
2.17202 1.43553 5.0e-5
2.17391 1.43551 5.0e-5
2.17581 1.43548 5.0e-5
2.1777 1.43545 5.0e-5
2.1796 1.43542 5.0e-5
2.1815 1.4354 5.0e-5
2.18341 1.43537 5.0e-5
2.18531 1.43534 5.0e-5
2.18723 1.43531 5.0e-5
2.18914 1.43528 5.0e-5
2.19106 1.43525 5.0e-5
2.19298 1.43523 5.0e-5
2.19491 1.4352 5.0e-5
2.19684 1.43517 5.0e-5
2.19877 1.43514 5.0e-5
2.2007 1.43511 5.0e-5
2.20264 1.43508 5.0e-5
2.20459 1.43505 5.0e-5
2.20653 1.43503 5.0e-5
2.20848 1.435 5.0e-5
2.21043 1.43497 5.0e-5
2.21239 1.43494 5.0e-5
2.21435 1.43491 5.0e-5
2.21631 1.43488 5.0e-5
2.21828 1.43485 5.0e-5
2.22025 1.43482 5.0e-5
2.22222 1.43479 5.0e-5
2.2242 1.43476 5.0e-5
2.22618 1.43473 5.0e-5
2.22816 1.4347 5.0e-5
2.23015 1.43467 5.0e-5
2.23214 1.43464 5.0e-5
2.23414 1.43461 5.0e-5
2.23614 1.43458 5.0e-5
2.23814 1.43455 5.0e-5
2.24014 1.43452 5.0e-5
2.24215 1.43449 5.0e-5
2.24417 1.43446 6.0e-5
2.24618 1.43443 6.0e-5
2.2482 1.4344 6.0e-5
2.25023 1.43437 6.0e-5
2.25225 1.43434 6.0e-5
2.25428 1.43431 6.0e-5
2.25632 1.43427 6.0e-5
2.25836 1.43424 6.0e-5
2.2604 1.43421 6.0e-5
2.26244 1.43418 6.0e-5
2.26449 1.43415 6.0e-5
2.26655 1.43412 6.0e-5
2.2686 1.43409 6.0e-5
2.27066 1.43405 6.0e-5
2.27273 1.43402 6.0e-5
2.2748 1.43399 6.0e-5
2.27687 1.43396 6.0e-5
2.27894 1.43393 6.0e-5
2.28102 1.43389 6.0e-5
2.28311 1.43386 6.0e-5
2.28519 1.43383 6.0e-5
2.28728 1.4338 6.0e-5
2.28938 1.43376 6.0e-5
2.29148 1.43373 6.0e-5
2.29358 1.4337 6.0e-5
2.29568 1.43367 6.0e-5
2.29779 1.43363 6.0e-5
2.29991 1.4336 6.0e-5
2.30203 1.43357 6.0e-5
2.30415 1.43353 6.0e-5
2.30627 1.4335 6.0e-5
2.3084 1.43347 6.0e-5
2.31054 1.43343 6.0e-5
2.31267 1.4334 6.0e-5
2.31481 1.43337 6.0e-5
2.31696 1.43333 6.0e-5
2.31911 1.4333 6.0e-5
2.32126 1.43326 6.0e-5
2.32342 1.43323 6.0e-5
2.32558 1.43319 6.0e-5
2.32775 1.43316 6.0e-5
2.32992 1.43313 6.0e-5
2.33209 1.43309 6.0e-5
2.33427 1.43306 6.0e-5
2.33645 1.43302 6.0e-5
2.33863 1.43299 6.0e-5
2.34082 1.43295 6.0e-5
2.34302 1.43292 6.0e-5
2.34522 1.43288 6.0e-5
2.34742 1.43285 6.0e-5
2.34962 1.43281 6.0e-5
2.35183 1.43278 6.0e-5
2.35405 1.43274 6.0e-5
2.35627 1.4327 6.0e-5
2.35849 1.43267 6.0e-5
2.36072 1.43263 6.0e-5
2.36295 1.4326 6.0e-5
2.36518 1.43256 6.0e-5
2.36742 1.43252 6.0e-5
2.36967 1.43249 7.0e-5
2.37192 1.43245 7.0e-5
2.37417 1.43241 7.0e-5
2.37643 1.43238 7.0e-5
2.37869 1.43234 7.0e-5
2.38095 1.4323 7.0e-5
2.38322 1.43227 7.0e-5
2.3855 1.43223 7.0e-5
2.38777 1.43219 7.0e-5
2.39006 1.43215 7.0e-5
2.39234 1.43212 7.0e-5
2.39464 1.43208 7.0e-5
2.39693 1.43204 7.0e-5
2.39923 1.432 7.0e-5
2.40154 1.43197 7.0e-5
2.40385 1.43193 7.0e-5
2.40616 1.43189 7.0e-5
2.40848 1.43185 7.0e-5
2.4108 1.43181 7.0e-5
2.41313 1.43177 7.0e-5
2.41546 1.43173 7.0e-5
2.41779 1.4317 7.0e-5
2.42014 1.43166 7.0e-5
2.42248 1.43162 7.0e-5
2.42483 1.43158 7.0e-5
2.42718 1.43154 7.0e-5
2.42954 1.4315 7.0e-5
2.43191 1.43146 7.0e-5
2.43427 1.43142 7.0e-5
2.43665 1.43138 7.0e-5
2.43902 1.43134 7.0e-5
2.44141 1.4313 7.0e-5
2.44379 1.43126 7.0e-5
2.44618 1.43122 7.0e-5
2.44858 1.43118 7.0e-5
2.45098 1.43114 7.0e-5
2.45339 1.4311 7.0e-5
2.4558 1.43106 7.0e-5
2.45821 1.43102 7.0e-5
2.46063 1.43097 7.0e-5
2.46305 1.43093 7.0e-5
2.46548 1.43089 7.0e-5
2.46792 1.43085 7.0e-5
2.47036 1.43081 7.0e-5
2.4728 1.43077 7.0e-5
2.47525 1.43072 7.0e-5
2.4777 1.43068 7.0e-5
2.48016 1.43064 8.0e-5
2.48262 1.4306 8.0e-5
2.48509 1.43056 8.0e-5
2.48756 1.43051 8.0e-5
2.49004 1.43047 8.0e-5
2.49252 1.43043 8.0e-5
2.49501 1.43038 8.0e-5
2.4975 1.43034 8.0e-5
2.5 1.4303 8.0e-5
2.5025 1.43025 8.0e-5
2.50501 1.43021 8.0e-5
2.50752 1.43017 8.0e-5
2.51004 1.43012 8.0e-5
2.51256 1.43008 8.0e-5
2.51509 1.43003 8.0e-5
2.51762 1.42999 8.0e-5
2.52016 1.42995 8.0e-5
2.5227 1.4299 8.0e-5
2.52525 1.42986 8.0e-5
2.52781 1.42981 8.0e-5
2.53036 1.42977 8.0e-5
2.53293 1.42972 8.0e-5
2.5355 1.42968 8.0e-5
2.53807 1.42963 8.0e-5
2.54065 1.42958 8.0e-5
2.54323 1.42954 8.0e-5
2.54582 1.42949 8.0e-5
2.54842 1.42945 8.0e-5
2.55102 1.4294 8.0e-5
2.55363 1.42935 8.0e-5
2.55624 1.42931 8.0e-5
2.55885 1.42926 8.0e-5
2.56148 1.42921 8.0e-5
2.5641 1.42917 8.0e-5
2.56674 1.42912 8.0e-5
2.56937 1.42907 8.0e-5
2.57202 1.42902 8.0e-5
2.57467 1.42898 8.0e-5
2.57732 1.42893 8.0e-5
2.57998 1.42888 8.0e-5
2.58264 1.42883 9.0e-5
2.58532 1.42878 9.0e-5
2.58799 1.42873 9.0e-5
2.59067 1.42869 9.0e-5
2.59336 1.42864 9.0e-5
2.59605 1.42859 9.0e-5
2.59875 1.42854 9.0e-5
2.60146 1.42849 9.0e-5
2.60417 1.42844 9.0e-5
2.60688 1.42839 9.0e-5
2.6096 1.42834 9.0e-5
2.61233 1.42829 9.0e-5
2.61506 1.42824 9.0e-5
2.6178 1.42819 9.0e-5
2.62055 1.42814 9.0e-5
2.62329 1.42809 9.0e-5
2.62605 1.42804 9.0e-5
2.62881 1.42799 9.0e-5
2.63158 1.42793 9.0e-5
2.63435 1.42788 9.0e-5
2.63713 1.42783 9.0e-5
2.63992 1.42778 9.0e-5
2.64271 1.42773 9.0e-5
2.6455 1.42767 9.0e-5
2.64831 1.42762 9.0e-5
2.65111 1.42757 9.0e-5
2.65393 1.42752 9.0e-5
2.65675 1.42746 9.0e-5
2.65957 1.42741 9.0e-5
2.66241 1.42736 9.0e-5
2.66525 1.4273 9.0e-5
2.66809 1.42725 9.0e-5
2.67094 1.4272 9.0e-5
2.6738 1.42714 9.0e-5
2.67666 1.42709 0.0001
2.67953 1.42703 0.0001
2.6824 1.42698 0.0001
2.68528 1.42692 0.0001
2.68817 1.42687 0.0001
2.69107 1.42681 0.0001
2.69397 1.42676 0.0001
2.69687 1.4267 0.0001
2.69978 1.42665 0.0001
2.7027 1.42659 0.0001
2.70563 1.42653 0.0001
2.70856 1.42648 0.0001
2.7115 1.42642 0.0001
2.71444 1.42636 0.0001
2.71739 1.42631 0.0001
2.72035 1.42625 0.0001
2.72331 1.42619 0.0001
2.72628 1.42614 0.0001
2.72926 1.42608 0.0001
2.73224 1.42602 0.0001
2.73523 1.42596 0.0001
2.73823 1.4259 0.0001
2.74123 1.42584 0.0001
2.74424 1.42578 0.0001
2.74725 1.42573 0.0001
2.75028 1.42567 0.0001
2.7533 1.42561 0.0001
2.75634 1.42555 0.0001
2.75938 1.42549 0.0001
2.76243 1.42543 0.0001
2.76549 1.42537 0.00011
2.76855 1.4253 0.00011
2.77162 1.42524 0.00011
2.77469 1.42518 0.00011
2.77778 1.42512 0.00011
2.78087 1.42506 0.00011
2.78396 1.425 0.00011
2.78707 1.42494 0.00011
2.79018 1.42487 0.00011
2.7933 1.42481 0.00011
2.79642 1.42475 0.00011
2.79955 1.42468 0.00011
2.80269 1.42462 0.00011
2.80584 1.42456 0.00011
2.80899 1.42449 0.00011
2.81215 1.42443 0.00011
2.81532 1.42437 0.00011
2.81849 1.4243 0.00011
2.82167 1.42424 0.00011
2.82486 1.42417 0.00011
2.82805 1.42411 0.00011
2.83126 1.42404 0.00011
2.83447 1.42398 0.00011
2.83768 1.42391 0.00011
2.84091 1.42384 0.00011
2.84414 1.42378 0.00012
2.84738 1.42371 0.00012
2.85063 1.42364 0.00012
2.85388 1.42358 0.00012
2.85714 1.42351 0.00012
2.86041 1.42344 0.00012
2.86369 1.42337 0.00012
2.86697 1.4233 0.00012
2.87026 1.42324 0.00012
2.87356 1.42317 0.00012
2.87687 1.4231 0.00012
2.88018 1.42303 0.00012
2.88351 1.42296 0.00012
2.88684 1.42289 0.00012
2.89017 1.42282 0.00012
2.89352 1.42275 0.00012
2.89687 1.42268 0.00012
2.90023 1.42261 0.00012
2.9036 1.42254 0.00012
2.90698 1.42246 0.00012
2.91036 1.42239 0.00012
2.91375 1.42232 0.00012
2.91715 1.42225 0.00012
2.92056 1.42218 0.00013
2.92398 1.4221 0.00013
2.9274 1.42203 0.00013
2.93083 1.42196 0.00013
2.93427 1.42188 0.00013
2.93772 1.42181 0.00013
2.94118 1.42173 0.00013
2.94464 1.42166 0.00013
2.94811 1.42158 0.00013
2.95159 1.42151 0.00013
2.95508 1.42143 0.00013
2.95858 1.42136 0.00013
2.96209 1.42128 0.00013
2.9656 1.4212 0.00013
2.96912 1.42113 0.00013
2.97265 1.42105 0.00013
2.97619 1.42097 0.00013
2.97974 1.42089 0.00013
2.98329 1.42082 0.00013
2.98686 1.42074 0.00013
2.99043 1.42066 0.00013
2.99401 1.42058 0.00014
2.9976 1.4205 0.00014
3.0012 1.42042 0.00014
3.00481 1.42034 0.00014
3.00842 1.42026 0.00014
3.01205 1.42018 0.00014
3.01568 1.4201 0.00014
3.01932 1.42002 0.00014
3.02297 1.41994 0.00014
3.02663 1.41985 0.00014
3.0303 1.41977 0.00014
3.03398 1.41969 0.00014
3.03767 1.41961 0.00014
3.04136 1.41952 0.00014
3.04507 1.41944 0.00014
3.04878 1.41935 0.00014
3.0525 1.41927 0.00014
3.05623 1.41918 0.00014
3.05998 1.4191 0.00014
3.06373 1.41901 0.00015
3.06748 1.41893 0.00015
3.07125 1.41884 0.00015
3.07503 1.41875 0.00015
3.07882 1.41867 0.00015
3.08261 1.41858 0.00015
3.08642 1.41849 0.00015
3.09023 1.4184 0.00015
3.09406 1.41832 0.00015
3.09789 1.41823 0.00015
3.10174 1.41814 0.00015
3.10559 1.41805 0.00015
3.10945 1.41796 0.00015
3.11333 1.41787 0.00015
3.11721 1.41778 0.00015
3.1211 1.41769 0.00015
3.125 1.41759 0.00015
3.12891 1.4175 0.00016
3.13283 1.41741 0.00016
3.13676 1.41732 0.00016
3.1407 1.41722 0.00016
3.14465 1.41713 0.00016
3.14861 1.41704 0.00016
3.15259 1.41694 0.00016
3.15657 1.41685 0.00016
3.16056 1.41675 0.00016
3.16456 1.41666 0.00016
3.16857 1.41656 0.00016
3.17259 1.41646 0.00016
3.17662 1.41637 0.00016
3.18066 1.41627 0.00016
3.18471 1.41617 0.00016
3.18878 1.41607 0.00017
3.19285 1.41598 0.00017
3.19693 1.41588 0.00017
3.20102 1.41578 0.00017
3.20513 1.41568 0.00017
3.20924 1.41558 0.00017
3.21337 1.41548 0.00017
3.2175 1.41537 0.00017
3.22165 1.41527 0.00017
3.22581 1.41517 0.00017
3.22997 1.41507 0.00017
3.23415 1.41496 0.00017
3.23834 1.41486 0.00017
3.24254 1.41476 0.00017
3.24675 1.41465 0.00018
3.25098 1.41455 0.00018
3.25521 1.41444 0.00018
3.25945 1.41434 0.00018
3.26371 1.41423 0.00018
3.26797 1.41412 0.00018
3.27225 1.41401 0.00018
3.27654 1.41391 0.00018
3.28084 1.4138 0.00018
3.28515 1.41369 0.00018
3.28947 1.41358 0.00018
3.29381 1.41347 0.00018
3.29815 1.41336 0.00018
3.30251 1.41325 0.00018
3.30688 1.41314 0.00019
3.31126 1.41302 0.00019
3.31565 1.41291 0.00019
3.32005 1.4128 0.00019
3.32447 1.41269 0.00019
3.32889 1.41257 0.00019
3.33333 1.41246 0.00019
3.33778 1.41234 0.00019
3.34225 1.41223 0.00019
3.34672 1.41211 0.00019
3.35121 1.41199 0.00019
3.3557 1.41187 0.00019
3.36022 1.41176 0.0002
3.36474 1.41164 0.0002
3.36927 1.41152 0.0002
3.37382 1.4114 0.0002
3.37838 1.41128 0.0002
3.38295 1.41116 0.0002
3.38753 1.41104 0.0002
3.39213 1.41092 0.0002
3.39674 1.41079 0.0002
3.40136 1.41067 0.0002
3.40599 1.41055 0.0002
3.41064 1.41042 0.00021
3.4153 1.4103 0.00021
3.41997 1.41017 0.00021
3.42466 1.41004 0.00021
3.42936 1.40992 0.00021
3.43407 1.40979 0.00021
3.43879 1.40966 0.00021
3.44353 1.40953 0.00021
3.44828 1.4094 0.00021
3.45304 1.40927 0.00021
3.45781 1.40914 0.00021
3.4626 1.40901 0.00022
3.46741 1.40888 0.00022
3.47222 1.40875 0.00022
3.47705 1.40861 0.00022
3.48189 1.40848 0.00022
3.48675 1.40835 0.00022
3.49162 1.40821 0.00022
3.4965 1.40807 0.00022
3.5014 1.40794 0.00022
3.50631 1.4078 0.00022
3.51124 1.40766 0.00023
3.51617 1.40752 0.00023
3.52113 1.40738 0.00023
3.52609 1.40724 0.00023
3.53107 1.4071 0.00023
3.53607 1.40696 0.00023
3.54108 1.40682 0.00023
3.5461 1.40668 0.00023
3.55114 1.40653 0.00023
3.55619 1.40639 0.00023
3.56125 1.40624 0.00024
3.56633 1.4061 0.00024
3.57143 1.40595 0.00024
3.57654 1.4058 0.00024
3.58166 1.40566 0.00024
3.5868 1.40551 0.00024
3.59195 1.40536 0.00024
3.59712 1.40521 0.00024
3.60231 1.40505 0.00024
3.6075 1.4049 0.00025
3.61272 1.40475 0.00025
3.61795 1.4046 0.00025
3.62319 1.40444 0.00025
3.62845 1.40429 0.00025
3.63372 1.40413 0.00025
3.63901 1.40397 0.00025
3.64431 1.40381 0.00025
3.64964 1.40366 0.00026
3.65497 1.4035 0.00026
3.66032 1.40334 0.00026
3.66569 1.40317 0.00026
3.67107 1.40301 0.00026
3.67647 1.40285 0.00026
3.68189 1.40269 0.00026
3.68732 1.40252 0.00026
3.69276 1.40235 0.00027
3.69822 1.40219 0.00027
3.7037 1.40202 0.00027
3.7092 1.40185 0.00027
3.71471 1.40168 0.00027
3.72024 1.40151 0.00027
3.72578 1.40134 0.00027
3.73134 1.40117 0.00027
3.73692 1.401 0.00028
3.74251 1.40082 0.00028
3.74813 1.40065 0.00028
3.75375 1.40047 0.00028
3.7594 1.40029 0.00028
3.76506 1.40012 0.00028
3.77074 1.39994 0.00028
3.77644 1.39976 0.00029
3.78215 1.39958 0.00029
3.78788 1.39939 0.00029
3.79363 1.39921 0.00029
3.79939 1.39903 0.00029
3.80518 1.39884 0.00029
3.81098 1.39865 0.00029
3.81679 1.39847 0.0003
3.82263 1.39828 0.0003
3.82848 1.39809 0.0003
3.83436 1.3979 0.0003
3.84025 1.39771 0.0003
3.84615 1.39751 0.0003
3.85208 1.39732 0.00031
3.85802 1.39713 0.00031
3.86399 1.39693 0.00031
3.86997 1.39673 0.00031
3.87597 1.39653 0.00031
3.88199 1.39633 0.00031
3.88802 1.39613 0.00031
3.89408 1.39593 0.00032
3.90016 1.39573 0.00032
3.90625 1.39552 0.00032
3.91236 1.39532 0.00032
3.9185 1.39511 0.00032
3.92465 1.3949 0.00032
3.93082 1.39469 0.00033
3.93701 1.39448 0.00033
3.94322 1.39427 0.00033
3.94945 1.39406 0.00033
3.9557 1.39384 0.00033
3.96197 1.39363 0.00034
3.96825 1.39341 0.00034
3.97456 1.39319 0.00034
3.98089 1.39297 0.00034
3.98724 1.39275 0.00034
3.99361 1.39253 0.00034
4.0 1.39231 0.00035
4.00641 1.39208 0.00035
4.01284 1.39186 0.00035
4.01929 1.39163 0.00035
4.02576 1.3914 0.00035
4.03226 1.39117 0.00036
4.03877 1.39094 0.00036
4.04531 1.3907 0.00036
4.05186 1.39047 0.00036
4.05844 1.39023 0.00036
4.06504 1.38999 0.00037
4.07166 1.38975 0.00037
4.0783 1.38951 0.00037
4.08497 1.38927 0.00037
4.09165 1.38903 0.00037
4.09836 1.38878 0.00038
4.10509 1.38853 0.00038
4.11184 1.38828 0.00038
4.11862 1.38803 0.00038
4.12541 1.38778 0.00038
4.13223 1.38753 0.00039
4.13907 1.38727 0.00039
4.14594 1.38702 0.00039
4.15282 1.38676 0.00039
4.15973 1.3865 0.00039
4.16667 1.38623 0.0004
4.17362 1.38597 0.0004
4.1806 1.38571 0.0004
4.1876 1.38544 0.0004
4.19463 1.38517 0.00041
4.20168 1.3849 0.00041
4.20875 1.38463 0.00041
4.21585 1.38435 0.00041
4.22297 1.38408 0.00042
4.23012 1.3838 0.00042
4.23729 1.38352 0.00042
4.24448 1.38324 0.00042
4.2517 1.38295 0.00043
4.25894 1.38267 0.00043
4.26621 1.38238 0.00043
4.2735 1.38209 0.00043
4.28082 1.3818 0.00044
4.28816 1.3815 0.00044
4.29553 1.38121 0.00044
4.30293 1.38091 0.00044
4.31034 1.38061 0.00045
4.31779 1.38031 0.00045
4.32526 1.38 0.00045
4.33276 1.3797 0.00045
4.34028 1.37939 0.00046
4.34783 1.37908 0.00046
4.3554 1.37877 0.00046
4.363 1.37845 0.00047
4.37063 1.37813 0.00047
4.37828 1.37782 0.00047
4.38596 1.37749 0.00047
4.39367 1.37717 0.00048
4.40141 1.37684 0.00048
4.40917 1.37651 0.00048
4.41696 1.37618 0.00049
4.42478 1.37585 0.00049
4.43262 1.37551 0.00049
4.4405 1.37518 0.00049
4.4484 1.37484 0.0005
4.45633 1.37449 0.0005
4.46429 1.37415 0.0005
4.47227 1.3738 0.00051
4.48029 1.37345 0.00051
4.48833 1.37309 0.00051
4.4964 1.37274 0.00052
4.5045 1.37238 0.00052
4.51264 1.37202 0.00052
4.5208 1.37165 0.00053
4.52899 1.37129 0.00053
4.53721 1.37092 0.00053
4.54545 1.37054 0.00054
4.55373 1.37017 0.00054
4.56204 1.36979 0.00054
4.57038 1.36941 0.00055
4.57875 1.36902 0.00055
4.58716 1.36864 0.00055
4.59559 1.36825 0.00056
4.60405 1.36785 0.00056
4.61255 1.36746 0.00057
4.62107 1.36706 0.00057
4.62963 1.36665 0.00057
4.63822 1.36625 0.00058
4.64684 1.36584 0.00058
4.65549 1.36543 0.00058
4.66418 1.36501 0.00059
4.6729 1.36459 0.00059
4.68165 1.36417 0.0006
4.69043 1.36374 0.0006
4.69925 1.36331 0.0006
4.7081 1.36288 0.00061
4.71698 1.36245 0.00061
4.7259 1.36201 0.00062
4.73485 1.36156 0.00062
4.74383 1.36112 0.00062
4.75285 1.36066 0.00063
4.7619 1.36021 0.00063
4.77099 1.35975 0.00064
4.78011 1.35929 0.00064
4.78927 1.35882 0.00065
4.79846 1.35835 0.00065
4.80769 1.35788 0.00066
4.81696 1.3574 0.00066
4.82625 1.35692 0.00067
4.83559 1.35643 0.00067
4.84496 1.35594 0.00067
4.85437 1.35545 0.00068
4.86381 1.35495 0.00068
4.87329 1.35445 0.00069
4.88281 1.35394 0.00069
4.89237 1.35343 0.0007
4.90196 1.35291 0.0007
4.91159 1.35239 0.00071
4.92126 1.35186 0.00071
4.93097 1.35133 0.00072
4.94071 1.3508 0.00073
4.9505 1.35026 0.00073
4.96032 1.34971 0.00074
4.97018 1.34916 0.00074
4.98008 1.34861 0.00075
4.99002 1.34805 0.00075
5.0 1.34748 0.00076
5.01002 1.34691 0.00076
5.02008 1.34633 0.00077
5.03018 1.34575 0.00078
5.04032 1.34517 0.00078
5.05051 1.34457 0.00079
5.06073 1.34398 0.00079
5.07099 1.34337 0.0008
5.0813 1.34276 0.00081
5.09165 1.34215 0.00081
5.10204 1.34153 0.00082
5.11247 1.3409 0.00082
5.12295 1.34027 0.00083
5.13347 1.33963 0.00084
5.14403 1.33899 0.00084
5.15464 1.33833 0.00085
5.16529 1.33768 0.00086
5.17598 1.33701 0.00086
5.18672 1.33634 0.00087
5.19751 1.33566 0.00088
5.20833 1.33498 0.00089
5.21921 1.33429 0.00089
5.23013 1.33359 0.0009
5.24109 1.33288 0.00091
5.2521 1.33217 0.00091
5.26316 1.33145 0.00092
5.27426 1.33072 0.00093
5.28541 1.32999 0.00094
5.29661 1.32924 0.00095
5.30786 1.32849 0.00095
5.31915 1.32774 0.00096
5.33049 1.32697 0.00097
5.34188 1.32619 0.00098
5.35332 1.32541 0.00099
5.36481 1.32462 0.00099
5.37634 1.32382 0.001
5.38793 1.32301 0.00101
5.39957 1.32219 0.00102
5.41126 1.32137 0.00103
5.42299 1.32053 0.00104
5.43478 1.31969 0.00105
5.44662 1.31883 0.00106
5.45852 1.31797 0.00107
5.47046 1.3171 0.00108
5.48246 1.31621 0.00109
5.49451 1.31532 0.0011
5.50661 1.31442 0.00111
5.51876 1.3135 0.00112
5.53097 1.31258 0.00113
5.54324 1.31164 0.00114
5.55556 1.31069 0.00115
5.56793 1.30974 0.00116
5.58036 1.30877 0.00117
5.59284 1.30779 0.00118
5.60538 1.30679 0.00119
5.61798 1.30579 0.0012
5.63063 1.30477 0.00121
5.64334 1.30374 0.00122
5.65611 1.3027 0.00124
5.66893 1.30165 0.00125
5.68182 1.30058 0.00126
5.69476 1.2995 0.00127
5.70776 1.2984 0.00129
5.72082 1.2973 0.0013
5.73394 1.29617 0.00131
5.74713 1.29504 0.00132
5.76037 1.29388 0.00134
5.77367 1.29272 0.00135
5.78704 1.29154 0.00137
5.80046 1.29034 0.00138
5.81395 1.28912 0.00139
5.82751 1.28789 0.00141
5.84112 1.28665 0.00142
5.8548 1.28538 0.00144
5.86854 1.2841 0.00145
5.88235 1.28281 0.00147
5.89623 1.28149 0.00149
5.91017 1.28016 0.0015
5.92417 1.2788 0.00152
5.93824 1.27743 0.00153
5.95238 1.27604 0.00155
5.96659 1.27463 0.00157
5.98086 1.27319 0.00159
5.9952 1.27174 0.0016
6.00962 1.27027 0.00162
6.0241 1.26877 0.00164
6.03865 1.26725 0.00166
6.05327 1.26571 0.00168
6.06796 1.26415 0.0017
6.08273 1.26256 0.00172
6.09756 1.26095 0.00174
6.11247 1.25931 0.00176
6.12745 1.25764 0.00178
6.14251 1.25595 0.00181
6.15764 1.25424 0.00183
6.17284 1.25249 0.00185
6.18812 1.25072 0.00187
6.20347 1.24892 0.0019
6.21891 1.24709 0.00192
6.23441 1.24523 0.00195
6.25 1.24334 0.00197
6.26566 1.24141 0.002
6.28141 1.23946 0.00203
6.29723 1.23747 0.00205
6.31313 1.23544 0.00208
6.32911 1.23338 0.00211
6.34518 1.23128 0.00214
6.36132 1.22915 0.00217
6.37755 1.22698 0.0022
6.39386 1.22476 0.00223
6.41026 1.22251 0.00227
6.42674 1.22022 0.0023
6.4433 1.21788 0.00233
6.45995 1.21549 0.00237
6.47668 1.21307 0.00241
6.49351 1.21059 0.00244
6.51042 1.20807 0.00248
6.52742 1.20549 0.00252
6.5445 1.20286 0.00256
6.56168 1.20019 0.00261
6.57895 1.19745 0.00265
6.59631 1.19466 0.00269
6.61376 1.19181 0.00274
6.6313 1.1889 0.00279
6.64894 1.18593 0.00284
6.66667 1.18289 0.00289
6.68449 1.17978 0.00295
6.70241 1.17661 0.003
6.72043 1.17336 0.00306
6.73854 1.17004 0.00312
6.75676 1.16664 0.00318
6.77507 1.16316 0.00325
6.79348 1.1596 0.00331
6.81199 1.15595 0.00339
6.8306 1.15221 0.00346
6.84932 1.14838 0.00354
6.86813 1.14445 0.00362
6.88705 1.14042 0.0037
6.90608 1.13628 0.00379
6.92521 1.13204 0.00389
6.94444 1.12767 0.00398
6.96379 1.12319 0.00409
6.98324 1.11858 0.0042
7.0028 1.11384 0.00432
7.02247 1.10896 0.00444
7.04225 1.10394 0.00457
7.06215 1.09877 0.00471
7.08215 1.09343 0.00486
7.10227 1.08793 0.00502
7.12251 1.08225 0.0052
7.14286 1.07639 0.00538
7.16332 1.07032 0.00558
7.18391 1.06406 0.0058
7.20461 1.05757 0.00603
7.22543 1.05085 0.00629
7.24638 1.04388 0.00657
7.26744 1.03665 0.00688
7.28863 1.02913 0.00722
7.30994 1.02132 0.00759
7.33138 1.01319 0.008
7.35294 1.00472 0.00846
7.37463 0.99589 0.00898
7.39645 0.98666 0.00956
7.4184 0.977 0.01022
7.44048 0.96689 0.01096
7.46269 0.95629 0.01181
7.48503 0.94515 0.01278
7.50751 0.93343 0.0139
7.53012 0.92108 0.0152
7.55287 0.90804 0.01672
7.57576 0.89424 0.01849
7.59878 0.87963 0.02058
7.62195 0.86413 0.02307
7.64526 0.84764 0.02603
7.66871 0.8301 0.02959
7.69231 0.8114 0.03388
7.71605 0.79147 0.03908
7.73994 0.77021 0.04543
7.76398 0.74758 0.05319
7.78816 0.72356 0.06272
7.8125 0.69819 0.07443
7.83699 0.67163 0.08881
7.86164 0.64421 0.10639
7.88644 0.61646 0.1277
7.91139 0.58921 0.15315
7.93651 0.56351 0.18289
7.96178 0.54054 0.21658
7.98722 0.52132 0.2534
8.01282 0.50638 0.29212
8.03859 0.49564 0.33153
8.06452 0.4886 0.37072
8.09061 0.48459 0.40924
8.11688 0.48309 0.44699
8.14332 0.48386 0.48403
8.16993 0.48688 0.52033
8.19672 0.49223 0.55563
8.22368 0.49989 0.58946
8.25083 0.50958 0.6212
8.27815 0.52066 0.65024
8.30565 0.53216 0.67628
8.33333 0.54295 0.69945
8.3612 0.55206 0.72038
8.38926 0.55888 0.74006
8.41751 0.56333 0.75958
8.44595 0.56586 0.7798
8.47458 0.56717 0.80107
8.5034 0.56782 0.82306
8.53242 0.56761 0.84504
8.56164 0.56528 0.86671
8.59107 0.55926 0.88913
8.62069 0.54901 0.91466
8.65052 0.53562 0.94547
8.68056 0.52092 0.9826
8.7108 0.50643 1.02616
8.74126 0.49305 1.07603
8.77193 0.48134 1.13242
8.80282 0.47204 1.19597
8.83392 0.46639 1.26754
8.86525 0.46637 1.34784
8.8968 0.47462 1.43703
8.92857 0.49418 1.53432
8.96057 0.52817 1.6378
8.99281 0.57931 1.74424
9.02527 0.64924 1.84907
9.05797 0.73752 1.94684
9.09091 0.84093 2.03267
9.12409 0.95412 2.10448
9.15751 1.0725 2.16419
9.19118 1.19557 2.21577
9.22509 1.32733 2.26057
9.25926 1.47188 2.29387
9.29368 1.62714 2.30736
9.32836 1.78426 2.29703
9.3633 1.93544 2.26706
9.3985 2.08084 2.2235
9.43396 2.22394 2.16431
9.4697 2.35725 2.0846
9.5057 2.47376 1.99475
9.54198 2.5828 1.89944
9.57854 2.68488 1.78965
9.61538 2.76898 1.66503
9.65251 2.83031 1.53603
9.68992 2.87413 1.41089
9.72763 2.90744 1.28965
9.76563 2.93182 1.1682
9.80392 2.94379 1.04494
9.84252 2.93983 0.92326
9.88142 2.92035 0.80887
9.92063 2.88951 0.70568
9.96016 2.85225 0.61411
10.0 2.8118 0.53217
10.04016 2.76904 0.45759
10.08065 2.72354 0.38927
10.12146 2.6749 0.32737
10.1626 2.62348 0.27266
10.20408 2.5704 0.22569
10.2459 2.51707 0.18645
10.28807 2.46479 0.15438
10.33058 2.41454 0.12857
10.37344 2.36687 0.10802
10.41667 2.32206 0.09175
10.46025 2.28013 0.07893
10.5042 2.24098 0.06886
10.54852 2.20442 0.061
10.59322 2.17023 0.05492
10.6383 2.13818 0.05029
10.68376 2.10805 0.04686
10.72961 2.07964 0.04446
10.77586 2.05275 0.04296
10.82251 2.02724 0.04228
10.86957 2.00296 0.04236
10.91703 1.9798 0.04317
10.96491 1.95769 0.04471
11.01322 1.93656 0.04696
11.06195 1.9164 0.04995
11.11111 1.89719 0.05366
11.16071 1.87896 0.05809
11.21076 1.86174 0.0632
11.26126 1.84556 0.06894
11.31222 1.83045 0.07525
11.36364 1.8164 0.08204
11.41553 1.80341 0.08924
11.46789 1.79143 0.09678
11.52074 1.78044 0.10464
11.57407 1.77039 0.11281
11.62791 1.76132 0.12133
11.68224 1.75327 0.13019
11.73709 1.74636 0.1394
11.79245 1.74074 0.14885
11.84834 1.73652 0.15839
11.90476 1.73378 0.16778
11.96172 1.73248 0.17672
12.01923 1.73247 0.18498
12.07729 1.73352 0.19237
12.13592 1.73537 0.19887
12.19512 1.73783 0.20453
12.2549 1.74082 0.20949
12.31527 1.74439 0.21381
12.37624 1.74866 0.21746
12.43781 1.75367 0.22019
12.5 1.7593 0.22171
12.56281 1.76517 0.22183
12.62626 1.77085 0.22064
12.69036 1.7761 0.21842
12.7551 1.78091 0.21548
12.82051 1.78543 0.21195
12.8866 1.78975 0.2078
12.95337 1.7939 0.20292
13.02083 1.79774 0.19719
13.08901 1.80107 0.19056
13.15789 1.80364 0.18315
13.22751 1.80528 0.17513
13.29787 1.80591 0.16676
13.36898 1.80555 0.15829
13.44086 1.80433 0.14989
13.51351 1.80239 0.14169
13.58696 1.79987 0.13369
13.6612 1.79685 0.12588
13.73626 1.79339 0.11821
13.81215 1.78948 0.11065
13.88889 1.78507 0.10319
13.96648 1.78013 0.09586
14.04494 1.77462 0.08873
14.12429 1.76854 0.08189
14.20455 1.76192 0.07544
14.28571 1.75483 0.06946]


text:
basicblock(inplanes, outplanes, downsample = false) = downsample ?
  Chain(Conv((3, 3), inplanes => outplanes[1], stride = 2, pad = 1),
        BatchNorm(outplanes[1], relu),
        Conv((3, 3), outplanes[1] => outplanes[2], stride = 1, pad = 1),
        BatchNorm(outplanes[2], relu)) :
  Chain(Conv((3, 3), inplanes => outplanes[1], stride = 1, pad = 1),
        BatchNorm(outplanes[1], relu),
        Conv((3, 3), outplanes[1] => outplanes[2], stride = 1, pad = 1),
        BatchNorm(outplanes[2], relu))

bottleneck(inplanes, outplanes, downsample = false) = downsample ?
  Chain(Conv((1, 1), inplanes => outplanes[1], stride = 2),
        BatchNorm(outplanes[1], relu),
        Conv((3, 3), outplanes[1] => outplanes[2], stride = 1, pad = 1),
        BatchNorm(outplanes[2], relu),
        Conv((1, 1), outplanes[2] => outplanes[3], stride = 1),
        BatchNorm(outplanes[3], relu)) :
  Chain(Conv((1, 1), inplanes => outplanes[1], stride = 1),
        BatchNorm(outplanes[1], relu),
        Conv((3, 3), outplanes[1] => outplanes[2], stride = 1, pad = 1),
        BatchNorm(outplanes[2], relu),
        Conv((1, 1), outplanes[2] => outplanes[3], stride = 1),
        BatchNorm(outplanes[3], relu))

function projection(inplanes, outplanes, downsample = false)
  shortcut = downsample ?
    Chain(Conv((1, 1), inplanes => outplanes, stride = 2),
          BatchNorm((outplanes), relu)) :
    Chain(Conv((1, 1), inplanes => outplanes, stride = 1),
          BatchNorm((outplanes), relu))
  return (x, y) -> x + shortcut(y)
end

# array -> PaddedView(0, array, outplanes) for zero padding arrays
function identity(inplanes, outplanes)
  if outplanes[end] > inplanes
    pool = MaxPool((1, 1), stride = 2)
    return (x, y) -> begin
      y = pool(y)
      y = cat(y, zeros(eltype(y), size(y, 1), size(y, 2), outplanes[end] - inplanes, size(y, 4)); dims = 3)
      x + y
    end
  else
    return +
  end
end

function resnet(block, shortcut_config, channel_config, block_config)
  inplanes = 64
  baseplanes = 64
  layers = []
  push!(layers, Conv((7, 7), 3=>inplanes, stride=(2, 2), pad=(3, 3)))
  push!(layers, BatchNorm(inplanes, relu))
  push!(layers, MaxPool((3, 3), stride=(2, 2), pad=(1, 1)))
  for (i, nrepeats) in enumerate(block_config)
    outplanes = baseplanes .* channel_config
    if shortcut_config == :A
      push!(layers, SkipConnection(block(inplanes, outplanes, i != 1),
                                   identity(inplanes, outplanes)))
    elseif shortcut_config == :B || shortcut_config == :C
      push!(layers, SkipConnection(block(inplanes, outplanes, i != 1),
                                   projection(inplanes, outplanes[end], i != 1)))
    end
    inplanes = outplanes[end]
    for j in 2:nrepeats
      if shortcut_config == :A || shortcut_config == :B
        push!(layers, SkipConnection(block(inplanes, outplanes, false),
                                     identity(inplanes, outplanes[end])))
      elseif shortcut_config == :C
        push!(layers, SkipConnection(block(inplanes, outplanes, false),
                                     projection(inplanes, outplanes, false)))
      end
      inplanes = outplanes[end]
    end
    baseplanes *= 2
  end
  push!(layers, AdaptiveMeanPool((1, 1)))
  push!(layers, flatten)
  push!(layers, Dense(inplanes, 1000))
  layers = Chain(layers...)
  Flux.testmode!(layers, false)
  return layers
end

const resnet_config =
Dict("resnet18" => ([1, 1], [2, 2, 2, 2]),
     "resnet34" => ([1, 1], [3, 4, 6, 3]),
     "resnet50" => ([1, 1, 4], [3, 4, 6, 3]),
     "resnet101" => ([1, 1, 4], [3, 4, 23, 3]),
     "resnet152" => ([1, 1, 4], [3, 8, 36, 3]))

ResNet18() = resnet(basicblock, :A, resnet_config["resnet18"]...)

ResNet34() = resnet(basicblock, :A, resnet_config["resnet34"]...)

ResNet50() = resnet(bottleneck, :B, resnet_config["resnet50"]...)

ResNet101() = resnet(bottleneck, :B, resnet_config["resnet101"]...)

ResNet152() = resnet(bottleneck, :B, resnet_config["resnet152"]...)


text:
using BioSymbols

using Test

function round_trip(x)
    io = IOBuffer()
    write(io, x)
    io = IOBuffer(take!(io))
    y = read(io, typeof(x))
    return x == y
end

@testset "BioSymbols" begin
    for i in alphabet(DNA)
        @test length(i) == 1
        @test collect(i) == [i]
    end
    for i in alphabet(RNA)
        @test length(i) == 1
        @test collect(i) == [i]
    end
    for i in alphabet(AminoAcid)
        @test length(i) == 1
        @test collect(i) == [i]
    end
end

@testset "NucleicAcids" begin
    @testset "Conversions" begin
        @testset "UInt8" begin
            @testset "DNA conversions from UInt8" begin
                @test convert(DNA, 0b0000) === DNA_Gap
                @test convert(DNA, 0b0001) === DNA_A
                @test convert(DNA, 0b0010) === DNA_C
                @test convert(DNA, 0b0011) === DNA_M
                @test convert(DNA, 0b0100) === DNA_G
                @test convert(DNA, 0b0101) === DNA_R
                @test convert(DNA, 0b0110) === DNA_S
                @test convert(DNA, 0b0111) === DNA_V
                @test convert(DNA, 0b1000) === DNA_T
                @test convert(DNA, 0b1001) === DNA_W
                @test convert(DNA, 0b1010) === DNA_Y
                @test convert(DNA, 0b1011) === DNA_H
                @test convert(DNA, 0b1100) === DNA_K
                @test convert(DNA, 0b1101) === DNA_D
                @test convert(DNA, 0b1110) === DNA_B
                @test convert(DNA, 0b1111) === DNA_N
            end

            @testset "RNA conversions from UInt8" begin
                @test convert(RNA, 0b0000) === RNA_Gap
                @test convert(RNA, 0b0001) === RNA_A
                @test convert(RNA, 0b0010) === RNA_C
                @test convert(RNA, 0b0011) === RNA_M
                @test convert(RNA, 0b0100) === RNA_G
                @test convert(RNA, 0b0101) === RNA_R
                @test convert(RNA, 0b0110) === RNA_S
                @test convert(RNA, 0b0111) === RNA_V
                @test convert(RNA, 0b1000) === RNA_U
                @test convert(RNA, 0b1001) === RNA_W
                @test convert(RNA, 0b1010) === RNA_Y
                @test convert(RNA, 0b1011) === RNA_H
                @test convert(RNA, 0b1100) === RNA_K
                @test convert(RNA, 0b1101) === RNA_D
                @test convert(RNA, 0b1110) === RNA_B
                @test convert(RNA, 0b1111) === RNA_N
            end

            @testset "DNA conversions to UInt8" begin
                @test convert(UInt8, DNA_Gap) === 0b0000
                @test convert(UInt8, DNA_A)   === 0b0001
                @test convert(UInt8, DNA_C)   === 0b0010
                @test convert(UInt8, DNA_M)   === 0b0011
                @test convert(UInt8, DNA_G)   === 0b0100
                @test convert(UInt8, DNA_R)   === 0b0101
                @test convert(UInt8, DNA_S)   === 0b0110
                @test convert(UInt8, DNA_V)   === 0b0111
                @test convert(UInt8, DNA_T)   === 0b1000
                @test convert(UInt8, DNA_W)   === 0b1001
                @test convert(UInt8, DNA_Y)   === 0b1010
                @test convert(UInt8, DNA_H)   === 0b1011
                @test convert(UInt8, DNA_K)   === 0b1100
                @test convert(UInt8, DNA_D)   === 0b1101
                @test convert(UInt8, DNA_B)   === 0b1110
                @test convert(UInt8, DNA_N)   === 0b1111
            end

            @testset "RNA conversions to UInt8" begin
                @test convert(UInt8, RNA_Gap) === 0b0000
                @test convert(UInt8, RNA_A)   === 0b0001
                @test convert(UInt8, RNA_C)   === 0b0010
                @test convert(UInt8, RNA_M)   === 0b0011
                @test convert(UInt8, RNA_G)   === 0b0100
                @test convert(UInt8, RNA_R)   === 0b0101
                @test convert(UInt8, RNA_S)   === 0b0110
                @test convert(UInt8, RNA_V)   === 0b0111
                @test convert(UInt8, RNA_U)   === 0b1000
                @test convert(UInt8, RNA_W)   === 0b1001
                @test convert(UInt8, RNA_Y)   === 0b1010
                @test convert(UInt8, RNA_H)   === 0b1011
                @test convert(UInt8, RNA_K)   === 0b1100
                @test convert(UInt8, RNA_D)   === 0b1101
                @test convert(UInt8, RNA_B)   === 0b1110
                @test convert(UInt8, RNA_N)   === 0b1111
            end
        end

        @testset "UInt64" begin
            @testset "DNA conversions from UInt64" begin
                @test convert(DNA, UInt64(0b0000)) === DNA_Gap
                @test convert(DNA, UInt64(0b0001)) === DNA_A
                @test convert(DNA, UInt64(0b0010)) === DNA_C
                @test convert(DNA, UInt64(0b0100)) === DNA_G
                @test convert(DNA, UInt64(0b1000)) === DNA_T
                @test convert(DNA, UInt64(0b1111)) === DNA_N
            end

            @testset "RNA conversions from UInt64" begin
                @test convert(RNA, UInt64(0b0000)) === RNA_Gap
                @test convert(RNA, UInt64(0b0001)) === RNA_A
                @test convert(RNA, UInt64(0b0010)) === RNA_C
                @test convert(RNA, UInt64(0b0100)) === RNA_G
                @test convert(RNA, UInt64(0b1000)) === RNA_U
                @test convert(RNA, UInt64(0b1111)) === RNA_N
            end

            @testset "DNA conversions to UInt64" begin
                @test convert(UInt64, DNA_Gap) === UInt64(0b0000)
                @test convert(UInt64, DNA_A)   === UInt64(0b0001)
                @test convert(UInt64, DNA_C)   === UInt64(0b0010)
                @test convert(UInt64, DNA_G)   === UInt64(0b0100)
                @test convert(UInt64, DNA_T)   === UInt64(0b1000)
                @test convert(UInt64, DNA_N)   === UInt64(0b1111)
            end

            @testset "RNA conversions to UInt64" begin
                @test convert(UInt64, RNA_Gap) === UInt64(0b0000)
                @test convert(UInt64, RNA_A)   === UInt64(0b0001)
                @test convert(UInt64, RNA_C)   === UInt64(0b0010)
                @test convert(UInt64, RNA_G)   === UInt64(0b0100)
                @test convert(UInt64, RNA_U)   === UInt64(0b1000)
                @test convert(UInt64, RNA_N)   === UInt64(0b1111)
            end
        end

        @testset "Char" begin
            @testset "DNA conversions from Char" begin
                @test convert(DNA, 'A') === DNA('A') === DNA_A
                @test convert(DNA, 'C') === DNA('C') === DNA_C
                @test convert(DNA, 'G') === DNA('G') === DNA_G
                @test convert(DNA, 'T') === DNA('T') === DNA_T
                @test convert(DNA, 'N') === DNA('N') === DNA_N
                @test_throws InexactError convert(DNA, 'Z')
                @test_throws InexactError convert(DNA, '核')
            end

            @testset "RNA conversions from Char" begin
                @test convert(RNA, 'A') === RNA('A') === RNA_A
                @test convert(RNA, 'C') === RNA('C') === RNA_C
                @test convert(RNA, 'G') === RNA('G') === RNA_G
                @test convert(RNA, 'U') === RNA('U') === RNA_U
                @test convert(RNA, 'N') === RNA('N') === RNA_N
                @test_throws InexactError convert(RNA, 'Z')
                @test_throws InexactError convert(RNA, '核')
            end

            @testset "DNA conversions to Char" begin
                @test convert(Char, DNA_A) === Char(DNA_A) === 'A'
                @test convert(Char, DNA_C) === Char(DNA_C) === 'C'
                @test convert(Char, DNA_G) === Char(DNA_G) === 'G'
                @test convert(Char, DNA_T) === Char(DNA_T) === 'T'
                @test convert(Char, DNA_N) === Char(DNA_N) === 'N'
            end

            @testset "RNA conversions to Char" begin
                @test convert(Char, RNA_A) === Char(RNA_A) === 'A'
                @test convert(Char, RNA_C) === Char(RNA_C) === 'C'
                @test convert(Char, RNA_G) === Char(RNA_G) === 'G'
                @test convert(Char, RNA_U) === Char(RNA_U) === 'U'
                @test convert(Char, RNA_N) === Char(RNA_N) === 'N'
            end
        end

        @testset "Other numeric types" begin
            @test convert(Int, DNA_A) === 1
            @test convert(Int, DNA_C) === 2
            @test convert(Int, DNA_G) === 4
            @test convert(Int, DNA_T) === 8
            @test convert(Int, DNA_N) === 15
            @test convert(DNA,  1) === DNA_A
            @test convert(DNA,  2) === DNA_C
            @test convert(DNA,  4) === DNA_G
            @test convert(DNA,  8) === DNA_T
            @test convert(DNA, 15) === DNA_N

            @test convert(Int, RNA_A) === 1
            @test convert(Int, RNA_C) === 2
            @test convert(Int, RNA_G) === 4
            @test convert(Int, RNA_U) === 8
            @test convert(Int, RNA_N) === 15
            @test convert(RNA,  1) === RNA_A
            @test convert(RNA,  2) === RNA_C
            @test convert(RNA,  4) === RNA_G
            @test convert(RNA,  8) === RNA_U
            @test convert(RNA, 15) === RNA_N
        end

        @testset "Nucleic acid types" begin
            fromto = [(DNA_Gap, RNA_Gap), (DNA_A, RNA_A), (DNA_C, RNA_C),
                      (DNA_M, RNA_M), (DNA_G, RNA_G), (DNA_R, RNA_R),
                      (DNA_S, RNA_S), (DNA_V, RNA_V), (DNA_T, RNA_U),
                      (DNA_W, RNA_W), (DNA_Y, RNA_Y), (DNA_H, RNA_H),
                      (DNA_K, RNA_K), (DNA_D, RNA_D), (DNA_B, RNA_B), (DNA_N, RNA_N)]

            for (from, to) in fromto
                @test convert(RNA, from) === RNA(from) === to
                @test convert(DNA, to) === DNA(to) === from
            end
        end
    end

    @testset "iscompatible" begin
        @test  iscompatible(DNA_A, DNA_A)
        @test  iscompatible(DNA_A, DNA_R)
        @test !iscompatible(DNA_C, DNA_A)
        @test !iscompatible(DNA_C, DNA_R)

        for x in alphabet(DNA)
            @test iscompatible(x, DNA_N) == (x != DNA_Gap)
            @test iscompatible(DNA_N, x) == (x != DNA_Gap)
        end

        @test  iscompatible(RNA_A, RNA_A)
        @test  iscompatible(RNA_A, RNA_R)
        @test !iscompatible(RNA_C, RNA_A)
        @test !iscompatible(RNA_C, RNA_R)

        for x in alphabet(RNA)
            @test iscompatible(x, RNA_N) == (x != RNA_Gap)
            @test iscompatible(RNA_N, x) == (x != RNA_Gap)
        end
    end

    @testset "isambiguous" begin
        for nt in alphabet(DNA)
            @test isambiguous(nt) == (nt ∉ (DNA_A, DNA_C, DNA_G, DNA_T, DNA_Gap))
        end
        for nt in alphabet(RNA)
            @test isambiguous(nt) == (nt ∉ (RNA_A, RNA_C, RNA_G, RNA_U, RNA_Gap))
        end
    end

    @testset "isGC" begin
        for nt in alphabet(DNA)
            @test isGC(nt) == (nt ∈ (DNA_G, DNA_C, DNA_S))
        end
        for nt in alphabet(RNA)
            @test isGC(nt) == (nt ∈ (RNA_G, RNA_C, RNA_S))
        end
    end

    @testset "ispurine" begin
        for nt in alphabet(DNA)
            @test ispurine(nt) == (nt == DNA_A || nt == DNA_G || nt == DNA_R)
        end
        for nt in alphabet(RNA)
            @test ispurine(nt) == (nt == RNA_A || nt == RNA_G || nt == RNA_R)
        end
    end

    @testset "ispyrimidine" begin
        for nt in alphabet(DNA)
            @test ispyrimidine(nt) == (nt == DNA_T || nt == DNA_C || nt == DNA_Y)
        end
        for nt in alphabet(RNA)
            @test ispyrimidine(nt) == (nt == RNA_U || nt == RNA_C || nt == RNA_Y)
        end
    end

    @testset "iscertain" begin
        for nt in alphabet(DNA)
            @test iscertain(nt) == (nt ∈ ACGT)
        end
        for nt in alphabet(RNA)
            @test iscertain(nt) == (nt ∈ ACGU)
        end
    end

    @testset "isgap" begin
        for nt in alphabet(DNA)
            @test isgap(nt) == (nt === DNA_Gap)
        end
        for nt in alphabet(RNA)
            @test isgap(nt) == (nt === RNA_Gap)
        end
    end

    @testset "isterm" begin
        for nt in alphabet(DNA)
            @test BioSymbols.isterm(nt) === false
        end
        for nt in alphabet(RNA)
            @test BioSymbols.isterm(nt) === false
        end
    end

    @testset "complement" begin
        @test complement(DNA_A) === DNA_T
        @test complement(DNA_C) === DNA_G
        @test complement(DNA_G) === DNA_C
        @test complement(DNA_T) === DNA_A
        @test complement(DNA_Gap) === DNA_Gap
        @test complement(DNA_N) === DNA_N

        @test complement(RNA_A) === RNA_U
        @test complement(RNA_C) === RNA_G
        @test complement(RNA_G) === RNA_C
        @test complement(RNA_U) === RNA_A
        @test complement(RNA_Gap) === RNA_Gap
        @test complement(RNA_N) === RNA_N
    end

    @testset "Arithmetic and Order" begin
        @testset "DNA" begin
            @test ~DNA_Gap === DNA_N
            @test ~DNA_N   === DNA_Gap
            @test DNA_A | DNA_C === DNA_M
            @test DNA_A & DNA_C === DNA_Gap
            @test DNA_Gap - DNA_A   === -1
            @test DNA_A   - DNA_Gap === +1
            @test DNA_Gap + 1 === DNA_Gap + 17 === DNA_A
            @test DNA_Gap - 1 === DNA_Gap - 17 === DNA_N
            @test DNA_Gap < DNA_A < DNA_C < DNA_G < DNA_T < DNA_N
            @test !(DNA_A > DNA_G)
            @test trailing_zeros(DNA_A) === 0
            @test trailing_zeros(DNA_C) === 1
            @test trailing_zeros(DNA_G) === 2
            @test trailing_zeros(DNA_T) === 3
            @test gap(DNA) === DNA_Gap
            @test collect(alphabet(DNA)) == sort([
                DNA_A, DNA_C, DNA_G, DNA_T,
                DNA_M, DNA_R, DNA_W, DNA_S,
                DNA_Y, DNA_K, DNA_V, DNA_H,
                DNA_D, DNA_B, DNA_N, DNA_Gap])
        end
        @testset "RNA" begin
            @test ~RNA_Gap === RNA_N
            @test ~RNA_N   === RNA_Gap
            @test RNA_A | RNA_C === RNA_M
            @test RNA_A & RNA_C === RNA_Gap
            @test RNA_Gap - RNA_A   === -1
            @test RNA_A   - RNA_Gap === +1
            @test RNA_Gap + 1 === RNA_Gap + 17 === RNA_A
            @test RNA_Gap - 1 === RNA_Gap - 17 === RNA_N
            @test RNA_Gap < RNA_A < RNA_C < RNA_G < RNA_U < RNA_N
            @test !(RNA_A > RNA_G)
            @test trailing_zeros(RNA_A) === 0
            @test trailing_zeros(RNA_C) === 1
            @test trailing_zeros(RNA_G) === 2
            @test trailing_zeros(RNA_U) === 3
            @test gap(RNA) === RNA_Gap
            @test collect(alphabet(RNA)) == sort([
                RNA_A, RNA_C, RNA_G, RNA_U,
                RNA_M, RNA_R, RNA_W, RNA_S,
                RNA_Y, RNA_K, RNA_V, RNA_H,
                RNA_D, RNA_B, RNA_N, RNA_Gap])
        end
    end

    @testset "Show DNA" begin
        dnas = [DNA_A, DNA_C, DNA_G, DNA_T, DNA_N, DNA_Gap]
        @testset "print" begin
            buf = IOBuffer()
            for nt in dnas
                print(buf, nt)
            end
            @test String(take!(buf)) == "ACGTN-"
            @test_throws ArgumentError print(reinterpret(DNA, 0xf0))
        end

        @testset "show" begin
            buf = IOBuffer()
            for nt in dnas
                @test BioSymbols.prefix(nt) === BioSymbols.type_text(nt) === "DNA"
            end
            for nt in dnas
                show(buf, nt)
                write(buf, ' ')
            end
            @test String(take!(buf)) == "DNA_A DNA_C DNA_G DNA_T DNA_N DNA_Gap "
            @test sprint(show, reinterpret(DNA, 0xf0)) == "Invalid DNA"
        end
    end

    @testset "Show RNA" begin
        rnas = [RNA_A, RNA_C, RNA_G, RNA_U, RNA_N, RNA_Gap]
        @testset "print" begin
            buf = IOBuffer()
            for nt in rnas
                print(buf, nt)
            end
            @test String(take!(buf)) == "ACGUN-"
            @test_throws ArgumentError print(reinterpret(RNA, 0xf0))
        end

        @testset "show" begin
            for nt in rnas
                @test BioSymbols.prefix(nt) === BioSymbols.type_text(nt) === "RNA"
            end
            buf = IOBuffer()
            for nt in rnas
                show(buf, nt)
                write(buf, ' ')
            end
            @test String(take!(buf)) == "RNA_A RNA_C RNA_G RNA_U RNA_N RNA_Gap "
            @test sprint(show, reinterpret(RNA, 0xf0)) == "Invalid RNA"
        end

        @testset "read and write" begin
            @test round_trip(AA_X)
            @test round_trip(AA_Y)
        end
    end

    @testset "Sets" begin
        @test length(ACGT) == 4
        @test ACGT[1] === DNA_A
        @test ACGT[2] === DNA_C
        @test ACGT[3] === DNA_G
        @test ACGT[4] === DNA_T
        @test collect(ACGT) == [DNA_A, DNA_C, DNA_G, DNA_T]

        @test length(ACGTN) == 5
        @test ACGTN[1] === DNA_A
        @test ACGTN[2] === DNA_C
        @test ACGTN[3] === DNA_G
        @test ACGTN[4] === DNA_T
        @test ACGTN[5] === DNA_N
        @test collect(ACGTN) == [DNA_A, DNA_C, DNA_G, DNA_T, DNA_N]

        @test length(ACGU) == 4
        @test ACGU[1] === RNA_A
        @test ACGU[2] === RNA_C
        @test ACGU[3] === RNA_G
        @test ACGU[4] === RNA_U
        @test collect(ACGU) == [RNA_A, RNA_C, RNA_G, RNA_U]

        @test length(ACGUN) == 5
        @test ACGUN[1] === RNA_A
        @test ACGUN[2] === RNA_C
        @test ACGUN[3] === RNA_G
        @test ACGUN[4] === RNA_U
        @test ACGUN[5] === RNA_N
        @test collect(ACGUN) == [RNA_A, RNA_C, RNA_G, RNA_U, RNA_N]
    end
end

@testset "Aminoacids" begin
    @testset "conversion" begin
        @test BioSymbols.bytemask(AA_A) === 0b11111

        for (int, aa) in [
            (0x00, AA_A), (0x01, AA_R), (0x02, AA_N), (0x03, AA_D), (0x04, AA_C),
            (0x05, AA_Q), (0x06, AA_E), (0x07, AA_G), (0x08, AA_H), (0x09, AA_I),
            (0x0a, AA_L), (0x0b, AA_K), (0x0c, AA_M), (0x0d, AA_F), (0x0e, AA_P),
            (0x0f, AA_S), (0x10, AA_T), (0x11, AA_W), (0x12, AA_Y), (0x13, AA_V),
            (0x14, AA_O), (0x15, AA_U), (0x16, AA_B), (0x17, AA_J), (0x18, AA_Z),
            (0x19, AA_X), (0x1a, AA_Term), (0x1b, AA_Gap)]
            @test convert(AminoAcid, int) === AminoAcid(int) === aa
        end

        @test convert(AminoAcid, 0) === AA_A
        @test convert(AminoAcid, 10) === AA_L

        for (c, aa) in [
                ('A', AA_A), ('R', AA_R), ('N', AA_N), ('D', AA_D), ('C', AA_C),
                ('Q', AA_Q), ('E', AA_E), ('G', AA_G), ('H', AA_H), ('I', AA_I),
                ('L', AA_L), ('K', AA_K), ('M', AA_M), ('F', AA_F), ('P', AA_P),
                ('S', AA_S), ('T', AA_T), ('W', AA_W), ('Y', AA_Y), ('V', AA_V),
                ('O', AA_O), ('U', AA_U), ('B', AA_B), ('J', AA_J), ('Z', AA_Z),
                ('X', AA_X), ('*', AA_Term), ('-', AA_Gap)]
            @test convert(AminoAcid, c) === convert(AminoAcid, lowercase(c)) == AminoAcid(c) === aa
            @test Char(aa) === c
        end
        @test_throws InexactError convert(AminoAcid, '\0')
        @test_throws InexactError convert(AminoAcid, '@')
        @test_throws InexactError convert(AminoAcid, '亜')
    end

    @testset "isvalid" begin
        for aa in alphabet(AminoAcid)
            @test isvalid(aa)
        end
        @test !isvalid(reinterpret(AminoAcid, 0x1c))
        @test !isvalid(reinterpret(AminoAcid, 0xff))
        @test  isvalid(AminoAcid, 0x1b)
        @test !isvalid(AminoAcid, 0x1c)
    end

    @testset "Arithmetic and Order" begin
        @test AA_A + 1 == 1 + AA_A == AA_R
        @test AA_R + 1 == 1 + AA_R == AA_N
        @test AA_A + 2 == 2 + AA_A == AA_N
        @test AA_A + 28 == 28 + AA_A == AA_A
        @test AA_R - 1 == AA_A
        @test AA_N - 2 == AA_A
        @test AA_A - 28 == AA_A
        @test AA_D - AA_A ==  3
        @test AA_A - AA_D == -3
        @test (AA_A < AA_R < AA_N < AA_V < AA_O < AA_U <
               AA_B < AA_J < AA_Z < AA_X < AA_Term < AA_Gap)
        @test !(AA_J < AA_B)

        @test gap(AminoAcid) === AA_Gap
        @test length(alphabet(AminoAcid)) == 28
        @test AA_A in alphabet(AminoAcid)
        @test AA_I in alphabet(AminoAcid)
        @test AA_U in alphabet(AminoAcid)
    end

    @testset "Range" begin
        @test !(AA_C in AA_Q:AA_H)
        @test   AA_Q in AA_Q:AA_H
        @test   AA_E in AA_Q:AA_H
        @test   AA_G in AA_Q:AA_H
        @test   AA_H in AA_Q:AA_H
        @test !(AA_I in AA_Q:AA_H)

        @test collect(AA_W:AA_V) == [AA_W, AA_Y, AA_V]
    end

    @testset "iscompatible" begin
        @test  iscompatible(AA_A, AA_A)
        @test !iscompatible(AA_A, AA_R)

        for x in alphabet(AminoAcid)
            @test iscompatible(x, AA_B) == (x ∈ (AA_D, AA_N, AA_B, AA_X))
            @test iscompatible(x, AA_J) == (x ∈ (AA_I, AA_L, AA_J, AA_X))
            @test iscompatible(x, AA_Z) == (x ∈ (AA_E, AA_Q, AA_Z, AA_X))
            @test iscompatible(x, AA_X) == (x ∉ (AA_Term, AA_Gap))
        end
    end

    @testset "isambiguous" begin
        for x in alphabet(AminoAcid)
            @test isambiguous(x) == (AA_B <= x <= AA_X)
        end
    end

    @testset "iscertain" begin
        for x in alphabet(AminoAcid)
            @test iscertain(x) == (!isambiguous(x) && x != AA_Gap)
        end
    end

    @testset "isgap" begin
        for x in alphabet(AminoAcid)
            @test isgap(x) == (x == AA_Gap)
        end
    end

    @testset "Show amino acid" begin
        aas = [AA_A, AA_D, AA_B, AA_X, AA_Term, AA_Gap]
        @testset "print" begin
            buf = IOBuffer()
            for aa in aas
                print(buf, aa)
            end
            @test String(take!(buf)) == "ADBX*-"
            @test_throws ArgumentError print(BioSymbols.AA_INVALID)
        end

        @testset "show" begin
            for aa in aas
                @test BioSymbols.prefix(aa) === "AA"
                @test BioSymbols.type_text(aa) === "Amino Acid"
            end
            buf = IOBuffer()
            for aa in aas
                show(buf, aa)
                write(buf, ' ')
            end
            @test String(take!(buf)) == "AA_A AA_D AA_B AA_X AA_Term AA_Gap "
            @test sprint(show, BioSymbols.AA_INVALID) == "Invalid Amino Acid"
        end

        @testset "read and write" begin
            @test round_trip(DNA_G)
            @test round_trip(RNA_U)
        end
    end

    @testset "Parsers" begin
        @testset "Valid Cases" begin
            # case-insensitive and ignores spaces
            @test parse(AminoAcid, "a") == AA_A
            @test parse(AminoAcid, "Ala") == AA_A
            @test parse(AminoAcid, "aLa ") == AA_A
            @test parse(AminoAcid, " alA ") == AA_A
            @test parse(AminoAcid, "\tAlA\n") == AA_A
            @test parse(AminoAcid, "x") == AA_X
            @test parse(AminoAcid, "X") == AA_X
            aas = [
                ("A", "ALA", AA_A),
                ("R", "ARG", AA_R),
                ("N", "ASN", AA_N),
                ("D", "ASP", AA_D),
                ("C", "CYS", AA_C),
                ("E", "GLU", AA_E),
                ("Q", "GLN", AA_Q),
                ("G", "GLY", AA_G),
                ("H", "HIS", AA_H),
                ("I", "ILE", AA_I),
                ("L", "LEU", AA_L),
                ("K", "LYS", AA_K),
                ("M", "MET", AA_M),
                ("F", "PHE", AA_F),
                ("P", "PRO", AA_P),
                ("S", "SER", AA_S),
                ("T", "THR", AA_T),
                ("W", "TRP", AA_W),
                ("Y", "TYR", AA_Y),
                ("V", "VAL", AA_V),
                ("O", "PYL", AA_O),
                ("U", "SEC", AA_U),
                ("B", "ASX", AA_B),
                ("J", "XLE", AA_J),
                ("Z", "GLX", AA_Z),
                ("X", "XAA", AA_X),
            ]
            @test length(aas) == 26
            for (one, three, aa) in aas
                @test parse(AminoAcid, one) == aa
                @test parse(AminoAcid, three) == aa
                @test parse(AminoAcid, Char(one[1])) == aa
                @test tryparse(AminoAcid, one) === aa
                @test tryparse(AminoAcid, three) === aa
                @test tryparse(AminoAcid, Char(one[1])) === aa
            end
            @test parse(AminoAcid, "*") == AA_Term
            @test parse(AminoAcid, "-") == AA_Gap
            @test tryparse(AminoAcid, "*") === AA_Term
            @test tryparse(AminoAcid, "-") === AA_Gap
        end

        @testset "Invalid Cases" begin
            @test_throws ArgumentError parse(AminoAcid, "")
            @test_throws ArgumentError parse(AminoAcid, "AL")
            @test_throws ArgumentError parse(AminoAcid, "LA")
            @test_throws ArgumentError parse(AminoAcid, "ALAA")
            @test_throws ArgumentError parse(AminoAcid, '\0')
            @test_throws ArgumentError parse(AminoAcid, '@')
            @test_throws ArgumentError parse(AminoAcid, '亜')
            @test tryparse(AminoAcid, "") == nothing
            @test tryparse(AminoAcid, "AL") == nothing
            @test tryparse(AminoAcid, "LA") == nothing
            @test tryparse(AminoAcid, "ALAA") == nothing
            @test tryparse(AminoAcid, '\0') == nothing
            @test tryparse(AminoAcid, '@') == nothing
            @test tryparse(AminoAcid, '亜') == nothing
        end
    end
end