text:
using ClimateMachine
ClimateMachine.init(;
    parse_clargs = true,
    output_dir = get(ENV, "CLIMATEMACHINE_SETTINGS_OUTPUT_DIR", "output"),
    fix_rng_seed = true,
)
using ClimateMachine.SingleStackUtils
using ClimateMachine.Checkpoint
using ClimateMachine.BalanceLaws: vars_state
const clima_dir = dirname(dirname(pathof(ClimateMachine)));

include(joinpath(clima_dir, "experiments", "AtmosLES", "stable_bl_model.jl"))
include("edmf_model.jl")
include("edmf_kernels.jl")

"""
    init_state_prognostic!(
            turbconv::EDMF{FT},
            m::AtmosModel{FT},
            state::Vars,
            aux::Vars,
            localgeo,
            t::Real,
        ) where {FT}

Initialize EDMF state variables.
This method is only called at `t=0`.
"""
function init_state_prognostic!(
    turbconv::EDMF{FT},
    m::AtmosModel{FT},
    state::Vars,
    aux::Vars,
    localgeo,
    t::Real,
) where {FT}
    # Aliases:
    gm = state
    en = state.turbconv.environment
    up = state.turbconv.updraft
    N_up = n_updrafts(turbconv)
    # GCM setting - Initialize the grid mean profiles of prognostic variables (ρ,e_int,q_tot,u,v,w)
    z = altitude(m, aux)

    # SCM setting - need to have separate cases coded and called from a folder - see what LES does
    # a thermo state is used here to convert the input θ to e_int profile
    e_int = internal_energy(m, state, aux)

    ts = PhaseDry(m.param_set, e_int, state.ρ)
    T = air_temperature(ts)
    p = air_pressure(ts)
    q = PhasePartition(ts)
    θ_liq = liquid_ice_pottemp(ts)

    a_min = turbconv.subdomains.a_min
    @unroll_map(N_up) do i
        up[i].ρa = gm.ρ * a_min
        up[i].ρaw = gm.ρu[3] * a_min
        up[i].ρaθ_liq = gm.ρ * a_min * θ_liq
        up[i].ρaq_tot = FT(0)
    end

    # initialize environment covariance with zero for now
    if z <= FT(250)
        en.ρatke =
            gm.ρ *
            FT(0.4) *
            FT(1 - z / 250.0) *
            FT(1 - z / 250.0) *
            FT(1 - z / 250.0)
        en.ρaθ_liq_cv =
            gm.ρ *
            FT(0.4) *
            FT(1 - z / 250.0) *
            FT(1 - z / 250.0) *
            FT(1 - z / 250.0)
    else
        en.ρatke = FT(0)
        en.ρaθ_liq_cv = FT(0)
    end
    en.ρaq_tot_cv = FT(0)
    en.ρaθ_liq_q_tot_cv = FT(0)
    return nothing
end;

function main(::Type{FT}) where {FT}
    # add a command line argument to specify the kind of surface flux
    # TODO: this will move to the future namelist functionality
    sbl_args = ArgParseSettings(autofix_names = true)
    add_arg_group!(sbl_args, "StableBoundaryLayer")
    @add_arg_table! sbl_args begin
        "--surface-flux"
        help = "specify surface flux for energy and moisture"
        metavar = "prescribed|bulk"
        arg_type = String
        default = "bulk"
    end

    cl_args = ClimateMachine.init(parse_clargs = true, custom_clargs = sbl_args)

    surface_flux = cl_args["surface_flux"]

    # DG polynomial order
    N = 1
    nelem_vert = 50

    # Prescribe domain parameters
    zmax = FT(400)

    t0 = FT(0)

    # Simulation time
    timeend = FT(60)
    CFLmax = FT(0.50)

    config_type = SingleStackConfigType

    ode_solver_type = ClimateMachine.ExplicitSolverType(
        solver_method = LSRK144NiegemannDiehlBusch,
    )

    N_updrafts = 1
    N_quad = 3 # Using N_quad = 1 leads to norm(Q) = NaN at init.
    turbconv = EDMF(FT, N_updrafts, N_quad)

    model = stable_bl_model(
        FT,
        config_type,
        zmax,
        surface_flux;
        turbconv = turbconv,
    )

    # Assemble configuration
    driver_config = ClimateMachine.SingleStackConfiguration(
        "SBL_EDMF",
        N,
        nelem_vert,
        zmax,
        param_set,
        model;
        hmax = FT(40),
        solver_type = ode_solver_type,
    )

    solver_config = ClimateMachine.SolverConfiguration(
        t0,
        timeend,
        driver_config,
        init_on_cpu = true,
        Courant_number = CFLmax,
    )

    # --- Zero-out horizontal variations:
    vsp = vars_state(model, Prognostic(), FT)
    horizontally_average!(
        driver_config.grid,
        solver_config.Q,
        varsindex(vsp, :turbconv),
    )
    horizontally_average!(
        driver_config.grid,
        solver_config.Q,
        varsindex(vsp, :ρe),
    )
    vsa = vars_state(model, Auxiliary(), FT)
    horizontally_average!(
        driver_config.grid,
        solver_config.dg.state_auxiliary,
        varsindex(vsa, :turbconv),
    )
    # ---

    dgn_config = config_diagnostics(driver_config)

    cbtmarfilter = GenericCallbacks.EveryXSimulationSteps(1) do
        Filters.apply!(
            solver_config.Q,
            (turbconv_filters(turbconv)...,),
            solver_config.dg.grid,
            TMARFilter(),
        )
        nothing
    end

    # State variable
    Q = solver_config.Q
    # Volume geometry information
    vgeo = driver_config.grid.vgeo
    M = vgeo[:, Grids._M, :]
    # Unpack prognostic vars
    ρ₀ = Q.ρ
    ρe₀ = Q.ρe
    # DG variable sums
    Σρ₀ = sum(ρ₀ .* M)
    Σρe₀ = sum(ρe₀ .* M)

    grid = driver_config.grid

    # state_types = (Prognostic(), Auxiliary(), GradientFlux())
    state_types = (Prognostic(), Auxiliary())
    dons_arr = [dict_of_nodal_states(solver_config, state_types; interp = true)]
    time_data = FT[0]

    # Define the number of outputs from `t0` to `timeend`
    n_outputs = 5
    # This equates to exports every ceil(Int, timeend/n_outputs) time-step:
    every_x_simulation_time = ceil(Int, timeend / n_outputs)

    cb_data_vs_time =
        GenericCallbacks.EveryXSimulationTime(every_x_simulation_time) do
            push!(
                dons_arr,
                dict_of_nodal_states(solver_config, state_types; interp = true),
            )
            push!(time_data, gettime(solver_config.solver))
            nothing
        end

    cb_check_cons = GenericCallbacks.EveryXSimulationSteps(3000) do
        Q = solver_config.Q
        δρ = (sum(Q.ρ .* M) - Σρ₀) / Σρ₀
        δρe = (sum(Q.ρe .* M) .- Σρe₀) ./ Σρe₀
        @show (abs(δρ))
        @show (abs(δρe))
        @test (abs(δρ) <= 0.001)
        @test (abs(δρe) <= 0.1)
        nothing
    end

    cb_print_step = GenericCallbacks.EveryXSimulationSteps(100) do
        @show getsteps(solver_config.solver)
        nothing
    end

    result = ClimateMachine.invoke!(
        solver_config;
        diagnostics_config = dgn_config,
        user_callbacks = (
            cbtmarfilter,
            cb_check_cons,
            cb_data_vs_time,
            cb_print_step,
        ),
        check_euclidean_distance = true,
    )

    dons = dict_of_nodal_states(solver_config, state_types; interp = true)
    push!(dons_arr, dons)
    push!(time_data, gettime(solver_config.solver))

    return solver_config, dons_arr, time_data, state_types
end

solver_config, dons_arr, time_data, state_types = main(Float64)

## Uncomment lines to save output using JLD2
#
# output_dir = @__DIR__;
# mkpath(output_dir);

# z = get_z(solver_config.dg.grid; rm_dupes = true);
# save(
#     string(output_dir, "/sbl_edmf.jld2"),
#     "dons_arr",
#     dons_arr,
#     "time_data",
#     time_data,
#     "z",
#     z,
# )

max_stars_repo_name: jm-c/CLIMA

max_issues_repo_name: jm-c/CLIMA

max_forks_repo_name: jm-c/CLIMA


text:
### A Pluto.jl notebook ###
# v0.18.0

using Markdown
using InteractiveUtils

# ╔═╡ 207e1a73-7cb3-4030-9db8-fd100d681759
begin

	# import some packages -
	using PlutoUI
	using PrettyTables
	using Optim
	using Plots
	using LinearAlgebra

	# setup paths -
	const _PATH_TO_NOTEBOOK = pwd()
	const _PATH_TO_DATA = joinpath(_PATH_TO_NOTEBOOK,"data")
	const _PATH_TO_FIGS = joinpath(_PATH_TO_NOTEBOOK,"figs")
	const _PATH_TO_SRC = joinpath(_PATH_TO_NOTEBOOK,"src")

	# return -
	nothing
