text:
@testset "ContractAttributes" begin
    a1 = FinancialDSL.Core.ContractAttributes()
    a2 = FinancialDSL.Core.ContractAttributes()

    @test a1 == a2
    @test hash(a1) == hash(a2)

    a1["hey"] = "you"
    @test a1["hey"] == "you"
    a1["maturity"] = Date(2018, 2, 1)
    a1["spread"] = 10.2

    @test a1 != a2
    @test a2 != a1
    @test hash(a1) != hash(a2)

    a2["hey"] = "you"
    @test a1 != a2
    @test a2 != a1

    a2["maturity"] = Date(2018, 2, 1)
    a2["spread"] = 10.2

    @test a1 == a2
    @test a2 == a1
    @test hash(a1) == hash(a2)

    attributes = FinancialDSL.Core.ContractAttributes("price_serie" => Dict("serie_name" => "DI1Q18"))
end

@testset "equality para RiskFactors" begin
    @test FinancialDSL.Core.SpotCurrency(USD) == FinancialDSL.Core.SpotCurrency(USD)
    @test hash(FinancialDSL.Core.SpotCurrency(USD)) == hash(FinancialDSL.Core.SpotCurrency(USD))
    @test FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2)) == FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2))
    @test hash(FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2))) == hash(FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2)))
    v = [ FinancialDSL.Core.SpotCurrency(USD), FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2)) ]
    @test FinancialDSL.Core.SpotCurrency(USD) ∈ v
    @test FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2)) ∈ v
    @test FinancialDSL.Core.SpotCurrency(BRL) ∉ v
    @test FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 3)) ∉ v
    @test FinancialDSL.Core.DiscountFactor(:cpUSD, Date(2019, 1, 2)) ∉ v
end

@testset "Builtin contracts" begin
    @test FinancialDSL.Core.Amount(2.0BRL) == FinancialDSL.Core.Amount(2.0, BRL)
    @test FinancialDSL.Core.Amount(1.0BRL) == FinancialDSL.Core.Unit(BRL)
    @test FinancialDSL.Core.Amount(1.0, BRL) == FinancialDSL.Core.Unit(BRL)
    @test FinancialDSL.Core.Amount(0.0BRL) == FinancialDSL.Core.Worthless()
    @test FinancialDSL.Core.Amount(0.0, BRL) == FinancialDSL.Core.Worthless()
end

@testset "Observables Albebra" begin
    @testset "Konst eager algebra" begin
        k = FinancialDSL.Core.Konst(2.0)
        @test !iszero(k)
        @test !FinancialDSL.Core.iszerokonst(k)
        @test -k == FinancialDSL.Core.Konst(-2.0)
        @test -(-k) == k
        @test k^2 == FinancialDSL.Core.Konst(4.0)
        @test (1 + k)^(2) == FinancialDSL.Core.Konst((1+2.0)^2)
        @test 3^k == FinancialDSL.Core.Konst(9.0)

        kk = FinancialDSL.Core.Konst(3.0)
        @test k * kk == FinancialDSL.Core.Konst(6.0)
        @test k + kk == FinancialDSL.Core.Konst(5.0)
        @test k / kk == FinancialDSL.Core.Konst(2.0 / 3.0)
        @test kk - k == FinancialDSL.Core.Konst(1.0)

        @test FinancialDSL.Core.Konst(1) * 2.0 == FinancialDSL.Core.Konst(2.0)

        @test kk + kk * kk == FinancialDSL.Core.Konst(12.0)
        @test 2kk == FinancialDSL.Core.Konst(6.0)

        z = FinancialDSL.Core.Konst(0.0)
        @test iszero(z)
        @test FinancialDSL.Core.iszerokonst(z)
        z = FinancialDSL.Core.Konst(0)
        @test iszero(z)
        @test FinancialDSL.Core.iszerokonst(z)
        @test !FinancialDSL.Core.iszerokonst(FinancialDSL.Core.SpotCurrency(BRL))
    end

    @testset "Special functions" begin
        @test round(FinancialDSL.Core.Konst(2.2)) == FinancialDSL.Core.Konst(2.0)
        @test round(FinancialDSL.Core.Konst(2.23); digits=1) == FinancialDSL.Core.Konst(2.2)

        @test trunc(FinancialDSL.Core.Konst(2.8)) == FinancialDSL.Core.Konst(2.0)
        @test trunc(FinancialDSL.Core.Konst(2.83); digits=1) == FinancialDSL.Core.Konst(2.8)
    end

    @testset "Konst +, *, - obs optim" begin
        obs = FinancialDSL.Core.SpotCurrency(BRL)
        k1 = FinancialDSL.Core.Konst(2.0)
        k2 = FinancialDSL.Core.Konst(3.0)

        @testset "*" begin
            expected_result = FinancialDSL.Core.LiftObs2(*, FinancialDSL.Core.Konst(6.0), obs)
            @test k1 * (k2 * obs) == expected_result
            @test k1 * (obs * k2) == expected_result
            @test (k1 * obs) * k2 == expected_result
            @test (obs * k1) * k2 == expected_result
            @test k1 * k2 * obs == expected_result
            @test k1 * obs * k2 == expected_result
            @test obs * k1 * k2 == expected_result
        end

        @testset "+" begin
            expected_result = FinancialDSL.Core.LiftObs2(+, FinancialDSL.Core.Konst(5.0), obs)
            @test k1 + (k2 + obs) == expected_result
            @test k1 + (obs + k2) == expected_result
            @test (k1 + obs) + k2 == expected_result
            @test (obs + k1) + k2 == expected_result
            @test k1 + k2 + obs == expected_result
            @test k1 + obs + k2 == expected_result
            @test obs + k1 + k2 == expected_result
        end

        @testset "-" begin
            @test k1 - (k2 + obs) == (k1 - k2) + (-obs)
            @test k1 - (obs + k2) == (k1 - k2) + (-obs)
            @test k1 - (k2 - obs) == (k1 - k2) + obs
            @test k1 - (obs - k2) == (k1 + k2) + (-obs)
            @test (k1 - obs) + k2 == (k1 + k2) + (-obs)
            @test (k1 + obs) - k2 == (k1 - k2) + obs
            @test (obs - k1) + k2 == (k2 - k1) + obs
            @test (obs + k1) - k2 == (k1 - k2) + obs
            @test k2 + (k1 - obs) == (k1 + k2) + (-obs)
        end

        # mixing lifting and binary operators
        @test min(1.0, obs) == FinancialDSL.Core.LiftObs2(min, FinancialDSL.Core.Konst(1.0), obs)
        @test min(obs, 1.0) == FinancialDSL.Core.LiftObs2(min, obs, FinancialDSL.Core.Konst(1.0))
        @test max(1.0 + obs, obs) == FinancialDSL.Core.LiftObs2(max, FinancialDSL.Core.LiftObs2(+, FinancialDSL.Core.Konst(1.0), obs), obs)

        # Konst optimization does not apply to these cases
        @test k1 + k2 * obs == FinancialDSL.Core.LiftObs2(+, k1, FinancialDSL.Core.LiftObs2(*, k2, obs))
        @test k1 * k2 + obs == FinancialDSL.Core.LiftObs2(+, FinancialDSL.Core.Konst(6.0), obs)
        @test k1 * obs + k2 == FinancialDSL.Core.LiftObs2(+, FinancialDSL.Core.LiftObs2(*, k1, obs), k2)
        @test obs * k1 + k2 == FinancialDSL.Core.LiftObs2(+, FinancialDSL.Core.LiftObs2(*, obs, k1), k2)
    end

    @testset "exp and log" begin
        obs = FinancialDSL.Core.SpotCurrency(BRL)
        @test log(obs) == FinancialDSL.Core.LiftObs(log, obs)
        @test exp(obs) == FinancialDSL.Core.LiftObs(exp, obs)
        @test log(exp(obs)) == obs
        @test exp(log(obs)) == obs
    end
end

function scenario_map_function(rf::FinancialDSL.Core.SpotCurrency, val::FinancialDSL.Currencies.Cash)
    return val * 1.05
end

function scenario_map_function(rf::FinancialDSL.Core.DiscountFactor, val::Number)
    # 10% increase on BRL discount factor
    if FinancialDSL.Core.market_data_symbol(rf) == :PRE
        return identity(val)
    else
        return val * 1.1
    end
end

@testset "Scenarios" begin

    @testset "FixedScenario" begin
        scenario = FinancialDSL.Core.FixedScenario()
        scenario[FinancialDSL.Core.SpotCurrency(BRL)] = 1.0BRL
        scenario[FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2))] = 0.7
        @test_throws ErrorException scenario[FinancialDSL.Core.SpotCurrency(USD)] = 10
        @test_throws ErrorException scenario[FinancialDSL.Core.SpotCurrency(USD)] = 10.0
        @test haskey(scenario, FinancialDSL.Core.SpotCurrency(BRL))
        @test haskey(scenario, FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2)))
        @test scenario[FinancialDSL.Core.SpotCurrency(BRL)] == 1.0BRL
        @test scenario[FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2))] == 0.7
        scenario[FinancialDSL.Core.DiscountFactor(:PRE, Date(2020, 1, 2))] = 1
        @test scenario[FinancialDSL.Core.DiscountFactor(:PRE, Date(2020, 1, 2))] == 1.0
        @test isa(scenario[FinancialDSL.Core.DiscountFactor(:PRE, Date(2020, 1, 2))], Float64)
    end

    @testset "DebugScenario" begin
        scenario = FinancialDSL.Core.FixedScenario()
        scenario[FinancialDSL.Core.SpotCurrency(BRL)] = 1.0BRL
        scenario[FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2))] = 0.7

        debug = FinancialDSL.Core.DebugScenario(scenario)
        @test haskey(debug, FinancialDSL.Core.SpotCurrency(BRL))
        @test debug[FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2))] == 0.7
        @test length(debug.record) == 1
        @test debug.record[FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2))] == 0.7
    end

    @testset "ScenarioMap" begin
        scenario = FinancialDSL.Core.FixedScenario()
        scenario[FinancialDSL.Core.SpotCurrency(BRL)] = 1.0BRL
        scenario[FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2))] = 0.7
        scenario[FinancialDSL.Core.DiscountFactor(:cpUSD, Date(2019, 1, 2))] = 0.8

        scenario_map = FinancialDSL.Core.ScenarioMap(scenario_map_function, scenario)
        @test scenario_map[FinancialDSL.Core.SpotCurrency(BRL)] ≈ 1.0 * 1.05 * BRL
        @test scenario_map[FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2))] ≈ 0.7
        @test scenario_map[FinancialDSL.Core.DiscountFactor(:cpUSD, Date(2019, 1, 2))] ≈ 0.8 * 1.1
    end
