text:
module UtilsWrapper

using JavaCall

const AbsoluteDate = @jimport org.orekit.time.AbsoluteDate
const AbsolutePVCoordinates = @jimport org.orekit.utils.AbsolutePVCoordinates
const AbstractMultipleShooting = @jimport org.orekit.utils.AbstractMultipleShooting
const AngularCoordinates = @jimport org.orekit.utils.AngularCoordinates
const AngularDerivativesFilter = @jimport org.orekit.utils.AngularDerivativesFilter
const AttitudeProvider = @jimport org.orekit.attitudes.AttitudeProvider
const CartesianDerivativesFilter = @jimport org.orekit.utils.CartesianDerivativesFilter
const Class = @jimport java.lang.Class
const Collection = @jimport java.util.Collection
const Differentiation = @jimport org.orekit.utils.Differentiation
const EOPHistory = @jimport org.orekit.frames.EOPHistory
const ElevationMask = @jimport org.orekit.utils.ElevationMask
const Enum = @jimport java.lang.Enum
const ExtendedPVCoordinatesProvider = @jimport org.orekit.utils.ExtendedPVCoordinatesProvider
const Field = @jimport org.hipparchus.Field
const FieldAbsoluteDate = @jimport org.orekit.time.FieldAbsoluteDate
const FieldAbsolutePVCoordinates = @jimport org.orekit.utils.FieldAbsolutePVCoordinates
const FieldAngularCoordinates = @jimport org.orekit.utils.FieldAngularCoordinates
const FieldPVCoordinates = @jimport org.orekit.utils.FieldPVCoordinates
const FieldPVCoordinatesProvider = @jimport org.orekit.utils.FieldPVCoordinatesProvider
const FieldRotation = @jimport org.hipparchus.geometry.euclidean.threed.FieldRotation
const FieldTimeInterpolable = @jimport org.orekit.time.FieldTimeInterpolable
const FieldTimeSpanMap = @jimport org.orekit.utils.FieldTimeSpanMap
const FieldVector3D = @jimport org.hipparchus.geometry.euclidean.threed.FieldVector3D
const Frame = @jimport org.orekit.frames.Frame
const FundamentalNutationArguments = @jimport org.orekit.data.FundamentalNutationArguments
const GenericTimeStampedCache = @jimport org.orekit.utils.GenericTimeStampedCache
const Gradient = @jimport org.hipparchus.analysis.differentiation.Gradient
const IERSConventions = @jimport org.orekit.utils.IERSConventions
const IERSConventions_NutationCorrectionConverter = @jimport org.orekit.utils.IERSConventions$NutationCorrectionConverter
const ImmutableTimeStampedCache = @jimport org.orekit.utils.ImmutableTimeStampedCache
const InputStream = @jimport java.io.InputStream
const InterpolationTableLoader = @jimport org.orekit.utils.InterpolationTableLoader
const JString = @jimport java.lang.String
const LagrangianPoints = @jimport org.orekit.utils.LagrangianPoints
const List = @jimport java.util.List
const LoveNumbers = @jimport org.orekit.utils.LoveNumbers
const Map = @jimport java.util.Map
const MultipleShooter = @jimport org.orekit.utils.MultipleShooter
const MultipleShooting = @jimport org.orekit.utils.MultipleShooting
const NavigableSet = @jimport java.util.NavigableSet
const Object = @jimport java.lang.Object
const Optional = @jimport java.util.Optional
const OrbitType = @jimport org.orekit.orbits.OrbitType
const OrekitConfiguration = @jimport org.orekit.utils.OrekitConfiguration
const PVCoordinates = @jimport org.orekit.utils.PVCoordinates
const PVCoordinatesProvider = @jimport org.orekit.utils.PVCoordinatesProvider
const ParameterDriver = @jimport org.orekit.utils.ParameterDriver
const ParameterDriversList = @jimport org.orekit.utils.ParameterDriversList
const ParameterDriversList_DelegatingDriver = @jimport org.orekit.utils.ParameterDriversList$DelegatingDriver
const ParameterFunction = @jimport org.orekit.utils.ParameterFunction
const ParameterObserver = @jimport org.orekit.utils.ParameterObserver
const PoissonSeries_CompiledSeries = @jimport org.orekit.data.PoissonSeries$CompiledSeries
const PositionAngle = @jimport org.orekit.orbits.PositionAngle
const RealFieldElement = @jimport org.hipparchus.RealFieldElement
const Rotation = @jimport org.hipparchus.geometry.euclidean.threed.Rotation
const SecularAndHarmonic = @jimport org.orekit.utils.SecularAndHarmonic
const SortedSet = @jimport java.util.SortedSet
const SpacecraftState = @jimport org.orekit.propagation.SpacecraftState
const StateFunction = @jimport org.orekit.utils.StateFunction
const StateJacobian = @jimport org.orekit.utils.StateJacobian
const Stream = @jimport java.util.stream.Stream
const TimeInterpolable = @jimport org.orekit.time.TimeInterpolable
const TimeScalarFunction = @jimport org.orekit.time.TimeScalarFunction
const TimeScale = @jimport org.orekit.time.TimeScale
const TimeScales = @jimport org.orekit.time.TimeScales
const TimeSpanMap = @jimport org.orekit.utils.TimeSpanMap
const TimeSpanMap_Span = @jimport org.orekit.utils.TimeSpanMap$Span
const TimeStamped = @jimport org.orekit.time.TimeStamped
const TimeStampedAngularCoordinates = @jimport org.orekit.utils.TimeStampedAngularCoordinates
const TimeStampedCache = @jimport org.orekit.utils.TimeStampedCache
const TimeStampedFieldAngularCoordinates = @jimport org.orekit.utils.TimeStampedFieldAngularCoordinates
const TimeStampedFieldPVCoordinates = @jimport org.orekit.utils.TimeStampedFieldPVCoordinates
const TimeStampedGenerator = @jimport org.orekit.utils.TimeStampedGenerator
const TimeStampedPVCoordinates = @jimport org.orekit.utils.TimeStampedPVCoordinates
const TimeVectorFunction = @jimport org.orekit.time.TimeVectorFunction
const Vector3D = @jimport org.hipparchus.geometry.euclidean.threed.Vector3D

export AbsolutePVCoordinates
export AbstractMultipleShooting
export AngularCoordinates
export AngularDerivativesFilter
export CartesianDerivativesFilter
export Constants
export Differentiation
export ElevationMask
export ExtendedPVCoordinatesProvider
export FieldAbsolutePVCoordinates
export FieldAngularCoordinates
export FieldPVCoordinates
export FieldPVCoordinatesProvider
export FieldTimeSpanMap
export GenericTimeStampedCache
export IERSConventions
export ImmutableTimeStampedCache
export InterpolationTableLoader
export LagrangianPoints
export LoveNumbers
export MultipleShooter
export MultipleShooting
export OrekitConfiguration
export PVCoordinates
export PVCoordinatesProvider
export ParameterDriver
export ParameterDriversList
export ParameterFunction
export ParameterObserver
export SecularAndHarmonic
export StateFunction
export StateJacobian
export TimeSpanMap
export TimeStampedAngularCoordinates
export TimeStampedCache
export TimeStampedFieldAngularCoordinates
export TimeStampedFieldPVCoordinates
export TimeStampedGenerator
export TimeStampedPVCoordinates
export add
export add_constraint
export add_observer
export add_offset
export add_point
export add_valid_after
export add_valid_before
export apply_to
export approximate_as_polynomial_only
export compare_to
export compute
export create_from_modified_rodrigues
export cross_product
export describe_constable
export differentiate
export empty_cache
export equals
export estimate_rate
export estimate_velocity
export evaluate_tc
export extract_range
export filter
export find_by_name
export fit
export generate
export get
export get_abscissa_grid
export get_acceleration
export get_all
export get_angular_velocity
export get_cache_slots_number
export get_class
export get_date
export get_declaring_class
export get_drivers
export get_earliest
export get_earth_orientation_angle_function
export get_elevation
export get_entries
export get_eop_tidal_correction
export get_filter
export get_fitted_parameters
export get_frame
export get_gast_function
export get_generate_calls
export get_generator
export get_get_neighbors_calls
export get_gmst_function
export get_gmst_rate_function
export get_harmonic_amplitude
export get_identity
export get_imaginary
export get_latest
export get_love_numbers
export get_max_order
export get_max_slots
export get_max_span
export get_max_value
export get_mean_obliquity_function
export get_min_value
export get_modified_rodrigues
export get_momentum
export get_name
export get_nb_params
export get_neighbors
export get_neighbors_size
export get_new_slot_quantum_gap
export get_nominal_tidal_displacement
export get_normalized_value
export get_nutation_arguments
export get_nutation_correction_converter
export get_nutation_function
export get_nutation_reference_epoch
export get_observers
export get_ocean_pole_tide
export get_ordinate_grid
export get_permanent_tide
export get_plus
export get_position
export get_precession_function
export get_pv_coordinates
export get_real
export get_reference_date
export get_reference_value
export get_rotation
export get_rotation_acceleration
export get_rotation_rate
export get_scale
export get_size
export get_slots
export get_slots_evictions
export get_solid_pole_tide
export get_span
export get_tidal_displacement_frequency_correction_diurnal
export get_tidal_displacement_frequency_correction_zonal
export get_tide_frequency_dependence_function
export get_transitions
export get_value
export get_values_samples
export get_velocity
export get_xy_sp_xy2_function
export get_zero
export hash_code
export interpolate
export is_selected
export load_data
export max_value_changed
export mean_derivative
export mean_second_derivative
export mean_value
export min_value_changed
export name
export name_changed
export negate
export normalize
export notify
export notify_all
export ordinal
export osculating_derivative
export osculating_second_derivative
export osculating_value
export reference_date_changed
export reference_value_changed
export remove_observer
export replace_observer
export reset_fitting
export revert
export scale_changed
export selection_changed
export set_cache_slots_number
export set_closed_orbit_constraint
export set_epoch_freedom
export set_max_value
export set_min_value
export set_name
export set_normalized_value
export set_patch_point_component_freedom
export set_reference_date
export set_reference_value
export set_scale
export set_selected
export set_value
export shifted_by
export sort
export still_accepts_data
export subtract_offset
export to_absolute_pv_coordinates
export to_angular_coordinates
export to_derivative_structure_pv
export to_derivative_structure_rotation
export to_derivative_structure_vector
export to_field_pv_coordinates_provider
export to_pv_coordinates
export to_string
export to_taylor_provider
export to_time_stamped_pv_coordinates
export to_univariate_derivative1_rotation
export to_univariate_derivative1_vector
export to_univariate_derivative1pv
export to_univariate_derivative2_vector
export to_univariate_derivative2pv
export value
export value_changed
export value_of
export values
export wait

include("absolute_pv_coordinates.jl")
include("abstract_multiple_shooting.jl")
include("angular_coordinates.jl")
include("angular_derivatives_filter.jl")
include("cartesian_derivatives_filter.jl")
include("constants.jl")
include("differentiation.jl")
include("elevation_mask.jl")
include("extended_pv_coordinates_provider.jl")
include("field_absolute_pv_coordinates.jl")
include("field_angular_coordinates.jl")
include("field_pv_coordinates.jl")
include("field_pv_coordinates_provider.jl")
include("field_time_span_map.jl")
include("generic_time_stamped_cache.jl")
include("iers_conventions.jl")
include("immutable_time_stamped_cache.jl")
include("interpolation_table_loader.jl")
include("lagrangian_points.jl")
include("love_numbers.jl")
include("multiple_shooter.jl")
include("multiple_shooting.jl")
include("orekit_configuration.jl")
include("parameter_driver.jl")
include("parameter_drivers_list.jl")
include("parameter_function.jl")
include("parameter_observer.jl")
include("pv_coordinates.jl")
include("pv_coordinates_provider.jl")
include("secular_and_harmonic.jl")
include("state_function.jl")
include("state_jacobian.jl")
include("time_span_map.jl")
include("time_stamped_angular_coordinates.jl")
include("time_stamped_cache.jl")
include("time_stamped_field_angular_coordinates.jl")
include("time_stamped_field_pv_coordinates.jl")
include("time_stamped_generator.jl")
include("time_stamped_pv_coordinates.jl")