end

# ╔═╡ a0aca432-86ce-11ec-3668-679d09123b86
md"""
### Minimum Energy Metabolic Flux Distributions

In this lecture, we will:

1. Introduce Gibbs energy minimization and partial molar Gibbs energy for multiple coupled reactions
2. Compute the reversibility of multiple coupled enzyme-catalyzed reactions

Discussion problem:
* Compute the `low-energy` metabolic flux distribution through a metabolic network
"""

# ╔═╡ 552ffec5-d763-467f-a29d-eadf1bad6437
md"""
### Direct Gibbs Energy Minimization of Multiple Chemical Reactions in Central Carbon Metabolism
Calculate the equilibrium extent of reaction and the equilibrium concentrations for the first five steps of glycolysis occurring in an  _E. coli_ MG-1655 cell-free extract using Direct Gibbs Energy Minimization (DGEM).
The pathway in this example is [here](https://www.genome.jp/kegg-bin/show_pathway?eco00010).

__Assumptions__
* The cell-free extract has a constant V = 30.0μL
* The cell-free extract acts like an _ideal_ liquid solution
* The cell-free reaction is at a constant T, P
* The _default_ metabolic settings used by [eQuilibrator](https://equilibrator.weizmann.ac.il) are valid for this system
"""

# ╔═╡ 767ac9c4-3452-4f85-8de2-5b49001abc92
md"""
##### Theory

The problem asks us to use the Direct Gibbs Energy Minimization (DGEM) approach. For multiple reactions, the Gibbs expression:

$$\hat{G} = \sum_{i=1}^{\mathcal{M}}\bar{G}_{i}n_{i}$$

becomes:

$$\frac{\left(\hat{G}-\sum_{i=1}^{\mathcal{M}}n_{i}^{\circ}G_{i}^{\circ}\right)}{RT} = \sum_{j=1}^{\mathcal{R}}\epsilon_{j}\left(\frac{\Delta{G}_{j}^{\circ}}{RT}\right) + \sum_{i=1}^{\mathcal{M}}n_{i}\ln\hat{a}_{i}$$

where the number of mol for species _i_ is given by:

$$n_{i} = n_{i}^{\circ} + \sum_{r=1}^{\mathcal{R}}\sigma_{ir}\epsilon_{r}\qquad{i=1,2,\dots,\mathcal{M}}$$

The quantity $\Delta{G}^{\circ}_{j}$ denotes the Gibbs energy of reaction for reaction _j_ (units: kJ/mmol), and $\hat{a}_{i}$ denotes the ratio of fugacity for component _i_, which (after the assumption of an ideal solution) becomes: $$\ln\hat{a}_{i} = x_{i}$$ where $x_{i}$ denotes the mol fraction of component _i_.

To estimate the equilibrium extent _vector_ we minimize Gibbs energy expression, subject to constraints. Our decision variables (what we are looking for) are the extents of reaction $\epsilon_{i},i=1,\dots,\mathcal{R}$ subject to bounds on each extent $\epsilon_{i}\in\left[0,\star\right],\forall{i}$ and $n_{i}\geq{0},\forall{i}$.

We implement $\epsilon_{i}\in\left[0,\star\right]$ as a box constraint, and $n_{i}\geq{0}$ using a [Penalty Method](https://en.wikipedia.org/wiki/Penalty_method).

"""

# ╔═╡ 384f1569-b77e-4b7c-b559-01bc70b0ed89
md"""
##### Implementation
"""

# ╔═╡ e391a136-dbc2-4b56-b758-a1449db46693
T = 37.0 + 273.15; # units: K

# ╔═╡ 02d20bb5-d7d6-4435-9091-be6b65b10d5c
V = 30*(1/1e6); # units: L

# ╔═╡ 04bc136e-44d6-4ebf-81c4-8ab6f7a404d5
begin

	# setup problem parameters -
	parameters_dict = Dict{String,Any}()

	# conversion factor -
	ΔG_sf = 1e9; # convert to mol to *mol

	# what are my system dimensions?
	ℳ = 8 # number of metabolites
	ℛ = 5 # number of reactions

	# ΔG_formation data -
	G_formation_array = zeros(ℳ)
	G_formation_array[1] = -409.4 		# 1 gluc kJ/mol
	G_formation_array[2] = -1304.7 		# 2 gluc-6-p kJ/mol
	G_formation_array[3] = -2280.7 		# 3 atp kJ/mol
	G_formation_array[4] = -1405.9 		# 4 adp kJ/mol
	G_formation_array[5] = -1302.1 		# 5 fruc-6-p kJ/mol
	G_formation_array[6] = -2193.6 		# 6 fruc-1,6-bis-p kJ/mol
	G_formation_array[7] = -1097.2 		# 7 dhap kJ/mol
	G_formation_array[8] = -1091.5 		# 8 ga3p kJ/mol
	parameters_dict["G_formation_array"] = (1/ΔG_sf)*G_formation_array # units: kJ/*mol

	# what are my initial condtions?
	n_initial_array = 1.0*ones(ℳ)
	n_initial_array[1] = 35.9*(V)*(1e9/1e3) 		# 1 gluc nmol
	n_initial_array[3] = 2000.0 					# 3 atp nmol
	parameters_dict["n_initial_array"] = n_initial_array

	# setup stoichiometric array -
	S = [

		# ϵ₁ ϵ₂  ϵ₃  ϵ₄  ϵ₅
		-1.0 0.0 0.0 0.0 0.0 	; # 1 gluc
		1.0 -1.0 0.0 0.0 0.0 	; # 2 gluc-6-p
		-1.0 0.0 -1.0 0.0 0.0 	; # 3 atp
		1.0 0.0 1.0 0.0 0.0 	; # 4 adp
		0.0 1.0 -1.0 0.0 0.0 	; # 5 fruc-6-p
		0.0 0.0 1.0 -1.0 0.0 	; # 6 fruc-1,6-bis-p
		0.0 0.0 0.0 1.0 1.0		; # 7 dhap
		0.0 0.0 0.0 1.0 -1.0	; # 8 ga3p
	];
	parameters_dict["S"] = S

	# show -
	nothing
end

# ╔═╡ 6d422479-9788-42e3-a6fb-acc4fe369e20
R = 8.314*(1/1000)*(1/ΔG_sf); # units: kJ/nmol-K

# ╔═╡ 38a645d9-688e-4794-9c8f-98e8ec5b6516
md"""
### Discussion problem (experimental)

Compute the metabolic flux distribution for upper glycolysis using Direct Gibbs Energy Minimization (DGEM)
for the first five reactions of glycolysis. The reactions operate in an open logical control volume with a single input (s=1) and a single output (s=2). Let the rate of glucose input into the logical control volume be $\dot{n}_{1,1}=1077$ nmol/time and the rate of ATP input $\dot{n}_{3,1} = 2000$ nmol/time. All other components
enter the logical control volume at 1.0 nmol/time. All components can exit the logical control volume.

__Compute__
* The open extent of reaction $\dot{\epsilon}_{i}~\forall{i}$ using a DGEM approach for an _unbounded_ exit stream and unbounded extent ($\dot{\epsilon}_{i}\geq{0}~\forall{i}$).
* The open extent of reaction $\dot{\epsilon}_{i}~\forall{i}$ using a DGEM approach for a _bounded_ exit stream and unbounded extent ($\dot{\epsilon}_{i}\geq{0}~\forall{i}$). In particular, let's simulate the logical exit condition for DHAP $\dot{n_{7,2}}\leq{10}$.

__Assumptions__
* The cell-free extract has a constant V = 30.0μL
* The cell-free extract acts like an _ideal_ liquid solution
* The cell-free reaction is at a constant T, P
* The cell-free extract is well mixed
* The _default_ metabolic settings used by [eQuilibrator](https://equilibrator.weizmann.ac.il) are valid for this system
"""