end

@testset "Compiler" begin
    include("test_core_compiler.jl")
end

@testset "Pricing and Exposures" begin

    pricing_date = Date(2018, 5, 29)
    currency_to_curves_map = Dict( "onshore" => Dict( :BRL => :PRE, :USD => :cpUSD ))
    static_model = FinancialDSL.Core.StaticHedgingModel(BRL, currency_to_curves_map)
    empty_provider = FinancialDSL.MarketData.EmptyMarketDataProvider()

    @test FinancialDSL.Core.is_riskfree_discountfactor(static_model, "onshore", FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2)))
    @test !FinancialDSL.Core.is_riskfree_discountfactor(static_model, "onshore", FinancialDSL.Core.DiscountFactor(:OTHER_CURVE, Date(2019, 1, 2)))
    @test_throws AssertionError FinancialDSL.Core.is_riskfree_discountfactor(static_model, "offshore", FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2)))

    o = FinancialDSL.Core.Konst(10.2)
    lo = FinancialDSL.Core.LiftObs(string, o)
    @test typeof(lo) == FinancialDSL.Core.LiftObs{typeof(string), String}

    o1 = FinancialDSL.Core.Konst(10)
    o2 = FinancialDSL.Core.Konst(20.0)
    lo = FinancialDSL.Core.LiftObs2(+, o1, o2)
    @test typeof(lo) == FinancialDSL.Core.LiftObs2{typeof(+), Float64}

    # Scenarios
    scenario_fixed = FinancialDSL.Core.FixedScenario()
    scenario_fixed[FinancialDSL.Core.SpotCurrency(USD)] = 2.9BRL # dolar spot price
    scenario_fixed[FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2))] = 0.7 # BRL discount factor
    scenario_fixed[FinancialDSL.Core.DiscountFactor(:cpUSD, Date(2019, 1, 2))] = 0.9 # USD discount factor
    scenario_fixed[FinancialDSL.Core.DiscountFactor(:PRE, Date(2020, 1, 2))] = 0.5
    scenario_fixed[FinancialDSL.Core.DiscountFactor(:cpUSD, Date(2020, 1, 2))] = 0.8
    scenario_fixed[FinancialDSL.Core.DiscountFactor(:spOnshoreAA, Date(2019, 1, 2))] = 0.99 # credit risk spread discount factor

    let
        other_scenario_fixed = FinancialDSL.Core.FixedScenario()
        other_scenario_fixed[FinancialDSL.Core.SpotCurrency(USD)] = 5.0BRL
        composite_scenario = FinancialDSL.Core.CompositeScenario([other_scenario_fixed, scenario_fixed])

        @test haskey(composite_scenario, FinancialDSL.Core.DiscountFactor(:PRE, Date(2020, 1, 2)))
        @test composite_scenario[FinancialDSL.Core.DiscountFactor(:PRE, Date(2020, 1, 2))] == 0.5
        @test composite_scenario[FinancialDSL.Core.SpotCurrency(USD)] == 5.0BRL
    end

    @testset "dolar spot" begin
        c_dol_spot = FinancialDSL.Core.Amount(10.0USD)
        pricer_dol_spot = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model, c_dol_spot, FinancialDSL.Core.ContractAttributes())
        @test FinancialDSL.Core.price(pricer_dol_spot, scenario_fixed) == 2.9 * 10.0
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer_dol_spot, scenario_fixed)
        @test length(exposures_result) == 1
        @test exposures_result[FinancialDSL.Core.SpotCurrency(USD)] == 2.9 * 10.0

        # spot position on USD with credit risk, should make no difference
        pricer_dol_spot_spAA = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model, c_dol_spot, FinancialDSL.Core.ContractAttributes("riskfree_curves" => "onshore", "carry_type" => "curve"))
        @test FinancialDSL.Core.price(pricer_dol_spot_spAA, scenario_fixed) == 2.9 * 10.0
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer_dol_spot_spAA, scenario_fixed)
        @test length(exposures_result) == 1
        @test exposures_result[FinancialDSL.Core.SpotCurrency(USD)] == 2.9 * 10.0
    end

    @testset "FX zero-coupon" begin
        c_zcb_usd = FinancialDSL.Core.ZCB(Date(2019, 1, 2), 10.0USD)
        pricer_zcb_usd = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model, c_zcb_usd, FinancialDSL.Core.ContractAttributes("riskfree_curves" => "onshore", "carry_type" => "none"))
        @test length(FinancialDSL.Core.riskfactors(pricer_zcb_usd)) == 2
        @test in(FinancialDSL.Core.SpotCurrency(USD), FinancialDSL.Core.riskfactors(pricer_zcb_usd))
        @test in(FinancialDSL.Core.DiscountFactor(:cpUSD, Date(2019, 1, 2)), FinancialDSL.Core.riskfactors(pricer_zcb_usd))
        @test FinancialDSL.Core.price(pricer_zcb_usd, scenario_fixed) ≈ 10.0 * 2.9 * 0.9
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer_zcb_usd, scenario_fixed)
        @test length(exposures_result) == 2
        @test exposures_result[FinancialDSL.Core.SpotCurrency(USD)] ≈ 10.0 * 2.9 * 0.9
        @test exposures_result[FinancialDSL.Core.DiscountFactor(:cpUSD, Date(2019, 1, 2))] ≈ 10.0 * 2.9 * 0.9
    end

    @testset "FX zero-coupon with credit risk" begin
        c_zcb_usd = FinancialDSL.Core.ZCB(Date(2019, 1, 2), 10.0USD)
        pricer_zcb_usd_spAA = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model, c_zcb_usd, FinancialDSL.Core.ContractAttributes("riskfree_curves" => "onshore", "carry_type" => "curve", "carry_curves" => Dict("USD" => "spOnshoreAA")))
        @test length(FinancialDSL.Core.riskfactors(pricer_zcb_usd_spAA)) == 3
        @test in(FinancialDSL.Core.SpotCurrency(USD), FinancialDSL.Core.riskfactors(pricer_zcb_usd_spAA))
        @test in(FinancialDSL.Core.DiscountFactor(:cpUSD, Date(2019, 1, 2)), FinancialDSL.Core.riskfactors(pricer_zcb_usd_spAA))
        @test FinancialDSL.Core.price(pricer_zcb_usd_spAA, scenario_fixed) ≈ 10.0 * 2.9 * 0.9 * 0.99
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer_zcb_usd_spAA, scenario_fixed)
        @test length(exposures_result) == 3
        @test exposures_result[FinancialDSL.Core.SpotCurrency(USD)] ≈ 10.0 * 2.9 * 0.9 * 0.99
        @test exposures_result[FinancialDSL.Core.DiscountFactor(:cpUSD, Date(2019, 1, 2))] ≈ 10.0 * 2.9 * 0.9 * 0.99
        @test exposures_result[FinancialDSL.Core.DiscountFactor(:spOnshoreAA, Date(2019, 1, 2))] ≈ 10.0 * 2.9 * 0.9 * 0.99
    end

    @testset "BRL zero-coupon" begin
        c_zcb_pre = FinancialDSL.Core.ZCB(Date(2019, 1, 2), 1000.0BRL)
        pricer_zcb_pre = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model, c_zcb_pre, FinancialDSL.Core.ContractAttributes("riskfree_curves" => "onshore", "carry_type" => "none"))
        @test length(FinancialDSL.Core.riskfactors(pricer_zcb_pre)) == 1
        @test FinancialDSL.Core.riskfactors(pricer_zcb_pre)[1] == FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2))
        @test FinancialDSL.Core.price(pricer_zcb_pre, scenario_fixed) ≈ 1000.0 * 0.7
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer_zcb_pre, scenario_fixed)
        @test length(exposures_result) == 1
        @test exposures_result[FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2))] ≈ 1000.0 * 0.7
    end

    @testset "BRL zero-coupon with credit risk" begin
        c_zcb_pre = FinancialDSL.Core.ZCB(Date(2019, 1, 2), 1000.0BRL)
        pricer_zcb_pre = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model, c_zcb_pre, FinancialDSL.Core.ContractAttributes("riskfree_curves" => "onshore", "carry_type" => "curve", "carry_curves" => Dict("BRL" => "spOnshoreAA")))
        @test length(FinancialDSL.Core.riskfactors(pricer_zcb_pre)) == 2
        @test FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2)) ∈ FinancialDSL.Core.riskfactors(pricer_zcb_pre)
        @test FinancialDSL.Core.price(pricer_zcb_pre, scenario_fixed) ≈ 1000.0 * 0.7 * 0.99
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer_zcb_pre, scenario_fixed)
        @test length(exposures_result) == 2
        @test exposures_result[FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2))] ≈ 1000.0 * 0.7 * 0.99
        @test exposures_result[FinancialDSL.Core.DiscountFactor(:spOnshoreAA, Date(2019, 1, 2))] ≈ 1000.0 * 0.7 * 0.99
    end

    @testset "spot position on functional currency" begin
        c_brl_spot = FinancialDSL.Core.Amount(1BRL)
        pricer_brl_spot = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model, c_brl_spot, FinancialDSL.Core.ContractAttributes())
        @test FinancialDSL.Core.price(pricer_brl_spot, scenario_fixed) == 1.0
    end

    @testset "USD FWD without carry" begin
        c_future_usd = FinancialDSL.Core.Forward(Date(2019, 1, 2), 1USD, 2.9 * 0.9 / 0.7 * BRL)
        pricer_future_usd = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model, c_future_usd, FinancialDSL.Core.ContractAttributes("riskfree_curves" => "onshore", "carry_type" => "none"))
        @test FinancialDSL.Core.price(pricer_future_usd, scenario_fixed) ≈ 0.0
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer_future_usd, scenario_fixed)
        @test length(exposures_result) == 3
        @test exposures_result[FinancialDSL.Core.SpotCurrency(USD)] ≈ 2.9 * 0.9
        @test exposures_result[FinancialDSL.Core.DiscountFactor(:cpUSD, Date(2019, 1, 2))] ≈ 2.9 * 0.9
        @test exposures_result[FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2))] ≈ - (2.9 * 0.9 / 0.7 * 0.7)
    end

    @testset "When{When}" begin
        c_when_when = FinancialDSL.Core.WhenAt(Date(2019, 1, 2), FinancialDSL.Core.ZCB(Date(2020, 1, 2), 1USD))
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model, c_when_when, FinancialDSL.Core.ContractAttributes("riskfree_curves" => "onshore", "carry_type" => "none"))
        @test FinancialDSL.Core.price(pricer, scenario_fixed) ≈ 2.9 * 0.8
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test length(exposures_result) == 2
        @test exposures_result[FinancialDSL.Core.SpotCurrency(USD)] ≈ 2.9 * 0.8
        @test exposures_result[FinancialDSL.Core.DiscountFactor(:cpUSD, Date(2020, 1, 2))] ≈ 2.9 * 0.8
    end

    @testset "FutureValueModel" begin
        fvmodel = FinancialDSL.Core.FutureValueModel(static_model)

        c_zcb_brl = FinancialDSL.Core.ZCB(Date(2020, 1, 2), 10.0BRL)
        pricer_zcb_brl = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, fvmodel, c_zcb_brl, FinancialDSL.Core.ContractAttributes())
        @test FinancialDSL.Core.price(pricer_zcb_brl, scenario_fixed) == 10.0

        c_zcb_usd = FinancialDSL.Core.ZCB(Date(2020, 1, 2), 20.0USD)
        pricer_zcb_usd = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, fvmodel, c_zcb_usd, FinancialDSL.Core.ContractAttributes())
        @test FinancialDSL.Core.price(pricer_zcb_usd, scenario_fixed) ≈ 20.0 * 2.9
    end