end


text:
# This file is a part of BAT.jl, licensed under the MIT License (MIT).

mutable struct DirectSamplingState{
    Q<:AbstractProposalDist,
    S<:DensitySample
} <: AbstractMCMCState
    pdist::Q
    current_sample::S
    proposed_sample::S
    proposal_accepted::Bool
    current_nreject::Int64
    nsamples::Int64
    nsteps::Int64
end

function DirectSamplingState(
    pdist::AbstractProposalDist,
    current_sample::DensitySample
)
    proposed_sample = DensitySample(
        similar(current_sample.params),
        convert(typeof(current_sample.log_value), NaN),
        zero(current_sample.weight)
    )

    DirectSamplingState(
        pdist,
        current_sample,
        proposed_sample,
        false,
        zero(Int64),
        zero(Int64),
        one(Int64)
    )
end

nparams(state::DirectSamplingState) = nparams(state.pdist)

nsteps(state::DirectSamplingState) = state.nsteps

nsamples(state::DirectSamplingState) = state.nsamples

eff_acceptance_ratio(state::DirectSamplingState) = nsamples(state) / nsteps(state)

function next_cycle!(state::DirectSamplingState)
    state.current_sample.weight = one(state.current_sample.weight)
    state.nsamples = zero(Int64)
    state.nsteps = zero(Int64)
    state
end

density_sample_type(state::DirectSamplingState{Q,S}) where {Q,S} = S

_accrej_current_sample(state::DirectSamplingState) =
    ifelse(state.proposal_accepted, state.current_sample, state.proposed_sample)

function nsamples_available(chain::MCMCIterator{<:MCMCAlgorithm{DirectSamplingState}}, nonzero_weights::Bool = false)
    if nonzero_weights
        (_accrej_current_sample(chain.state).weight > 0) ? 1 : 0
    else
        1
    end
end

function get_samples!(appendable, chain::MCMCIterator{<:MCMCAlgorithm{DirectSamplingState}}, nonzero_weights::Bool)::typeof(appendable)
    sample = _accrej_current_sample(chain.state)
    if (!nonzero_weights || sample.weight > 0)
        push!(appendable, sample)
    end
    appendable
end

function get_sample_ids!(appendable, chain::MCMCIterator{<:MCMCAlgorithm{DirectSamplingState}}, nonzero_weights::Bool)::typeof(appendable)
    state = chain.state
    sample = _accrej_current_sample(state)
    if (!nonzero_weights || sample.weight > 0)
        sampletype = state.proposal_accepted ? 2 : 1
        sampleid = MCMCSampleID(chain.id, chain.cycle, state.nsteps, sampletype)
        push!(appendable, sampleid)
    end
    appendable
end

function MCMCIterator(
    algorithm::MCMCAlgorithm{DirectSamplingState},
    likelihood::AbstractDensity,
    prior::AbstractDensity,
    id::Int64,
    rng::AbstractRNG,
    initial_params::AbstractVector{P} = Vector{P}(),
    exec_context::ExecContext = ExecContext(),
) where {P<:Real}
    target = likelihood * prior

    cycle = zero(Int)
    reset_rng_counters!(rng, id, cycle, 0)

    params_vec = Vector{P}(nparams(target))
    if isempty(initial_params)
        rand_initial_params!(rng, algorithm, prior, params_vec)
    else
        params_vec .= initial_params
    end

    !(params_vec in param_bounds(target)) && throw(ArgumentError("Parameter(s) out of bounds"))

    m = length(params_vec)

    log_value = density_logval(target, params_vec, exec_context)
    L = typeof(log_value)
    W = sample_weight_type(typeof(algorithm))

    current_sample = DensitySample(
        params_vec,
        log_value,
        one(W)
    )

    proposed_sample = DensitySample(
        similar(current_sample.params),
        convert(typeof(current_sample.log_value), NaN),
        zero(W)
    )

    state = DirectSamplingState(
        algorithm,
        target,
        current_sample
    )

    chain = MCMCIterator(
        algorithm,
        target,
        state,
        rng,
        id,
        cycle,
        false,
        false
    )

    chain
end

exec_capabilities(mcmc_step!, callback::AbstractMCMCCallback, chain::MCMCIterator{<:MCMCAlgorithm{DirectSamplingState}}) =
    exec_capabilities(density_logval, chain.target, chain.state.proposed_sample.params)

function mcmc_step!(
    callback::AbstractMCMCCallback,
    chain::MCMCIterator{<:MCMCAlgorithm{DirectSamplingState}},
    exec_context::ExecContext,
    ll::LogLevel
)
    state = chain.state
    algorithm = chain.algorithm

    if !mcmc_compatible(algorithm, chain.state.pdist, param_bounds(chain.target))
        error("Implementation of algorithm $algorithm does not support current parameter bounds with current proposal distribution")
    end

    current_sample = state.current_sample
    proposed_sample = state.proposed_sample

    state.nsteps += 1
    reset_rng_counters!(chain)

    mcmc_propose_accept_reject!(callback, chain, exec_context)

    if state.proposal_accepted
        copy!(current_sample, proposed_sample)
        state.current_nreject = 0
        state.proposal_accepted = false
    end

    chain
end

struct DirectSampling <: MCMCAlgorithm{DirectSamplingState} end
export DirectSampling

mcmc_compatible(::DirectSampling, ::AbstractProposalDist, ::AbstractParamBounds) = true

# ToDo: Specialized version of rand_initial_params for DirectSampling:
#
#     rand_initial_params!(rng::AbstractRNG, algorithm::DirectSampling, target::DensityFunction, x::StridedVecOrMat{<:Real}) = ...

AbstractMCMCTunerConfig(algorithm::DirectSampling) = NoOpTunerConfig()

sample_weight_type(::Type{DirectSampling}) = Int

function DirectSamplingState(
    algorithm::DirectSampling,
    target::BAT.DensityProduct{2,<:Tuple{MvDistDensity, ConstDensity}},
    current_sample::DensitySample{P,T,W}
) where {P,T,W}
    DirectSamplingState(
        GenericProposalDist(parent(target)[1].d),
        current_sample
    )
end

function mcmc_propose_accept_reject!(
    callback::AbstractMCMCCallback,
    chain::MCMCIterator{<:DirectSampling},
    exec_context::ExecContext
)
    state = chain.state
    target = chain.target

    proposed_sample = state.proposed_sample
    proposed_params = proposed_sample.params

    # Propose new parameters:
    rand!(chain.rng, state.pdist.s, proposed_params)

    # Accept iff in bounds:
    if proposed_params in param_bounds(target)
        proposed_sample.log_value = density_logval(target, proposed_params, exec_context)

        state.proposed_sample.weight = 1
        @assert state.current_sample.weight == 1
        state.proposal_accepted = true
        state.nsamples += 1
    else
        proposed_sample.log_value = -Inf

        state.current_nreject += 1
    end
    callback(1, chain)

    chain
end

ext: jl