# ╔═╡ 77c6925b-6588-4702-8d1d-5de05316d722
md"""
##### Theory
The problem asks us to use the Direct Gibbs Energy Minimization (DGEM) approach to estimate metabolic flux in an `open system`. For multiple reactions in an `open problem`, the Gibbs expression is now given by:

$$\dot{G} = \sum_{i=1}^{\mathcal{M}}\bar{G}_{i}\dot{n}_{i,s^{\star}}$$

where $\dot{n}_{i}$ denotes the $\star$mol flow rate into/from the logical control volume (units: $\star$mol/time),
$\bar{G}_{i}$ denotes the partial molar Gibbs energy for component $i$ (units: energy/$\star$mol), and
$\dot{G}$ denotes the Gibbs energy in the logical control volume (units: energy/time).
The `open` mol balance around species $i$ inside the _logical_ control volume (assuming a single input s=1 and output steam s=2):

$$\dot{n}_{i,2} = \dot{n}_{i,1} + \sum_{j=1}^{\mathcal{R}}\sigma_{ij}\dot{\epsilon}_{j}\qquad{i=1,2,\dots,\mathcal{M}}$$

These balances can be used as constraints to find the optimal open extent of reaction with the lowest
total Gibbs energy for a particular stream. In particular, the total Gibbs energy for an open system in which we minimize the energy of the __exit stream__ is given by:

$$\dot{G} = \sum_{i=1}^{\mathcal{M}}\bar{G}_{i}\dot{n}_{i,2}$$

where the partial molar Gibbs energy (assuming an ideal solution) is given by:

$$\bar{G}_{i} = G_{i}^{\circ} + RT\ln{x}_{i}\qquad{i=1,2,\dots,\mathcal{M}}$$

and:

$$x_{i}=\frac{\dot{n}_{i}}{\sum_{j=1}^{\mathcal{M}}\dot{n}_{j}}\qquad{i=1,2,\dots,\mathcal{M}}$$

To estimate the open extent _vector_ we minimize the open Gibbs energy expression, subject to constraints. Our decision variables (what we are looking for) are the open extents of reaction $\dot{\epsilon}_{i},i=1,\dots,\mathcal{R}$. In this case the constraints are bounds on each extent $\dot{\epsilon}_{i}\in\left[0,\star\right],\forall{i}$ and $n_{i,\star}\geq{0},\forall{i}$.

"""

# ╔═╡ 68be4ebd-54b5-4f86-b467-1e06c681aaa2
md"""
##### Implementation
"""

# ╔═╡ c7c4218a-4c6f-48f4-9cca-76a2db9cd1d9
begin

	# problem setup -
	open_parameters_dict = Dict{String,Any}()
	open_parameters_dict["G_formation_array"] = parameters_dict["G_formation_array"];

	# setup the reaction to pull ga3p -
	Sₒ = [

		# ϵ₁ ϵ₂  ϵ₃  ϵ₄  ϵ₅
		-1.0 0.0 0.0 0.0 0.0 	; # 1 gluc
		1.0 -1.0 0.0 0.0 0.0 	; # 2 gluc-6-p
		-1.0 0.0 -1.0 0.0 0.0 	; # 3 atp
		1.0 0.0 1.0 0.0 0.0		; # 4 adp
		0.0 1.0 -1.0 0.0 0.0 	; # 5 fruc-6-p
		0.0 0.0 1.0 -1.0 0.0 	; # 6 fruc-1,6-bis-p
		0.0 0.0 0.0 1.0 1.0 	; # 7 dhap
		0.0 0.0 0.0 1.0 -1.0	; # 8 ga3p
	];
	open_parameters_dict["S"] = Sₒ
	(ℳₒ,ℛₒ) = size(Sₒ)

	# what are my initial condtions?
	n_dot_in_array = 0.01*ones(ℳₒ)
	n_dot_in_array[1] = 1077.0 					# 1 gluc nmol/time
	n_dot_in_array[3] = 2000.0 					# 3 atp nmol/time
	open_parameters_dict["n_dot_in_array"] = n_dot_in_array

	# what are the outflow terms -
	n_dot_out_upper_bound_array = 100000.0*ones(ℳₒ)

	# uncomment me to impose upper bound for DHAP -
	#n_dot_out_upper_bound_array[7] = 5.0
	open_parameters_dict["n_dot_out_upper_bound_array"] = n_dot_out_upper_bound_array

	# show -
	nothing
end

# ╔═╡ b4ed3db1-fa2a-4b3a-a44a-7366345979b2
md"""
### Summary and Conclusions

In this lecture we:

1. Introduced Gibbs energy minimization and partial molar Gibbs energy
2. Computed the reversibility of multiple coupled enzyme-catalyzed reactions
3. Used the Direct Gibbs Energy Minimization (DGEM) approach to estimate metabolic flux in an `open logical system`

"""

# ╔═╡ d4ce7976-85f2-47e0-8845-64c0b6d9249a
md"""
### Next time:

We'll discuss enzyme kinetics and the origin of the bounds conditions. In particular, we'll look at:

* The assumptions that underly [Michaelis-Menten kinetics](https://en.wikipedia.org/wiki/Michaelis–Menten_kinetics) (and the derivation)
* The [MWC](https://en.wikipedia.org/wiki/Monod-Wyman-Changeux_model) and [Sequential](https://en.wikipedia.org/wiki/Sequential_model) models for allosteric enzyme kinetics
* Developing our approach to modeling enzyme kinetics (it's going to be crazy awesome!)
"""

# ╔═╡ 72dddb17-3e97-4214-ae44-28e908febbba
md"""
### Julia function library
"""

# ╔═╡ b71d2bc5-0393-4ec8-97a6-bbfddae00b06
function objective_function_open(ϵ, parameters)

	# get data from the parameters -
	G_formation_array = parameters["G_formation_array"]
	S = parameters["S"]
	n_dot_in = parameters["n_dot_in_array"]
	UB_ndot_out = parameters["n_dot_out_upper_bound_array"]
	RT = R*T

	# compute the n_dot_out and mol fraction -
	tmp = n_dot_in + S*ϵ
	n_dot_out = max.(0.0, tmp) # hack: if we have a mol count less than 0, correct -
	n_total = sum(n_dot_out)
	x_array = (1/n_total)*n_dot_out
	activity_terms = log.(x_array)

	# compute the partial molar Gibbs energy --
	G_bar = G_formation_array .+ RT*(activity_terms)

	# compute the objective value -
	𝒪 = sum(n_dot_out.*G_bar)

	# setup non-negative penalty term array -
	penalty_terms_array_1 = Array{Float64,1}()
	for species_index ∈ 1:ℳ

		penalty_term = max(0,-1*tmp[species_index])^2
		push!(penalty_terms_array_1, penalty_term)
	end
	𝒫₁ = sum(penalty_terms_array_1);

	# setup penality term array -
	penalty_terms_array_2 = Array{Float64,1}()
	for species_index = 1:ℳ

		# compute the tmp term -
		tmp_term = (n_dot_out[species_index] - UB_ndot_out[species_index])
		penalty_term = max(0,tmp_term)^2
		push!(penalty_terms_array_2, penalty_term)
	end
	𝒫₂ = sum(penalty_terms_array_2);

	# return -
	return 𝒪 + 10*(𝒫₁ + 𝒫₂)
end

# ╔═╡ 7b1df4fa-51eb-4558-b808-f4a8e7433af8
begin

	# setup bounds -
	Lₒ = zeros(ℛₒ)

	# uncomment me:
	Uₒ = 1000000.0*ones(ℛₒ)

	# set the initial extent -
	ϵₒ = 0.1*ones(ℛₒ)

	# setup the objective function -
	OF_open(p) = objective_function_open(p, open_parameters_dict)

    # uncomment me: call the optimizer -
    opt_result_open = optimize(OF_open, Lₒ, Uₒ, ϵₒ, Fminbox(BFGS()))
end

# ╔═╡ 2625b050-e961-483f-8e67-1748a981d2e8
with_terminal() do

	ϵ = Optim.minimizer(opt_result_open)
	reaction_string_array = [
		"glc + atp = g6p + adp" 	;
		"g6p = f6p" 				;
		"f6p + atp = f16bp + adp" 	;
		"f16bp = dhap + ga3p" 		;
		"ga3p = dhap" 				;
	]

	# make the data table array -
	data_table_array = Array{Any,2}(undef,ℛₒ,3)
	for reaction_index = 1:ℛₒ
		data_table_array[reaction_index,1] = reaction_string_array[reaction_index]
		data_table_array[reaction_index,2] = ϵ[reaction_index]
		data_table_array[reaction_index,3] = ϵ[reaction_index]*(1/V)*(1e3/1e9)
	end

	# setup pretty table -
	# header row -
	path_table_header_row = (["Reaction","ϵdot","flux"],["","nmol/time", "mM/time"]);

	# write the table -
	pretty_table(data_table_array; header=path_table_header_row)
end

# ╔═╡ ac441583-be2d-4d58-8bce-885d2c1e6529
with_terminal() do

	ϵ = Optim.minimizer(opt_result_open)
	S = open_parameters_dict["S"]
	n_initial_array = open_parameters_dict["n_dot_in_array"]
	n = n_initial_array + S*ϵ

	# setp table_data_array -
	table_data_array = Array{Any,2}(undef,ℳ,4)
	species_array = ["glucose","g6p","atp","adp","f6p","f16bp","dhap","ga3p"]
	for species_index = 1:ℳ
		table_data_array[species_index,1] = species_array[species_index]
		table_data_array[species_index,2] = n_initial_array[species_index]
		table_data_array[species_index,3] = n[species_index]
		table_data_array[species_index,4] = n[species_index] - n_initial_array[species_index]
	end

	# setup pretty table -
	# header row -
	path_table_header_row = (["Species","n_dot_in","n_dot_out","dnᵢ/dt"],["","nmol/time","nmol/time","nmol/time"]);

	# write the table -
	pretty_table(table_data_array; header=path_table_header_row)
end