end

@testset "Functional Currency FixedScenario" begin
    pricing_date = Date(2018, 5, 29)
    currency_to_curves_map = Dict( "onshore" => Dict( :BRL => :PRE, :USD => :cpUSD ))
    static_model_usd = FinancialDSL.Core.StaticHedgingModel(USD, currency_to_curves_map)
    static_model_brl = FinancialDSL.Core.StaticHedgingModel(BRL, currency_to_curves_map)
    empty_provider = FinancialDSL.MarketData.EmptyMarketDataProvider()

    scenario_fixed = FinancialDSL.Core.FixedScenario()
    scenario_fixed[FinancialDSL.Core.SpotCurrency(USD)] = 2.9BRL
    scenario_fixed[FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2))] = 0.7
    scenario_fixed[FinancialDSL.Core.DiscountFactor(:cpUSD, Date(2019, 1, 2))] = 0.9

    attr_onshore_carry_none = FinancialDSL.Core.ContractAttributes(:riskfree_curves => "onshore", :carry_type => "none")

    @testset "USD spot position with BRL as functional currency" begin
        c = FinancialDSL.Core.Amount(1.0USD)
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_brl, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 2.9
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test length(exposures_result) == 1
        @test exposures_result[FinancialDSL.Core.SpotCurrency(USD)] == 2.9
    end

    @testset "USD spot position with BRL as functional currency with Scale" begin
        c = FinancialDSL.Core.Amount(2.0USD)
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_brl, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 2.0 * 2.9
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test length(exposures_result) == 1
        @test exposures_result[FinancialDSL.Core.SpotCurrency(USD)] == 2.0 * 2.9
    end

    @testset "USD Spot Worthless with BRL as functional currency" begin
        c = FinancialDSL.Core.Amount(0.0USD)
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_brl, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 0.0
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test isempty(exposures_result)
    end

    @testset "USD spot position with USD as functional currency" begin
        c = FinancialDSL.Core.Amount(1.0USD)
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_usd, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 1.0
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test isempty(exposures_result) # there are no exposures given that USD is the functional currency
    end

    @testset "USD spot position with USD as functional currency with Scale" begin
        c = FinancialDSL.Core.Amount(2.0USD)
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_usd, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 2.0
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test isempty(exposures_result) # there are no exposures given that USD is the functional currency
    end

    @testset "USD Spot Worthless with USD as functional currency" begin
        c = FinancialDSL.Core.Amount(0.0USD)
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_usd, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 0.0
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test isempty(exposures_result) # there are no exposures given that USD is the functional currency
    end

    @testset "zero-coupon USD with BRL as functional currency" begin
        c = FinancialDSL.Core.WhenAt(Date(2019, 1, 2), FinancialDSL.Core.Amount(1.0USD))
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_brl, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 2.9 * 0.9
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test length(exposures_result) == 2
        @test exposures_result[FinancialDSL.Core.SpotCurrency(USD)] == 2.9 * 0.9
        @test exposures_result[FinancialDSL.Core.DiscountFactor(:cpUSD, Date(2019, 1, 2))] == 2.9 * 0.9
    end

    @testset "zero-coupon USD with BRL as functional currency with Scale" begin
        c = FinancialDSL.Core.WhenAt(Date(2019, 1, 2), FinancialDSL.Core.Amount(2.0USD))
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_brl, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 2.0 * 2.9 * 0.9
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test length(exposures_result) == 2
        @test exposures_result[FinancialDSL.Core.SpotCurrency(USD)] == 2.0 * 2.9 * 0.9
        @test exposures_result[FinancialDSL.Core.DiscountFactor(:cpUSD, Date(2019, 1, 2))] == 2.0 * 2.9 * 0.9
    end

    @testset "zero-coupon USD Worthless with BRL as functional currency" begin
        c = FinancialDSL.Core.WhenAt(Date(2019, 1, 2), FinancialDSL.Core.Amount(0.0USD))
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_brl, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 0.0
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test isempty(exposures_result)
    end

    @testset "zero-coupon USD at maturity" begin
        c = FinancialDSL.Core.WhenAt(pricing_date, FinancialDSL.Core.Amount(1.0USD))
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_brl, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 2.9
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test length(exposures_result) == 1
        @test exposures_result[FinancialDSL.Core.SpotCurrency(USD)] == 2.9
    end

    @testset "zero-coupon USD at maturity with Scale" begin
        c = FinancialDSL.Core.WhenAt(pricing_date, FinancialDSL.Core.Amount(2.0USD))
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_brl, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 2.0 * 2.9
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test length(exposures_result) == 1
        @test exposures_result[FinancialDSL.Core.SpotCurrency(USD)] == 2.0 * 2.9
    end

    @testset "zero-coupon USD Worthless at maturity" begin
        c = FinancialDSL.Core.WhenAt(pricing_date, FinancialDSL.Core.Amount(0.0USD))
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_brl, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 0.0
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test isempty(exposures_result)
    end

    @testset "zero-coupon USD after maturity" begin
        c = FinancialDSL.Core.WhenAt(pricing_date - Dates.Day(1), FinancialDSL.Core.Amount(1.0USD))
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_brl, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 0.0
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test isempty(exposures_result)
    end

    @testset "zero-coupon USD after maturity with Scale" begin
        c = FinancialDSL.Core.WhenAt(pricing_date - Dates.Day(1), FinancialDSL.Core.Amount(2.0USD))
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_brl, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 0.0
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test isempty(exposures_result)
    end

    @testset "zero-coupon USD Worthless after maturity" begin
        c = FinancialDSL.Core.WhenAt(pricing_date - Dates.Day(1), FinancialDSL.Core.Amount(0.0USD))
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_brl, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 0.0
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test isempty(exposures_result)
    end

    @testset "zero-coupon USD with USD as functional currency" begin
        c = FinancialDSL.Core.WhenAt(Date(2019, 1, 2), FinancialDSL.Core.Amount(1.0USD))
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_usd, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 0.9
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test length(exposures_result) == 1
        @test exposures_result[FinancialDSL.Core.DiscountFactor(:cpUSD, Date(2019, 1, 2))] == 0.9 # functional currency is USD, so we get exposures only to cpUSD
    end

    @testset "zero-coupon USD with USD as functional currency with Scale" begin
        c = FinancialDSL.Core.WhenAt(Date(2019, 1, 2), FinancialDSL.Core.Amount(2.0USD))
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_usd, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 2.0 * 0.9
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test length(exposures_result) == 1
        @test exposures_result[FinancialDSL.Core.DiscountFactor(:cpUSD, Date(2019, 1, 2))] == 2.0 * 0.9 # functional currency is USD, so we get exposures only to cpUSD
    end

    @testset "zero-coupon USD Worthless with USD as functional currency" begin
        c = FinancialDSL.Core.WhenAt(Date(2019, 1, 2), FinancialDSL.Core.Amount(0.0USD))
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_usd, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 0
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test isempty(exposures_result)
    end

    @testset "BRL Spot with BRL as functional currency" begin
        c = FinancialDSL.Core.Amount(1.0BRL)
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_brl, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 1.0
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test isempty(exposures_result)
    end

    @testset "BRL Spot with BRL as functional currency with Scale" begin
        c = FinancialDSL.Core.Amount(2.0BRL)
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_brl, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 2.0
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test isempty(exposures_result)
    end

    @testset "BRL Spot Worthless with BRL as functional currency" begin
        c = FinancialDSL.Core.Amount(0.0BRL)
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_brl, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 0.0
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test isempty(exposures_result)
    end

    @testset "BRL Spot with USD as functional currency" begin
        c = FinancialDSL.Core.Amount(1.0BRL)
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_usd, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 1.0 / 2.9 # 1 BRL cotado em USD
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test length(exposures_result) == 1
        @test exposures_result[FinancialDSL.Core.SpotCurrency(BRL)] == 1.0 / 2.9
    end

    @testset "zero-coupon BRL with BRL as functional currency" begin
        c = FinancialDSL.Core.WhenAt(Date(2019, 1, 2), FinancialDSL.Core.Amount(1.0BRL))
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_brl, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == 0.7
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test length(exposures_result) == 1
        @test exposures_result[FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2))] == 0.7
    end

    @testset "zero-coupon BRL with USD as functional currency" begin
        c = FinancialDSL.Core.WhenAt(Date(2019, 1, 2), FinancialDSL.Core.Amount(1.0BRL))
        pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_usd, c, attr_onshore_carry_none)
        p = FinancialDSL.Core.price(pricer, scenario_fixed)
        @test p == (1.0 / 2.9) * 0.7
        exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
        @test length(exposures_result) == 2
        @test exposures_result[FinancialDSL.Core.SpotCurrency(BRL)] == (1.0 / 2.9) * 0.7
        @test exposures_result[FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 1, 2))] == (1.0 / 2.9) * 0.7
    end