text:
mutable struct SparseVector{T}
    data::Vector{T}
    index::Vector{<:Integer}
    function SparseVector{T}(data::Vector{T}, index::Vector{<:Integer}) where {T}
        # last index must specify the length of the full array
        Ld = length(data)
        Li = length(index)
        if (Ld + 1) != Li
            error(
                "Data array must have one element less then index array,
                 last index must contain the number of elements in the full array")
        end
        if Li[end] < Ld
            error("The last index element must contain the length of the full array")
        end
        vec = new(data, index);
    end
end

function SparseVector{T}(data::Vector{T}, index) where {T}
    vec = SparseVector{T}(data, index);
end

function SparseVector(data::Vector{T}, index) where {T}
    vec = SparseVector{T}(data, index);
end

function create_sparse(data::Vector, tolerance = 1e-10)
    # for now: create a temporary array with the size of data
    L = length(data)
    tmp_data = similar(data)
    tmp_index = Vector{Int64}(undef, L+1)

    jj = 1
    for ii = 1:L
        if abs( data[ii] ) >= tolerance
            tmp_data[jj] = data[ii]
            tmp_index[jj] = ii
            jj += 1
        end
    end
    tmp_index[jj] = L
    vec = SparseVector(tmp_data[1:jj-1], tmp_index[1:jj])
    return vec
end

function create_full(spvec::SparseVector{T}) where {T}
    L = spvec.index[end]
    Ls = sparse_length(spvec)
    vec = zeros(T, L)
    for ii = 1:Ls
        vec[ spvec.index[ii] ] = spvec.data[ii]
    end
    return vec
end

function Base.length(spvec::SparseVector{T}) where {T}
    return length(spvec.data)
end

function Base.size(spvec::SparseVector{T}) where {T}
    return (length(spvec),)
end

function n_nonzero(spvec::SparseVector{T}) where {T}
    return length(spvec)
end

function sparse_length(spvec::SparseVector{T}) where {T}
    return length(spvec)
end

function full_length(spvec::SparseVector{T}) where {T}
    return spvec.index[end]
end

function Base.show(io::IO, spvec::SparseVector{T}) where {T}
    n = sparse_length(spvec)
    L = full_length(spvec)
    println("$(n)-sparse element (full length: $(L)) SparseVector{$(T)}:")
    println("\tindex\tdata")
    for kk = 1:n
        ii = spvec.index[kk]
        dd = spvec.data[kk]
        println("\t$(ii)\t$(dd)")
    end
end

function Base.getindex(spvec::SparseVector{T}, idx::Int) where {T}
    # error handling
    1 <= idx <= spvec.index[end] || throw(BoundsError(spvec, idx))

    # use linear search for finding the array index
    data = zero(T)

    for ii = 1:length(spvec)
        if spvec.index[ii] == idx
            data = spvec.data[ii]
        end
    end

    return data
end

# =========================================================================== #
# Math functions
# =========================================================================== #

# sparse + sparse
# sparse .* sparse

function Base.:+(x::SparseVector{T}, y::SparseVector{T}) where {T}
    return plus(x, y)
end

function Base.:-(x::SparseVector{T}, y::SparseVector{T}) where {T}
    return minus(x, y)
end

function Base.:*(x::SparseVector{T}, s::S) where {T, S}
    return scalar_multiply(x,  convert(promote_type(T, S), s) )
end
function Base.:*(s::S, x::SparseVector{T}) where {T, S}
    return x * s
end

function plus(x::SparseVector{T}, y::SparseVector{T}) where {T}
    # z = x + y

    Lfullx = full_length(x)
    Lfully = full_length(y)
    if Lfullx != Lfully
        error("Full size mismatch")
    end

    # already contains the last index length of the full array
    new_index = [copy(x.index); copy(y.index)]
    new_index = sort!(new_index)
    new_index = unique!( new_index )

    new_data = zeros(eltype(x.data), length(new_index)-1)

    idx_x = 1;
    idx_y = 1;

    for ii = 1:(length(new_index)-1)
        if new_index[ii] == x.index[idx_x]
            new_data[ii] += x.data[idx_x]
            idx_x += 1
        end
        if new_index[ii] == y.index[idx_y]
            new_data[ii] += y.data[idx_y]
            idx_y += 1
        end
    end

    return SparseVector(new_data, new_index)
end

function minus(x::SparseVector{T}, y::SparseVector{T}) where {T}
    # z = x - y

    Lfullx = full_length(x)
    Lfully = full_length(y)
    if Lfullx != Lfully
        error("Full size mismatch")
    end

    # already contains the last index length of the full array
    new_index = [copy(x.index); copy(y.index)]
    new_index = sort!(new_index)
    new_index = unique!( new_index )

    new_data = zeros(eltype(x.data), length(new_index)-1)

    idx_x = 1;
    idx_y = 1;

    for ii = 1:(length(new_index)-1)
        if new_index[ii] == x.index[idx_x]
            new_data[ii] += x.data[idx_x]
            idx_x += 1
        end
        if new_index[ii] == y.index[idx_y]
            new_data[ii] -= y.data[idx_y]
            idx_y += 1
        end
    end

    return SparseVector(new_data, new_index)
end

function scalar_multiply(x::SparseVector{T}, s::T) where {T}
    new_data = similar(x.data)
    for ii = 1:length(x)
        new_data[ii] = x.data[ii] * s
    end
    return SparseVector(new_data, copy(x.index))
end

max_stars_repo_name: HomoModelicus/julia

max_issues_repo_name: HomoModelicus/julia

max_forks_repo_name: HomoModelicus/julia


text:
function init_deploy_repo(deploy_repo, dest_dir)
    gh_auth = github_auth(;allow_anonymous=false)
    gh_username = gh_get_json(DEFAULT_API, "/user"; auth=gh_auth)["login"]
    try
        GitHub.repo(deploy_repo; auth=gh_auth)
    catch e
        error("Resources repo `$(deploy_repo)` don't exists.")
    end

    #Always do new clone
    if isdir(dest_dir)
        rm(dest_dir, force = true, recursive = true)
    end
    @info("Cloning resources repo from https://github.com/$(deploy_repo) into $(dest_dir)")
    with_gitcreds(gh_username, gh_auth.token) do creds
        LibGit2.clone("https://github.com/$(deploy_repo)", dest_dir; credentials=creds)
    end
end

function old_build_info(dest_dir)
    default_info = (dash_version = v"0.0.0", build = 0)
    meta_path = joinpath(resources_dir(dest_dir), "dash.yaml")
    !isfile(meta_path) && return default_info
    try
        meta = YAML.load_file(meta_path)
        v = VersionNumber(meta["version"])
        build_n = meta["build"]
        (dash_version = v, build = build_n)
    catch e
        @error "error while loading dash.yaml" e
        return default_info
    end
end

function make_new_info(dash_version, old_info)
    if old_info.dash_version > dash_version
        error("You try to generate resources for dash $(dash_version), but $(deploy_repo) alredy contains version $(old_info.dash_version)")
    end
    build_n = old_info.dash_version == dash_version ? old_info.build + 1 : 0
    return (dash_version = dash_version, build = build_n)
end
function cleanup_deploy(deploy_dir)
end
resources_dir(deploy_dir) = joinpath(deploy_dir, "resources")
function fill_deploy_resources(sources, deploy_dir, info)
    resources_path = resources_dir(deploy_dir)
    #cleanup resources
    rm(resources_path, force = true, recursive = true)

    mkdir(resources_path)
    cd(resources_path) do
        @info "creating dash meta..."
        dash_meta = OrderedDict(
            :version => info.dash_version,
            :build => info.build,
            :embedded_components => Symbol.(collect(keys(sources["components"])))
        )

        dash_deps = OrderedDict{Symbol, Any}()
        dash_deps_files = Vector{String}()

        for (name, props) in sources["components"]
            fill_components_deps!(dash_deps, dash_deps_files, props["module"])
        end
        dash_meta[:deps] = collect(values(dash_deps))

        YAML.write_file("dash.yaml", dash_meta)

        mkdir("dash_deps")
        copy_files(dash_module_dir(), dash_deps_files, "dash_deps")

        @info "creating dash-renderer meta..."
        module_src, meta, files = renderer_resources(
                sources["dash_renderer"]["module"]
            )
        resources_path = realpath(
            joinpath(
                module_src,
                get(sources["dash_renderer"], "resources_path", ".")
            )
        )
        YAML.write_file("dash_renderer.yaml", meta)

        @info "copying dash-renderer resource files..."
        mkdir("dash_renderer_deps")
        copy_files(resources_path, files, "dash_renderer_deps/")
        @info "dash-renderer done"

        @info "processing components modules..."
        for (name, props) in sources["components"]
            @info "processing $name meta..."
            meta = components_module_resources(
                    props["module"];
                    name = name,
                    prefix = props["prefix"],
                    metadata_file = props["metadata_file"],
                )
            YAML.write_file("$(name).yaml", meta)
        end
    end
end

deploy_version(info) = VersionNumber(
    info.dash_version.major,
    info.dash_version.minor,
    info.dash_version.patch,
    info.dash_version.prerelease,
    (info.build,)
)

deploy_tagname(info) = string("v", deploy_version(info))

tarball_name(info) = string(
    "DashCoreResources.v", info.dash_version, ".tar.gz"
)

function push_repo(repo_name, deploy_dir, tag)
    println("https://github.com/$(repo_name).git")
    gh_auth = github_auth(;allow_anonymous=false)
    gh_username = gh_get_json(DEFAULT_API, "/user"; auth=gh_auth)["login"]
    repo = LibGit2.GitRepo(deploy_dir)
    LibGit2.add!(repo, ".")
    commit = LibGit2.commit(repo, "dash core resources build $(tag)")
    with_gitcreds(gh_username, gh_auth.token) do creds
        refspecs = ["refs/heads/master"]
        # Fetch the remote repository, to have the relevant refspecs up to date.
        LibGit2.fetch(
            repo;
            refspecs=refspecs,
            credentials=creds,
        )
        LibGit2.branch!(repo, "master", string(LibGit2.GitHash(commit)); track="master")
        LibGit2.push(
            repo;
            refspecs=refspecs,
            remoteurl="https://github.com/$(repo_name).git",
            credentials=creds,
        )
    end
end
function upload_to_releases(repo_name,  tag, tarball_path; attempts = 3)
    gh_auth = github_auth(;allow_anonymous=false)
    for attempt in 1:attempts
        try
            ghr() do ghr_path
                run(`$ghr_path -u $(dirname(repo_name)) -r $(basename(repo_name)) -t $(gh_auth.token) $(tag) $(tarball_path)`)
            end
            return
        catch
            @info("`ghr` upload step failed, beginning attempt #$(attempt)...")
        end
    end
    error("Unable to upload $(tarball_path) to GitHub repo $(repo_name) on tag $(tag)")
end


text:
include("mountain_car_rtaa_agent.jl")
include("mountain_car_cmax_agent.jl")
include("mountain_car_finite_model_class_agent.jl")
include("mountain_car_model_search_agent.jl")
include("mountain_car_agnostic_sysid_agent.jl")
include("mountain_car_online_model_search_agent.jl")


text:
"""
The ticker is a high level overview of the state of the market.
It shows you the current best bid and ask, as well as the last
trade price. It also includes information such as daily volume
and how much the price has moved over the last day.
"""
function getticker(symbol::String)
    r = get("$URL/pubticker/$symbol")
    s = String(r.body)
    return read(s)
end

"""
Various statistics about the requested pair.
"""
function getstats(symbol::String)
    r = get("$URL/stats/$symbol")
    s = String(r.body)
    return read(s)
end

"""
Full margin funding book.
"""
function getfundingbook(currency::String,
                        limit_bids::Int64 = 50,
                        limit_asks::Int64 = 50)
    r = get("$URL/lendbook/$currency?limit_bids=$limit_bids&limit_asks=$limit_asks")
    s = String(r.body)
    return read(s)
end

"""
Full order book.
"""
function getorderbook(symbol::String,
                      limit_bids::Int64 = 50,
                      limit_asks::Int64 = 50,
                      group::Bool = true)
    r = get("$URL/book/$symbol?limit_bids=$limit_bids&limit_asks=$limit_asks")
    s = String(r.body)
    return read(s)
end

"""
List of the most recent trades for the given symbol.
"""
function gettrades(symbol::String,
                   limit_trades::Int64 = 50)
    r = get("$URL/trades/$symbol?limit_trades=$limit_trades")
    s = String(r.body)
    return read(s)
end

function gettrades(symbol::String,
                   timestamp::String,
                   limit_trades::Int64 = 50)
    r = get("$URL/trades/$symbol?limit_trades=$limit_trades&timestamp=$timestamp")
    s = String(r.body)
    return read(s)
end

function gettrades(symbol::String,
                   timestamp::DateTime,
                   limit_trades::Int64 = 50)
    str_timestamp = string(value(timestamp))
    r = get("$URL/trades/$symbol?limit_trades=$limit_trades&timestamp=$str_timestamp")
    s = String(r.body)
    return read(s)
end

"""
List of the most recent funding data for the given currency: total
amount provided and Flash Return Rate (in % by 365 days) over time.
"""
function getlends(currency::String,
                 limit_lends::Int64 = 50)
    r = get("$URL/lends/$currency?limit_lends=$limit_lends")
    s = String(r.body)
    return read(s)
end

"""
List of symbol names.
"""
function symbols()
    r = get("$URL/symbols")
    s = String(r.body)
    return read(s)
end

"""
List of valid symbol IDs and the pair details.
"""
function symbol_details()
    r = get("$URL/symbols_details")
    s = String(r.body)
    return read(s)
end


text:
using LinearAlgebra

A = [1 1 -1; -2 0 1; 0 2 1]
B = inv(A)
E = B*A

println("A^{-1}=", B)
println("A*A^{-1}=", E)


text:
"""
GradientGrassmann is an optimisation methdod that keeps the MPS in left-canonical form, and
treats the tensors as points on Grassmann manifolds. It then applies one of the standard
gradient optimisation methods, e.g. conjugate gradient, to the MPS, making use of the
Riemannian manifold structure. A preconditioner is used, so that effectively the metric used
on the manifold is that given by the Hilbert space inner product.

The arguments to the constructor are
method = OptimKit.ConjugateGradient
    The gradient optimisation method to be used. Should either be an instance or a subtype
    of `OptimKit.OptimizationAlgorithm`. If it's an instance, this `method` is simply used
    to do the optimisation. If it's a subtype, then an instance is constructed as
    `method(; maxiter=maxiter, verbosity=verbosity, gradtol=tol)`

finalize! = OptimKit._finalize!
    A function that gets called once each iteration. See OptimKit for details.

tol = Defaults.tol
maxiter = Defaults.maxiter
verbosity = 2
    Arguments passed to the `method` constructor. If `method` is an instance of
    `OptimKit.OptimizationAlgorithm`, these argument are ignored.

In other words, by default conjugate gradient is used. One can easily set `tol`, `maxiter`
and `verbosity` for it, or switch to LBFGS or gradient descent by setting `method`. If more
control is wanted over things like specifics of the linesearch, CG flavor or the `m`
parameter of LBFGS, then the user should create the `OptimKit.OptimizationAlgorithm`
instance manually and pass it as `method`.
"""
struct GradientGrassmann <: Algorithm
    method::OptimKit.OptimizationAlgorithm
    finalize!::Function

    function GradientGrassmann(; method = ConjugateGradient,
                               finalize! = OptimKit._finalize!,
                               tol = Defaults.tol,
                               maxiter = Defaults.maxiter,
                               verbosity = 2)
        if isa(method, OptimKit.OptimizationAlgorithm)
            # We were given an optimisation method, just use it.
            m = method
        elseif method <: OptimKit.OptimizationAlgorithm
            # We were given an optimisation method type, construct an instance of it.
            m = method(; maxiter=maxiter, verbosity=verbosity, gradtol=tol)
        else
            msg = "method should be either an instance or a subtype of OptimKit.OptimizationAlgorithm."
            throw(ArgumentError(msg))
        end
        return new(m, finalize!)
    end
end

function find_groundstate(state::InfiniteMPS, H::Hamiltonian, alg::GradientGrassmann,
                          pars=params(state, H))
    method = alg.method
    method === nothing && (method = alg.methodtype(; maxiter=alg.maxiter,
                                                       verbosity=alg.verbosity,
                                                       gradtol=alg.tol))
    res = optimize(GrassmannInfiniteMPS.fg, (state, pars), method;
                   transport! = GrassmannInfiniteMPS.transport!,
                   retract = GrassmannInfiniteMPS.retract,
                   inner = GrassmannInfiniteMPS.inner,
                   scale! = GrassmannInfiniteMPS.scale!,
                   add! = GrassmannInfiniteMPS.add!,
                   finalize! = alg.finalize!,
                   precondition = GrassmannInfiniteMPS.precondition,
                   isometrictransport = true)
    (x, fx, gx, numfg, normgradhistory) = res
    (state, pars) = x
    return state, pars, normgradhistory[end]
end

# We separate some of the internals needed for implementing GradientGrassmann into a
# submodule, to keep the MPSKit module namespace cleaner.
"""
A module for functions related to treating an InfiniteMPS in left-canonical form as a bunch
of points on Grassmann manifolds, and performing things like retractions and transports
on these Grassmann manifolds.

The module exports nothing, and all references to it should be qualified, e.g.
`GrassmannInfiniteMPS.fg`.
"""
module GrassmannInfiniteMPS

using ..MPSKit
using TensorKit
import TensorKitManifolds.Grassmann

"""
Compute the expectation value, and its gradient with respect to the tensors in the unit
cell as tangent vectors on Grassmann manifolds.
"""
function fg(x)
    (state, pars) = x
    # The partial derivative with respect to AL, al_d, is the partial derivative with
    # respect to AC times CR'.
    ac_d = [ac_prime(state.AC[v], v, state, pars) for v in 1:length(state)]
    al_d = [d*c' for (d, c) in zip(ac_d, state.CR)]
    g = [Grassmann.project(d, a) for (d, a) in zip(al_d, state.AL)]
    f = real(sum(expectation_value(state, pars.opp, pars)))
    return f, g
end

"""
Retract a left-canonical infinite MPS along Grassmann tangent `g` by distance `alpha`.
"""
function retract(x, g, alpha)
    (state, pars) = x
    yal = similar(state.AL)  # The end-point
    h = similar(g)  # The tangent at the end-point
    for i in 1:length(g)
        (yal[i], h[i]) = Grassmann.retract(state.AL[i], g[i], alpha)
    end
    y = (InfiniteMPS(yal, leftgauged=true), pars)
    return y, h
end

"""
Transport a tangent vector `h` along the retraction from `x` in direction `g` by distance
`alpha`. `xp` is the end-point of the retraction.
"""
function transport!(h, x, g, alpha, xp)
    (state, pars) = x
    for i in 1:length(state)
        h[i] = Grassmann.transport!(h[i], state.AL[i], g[i], alpha, xp[1].AL[i])
    end
    return h
end

"""
Euclidean inner product between two Grassmann tangents of an infinite MPS.
"""
function inner(x, g1, g2)
    (state, pars) = x
    tot = sum(Grassmann.inner(a, d1, d2) for (a, d1, d2) in zip(state.AL, g1, g2))
    return 2*real(tot)
end

"""
Scale a tangent vector by scalar `alpha`.
"""
scale!(g, alpha) = g .* alpha

"""
Add two tangents vectors, scaling the latter by `alpha`.
"""
add!(g1, g2, alpha) = g1 + g2 .* alpha

"""
Take the L2 Tikhonov regularised inverse of a matrix `m`.

The regularisation parameter is the larger of `delta` (the optional argument that defaults
to zero) and square root of machine epsilon. The inverse is done using an SVD.
"""
function reginv(m, delta=zero(eltype(m)))
    delta = max(delta, sqrt(eps(real(float(one(eltype(m)))))))
    U, S, Vdg = tsvd(m)
    Sinv = inv(real(sqrt(S^2 + delta^2*one(S))))
    minv = Vdg' * Sinv * U'
    return minv
end

"""
Precondition a given Grassmann tangent `g` at state `x` by the Hilbert space inner product.

This requires inverting the right MPS transfer matrix. This is done using `reginv`, with a
regularisation parameter that is the norm of the tangent `g`.
"""
function precondition(x, g)
    (state, pars) = x
    delta = min(real(one(eltype(state))), sqrt(inner(x, g, g)))
    crinvs = [reginv(cr, delta) for cr in state.CR]
    g_prec = [Grassmann.project(d[]*(crinv'*crinv), a)
              for (d, crinv, a) in zip(g, crinvs, state.AL)]
    return g_prec
end

end  # module GrassmannInfiniteMPS


text:
#=
Copyright (c) 2018-2022 Chris Coey, Lea Kapelevich, and contributors

This Julia package Hypatia.jl is released under the MIT license; see LICENSE
file in the root directory or at https://github.com/chriscoey/Hypatia.jl
=#

nearestpolymat_n_d_ms = [
    [
    (1, 1, 2), # compile run
    (1, 20, 2),
    (1, 20, 4),
    (1, 20, 8),
    (1, 20, 16),
    (1, 20, 32),
    ],
    [
    (1, 1, 2), # compile run
    (1, 40, 2),
    (1, 40, 4),
    (1, 40, 8),
    (1, 40, 16),
    (1, 40, 32),
    ],
    [
    (1, 1, 2), # compile run
    (1, 80, 2),
    (1, 80, 4),
    (1, 80, 8),
    (1, 80, 16),
    ],
    [
    (3, 1, 2), # compile run
    (4, 2, 2),
    (4, 2, 4),
    (4, 2, 8),
    (4, 2, 16),
    ],
    [
    (3, 1, 2), # compile run
    (4, 4, 2),
    (4, 4, 4),
    (4, 4, 8),
    ],
    ]

insts = OrderedDict()
insts["nat"] = (nothing, [[(n, d, m, false, true, false)
    for (n, d, m) in ndms] for ndms in nearestpolymat_n_d_ms])
insts["ext"] = (nothing, [[(n, d, m, true, false, false)
    for (n, d, m) in ndms] for ndms in nearestpolymat_n_d_ms])
return (NearestPolyMatJuMP, insts)


text:
# Trace filtering operations

const available_filters = [:butterworth]

"""
    bandpass!(s::SACtr, c1, c2; ftype=:butterworth, npoles=2, passes=1) -> s

Perform a bandpass filter on the SAC trace `s`, between frequency corners `c1`
and `c2`, returning the modified trace.

Select type of filter with `ftype`: current options are: `$(available_filters)`.
Set number of poles with `npoles`.

`passes` may be 1 (forward) or 2 (forward and reverse).
"""
function bandpass!(s::SACtr, c1::Number, c2::Number;
        ftype=:butterworth, npoles::Integer=sac_npoles, passes::Integer=sac_passes)
    c1 >= c2 && error("SAC.bandpass: Upper corner must be larger than lower corner")
    ftype in available_filters || throw(ArgumentError("'$ftype' is not a valid filter type"))
    response = DSP.Bandpass(c1, c2; fs=1.0/s.delta)
    prototype = get_filter_prototype(ftype, npoles)
    # Create apply the filter
    f = DSP.digitalfilter(response, prototype)
    apply_filter!(s, f, passes)
end

function bandpass!(a::AbstractArray{SACtr}, c1, c2; ftype=:butterworth, npoles=sac_npoles,
        passes=sac_passes)
    for s in a
        bandpass!(s, c1, c2; ftype=ftype, npoles=npoles, passes=passes)
    end
    a
end
const bp! = bandpass!

"""
    highpass!(s::SACtr, c; ftype=:butterworth, npoles=2, passes=1) -> s

Perform a highpass filter on the SAC trace `s`, above frequency corner `c`,
returning the modified trace.

Select type of filter with `ftype`: current options are: `$(available_filters)`.
Set number of poles with `npoles`.

`passes` may be 1 (forward) or 2 (forward and reverse).
"""
function highpass!(s::SACtr, c::Number;
        ftype=:butterworth, npoles::Integer=sac_npoles,
        passes::Integer=sac_passes)
    ftype in available_filters || throw(ArgumentError("'$ftype' is not a valid filter type"))
    response = DSP.Highpass(c; fs=1.0/s.delta)
    prototype = get_filter_prototype(ftype, npoles)
    f = DSP.digitalfilter(response, prototype)
    apply_filter!(s, f, passes)
end

function highpass!(a::AbstractArray{SACtr}, c;
        ftype=:butterworth, npoles=sac_npoles, passes=sac_passes)
    for s in a
        highpass!(s, c; ftype=ftype, npoles=npoles, passes=passes)
    end
    a
end
const hp! = highpass!

"""
    lowpass!(s::SACtr, c; ftype=:butterworth, npoles=2, passes=1) -> s

Perform a lowpass filter on the SAC trace `s`, above frequency corner `c`,
returning the modified trace.

Select type of filter with `ftype`: current options are: `$(available_filters)`.
Set number of poles with `npoles`.

`passes` may be 1 (forward) or 2 (forward and reverse).
"""
function lowpass!(s::SACtr, c::Number;
        ftype=:butterworth, npoles::Integer=sac_npoles, passes::Integer=sac_passes)
    ftype in available_filters || throw(ArgumentError("'$ftype' is not a valid filter type"))
    response = DSP.Lowpass(c; fs=1.0/s.delta)
    prototype = get_filter_prototype(ftype, npoles)
    f = DSP.digitalfilter(response, prototype)
    apply_filter!(s, f, passes)
end

function lowpass!(a::AbstractArray{SACtr}, c;
        ftype=:butterworth, npoles=sac_npoles, passes=sac_passes)
    for s in a
        lowpass!(s, c; ftype=ftype, npoles=npoles, passes=passes)
    end
    a
end
const lp! = lowpass!

function apply_filter!(s::SACtr, f, passes::Integer)
        passes < 1 || passes > 2 && error("SAC.apply_filter!: Number of passes must be 1 or 2")
    if passes == 1
        DSP.filt!(s.t, f, s.t)
    elseif passes == 2
        s.t = DSP.filtfilt(f, s.t)
    else
        error("SAC.apply_filter!: passes must be 1 or 2")
    end
    update_headers!(s)
end

"""
    get_filter_prototype(ftype, npoles::Integer) -> prototype

Return a filter prototype for use with filtering via `DSP.filt`.

Filter type `ftype` must be one of:
    $(available_filters)

The number of poles of the filter, `npoles`, must be in the range 1–10.
"""
function get_filter_prototype(ftype, npoles::Integer)
    npoles < 1 || npoles > 10 &&
        error("SAC.get_filter_prototype: npoles must be in range 1 - 10")
    ftype = string(ftype)
    if lowercase(ftype[1:2]) == "bu"
        prototype = DSP.Butterworth(npoles)
    else
        error("SAC.get_filter_prototype: unrecognised filter type '$ftype'")
    end
    prototype
end


text:
# ------------------------------------------------------------------
# Licensed under the ISC License. See LICENSE in the project root.
# ------------------------------------------------------------------

"""
    CookieCutter(master, others)

A cookie-cutter simulation solver.

## Parameters

* `master` - Master simulation solver (a.k.a. facies solver)
* `others` - A list of pairs mapping categories to solvers

## Examples

Simulate lithology facies with image quilting and fill property
with direct Gaussian simulation:

```julia
julia> fsolver  = ImgQuilt(:facies => (TI=Strebelle, template=(30,30,1)))
julia> psolver₀ = DirectGaussSim(:property => (variogram=SphericalVariogram(range=10.),))
julia> psolver₁ = DirectGaussSim(:property => (variogram=SphericalVariogram(range=20.),))
julia> solver   = CookieCutter(fsolver, [0 => psolver₀, 1 => psolver₁])
```
"""
struct CookieCutter <: AbstractSimulationSolver
  master::AbstractSimulationSolver
  others::Vector{Pair{Number,AbstractSimulationSolver}}
end

function solve(problem::SimulationProblem, solver::CookieCutter)
  # retrieve problem info
  pdata   = data(problem)
  pdomain = domain(problem)
  pvars   = variables(problem)
  preals  = nreals(problem)
  pmaps   = datamap(problem)

  # master variable
  mvars = collect(keys(solver.master.params))
  @assert length(mvars) == 1 "one single variable must be specified in master solver"
  mvar = mvars[1]
  @assert mvar ∈ keys(pvars) "invalid variable in master solver"
  mtype = pvars[mvar]

  # other variables
  ovars = Tuple(var => V for (var, V) in pvars if var ≠ mvar)
  @assert length(ovars) > 0 "cookie-cutter requires problem with more than one target variable"

  # copy mappings for master variable
  mmapper = CopyMapper(collect(values(pmaps[mvar])), collect(keys(pmaps[mvar])))

  # define master problem
  if hasdata(problem)
    mproblem = SimulationProblem(pdata, pdomain, mvar, preals, mapper=mmapper)
  else
    mproblem = SimulationProblem(pdomain, mvar => mtype, preals, mapper=mmapper)
  end

  # solve master problem
  msolution = solve(mproblem, solver.master)

  # pre-allocate memory for result
  realizations = msolution.realizations
  for (var, V) in ovars
    reals = map(1:preals) do i
      # find inactive locations in master variable
      inactive = findall(isnan, realizations[mvar][i])

      # copy inactive locations to other variable
      real = Vector{V}(undef, npoints(pdomain))
      view(real, inactive) .= V(NaN)

      real
    end
    realizations[var] = reals
  end

  # find mappings for all other variables
  omaps = merge([pmaps[var] for var in first.(ovars)]...)

  # solve other problems
  for (i, mreal) in enumerate(realizations[mvar])
    for (mval, osolver) in solver.others
      # lookup indices with given master value
      inds = findall(isequal(mval), mreal)

      if !isempty(inds)
        # define subdomain
        odomain = view(pdomain, inds)

        # find mappings for subdomain
        datlocs = Vector{Int}()
        domlocs = Vector{Int}()
        for (j, ind) in enumerate(inds)
          if ind ∈ keys(omaps)
            push!(datlocs, omaps[ind])
            push!(domlocs, j)
          end
        end

        # copy hard data if needed
        omapper = CopyMapper(datlocs, domlocs)

        # define subproblem
        if hasdata(problem)
          oproblem = SimulationProblem(pdata, odomain, first.(ovars), 1, mapper=omapper)
        else
          oproblem = SimulationProblem(odomain, ovars, 1, mapper=omapper)
        end

        # solve subproblem
        osolution = solve(oproblem, osolver)

        # save result and continue
        for (var, V) in ovars
          view(realizations[var][i], inds) .= osolution.realizations[var][1]
        end
      end
    end
  end

  SimulationSolution(pdomain, realizations)
end

# ------------
# IO methods
# ------------
function Base.show(io::IO, solver::CookieCutter)
  print(io, "CookieCutter")
end

function Base.show(io::IO, ::MIME"text/plain", solver::CookieCutter)
  mvar = collect(keys(solver.master.params))[1]
  println(io, solver)
  println(io, "  └─", mvar, " ⇨ ", solver.master)
  for (val, osolver) in solver.others
    println(io, "    └─", val, " ⇨ ", osolver)
  end
end


text:
##############################################################################################################
# Optimization Run for NICE Without Revenue Recycling (Reference Case)
##############################################################################################################

#-------------------------------------------------------------------------------------
# Set up first-stage global optimization for reference case without revenue recycling.
#-------------------------------------------------------------------------------------

println("Beginning global optimization for reference case without revenue recycling.")

# Create NICE objective function with user parameter settings and revenue recycling switched off.
reference_objective = construct_nice_recycle_objective(nice, revenue_recycling = false)

# Create an NLopt optimization object.
reference_opt_global = Opt(global_opt_algorithm, n_objectives)

# Set upper and lower bounds for global CO₂ tax (upper bound = maximum RICE backstop prices).
upper_bound = maximum(rice_backstop_prices, dims=2)[2:(n_objectives+1)]

lower_bounds!(reference_opt_global, zeros(n_objectives))
upper_bounds!(reference_opt_global, upper_bound)

# Set max run time.
maxtime!(reference_opt_global, global_stop_time)

# Set convergence tolerance.
ftol_rel!(reference_opt_global, global_tolerance)

# Set objective function.
max_objective!(reference_opt_global, (x, grad) -> reference_objective(x))

# Optimize model using global optimization algorithm, initialized at a fraction of the upper bound.
reference_max_welfare_global, reference_opt_tax_global, reference_convergence_global = optimize(reference_opt_global, upper_bound ./ 100)

# Calculate full tax time series (just to have to cross-check with local solution).
reference_full_global_opt_tax, reference_global_opt_regional_mitigation = mu_from_tax(reference_opt_tax_global, rice_backstop_prices)

println("Convergence result = ", reference_convergence_global)

#--------------------------------------------------------------------------------------
# Set up second-stage local optimization for reference case without revenue recycling.
#--------------------------------------------------------------------------------------

println("Beginning local optimization for reference case without revenue recycling.")

# Create an NLopt optimization object for second-stage local optimization.
reference_opt = Opt(local_opt_algorithm, n_objectives)

# Set upper and lower bounds for global CO₂ tax (upper bound = maximum RICE backstop prices).
lower_bounds!(reference_opt, zeros(n_objectives))
upper_bounds!(reference_opt, upper_bound)

# Set max run time.
maxtime!(reference_opt, local_stop_time)

# Set convergence tolerance.
ftol_rel!(reference_opt, local_tolerance)

# Set objective function.
max_objective!(reference_opt, (x, grad) -> reference_objective(x))

# Optimize model using local optimization algorithm, initialized at global optimization solution.
reference_max_welfare, reference_opt_tax, reference_convergence = optimize(reference_opt, reference_opt_tax_global)

println("Convergence result = ", reference_convergence)

#-----------------------------------------------------------
# Run Reference Model Under Optimal Policy and Save Results
#-----------------------------------------------------------

# Get optimal regional CO₂ mitigation rates from final optimal tax.
reference_full_opt_tax, reference_opt_regional_mitigation = mu_from_tax(reference_opt_tax, rice_backstop_prices)

# Run model under optimal policy.
set_param!(nice, :MIU, reference_opt_regional_mitigation)
set_param!(nice, :global_carbon_tax, zeros(n_steps))
run(nice)

# Save results.
if save_results == true
    save_nice_recycle_results(nice, bau_model, reference_full_opt_tax, reference_full_global_opt_tax, output_directory, revenue_recycling=false)
end

println("Reference runs complete.")


text:
function year_to_seconds(n)
    seconds = 365*24*60*60
    return n*seconds
end

for n in [1 2 5 10]
    println(year_to_seconds(n))
end

max_stars_repo_name: sugitanishi/competitive-programming

max_issues_repo_name: sugitanishi/competitive-programming

max_forks_repo_name: sugitanishi/competitive-programming


text:
immutable Time
    microseconds::Int64
end

function as_seconds(time::Time)
    return Real(ccall((:sfTime_asSeconds, libcsfml_system), Cfloat, (Time,), time))
end

function as_milliseconds(time::Time)
    return ccall((:sfTime_asMilliseconds, libcsfml_system), Int32, (Time,), time)
end

function as_microseconds(time::Time)
    return ccall((:sfTime_asMicroseconds, libcsfml_system), Int64, (Time,), time)
end

function seconds(amount::Real)
    return ccall((:sfSeconds, libcsfml_system), Time, (Cfloat,), amount)
end

function milliseconds(amount::Integer)
    return ccall((:sfMilliseconds, libcsfml_system), Time, (Int32,), amount)
end

function microseconds(amount::Int64)
    return ccall((:sfMicroseconds, libcsfml_system), Time, (Int64,), amount)
end


text:
using Documenter, NonlinearTestProblems

makedocs(
    modules = [NonlinearTestProblems],
    format = Documenter.HTML(; prettyurls = get(ENV, "CI", nothing) == "true"),
    authors = "Tamas K. Papp",
    sitename = "NonlinearTestProblems.jl",
    pages = Any["index.md"]
    # strict = true,
    # clean = true,
    # checkdocs = :exports,
)

deploydocs(
    repo = "github.com/tpapp/NonlinearTestProblems.jl.git",
    push_preview = true
)


text:
# Julia wrapper for header: cufft.h
# Automatically generated using Clang.jl

@checked function cufftPlan1d(plan, nx, type, batch)
    initialize_api()
    @runtime_ccall((:cufftPlan1d, libcufft()), cufftResult,
                   (Ptr{cufftHandle}, Cint, cufftType, Cint),
                   plan, nx, type, batch)
end

@checked function cufftPlan2d(plan, nx, ny, type)
    initialize_api()
    @runtime_ccall((:cufftPlan2d, libcufft()), cufftResult,
                   (Ptr{cufftHandle}, Cint, Cint, cufftType),
                   plan, nx, ny, type)
end

@checked function cufftPlan3d(plan, nx, ny, nz, type)
    initialize_api()
    @runtime_ccall((:cufftPlan3d, libcufft()), cufftResult,
                   (Ptr{cufftHandle}, Cint, Cint, Cint, cufftType),
                   plan, nx, ny, nz, type)
end

@checked function cufftPlanMany(plan, rank, n, inembed, istride, idist, onembed, ostride,
                                odist, type, batch)
    initialize_api()
    @runtime_ccall((:cufftPlanMany, libcufft()), cufftResult,
                   (Ptr{cufftHandle}, Cint, Ptr{Cint}, Ptr{Cint}, Cint, Cint, Ptr{Cint},
                    Cint, Cint, cufftType, Cint),
                   plan, rank, n, inembed, istride, idist, onembed, ostride, odist, type,
                   batch)
end

@checked function cufftMakePlan1d(plan, nx, type, batch, workSize)
    initialize_api()
    @runtime_ccall((:cufftMakePlan1d, libcufft()), cufftResult,
                   (cufftHandle, Cint, cufftType, Cint, Ptr{Csize_t}),
                   plan, nx, type, batch, workSize)
end

@checked function cufftMakePlan2d(plan, nx, ny, type, workSize)
    initialize_api()
    @runtime_ccall((:cufftMakePlan2d, libcufft()), cufftResult,
                   (cufftHandle, Cint, Cint, cufftType, Ptr{Csize_t}),
                   plan, nx, ny, type, workSize)
end

@checked function cufftMakePlan3d(plan, nx, ny, nz, type, workSize)
    initialize_api()
    @runtime_ccall((:cufftMakePlan3d, libcufft()), cufftResult,
                   (cufftHandle, Cint, Cint, Cint, cufftType, Ptr{Csize_t}),
                   plan, nx, ny, nz, type, workSize)
end

@checked function cufftMakePlanMany(plan, rank, n, inembed, istride, idist, onembed,
                                    ostride, odist, type, batch, workSize)
    initialize_api()
    @runtime_ccall((:cufftMakePlanMany, libcufft()), cufftResult,
                   (cufftHandle, Cint, Ptr{Cint}, Ptr{Cint}, Cint, Cint, Ptr{Cint}, Cint,
                    Cint, cufftType, Cint, Ptr{Csize_t}),
                   plan, rank, n, inembed, istride, idist, onembed, ostride, odist, type,
                   batch, workSize)
end

@checked function cufftMakePlanMany64(plan, rank, n, inembed, istride, idist, onembed,
                                      ostride, odist, type, batch, workSize)
    initialize_api()
    @runtime_ccall((:cufftMakePlanMany64, libcufft()), cufftResult,
                   (cufftHandle, Cint, Ptr{Clonglong}, Ptr{Clonglong}, Clonglong,
                    Clonglong, Ptr{Clonglong}, Clonglong, Clonglong, cufftType, Clonglong,
                    Ptr{Csize_t}),
                   plan, rank, n, inembed, istride, idist, onembed, ostride, odist, type,
                   batch, workSize)
end

@checked function cufftGetSizeMany64(plan, rank, n, inembed, istride, idist, onembed,
                                     ostride, odist, type, batch, workSize)
    initialize_api()
    @runtime_ccall((:cufftGetSizeMany64, libcufft()), cufftResult,
                   (cufftHandle, Cint, Ptr{Clonglong}, Ptr{Clonglong}, Clonglong,
                    Clonglong, Ptr{Clonglong}, Clonglong, Clonglong, cufftType, Clonglong,
                    Ptr{Csize_t}),
                   plan, rank, n, inembed, istride, idist, onembed, ostride, odist, type,
                   batch, workSize)
end

@checked function cufftEstimate1d(nx, type, batch, workSize)
    initialize_api()
    @runtime_ccall((:cufftEstimate1d, libcufft()), cufftResult,
                   (Cint, cufftType, Cint, Ptr{Csize_t}),
                   nx, type, batch, workSize)
end

@checked function cufftEstimate2d(nx, ny, type, workSize)
    initialize_api()
    @runtime_ccall((:cufftEstimate2d, libcufft()), cufftResult,
                   (Cint, Cint, cufftType, Ptr{Csize_t}),
                   nx, ny, type, workSize)
end

@checked function cufftEstimate3d(nx, ny, nz, type, workSize)
    initialize_api()
    @runtime_ccall((:cufftEstimate3d, libcufft()), cufftResult,
                   (Cint, Cint, Cint, cufftType, Ptr{Csize_t}),
                   nx, ny, nz, type, workSize)
end

@checked function cufftEstimateMany(rank, n, inembed, istride, idist, onembed, ostride,
                                    odist, type, batch, workSize)
    initialize_api()
    @runtime_ccall((:cufftEstimateMany, libcufft()), cufftResult,
                   (Cint, Ptr{Cint}, Ptr{Cint}, Cint, Cint, Ptr{Cint}, Cint, Cint,
                    cufftType, Cint, Ptr{Csize_t}),
                   rank, n, inembed, istride, idist, onembed, ostride, odist, type, batch,
                   workSize)
end

@checked function cufftCreate(handle)
    initialize_api()
    @runtime_ccall((:cufftCreate, libcufft()), cufftResult,
                   (Ptr{cufftHandle},),
                   handle)
end

@checked function cufftGetSize1d(handle, nx, type, batch, workSize)
    initialize_api()
    @runtime_ccall((:cufftGetSize1d, libcufft()), cufftResult,
                   (cufftHandle, Cint, cufftType, Cint, Ptr{Csize_t}),
                   handle, nx, type, batch, workSize)
end

@checked function cufftGetSize2d(handle, nx, ny, type, workSize)
    initialize_api()
    @runtime_ccall((:cufftGetSize2d, libcufft()), cufftResult,
                   (cufftHandle, Cint, Cint, cufftType, Ptr{Csize_t}),
                   handle, nx, ny, type, workSize)
end

@checked function cufftGetSize3d(handle, nx, ny, nz, type, workSize)
    initialize_api()
    @runtime_ccall((:cufftGetSize3d, libcufft()), cufftResult,
                   (cufftHandle, Cint, Cint, Cint, cufftType, Ptr{Csize_t}),
                   handle, nx, ny, nz, type, workSize)
end

@checked function cufftGetSizeMany(handle, rank, n, inembed, istride, idist, onembed,
                                   ostride, odist, type, batch, workArea)
    initialize_api()
    @runtime_ccall((:cufftGetSizeMany, libcufft()), cufftResult,
                   (cufftHandle, Cint, Ptr{Cint}, Ptr{Cint}, Cint, Cint, Ptr{Cint}, Cint,
                    Cint, cufftType, Cint, Ptr{Csize_t}),
                   handle, rank, n, inembed, istride, idist, onembed, ostride, odist, type,
                   batch, workArea)
end

@checked function cufftGetSize(handle, workSize)
    initialize_api()
    @runtime_ccall((:cufftGetSize, libcufft()), cufftResult,
                   (cufftHandle, Ptr{Csize_t}),
                   handle, workSize)
end

@checked function cufftSetWorkArea(plan, workArea)
    initialize_api()
    @runtime_ccall((:cufftSetWorkArea, libcufft()), cufftResult,
                   (cufftHandle, CuPtr{Cvoid}),
                   plan, workArea)
end

@checked function cufftSetAutoAllocation(plan, autoAllocate)
    initialize_api()
    @runtime_ccall((:cufftSetAutoAllocation, libcufft()), cufftResult,
                   (cufftHandle, Cint),
                   plan, autoAllocate)
end

@checked function cufftExecC2C(plan, idata, odata, direction)
    initialize_api()
    @runtime_ccall((:cufftExecC2C, libcufft()), cufftResult,
                   (cufftHandle, CuPtr{cufftComplex}, CuPtr{cufftComplex}, Cint),
                   plan, idata, odata, direction)
end

@checked function cufftExecR2C(plan, idata, odata)
    initialize_api()
    @runtime_ccall((:cufftExecR2C, libcufft()), cufftResult,
                   (cufftHandle, CuPtr{cufftReal}, CuPtr{cufftComplex}),
                   plan, idata, odata)
end

@checked function cufftExecC2R(plan, idata, odata)
    initialize_api()
    @runtime_ccall((:cufftExecC2R, libcufft()), cufftResult,
                   (cufftHandle, CuPtr{cufftComplex}, CuPtr{cufftReal}),
                   plan, idata, odata)
end

@checked function cufftExecZ2Z(plan, idata, odata, direction)
    initialize_api()
    @runtime_ccall((:cufftExecZ2Z, libcufft()), cufftResult,
                   (cufftHandle, CuPtr{cufftDoubleComplex}, CuPtr{cufftDoubleComplex},
                    Cint),
                   plan, idata, odata, direction)
end

@checked function cufftExecD2Z(plan, idata, odata)
    initialize_api()
    @runtime_ccall((:cufftExecD2Z, libcufft()), cufftResult,
                   (cufftHandle, CuPtr{cufftDoubleReal}, CuPtr{cufftDoubleComplex}),
                   plan, idata, odata)
end

@checked function cufftExecZ2D(plan, idata, odata)
    initialize_api()
    @runtime_ccall((:cufftExecZ2D, libcufft()), cufftResult,
                   (cufftHandle, CuPtr{cufftDoubleComplex}, CuPtr{cufftDoubleReal}),
                   plan, idata, odata)
end

@checked function cufftSetStream(plan, stream)
    initialize_api()
    @runtime_ccall((:cufftSetStream, libcufft()), cufftResult,
                   (cufftHandle, CUstream),
                   plan, stream)
end

@checked function cufftDestroy(plan)
    initialize_api()
    @runtime_ccall((:cufftDestroy, libcufft()), cufftResult,
                   (cufftHandle,),
                   plan)
end

@checked function cufftGetVersion(version)
    @runtime_ccall((:cufftGetVersion, libcufft()), cufftResult,
                   (Ptr{Cint},),
                   version)
end

@checked function cufftGetProperty(type, value)
    @runtime_ccall((:cufftGetProperty, libcufft()), cufftResult,
                   (libraryPropertyType, Ptr{Cint}),
                   type, value)
end


text:
export  d4rl_dataset_params

function d4rl_dataset_params()
    dataset = keys(D4RL_DATASET_URLS)
    repo = "d4rl"
    @info dataset repo
end

const D4RL_DATASET_URLS = Dict{String, String}(
    "maze2d-open-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/maze2d/maze2d-open-sparse.hdf5",
    "maze2d-umaze-v1" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/maze2d/maze2d-umaze-sparse-v1.hdf5",
    "maze2d-medium-v1" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/maze2d/maze2d-medium-sparse-v1.hdf5",
    "maze2d-large-v1" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/maze2d/maze2d-large-sparse-v1.hdf5",
    "maze2d-eval-umaze-v1" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/maze2d/maze2d-eval-umaze-sparse-v1.hdf5",
    "maze2d-eval-medium-v1" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/maze2d/maze2d-eval-medium-sparse-v1.hdf5",
    "maze2d-eval-large-v1" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/maze2d/maze2d-eval-large-sparse-v1.hdf5",
    "maze2d-open-dense-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/maze2d/maze2d-open-dense.hdf5",
    "maze2d-umaze-dense-v1" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/maze2d/maze2d-umaze-dense-v1.hdf5",
    "maze2d-medium-dense-v1" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/maze2d/maze2d-medium-dense-v1.hdf5",
    "maze2d-large-dense-v1" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/maze2d/maze2d-large-dense-v1.hdf5",
    "maze2d-eval-umaze-dense-v1" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/maze2d/maze2d-eval-umaze-dense-v1.hdf5",
    "maze2d-eval-medium-dense-v1" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/maze2d/maze2d-eval-medium-dense-v1.hdf5",
    "maze2d-eval-large-dense-v1" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/maze2d/maze2d-eval-large-dense-v1.hdf5",
    "minigrid-fourrooms-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/minigrid/minigrid4rooms.hdf5",
    "minigrid-fourrooms-random-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/minigrid/minigrid4rooms_random.hdf5",
    "pen-human-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/hand_dapg/pen-v0_demos_clipped.hdf5",
    "pen-cloned-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/hand_dapg/pen-demos-v0-bc-combined.hdf5",
    "pen-expert-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/hand_dapg/pen-v0_expert_clipped.hdf5",
    "hammer-human-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/hand_dapg/hammer-v0_demos_clipped.hdf5",
    "hammer-cloned-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/hand_dapg/hammer-demos-v0-bc-combined.hdf5",
    "hammer-expert-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/hand_dapg/hammer-v0_expert_clipped.hdf5",
    "relocate-human-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/hand_dapg/relocate-v0_demos_clipped.hdf5",
    "relocate-cloned-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/hand_dapg/relocate-demos-v0-bc-combined.hdf5",
    "relocate-expert-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/hand_dapg/relocate-v0_expert_clipped.hdf5",
    "door-human-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/hand_dapg/door-v0_demos_clipped.hdf5",
    "door-cloned-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/hand_dapg/door-demos-v0-bc-combined.hdf5",
    "door-expert-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/hand_dapg/door-v0_expert_clipped.hdf5",
    "halfcheetah-random-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/gym_mujoco/halfcheetah_random.hdf5",
    "halfcheetah-medium-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/gym_mujoco/halfcheetah_medium.hdf5",
    "halfcheetah-expert-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/gym_mujoco/halfcheetah_expert.hdf5",
    "halfcheetah-medium-replay-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/gym_mujoco/halfcheetah_mixed.hdf5",
    "halfcheetah-medium-expert-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/gym_mujoco/halfcheetah_medium_expert.hdf5",
    "walker2d-random-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/gym_mujoco/walker2d_random.hdf5",
    "walker2d-medium-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/gym_mujoco/walker2d_medium.hdf5",
    "walker2d-expert-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/gym_mujoco/walker2d_expert.hdf5",
    "walker2d-medium-replay-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/gym_mujoco/walker_mixed.hdf5",
    "walker2d-medium-expert-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/gym_mujoco/walker2d_medium_expert.hdf5",
    "hopper-random-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/gym_mujoco/hopper_random.hdf5",
    "hopper-medium-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/gym_mujoco/hopper_medium.hdf5",
    "hopper-expert-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/gym_mujoco/hopper_expert.hdf5",
    "hopper-medium-replay-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/gym_mujoco/hopper_mixed.hdf5",
    "hopper-medium-expert-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/gym_mujoco/hopper_medium_expert.hdf5",
    "ant-random-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/gym_mujoco/ant_random.hdf5",
    "ant-medium-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/gym_mujoco/ant_medium.hdf5",
    "ant-expert-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/gym_mujoco/ant_expert.hdf5",
    "ant-medium-replay-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/gym_mujoco/ant_mixed.hdf5",
    "ant-medium-expert-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/gym_mujoco/ant_medium_expert.hdf5",
    "ant-random-expert-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/gym_mujoco/ant_random_expert.hdf5",
    "antmaze-umaze-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/ant_maze_new/Ant_maze_u-maze_noisy_multistart_False_multigoal_False_sparse.hdf5",
    "antmaze-umaze-diverse-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/ant_maze_new/Ant_maze_u-maze_noisy_multistart_True_multigoal_True_sparse.hdf5",
    "antmaze-medium-play-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/ant_maze_new/Ant_maze_big-maze_noisy_multistart_True_multigoal_False_sparse.hdf5",
    "antmaze-medium-diverse-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/ant_maze_new/Ant_maze_big-maze_noisy_multistart_True_multigoal_True_sparse.hdf5",
    "antmaze-large-play-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/ant_maze_new/Ant_maze_hardest-maze_noisy_multistart_True_multigoal_False_sparse.hdf5",
    "antmaze-large-diverse-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/ant_maze_new/Ant_maze_hardest-maze_noisy_multistart_True_multigoal_True_sparse.hdf5",
    "flow-ring-random-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/flow/flow-ring-v0-random.hdf5",
    "flow-ring-controller-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/flow/flow-ring-v0-idm.hdf5",
    "flow-merge-random-v0"=>"http://rail.eecs.berkeley.edu/datasets/offline_rl/flow/flow-merge-v0-random.hdf5",
    "flow-merge-controller-v0"=>"http://rail.eecs.berkeley.edu/datasets/offline_rl/flow/flow-merge-v0-idm.hdf5",
    "kitchen-complete-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/kitchen/mini_kitchen_microwave_kettle_light_slider-v0.hdf5",
    "kitchen-partial-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/kitchen/kitchen_microwave_kettle_light_slider-v0.hdf5",
    "kitchen-mixed-v0" => "http://rail.eecs.berkeley.edu/datasets/offline_rl/kitchen/kitchen_microwave_kettle_bottomburner_light-v0.hdf5",
    "carla-lane-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/carla/carla_lane_follow_flat-v0.hdf5",
    "carla-town-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/carla/carla_town_subsamp_flat-v0.hdf5",
    "carla-town-full-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/carla/carla_town_flat-v0.hdf5",
    "bullet-halfcheetah-random-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-halfcheetah_random.hdf5",
    "bullet-halfcheetah-medium-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-halfcheetah_medium.hdf5",
    "bullet-halfcheetah-expert-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-halfcheetah_expert.hdf5",
    "bullet-halfcheetah-medium-expert-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-halfcheetah_medium_expert.hdf5",
    "bullet-halfcheetah-medium-replay-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-halfcheetah_medium_replay.hdf5",
    "bullet-hopper-random-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-hopper_random.hdf5",
    "bullet-hopper-medium-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-hopper_medium.hdf5",
    "bullet-hopper-expert-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-hopper_expert.hdf5",
    "bullet-hopper-medium-expert-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-hopper_medium_expert.hdf5",
    "bullet-hopper-medium-replay-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-hopper_medium_replay.hdf5",
    "bullet-ant-random-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-ant_random.hdf5",
    "bullet-ant-medium-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-ant_medium.hdf5",
    "bullet-ant-expert-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-ant_expert.hdf5",
    "bullet-ant-medium-expert-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-ant_medium_expert.hdf5",
    "bullet-ant-medium-replay-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-ant_medium_replay.hdf5",
    "bullet-walker2d-random-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-walker2d_random.hdf5",
    "bullet-walker2d-medium-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-walker2d_medium.hdf5",
    "bullet-walker2d-expert-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-walker2d_expert.hdf5",
    "bullet-walker2d-medium-expert-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-walker2d_medium_expert.hdf5",
    "bullet-walker2d-medium-replay-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-walker2d_medium_replay.hdf5",
    "bullet-maze2d-open-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-maze2d-open-sparse.hdf5",
    "bullet-maze2d-umaze-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-maze2d-umaze-sparse.hdf5",
    "bullet-maze2d-medium-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-maze2d-medium-sparse.hdf5",
    "bullet-maze2d-large-v0"=> "http://rail.eecs.berkeley.edu/datasets/offline_rl/bullet/bullet-maze2d-large-sparse.hdf5",
)

const D4RL_REF_MIN_SCORE = Dict{String, Float32}(
    "maze2d-open-v0" => 0.01 ,
    "maze2d-umaze-v1" => 23.85 ,
    "maze2d-medium-v1" => 13.13 ,
    "maze2d-large-v1" => 6.7 ,
    "maze2d-open-dense-v0" => 11.17817 ,
    "maze2d-umaze-dense-v1" => 68.537689 ,
    "maze2d-medium-dense-v1" => 44.264742 ,
    "maze2d-large-dense-v1" => 30.569041 ,
    "minigrid-fourrooms-v0" => 0.01442 ,
    "minigrid-fourrooms-random-v0" => 0.01442 ,
    "pen-human-v0" => 96.262799 ,
    "pen-cloned-v0" => 96.262799 ,
    "pen-expert-v0" => 96.262799 ,
    "hammer-human-v0" => -274.856578 ,
    "hammer-cloned-v0" => -274.856578 ,
    "hammer-expert-v0" => -274.856578 ,
    "relocate-human-v0" => -6.425911 ,
    "relocate-cloned-v0" => -6.425911 ,
    "relocate-expert-v0" => -6.425911 ,
    "door-human-v0" => -56.512833 ,
    "door-cloned-v0" => -56.512833 ,
    "door-expert-v0" => -56.512833 ,
    "halfcheetah-random-v0" => -280.178953 ,
    "halfcheetah-medium-v0" => -280.178953 ,
    "halfcheetah-expert-v0" => -280.178953 ,
    "halfcheetah-medium-replay-v0" => -280.178953 ,
    "halfcheetah-medium-expert-v0" => -280.178953 ,
    "walker2d-random-v0" => 1.629008 ,
    "walker2d-medium-v0" => 1.629008 ,
    "walker2d-expert-v0" => 1.629008 ,
    "walker2d-medium-replay-v0" => 1.629008 ,
    "walker2d-medium-expert-v0" => 1.629008 ,
    "hopper-random-v0" => -20.272305 ,
    "hopper-medium-v0" => -20.272305 ,
    "hopper-expert-v0" => -20.272305 ,
    "hopper-medium-replay-v0" => -20.272305 ,
    "hopper-medium-expert-v0" => -20.272305 ,
    "ant-random-v0" => -325.6,
    "ant-medium-v0" => -325.6,
    "ant-expert-v0" => -325.6,
    "ant-medium-replay-v0" => -325.6,
    "ant-medium-expert-v0" => -325.6,
    "antmaze-umaze-v0" => 0.0 ,
    "antmaze-umaze-diverse-v0" => 0.0 ,
    "antmaze-medium-play-v0" => 0.0 ,
    "antmaze-medium-diverse-v0" => 0.0 ,
    "antmaze-large-play-v0" => 0.0 ,
    "antmaze-large-diverse-v0" => 0.0 ,
    "kitchen-complete-v0" => 0.0 ,
    "kitchen-partial-v0" => 0.0 ,
    "kitchen-mixed-v0" => 0.0 ,
    "flow-ring-random-v0" => -165.22 ,
    "flow-ring-controller-v0" => -165.22 ,
    "flow-merge-random-v0" => 118.67993 ,
    "flow-merge-controller-v0" => 118.67993 ,
    "carla-lane-v0"=> -0.8503839912088142,
    "carla-town-v0"=> -114.81579500772153, # random score
    "bullet-halfcheetah-random-v0"=> -1275.766996,
    "bullet-halfcheetah-medium-v0"=> -1275.766996,
    "bullet-halfcheetah-expert-v0"=> -1275.766996,
    "bullet-halfcheetah-medium-expert-v0"=> -1275.766996,
    "bullet-halfcheetah-medium-replay-v0"=> -1275.766996,
    "bullet-hopper-random-v0"=> 20.058972,
    "bullet-hopper-medium-v0"=> 20.058972,
    "bullet-hopper-expert-v0"=> 20.058972,
    "bullet-hopper-medium-expert-v0"=> 20.058972,
    "bullet-hopper-medium-replay-v0"=> 20.058972,
    "bullet-ant-random-v0"=> 373.705955,
    "bullet-ant-medium-v0"=> 373.705955,
    "bullet-ant-expert-v0"=> 373.705955,
    "bullet-ant-medium-expert-v0"=> 373.705955,
    "bullet-ant-medium-replay-v0"=> 373.705955,
    "bullet-walker2d-random-v0"=> 16.523877,
    "bullet-walker2d-medium-v0"=> 16.523877,
    "bullet-walker2d-expert-v0"=> 16.523877,
    "bullet-walker2d-medium-expert-v0"=> 16.523877,
    "bullet-walker2d-medium-replay-v0"=> 16.523877,
    "bullet-maze2d-open-v0"=> 8.750000,
    "bullet-maze2d-umaze-v0"=> 32.460000,
    "bullet-maze2d-medium-v0"=> 14.870000,
    "bullet-maze2d-large-v0"=> 1.820000,
)

const D4RL_REF_MAX_SCORE = Dict{String, Float32}(
    "maze2d-open-v0" => 20.66 ,
    "maze2d-umaze-v1" => 161.86 ,
    "maze2d-medium-v1" => 277.39 ,
    "maze2d-large-v1" => 273.99 ,
    "maze2d-open-dense-v0" => 27.166538620695782 ,
    "maze2d-umaze-dense-v1" => 193.66285642381482 ,
    "maze2d-medium-dense-v1" => 297.4552547777125 ,
    "maze2d-large-dense-v1" => 303.4857382709002 ,
    "minigrid-fourrooms-v0" => 2.89685 ,
    "minigrid-fourrooms-random-v0" => 2.89685 ,
    "pen-human-v0" => 3076.8331017826877 ,
    "pen-cloned-v0" => 3076.8331017826877 ,
    "pen-expert-v0" => 3076.8331017826877 ,
    "hammer-human-v0" => 12794.134825156867 ,
    "hammer-cloned-v0" => 12794.134825156867 ,
    "hammer-expert-v0" => 12794.134825156867 ,
    "relocate-human-v0" => 4233.877797728884 ,
    "relocate-cloned-v0" => 4233.877797728884 ,
    "relocate-expert-v0" => 4233.877797728884 ,
    "door-human-v0" => 2880.5693087298737 ,
    "door-cloned-v0" => 2880.5693087298737 ,
    "door-expert-v0" => 2880.5693087298737 ,
    "halfcheetah-random-v0" => 12135.0 ,
    "halfcheetah-medium-v0" => 12135.0 ,
    "halfcheetah-expert-v0" => 12135.0 ,
    "halfcheetah-medium-replay-v0" => 12135.0 ,
    "halfcheetah-medium-expert-v0" => 12135.0 ,
    "walker2d-random-v0" => 4592.3 ,
    "walker2d-medium-v0" => 4592.3 ,
    "walker2d-expert-v0" => 4592.3 ,
    "walker2d-medium-replay-v0" => 4592.3 ,
    "walker2d-medium-expert-v0" => 4592.3 ,
    "hopper-random-v0" => 3234.3 ,
    "hopper-medium-v0" => 3234.3 ,
    "hopper-expert-v0" => 3234.3 ,
    "hopper-medium-replay-v0" => 3234.3 ,
    "hopper-medium-expert-v0" => 3234.3 ,
    "ant-random-v0" => 3879.7,
    "ant-medium-v0" => 3879.7,
    "ant-expert-v0" => 3879.7,
    "ant-medium-replay-v0" => 3879.7,
    "ant-medium-expert-v0" => 3879.7,
    "antmaze-umaze-v0" => 1.0 ,
    "antmaze-umaze-diverse-v0" => 1.0 ,
    "antmaze-medium-play-v0" => 1.0 ,
    "antmaze-medium-diverse-v0" => 1.0 ,
    "antmaze-large-play-v0" => 1.0 ,
    "antmaze-large-diverse-v0" => 1.0 ,
    "kitchen-complete-v0" => 4.0 ,
    "kitchen-partial-v0" => 4.0 ,
    "kitchen-mixed-v0" => 4.0 ,
    "flow-ring-random-v0" => 24.42 ,
    "flow-ring-controller-v0" => 24.42 ,
    "flow-merge-random-v0" => 330.03179 ,
    "flow-merge-controller-v0" => 330.03179 ,
    "carla-lane-v0"=> 1023.5784385429523,
    "carla-town-v0"=> 2440.1772022247314, # avg dataset score
    "bullet-halfcheetah-random-v0"=> 2381.6725,
    "bullet-halfcheetah-medium-v0"=> 2381.6725,
    "bullet-halfcheetah-expert-v0"=> 2381.6725,
    "bullet-halfcheetah-medium-expert-v0"=> 2381.6725,
    "bullet-halfcheetah-medium-replay-v0"=> 2381.6725,
    "bullet-hopper-random-v0"=> 1441.8059623430963,
    "bullet-hopper-medium-v0"=> 1441.8059623430963,
    "bullet-hopper-expert-v0"=> 1441.8059623430963,
    "bullet-hopper-medium-expert-v0"=> 1441.8059623430963,
    "bullet-hopper-medium-replay-v0"=> 1441.8059623430963,
    "bullet-ant-random-v0"=> 2650.495,
    "bullet-ant-medium-v0"=> 2650.495,
    "bullet-ant-expert-v0"=> 2650.495,
    "bullet-ant-medium-expert-v0"=> 2650.495,
    "bullet-ant-medium-replay-v0"=> 2650.495,
    "bullet-walker2d-random-v0"=> 1623.6476303317536,
    "bullet-walker2d-medium-v0"=> 1623.6476303317536,
    "bullet-walker2d-expert-v0"=> 1623.6476303317536,
    "bullet-walker2d-medium-expert-v0"=> 1623.6476303317536,
    "bullet-walker2d-medium-replay-v0"=> 1623.6476303317536,
    "bullet-maze2d-open-v0"=> 64.15,
    "bullet-maze2d-umaze-v0"=> 153.99,
    "bullet-maze2d-medium-v0"=> 238.05,
    "bullet-maze2d-large-v0"=> 285.92,
)

# give a prompt for flow and carla tasks

function d4rl_init()
    repo = "d4rl"
    for ds in keys(D4RL_DATASET_URLS)
        register(
            DataDep(
                repo*"-"* ds,
                """
                Credits: https://arxiv.org/abs/2004.07219
                The following dataset is fetched from the d4rl.
                The dataset is fetched and modified in a form that is useful for RL.jl package.

                Dataset information:
                Name: $(ds)
                $(if ds in keys(D4RL_REF_MAX_SCORE) "MAXIMUM_SCORE: " * string(D4RL_REF_MAX_SCORE[ds]) end)
                $(if ds in keys(D4RL_REF_MIN_SCORE) "MINIMUM_SCORE: " * string(D4RL_REF_MIN_SCORE[ds]) end)
                """, #check if the MAX and MIN score part is even necessary and make the log file prettier
                D4RL_DATASET_URLS[ds],
            )
        )
    end
    nothing
end


text:
###############################################################################
#
# Update CanopyLayer struct when temperature or upstream pressure changes
#
###############################################################################
"""
    update_leaf_TP!(
                photo_set::AbstractPhotoModelParaSet{FT},
                canopyi::CanopyLayer{FT},
                hs::LeafHydraulics{FT},
                envir::AirLayer{FT}
    ) where {FT<:AbstractFloat}

Update leaf physiological parameters if temperature or pressure changes in the
daytime, given
- `photo_set` [`C3ParaSet`] or [`C4ParaSet`] type parameter set
- `canopyi` [`CanopyLayer`](@ref) type struct
- `hs` Leaf hydraulic system
- `envir` [`AirLayer`] type struct
"""
function update_leaf_TP!(
            photo_set::AbstractPhotoModelParaSet{FT},
            canopyi::CanopyLayer{FT},
            hs::LeafHydraulics{FT},
            envir::AirLayer{FT}
) where {FT<:AbstractFloat}
    # unpack required variables
    @unpack g_max25, g_min25, p_ups, p_old, T, T_old = canopyi;

    # if T changes, update TD and ec, then T_old
    if T != T_old
        canopyi.g_max = g_max25 * relative_diffusive_coefficient(T);
        canopyi.g_min = g_min25 * relative_diffusive_coefficient(T);
        canopyi.LV    = latent_heat_vapor(T) * M_H₂O(FT);
        canopyi.ps.T  = canopyi.T;
        leaf_temperature_dependence!(photo_set, canopyi.ps, envir);
        canopyi.p_sat = canopyi.ps.p_sat;
        temperature_effects!(hs);
        hs.p_ups      = canopyi.p_ups;
        canopyi.ec    = critical_flow(hs, canopyi.ec);
        canopyi.T_old = canopyi.T;
        canopyi.p_old = canopyi.p_ups;
    # if only p_ups changes, update ec and p_old
    elseif p_ups != p_old
        hs.p_ups      = canopyi.p_ups;
        canopyi.ec    = critical_flow(hs, canopyi.ec);
        canopyi.p_old = canopyi.p_ups;
    end

    return nothing
end

function update_leaf_TP!(
            photo_set::AbstractPhotoModelParaSet{FT},
            canopyi::CanopyLayer{FT},
            hs::TreeSimple{FT},
            envir::AirLayer{FT}
) where {FT<:AbstractFloat}
    # unpack required variables
    @unpack g_max25, g_min25, p_ups, p_old, T, T_old = canopyi;

    # note that canopyi.p_ups is not used here
    # if T changes, update TD and ec, then T_old
    if T != T_old
        canopyi.g_max = g_max25 * relative_diffusive_coefficient(T);
        canopyi.g_min = g_min25 * relative_diffusive_coefficient(T);
        canopyi.LV    = latent_heat_vapor(T) * M_H₂O(FT);
        canopyi.ps.T  = canopyi.T;
        leaf_temperature_dependence!(photo_set, canopyi.ps, envir);
        canopyi.p_sat = canopyi.ps.p_sat;
        temperature_effects!(hs);
        tree_ec       = critical_flow(hs, canopyi.ec * canopyi.LA);
        canopyi.ec    = tree_ec / canopyi.LA;
        canopyi.T_old = canopyi.T;
        canopyi.p_old = canopyi.p_ups;
    # if only p_ups changes, update ec and p_old
    elseif p_ups != p_old
        tree_ec       = critical_flow(hs, canopyi.ec * canopyi.LA);
        canopyi.ec    = tree_ec / canopyi.LA;
        canopyi.p_old = canopyi.p_ups;
    end

    return nothing
end

###############################################################################
#
# Update leaf maximal A and K particularly for optimization models
#
###############################################################################
"""
    update_leaf_AK!(
            photo_set::AbstractPhotoModelParaSet{FT},
            canopyi::CanopyLayer{FT},
            hs::LeafHydraulics{FT},
            envir::AirLayer{FT}
    ) where {FT<:AbstractFloat}

Update leaf maximal A and K for Sperry model, given
- `photo_set` [`C3ParaSet`] or [`C4ParaSet`] type parameter set
- `canopyi` [`CanopyLayer`](@ref) type struct
- `envir` [`AirLayer`] type struct
"""
function update_leaf_AK!(
            photo_set::AbstractPhotoModelParaSet{FT},
            canopyi::CanopyLayer{FT},
            hs::LeafHydraulics{FT},
            envir::AirLayer{FT}
) where {FT<:AbstractFloat}
    # unpack required variables
    @unpack APAR, ec, g_bc, g_bw, g_m, g_max, g_min, p_sat = canopyi;
    @unpack p_atm, p_H₂O = envir;

    # calculate the physiological maximal g_sw
    _g_crit = ec / (p_sat - p_H₂O) * p_atm;
    for i in eachindex(APAR)
        _g_sw = 1 / max(1/_g_crit - 1/g_bw[i], FT(1e-3));
        _g_sw = min(_g_sw, g_max);
        _g_sw = max(_g_sw, g_min);
        _g_lc = 1 / (1/g_bc[i] + FT(1.6)/_g_sw + 1/g_m[i]);
        canopyi.ps.APAR = APAR[i];
        leaf_photosynthesis!(photo_set, canopyi.ps, envir, GCO₂Mode(), _g_lc);

        # update the a_max for each leaf
        canopyi.a_max[i] = canopyi.ps.An;
    end

    # update the kr_max
    canopyi.kr_max  = hs.k_history[end];

    return nothing
end

max_forks_repo_name: climate-machine/Land


text:
@testset "ui and its derivative" begin

    um1 = ui(-1, Float64[], Float64[], Float64[])
    x = randn()
    @test um1(x)==0.0

    @test D(um1)(x)==0.0

    a0 = randn()
    u0 = ui(0, Float64[], Float64[], [a0])
    @test norm(u0(x) - a0*x)<1e-10

    @test norm(D(u0)(x) - ForwardDiff.derivative(u0, x))<1e-10

    @test ui(0, Float64[], Float64[], [1.0])(x)==x

    u1 = ui(1, [-2.0], [1.0] , [3.0,2.0])
    @test abs(u1(x) - (3.0*x + 2.0*rbf(-2.0,1.0)(x)))<1e-10

    u4 = ui(2, zeros(2), ones(2), [1.0,0.0,0.0])
    @test u4.p == 2

    @test u4(2.0) ==2.0

    u4.coeffi[1] = 0.0
    u4.coeffi[2] = 1.0

    @test u4.coeffi == [0.0, 1.0, 0.0]

    @test u4(2.0) == rbf(0.0,1.0)(2.0)

    u4.coeffi[1] = 2.0
    u4.coeffi[3] = 2.0
    u4.ξi[2] = 2.0
    u4.σi[2] = 5.0

    @test abs(u4(x)- (Lin(x)*2 + rbf(0.0, 1.0)(x) +
                2.0*rbf(2.0, 5.0)(x))) <1e-10

    @test abs(D(u4)(x) - ForwardDiff.derivative(u4, x))<1e-10

    u5 = ui(4, randn(4), rand(4), randn(5))

    @test abs(D(u5)(x) - ForwardDiff.derivative(u5, x))<1e-10
end

@testset "uk and its derivative (first and second)" begin
    um1 = uk(-1, Float64[], Float64[],Float64[])
    x = randn()
    @test um1(x) == x
    @test D!(um1, x)==1.0
    @test D(um1)(x)==1.0
    @test H!(um1, x)==0.0
    @test H(um1)(x)==0.0

    @test uk(0, Float64[], Float64[],[5.0;2.0])(x)== 5.0 + 2.0*x

    a = randn(2)
    u0 = uk(0, Float64[], Float64[],a)
    @test norm(D!(u0, x) - ForwardDiff.derivative(u0,x))<1e-10

    u4 = uk(2)

    @test u4.p == 2

    @test u4(x) == 0.0
    #

    u4.coeffk[1] = 3.0

    @test u4.coeffk == [3.0, 0.0, 0.0, 0.0, 0.0]

    @test u4(x) == 3.0

    u4.coeffk[1] = 0.0
    u4.coeffk[2] = 2.0

    @test u4(x) == 2.0ψ₀(0.0,1.0)(x)

    u4.coeffk .= ones(5)

    @test abs(u4(x) -( 1.0 + ψ₀(0.0,1.0)(x) + 2.0*ψj(0.0,1.0)(x) +
                        ψpp1(0.0,1.0)(x))) <1e-10

    u4.coeffk[1] = 6.0
    u4.σk .= [1.0,2.0,3.0,4.0]

    @test abs(u4(x) -( 6.0 + ψ₀(0.0,1.0)(x) + ψj(0.0,2.0)(x) + ψj(0.0,3.0)(x) +
                        ψpp1(0.0,4.0)(x))) <1e-10
    @test norm(D!(u4, x) - ForwardDiff.derivative(u4, x))<1e-10

    u5 = uk(5, randn(7), rand(7), randn(8))

    @test norm(D(u5)(x) - ForwardDiff.derivative(u5, x))<1e-10

    @test norm(H!(u5, x) - ForwardDiff.derivative(D(u5), x))<1e-10
    @test norm(H(u5)(x) - ForwardDiff.derivative(D(u5), x))<1e-10

end


text:
using FileIO
using FCSFiles
using Gadfly

flowrun = load(raw"C:\Users\ljame\Documents\GitHub\FCS-with-Julia\FCS_data\BD-FACS-Aria-II.fcs")

p = plot(x=flowrun["FSC-A"], y=flowrun["SSC-A"], Geom.histogram2d,
Guide.xlabel("FSC-A"), Guide.ylabel("SSC-A"), Coord.cartesian(xmin=0, ymin=0))

#import Cairo, Fontconfig
#draw(PNG("BD-FACS-Aria-II-Graph.png", 10cm, 7cm, dpi=300), p)

max_stars_repo_name: ljamesherald/FCS-with-Julia

max_issues_repo_name: ljamesherald/FCS-with-Julia

max_forks_repo_name: ljamesherald/FCS-with-Julia