# ╔═╡ 4e93ffc7-a323-4349-9022-899ee7274e9d
function objective_function_closed(ϵ,parameters)

	# get data from the parameters -
	G_formation_array = parameters["G_formation_array"]
	S = parameters["S"]
	n_initial_array = parameters["n_initial_array"]
	RT = R*T

	# compute the ΔG/RT terms -
	ΔG_terms = (1/RT)*transpose(S)*G_formation_array
	term_1 = sum(ΔG_terms.*ϵ)

	# compute mols -
	tmp = n_initial_array + S*ϵ
	n_array = max.(0.0,tmp) # hack: if we have a mol count less than 0, correct -
	n_total = sum(n_array)
	x_array = (1/n_total)*n_array
	activity_terms = log.(x_array)
	term_2 = sum(n_array.*activity_terms)

	# setup non-negative penalty term array -
	penalty_terms_array_1 = Array{Float64,1}()
	for species_index ∈ 1:ℳ

		penalty_term = max(0,-1*tmp[species_index])^2
		push!(penalty_terms_array_1, penalty_term)
	end
	𝒫₁ = sum(penalty_terms_array_1);

	# return -
	return (term_1 + term_2) + 10*𝒫₁
end

# ╔═╡ 2777bfbf-122a-4344-a15c-30ac7dd3fcfb
begin

	# setup bounds -
	L = zeros(ℛ)
	U = maximum(n_initial_array)*ones(ℛ)

	# set the initial -
	xinitial = 0.001*ones(ℛ)
	xinitial[1] = 0.5*maximum(U)

	# setup the objective function -
	OF_closed(p) = objective_function_closed(p, parameters_dict)

    # call the optimizer -
    opt_result_closed = optimize(OF_closed, L, U, xinitial, Fminbox(BFGS()))
end

# ╔═╡ d1178ff2-ef25-4f0f-9f58-e69bb8908f9a
with_terminal() do

	ϵ = Optim.minimizer(opt_result_closed)
	reaction_string_array = [
		"glc + atp = g6p + adp" 	;
		"g6p = f6p" 				;
		"f6p + atp = f16bp + adp" 	;
		"f16bp = dhap + ga3p" 		;
		"ga3p = dhap" 				;
	]

	# compute the dG_reaction -
	G_formation_array = parameters_dict["G_formation_array"]
	ΔG_rxn = transpose(S)*G_formation_array

	# compute the equlibrium constant -
	n_final = n_initial_array + S*ϵ

	# compute the final mol fraction -
	ln_x_final = log.((1/sum(n_final)).*n_final)

	# make the data table array -
	data_table_array = Array{Any,2}(undef,ℛ,7)
	for reaction_index = 1:ℛ
		data_table_array[reaction_index,1] = reaction_string_array[reaction_index]
		data_table_array[reaction_index,2] = ΔG_rxn[reaction_index]*(ΔG_sf)
		data_table_array[reaction_index,3] = ϵ[reaction_index]
		data_table_array[reaction_index,4] = ϵ[reaction_index]*(1/n_initial_array[1])

		# compute the Keq -
		tmp = dot(S[:,reaction_index],ln_x_final)
		K_eq = exp(tmp)

		data_table_array[reaction_index,5] = K_eq
		data_table_array[reaction_index,6] = exp(-ΔG_rxn[reaction_index]/(R*T))
		data_table_array[reaction_index,7] = sign(ΔG_rxn[reaction_index]/(R*T)) == 1 ? true : false
	end

	# setup pretty table -
	# header row -
	path_table_header_row = (["Reaction","ΔG_rxn","ϵ", "ϵ-scaled", "Keq (ϵ)", "Keq (ΔG)","reversible"],["","kJ/mol-K","nmol", "AU","","", "Bool"]);

	# write the table -
	pretty_table(data_table_array; header=path_table_header_row)
end

# ╔═╡ 02f2c64c-9e93-4d79-966d-e7de429317d8
with_terminal() do

	ϵ = Optim.minimizer(opt_result_closed)
	S = parameters_dict["S"]
	n_initial_array = parameters_dict["n_initial_array"]
	n = n_initial_array + S*ϵ

	# setp table_data_array -
	table_data_array = Array{Any,2}(undef,ℳ,5)
	species_array = ["glucose","g6p","atp","adp","f6p","f16bp","dhap","ga3p"]
	for species_index = 1:ℳ
		table_data_array[species_index,1] = species_array[species_index]
		table_data_array[species_index,2] = n_initial_array[species_index]
		table_data_array[species_index,3] = n[species_index]
		table_data_array[species_index,4] = (1/V)*n_initial_array[species_index]*(1e3)*(1/ΔG_sf) # converts to mM
		table_data_array[species_index,5] = (1/V)*n[species_index]*(1e3)*(1/ΔG_sf) # converts to mM
	end

	# setup pretty table -
	# header row -
	path_table_header_row = (["Species","n_i","n_f", "C_i", "C_f"],["","nmol","nmol", "mM", "mM"]);

	# write the table -
	pretty_table(table_data_array; header=path_table_header_row)
end

# ╔═╡ d7b59095-9c08-4a5e-b89d-c83063acd86b
TableOfContents(title="📚 Table of Contents", indent=true, depth=5, aside=true)

# ╔═╡ d64d393d-8e8e-4742-a501-958f3b385864
html"""
<style>
main {
    max-width: 960px;
    width: 75%;
    margin: auto;
    font-family: "Roboto, monospace";
}

a {
    color: blue;
    text-decoration: none;
}
</style>"""

# ╔═╡ 24c51418-c13e-4f8a-939a-7c15ff7d01db
html"""
<script>
	// initialize -
	var section = 0;
	var subsection = 0;
	var subsubsection = 0;
	var headers = document.querySelectorAll('h3, h5, h6');

	// main loop -
	for (var i=0; i < headers.length; i++) {

		var header = headers[i];
	    var text = header.innerText;
	    var original = header.getAttribute("text-original");
	    if (original === null) {

			// Save original header text
	        header.setAttribute("text-original", text);
	    } else {

			// Replace with original text before adding section number
	        text = header.getAttribute("text-original");
	    }

	    var numbering = "";
	    switch (header.tagName) {
	        case 'H3':
	            section += 1;
	            numbering = section + ".";
	            subsection = 0;
	            break;
	        case 'H5':
	            subsection += 1;
	            numbering = section + "." + subsection;
	            break;
			case 'H6':
	            subsubsection += 1;
	            numbering = section + "." + subsection + "." + subsubsection;
	            break;
	    }
		// update the header text
		header.innerText = numbering + " " + text;
	};
</script>"""

# ╔═╡ 00000000-0000-0000-0000-000000000001
PLUTO_PROJECT_TOML_CONTENTS = """
[deps]
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Optim = "429524aa-4258-5aef-a3af-852621145aeb"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
PlutoUI = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"

[compat]
Optim = "~1.6.1"
Plots = "~1.25.7"
PlutoUI = "~0.7.34"
PrettyTables = "~1.3.1"
"""

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

julia_version = "1.7.1"
manifest_format = "2.0"

[[deps.AbstractPlutoDingetjes]]
deps = ["Pkg"]
git-tree-sha1 = "8eaf9f1b4921132a4cff3f36a1d9ba923b14a481"
uuid = "6e696c72-6542-2067-7265-42206c756150"
version = "1.1.4"

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

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

[[deps.ArrayInterface]]
deps = ["Compat", "IfElse", "LinearAlgebra", "Requires", "SparseArrays", "Static"]
git-tree-sha1 = "1bdcc02836402d104a46f7843b6e6730b1948264"
uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9"
version = "4.0.2"

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

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

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

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

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

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

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

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

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

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

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

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

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

[[deps.Crayons]]
git-tree-sha1 = "249fe38abf76d48563e2f4556bebd215aa317e15"
uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f"
version = "4.1.1"

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

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

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

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

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

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

[[deps.DiffRules]]
deps = ["IrrationalConstants", "LogExpFunctions", "NaNMath", "Random", "SpecialFunctions"]
git-tree-sha1 = "84083a5136b6abf426174a58325ffd159dd6d94f"
uuid = "b552c78f-8df3-52c6-915a-8e097449b14b"
version = "1.9.1"

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

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

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

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

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

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

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

[[deps.FillArrays]]
deps = ["LinearAlgebra", "Random", "SparseArrays", "Statistics"]
git-tree-sha1 = "8756f9935b7ccc9064c6eef0bff0ad643df733a3"
uuid = "1a297f60-69ca-5386-bcde-b61e274b549b"
version = "0.12.7"

[[deps.FiniteDiff]]
deps = ["ArrayInterface", "LinearAlgebra", "Requires", "SparseArrays", "StaticArrays"]
git-tree-sha1 = "6eae72e9943d8992d14359c32aed5f892bda1569"
uuid = "6a86dc24-6348-571c-b903-95158fe2bd41"
version = "2.10.0"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

[[deps.Hyperscript]]
deps = ["Test"]
git-tree-sha1 = "8d511d5b81240fc8e6802386302675bdf47737b9"
uuid = "47d2ed2b-36de-50cf-bf87-49c2cf4b8b91"
version = "0.0.4"