end # @testset "Functional Currency FixedScenario"

@testset "FixedCashRiskFactor, FixedNonCashRiskFactor" begin
    pricing_date = Date(2018, 5, 29)
    rf_pre = FinancialDSL.Core.DiscountFactor(:PRE, Date(2020, 12, 1))
    currency_to_curves_map = Dict( "onshore" => Dict( :BRL => :PRE ))
    static_model_brl = FinancialDSL.Core.StaticHedgingModel(BRL, currency_to_curves_map)
    empty_provider = FinancialDSL.MarketData.EmptyMarketDataProvider()

    scenario_fixed = FinancialDSL.Core.FixedScenario()
    scenario_fixed[rf_pre] = 0.7
    attr_onshore_carry_none = FinancialDSL.Core.ContractAttributes(:riskfree_curves => "onshore", :carry_type => "none")

    rf_fixed = FinancialDSL.Core.FixedNonCashRiskFactor(FinancialDSL.Core.DiscountFactor(:BASIS, Date(2020, 12, 1)), 1.0)
    c = FinancialDSL.Core.Scale(rf_fixed, FinancialDSL.Core.WhenAt(Date(2020, 12, 1), FinancialDSL.Core.Amount(1.0BRL)))

    pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_brl, c, attr_onshore_carry_none)
    p = FinancialDSL.Core.price(pricer, scenario_fixed)
    @test p ≈ 0.7

    exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
    #println(exposures_result)

    @test exposures_result[rf_pre] ≈ 0.7
    @test exposures_result[rf_fixed] ≈ 0.7

    # generates two DiscountFactor exposures
    rf_fixed_fwd = FinancialDSL.Core.FixedNonCashRiskFactor(FinancialDSL.Core.DiscountFactorForward(:BASIS, Date(2019,12,1), Date(2020, 12, 1)), 1.0)
    c_fwd = FinancialDSL.Core.Scale(rf_fixed_fwd, FinancialDSL.Core.WhenAt(Date(2020, 12, 1), FinancialDSL.Core.Amount(1.0BRL)))
    pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_brl, c_fwd, attr_onshore_carry_none)
    exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
    #println(exposures_result)
    @test length(exposures_result) == 3
    @test haskey(exposures_result, FinancialDSL.Core.FixedNonCashRiskFactor(FinancialDSL.Core.DiscountFactor(:BASIS, Date(2019,12,1)), 1.0))
    @test haskey(exposures_result, FinancialDSL.Core.FixedNonCashRiskFactor(FinancialDSL.Core.DiscountFactor(:BASIS, Date(2020,12,1)), 1.0))

    # generate one DiscountFactor exposure (first is dropped
    # because forward start date == pricing_date)
    rf_fixed_fwd2 = FinancialDSL.Core.FixedNonCashRiskFactor(FinancialDSL.Core.DiscountFactorForward(:BASIS, pricing_date, Date(2020, 12, 1)), 1.0)
    c_fwd = FinancialDSL.Core.Scale(rf_fixed_fwd2, FinancialDSL.Core.WhenAt(Date(2020, 12, 1), FinancialDSL.Core.Amount(1.0BRL)))
    pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model_brl, c_fwd, attr_onshore_carry_none)
    exposures_result = FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, scenario_fixed)
    #println(exposures_result)
    @test length(exposures_result) == 2
    @test !haskey(exposures_result, FinancialDSL.Core.FixedNonCashRiskFactor(FinancialDSL.Core.DiscountFactor(:BASIS, pricing_date), 1.0))
    @test haskey(exposures_result, FinancialDSL.Core.FixedNonCashRiskFactor(FinancialDSL.Core.DiscountFactor(:BASIS, Date(2020,12,1)), 1.0))

end

@testset "Cashflow projection" begin

    @testset "Both Contract" begin
        c = FinancialDSL.Core.Both(
            FinancialDSL.Core.WhenAt(Date(2019, 8, 2), FinancialDSL.Core.Unit(BRL)),
            FinancialDSL.Core.WhenAt(Date(2019, 8, 1), FinancialDSL.Core.Unit(BRL)))

        @test !FinancialDSL.Core.is_expired(c, Date(2019, 7, 2))
        @test FinancialDSL.Core.is_expired(c, Date(2019, 8, 3))
        @test FinancialDSL.Core.is_expired_or_expires_today(c, Date(2019, 8, 2))
    end

    @testset "FixedIncomeContract" begin
        c = FinancialDSL.Core.FixedIncomeContract()
        @test ismissing(FinancialDSL.Core.get_horizon(c))
        @test !FinancialDSL.Core.is_expired(c, Dates.today())
        @test !FinancialDSL.Core.is_expired_or_expires_today(c, Dates.today())

        push!(c, FinancialDSL.Core.Events.Amort(Date(2019, 2, 1), 2.0, BRL))
        @test FinancialDSL.Core.get_horizon(c) == Date(2019, 2, 1)
    end

    @testset "expires_at_maturity" begin
        c = FinancialDSL.Core.WhenAt(
                Date(2020, 2, 1),
                FinancialDSL.Core.Both(
                        FinancialDSL.Core.WhenAt(Date(2021, 2, 1), FinancialDSL.Core.Amount(1.0USD)),
                        FinancialDSL.Core.Give(FinancialDSL.Core.Amount(5.5BRL))
                    )
            )

        @test FinancialDSL.Core.get_horizon(c) == Date(2021, 2, 1)

        c = FinancialDSL.Core.WhenAt(
                Date(2020, 2, 1),
                FinancialDSL.Core.Both(
                        FinancialDSL.Core.WhenAt(Date(2021, 2, 1), FinancialDSL.Core.Amount(1.0USD)),
                        FinancialDSL.Core.Give(FinancialDSL.Core.Amount(5.5BRL))
                    ),
                expires_at_maturity=true
            )

        @test FinancialDSL.Core.get_horizon(c) == Date(2020, 2, 1)
    end
end

@testset "FixedIncome" begin
    c = FinancialDSL.Core.FixedIncomeEvent(:AMORT, FinancialDSL.Core.WhenAt(Date(2019, 2, 1), FinancialDSL.Core.Amount(1.0BRL)))
    @test FinancialDSL.Core.event_symbol(c) == :AMORT
    @test c.c == FinancialDSL.Core.WhenAt(Date(2019, 2, 1), FinancialDSL.Core.Amount(1.0BRL))
    @test c == FinancialDSL.Core.FixedIncomeEvent(:AMORT, Date(2019, 2, 1), 1.0, BRL)

    c2 = FinancialDSL.Core.FixedIncomeEvent(:INTEREST, FinancialDSL.Core.WhenAt(Date(2019, 2, 1), FinancialDSL.Core.Amount(0.5BRL)))
    contract = FinancialDSL.Core.FixedIncomeContract([c, c2])

    pricing_date = Date(2018, 5, 29)
    currency_to_curves_map = Dict( "onshore" => Dict( :BRL => :PRE, :USD => :cpUSD ))
    static_model = FinancialDSL.Core.StaticHedgingModel(BRL, currency_to_curves_map)
    attr = FinancialDSL.Core.ContractAttributes(:riskfree_curves => "onshore", :carry_type => "none")
    empty_provider = FinancialDSL.MarketData.EmptyMarketDataProvider()

    pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model, contract, attr)

    scenario_fixed = FinancialDSL.Core.FixedScenario()
    scenario_fixed[FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 2, 1))] = 0.9
    @test FinancialDSL.Core.price(pricer, scenario_fixed) == 1.5*0.9
end

@testset "Swap" begin
    c = FinancialDSL.Core.FixedIncomeEvent(:AMORT, FinancialDSL.Core.WhenAt(Date(2019, 2, 1), FinancialDSL.Core.Amount(1.0BRL)))
    c2 = FinancialDSL.Core.FixedIncomeEvent(:INTEREST, FinancialDSL.Core.WhenAt(Date(2019, 2, 1), FinancialDSL.Core.Amount(0.5BRL)))
    swap_leg = FinancialDSL.Core.FixedIncomeContract([c, c2])
    swap = FinancialDSL.Core.SwapContract(swap_leg, swap_leg)

    pricing_date = Date(2018, 5, 29)
    currency_to_curves_map = Dict( "onshore" => Dict( :BRL => :PRE, :USD => :cpUSD ))
    static_model = FinancialDSL.Core.StaticHedgingModel(BRL, currency_to_curves_map)
    attr = FinancialDSL.Core.ContractAttributes(:riskfree_curves => "onshore", :carry_type => "none")
    empty_provider = FinancialDSL.MarketData.EmptyMarketDataProvider()

    pricer = FinancialDSL.Core.compile_pricer(empty_provider, pricing_date, static_model, swap, attr)

    scenario_fixed = FinancialDSL.Core.FixedScenario()
    scenario_fixed[FinancialDSL.Core.DiscountFactor(:PRE, Date(2019, 2, 1))] = 0.9
    @test FinancialDSL.Core.price(pricer, scenario_fixed) == 0.0
    @test FinancialDSL.Core.get_horizon(swap) == Date(2019, 2, 1)
end

@testset "Repeated risk-factors" begin
    currency_to_curves_map = Dict( "onshore" => Dict( :BRL => :PRE, :USD => :cpUSD ))
    model = FinancialDSL.Core.StaticHedgingModel(BRL, currency_to_curves_map)
    empty_provider = FinancialDSL.MarketData.EmptyMarketDataProvider()
    dt_analise = Date(2018, 5, 1)
    c = FinancialDSL.Core.Both(FinancialDSL.Core.ZCB(Date(2030, 2, 1), 800USD), FinancialDSL.Core.ZCB(Date(2040, 2, 1), 1000USD))
    pricer = FinancialDSL.Core.compile_pricer(empty_provider, dt_analise, model, c, FinancialDSL.Core.ContractAttributes("riskfree_curves" => "onshore", "carry_type" => "none"))

    scenario_fixed = FinancialDSL.Core.FixedScenario()
    scenario_fixed[FinancialDSL.Core.SpotCurrency(USD)] = 3.5BRL
    scenario_fixed[FinancialDSL.Core.DiscountFactor(:cpUSD, Date(2030, 2, 1))] = 0.7
    scenario_fixed[FinancialDSL.Core.DiscountFactor(:cpUSD, Date(2040, 2, 1))] = 0.4
    @test FinancialDSL.Core.price(pricer, scenario_fixed) == 3.5 * 800 * 0.7 + 3.5 * 1000 * 0.4
end

@testset "project cashflows" begin
    c = FinancialDSL.Core.FixedIncomeEvent(:AMORT, FinancialDSL.Core.WhenAt(Date(2020, 2, 1), FinancialDSL.Core.Amount(10.0BRL)))
    c2 = FinancialDSL.Core.FixedIncomeEvent(:INTEREST, FinancialDSL.Core.WhenAt(Date(2019, 2, 1), FinancialDSL.Core.Amount(5.0BRL)))
    contract = FinancialDSL.Core.FixedIncomeContract([c, c2])

    pricing_date = Date(2018, 5, 29)
    currency_to_curves_map = Dict( "onshore" => Dict( :BRL => :PRE, :USD => :cpUSD ))
    static_model = FinancialDSL.Core.StaticHedgingModel(BRL, currency_to_curves_map)
    fv_model = FinancialDSL.Core.FutureValueModel(static_model)
    attr = FinancialDSL.Core.ContractAttributes("riskfree_curves" => "onshore", "carry_type" => "none")
    empty_provider = FinancialDSL.MarketData.EmptyMarketDataProvider()

    empty_scenario = FinancialDSL.Core.FixedScenario()
    pricer = FinancialDSL.Core.compile_cashflow_pricer(empty_provider, pricing_date, fv_model, contract, attr)
    @test FinancialDSL.Core.get_functional_currency(pricer) == BRL
    for cf in FinancialDSL.Core.eachcashflow(pricer, empty_scenario)
        if cf.event == :AMORT
            @test cf.maturity == Date(2020, 2, 1)
            @test cf.value == 10.0
            @test cf.currency == BRL
        elseif cf.event == :INTEREST
            @test cf.maturity == Date(2019, 2, 1)
            @test cf.value == 5.0
            @test cf.currency == BRL
        else
            @test false
        end
    end

    @test FinancialDSL.Core.price(pricer, empty_scenario) ≈ 15.0
    @test isempty(FinancialDSL.Core.riskfactors(pricer))
    @test isempty(FinancialDSL.Core.exposures(FinancialDSL.Core.DeltaNormalExposuresMethod(), pricer, empty_scenario))
end

@testset "Black-Scholes" begin
    include("test_core_black_scholes.jl")
end

@testset "Binomial Daily" begin
    include("test_core_binomial_daily.jl")
end


text:
	X	Y	Z

1	5399	5770	3362

2	4564	1577	5428

3	6257	7290	6138

4	3912	5163	2451

5	1426	1874	3944

6	3896	9827	7006

ext: jl

max_stars_repo_name: ethansaxenian/RosettaDecode

max_issues_repo_name: ethansaxenian/RosettaDecode

max_forks_repo_name: ethansaxenian/RosettaDecode


text:
using PyPlot
using Statistics
using LinearAlgebra

# Random data
d = 3
N = 100

x = randn(N)'
y = [0.25*xi + 0.13 + 0.1*(randn()-0.5) for xi in x]
z = [0.37*xi + 0.74 + 0.1*(randn()-0.5) for xi in x]

R = vcat(x,y,z)

# Normalization
R = (R .- mean(R,dims=2))./std(R,dims=2)

# Correlation matrix
C = R*R'/(N-1)

# Eigenstates
va = eigvals(C)
ve = eigvecs(C)

# Plot data and axes
if (false)
    pygui(true)
    fig = figure()
    ax = fig.gca(projection="3d")
    ax.scatter(R[1,:],R[2,:],R[3,:])

    mx = mean(R[1,:])
    my = mean(R[2,:])
    mz = mean(R[3,:])

    ax.quiver([mx],[my],[mz],[ve[1,1]],[ve[2,1]],[ve[3,1]],color="red")
    ax.quiver([mx],[my],[mz],[ve[1,2]],[ve[2,2]],[ve[3,2]],color="red")
    ax.quiver([mx],[my],[mz],[ve[1,3]],[ve[2,3]],[ve[3,3]],color="red")
    legend(["","v_1","v_2","v_3"])
    show()
end

# Plot explained variance
if (false)
    R = rand(100,100)
    R = (R .- mean(R,dims=2))./std(R,dims=2)
    C = R*R'/99
    va = eigvals(C)

    va = reverse(va)
    cs = sum(va)
    PEV = 100*va./cs
    CPEV = 100*cumsum(va)./cs

    plot(PEV,"o-")
    xlabel("Eigenvalue number")
    ylabel("PEV [%]")

    pl = twinx()
    plot(CPEV,"s-",color="orange")
    ylabel("CPEV [%]")
    show()
end

# Plot projected data
if (true)
    W = hcat(ve[:,1],ve[:,2])
    R = W'*R
    scatter(R[1,:],R[2,:])
    show()
end

max_stars_repo_name: StxGuy/MachineLearning

max_issues_repo_name: StxGuy/MachineLearning

max_forks_repo_name: StxGuy/MachineLearning


text:
module FlowOverCircle

using WaterLily, LinearAlgebra, ProgressMeter, MLUtils
using NeuralOperators, Flux, GeometricFlux, Graphs
using CUDA, FluxTraining, BSON

function circle(n, m; Re=250) # copy from [WaterLily](https://github.com/weymouth/WaterLily.jl)
    # Set physical parameters
    U, R, center = 1., m/8., [m/2, m/2]
    ν = U * R / Re

    body = AutoBody((x,t) -> LinearAlgebra.norm2(x .- center) - R)
    Simulation((n+2, m+2), [U, 0.], R; ν, body)
end

function gen_data(ts::AbstractRange)
    @info "gen data... "
    p = Progress(length(ts))

    n, m = 3(2^5), 2^6
    circ = circle(n, m)

    𝐩s = Array{Float32}(undef, 1, n, m, length(ts))
    for (i, t) in enumerate(ts)
        sim_step!(circ, t)
        𝐩s[1, :, :, i] .= Float32.(circ.flow.p)[2:end-1, 2:end-1]

        next!(p)
    end

    return 𝐩s
end

function get_dataloader(; ts::AbstractRange=LinRange(100, 11000, 10000), ratio::Float64=0.95, batchsize=100, flatten=false)
    data = gen_data(ts)
    𝐱, 𝐲 = data[:, :, :, 1:end-1], data[:, :, :, 2:end]
    n = length(ts) - 1

    if flatten
        𝐱, 𝐲 = reshape(𝐱, 1, :, n), reshape(𝐲, 1, :, n)
    end

    data_train, data_test = splitobs(shuffleobs((𝐱, 𝐲)), at=ratio)

    loader_train = DataLoader(data_train, batchsize=batchsize, shuffle=true)
    loader_test = DataLoader(data_test, batchsize=batchsize, shuffle=false)

    return loader_train, loader_test
end

function train(; cuda=true, η₀=1f-3, λ=1f-4, epochs=50)
    if cuda && CUDA.has_cuda()
        device = gpu
        CUDA.allowscalar(false)
        @info "Training on GPU"
    else
        device = cpu
        @info "Training on CPU"
    end

    model = MarkovNeuralOperator(ch=(1, 64, 64, 64, 64, 64, 1), modes=(24, 24), σ=gelu)
    data = get_dataloader()
    optimiser = Flux.Optimiser(WeightDecay(λ), Flux.ADAM(η₀))
    loss_func = l₂loss

    learner = Learner(
        model, data, optimiser, loss_func,
        ToDevice(device, device),
        Checkpointer(joinpath(@__DIR__, "../model/"))
    )

    fit!(learner, epochs)

    return learner
end

function train_gno(; cuda=true, η₀=1f-3, λ=1f-4, epochs=50)
    if cuda && CUDA.has_cuda()
        device = gpu
        CUDA.allowscalar(false)
        @info "Training on GPU"
    else
        device = cpu
        @info "Training on CPU"
    end

    featured_graph = FeaturedGraph(grid([96, 64]))
    model = Chain(
        Dense(1, 16),
        WithGraph(featured_graph, GraphKernel(Dense(2*16, 16, gelu), 16)),
        WithGraph(featured_graph, GraphKernel(Dense(2*16, 16, gelu), 16)),
        WithGraph(featured_graph, GraphKernel(Dense(2*16, 16, gelu), 16)),
        WithGraph(featured_graph, GraphKernel(Dense(2*16, 16, gelu), 16)),
        Dense(16, 1),
    )
    data = get_dataloader(batchsize=16, flatten=true)
    optimiser = Flux.Optimiser(WeightDecay(λ), Flux.ADAM(η₀))
    loss_func = l₂loss

    learner = Learner(
        model, data, optimiser, loss_func,
        ToDevice(device, device),
        Checkpointer(joinpath(@__DIR__, "../model/"))
    )

    fit!(learner, epochs)

    return learner
end

function get_model()
    model_path = joinpath(@__DIR__, "../model/")
    model_file = readdir(model_path)[end]

    return BSON.load(joinpath(model_path, model_file), @__MODULE__)[:model]
end

end # module


text:
export scan_block