[[deps.HypertextLiteral]]
git-tree-sha1 = "2b078b5a615c6c0396c77810d92ee8c6f470d238"
uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2"
version = "0.9.3"

[[deps.IOCapture]]
deps = ["Logging", "Random"]
git-tree-sha1 = "f7be53659ab06ddc986428d3a9dcc95f6fa6705a"
uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89"
version = "0.2.2"

[[deps.IfElse]]
git-tree-sha1 = "debdd00ffef04665ccbb3e150747a77560e8fad1"
uuid = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173"
version = "0.1.1"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

[[deps.LineSearches]]
deps = ["LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "Printf"]
git-tree-sha1 = "f27132e551e959b3667d8c93eae90973225032dd"
uuid = "d3d80556-e9d4-5f37-9878-2ab0fcc64255"
version = "7.1.1"

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

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

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

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

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

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

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

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

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

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

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

[[deps.NLSolversBase]]
deps = ["DiffResults", "Distributed", "FiniteDiff", "ForwardDiff"]
git-tree-sha1 = "50310f934e55e5ca3912fb941dec199b49ca9b68"
uuid = "d41bc354-129a-5804-8e4c-c37616107c6c"
version = "7.8.2"

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

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

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

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

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

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

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

[[deps.Optim]]
deps = ["Compat", "FillArrays", "ForwardDiff", "LineSearches", "LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "PositiveFactorizations", "Printf", "SparseArrays", "StatsBase"]
git-tree-sha1 = "045d10789f5daff18deb454d5923c6996017c2f3"
uuid = "429524aa-4258-5aef-a3af-852621145aeb"
version = "1.6.1"

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

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

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

[[deps.Parameters]]
deps = ["OrderedCollections", "UnPack"]
git-tree-sha1 = "34c0e9ad262e5f7fc75b10a9952ca7692cfc5fbe"
uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a"
version = "0.12.3"

[[deps.Parsers]]
deps = ["Dates"]
git-tree-sha1 = "0b5cfbb704034b5b4c1869e36634438a047df065"
uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0"
version = "2.2.1"

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

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

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

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

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

[[deps.PlutoUI]]
deps = ["AbstractPlutoDingetjes", "Base64", "ColorTypes", "Dates", "Hyperscript", "HypertextLiteral", "IOCapture", "InteractiveUtils", "JSON", "Logging", "Markdown", "Random", "Reexport", "UUIDs"]
git-tree-sha1 = "8979e9802b4ac3d58c503a20f2824ad67f9074dd"
uuid = "7f904dfe-b85e-4ff6-b463-dae2292396a8"
version = "0.7.34"

[[deps.PositiveFactorizations]]
deps = ["LinearAlgebra"]
git-tree-sha1 = "17275485f373e6673f7e7f97051f703ed5b15b20"
uuid = "85a6dd25-e78a-55b7-8502-1745935b8125"
version = "0.2.4"

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

[[deps.PrettyTables]]
deps = ["Crayons", "Formatting", "Markdown", "Reexport", "Tables"]
git-tree-sha1 = "dfb54c4e414caa595a1f2ed759b160f5a3ddcba5"
uuid = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
version = "1.3.1"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

[[deps.Static]]
deps = ["IfElse"]
git-tree-sha1 = "d4da8b728580709d736704764e55d6ef38cb7c87"
uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3"
version = "0.5.3"

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

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

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

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

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

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

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

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

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

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

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

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

[[deps.UnPack]]
git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b"
uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
version = "1.0.2"

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

# ╔═╡ Cell order:
# ╟─a0aca432-86ce-11ec-3668-679d09123b86
# ╟─552ffec5-d763-467f-a29d-eadf1bad6437
# ╟─767ac9c4-3452-4f85-8de2-5b49001abc92
# ╟─384f1569-b77e-4b7c-b559-01bc70b0ed89
# ╠═e391a136-dbc2-4b56-b758-a1449db46693
# ╠═02d20bb5-d7d6-4435-9091-be6b65b10d5c
# ╠═6d422479-9788-42e3-a6fb-acc4fe369e20
# ╠═04bc136e-44d6-4ebf-81c4-8ab6f7a404d5
# ╠═2777bfbf-122a-4344-a15c-30ac7dd3fcfb
# ╠═d1178ff2-ef25-4f0f-9f58-e69bb8908f9a
# ╠═02f2c64c-9e93-4d79-966d-e7de429317d8
# ╟─38a645d9-688e-4794-9c8f-98e8ec5b6516
# ╟─77c6925b-6588-4702-8d1d-5de05316d722
# ╟─68be4ebd-54b5-4f86-b467-1e06c681aaa2
# ╠═c7c4218a-4c6f-48f4-9cca-76a2db9cd1d9
# ╠═7b1df4fa-51eb-4558-b808-f4a8e7433af8
# ╠═2625b050-e961-483f-8e67-1748a981d2e8
# ╠═ac441583-be2d-4d58-8bce-885d2c1e6529
# ╟─b4ed3db1-fa2a-4b3a-a44a-7366345979b2
# ╟─d4ce7976-85f2-47e0-8845-64c0b6d9249a
# ╟─72dddb17-3e97-4214-ae44-28e908febbba
# ╠═b71d2bc5-0393-4ec8-97a6-bbfddae00b06
# ╠═4e93ffc7-a323-4349-9022-899ee7274e9d
# ╠═207e1a73-7cb3-4030-9db8-fd100d681759
# ╠═d7b59095-9c08-4a5e-b89d-c83063acd86b
# ╠═d64d393d-8e8e-4742-a501-958f3b385864
# ╠═24c51418-c13e-4f8a-939a-7c15ff7d01db
# ╟─00000000-0000-0000-0000-000000000001
# ╟─00000000-0000-0000-0000-000000000002

ext: jl


text:
using Plexifications
using Base.Test: @test, @test_throws

@test_throws ErrorException begin
    inv(BiNilplex(0, 0.0))
end

@test begin
    !iszerodivisor(BiNilplex(1,2,3,4))
end

@test begin
    iszerodivisor(BiNilplex(0,0,3,4))
end

@test begin
    iszerodivisor(BiNilplex(0,3,0,4))
end

@test begin
    a = Plexifications.randomBigFloat()
    isreal(BiNilplex(a))
end

@test begin
    a = 1
    !isreal(BiNilplex(a, a))
end

@test begin
    z = random(BiNilplex{Int})
    z == +(z)
end

@test begin
    a = Plexifications.randomBigFloat()
    real(BiNilplex(a)) == a
end

@test begin
    io = IOBuffer()
    show(io, BiNilplex(1, 2, 3, 4))
    l = String(take!(io))
    r = "[1: 1, A: 2, B: 3, AB: 4]"
    l == r
end

@test begin
    x = random(BiNilplex{BigFloat})
    y = random(BiNilplex{BigFloat})
    x != y
end

@test begin
    a = Plexifications.randomBigInt()
    z = random(BiNilplex{BigInt})
    l = a + z
    r = z + a
    l == r
end

@test begin
    a = Plexifications.randomBigInt()
    z = random(BiNilplex{BigInt})
    l = a - z
    r = -(z - a)
    l == r
end

@test begin
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    l = x + y
    r = y + x
    l == r
end

@test begin
    x = random(Nlplex{BigInt})
    y = random(BiNilplex{BigInt})
    l = x + y
    r = y + x
    l == r
end

@test begin
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    l = x * y
    r = y * x
    l == r
end

@test begin
    x = random(Nlplex{BigInt})
    y = random(BiNilplex{BigInt})
    l = x * y
    r = y * x
    l == r
end

@test begin
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    l = x - y
    r = -(y - x)
    l == r
end

@test begin
    x = random(Nlplex{BigInt})
    y = random(BiNilplex{BigInt})
    l = x - y
    r = -(y - x)
    l == r
end

@test begin
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    z = random(BiNilplex{BigInt})
    l = (x + y) + z
    r = x + (y + z)
    l == r
end

@test begin
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    z = random(BiNilplex{BigInt})
    l = (x * y) * z
    r = x * (y * z)
    l == r
end

@test begin
    x = random(BiNilplex{BigInt})
    barA(barA(x)) == x
end

@test begin
    x = random(BiNilplex{BigInt})
    barB(barB(x)) == x
end

@test begin
    x = random(BiNilplex{BigInt})
    barB(barA(x)) == barA(barB(x))
end

@test begin
    x = random(BiNilplex{Rational{BigInt}})
    inv(inv(x)) == x
end

@test begin
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    l = barA(x * y)
    r = barA(x) * barA(y)
    l == r
end

@test begin
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    l = barA(x + y)
    r = barA(x) + barA(y)
    l == r
end

@test begin
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    l = barA(x - y)
    r = barA(x) - barA(y)
    l == r
end

@test begin
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    l = barB(x * y)
    r = barB(x) * barB(y)
    l == r
end

@test begin
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    l = barB(x + y)
    r = barB(x) + barB(y)
    l == r
end

@test begin
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    l = barB(x - y)
    r = barB(x) - barB(y)
    l == r
end

@test begin
    x = random(BiNilplex{Rational{BigInt}})
    y = random(BiNilplex{Rational{BigInt}})
    l = inv(x * y)
    r = inv(y) * inv(x)
    l == r
end

@test begin
    x = random(BiNilplex{Rational{BigInt}})
    y = random(BiNilplex{Rational{BigInt}})
    l = inv(x / y)
    r = y / x
    l == r
end

@test begin
    x = random(BiNilplex{Rational{BigInt}})
    y = random(BiNilplex{Rational{BigInt}})
    l = inv(x \ y)
    r = y \ x
    l == r
end

@test begin
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    z = random(BiNilplex{BigInt})
    l = x * (y + z)
    r = (x * y) + (x * z)
    l == r
end

@test begin
    a = Plexifications.randomBigInt()
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    l = a * (x + y)
    r = (a * x) + (a * y)
    l == r
end

@test begin
    a = Plexifications.randomBigInt()
    x = random(BiNilplex{BigInt})
    l = a * x
    r = x * a
    l == r
end

@test begin
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    z = random(BiNilplex{BigInt})
    l = (x + y) * z
    r = (x * z) + (y * z)
    l == r
end

@test begin
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    z = random(BiNilplex{BigInt})
    l = x * (y - z)
    r = (x * y) - (x * z)
    l == r
end

@test begin
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    z = random(BiNilplex{BigInt})
    l = (x - y) * z
    r = (x * z) - (y * z)
    l == r
end

@test begin
    x = random(BiNilplex{BigInt})
    n = norm(x)
    n > big(0) || n == big(0)
end

@test begin
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    l = norm(x * y)
    r = norm(x) * norm(y)
    l == r
end

@test_throws ErrorException begin
    inv(BiNilplex(0, 0.0))
end

@test_throws ErrorException begin
    random(BiNilplex{Int}) / 0
end

@test_throws ErrorException begin
    0 \ random(BiNilplex{Int})
end

@test begin
    a = Plexifications.randomBigRational()
    z = random(BiNilplex{Rational{BigInt}})
    l = z / a
    r = a \ z
    l == r
end

@test begin
    a = Plexifications.randomBigRational()
    z = random(BiNilplex{Rational{BigInt}})
    l = a / z
    r = z \ a
    l == r
end

@test begin
    z = random(BiNilplex{BigInt})
    z == z + zero(BiNilplex{BigInt})
end

@test begin
    z = random(BiNilplex{BigInt})
    z == z * one(BiNilplex{BigInt})
end

@test begin
    z = random(BiNilplex{BigInt})
    z == z + zero(z)
end

@test begin
    z = random(BiNilplex{BigInt})
    z == z * one(z)
end

@test begin
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    l = commutator(x, y)
    r = zero(BiNilplex{BigInt})
    l == r
end

@test begin
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    l = alternatorL(x, y)
    r = zero(BiNilplex{BigInt})
    l == r
end

@test begin
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    l = alternatorR(x, y)
    r = zero(BiNilplex{BigInt})
    l == r
end

@test begin
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    l = flexator(x, y)
    r = zero(BiNilplex{BigInt})
    l == r
end

@test begin
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    z = random(BiNilplex{BigInt})
    l = associator(x, y, z)
    r = zero(BiNilplex{BigInt})
    l == r
end

@test begin
    x = random(BiNilplex{BigInt})
    y = random(BiNilplex{BigInt})
    z = random(BiNilplex{BigInt})
    l = jacobiator(x, y, z)
    r = 3 * x * y * z
    l == r
end

@test begin
    l = BiNilplex(Nlplex(1,2))
    r = BiNilplex(1,2,0)
    l == r
end

@test begin
    l = BiNilplex(1, 2, 3.0)
    r = BiNilplex(1.0, 2.0, 3.0)
    l == r
end

@test begin
    l = BiNilplex(1, 2, 3, 4.0)
    r = BiNilplex(1.0, 2.0, 3.0, 4.0)
    l == r
end


text:
using GeometricInterpretation
using Test

@testset "GeometricInterpretation.jl" begin
    # Write your tests here.
end


text:
"""
Submodule of `SirenSeq`.
Defines instrument name shortcuts for some instruments of the general musescore 144 soundfont file.
`(bank,program)` pairs defined here are used by the `SirenSeq.Inst` function.
"""
module GenMuseScoreSF144

const iGrandPiano		= (0,0)
const iBrightPiano		= (0,1)
const iHarpsichord		= (0,6)
const iCeleste			= (0,8)
const iGlockenspiel		= (0,9)
const iTubularBells		= (0,14)
const iDulcimer			= (0,15)
const iPipeOrgan		= (0,19)
const iNylonGuitar		= (0,24)
const iSteelGuitar		= (0,25)
const iDistGuitar		= (0,30)
const iAcousticBass		= (0,32)
const iFingerBass		= (0,33)
const iPickBass			= (0,34)
const iFretlessBass		= (0,35)
const iViolin			= (0,40)
const iViola			= (0,41)
const iCello			= (0,42)
const iDoubleBass		= (0,43)
const iOrchestralHarp	= (0,46)
const iSynthAbstractStrings1	= (0,50)
const iSynthAbstractStrings2	= (0,51)
const iSynthBrass1		= (0,62)
const iSynthBrass2		= (0,63)
const iSquareLead		= (0,80)
const iSawLead			= (0,81)
const iCharang			= (0,84)
const iBassLead			= (0,87)
const iFantasia			= (0,88)
const iWarmPad			= (0,89)
const iSpaceVoice		= (0,91)
const iMetalPad			= (0,93)
const iHalo				= (0,94)
const iCrystal			= (0,98)
const iAtmosphere		= (0,99)
const iBrightness		= (0,100)
const iGoblin			= (0,101)
const iSitar			= (0,104)
const iBanj				= (0,105)
const iKoto				= (0,107)
const iTinkerBell		= (0,112)
const iSteelDrums		= (0,114)

const iStandardDrums	= (120,0)
const iStandardDrums2	= (120,1)
const iRoomDrums		= (120,8)
const iPowerDrums		= (120,16)
const i809Drums			= (120,25)
const iJazzDrums		= (120,32)

end


text:
using Test
using Smoothers

@testset "loess" begin

    # AssertionsErrors
    @test_throws AssertionError loess(rand(5),rand(5); d=3)

    # Standard
    fx = loess(sort(rand(10)),rand(10))
    x = fx(rand(20));
    @test length(x) == 20

    fx = loess(sort(rand(10)), rand(10); d=1)
    x = fx(rand(20));
    @test length(x) == 20

    xv = sort(sin.(collect(1:5.)))
    fx = loess(xv,sin.(collect(1:5.)); d=2)
    x = fx(xv);
    @test isapprox(x,[0.8414709848078966, 0.9095525828909523, 0.1420295878550277, -0.7350481509902661, -0.9589242746631387]; atol=.1)

    xv = sort(sin.(collect(1:5.)))
    fx = loess(xv,sin.(collect(1:5.)); d=1)
    x = fx(xv);
    @test isapprox(x,[0.8414709848078965, 0.9092974268256818, 0.14112000805986713, -0.7568024953079286, -0.9589242746631383]; atol=.1)

    fx = loess(1:100,rand(1:100,100))
    x = fx(Int64.(round.(100*rand(20))));
    @test length(x) == 20

    fx = loess(1:2:200, vcat(rand(80),repeat([missing],20)))
    x = fx(1.:2:40)
    @test length(x) == 20

end


text:
@testset "Finds a trivial complete arnoldi decomposition" begin

    matrix = [1 1 1;1 1 1;0 1 1];
    guess = [1;0;0]

    expected = [1 1 1;1 1 1;0 1 1]
    actual = Eigen.arnoldi(matrix, guess, 3)

    @test expected == actual.H
end

@testset "Finds a trivial partial arnoldi decomposition" begin

    matrix = [1 1 1;1 1 1;0 1 1];
    guess = [1;0;0]

    expected = [1 1;1 1;0 1]
    actual = Eigen.arnoldi(matrix, guess, 2)

    @test expected == actual.H
end

@testset "Stops the decomposition if an invariant subspace is found" begin

    matrix = [1 0 0;0 1 0;0 0 1]
    guess = [1;0;0]

    expected = 1
    actual = Eigen.arnoldi(matrix, guess, 2)

    @test expected == actual.numColumns
end


text:
@testset "Simulator: Quadruped" begin
    # Reference trajectory
    s = get_simulation("quadruped", "flat_2D_lc", "flat")
    model = s.model
    env = s.env
    model.μ_world = 0.5

    ref_traj = deepcopy(ContactImplicitMPC.get_trajectory(s.model, s.env,
		joinpath(module_dir(), "src/dynamics/quadruped/gaits/gait2.jld2"),
		load_type = :split_traj_alt))
    ContactImplicitMPC.update_friction_coefficient!(ref_traj, model, env)

    T = ref_traj.H
    h = ref_traj.h

    for t = 1:T
      r = ContactImplicitMPC.residual(model, env, ref_traj.z[t], ref_traj.θ[t], 0.0)
      @test norm(r) < 1.0e-4
    end

    # initial conditions
    v1 = (ref_traj.q[2] - ref_traj.q[1]) ./ h
    q1 = ref_traj.q[2]

    # policy
    p = ContactImplicitMPC.open_loop_policy([ut for ut in ref_traj.u])

    # simulator
    sim = ContactImplicitMPC.simulator(s, T, h=h, policy=p)

    # simulate
    @test status = ContactImplicitMPC.simulate!(sim, q1, v1)
    @test norm(ref_traj.q[end][1:3] - sim.traj.q[end][1:3], Inf) < 0.025
end


text:
# *****************************************************************************
# Written by Ritchie Lee, ritchie.lee@sv.cmu.edu
# *****************************************************************************
# Copyright ã 2015, United States Government, as represented by the
# Administrator of the National Aeronautics and Space Administration. All
# rights reserved.  The Reinforcement Learning Encounter Simulator (RLES)
# platform is licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. You
# may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0. Unless required by applicable
# law or agreed to in writing, software distributed under the License is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the specific language
# governing permissions and limitations under the License.
# _____________________________________________________________________________
# Reinforcement Learning Encounter Simulator (RLES) includes the following
# third party software. The SISLES.jl package is licensed under the MIT Expat
# License: Copyright (c) 2014: Youngjun Kim.
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
# "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
# NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# *****************************************************************************

using RLESCAS
using SISLES.GenerativeModel

#TODO: remove all the hardcodings in here

function print_results(results)
  println("\n")
  println("Function \t\t Wall Time (seconds)")
  println("============================================")
  for r = 1:size(results, 1)
    println(results[r, 1], " \t\t ", results[r, 2] )
  end
  println("\n")

end

function test_sim()
  res = Array(Any, 7, 2)

  p = defineSimParams()
  sim = defineSim(p)
  initialize(sim)
  update(sim)
  update(sim)

  #test 1
  tic();
  sim = defineSim(p)
  res[1, :] = ["defineSim(p)", toq()]

  #test 2
  tic();
  initialize(sim)
  res[2, :] = ["1st init(sim)", toq()]

  #test 3
  tic();
  update(sim)
  res[3, :] = ["1st update1(sim)", toq()]

  #test 4
  tic();
  update(sim)
  res[4, :] = ["1st update2(sim)", toq()]

  #test 5
  tic();
  initialize(sim)
  res[5, :] = ["2nd init(sim)", toq()]

  #test 6
  tic();
  update(sim)
  res[6, :] = ["2nd update1(sim)", toq()]

  #test 7
  tic();
  update(sim)
  res[7, :] = ["2nd update2(sim)", toq()]

  return res
end

function test_simcomponents()
  res = Array(Any, 10, 2)

  p = defineSimParams()
  sim = defineSim(p)
  initialize(sim)
  update(sim)
  update(sim)

  sim = defineSim(p)
  initialize(sim)

  #test 1
  tic();
  EncounterDBN.update(sim.em)
  res[1, :] = ["1st update(em)", toq()]

  states = WorldModel.getAll(sim.wm)
  command = EncounterDBN.get(sim.em, 1)

  #test 2
  tic();
  output = Sensor.update(sim.sr[1], states)
  res[2, :] = ["1st update(sr)", toq()]

  #test 3
  tic();
  RA = CollisionAvoidanceSystem.update(sim.cas[1], output)
  res[3, :] = ["1st update(cas)", toq()]

  #test 4
  tic();
  response = PilotResponse.update(sim.pr[1], command, RA)
  res[4, :] = ["1st update(pr)", toq()]

  #test 5
  tic();
  state = DynamicModel.update(sim.dm[1], response)
  res[5, :] = ["1st update(dm)", toq()]

  #test 6
  tic();
  EncounterDBN.update(sim.em)
  res[6, :] = ["2nd update(em)", toq()]

  states = WorldModel.getAll(sim.wm)
  command = EncounterDBN.get(sim.em, 1)

  #test 7
  tic();
  output = Sensor.update(sim.sr[1], states)
  res[7, :] = ["2nd update(sr)", toq()]

  #test 8
  tic();
  RA = CollisionAvoidanceSystem.update(sim.cas[1], output)
  res[8, :] = ["2nd update(cas)", toq()]

  #test 9
  tic();
  response = PilotResponse.update(sim.pr[1], command, RA)
  res[9, :] = ["2nd update(pr)", toq()]

  #test 10
  tic();
  state = DynamicModel.update(sim.dm[1], response)
  res[10, :] = ["2nd update(dm)", toq()]

  return res
end

function test_rollout()
  res = Array(Any, 3, 2)

  p = defineSimParams()
  sim = defineSim(p)
  initialize(sim)
  update(sim)
  update(sim)

  #test1 single
  tic();
  initialize(sim)
  for t = 1:50
    update(sim)
  end
  res[1, :] = ["rollout1", toq()]

  #test2 rollout
  tic();
  initialize(sim)
  for i = 1:10
    for t = 1:50
      update(sim)
    end
  end
  res[2, :] = ["rollout10", toq()]

  #test3 rollout
  tic();
  initialize(sim)
  for i = 1:100
    for t = 1:50
      update(sim)
    end
  end
  res[3, :] = ["rollout100", toq()]

  return res
end

function est_runtime(results::Array{Any, 2}, iterations::Int=3000, nsteps::Int=50)
  init_time = results[5, 2]
  update1 = results[6, 2]
  update2 = results[7, 2]

  runtime = (init_time + update1 + (nsteps - 1) * update2) * iterations * nsteps
  println("estimated runtime: $runtime seconds or $(runtime/3600.0) hours")

  return runtime
end

function test_main()

  #[test name, wall time (seconds)]
  results = Array(Any, 0, 2)

  #test sim
  res = test_sim()
  results = vcat(results, res)

  #test sim components
  res = test_simcomponents()
  results = vcat(results, res)

  #test single rollout
  res = test_rollout()
  results = vcat(results, res)

  print_results(results)

  runtime = est_runtime(results)

  return results
end

max_stars_repo_name: sisl/RLESCAS

max_issues_repo_name: sisl/RLESCAS

max_forks_repo_name: sisl/RLESCAS


text:
module AutomotivePOMDPs

using POMDPs
using StatsBase
using Distributions
using POMDPModelTools
using POMDPSimulators
using POMDPPolicies
using BeliefUpdaters
using RLInterface
using Parameters
using GridInterpolations
using StaticArrays
using DiscreteValueIteration
using AutomotiveDrivingModels
using AutoUrban
using AutoViz
using AutomotiveSensors
using Reel
using Random
using DataStructures
using LinearAlgebra
import Cairo

"""
Abstract type to define driving environment with occlusion
"""
abstract type OccludedEnv end

# helpers
export
        # for rendering
        animate_hist,
        animate_record,
        animate_scenes,

        # helpers
        get_end,
        get_lanes,
        get_start_lanes,
        get_exit_lanes,
        get_ego,
        is_crash,
        direction_from_center,
        random_route,
        is_observable_dyna,
        is_observable_fixed,
        off_the_grid,
        get_conflict_lanes,
        get_colors,
        next_car_id,
        next_ped_id,
        EGO_ID,
        CAR_ID,
        PED_ID,
        EgoDriver

include("constants.jl")
include("utils/helpers.jl")
include("utils/occlusions.jl")
include("utils/rendering.jl")

# envs
export
    OccludedEnv,
    CrosswalkParams,
    CrosswalkEnv,
    TInterParams,
    IntersectionEnv,
    SimpleInterParams,
    SimpleInterEnv,
    gen_T_roadway,
    UrbanParams,
    UrbanEnv,
    ObstacleDistribution,
    sample_obstacles!,
    sample_obstacle!,
    empty_obstacles!,
    add_obstacle!,
    car_roadway

include("envs/occluded_crosswalk_env.jl")
include("envs/multi_lane_T_env.jl")
include("envs/urban_env.jl")
include("envs/obstacles.jl")
include("envs/rendering.jl")

# driver models and action types
export
    action_space,
    get_distribution,
    ConstantPedestrian,
    ConstantSpeedDawdling,
    RouteFollowingIDM,
    set_direction!,
    get_direction,
    LonAccelDirection,
    CrosswalkDriver,
    StopIntersectionDriver,
    TTCIntersectionDriver,
    UrbanDriver,
    IntelligentPedestrian,
    LidarOverlay,
    get_stop_model,
    get_ttc_model

include("driver_models/route_following_idm.jl")
include("driver_models/stop.jl")
include("driver_models/stop_intersection_driver.jl")
include("driver_models/ttc_intersection_driver.jl")
include("driver_models/constant_pedestrian.jl")
include("driver_models/crosswalk_driver.jl")
include("driver_models/urban_driver.jl")
include("driver_models/lidar_sensor.jl")
include("driver_models/intelligent_pedestrian_model.jl")
include("driver_models/helpers.jl")

export
    # pomdp types
    OCPOMDP,
    OCAction,
    OCState,
    OCObs,
    SingleOCPOMDP,
    SingleOCAction,
    SingleOCState,
    SingleOCObs,
    SingleOCBelief,
    SingleOCDistribution,
    SingleOCUpdater,
    OIPOMDP,
    OIAction,
    OIState,
    OIObs,
    SingleOIPOMDP,
    SingleOIAction,
    SingleOIState,
    SingleOIObs,
    state_to_scene,
    UrbanPOMDP,
    UrbanState,
    UrbanAction,
    UrbanObs,
    initial_car,
    initial_pedestrian,
    initial_ego,
    obs_weight,
    rescale!,
    unrescale!,
    obs_to_scene,
    fuse_value,
    fuse_value_min,
    interpolate_state,
    scene_to_states,
    states_to_scene,
    normalized_off_the_grid_pos,
    get_normalized_absent_state,
    split_o,
    n_dims

# single crosswalk
include("explicit_pomdps/single_crosswalk/pomdp_types.jl")
include("explicit_pomdps/single_crosswalk/spaces.jl")
include("explicit_pomdps/single_crosswalk/transition.jl")
include("explicit_pomdps/single_crosswalk/observation.jl")
include("explicit_pomdps/single_crosswalk/belief.jl")
include("explicit_pomdps/single_crosswalk/adm_helpers.jl")
include("explicit_pomdps/single_crosswalk/render_helpers.jl")
include("explicit_pomdps/single_crosswalk/decomposition.jl")

# multi crowsswalk
include("generative_pomdps/multi_crosswalk/pomdp_types.jl")
include("generative_pomdps/multi_crosswalk/generative_model.jl")
include("generative_pomdps/multi_crosswalk/render_helpers.jl")

# single intersection
include("explicit_pomdps/single_intersection/occluded_intersection_env.jl")
include("explicit_pomdps/single_intersection/pomdp_types.jl")
include("explicit_pomdps/single_intersection/spaces.jl")
include("explicit_pomdps/single_intersection/transition.jl")
include("explicit_pomdps/single_intersection/observation.jl")
include("explicit_pomdps/single_intersection/belief.jl")
include("explicit_pomdps/single_intersection/render_helpers.jl")

# multi intersection
include("generative_pomdps/multi_lane_T_intersection/pomdp_types.jl")
include("generative_pomdps/multi_lane_T_intersection/generative_model.jl")
include("generative_pomdps/multi_lane_T_intersection/render_helpers.jl")

#urban
include("generative_pomdps/urban/pomdp_types.jl")
include("generative_pomdps/urban/generative_model.jl")
include("generative_pomdps/urban/render_helpers.jl")

export
    CarMDP,
    CarMDPState,
    CarMDPAction,
    PedMDP,
    PedMDPState,
    PedMDPAction
export
    labeling,
    get_mdp_state,
    state2scene,
    get_car_vspace,
    get_ped_vspace,
    get_ego_states,
    get_car_states,
    get_ped_states,
    get_car_routes,
    get_ped_lanes,
    ind2ego,
    ind2ped,
    ind2car,
    find_route,
    ego_stateindex,
    ped_stateindex,
    car_stateindex,
    n_ego_states,
    n_car_states,
    n_ped_states,
    get_off_the_grid,
    get_ped_mdp,
    get_car_mdp,
    get_car_models,
    get_stop_model,
    get_ttc_model,
    get_discretized_lane,
    interpolate_pedestrian,
    interpolate_state

# more discrete POMDPs
include("explicit_pomdps/discretization.jl")
include("explicit_pomdps/rendering.jl")
include("explicit_pomdps/car_mdp/pomdp_types.jl")
include("explicit_pomdps/car_mdp/state_space.jl")
include("explicit_pomdps/car_mdp/transition.jl")
include("explicit_pomdps/car_mdp/render_helpers.jl")
include("explicit_pomdps/car_mdp/high_fidelity.jl")
include("explicit_pomdps/pedestrian_mdp/pomdp_types.jl")
include("explicit_pomdps/pedestrian_mdp/state_space.jl")
include("explicit_pomdps/pedestrian_mdp/transition.jl")
include("explicit_pomdps/pedestrian_mdp/render_helpers.jl")
include("explicit_pomdps/pedestrian_mdp/high_fidelity.jl")
# include("explicit_pomdps/pedcar_mdp/driver_models_helpers.jl")
# include("explicit_pomdps/pedcar_mdp/pomdp_types.jl")
# include("explicit_pomdps/pedcar_mdp/state_space.jl")
# include("explicit_pomdps/pedcar_mdp/transition.jl")
# include("explicit_pomdps/pedcar_mdp/high_fidelity.jl")
# include("explicit_pomdps/pedcar_mdp/render_helpers.jl")
include("explicit_pomdps/interpolation.jl")

export
    # decomposition stuff
    TwoCars,
    ObsPed,
    ObsCar,
    TwoCarsScenario,
    PedCarScenario,
    ObsPedScenario,
    ObsCarScenario,
    decompose_input,
    DecomposedPolicy,
    KMarkovDecUpdater,
    KMarkovDecBelief,
    PreviousObsDecUpdater,
    PreviousObsDecBelief,
    initialize_dec_belief,
    BeliefOverlay

include("decomposition/base_scenarios.jl")
include("decomposition/decomposition_wrapper.jl")
include("decomposition/rendering.jl")

end

max_stars_repo_name: MaximeBouton/AutomotivePOMDPs

max_issues_repo_name: MaximeBouton/AutomotivePOMDPs

max_forks_repo_name: MaximeBouton/AutomotivePOMDPs


text:
export flatten, events2dynet, snapshots2dynet

"""
    flatten(G::SparseMatrixCSC{<:Number,Int})
    flatten(G::SparseMatrixCSC{Events,Int})
    flatten(nt::Network)
    flatten(dy::DynamicNetwork)

Convert dynamic network to a static network, where each dynamic edge
corresponds to a static edge with weight 1. It does not make a copy of the
network (so, the sparse matrix indices will be shared).
"""
flatten(G::SparseMatrixCSC{<:Number,Int}) = G
flatten(G::SparseMatrixCSC{Events,Int}) =
    SparseMatrixCSC(G.m,G.n,G.colptr,G.rowval,ones(Int,length(G.nzval)))
flatten(nt::Network) = nt
flatten(dy::DynamicNetwork) = Network(flatten(dy.G), dy.nodes)

"""
    events2dynet(I, J, V, n, nodes; symmetric=true) -> SparseMatrixCSC{Events}, nodes

Similar to `sparse`, given indices and values, create
an dynamic network.

# Arguments
- `n` : # of nodes in network
- `I`,`J`: indices
- `V` : vector of `Events`
- `symmetric=true` : If true, make the sparse matrix symmetric.
"""
function events2dynet(I, J, V, n, nodes; symmetric=true)
    if symmetric
        G = sparse(vcat(I,J),vcat(J,I),vcat(V,V),n,n,fixevents)
    else
        G = sparse(I,J, V, n, n, fixevents)
    end
    DynamicNetwork(G,nodes)
end

"""
    snapshots2dynet(snaps::Vector{Network};
              symmetric=false,sortby=nothing)

Converts a vector of networks (i.e. temporal snapshots)
into a dynamic network with event duration 1
and time starting at 0.
"""
function snapshots2dynet(snaps::Vector{Network};
                                 symmetric=false,sortby=nothing)
    nodes = Set{String}()
    events = Vector{Tuple{String,String,Float64,Float64}}()
    for t = 1:length(snaps)
        Gc = snaps[t].G
        nodesc = snaps[t].nodes
        Ic,Jc,Vc = findnz(triu(Gc,1))
        append!(events, collect(zip(nodesc[Ic],nodesc[Jc],
                                    fill(Float64(t-1),length(Vc)),
                                    fill(Float64(t),length(Vc)))))
        union!(nodes,nodesc)
    end
    nodes = collect(nodes)
    if sortby!=nothing
        nodes = sort(nodes,by=sortby)
    end
    nodesnum = indexmap(nodes)
    edges = Matrix{Int}(length(events),2)
    timestamps = Vector{Vector{Tuple{Float64,Float64}}}(length(events))
    for i = 1:length(events)
        vals = events[i]
        n1 = nodesnum[vals[1]]
        n2 = nodesnum[vals[2]]
        edges[i,1] = min(n1,n2)
        edges[i,2] = max(n1,n2)
        timestamps[i] = [(vals[3],vals[4])]
    end
    events2dynet(edges[:,1], edges[:,2], timestamps,
                 length(nodes), nodes,
                 symmetric=symmetric)
end


text:
using Base: BufferStream
using Lehmann
using Test
using Printf
using JLD2
using CodecZlib #it is important to import CodecZlib explicitly. Otherwise, the code may try to dynamically load this package, and sometimes leads to error

include("spectral.jl")
include("dlr.jl")

# @testset "Lehmann.jl" begin
# Write your tests here.
# end