function scan_block(buf::IO, mem_block::Int, mem_trace::Int, keys::Array{String,1},
                    chunk_start::Int, file::String, th_byte2sample::Dict{String, Int32})

    # Calc info about this block
    startbyte = position(buf) + chunk_start
    ntraces_block = Int(mem_block/mem_trace)
    headers = Array{BinaryTraceHeader,1}(undef, ntraces_block)
    count = 0

    # Read all headers and record end byte
    while !eof(buf) && count<ntraces_block
        count += 1
        headers[count] = read_traceheader(buf, keys, th_byte2sample)
        skip(buf, mem_trace-240)
    end
    endbyte = position(buf) + chunk_start
    headers_block = view(headers,1:count)

    # Parse headers for min/max
    summary = Dict{String, Array{Int32,1}}()
    for k in keys
        tmp = Int32.([getfield((headers_block[i]), Symbol(k)) for i in 1:count])
        summary["$k"] = [minimum(tmp); maximum(tmp)]
    end # k

    # Collect in BlockScan and return
    scan = BlockScan(file, startbyte, endbyte, summary)

    return scan
end


text:
mutable struct RegressionData
    X::Array{Float64,2}
    Y::Vector{Float64}
    w::Vector{Float64}
end

"""
    getdata(; Xdata::XData = XData(),
                         wdist::BenchmarkwDists = BinChoice(),
                         noisedist::BenchmarkNoiseDists = NoNoise(),
                         SNR::Float64 = 0.0,
                         n::Int = 100,
                         nfeatures::Int = 100,
                         sparsity::Int = 10
                )

Get regression data. Created to be stand-alone from the rest of the
benchmarking. Maybe will remove later, want user to only interface with
BenchmarkData object.
"""
function getdata(; Xdata::XData = XData(),
                         wdist::BenchmarkwDists = BinChoice(),
                         noisedist::BenchmarkNoiseDists = NoNoise(),
                         SNR::Float64 = 0.0,
                         n::Int = 100,
                         nfeatures::Int = 100,
                         sparsity::Int = 10
                        )
    bd = BenchmarkData(Xdata, wdist, noisedist, SNR, [n], nfeatures, sparsity)
    getdata(bd, 1)
end
"""
    getdata(bd::BenchmarkData, i::Int)

Get regression data, the i^th value in the range for n will be used.
"""
function getdata(bd::BenchmarkData, i::Int)
    w = getw(bd)
    X = getX(bd, i)
    # In case we are using a multivariate distribution for x
    if size(X, 2) != (bd.nfeatures)
        error("X distribution $(bd.Xdata.dist) doesn't match the number of
                features requested, $(bd.nfeatures).")
    end
    Y = X * w
    noise = getnoise(bd, Y)
    Y .+= noise
    RegressionData(X, Y, w)
end


text:
using MeasureTheory
using Documenter

pages = [
    "Introduction" => "intro.md"
    "Home" => "index.md"
    "Adding a New Measure" => "adding.md"
]

makedocs(;
    modules=[MeasureTheory],
    authors="Chad Scherrer <chad.scherrer@gmail.com> and contributors",
    repo="https://github.com/cscherrer/MeasureTheory.jl/blob/{commit}{path}#L{line}",
    sitename="MeasureTheory.jl",
    format=Documenter.HTML(;
        prettyurls=get(ENV, "CI", "false") == "true",
        canonical="https://cscherrer.github.io/MeasureTheory.jl",
        assets=String[],
    ),
    pages=pages
)

deploydocs(;
    repo="github.com/cscherrer/MeasureTheory.jl",
)


text:
using SparseArrays
using Distributions
using LinearAlgebra
using Plots
using GLM
using DataFrames
using Statistics
using Convex
using SCS
using LightGraphs
using TimerOutputs
import JSON

WEIGHT = Float32
Adj_Matrix = SparseMatrixCSC{WEIGHT, Int64}
OPINIONS = Union{Array{WEIGHT, 1}, Array{WEIGHT, 2}}
PSYCHOLOGICAL_FACTOR = Array{WEIGHT, 1}

WHITESPACE = r"\s+"
COMMA = ","

DATASETS = Dict("congress"=>WHITESPACE, "wikielections" => WHITESPACE,
                "cloister" => WHITESPACE, "highlandtribes" => WHITESPACE,
                "bitcoinotc" => COMMA, "bitcoinalpha" => COMMA,
                "twitterreferendum"=>WHITESPACE)

CENTRALITIES = Dict(
    "pagerank" => pagerank,
    #"betweeness" => betweenness_centrality,
    #"closeness" => closeness_centrality,
    "stress" => stress_centrality,
    #"radiality" => radiality_centrality
)

MARKERS = Dict(
    "complete_centrality_pagerank"   => :+,
    "complete_knapsack"              => :circle,
    "optimal"                        => :none,
    "fractional_knapsack_approx"     => :diamond,
    "complete_centrality_radiality"  => :dtriangle,
    "complete_centrality_stress"     => :hexagon,
    "greedy_approx"                  => :rect,
    "complete_centrality_closeness"  => :star4,
    "complete_centrality_betweeness" => :cross,
    "complete_greedy"                => :star5
)

COLORS = Dict(
    "complete_centrality_pagerank"   => "#A6CEE3",
    "complete_knapsack"              => "#B2DF8A",
    "optimal"                        => "#1F78B4",
    "fractional_knapsack_approx"     => "#33A02C",
    "complete_centrality_radiality"  => "#FB9A99",
    "complete_centrality_stress"     => "#FDBF6F",
    "greedy_approx"                  => "#FF7F00",
    "complete_centrality_closeness"  => "#CAB2D6",
    "complete_centrality_betweeness" => "#6A3D9A",
    "complete_greedy"                => "#E31A1C"
)

max_stars_repo_name: InzamamRahaman/SignedDegroot

max_issues_repo_name: InzamamRahaman/SignedDegroot

max_forks_repo_name: InzamamRahaman/SignedDegroot


text:
"""
    hamming(x, X)
Compute the hamming distance of `x` over a collection of solutions `X`, i.e. the minimal number of variables to switch in `x`to reach a solution.
"""
hamming(x, X) = mapreduce(y -> Distances.hamming(x,y), min, X)

"""
    minkowski(x, X, p)
"""
minkowski(x, X, p) = mapreduce(Distances.minkowski(x, y, p), min, X)

"""
    manhattan(x, X)
"""
manhattan(x, X) = mapreduce(y -> Distances.cityblock(x, y), min, X)

"""
    weigths_bias(x)
A metric that bias `x` towards operations with a lower bit. Do not affect the main metric.
"""
weigths_bias(x) = sum(p -> p[1] * log2(1. + p[2]), enumerate(x)) / length(x)^4


text:
using ARCTR
using LinearAlgebra
using Test
using Printf
using NLPModels
using Stopping

# test all solvers with the well known Rosenbrock test function
include("rosenbrock.jl")

global nbsolver = 0
for solver in ALL_solvers
    global nbsolver += 1
    nlp = ADNLPModel(extrosnb, [-1.0, -1.0], name = "rosenbrock")
    nlpatx = NLPAtX([-1.0, -1.0])
    nlpstop = NLPStopping(nlp, Stopping.unconstrained, nlpatx)
    println(nbsolver,"  ",solver)
    final_nlp_at_x, optimal = solver(nlp, nlpstop, verbose = true)
    @test optimal
    reset!(nlp)
end


text:
function parse_header(io)
    natom = nbond = nangle = ndihedral = nimproper = 0
    ntypes = nbtypes = natypes = ndtypes = nitypes = 0

    while !isuppercase(peek(io, Char))
        datastr = readline(io) |> strip
        isempty(datastr) && continue
        if endswith(datastr, "atoms")
            natom = parse(Int, rstrip(!isdigit, datastr))
        elseif endswith(datastr, "bonds")
            nbond = parse(Int, rstrip(!isdigit, datastr))
        elseif endswith(datastr, "angles")
            nangle = parse(Int, rstrip(!isdigit, datastr))
        elseif endswith(datastr, "dihedrals")
            ndihedral = parse(Int, rstrip(!isdigit, datastr))
        elseif endswith(datastr, "impropers")
            nimproper = parse(Int, rstrip(!isdigit, datastr))
        elseif endswith(datastr, "atom types")
            ntypes = parse(Int, rstrip(!isdigit, datastr))
        elseif endswith(datastr, "bond types")
            nbtypes = parse(Int, rstrip(!isdigit, datastr))
        elseif endswith(datastr, "angle types")
            natypes = parse(Int, rstrip(!isdigit, datastr))
        elseif endswith(datastr, "dihedral types")
            ndtypes = parse(Int, rstrip(!isdigit, datastr))
        elseif endswith(datastr, "improper types")
            nitypes = parse(Int, rstrip(!isdigit, datastr))
        else
            @warn "Unused header line: $datastr"
        end
    end
    natom, nbond, nangle, ndihedral, nimproper,
    ntypes, nbtypes, natypes, ndtypes, nitypes
end

function read_masses!(container, io::IO, natoms::Integer)
    readline(io)

    for _ in 1:natoms
        ln = readline(io)
        if isempty(ln)
            error("Not all masses are given")
        end
        is, ms = split(ln)
        i = parse(Int16, is)
        m = parse(Float64, ms)
        container[i] = m
    end
    return container
end

function read_pcoeff!(pair_coeff, types, io::IO, natoms::Integer)
    readline(io)

    ntypes = 0
    for ia in 1:natoms
        ln = readline(io)
        if isempty(ln)
            error("Not all pair coeffs are given")
        end
        is, εs, σs = split(ln)
        i = parse(Int16, is)
        ε = parse(Float64, εs)
        σ = parse(Float64, σs)
        type = findfirst(==((ε, σ)), pair_coeff)
        if type !== nothing
            types[ia] = type
        else
            ntypes += 1
            push!(pair_coeff, (ε, σ))
            types[ia] = ntypes
        end
    end
    return types
end

function read_bcoeff!(bond_coeff, btypes, io::IO, nbonds::Integer)
    readline(io)

    ntypes = 0
    for ib in 1:nbonds
        ln = readline(io)
        if isempty(ln)
            error("Not all bond coeffs are given")
        end
        is, ks, rs = split(ln)
        i = parse(Int16, is)
        k = parse(Float64, ks)
        r0 = parse(Float64, rs)
        type = findfirst(==((k, r0)), bond_coeff)
        if k == 0
            btypes[ib] = 0
        elseif type !== nothing
            btypes[ib] = type
        else
            ntypes += 1
            push!(bond_coeff, (k, r0))
            btypes[ib] = ntypes
        end
    end
    return btypes
end

function read_acoeff!(angle_coeff, atypes, io::IO, nangles::Integer)
    readline(io)

    ntypes = 0
    for ia in 1:nangles
        ln = readline(io)
        if isempty(ln)
            error("Not all angle coeffs are given")
        end
        is, ks, θs = split(ln)
        i = parse(Int16, is)
        k = parse(Float64, ks)
        θ0 = parse(Float64, θs)
        type = findfirst(==((k, θ0)), angle_coeff)
        if k == 0
            atypes[ia] = 0
        elseif type !== nothing
            atypes[ia] = type
        else
            ntypes += 1
            push!(angle_coeff, (k, θ0))
            atypes[ia] = ntypes
        end
    end
    return atypes
end

function read_dcoeff!(dihed_coeff, dtypes, io::IO, ndihed::Integer)
    readline(io)

    ntypes = 0
    for id in 1:ndihed
        ln = readline(io)
        if isempty(ln)
            error("Not all dihedral coeffs are given")
        end
        is, c1s, c2s, c3s, c4s = split(ln)
        i = parse(Int16, is)
        c1, c2, c3, c4 = parse.(Float64, (c1s, c2s, c3s, c4s))

        type = findfirst(==((c1, c2, c3, c4)), dihed_coeff)
        if all(iszero, (c1, c2, c3, c4))
            dtypes[id] = 0
        elseif type !== nothing
            dtypes[id] = type
        else
            ntypes += 1
            push!(dihed_coeff, (c1, c2, c3, c4))
            dtypes[id] = ntypes
        end
    end
    return dtypes
end

function read_icoeff!(improper_coeff, itypes, io::IO, nimproper::Integer)
    readline(io)

    ntypes = 0
    for ii in 1:nimproper
        ln = readline(io)
        if isempty(ln)
            error("Not all improper coeffs are given")
        end
        is, ks, ds, ns = split(ln)
        i = parse(Int16, is)
        k = parse(Float64, ks)
        d = parse(Int8, ds)
        n = parse(Int8, ns)

        type = findfirst(==((k, d, n)), improper_coeff)
        if k == 0
            itypes[ii] = 0
        elseif type !== nothing
            itypes[ii] = type
        else
            ntypes += 1
            push!(improper_coeff, (k, d, n))
            itypes[ii] = ntypes
        end
    end
    return itypes
end

function read_atoms!(coord, charge, io::IO, natoms::Integer)
    readline(io)

    for _ in 1:natoms
        ln = readline(io)
        if isempty(ln)
            error("Missing atoms")
        end
        is, ms, ts, qs, xs, ys, zs = split(ln)
        i, type = parse.(Int16, (is, ts))
        q, x, y, z = parse.(Float64, (qs, xs, ys, zs))
        charge[i] = q
        coord[i] = (x, y, z)
    end

    total_charge = sum(charge)
    if abs(total_charge) > natoms * eps(Float64)
        @warn "Total charge is non-zero" charge=total_charge
    end

    return coord
end

function read_bonds!(bonds, io::IO, nbonds::Integer, bond_map)
    readline(io)

    for _ in 1:nbonds
        ln = readline(io)
        if isempty(ln)
            error("Missing bonds")
        end
        is, ts, a1s, a2s = split(ln)
        i, type, a1, a2 = parse.(Int16, (is, ts, a1s, a2s))
        type = bond_map[type]
        type > 0 && push!(bonds, (a1, a2) => type)
    end
    return bonds
end

function read_angles!(angles, io::IO, nangles::Integer, angle_map)
    readline(io)

    for _ in 1:nangles
        ln = readline(io)
        if isempty(ln)
            error("Missing angles")
        end
        is, ts, a1s, a2s, a3s = split(ln)
        i, type, a1, a2, a3 = parse.(Int16, (is, ts, a1s, a2s, a3s))
        type = angle_map[type]
        type > 0 && push!(angles, (a1, a2, a3) => type)
    end
    return angles
end

function read_dihed!(dihed, io::IO, ndihed::Integer, dihed_map)
    readline(io)

    for _ in 1:ndihed
        ln = readline(io)
        if isempty(ln)
            error("Missing dihedrals")
        end
        is, ts, a1s, a2s, a3s, a4s = split(ln)
        i, type, a1, a2, a3, a4 = parse.(Int16, (is, ts, a1s, a2s, a3s, a4s))
        type = dihed_map[type]
        type > 0 && push!(dihed, (a1, a2, a3, a4) => type)
    end
    return dihed
end

function read_impropers!(improper, io::IO, nimproper::Integer, improper_map)
    readline(io)

    for _ in 1:nimproper
        ln = readline(io)
        if isempty(ln)
            error("Missing impropers")
        end
        is, ts, a1s, a2s, a3s, a4s = split(ln)
        i, type, a1, a2, a3, a4 = parse.(Int16, (is, ts, a1s, a2s, a3s, a4s))
        type = improper_map[type]
        type > 0 && push!(improper, (a1, a2, a3, a4) => type)
    end
    return improper
end


text:
using MosimoBase: Vector3s

import ..Types: AbstractIntegrator, current_positions, current_velocities, set_state!

struct VerletIntegrator{M <: Function, F <: Function} <: AbstractIntegrator{M, F}
    positions::Vector3s
    velocities::Vector3s
    timestep::Float64

    mass_function::M
    force_function::F

    forces::Vector3s
end

function VerletIntegrator(r, v, dt, m, f)
    N = length(r)
    @assert N === length(v)
    fs = f(r)
    @assert N === length(fs)
    VerletIntegrator{typeof(m), typeof(f)}(r, v, dt, m, f, fs)
end

current_positions(vi::VerletIntegrator) = vi.positions
current_velocities(vi::VerletIntegrator) = vi.velocities

function set_state!(vi::VerletIntegrator, rs::Vector3s, vs::Vector3s)
    vi.positions .= rs
    vi.velocities .= vs
    vi
end


text:
# modified example from GradDescent.jl documentation
using GradDescent
using Yota
using Statistics
using Random

obj(Y, X, b) = mean((Y .- X * b) .^ 2.0) # objective to minimize

function main()
    Random.seed!(1) # set seed
    n = 1000 # number of observations
    d = 10   # number of covariates
    X = randn(n, d) # simulated covariates
    b = randn(d)    # generated coefficients
    ϵ = randn(n) * 0.1 # noise
    Y = X * b + ϵ # observed outcome

    epochs = 100 # number of epochs

    θ = randn(d) # initialize model parameters
    opt = Adam(α=1.0)  # initalize optimizer with learning rate 1.0

    for i in 1:epochs
        val, g = grad(obj, Y, X, θ)
        println("Epoch: $i; loss = $val")

        δ = update(opt, g[3])
        θ -= δ
    end
end


text:
# Test for the integrator methods, without outputs.
@testset "Integrator" begin
    ###### Float64 ######
    # Initial Conditions for Float64 version
    H = [3,1,1]
    n = 3
    t0 = 7257.93115525
    elements = readdlm("elements.txt", ',')
    # Increase mass of inner planets:
    elements[2,1] *= 100.0
    elements[3,1] *= 100.0
    # Set Ωs to 0.0
    elements[:,end] .= 0.0
    # Generate ICs
    ic = ElementsIC(t0, H, elements[1:n,:])

    # Setup State and tilt orbits
    function perturb!(s::State{<:AbstractFloat})
    s.x[2,1] = 5e-1 * sqrt(s.x[1,1]^2 + s.x[3,1]^2)
    s.x[2,2] = -5e-1 * sqrt(s.x[1,2]^2 + s.x[3,2]^2)
    s.x[2,3] = -5e-1 * sqrt(s.x[1,2]^2 + s.x[3,2]^2)
    s.v[2,1] = 5e-1 * sqrt(s.v[1,1]^2 + s.v[3,1]^2)
    s.v[2,2] = -5e-1 * sqrt(s.v[1,2]^2 + s.v[3,2]^2)
    s.v[2,3] = -5e-1 * sqrt(s.v[1,2]^2 + s.v[3,2]^2)
    return
    end

    s0 = State(ic)
    perturb!(s0)

    # Setup integrator
    h  = 0.05
    nstep = 100
    tmax = nstep * h
    AHL21 = Integrator(ahl21!, h, t0, tmax)

    # Integrate
    AHL21(s0)
    ####################

    ##### BigFloat #####
    t0_big = big(t0)
    elements_big = big.(elements)
    ic_big = ElementsIC(t0_big, H, elements_big)

    s_big = State(ic_big)
    perturb!(s_big)

    h_big = big(h)
    tmax_big = nstep * h_big
    AHL21_big = Integrator(ahl21!, h_big, t0_big, tmax_big)

    AHL21_big(s_big, grad=false)
    ####################

    ## Numerical Derivatives ##
    # Vary the initial parameters of planet j:
    n = 3
    dlnq = big(1e-20)
    jac_step_num = zeros(BigFloat, 7 * n, 7 * n)
    for j = 1:n
        # Vary the initial phase-space elements:
        for jj = 1:3
            # Position derivatives:
            sm = deepcopy(State(ic_big))
            perturb!(sm)
            dq = dlnq * sm.x[jj,j]
            if sm.x[jj,j] != 0.0
                sm.x[jj,j] -=  dq
            else
                dq = dlnq
                sm.x[jj,j] = -dq
            end
            AHL21_big(sm, grad=false)

            sp = deepcopy(State(ic_big))
            perturb!(sp)
            dq = dlnq * sp.x[jj,j]
            if sp.x[jj,j] != 0.0
                sp.x[jj,j] +=  dq
            else
                dq = dlnq
                sp.x[jj,j] = dq
            end
            AHL21_big(sp, grad=false)

            # Now x & v are final positions & velocities after time step
            for i = 1:n
                for k = 1:3
                    jac_step_num[(i - 1) * 7 +  k,(j - 1) * 7 + jj] = .5 * (sp.x[k,i] - sm.x[k,i]) / dq
                    jac_step_num[(i - 1) * 7 + 3 + k,(j - 1) * 7 + jj] = .5 * (sp.v[k,i] - sm.v[k,i]) / dq
                end
            end

            # Next, velocity derivatives:
            sm = deepcopy(State(ic_big))
            perturb!(sm)
            dq = dlnq * sm.v[jj,j]
            if sm.v[jj,j] != 0.0
                sm.v[jj,j] -=  dq
            else
                dq = dlnq
                sm.v[jj,j] = -dq
            end
            AHL21_big(sm, grad=false)

            sp = deepcopy(State(ic_big))
            perturb!(sp)
            dq = dlnq * sp.v[jj,j]
            if sp.v[jj,j] != 0.0
                sp.v[jj,j] +=  dq
            else
                dq = dlnq
                sp.v[jj,j] = dq
            end
            AHL21_big(sp;grad=false)

            for i = 1:n
                for k = 1:3
                    jac_step_num[(i - 1) * 7 +  k,(j - 1) * 7 + 3 + jj] = .5 * (sp.x[k,i] - sm.x[k,i]) / dq
                    jac_step_num[(i - 1) * 7 + 3 + k,(j - 1) * 7 + 3 + jj] = .5 * (sp.v[k,i] - sm.v[k,i]) / dq
                end
            end
        end

        # Now vary mass of planet:
        sm = deepcopy(State(ic_big))
        perturb!(sm)
        dq = sm.m[j] * dlnq
        sm.m[j] -= dq
        AHL21_big(sm;grad=false)

        sp = deepcopy(State(ic_big))
        perturb!(sp)
        dq = sp.m[j] * dlnq
        sp.m[j] += dq
        AHL21_big(sp;grad=false)
        for i = 1:n
            for k = 1:3
                jac_step_num[(i - 1) * 7 +  k,j * 7] = .5 * (sp.x[k,i] - sm.x[k,i]) / dq
                jac_step_num[(i - 1) * 7 + 3 + k,j * 7] = .5 * (sp.v[k,i] - sm.v[k,i]) / dq
            end
        end
        # Mass unchanged -> identity
        jac_step_num[j * 7,j * 7] = 1.0
    end

    # dqdt
    s_dt = State(ic)
    AHL21(s_dt, 1)
    dqdt_num = zeros(BigFloat, 7 * n)

    s_dtm = deepcopy(State(ic_big))
    hbig = big(h)
    dq = hbig * dlnq
    hbig -= dq
    AHL21_big = Integrator(ahl21!, hbig, t0_big, tmax_big)
    AHL21_big(s_dtm, 1;grad=false)

    s_dtp = deepcopy(State(ic_big))
    hbig += 2dq
    AHL21_big = Integrator(ahl21!, hbig, t0_big, tmax_big)
    AHL21_big(s_dtp, 1;grad=false)
    for i in 1:n, k in 1:3
        dqdt_num[(i - 1) * 7 +  k] = .5 * (s_dtp.x[k,i] - s_dtm.x[k,i]) / dq
        dqdt_num[(i - 1) * 7 + 3 + k] = .5 * (s_dtp.v[k,i] - s_dtm.v[k,i]) / dq
    end
    dqdt_num = convert(Array{Float64,1}, dqdt_num)

    ####################

    ###### Tests #######
    # Check analytic vs finite difference derivatives
    @test isapprox(asinh.(s0.jac_step), asinh.(jac_step_num);norm=maxabs)
    @test isapprox(s_dt.dqdt, dqdt_num, norm=maxabs)
end


text:
"""
    PoissonSample(Z, E)

An observed sample ``Z`` drawn from a Poisson distribution,

```math
Z \\sim \\text{Poisson}(\\mu \\cdot E).
```

The multiplying intensity ``E`` is assumed to be known (and equal to `1.0` by default), while
``\\mu`` is assumed unknown. The type above is used when the sample ``Z`` is to be used for estimation or inference of ``\\mu``.

```jldoctest
julia> PoissonSample(3)
Z=3  | E=1.0
julia> PoissonSample(3, 1.5)
Z=3  | E=1.5
```
"""
struct PoissonSample{T,S} <: DiscreteEBayesSample{T}
    Z::T
    E::S
end

PoissonSample(Z) = PoissonSample(Z, 1.0)
PoissonSample() = PoissonSample(missing)

response(Z::PoissonSample) = Z.Z
nuisance_parameter(Z::PoissonSample) = Z.E

likelihood_distribution(Z::PoissonSample, λ) = Poisson(λ * nuisance_parameter(Z))

summarize_by_default(Zs::Vector{<:PoissonSample}) = skedasticity(Zs) == Homoskedastic()

function Base.show(io::IO, Z::PoissonSample)
    resp_Z = response(Z)
    if ismissing(resp_Z) || isa(resp_Z, Interval)
        spaces_to_keep = 1
    else
        spaces_to_keep = max(3 - ndigits(response(Z)), 1)
    end
    spaces = repeat(" ", spaces_to_keep)
    print(io, "Z=", resp_Z, spaces, "| ", "E=", Z.E)
end

# Conjugate computations

function default_target_computation(::BasicPosteriorTarget, ::PoissonSample, ::Gamma)
    Conjugate()
end

function marginalize(Z::PoissonSample, prior::Gamma)
    E = nuisance_parameter(Z)
    @unpack α, θ = prior
    β = 1 / θ
    p = β / (E + β)
    NegativeBinomial(α, p)
end

function posterior(Z::PoissonSample, prior::Gamma)
    E = nuisance_parameter(Z)
    @unpack α, θ = prior
    β = 1 / θ
    α_post = α + response(Z)
    β_post = β + E
    Gamma(α_post, 1 / β_post)
end

function StatsBase.fit(::ParametricMLE{<:Gamma}, Zs::VectorOrSummary{<:PoissonSample})
    func = TwiceDifferentiable(
        params -> -loglikelihood(Zs, Gamma(params...)),
        [1.0; 1.0];
        autodiff = :forward,
    )
    dfc = TwiceDifferentiableConstraints([0.0; 0.0], [Inf; Inf])

    opt = optimize(func, dfc, [1.0; 1.0], IPNewton())
    Gamma(Optim.minimizer(opt)...)
end

# DiscretePriorClass

function _set_defaults(
    convexclass::DiscretePriorClass,
    Zs::VectorOrSummary{<:PoissonSample};
    hints,
)
    eps = get(hints, :eps, 1e-4)
    prior_grid_length = get(hints, :prior_grid_length, 300)::Integer
    _sample_min, _sample_max = extrema(response.(Zs) ./ nuisance_parameter.(Zs))
    _grid_min = max(2 * eps, _sample_min - eps)
    _grid_max = _sample_max + eps
    DiscretePriorClass(range(_grid_min; stop = _grid_max, length = prior_grid_length))
end


text:
using QuadricMeshSimplification
using Test
using Meshing
using GeometryBasics

@testset "QuadricMeshSimplification.jl" begin
    #m = GLNormalMesh(Sphere(zero(Point{3,Float32}),1.0))
    #simplify_mesh_lossless!(vertices(m),faces(m))
    @testset "Sphere" begin
        sphere(v) = sqrt(sum(v.^2)) - 1
        vts, fcs = isosurface(sphere,MarchingTetrahedra())
        @show length(vts), length(fcs)
        vts, fcs = simplify_mesh!(vts,fcs, length(vts)>>2)
        @show length(vts), length(fcs)
    end
    @testset "random" begin
        vts, fcs = isosurface(rand(20,20,20),MarchingCubes(0.5))
        @show length(vts), length(fcs)
        vts, fcs = simplify_mesh!(vts,fcs, length(vts)>>2)
        @show length(vts), length(fcs)
    end
end


text:
module CFMG

# includes -
include("Include.jl")

# methods to make various types of models -
export make_julia_model
export make_octave_model
export make_python_model
export make_matlab_model
export make_vff_model
export make_sbml_model

# method to make a default project structure the user can edit -
export generate_default_project

# method to export MAT files to an editable format -
export extract_files_from_cobra_model

end # module

max_stars_repo_name: varnerlab/CFMG

max_issues_repo_name: varnerlab/CFMG

max_forks_repo_name: varnerlab/CFMG


text:
# This file was generated, do not modify it. # hide
using MLJ
import RDatasets: dataset
using PrettyPrinting
MLJ.color_off() # hide
import Distributions
const D = Distributions

@load LinearRegressor pkg=MLJLinearModels
@load RidgeRegressor pkg=MLJLinearModels
@load LassoRegressor pkg=MLJLinearModels


text:
using PROJ_jll
using NetworkOptions

const stat = Cvoid

const _stat64 = Cvoid

const tm = Libc.TmStruct

const time_t = Int

CPL_STATIC_CAST(type, value) = value % type

GDAL_COMPUTE_VERSION(maj, min, rev) = ((maj) * 1000000 + (min) * 10000 + (rev) * 100)


text:
"""
    LOCF(; context=Context())

Last observation carried forward (LOCF) iterates forwards through the `data` and fills
missing data with the last existing observation. The current implementation is univariate,
so each variable in a table or matrix will be handled independently.

See also:
- [NOCB](@ref): Next Observation Carried Backward

WARNING: missing elements at the head of the array may not be imputed if there is no
existing observation to carry forward. As a result, this method does not guarantee
that all missing values will be imputed.

# Keyword Arguments
* `context::AbstractContext`: A context which keeps track of missing data
  summary information

# Example
"""
struct LOCF <: Imputor
    context::AbstractContext
end

# TODO: Switch to using Base.@kwdef on 1.1
LOCF(; context=Context()) = LOCF(context)

function impute!(data::AbstractVector, imp::LOCF)
    imp.context() do c
        start_idx = findfirst(c, data) + 1
        for i in start_idx:lastindex(data)
            if ismissing!(c, data[i])
                data[i] = data[i-1]
            end
        end

        return data
    end
end