text:
# Test core DispatchVariableRef extensions
@testset "Core Data Accessers" begin
    # Setup data
    m = InfiniteModel()
    obj_idx = DependentParametersIndex(1)
    idx = DependentParameterIndex(obj_idx, 1)
    set = CollectionSet([IntervalSet(0, 1), IntervalSet(0, 1)])
    methods = [InfiniteOpt.DefaultDerivativeMethod for i = 1:2]
    params = DependentParameters(set, Dict{Vector{Float64}, Set{DataType}}(), 5, methods)
    object = MultiParameterData(params, 1, 1:2, ["p1", "p2"])
    pref = DependentParameterRef(m, idx)
    gvref = GeneralVariableRef(m, 1, DependentParameterIndex, 1)
    bad_idx = DependentParameterIndex(DependentParametersIndex(-1), 2)
    bad_pref = DependentParameterRef(m, bad_idx)
    # test dispatch_variable_ref
    @testset "dispatch_variable_ref" begin
        @test dispatch_variable_ref(m, idx) == pref
        @test dispatch_variable_ref(gvref) == pref
    end
    # test _add_data_object
    @testset "_add_data_object" begin
        @test InfiniteOpt._add_data_object(m, object) == obj_idx
        @test InfiniteOpt._param_object_indices(m)[end] == obj_idx
    end
    # test _data_dictionary
    @testset "_data_dictionary" begin
        @test InfiniteOpt._data_dictionary(pref) === m.dependent_params
        @test InfiniteOpt._data_dictionary(gvref) === m.dependent_params
        @test InfiniteOpt._data_dictionary(m, DependentParameters) === m.dependent_params
    end
    # test _data_object
    @testset "_data_object" begin
        @test InfiniteOpt._data_object(pref) == object
        @test InfiniteOpt._data_object(gvref) == object
        @test_throws ErrorException InfiniteOpt._data_object(bad_pref)
    end
    # test _core_variable_object
    @testset "_core_variable_object" begin
        @test InfiniteOpt._core_variable_object(pref) == params
        @test InfiniteOpt._core_variable_object(gvref) == params
    end
    # test _num_parameters
    @testset "_num_parameters" begin
        @test InfiniteOpt._num_parameters(pref) == 2
    end
    # test _delete_data_object
    @testset "_delete_data_object" begin
        @test is_valid(m, pref)
        @test InfiniteOpt._delete_data_object(pref) isa Nothing
        @test !is_valid(m, pref)
    end
end

# Test Definition
@testset "Definition" begin
    # Setup data
    m = InfiniteModel();
    sset1 = IntervalSet(0, 1)
    sset2 = UniDistributionSet(Uniform())
    set1 = CollectionSet([sset1, sset1])
    set2 = MultiDistributionSet(MvNormal(ones(2)))
    set3 = MultiDistributionSet(MatrixBeta(2, 2, 2))
    set4 = CollectionSet([sset1, sset2])
    method = InfiniteOpt.DefaultDerivativeMethod
    method_type = typeof(method)
    # test _DependentParameter
    @testset "_DependentParameter" begin
        @test InfiniteOpt._DependentParameter isa UnionAll
        @test isa(InfiniteOpt._DependentParameter(sset1, Float64[], "p", method),
                  InfiniteOpt._DependentParameter{IntervalSet,method_type})
        @test isa(InfiniteOpt._DependentParameter(set1, 1, "p", method),
                  InfiniteOpt._DependentParameter{<:CollectionSet, method_type})
        @test isa(InfiniteOpt._DependentParameter(set3, [1, 3], "p", method),
                  InfiniteOpt._DependentParameter{<:MultiDistributionSet, method_type})
    end
    # prepare containers of _DependentParameters
    raw_params1 = [InfiniteOpt._DependentParameter(sset1, Float64[], "p", method) for i = 1:2]
    raw_params2 = [InfiniteOpt._DependentParameter(set1, [0, 1], "p", method) for i = 1:2]
    raw_params3 = [InfiniteOpt._DependentParameter(set2, 1, "p", method) for i = 1:2]
    raw_params4 = [InfiniteOpt._DependentParameter(set3, Float64[], "p", method) for i = 1:2]
    raw_params5 = [InfiniteOpt._DependentParameter(set3, Float64[], "p", method)
                   for i = CartesianIndices((1:2, 1:2))]
    raw_params6 = [InfiniteOpt._DependentParameter(set4, Float64[], "p", method) for i = 1:2]
    raw_params7 = [InfiniteOpt._DependentParameter(set2, Float64[], "p", method),
                   InfiniteOpt._DependentParameter(set3, Float64[], "p", method)]
    raw_params8 = [InfiniteOpt._DependentParameter(set1, [0, 1], "p", method) for i = 1:3]
    raw_params9 = [InfiniteOpt._DependentParameter(set1, Float64[], "p", method),
                   InfiniteOpt._DependentParameter(set4, Float64[], "p", method)]
    raw_params10 = [InfiniteOpt._DependentParameter(set1, Float64[], "p", method),
                    InfiniteOpt._DependentParameter(set2, Float64[], "p", method)]
    raw_params11 = [InfiniteOpt._DependentParameter(BadArraySet(), 1, "p", method) for i = 1:2]
    raw_params12 = [InfiniteOpt._DependentParameter(sset1, Float64[], "p", method),
                    InfiniteOpt._DependentParameter(sset2, Float64[], "p", method)]
    raw_params13 = [InfiniteOpt._DependentParameter(sset1, Float64[], "p", TestGenMethod()) for i = 1:2]
    raw_params14 = [InfiniteOpt._DependentParameter(sset1, Float64[], "p", TestGenMethod()),
                    InfiniteOpt._DependentParameter(sset2, Float64[], "p", method)]
    # test _check_param_sets (InfiniteScalarSet)
    @testset "_check_param_sets (InfiniteScalarSet)" begin
        @test InfiniteOpt._check_param_sets(error, raw_params1) isa Nothing
    end
    # test _check_param_sets (General MultiDistributionSet)
    @testset "_check_param_sets (General MultiDistributionSet)" begin
        @test InfiniteOpt._check_param_sets(error, raw_params5) isa Nothing
        @test InfiniteOpt._check_param_sets(error, raw_params3) isa Nothing
        @test_throws ErrorException InfiniteOpt._check_param_sets(error, raw_params4)
    end
    # test _check_param_sets (SparseAxisArray MultiDistributionSet)
    @testset "_check_param_sets (SparseAxisArray MultiDistributionSet)" begin
        new_params = convert(JuMPC.SparseAxisArray, raw_params5)
        @test_throws ErrorException InfiniteOpt._check_param_sets(error, new_params)
    end
    # test _check_param_sets (CollectionSet)
    @testset "_check_param_sets (CollectionSet)" begin
        @test InfiniteOpt._check_param_sets(error, raw_params2) isa Nothing
        @test_throws ErrorException InfiniteOpt._check_param_sets(error, raw_params8)
        new_params = convert(JuMPC.SparseAxisArray, raw_params2)
        warn = "CollectionSet order may not match the given `SparseAxisArray` " *
               "of specified dependent infinite parameters, consider instead " *
               "specifying the `InfiniteScalarSet` for each parameter using " *
               "the `set` keyword and the appropriate indices."
        @test_logs (:warn, warn) InfiniteOpt._check_param_sets(error, new_params)
    end
    # test _check_param_sets (InfiniteArraySet)
    @testset "_check_param_sets (InfiniteArraySet)" begin
        @test InfiniteOpt._check_param_sets(error, raw_params11) isa Nothing
    end
    # test _check_param_sets (Mixed)
    @testset "_check_param_sets (Mixed)" begin
        @test InfiniteOpt._check_param_sets(error, raw_params12) isa Nothing
        @test_throws ErrorException InfiniteOpt._check_param_sets(error, raw_params10)
        @test_throws ErrorException InfiniteOpt._check_param_sets(error, raw_params7)
        @test_throws ErrorException InfiniteOpt._check_param_sets(error, raw_params9)
    end
    # test _check_param_sets (Fallback)
    @testset "_check_param_sets (Fallback)" begin
        @test_throws ErrorException InfiniteOpt._check_param_sets(error, ones(2))
    end
    # test _check_derivative_methods
    @testset "_check_derivative_methods" begin
        # test normal
        @test InfiniteOpt._check_derivative_methods(error, raw_params1) isa Nothing
        @test InfiniteOpt._check_derivative_methods(error, raw_params12) isa Nothing
        # test bad type
        @test_throws ErrorException InfiniteOpt._check_derivative_methods(error, raw_params13)
        @test_throws ErrorException InfiniteOpt._check_derivative_methods(error, raw_params14)
        # test fallback
        @test_throws ErrorException InfiniteOpt._check_derivative_methods(error, ones(2))
    end
    # test _make_array_set (InfiniteArraySet)
    @testset "_make_array_set (InfiniteArraySet)" begin
        @test InfiniteOpt._make_array_set(raw_params3) == set2
        @test InfiniteOpt._make_array_set(raw_params2) == set1
    end
    # test _make_array_set (InfiniteScalarSet)
    @testset "_make_array_set (InfiniteScalarSet)" begin
        @test InfiniteOpt._make_array_set(raw_params1) isa CollectionSet{IntervalSet}
    end
    # test _build_parameters
    @testset "_build_parameters" begin
        # test errors
        @test_throws ErrorException InfiniteOpt._build_parameters(error, raw_params1, bob = 2)
        @test_throws ErrorException InfiniteOpt._build_parameters(error, raw_params4)
        @test_throws ErrorException InfiniteOpt._build_parameters(error, raw_params9)
        raw_params12 = [InfiniteOpt._DependentParameter(set1, 0, "p", method),
                        InfiniteOpt._DependentParameter(set1, Float64[], "p", method)]
        @test_throws ErrorException InfiniteOpt._build_parameters(error, raw_params12)
        raw_params13 = [InfiniteOpt._DependentParameter(set1, [0, 2], "p", method) for i = 1:2]
        @test_throws ErrorException InfiniteOpt._build_parameters(error, raw_params13)
        # test has supports
        @test InfiniteOpt._build_parameters(error,
                            raw_params2)[1] isa DependentParameters
        @test InfiniteOpt._build_parameters(error, raw_params2)[1].set == set1
        @test length(InfiniteOpt._build_parameters(error,
                                              raw_params2)[1].supports) == 2
        @test InfiniteOpt._build_parameters(error, raw_params2)[2] == ["p", "p"]
        @test InfiniteOpt._build_parameters(error,
                            raw_params2)[3] == CartesianIndices(1:2)
        # test support generation
        @test InfiniteOpt._build_parameters(error, raw_params6,
                            num_supports = 4, sig_digits = 5)[1] isa DependentParameters
        @test InfiniteOpt._build_parameters(error, raw_params6,
                            num_supports = 4, sig_digits = 5)[1].set == set4
        @test InfiniteOpt._build_parameters(error, raw_params6,
                            num_supports = 4, sig_digits = 5)[1].supports isa Dict{Vector{Float64}, Set{DataType}}
        @test Mixture in first(InfiniteOpt._build_parameters(error, raw_params6,
                              num_supports = 4, sig_digits = 5)[1].supports)[2]
        @test InfiniteOpt._build_parameters(error, raw_params2,
                            num_supports = 4)[2] == ["p", "p"]
        @test InfiniteOpt._build_parameters(error, raw_params2,
                            num_supports = 4)[3] == CartesianIndices(1:2)
        # test with no supports
        @test InfiniteOpt._build_parameters(error,
                            raw_params5)[1] isa DependentParameters
        @test InfiniteOpt._build_parameters(error, raw_params5)[1].set == set3
        @test InfiniteOpt._build_parameters(error,
                            raw_params5)[1].supports == Dict{Vector{Float64}, Set{DataType}}()
        @test InfiniteOpt._build_parameters(error,
                            raw_params5)[2] == ["p", "p", "p", "p"]
        @test InfiniteOpt._build_parameters(error,
                            raw_params5)[3] == CartesianIndices((1:2, 1:2))
    end
    # test add_parameters
    @testset "add_parameters" begin
        # test default
        pref1 = GeneralVariableRef(m, 1, DependentParameterIndex, 1)
        pref2 = GeneralVariableRef(m, 1, DependentParameterIndex, 2)
        params = InfiniteOpt._build_parameters(error, raw_params1)[1]
        @test add_parameters(m, params) == [pref1, pref2]
        @test InfiniteOpt._param_object_indices(m) == [index(pref1).object_index]
        @test InfiniteOpt._last_param_num(m) == 2
        @test name(pref1) == "noname"
        # test vector build
        pref1 = GeneralVariableRef(m, 2, DependentParameterIndex, 1)
        pref2 = GeneralVariableRef(m, 2, DependentParameterIndex, 2)
        inputs = InfiniteOpt._build_parameters(error, raw_params2)
        @test add_parameters(m, inputs...) == [pref1, pref2]
        @test InfiniteOpt._param_object_indices(m)[2] == index(pref1).object_index
        @test InfiniteOpt._last_param_num(m) == 4
        @test name(pref1) == "p"
        # test array build
        pref1 = GeneralVariableRef(m, 3, DependentParameterIndex, 1)
        pref2 = GeneralVariableRef(m, 3, DependentParameterIndex, 2)
        pref3 = GeneralVariableRef(m, 3, DependentParameterIndex, 3)
        pref4 = GeneralVariableRef(m, 3, DependentParameterIndex, 4)
        inputs = InfiniteOpt._build_parameters(error, raw_params5)
        @test add_parameters(m, inputs...) == [pref1 pref3; pref2 pref4]
        @test InfiniteOpt._param_object_indices(m)[3] == index(pref1).object_index
        @test InfiniteOpt._last_param_num(m) == 8
        @test name(pref1) == "p"
        # test DenseAxisArray build
        pref1 = GeneralVariableRef(m, 4, DependentParameterIndex, 1)
        pref2 = GeneralVariableRef(m, 4, DependentParameterIndex, 2)
        pref3 = GeneralVariableRef(m, 4, DependentParameterIndex, 3)
        pref4 = GeneralVariableRef(m, 4, DependentParameterIndex, 4)
        dense_params = JuMPC.DenseAxisArray(raw_params5, axes(raw_params5)...)
        inputs = InfiniteOpt._build_parameters(error, dense_params)
        expected = JuMPC.DenseAxisArray([pref1 pref3; pref2 pref4], axes(raw_params5)...)
        @test add_parameters(m, inputs...) == expected
        @test InfiniteOpt._param_object_indices(m)[4] == index(pref1).object_index
        @test InfiniteOpt._last_param_num(m) == 12
        @test name(pref1) == "p"
        # test SparseAxisArray
        pref1 = GeneralVariableRef(m, 5, DependentParameterIndex, 1)
        pref2 = GeneralVariableRef(m, 5, DependentParameterIndex, 2)
        sparse_params = convert(JuMPC.SparseAxisArray, raw_params1)
        inputs = InfiniteOpt._build_parameters(error, sparse_params)
        expected = convert(JuMPC.SparseAxisArray, [pref1, pref2])
        @test add_parameters(m, inputs...) == expected
        @test InfiniteOpt._param_object_indices(m)[5] == index(pref1).object_index
        @test InfiniteOpt._last_param_num(m) == 14
        @test name(pref1) == "p"
    end
end

# test macro definition
@testset "Macro Definition" begin
    # Setup data
    m = InfiniteModel();
    dist1 = Uniform()
    dist2 = MvNormal(ones(2))
    dist3 = MatrixBeta(2, 2, 2)
    sset1 = IntervalSet(0, 1)
    sset2 = UniDistributionSet(dist1)
    set1 = CollectionSet([sset1, sset1])
    set2 = MultiDistributionSet(dist2)
    set3 = MultiDistributionSet(dist3)
    set4 = CollectionSet([sset1, sset2])
    set5 = CollectionSet([sset2, sset2])
    # test _construct_array_set
    @testset "_construct_array_set" begin
        info = InfiniteOpt._ParameterInfoExpr()
        @test_throws ErrorException InfiniteOpt._construct_array_set(error, info)
        info.has_lb = true; info.lower_bound = 0
        @test_throws ErrorException InfiniteOpt._construct_array_set(error, info)
        info.has_ub = true; info.upper_bound = 1
        check = :(isa($(info.lower_bound), Real))
        expected = :($(check) ? IntervalSet($(info.lower_bound), $(info.upper_bound)) : error("Bounds must be a real number."))
        @test InfiniteOpt._construct_array_set(error, info) == expected
        info = InfiniteOpt._ParameterInfoExpr(distribution = Normal())
        check = :(isa($(info.distribution), Distributions.UnivariateDistribution))
        expected = :($(check) ? UniDistributionSet($(info.distribution)) : MultiDistributionSet($(info.distribution)))
        @test InfiniteOpt._construct_array_set(error, info) == expected
        info = InfiniteOpt._ParameterInfoExpr(set = IntervalSet(0, 1))
        check1 = :(isa($(info.set), AbstractInfiniteSet))
        check2 = :(isa($(info.set), Distributions.UnivariateDistribution))
        expected = :($(check1) ? $(info.set) : ($(check2) ? UniDistributionSet($(info.set)) : MultiDistributionSet($(info.set))))
        @test InfiniteOpt._construct_array_set(error, info) == expected
    end
    # test @dependent_parameters
    @testset "@dependent_parameters" begin
        # test macro errors
        @test_macro_throws ErrorException @dependent_parameters(m)
        @test_macro_throws ErrorException @dependent_parameters(m, p[1:2], 42)
        @test_macro_throws ErrorException @dependent_parameters(m, param)
        @test_macro_throws ErrorException @dependent_parameters(m, [1:2] in dist1)
        @test_macro_throws ErrorException @dependent_parameters(m, "bob"[1:2])
        # test set errors
        @test_macro_throws ErrorException @dependent_parameters(m, p[1:2],
                                            lower_bound = 3)
        @test_macro_throws ErrorException @dependent_parameters(m, p[1:2],
                                            upper_bound = 3)
        @test_macro_throws ErrorException @dependent_parameters(m, p[1:2],
                                            lower_bound = Complex(1),
                                            upper_bound = 2)
        @test_macro_throws ErrorException @dependent_parameters(m, p[1:2])
        # test build errors
        @test_macro_throws ErrorException @dependent_parameters(m, p[1:2] in dist1, bob = 42)
        @test_macro_throws ErrorException @dependent_parameters(m, p[i = 1:2] in [set1, set2][i])
        @test_macro_throws ErrorException @dependent_parameters(m, p[1:2] in dist3)
        @test_macro_throws ErrorException @dependent_parameters(m, p[i = 1:3] in set1)
        @test_macro_throws ErrorException @dependent_parameters(m, p[1:2] in set1, supports = 4)
        @test_macro_throws ErrorException @dependent_parameters(m, p[i = 1:2] in set1, supports = [[1, 0], 1][i])
        # test simple explict build
        pref1 = GeneralVariableRef(m, 1, DependentParameterIndex, 1)
        pref2 = GeneralVariableRef(m, 1, DependentParameterIndex, 2)
        @test @dependent_parameters(m, a[1:2] in dist1,
                num_supports = 10) == [pref1, pref2]
        @test InfiniteOpt._data_object(pref1).names == ["a[1]", "a[2]"]
        @test length(InfiniteOpt._core_variable_object(pref1).supports) == 10
        @test WeightedSample in first(InfiniteOpt._core_variable_object(pref1).supports)[2]
        @test InfiniteOpt._core_variable_object(pref1).set.sets == set5.sets
        # test another explicit build
        pref1 = GeneralVariableRef(m, 2, DependentParameterIndex, 1)
        pref2 = GeneralVariableRef(m, 2, DependentParameterIndex, 2)
        expected = JuMPC.DenseAxisArray([pref1, pref2], 3:4)
        @test @dependent_parameters(m, b[3:4] in set2,
                supports = 0) == expected
        @test InfiniteOpt._data_object(pref1).names == ["b[3]", "b[4]"]
        @test InfiniteOpt._core_variable_object(pref1).supports == Dict{Vector{Float64}, Set{DataType}}(zeros(2) => Set([UserDefined]))
        # test explicit build with some args
        pref1 = GeneralVariableRef(m, 3, DependentParameterIndex, 1)
        pref2 = GeneralVariableRef(m, 3, DependentParameterIndex, 2)
        expected = convert(JuMPC.SparseAxisArray, [pref1, pref2])
        @test @dependent_parameters(m, c[1:2] in sset1,
                supports = 0, base_name = "z",
                container = SparseAxisArray) == expected
        @test InfiniteOpt._data_object(pref1).names == ["z[1]", "z[2]"]
        # test explicit comparison
        pref1 = GeneralVariableRef(m, 4, DependentParameterIndex, 1)
        pref2 = GeneralVariableRef(m, 4, DependentParameterIndex, 2)
        @test @dependent_parameters(m, 0 <= d[1:2] <= 1,
                num_supports = 10) == [pref1, pref2]
        @test InfiniteOpt._data_object(pref1).names == ["d[1]", "d[2]"]
        @test length(InfiniteOpt._core_variable_object(pref1).supports) == 10
        @test UniformGrid in first(InfiniteOpt._core_variable_object(pref1).supports)[2]
        @test InfiniteOpt._core_variable_object(pref1).set.sets == set1.sets
        # test test anonymous
        pref1 = GeneralVariableRef(m, 5, DependentParameterIndex, 1)
        pref2 = GeneralVariableRef(m, 5, DependentParameterIndex, 2)
        pref3 = GeneralVariableRef(m, 5, DependentParameterIndex, 3)
        pref4 = GeneralVariableRef(m, 5, DependentParameterIndex, 4)
        @test @dependent_parameters(m, [1:2, 1:2],
                 distribution = dist3) == [pref1 pref3; pref2 pref4]
        @test InfiniteOpt._data_object(pref1).names == ["", "", "", ""]
        @test isempty(InfiniteOpt._core_variable_object(pref1).supports)
        # test anonymous with set keyword
        pref1 = GeneralVariableRef(m, 6, DependentParameterIndex, 1)
        pref2 = GeneralVariableRef(m, 6, DependentParameterIndex, 2)
        @test @dependent_parameters(m, [1:2], set = sset2,
                                    derivative_method = TestMethod()) == [pref1, pref2]
        # test anonymous with dist keyword and base_name
        pref1 = GeneralVariableRef(m, 7, DependentParameterIndex, 1)
        pref2 = GeneralVariableRef(m, 7, DependentParameterIndex, 2)
        @test @dependent_parameters(m, [1:2],
                 distribution = dist1, base_name = "zz") == [pref1, pref2]
        @test InfiniteOpt._data_object(pref1).names == ["zz[1]", "zz[2]"]
        # test anonymous with bounds keywords
        pref1 = GeneralVariableRef(m, 8, DependentParameterIndex, 1)
        pref2 = GeneralVariableRef(m, 8, DependentParameterIndex, 2)
        @test @dependent_parameters(m, [i = 1:2], upper_bound = [1, 2][i],
                  lower_bound = 0) == [pref1, pref2]
        @test InfiniteOpt._param_object_indices(m)[InfiniteOpt._object_number(pref2)] == index(pref2).object_index
    end
    # test @infinite_parameter
    @testset "@infinite_parameter" begin
        m = InfiniteModel();
        # test anonymous single
        pref = GeneralVariableRef(m, 1, IndependentParameterIndex)
        @test @infinite_parameter(m, distribution = dist1) == pref
        # test explicit single
        pref = GeneralVariableRef(m, 2, IndependentParameterIndex)
        @test @infinite_parameter(m, a in [0, 1]) == pref
        # test independent multi
        pref1 = GeneralVariableRef(m, 3, IndependentParameterIndex)
        pref2 = GeneralVariableRef(m, 4, IndependentParameterIndex)
        @test @infinite_parameter(m, b[1:2] in [0, 1], num_supports = 2,
                                  independent = true) == [pref1, pref2]
        # test dependent multi
        pref1 = GeneralVariableRef(m, 1, DependentParameterIndex, 1)
        pref2 = GeneralVariableRef(m, 1, DependentParameterIndex, 2)
        @test @infinite_parameter(m, c[1:2] in dist2,
                                  base_name = "bob") == [pref1, pref2]
        # test anonymous multi dependent
        pref1 = GeneralVariableRef(m, 2, DependentParameterIndex, 1)
        pref2 = GeneralVariableRef(m, 2, DependentParameterIndex, 2)
        @test @infinite_parameter(m, [1:2], set = set2,
                                  base_name = "bob") == [pref1, pref2]
        # test multi with variable independent
        pref1 = GeneralVariableRef(m, 5, IndependentParameterIndex)
        pref2 = GeneralVariableRef(m, 6, IndependentParameterIndex)
        indep = true
        @test @infinite_parameter(m, d[1:2] in [0, 1], num_supports = 2,
                                  independent = indep) == [pref1, pref2]
    end
end

# test naming stuff
@testset "Naming" begin
    # setup data
    m = InfiniteModel();
    gvrefs = @dependent_parameters(m, a[1:2] in [0, 1])
    prefs = dispatch_variable_ref.(gvrefs)
    bad_idx = DependentParameterIndex(DependentParametersIndex(-1), 2)
    bad_pref = DependentParameterRef(m, bad_idx)
    # test _param_index
    @testset "_param_index" begin
        @test InfiniteOpt._param_index(prefs[1]) == 1
        @test InfiniteOpt._param_index(prefs[2]) == 2
    end
    # test _update_param_name_dict
    @testset "_update_param_name_dict" begin
        m.name_to_param = Dict{String, AbstractInfOptIndex}()
        @test InfiniteOpt._update_param_name_dict(m, m.dependent_params) isa Nothing
        @test m.name_to_param["a[1]"] == DependentParameterIndex(DependentParametersIndex(1), 1)
        @test m.name_to_param["a[2]"] == DependentParameterIndex(DependentParametersIndex(1), 2)
        m.name_to_param = nothing
    end
    # parameter_by_name
    @testset "parameter_by_name" begin
        @test parameter_by_name(m, "a[1]") == gvrefs[1]
        @test parameter_by_name(m, "a[2]") == gvrefs[2]
        @test isa(parameter_by_name(m, "a[3]"), Nothing)
    end
    # test name
    @testset "JuMP.name" begin
        @test name(prefs[1]) == "a[1]"
        @test name(prefs[2]) == "a[2]"
        @test name(gvrefs[1]) == "a[1]"
        @test name(gvrefs[2]) == "a[2]"
        @test name(bad_pref) == ""
    end
    # test set_name
    @testset "JuMP.set_name" begin
        @test set_name(prefs[1], "joe") isa Nothing
        @test name(prefs[1]) == "joe"
        @test set_name(prefs[2], "joe") isa Nothing
        @test name(prefs[2]) == "joe"
        @test set_name(gvrefs[2], "joe2") isa Nothing
        @test name(gvrefs[2]) == "joe2"
    end
    # test is_valid
    @testset "JuMP.is_valid" begin
        @test is_valid(m, prefs[1])
        @test !is_valid(InfiniteModel(), prefs[1])
        @test is_valid(m, gvrefs[1])
    end
end

# test dependency functions
@testset "Parameter Dependencies" begin
    # setup data
    m = InfiniteModel();
    gvrefs = @dependent_parameters(m, a[1:2] in [0, 1])
    prefs = dispatch_variable_ref.(gvrefs)
    data = InfiniteOpt._data_object(first(prefs))
    bad_idx = DependentParameterIndex(DependentParametersIndex(-1), 2)
    bad_pref = DependentParameterRef(m, bad_idx)
    # test _infinite_variable_dependencies
    @testset "_infinite_variable_dependencies" begin
        @test InfiniteOpt._infinite_variable_dependencies(prefs[1]) == data.infinite_var_indices
        @test InfiniteOpt._infinite_variable_dependencies(prefs[2]) == data.infinite_var_indices
        @test InfiniteOpt._infinite_variable_dependencies(gvrefs[1]) == data.infinite_var_indices
        @test_throws ErrorException InfiniteOpt._infinite_variable_dependencies(bad_pref)
    end
    # test _parameter_function_dependencies
    @testset "_parameter_function_dependencies" begin
        @test InfiniteOpt._parameter_function_dependencies(prefs[1]) == data.parameter_func_indices
        @test InfiniteOpt._parameter_function_dependencies(prefs[2]) == data.parameter_func_indices
        @test InfiniteOpt._parameter_function_dependencies(gvrefs[1]) == data.parameter_func_indices
        @test_throws ErrorException InfiniteOpt._parameter_function_dependencies(bad_pref)
    end
    # test _measure_dependencies
    @testset "_measure_dependencies" begin
        @test InfiniteOpt._measure_dependencies(prefs[1]) == data.measure_indices[1]
        @test InfiniteOpt._measure_dependencies(prefs[2]) == data.measure_indices[2]
        @test InfiniteOpt._measure_dependencies(gvrefs[1]) == data.measure_indices[1]
        @test_throws ErrorException InfiniteOpt._measure_dependencies(bad_pref)
    end
    # test _constraint_dependencies
    @testset "_constraint_dependencies" begin
        @test InfiniteOpt._constraint_dependencies(prefs[1]) == data.constraint_indices[1]
        @test InfiniteOpt._constraint_dependencies(prefs[2]) == data.constraint_indices[2]
        @test InfiniteOpt._constraint_dependencies(gvrefs[1]) == data.constraint_indices[1]
        @test_throws ErrorException InfiniteOpt._constraint_dependencies(bad_pref)
    end
    # test _derivative_dependencies
    @testset "_derivative_dependencies" begin
        @test InfiniteOpt._derivative_dependencies(prefs[1]) == data.derivative_indices[1]
        @test InfiniteOpt._derivative_dependencies(prefs[2]) == data.derivative_indices[2]
        @test InfiniteOpt._derivative_dependencies(gvrefs[1]) == data.derivative_indices[1]
        @test_throws ErrorException InfiniteOpt._derivative_dependencies(bad_pref)
    end
    # test used_by_infinite_variable
    @testset "used_by_infinite_variable" begin
        # test not used
        @test !used_by_infinite_variable(prefs[1])
        @test !used_by_infinite_variable(prefs[2])
        @test !used_by_infinite_variable(gvrefs[1])
        # test used
        push!(data.infinite_var_indices, InfiniteVariableIndex(1))
        @test used_by_infinite_variable(prefs[1])
        # undo changes
        empty!(data.infinite_var_indices)
    end
    # test used_by_parameter_function
    @testset "used_by_parameter_function" begin
        # test not used
        @test !used_by_parameter_function(prefs[1])
        @test !used_by_parameter_function(prefs[2])
        @test !used_by_parameter_function(gvrefs[1])
        # test used
        push!(data.parameter_func_indices, ParameterFunctionIndex(1))
        @test used_by_parameter_function(prefs[1])
        # undo changes
        empty!(data.parameter_func_indices)
    end
    # test used_by_derivative
    @testset "used_by_derivative" begin
        # test not used
        @test !used_by_derivative(prefs[1])
        @test !used_by_derivative(prefs[2])
        @test !used_by_derivative(gvrefs[1])
        # test used
        push!(data.derivative_indices[1], DerivativeIndex(1))
        @test used_by_derivative(prefs[1])
        # undo changes
        empty!(data.derivative_indices[1])
    end
    # test used_by_measure
    @testset "used_by_measure" begin
        # test not used
        @test !used_by_measure(prefs[1])
        @test !used_by_measure(prefs[2])
        @test !used_by_measure(gvrefs[1])
        # test used
        push!(data.measure_indices[1], MeasureIndex(1))
        @test used_by_measure(prefs[1])
        # undo changes
        empty!(data.measure_indices[1])
    end
    # test used_by_constraint
    @testset "used_by_constraint" begin
        # test not used
        @test !used_by_constraint(prefs[1])
        @test !used_by_constraint(prefs[2])
        @test !used_by_constraint(gvrefs[1])
        # test used
        push!(data.constraint_indices[1], ConstraintIndex(1))
        @test used_by_constraint(prefs[1])
        # undo changes
        empty!(data.constraint_indices[1])
    end
    # test used_by_objective
    @testset "used_by_objective" begin
        @test !used_by_objective(prefs[1])
        @test !used_by_objective(prefs[2])
        @test !used_by_objective(gvrefs[1])
    end
    # test is_used
    @testset "is_used" begin
        # test not used
        @test !is_used(prefs[1])
        @test !is_used(prefs[2])
        @test !is_used(gvrefs[1])
        # test used
        push!(data.infinite_var_indices, InfiniteVariableIndex(1))
        @test is_used(prefs[1])
    end
end

# test Parameter Object Methods
@testset "Object Methods" begin
    # setup data
    m = InfiniteModel();
    gvrefs = @dependent_parameters(m, a[1:2] in [0, 1])
    prefs = dispatch_variable_ref.(gvrefs)
    data = InfiniteOpt._data_object(first(prefs))
    set = CollectionSet([IntervalSet(0, 2), IntervalSet(0, 2)])
    methods = [InfiniteOpt.DefaultDerivativeMethod for i = 1:2]
    params = DependentParameters(set, Dict{Vector{Float64}, Set{DataType}}(), 10, methods)
    bad_idx = DependentParameterIndex(DependentParametersIndex(-1), 2)
    bad_pref = DependentParameterRef(m, bad_idx)
    # test _parameter_number
    @testset "_parameter_number" begin
        @test InfiniteOpt._parameter_number(prefs[1]) == 1
        @test InfiniteOpt._parameter_number(prefs[2]) == 2
        @test InfiniteOpt._parameter_number(gvrefs[1]) == 1
        @test_throws ErrorException InfiniteOpt._parameter_number(bad_pref)
    end
    # test _parameter_numbers
    @testset "_parameter_numbers" begin
        @test InfiniteOpt._parameter_numbers(prefs[1]) == [1]
        @test InfiniteOpt._parameter_numbers(prefs[2]) == [2]
        @test InfiniteOpt._parameter_numbers(gvrefs[1]) == [1]
    end
    # test _object_number
    @testset "_object_number" begin
        @test InfiniteOpt._object_number(prefs[1]) == 1
        @test InfiniteOpt._object_number(prefs[2]) == 1
        @test InfiniteOpt._object_number(gvrefs[1]) == 1
    end
    # test _object_numbers
    @testset "_object_numbers" begin
        @test InfiniteOpt._object_numbers(prefs[1]) == [1]
        @test InfiniteOpt._object_numbers(prefs[2]) == [1]
        @test InfiniteOpt._object_numbers(gvrefs[1]) == [1]
    end
    # test _adaptive_data_update
    @testset "_adaptive_data_update" begin
        # test with same data
        @test InfiniteOpt._adaptive_data_update(prefs[1], params, data) isa Nothing
        # test with different data
        set = MultiDistributionSet(MvNormal([0, 0], [1, 1]))
        ps = DependentParameters(set, Dict{Vector{Float64}, Set{DataType}}(), 10, methods)
        @test InfiniteOpt._adaptive_data_update(prefs[2], ps, data) isa Nothing
        @test InfiniteOpt._core_variable_object(prefs[2]) == ps
    end
    # test _set_core_variable_object
    @testset "_set_core_variable_object" begin
        # test with different type
        @test InfiniteOpt._set_core_variable_object(prefs[1], params) isa Nothing
        @test InfiniteOpt._core_variable_object(prefs[2]) == params
        # test with same type
        @test InfiniteOpt._set_core_variable_object(prefs[2], params) isa Nothing
        @test InfiniteOpt._core_variable_object(prefs[1]) == params
    end
end

# test Derivative Method
@testset "Derivative Methods" begin
    # setup the data
    m = InfiniteModel();
    gvrefs = @dependent_parameters(m, a[1:2] in [0, 1], derivative_method = TestMethod())
    prefs = dispatch_variable_ref.(gvrefs)
    push!(InfiniteOpt._constraint_dependencies(prefs[1]), ConstraintIndex(1))
    # test has_generative_supports
    @testset "has_generative_supports" begin
        @test !has_generative_supports(prefs[1])
        @test !has_generative_supports(gvrefs[2])
    end
    # test add_generative_supports
    @testset "add_generative_supports" begin
        @test add_generative_supports(prefs[1]) isa Nothing
        @test add_generative_supports(gvrefs[2]) isa Nothing
    end
    # test _set_has_generative_supports
    @testset "_set_has_generative_supports" begin
        @test InfiniteOpt._set_has_generative_supports(prefs[1], true) isa Nothing
        @test InfiniteOpt._set_has_generative_supports(gvrefs[2], false) isa Nothing
    end
    # test has_derivative_constraints
    @testset "has_derivative_constraints" begin
        @test !has_derivative_constraints(prefs[1])
        InfiniteOpt._data_object(prefs[1]).has_deriv_constrs[1] = true
        @test has_derivative_constraints(gvrefs[1])
    end
    # test _set_has_derivative_constraints
    @testset "_set_has_derivative_constraints" begin
        @test InfiniteOpt._set_has_derivative_constraints(prefs[1], true) isa Nothing
        @test has_derivative_constraints(prefs[1])
        @test InfiniteOpt._set_has_derivative_constraints(gvrefs[1], false) isa Nothing
        @test !has_derivative_constraints(prefs[1])
    end
    # test _derivative_methods
    @testset "_derivative_methods" begin
        @test InfiniteOpt._derivative_methods(prefs[1]) isa Vector{TestMethod}
    end
    # test derivative_method
    @testset "derivative_method" begin
        @test derivative_method(prefs[1]) isa TestMethod
        @test derivative_method(gvrefs[2]) isa TestMethod
    end
    # test _adaptive_method_update
    @testset "_adaptive_method_update" begin
        # same type
        params = InfiniteOpt._core_variable_object(prefs[1])
        @test InfiniteOpt._adaptive_method_update(prefs[1], params, TestMethod()) isa Nothing
        @test derivative_method(prefs[1]) isa TestMethod
        # different type
        params = InfiniteOpt._core_variable_object(prefs[1])
        method = InfiniteOpt.DefaultDerivativeMethod
        @test InfiniteOpt._adaptive_method_update(prefs[2], params, method) isa Nothing
        @test InfiniteOpt._derivative_methods(prefs[1]) == [TestMethod(), method]
    end
    # test set_derivative_method
    @testset "set_derivative_method" begin
        # same type
        method = InfiniteOpt.DefaultDerivativeMethod
        @test set_derivative_method(prefs[1], method) isa Nothing
        @test derivative_method(prefs[1]) == method
        @test InfiniteOpt._derivative_methods(prefs[1]) == [method, method]
        # different type
        @test set_derivative_method(prefs[2], TestMethod()) isa Nothing
        @test InfiniteOpt._derivative_methods(prefs[1]) == [method, TestMethod()]
        # test error
        @test_throws ErrorException set_derivative_method(gvrefs[2], TestGenMethod())
    end
    # test set_all_derivative_methods
    @testset "set_all_derivative_methods" begin
        @infinite_parameter(m, pref in [0, 1])
        @test set_all_derivative_methods(m, TestMethod()) isa Nothing
        @test InfiniteOpt._derivative_methods(prefs[1]) == [TestMethod(), TestMethod()]
        @test derivative_method(pref) == TestMethod()
        @test_throws ErrorException set_all_derivative_methods(m, TestGenMethod())
    end
end

# test Infinite Set Methods
@testset "Infinite Set Methods" begin
    # setup data
    m = InfiniteModel();
    gvrefs1 = @dependent_parameters(m, a[1:2] in [0, 1], num_supports = 2)
    prefs1 = dispatch_variable_ref.(gvrefs1)
    gvrefs2 = @dependent_parameters(m, b[1:2, 1:2] in MatrixBeta(2, 2, 2))
    prefs2 = dispatch_variable_ref.(gvrefs2)
    push!(InfiniteOpt._constraint_dependencies(prefs1[1]), ConstraintIndex(1))
    # test _parameter_set (raw set)
    @testset "_parameter_set (Raw Set)" begin
        @test InfiniteOpt._parameter_set(prefs1[1]) isa CollectionSet
        @test InfiniteOpt._parameter_set(prefs2[1, 1]) isa MultiDistributionSet
    end
    # test _parameter_set (CollectionSet)
    @testset "_parameter_set (CollectionSet)" begin
        set = InfiniteOpt._parameter_set(prefs1[1])
        @test InfiniteOpt._parameter_set(set, prefs1[1]) == IntervalSet(0, 1)
    end
    # test _parameter_set (Fallback)
    @testset "_parameter_set (Fallback)" begin
        set = InfiniteOpt._parameter_set(prefs2[1])
        @test_throws ErrorException InfiniteOpt._parameter_set(set, prefs2[1])
    end
    # test infinite_set (single)
    @testset "infinite_set (Single)" begin
        @test infinite_set(prefs1[1]) == IntervalSet(0, 1)
        @test_throws ErrorException infinite_set(prefs2[1])
        @test infinite_set(gvrefs1[1]) == IntervalSet(0, 1)
    end
    # test _check_complete_param_array
    @testset "_check_complete_param_array" begin
        @test InfiniteOpt._check_complete_param_array(prefs1) isa Nothing
        @test_throws ErrorException InfiniteOpt._check_complete_param_array(prefs2[:, 1])
    end
    # test infinite_set (Array)
    @testset "infinite_set (Array)" begin
        @test infinite_set(prefs1) isa CollectionSet
        @test_throws ErrorException infinite_set(prefs2[:, 1])
        @test infinite_set(prefs2) isa MultiDistributionSet
        @test infinite_set(gvrefs1) isa CollectionSet
    end
    # test _update_parameter_set
    @testset "_update_parameter_set" begin
        old_set = infinite_set(prefs1)
        new_set = CollectionSet([IntervalSet(0, 1), IntervalSet(0, 2)])
        @test InfiniteOpt._update_parameter_set(prefs1[1], new_set) isa Nothing
        @test num_supports(prefs1) == 0
        @test !optimizer_model_ready(m)
        @test infinite_set(prefs1) == new_set
        @test InfiniteOpt._update_parameter_set(prefs1[1], old_set) isa Nothing
    end
    # test set_infinite_set (Single)
    @testset "set_infinite_set (Single)" begin
        # test normal
        @test set_infinite_set(prefs1[2], IntervalSet(-1, 1)) isa Nothing
        @test infinite_set(prefs1[2]) == IntervalSet(-1, 1)
        @test set_infinite_set(gvrefs1[2], IntervalSet(0, 1)) isa Nothing
        @test set_infinite_set(prefs1[1], UniDistributionSet(Normal())) isa Nothing
        @test infinite_set(prefs1[1]) isa UniDistributionSet
        @test set_infinite_set(prefs1[1], IntervalSet(0, 1)) isa Nothing
        # test errors
        @test_throws ErrorException set_infinite_set(prefs2[1], IntervalSet(0, 2))
        push!(InfiniteOpt._measure_dependencies(prefs1[1]), MeasureIndex(1))
        @test_throws ErrorException set_infinite_set(prefs1[1], IntervalSet(0, 2))
        empty!(InfiniteOpt._measure_dependencies(prefs1[1]))
    end
    # test set_infinite_set (Array)
    @testset "set_infinite_set (Array)" begin
        # test normal
        old_set = infinite_set(prefs1)
        new_set = CollectionSet([IntervalSet(0, 1), IntervalSet(0, 2)])
        @test set_infinite_set(prefs1, new_set) isa Nothing
        @test infinite_set(prefs1) == new_set
        @test set_infinite_set(gvrefs1, old_set) isa Nothing
        # test errors
        @test_throws ErrorException set_infinite_set(prefs2[:, 1], new_set)
        push!(InfiniteOpt._measure_dependencies(prefs1[1]), MeasureIndex(1))
        @test_throws ErrorException set_infinite_set(prefs1, new_set)
        empty!(InfiniteOpt._measure_dependencies(prefs1[1]))
    end
    # test JuMP.has_lower_bound
    @testset "JuMP.has_lower_bound" begin
        @test has_lower_bound(prefs1[1])
        @test has_lower_bound(gvrefs1[2])
        @test !has_lower_bound(prefs2[2])
    end
    # test JuMP.lower_bound
    @testset "JuMP.lower_bound" begin
        @test lower_bound(prefs1[1]) == 0
        @test lower_bound(gvrefs1[2]) == 0
        @test_throws ErrorException lower_bound(prefs2[2])
    end
    # test JuMP.set_lower_bound
    @testset "JuMP.set_lower_bound" begin
        @test set_lower_bound(prefs1[1], -1) isa Nothing
        @test lower_bound(prefs1[1]) == -1
        @test set_lower_bound(gvrefs1[2], 0) isa Nothing
        @test lower_bound(prefs1[2]) == 0
        @test_throws ErrorException set_lower_bound(prefs2[2], -3)
    end
    # test JuMP.has_upper_bound
    @testset "JuMP.has_upper_bound" begin
        @test has_upper_bound(prefs1[1])
        @test has_upper_bound(gvrefs1[2])
        @test !has_upper_bound(prefs2[2])
    end
    # test JuMP.upper_bound
    @testset "JuMP.upper_bound" begin
        @test upper_bound(prefs1[1]) == 1
        @test upper_bound(gvrefs1[2]) == 1
        @test_throws ErrorException upper_bound(prefs2[2])
    end
    # test JuMP.set_upper_bound
    @testset "JuMP.set_upper_bound" begin
        @test set_upper_bound(prefs1[1], 42) isa Nothing
        @test upper_bound(prefs1[1]) == 42
        @test set_upper_bound(gvrefs1[2], 0) isa Nothing
        @test upper_bound(prefs1[2]) == 0
        @test_throws ErrorException set_upper_bound(prefs2[2], 42)
    end
end

# test Support Methods
@testset "Support Methods" begin
    # Setup data
    m = InfiniteModel();
    gvrefs1 = @dependent_parameters(m, a[1:2] in [0, 1], num_supports = 2)
    prefs1 = dispatch_variable_ref.(gvrefs1)
    gvrefs2 = @dependent_parameters(m, b[1:2, 1:2] in MatrixBeta(2, 2, 2))
    prefs2 = dispatch_variable_ref.(gvrefs2)
    gvrefs3 = @dependent_parameters(m, c[1:2] in [0, 1])
    gvrefs4 = @dependent_parameters(m, d[1:2] in [0, 1], supports = 0)
    push!(InfiniteOpt._constraint_dependencies(prefs1[1]), ConstraintIndex(1))
    # test has_internal_supports
    @testset "has_internal_supports" begin
        @test !has_internal_supports(prefs1[1])
        @test !has_internal_supports(gvrefs4[2])
    end
    # test _set_has_internal_supports
    @testset "_set_has_internal_supports" begin
        @test InfiniteOpt._set_has_internal_supports(prefs1[1], true) isa Nothing
        @test has_internal_supports(prefs1[1])
        @test InfiniteOpt._set_has_internal_supports(gvrefs1[1], false) isa Nothing
        @test !has_internal_supports(prefs1[1])
    end
    # test _parameter_supports
    @testset "_parameter_supports" begin
        @test sort(collect(keys(InfiniteOpt._parameter_supports(prefs1[1])))) == [[0., 0.], [1., 1.]]
        @test isempty(InfiniteOpt._parameter_supports(prefs2[2]))
    end
    # test significant_digits
    @testset "significant_digits" begin
        @test significant_digits(prefs1[1]) == InfiniteOpt.DefaultSigDigits
        @test significant_digits(gvrefs1[2]) == InfiniteOpt.DefaultSigDigits
    end
    # test num_supports (Single)
    @testset "num_supports (Single)" begin
        # test default
        @test num_supports(prefs1[1]) == 2
        @test num_supports(gvrefs1[2]) == 2
        @test num_supports(prefs2[2]) == 0
        # test label
        @test num_supports(prefs1[1], label = MCSample) == 0
        @test num_supports(prefs1[1], label = UniformGrid) == 2
        @test num_supports(gvrefs1[2], label = MCSample) == 0
        @test num_supports(prefs1[1], label = All) == 2
        @test num_supports(prefs1[1], label = SampleLabel) == 0
    end
    # test num_supports (Array)
    @testset "num_supports (Array)" begin
        # test default
        @test num_supports(prefs1) == 2
        @test num_supports(gvrefs1) == 2
        @test num_supports(prefs2) == 0
        # test label
        @test num_supports(prefs1, label = MCSample) == 0
        @test num_supports(prefs1, label = UniformGrid) == 2
        @test num_supports(gvrefs1, label = MCSample) == 0
        # test error
        @test_throws ErrorException num_supports(prefs2[:, 1])
    end
    # test has_supports (Single)
    @testset "has_supports (Single)" begin
        @test has_supports(prefs1[1])
        @test has_supports(gvrefs1[2])
        @test !has_supports(prefs2[2])
    end
    # test has_supports (Array)
    @testset "has_supports (Array)" begin
        @test has_supports(prefs1)
        @test has_supports(gvrefs1)
        @test !has_supports(prefs2)
        # test error
        @test_throws ErrorException has_supports(prefs2[:, 1])
    end
    # test supports (Single)
    @testset "supports (Single)" begin
        # test default
        @test sort!(supports(prefs1[1])) == Float64[0, 1]
        @test sort!(supports(gvrefs1[2])) == Float64[0, 1]
        @test supports(prefs2[2]) == Float64[]
        # test label
        @test supports(prefs1[1], label = MCSample) == Float64[]
        @test sort!(supports(prefs1[1], label = UniformGrid)) == Float64[0, 1]
        @test supports(gvrefs1[2], label = MCSample) == Float64[]
        @test supports(gvrefs4[1], label = All) == [0]
    end
    # test supports (AbstractArray)
    @testset "supports (AbstractArray)" begin
        # test default
        new_prefs1 = convert(JuMPC.SparseAxisArray, prefs1)
        new_gvrefs1 = convert(JuMPC.SparseAxisArray, gvrefs1)
        expected = convert(JuMPC.SparseAxisArray, [Float64[0, 1] for i = 1:2])
        expected2 = convert(JuMPC.SparseAxisArray, [Float64[] for i = 1:2])
        @test sort!.(supports(new_prefs1)) == expected
        @test sort!.(supports(new_gvrefs1)) == expected
        @test supports(prefs2) == [Float64[] for i in CartesianIndices(prefs2)]
        # test label
        @test supports(new_prefs1, label = MCSample) == expected2
        @test sort!.(supports(new_prefs1, label = UniformGrid)) == expected
        @test supports(new_gvrefs1, label = MCSample) == expected2
        @test supports(gvrefs4, label = All) == zeros(2, 1)
        @test supports(gvrefs4, label = AbstractSupportLabel) == zeros(2, 1)
    end
    # test supports (Vector)
    @testset "supports (Vector)" begin
        # test default
        @test sortcols(supports(prefs1)) == [0 1; 0 1]
        @test sortcols(supports(gvrefs1)) == [0 1; 0 1]
        @test supports(gvrefs3) == zeros(2, 0)
        @test supports(gvrefs4) == zeros(2, 1)
        # test label
        @test supports(prefs1, label = MCSample) == zeros(2, 0)
        @test sortcols(supports(prefs1, label = UniformGrid)) == [0 1; 0 1]
        @test supports(gvrefs1, label = MCSample) == zeros(2, 0)
        @test supports(gvrefs1, label = InternalLabel) == zeros(2, 0)
        # test error
        @test_throws ErrorException supports(prefs2[:, 1])
    end
    # test _update_parameter_supports
    @testset "_update_parameter_supports" begin
        old_supports = supports(prefs1)
        @test InfiniteOpt._update_parameter_supports(prefs1, ones(Int, 2, 3),
                                                     UserDefined) isa Nothing
        @test supports(prefs1) == ones(Float64, 2, 1)
        @test !optimizer_model_ready(m)
        @test InfiniteOpt._update_parameter_supports(prefs1, old_supports,
                                                     UniformGrid) isa Nothing
    end
    # test _make_support_matrix
    @testset "_make_support_matrix" begin
        # test errors
        supps = JuMPC.DenseAxisArray([[0] for i in CartesianIndices(prefs2)], 3:4, 1:2)
        @test_throws ErrorException InfiniteOpt._make_support_matrix(prefs2, supps)
        supps = [i[1] != 1 ? [0] : [0, 1] for i in CartesianIndices(prefs2)]
        @test_throws ErrorException InfiniteOpt._make_support_matrix(prefs2, supps)
        # test normal
        supps = [[1, 1, 1] for i in CartesianIndices(prefs2)]
        @test InfiniteOpt._make_support_matrix(prefs2, supps) == ones(Float64, 4, 3)
    end
    # test set_supports (Single)
    @testset "set_supports (Single)" begin
        @test_throws ErrorException set_supports(prefs1[1], [0, 1])
        @test_throws ErrorException set_supports(gvrefs1[1], [0, 1], label = Mixture)
    end
    # test set_supports (Vector)
    @testset "set_supports (Vector)" begin
        # test errors
        @test_throws ErrorException set_supports(prefs2[:, 1], ones(2, 2))
        @test_throws ErrorException set_supports(prefs1, ones(2, 2))
        @test_throws ErrorException set_supports(prefs1, ones(2, 2) * 2, force = true)
        # test default
        old_supports = supports(prefs1)
        @test set_supports(prefs1, ones(2, 3), force = true) isa Nothing
        @test supports(prefs1) == ones(Float64, 2, 1)
        @test collect(values(InfiniteOpt._parameter_supports(prefs1[1]))) == [Set([UserDefined])]
        # test keywords
        @test set_supports(gvrefs1, old_supports, force = true,
                           label = UniformGrid) isa Nothing
        @test sortcols(supports(prefs1)) == sortcols(old_supports)
        @test collect(values(InfiniteOpt._parameter_supports(prefs1[1]))) == [Set([UniformGrid]) for i = 1:2]
        # test setting with internal supports
        @test set_supports(gvrefs1, old_supports, force = true,
                            label = InternalLabel) isa Nothing
        @test sortcols(supports(prefs1, label = All)) == sortcols(old_supports)
        @test has_internal_supports(prefs1[1])
        @test set_supports(gvrefs1, old_supports, force = true,
                           label = UniformGrid) isa Nothing
        @test !has_internal_supports(prefs1[1])
    end
    # test set_supports (AbstractArray)
    @testset "set_supports (AbstractArray)" begin
        # default
        supps = [[1, 1, 1] for i in CartesianIndices(prefs2)]
        @test set_supports(prefs2, supps) isa Nothing
        @test supports(prefs2) == [ones(Float64, 1) for i in CartesianIndices(prefs2)]
        @test collect(values(InfiniteOpt._parameter_supports(prefs2[1]))) == [Set([UserDefined])]
        # test keywords
        supps = [Float64[] for i in CartesianIndices(prefs2)]
        @test set_supports(gvrefs2, supps, force = true, label = Mixture) isa Nothing
        @test supports(prefs2) == [ones(Float64, 0) for i in CartesianIndices(prefs2)]
        @test isempty(InfiniteOpt._parameter_supports(prefs2[1]))
    end
    # test add_supports (Single)
    @testset "add_supports (Single)" begin
        @test_throws ErrorException add_supports(prefs1[1], [0, 1])
        @test_throws ErrorException add_supports(gvrefs1[1], [0, 1], label = Mixture)
    end
    # test add_supports (Vector)
    @testset "add_supports (Vector)" begin
        # test errors
        @test_throws ErrorException add_supports(prefs2[:, 1], ones(2, 2))
        @test_throws ErrorException add_supports(prefs1, ones(2, 2) * 2)
        # test default
        @test add_supports(prefs1, 0.1 * ones(2, 2)) isa Nothing
        @test sortcols(supports(prefs1)) == Float64[0 0.1 1; 0 0.1 1]
        @test InfiniteOpt._parameter_supports(prefs1[1])[0.1 * ones(2)] == Set([UserDefined])
        # test keywords
        @test add_supports(gvrefs1, zeros(2, 1), check = false,
                           label = InternalLabel) isa Nothing
        @test sortcols(supports(prefs1)) == Float64[0 0.1 1; 0 0.1 1]
        @test InfiniteOpt._parameter_supports(prefs1[1])[zeros(2)] == Set([UniformGrid, InternalLabel])
        # test warning
        InfiniteOpt._data_object(prefs1[1]).has_deriv_constrs[1] = true
        warn = "Support/method changes will invalidate existing derivative evaluation " *
               "constraints that have been added to the InfiniteModel. Thus, " *
               "these are being deleted."
        @test_logs (:warn, warn) add_supports(prefs1, 0.1 * ones(2, 2)) isa Nothing
        InfiniteOpt._data_object(prefs1[1]).has_deriv_constrs[1] = false
    end
    # test add_supports (AbstractArray)
    @testset "add_supports (AbstractArray)" begin
        # default
        supps = [[1, 1, 1] for i in CartesianIndices(prefs2)]
        @test add_supports(prefs2, supps) isa Nothing
        @test supports(prefs2) == [ones(Float64, 1) for i in CartesianIndices(prefs2)]
        @test collect(values(InfiniteOpt._parameter_supports(prefs2[1]))) == [Set([UserDefined])]
        # test keywords
        supps = [[0.5] for i in CartesianIndices(prefs2)]
        @test add_supports(gvrefs2, supps, check = false, label = MCSample) isa Nothing
        @test sort!.(supports(prefs2)) == [[0.5, 1] for i in CartesianIndices(prefs2)]
        @test Set([MCSample]) in values(InfiniteOpt._parameter_supports(prefs2[1]))
    end
    # test delete_supports (Single)
    @testset "delete_supports (Single)" begin
        @test_throws ErrorException delete_supports(prefs1[1])
        @test_throws ErrorException delete_supports(gvrefs1[1])
    end
    # test delete_supports (AbstractArray)
    @testset "delete_supports (AbstractArray)" begin
        # test errors
        @test_throws ErrorException delete_supports(prefs2[:, 1])
        push!(InfiniteOpt._measure_dependencies(prefs1[1]), MeasureIndex(1))
        @test_throws ErrorException delete_supports(prefs1)
        empty!(InfiniteOpt._measure_dependencies(prefs1[1]))
        # test label deletion
        @test delete_supports(prefs1, label = InternalLabel) isa Nothing
        @test !has_internal_supports(prefs1[1])
        # normal
        @test delete_supports(prefs1) isa Nothing
        @test supports(prefs1) == zeros(Float64, 2, 0)
        @test delete_supports(gvrefs2) isa Nothing
        @test supports(prefs2) == [Float64[] for i in CartesianIndices(prefs2)]
    end
end

# test Support Filling
@testset "Support Filling" begin
    # Setup data
    m = InfiniteModel();
    gvrefs1 = @dependent_parameters(m, a[1:2] in [0, 1], num_supports = 2)
    prefs1 = dispatch_variable_ref.(gvrefs1)
    gvrefs2 = @dependent_parameters(m, b[1:2, 1:2] in MatrixBeta(2, 2, 2))
    prefs2 = dispatch_variable_ref.(gvrefs2)
    gvref = @independent_parameter(m, c in [0, 1])
    pref = dispatch_variable_ref(gvref)
    # test generate_and_add_supports!
    @testset "generate_and_add_supports!" begin
        # old_supports = supports(prefs1)
        set = infinite_set(prefs1)
        @test generate_and_add_supports!(prefs1, set, num_supports = 2) isa Nothing
        @test sortcols(supports(prefs1)) == Float64[0 1; 0 1]
        expected = [Set([UniformGrid]) for i = 1:2]
        @test collect(values(InfiniteOpt._parameter_supports(prefs1[1]))) == expected
        # @test set_supports(prefs1, old_supports, force = true) isa Nothing
    end
    # test fill_in_supports! (Single)
    @testset "fill_in_supports! (Single)" begin
        @test_throws ErrorException fill_in_supports!(prefs1[1])
        @test_throws ErrorException fill_in_supports!(gvrefs1[1])
    end
    # test fill_in_supports! (AbstractArray)
    @testset "fill_in_supports! (AbstractArray)" begin
        # test error
        @test_throws ErrorException fill_in_supports!(prefs2[1, :])
        # test default
        @test fill_in_supports!(prefs1) isa Nothing
        @test num_supports(prefs1) == 8
        @test fill_in_supports!(gvrefs2) isa Nothing
        @test num_supports(prefs2) == 10
        # test keywords
        @test fill_in_supports!(prefs1, num_supports = 2) isa Nothing
        @test num_supports(prefs1) == 8
        @test fill_in_supports!(gvrefs2, modify = false,
                                num_supports = 20) isa Nothing
        @test num_supports(prefs2) == 10
        # delete additions
        @test delete_supports(prefs1) isa Nothing
        @test delete_supports(prefs2) isa Nothing
    end
    # test fill_in_supports! (InfiniteModel)
    @testset "fill_in_supports! (InfiniteModel)" begin
        # test default
        @test fill_in_supports!(m) isa Nothing
        @test num_supports(prefs1) == 10
        @test num_supports(prefs2) == 10
        @test num_supports(pref) == 10
        # test with keywords
        @test fill_in_supports!(m, num_supports = 12, modify = false) isa Nothing
        @test num_supports(prefs1) == 10
        @test num_supports(prefs2) == 10
        @test num_supports(pref) == 10
    end
end

# Test parameter counting and listing methods
@testset "General Queries" begin
    # Setup data
    m = InfiniteModel();
    prefs1 = @dependent_parameters(m, a[1:2] in [0, 1], num_supports = 2)
    prefs2 = @dependent_parameters(m, b[1:2, 1:2] in MatrixBeta(2, 2, 2))
    pref = @independent_parameter(m, c in [0, 1])
    fpref = @finite_parameter(m, d, 10)
    # test num_parameters (Default)
    @testset "num_parameters (Default)" begin
        @test num_parameters(m) == 8
    end
    # test num_parameters (Specific Scalar)
    @testset "num_parameters (Specific Scalar)" begin
        @test num_parameters(m, IndependentParameter) == 1
        @test num_parameters(m, FiniteParameter) == 1
    end
    # test num_parameters (ScalarParameter)
    @testset "num_parameters (ScalarParameter)" begin
        @test num_parameters(m, ScalarParameter) == 2
    end
    # test num_parameters (DependentParameters)
    @testset "num_parameters (DependentParameters)" begin
        @test num_parameters(m, DependentParameters) == 6
    end
    # test num_parameters (InfiniteParameter)
    @testset "num_parameters (InfiniteParameter)" begin
        @test num_parameters(m, InfiniteParameter) == 7
    end
    # test all_parameters (Default)
    @testset "all_parameters (Default)" begin
        @test all_parameters(m) == [pref; prefs1; [prefs2...]; fpref]
    end
    # test all_parameters (Specific Scalar)
    @testset "all_parameters (Specific Scalar)" begin
        @test all_parameters(m, IndependentParameter) == [pref]
        @test all_parameters(m, FiniteParameter) == [fpref]
    end
    # test all_parameters (ScalarParameter)
    @testset "all_parameters (ScalarParameter)" begin
        @test all_parameters(m, ScalarParameter) == [pref, fpref]
    end
    # test all_parameters (DependentParameters)
    @testset "all_parameters (DependentParameters)" begin
        @test all_parameters(m, DependentParameters) == [prefs1; [prefs2...]]
    end
    # test all_parameters (InfiniteParameter)
    @testset "all_parameters (InfiniteParameter)" begin
        @test all_parameters(m, InfiniteParameter) == [prefs1; [prefs2...]; pref]
    end
end

ext: jl


text:
"""
The `assembleFreeEnergy` function accepts an `Algorithm` and populates
required fields for computing the variational free energy.
"""
function assembleFreeEnergy!(algo=currentInferenceAlgorithm())
    # Find counting numbers for energies and entropies
    pfz = algo.posterior_factorization
    assembleCountingNumbers!(pfz)

    # Convert energy counting numbers to energy inbounds
    average_energies_vect = Vector{Dict{Symbol, Any}}()
    entropies_vect = Vector{Dict{Symbol, Any}}()

    energy_counting_numbers_vect = [(node, cnt) for (node, cnt) in pfz.energy_counting_numbers] # Order the Dict in a Vector
    for (node, cnt) in sort(energy_counting_numbers_vect)
        if cnt != 0
            average_energy = Dict{Symbol, Any}(:counting_number => cnt,
                                               :node => typeof(node),
                                               :node_id => node.id,
                                               :inbounds => collectAverageEnergyInbounds(node))
            push!(average_energies_vect, average_energy)
        end
    end

    # Convert entropy counting numbers to entropy inbounds
    entropy_counting_numbers_vect = [(target, cnt) for (target, cnt) in pfz.entropy_counting_numbers] # Order the Dict in a Vector
    for (target, cnt) in sort(entropy_counting_numbers_vect)
        if cnt != 0
            entropy = Dict{Symbol, Any}(:counting_number => cnt,
                                        :target => target,
                                        :inbound => algo.target_to_marginal_entry[target])
            push!(entropies_vect, entropy)
        end
    end

    algo.average_energies = average_energies_vect
    algo.entropies = entropies_vect

    return algo
end

"""
The `assembleCountingNumbers` function accepts an `Algorithm` and
populates the counting numbers for the average energies and entropies.
"""
function assembleCountingNumbers!(pfz=currentPosteriorFactorization())
    pfz.free_energy_flag || error("Required quantities for free energy evaluation are not computed by the algorithm. Make sure to flag free_energy=true upon algorithm construction to schedule computation of required quantities.")

    energy_counting_numbers = Dict{FactorNode, Int64}()
    entropy_counting_numbers = Dict{Region, Int64}()

    # Collect regions
    internal_edges = Set{Edge}()
    for (_, pf) in pfz.posterior_factors
        union!(internal_edges, pf.internal_edges)
    end
    nodes_connected_to_internal_edges = nodes(internal_edges)

    # Iterate over large regions
    for node in nodes_connected_to_internal_edges
        target_regions = unique!(localStochasticRegions(node, pfz)) # Collect all unique stochastic regions around node
        if isDeltaConstraint(node)
            continue
        elseif !isa(node, DeltaFactor) # Node is stochastic
            increase!(energy_counting_numbers, node, 1) # Count average energy
            for target in target_regions
                increase!(entropy_counting_numbers, target, 1) # Count (joint) entropy
            end
        elseif isa(node, Equality)
            increase!(entropy_counting_numbers, node.i[1].edge.variable, 1) # Count univariate entropy
        elseif length(node.interfaces) >= 2 # Node is deterministic and not equality, requires the counting of the joint inbounds region
            outbound_region = region(node, node.interfaces[1].edge)
            for target in target_regions
                if target != outbound_region # Exclude outbound region
                    increase!(entropy_counting_numbers, target, 1) # Count (joint) entropy
                end
            end
        end
    end

    # Iterate over small regions
    for edge in internal_edges
        increase!(entropy_counting_numbers, edge.variable, -(degree(edge) - 1)) # Discount univariate entropy
        if edge in pfz.deterministic_edges
            entropy_counting_numbers[edge.variable] = 0 # However, ignore entropies of deterministic beliefs
        end
    end

    pfz.energy_counting_numbers = energy_counting_numbers
    pfz.entropy_counting_numbers = entropy_counting_numbers

    return pfz
end

"""
Increase (or decrease) a counting number
"""
function increase!(dict::Dict, key::Any, increase::Number)
    if haskey(dict, key)
        dict[key] += increase
    else
        dict[key] = increase
    end

    return dict
end


text:
using Distributions
using LinearAlgebra
using Random

# Define the DGP
function simulate_sample(N0, N1)
    dy1 = LogNormal(0.3, 0.7);
    dy2 = MixtureModel(LogNormal, [(0.0, 1.0), (0.3, 1.2)], [0.6, 0.4]);
    X0 = [ones(N0) rand([0, 1], N0, 4) rand(N0)]
    X1 = kron([ones(2, 4) [1, 0] [0, 0]], ones(N1))
    y0 = [X0[i, end] == 1 ? rand(dy2) : rand(dy1) for i in 1:N0]
    y1 = LinRange(0, 6, N1) |> collect |> x -> repeat(x, 2)
    c0 = rand(Exponential(12), N0)
    z0 = deepcopy(y0)
    return dy1, dy2, z0, c0, y0, X0, y1, X1
end

# Not run
Random.seed!(1);
N0, N1 = 500, 0;
dy1, dy2, z0, c0, y0, X0, y1, X1 = simulate_sample(N0, N1);
mean(z0 .> c0)


text:
function FULLOPTEQ(trans::SparseMatrixCSC{Float64, Int64},
                   capacity::Array{Int64,1},
                   abort::Int64,
                   show_opt::Int64,
                   cpu_cores::Int64,
                   allowed_gap::Float64,
                   max_nodes::Int64)
    trans = Matrix(trans)
    if CHECKCAPACITY(trans,capacity) == 1
        allocation = Model(GAMS.Optimizer)
        if show_opt == 0
            set_silent(allocation)
        end
        set_optimizer_attribute(allocation, GAMS.ModelType(), "MIP")
        set_optimizer_attribute(allocation, "Solver",  "CPLEX")
        set_optimizer_attribute(allocation, "OptCR",   allowed_gap)
        set_optimizer_attribute(allocation, "ResLim",  abort)
        set_optimizer_attribute(allocation, "Threads", cpu_cores)
        set_optimizer_attribute(allocation, "NodLim",  max_nodes)
        GJ = 1:size(trans,1)
        GI = 1:size(trans,2)
        GK = 1:size(capacity,1)
        @variable(allocation, X[GI,GK], Bin)
        @variable(allocation, Y[GJ,GK], Bin)
        @objective(allocation, Min, sum(Y[j,k] for j in GJ, k in GK))
        @constraint(allocation, capconstraint[k in GK], sum(X[i,k] for i in GI) == capacity[k])
        @constraint(allocation, minallocation[i in GI], sum(X[i,k] for k in GK) == 1)
        @constraint(allocation, mapping[j in GJ, k in GK, i in GI; trans[j,i] == 1], X[i,k] <= Y[j,k])
        JuMP.optimize!(allocation)
        G = abs(objective_bound(allocation)-objective_value(allocation))/abs(objective_value(allocation)+0.00000000001)
        P = objective_value(allocation)
        out = Array{Int64,2}(undef,size(trans,2),size(capacity,1)) .= 0
        for i = 1:size(out,1)
            for j = 1:size(out,2)
                if value.(X[i,j]) > 0
                    out[i,j] = 1
                end
            end
        end
        return out::Array{Int64,2},G::Float64,P::Float64
    end
end

max_stars_repo_name: beyondatlas/splitdeliveries

max_issues_repo_name: beyondatlas/splitdeliveries

max_forks_repo_name: beyondatlas/splitdeliveries


text:
@doc """
Euler method

Step Propagation using the Euler formula.
""" ->
immutable QuEuler <: QuPropagatorMethod
end

@doc """
Crank Nicolson Method

Step Propagation using the Crank Nicolson formula.
""" ->
immutable QuCrankNicolson <: QuPropagatorMethod
end

@doc """
Krylov subspace Method

Step Propagation using the Krylov subspace method.

### Fields :

* options :: Dict

  Dictionary to set the size of basis by using the key `:NC`.
""" ->
immutable QuKrylov <: QuPropagatorMethod
    options::Dict
end

QuKrylov() = QuKrylov(@compat Dict(:NC=>10))

@doc """
Propagate for different solver types.

Method used to propagate one time step using the solver.

### Arguments

Inputs :
* prob <: QuPropagatorMethod

  Solver type (Method to be used  -> QuEuler, QuCrankNicolson,
                       QuKrylov, QuODE45, QuODE78, QuODE23s,
                       QuExpmV, QuExpokit, QuMCWF)
* eq <: QuEquation

  Equation type
* t :: Float64

  Final time
* current_t :: Float64

  Current time
* current_qustate

  Quantum state corresponding to current time

Output :
* Same type as current_qustate.
""" ->
function propagate(prob::QuEuler, eq::QuEquation, t, current_t, current_qustate)
    dt = t - current_t
    dims = size(current_qustate)
    op = operator(eq, t)
    next_state = (eye(op)-im*op*dt)*vec(current_qustate)
    CQST = QuBase.similar_type(current_qustate)
    return CQST(reshape(coeffs(next_state), dims), bases(current_qustate))
end

function propagate(prob::QuCrankNicolson, eq::QuEquation, t, current_t, current_qustate)
    dt = t - current_t
    dims = size(current_qustate)
    op = operator(eq, t)
    uni = eye(op)-im*op*dt/2
    next_state = \(uni', uni*vec(current_qustate))
    CQST = QuBase.similar_type(current_qustate)
    return CQST(reshape(coeffs(next_state), dims), bases(current_qustate))
end

function propagate(prob::QuKrylov, eq::QuEquation, t, current_t, current_qustate)
    dt = t - current_t
    dims = size(current_qustate)
    cqs = vec(current_qustate)
    basis_size = get(prob.options,:NC, length(cqs))
    N = min(basis_size, length(cqs))
    v = Array(typeof(cqs),0)
    @compat sizehint!(v, N+1)
    push!(v,zeros(cqs))
    push!(v,cqs)
    alpha = Array(Complex{Float64},0)
    @compat sizehint!(alpha, N)
    beta = Array(Complex{Float64},0)
    @compat sizehint!(beta, N+1)
    op = operator(eq, t)
    push!(beta,0.)
    for i=2:N
        w = op*v[i]
        push!(alpha, w'*v[i])
        w = w-alpha[i-1]*v[i]-beta[i-1]*v[i-1]
        push!(beta, norm(w))
        push!(v, w/beta[i])
    end
    w = op*v[end]
    push!(alpha, w'*v[end])
    deleteat!(v,1)
    H_k = full(Tridiagonal(beta[2:end], alpha, beta[2:end]))
    U_k = expm(-im*dt*H_k)
    next_state = zeros(cqs)
    for j=1:N
        next_state = next_state + v[j]*U_k[j,1]
    end
    CQST = QuBase.similar_type(current_qustate)
    return CQST(reshape(coeffs(next_state), dims), bases(current_qustate))
end

export QuEuler,
     QuCrankNicolson,
     QuKrylov


text:
# Autogenerated wrapper script for libclangex_jll for i686-linux-gnu-cxx03-julia_version+1.8.0
export libclangex

JLLWrappers.@generate_wrapper_header("libclangex")
JLLWrappers.@declare_library_product(libclangex, "libclangex.so")
function __init__()
    JLLWrappers.@generate_init_header()
    JLLWrappers.@init_library_product(
        libclangex,
        "lib/libclangex.so",
        nothing,
    )

    JLLWrappers.@generate_init_footer()
end  # __init__()


text:
"""
GenX: An Configurable Capacity Expansion Model
Copyright (C) 2021,  Massachusetts Institute of Technology
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
A complete copy of the GNU General Public License v2 (GPLv2) is available
in LICENSE.txt.  Users uncompressing this from an archive may not have
received this license file.  If not, see <http://www.gnu.org/licenses/>.
"""

@doc raw"""
	write_reserve_margin_revenue(path::AbstractString, inputs::Dict, setup::Dict, dfPower::DataFrame, dfCharge::DataFrame, dfResMar::DataFrame, dfCap::DataFrame)

Function for reporting the capacity revenue earned by each generator listed in the input file. GenX will print this file only when capacity reserve margin is modeled and the shadow price can be obtained form the solver. Each row corresponds to a generator, and each column starting from the 6th to the second last is the total revenue from each capacity reserve margin constraint. The revenue is calculated as the capacity contribution of each time steps multiplied by the shadow price, and then the sum is taken over all modeled time steps. The last column is the total revenue received from all capacity reserve margin constraints.  As a reminder, GenX models the capacity reserve margin (aka capacity market) at the time-dependent level, and each constraint either stands for an overall market or a locality constraint.
"""
function write_reserve_margin_revenue(path::AbstractString, inputs::Dict, setup::Dict, dfPower::DataFrame, dfCharge::DataFrame, dfResMar::DataFrame, dfCap::DataFrame)
	dfGen = inputs["dfGen"]
	G = inputs["G"]     # Number of resources (generators, storage, DR, and DERs)
	T = inputs["T"]     # Number of time steps (hours)
	SEG = inputs["SEG"]  # Number of lines
	Z = inputs["Z"]     # Number of zonests
	L = inputs["L"] # Number of lines
	THERM_ALL = inputs["THERM_ALL"]
	VRE = inputs["VRE"]
	HYDRO_RES = inputs["HYDRO_RES"]
	# VRE_HYDRO_RES = union(inputs["HYDRO_RES"],inputs["VRE"])
	STOR_ALL = inputs["STOR_ALL"]
	FLEX = inputs["FLEX"]
	### calculating capacity reserve revenue

	dfResRevenue = DataFrame(region = dfGen[!,:region], Resource = inputs["RESOURCES"], zone = dfGen[!,:Zone], Cluster = dfGen[!,:cluster], R_ID = dfGen[!,:R_ID])
	for i in 1:inputs["NCapacityReserveMargin"]
		# initiate the process by assuming everything is thermal
		dfResRevenue = hcat(dfResRevenue, round.(Int, dfCap[1:end-1,:EndCap] .* dfGen[!,Symbol("CapRes_$i")] .* sum(dfResMar[i,:])))
		for y in 1:G
			if (y in STOR_ALL)
				dfResRevenue[y,:x1] = round.(Int, sum(
				(DataFrame([[names(dfPower)]; collect.(eachrow(dfPower))], [:column; Symbol.(axes(dfPower, 1))])[4:T+3,y+1] .-
				DataFrame([[names(dfPower)]; collect.(eachrow(dfCharge))], [:column; Symbol.(axes(dfPower, 1))])[4:T+3,y+1]) .*
				DataFrame([[names(dfResMar)]; collect.(eachrow(dfResMar))], [:column; Symbol.(axes(dfResMar, 1))])[!,i+1] .* dfGen[y,Symbol("CapRes_$i")]))
			elseif (y in HYDRO_RES)
				dfResRevenue[y,:x1] = round.(Int, sum((DataFrame([[names(dfPower)]; collect.(eachrow(dfPower))], [:column; Symbol.(axes(dfPower, 1))])[4:T+3,y+1]) .*
				DataFrame([[names(dfResMar)]; collect.(eachrow(dfResMar))], [:column; Symbol.(axes(dfResMar, 1))])[!,i+1] .* dfGen[y,Symbol("CapRes_$i")]))
           		elseif (y in VRE)
                		dfResRevenue[y,:x1] = round.(Int, sum( dfCap[y,:EndCap] .* inputs["pP_Max"][y,:] .*
                		DataFrame([[names(dfResMar)]; collect.(eachrow(dfResMar))], [:column; Symbol.(axes(dfResMar, 1))])[!,i+1] .* dfGen[y,Symbol("CapRes_$i")]))
			elseif (y in FLEX)
				dfResRevenue[y,:x1] = round.(Int, sum(
				(DataFrame([[names(dfPower)]; collect.(eachrow(dfCharge))], [:column; Symbol.(axes(dfPower, 1))])[4:T+3,y+1] .-
				DataFrame([[names(dfPower)]; collect.(eachrow(dfPower))], [:column; Symbol.(axes(dfPower, 1))])[4:T+3,y+1]) .*
				DataFrame([[names(dfResMar)]; collect.(eachrow(dfResMar))], [:column; Symbol.(axes(dfResMar, 1))])[!,i+1] .* dfGen[y,Symbol("CapRes_$i")]))
			end
		end
		# the capacity and power is in MW already, no need to scale
		# if setup["ParameterScale"] == 1
		# 	dfResRevenue[!,:x1] = dfResRevenue[!,:x1] * ModelScalingFactor #(1e+3) # This is because although the unit of price is US$/MWh, the capacity or generation is in GW
		# end
		rename!(dfResRevenue, Dict(:x1 => Symbol("CapRes_$i")))
	end
	dfResRevenue.AnnualSum = sum(eachcol(dfResRevenue[:,6:inputs["NCapacityReserveMargin"]+5]))

	CSV.write(joinpath(path, "ReserveMarginRevenue.csv"), dfResRevenue)
	return dfResRevenue
end

max_stars_repo_name: Betristor/LTESOM

max_issues_repo_name: Betristor/LTESOM

max_forks_repo_name: Betristor/LTESOM


text:
export NormL1_dual

"""
     NormL1_dual(x::AbstractArray, weights::AbstractArray, params::Dict)
"""
function NormL1_dual(x::AbstractVector{ETx},
                     weights::Tw,
                     params::Dict{String, Any}) where
                       {Tw<:Union{AbstractVector, Number}, ETx<:Number}

    d = norm(x./weights, Inf)

end


text:
using ProjectMoana

pcg = PCG()

@testset "PCG generator" begin
    @test pcg.state == 1753877967969059832
    @test pcg.inc == 109

    for expected in [2707161783, 2068313097, 3122475824, 2211639955, 3215226955, 3421331566]
        @test expected == pcg_rand(pcg)
    end

end


text:
#=
network.jl
~~~~~~~~~~

A module to implement the stochastic gradient descent learning
algorithm for a feedforward neural network. Gradients are calculated
using backpropagation. Note that I have focused on making the code
simple, easily readable, and easily modifiable. It is not optimized,
and omits many desirable features.

Original Python code: Copyright © 2012-2022 Michael Nielsen
Julia reimplementation: Copyright © 2018-2022 Derik Kauffman
Licensed under MIT license
=#

using Random

struct Network
	sizes::Vector{Int}
	biases::Vector{Vector{Float32}}
	weights::Vector{Matrix{Float32}}
end

"""
	Network(sizes::Vector{<:Integer})

The list `sizes` contains the number of neurons in the
respective layers of the network. For example, if the list
was [2, 3, 1] then it would be a three-layer network, with the
first layer containing 2 neurons, the second layer 3 neurons,
and the third layer 1 neuron. The biases and weights for the
network are initialized randomly, using a Gaussian
distribution with mean 0 and variance 1. Note that the first
layer is assumed to be an input layer, and by convention we
won't set any biases for those neurons, since biases are only
ever used in computing the outputs from later layers.
"""
function Network(sizes::Vector{<:Integer})
	biases = randn.(sizes[2:end])
	weights = randn.(zip(sizes[2:end], sizes[1:end-1]))
	Network(sizes, biases, weights)
end

"""
	feedforward(net::Network, a::AbstractVector{<:Real})

Return the output of the network if `a` is input.
"""
function feedforward(net::Network, a::AbstractVector{<:Real})
	for (b, w) = zip(net.biases, net.weights)
		a = σ.(w * a .+ b)
	end
	return a
end

"""
The neural network's output is assumed to be the index of whichever
neuron in the final layer has the highest activation.
"""
classify(net::Network, a::AbstractVector{<:Real}) = argmax(feedforward(net, a)) - 1

"""
Train the neural network using mini-batch stochastic gradient
descent. The `training_data` is a list of tuples `(x, y)`
representing the training inputs and the desired outputs.
The other non-optional parameters are self-explanatory.
If `test_data` is provided then the network will be evaluated
against the test data after each epoch, and partial progress
printed out. This is useful for tracking progress, but slows things
down substantially.
"""
function SGD!(net::Network, training_data, epochs::Integer,
	  mini_batch_size::Integer, η::Real; test_data=nothing)
	if test_data !== nothing n_test = length(test_data) end
	for j in 1:epochs
		shuffle!(training_data)
		mini_batches = reshape(training_data, :, mini_batch_size)
		for mini_batch in eachrow(mini_batches)
			update_mini_batch!(net, mini_batch, η)
		end

		if test_data !== nothing
			println("Epoch $j: $(evaluate(net, test_data)) / $n_test")
		else
			println("Epoch $j complete")
		end
	end
end

"""
	update_mini_batch!(net::Network, mini_batch, η::Real)

Update the network's weights and biases by applying
gradient descent using backpropagation to a single mini batch.
The `mini_batch` is a list of tuples `(x, y)`, and `η`
is the learning rate.
"""
function update_mini_batch!(net::Network, mini_batch, η::Real)
	∇b = zero.(net.biases)
	∇w = zero.(net.weights)
	for (x, y) in mini_batch
		Δ∇b, Δ∇w = backprop(net, x, y)
		∇b .+= Δ∇b
		∇w .+= Δ∇w
	end
	net.biases  .-= Float32(η / length(mini_batch)) .* ∇b # Eq. 21
	net.weights .-= Float32(η / length(mini_batch)) .* ∇w # Eq. 20
end

"""
	backprop(net::Network, x, y)

Return a tuple `(∇b, ∇w)` representing the gradient for the
cost function Cₓ. `∇b` and `∇w` are layer-by-layer lists of arrays,
similar to `net.biases` and `net.weights`.
"""
function backprop(net::Network, x, y)
	∇b = zero.(net.biases)
	∇w = zero.(net.weights)

	# feedforward
	activation = x
	activations = [x] # list to store all the activations, layer by layer
	zs = typeof(x)[]  # list to store all the z vectors, layer by layer
	for (b, w) = zip(net.biases, net.weights)
		z = w * activation .+ b
		push!(zs, z)
		activation = σ.(z)
		push!(activations, activation)
	end

	# backward pass
	δ = cost_derivative(activations[end], y) .* σ′.(zs[end]) # Eq. BP1
	∇b[end] = δ
	∇w[end] = δ * activations[end-1]'

	for l in length(net.sizes)-1:2
		z = zs[l]
		δ = (net.weights[l+1]' * δ) .* σ′.(z) # Eq. BP2
		∇b[l] = δ # Eq. BP3
		∇w[l] = δ * activations[l-1]' # Eq. BP4
	end
	return ∇b, ∇w
end

"""
	evaluate(net::Network, test_data)

Return the number of test inputs for which the neural
network outputs the correct result.
"""
function evaluate(net::Network, test_data)
	return count((classify(net, x) == y) for (x, y) in test_data)
end

"""
	cost_derivative(output_activations, y)

Return the vector of partial derivatives ∂Cₓ/∂a for the output activations.
"""
cost_derivative(output_activations, y) = output_activations .- onehot(y)

#### Miscellaneous functions
"""The sigmoid function."""
σ(z) = 1/(1 + exp(-z))

"""Derivative of the sigmoid function."""
σ′(z) = σ(z) * (1 - σ(z))

"""
	onehot(j::Integer)

Return a 10-dimensional unit vector with a 1 in the jth
position and zeros elsewhere. This is used to convert a digit (0-9)
into a corresponding desired output from the neural network.
"""
function onehot(j::Integer)
	e = falses(10)
	e[j+1] = true
	return e
end

# MNIST loading code
using MLDatasets

function load_data()
	training_inputs = reshape(MNIST.traintensor(Float32), 784, :)
	training_labels = MNIST.trainlabels()
	training_data = zip(eachcol(training_inputs), training_labels)

	test_inputs = reshape(MNIST.testtensor(Float32), 784, :)
	test_labels = MNIST.testlabels()
	test_data = zip(eachcol(test_inputs), test_labels)
	println("Loaded data")
	return training_data, test_data
end

function test_mnist()
	training_data, test_data = load_data()
	net = Network([784, 30, 10])
	SGD!(net, training_data, 30, 10, 0.1, test_data=test_data)
	return net
end

function test_mnist_quick()
	training_data, test_data = load_data()
	net = Network([784, 10])
	SGD!(net, training_data, 5, 10, 3.0, test_data=test_data)
	return net
end

max_stars_repo_name: derikk/nndl-julia

max_issues_repo_name: derikk/nndl-julia

max_forks_repo_name: derikk/nndl-julia


text:
# Interface Concorde / Julia

function versTSPLIB(instance)
    sortie = open("temp/instance_TSPLIB", "w")
    write(sortie, "NAME : none")
    write(sortie, "\nCOMMENT : none")
    write(sortie, "\nTYPE : TSP")
    write(sortie, "\nDIMENSION : "*string(instance.nbPoints))
    write(sortie, "\nEDGE_WEIGHT_TYPE : EUC_2D")
    write(sortie, "\nNODE_COORD_SECTION")
    for i in 1:instance.nbPoints
        # On multiplie par 1000 car Concorde ne gère pas les flottants, cela évite donc de se retrouver avec des erreurs liées aux arrondies
        # Les distances sur certaines instances peuvent en effet être sensiblement proches
        write(sortie, "\n"*string(i)*" "*string(instance.listePoints[i].x*1000)*" "*string(instance.listePoints[i].y*1000))
    end
    write(sortie, "\nEOF")
    close(sortie);
end

function lectureSolutionLINKERN()
    # On lit la solution dans le fichier de sortie après exécution programme linkern
    f = open("temp/res")
    lignes = readlines(f)
    ordreVisite = []
    push!(ordreVisite, 1)
    for i in 2:size(lignes,1)
       push!(ordreVisite, parse.(Int64, split(lignes[i])[2]) + 1)
    end
    close(f)
    return ordreVisite
end

function lectureSolutionCONCORDE()
    # On lit la solution dans le fichier de sortie après exécution programme concorde
    f = open("temp/res")
    lignes = readlines(f)
    ordreVisite = []
    l = 2
    n = 1
    for i in 1:parse.(Int64, lignes[1])
       push!(ordreVisite, parse.(Int64, split(lignes[l])[n]) + 1)
       if mod(i,10) == 0 # 10 noeuds par ligne
           l += 1
           n = 1
       else
           n += 1
       end
    end
    push!(ordreVisite, 1)
    close(f)
    return ordreVisite
end

function resolutionConcorde(instance)
    asciiArtAvion()
    versTSPLIB(instance) # On convertit l'instance courante vers le format TSPLIB (compatible Concorde)

    println("\n Choix du type de résolution (TSP) :")
    println(" -----------------------------------")
    println("    --> 1) Exacte")
    println("    --> 2) Approchée : Lin-Kernighan (à personnaliser)")
    println("    --> 3) Approchée : Lin-Kernighan (défaut)")
    choix = choixListe(3)
    if choix == "1"
         run(pipeline(`./concorde/concorde -o temp/res temp/instance_TSPLIB`, stdout=devnull, stderr=devnull))
         ordreVisite = lectureSolutionCONCORDE()
         instance.codeResolution = 1
    elseif choix == "2"
         println("\n Construction initiale : ")
         println(" -----------------------")
         println("    --> 1) Aléatoire")
         println("    --> 2) Nearest-Neighbor")
         println("    --> 3) Glouton")
         println("    --> 4) Boruvka")
         println("    --> 5) Quick-Boruvka")
         choix = choixListe(5)
         constructionInitiale = string((parse(Int64, choix)-1))
         # Note : on repasse le choix en int pour y soustraire une unité et correspondre aux choix proposés par le programme linkern
         # 0 : Aléatoire, 1 : Nearest-Neighbor, 2 : Glouton, 3 : Boruvka, 4 : Quick-Boruvka
         # On repasse ensuite en string pour personnaliser la commande ci-dessous

         println("\n Choix du kick : ")
         println(" ---------------")
         println("    --> 1) Aléatoire")
         println("    --> 2) Géométrique")
         println("    --> 3) Close")
         println("    --> 4) Marche Aléatoire")
         choix = choixListe(4)
         kick = string((parse(Int64, choix)-1))

         print("\n Temps limite de résolution (secondes) : ")
         tempsLimite = readline()
         tempsLimite = parse(Int64, tempsLimite)

         run(pipeline(`./concorde/linkern -I $constructionInitiale -K $kick -t $tempsLimite -o temp/res temp/instance_TSPLIB`, stdout=devnull, stderr=devnull)) # On sauvegarde le résultat de la résolution dans le fichier temporaire res et on ne conserve pas l'affichage textuelle
         ordreVisite = lectureSolutionLINKERN()
         instance.codeResolution = 2
    elseif choix == "3"
        # Ici on exécute Lin-Kernighan avec les choix par défaut
        # Quick-boruvka + Random_walk kicks
        # Nombre de kicks : nombre de noeuds
        run(pipeline(`./concorde/linkern -o temp/res temp/instance_TSPLIB`, stdout=devnull, stderr=devnull))
        ordreVisite = lectureSolutionLINKERN()
        instance.codeResolution = 2
    end
    run(`./clean.sh`) # On supprime les fichiers résiduels
    # Note : on ne peut pas utiliser le pattern * (propre au shell) avec la fonction run(), il semblerait que cela va être implémenté dans les prochaines versions de Julia (vu sur discourse.julialang.org : "using * as a wildcard in backtick commands").
    # Pour cette raison, on passe par un script Shell annexe pour supprimer les fichiers temporaires
    solution = Solution(ordreVisite, [], coutTour(ordreVisite, instance), 0)
    instance.solution = solution
end

function asciiArtAvion()
    println("")
    println(" _____         ______  ")
    println("| : \\         |    \\   ")
    println("| :  `\\______|______\\_______ ")
    println(" \\'______    Concorde  \\_____\\_____ ")
    println("   \\____/-)_,---------,_____________>-- ")
    println("             \\       / ")
    println("              |     / ")
    println("              |____/__  ")
    println("")
end

########## Fonctions rapides (sans affichage ni lecture utilisateur) ##########

function concordeFast(instance) # 0 verbosité
    versTSPLIB(instance)
    run(pipeline(`./concorde/concorde -o temp/res temp/instance_TSPLIB`, stdout=devnull, stderr=devnull))
    ordreVisite = lectureSolutionCONCORDE()
    instance.codeResolution = 1
    run(`./clean.sh`) # On supprime les fichiers résiduels
    solution = Solution(ordreVisite, [], coutTour(ordreVisite, instance), 0)
    instance.solution = solution
end

function lkhFast(instance) # 0 verbosité
    versTSPLIB(instance)
    run(pipeline(`./concorde/linkern -o temp/res temp/instance_TSPLIB`, stdout=devnull, stderr=devnull))
    ordreVisite = lectureSolutionLINKERN()
    instance.codeResolution = 2
    run(pipeline(`./clean.sh`, stderr=devnull)) # On supprime les fichiers résiduels
    solution = Solution(ordreVisite, [], coutTour(ordreVisite, instance), 0)
    instance.solution = solution
end

max_stars_repo_name: xgandibleux/tspd-solver

max_issues_repo_name: xgandibleux/tspd-solver

max_forks_repo_name: xgandibleux/tspd-solver


text:
module Gym

using Flux

#Spaces
include("Spaces/Space.jl")
using .Space
export sample

include("Envs/registry.jl")
export make, register,        	     		# Registry functions
       EnvWrapper, reset!, step!, state,
       trainable, game_over, testmode!  # Environment interaction functions

end #module


text:
using Plots

anim = @animate for i in 1:10
    plot(t->sinpi(t+i/5), range(0, 2, length=100))
end

gif(anim, "test_animation.gif", fps=40)


text:
@testset "Searches" begin
    @testset "Searches: Binary" begin
        @testset "binary_search - first method" begin
            sample = [0, 23, 52, 552, 555, 602, 1004]
            reversed_sample = reverse(sample)
            unsorted_sample = [124, 53, 21, 163]
            @test binary_search(sample, 52) == 3:3
            @test binary_search(sample, 602) == 6:6
            @test binary_search(reversed_sample, 52; rev=true) == 5:5
            @test binary_search(reversed_sample, 602; rev=true) == 2:2
            @test_throws ErrorException binary_search(unsorted_sample, 21)  # throws an error
        end
        @testset "binary_search - second method" begin
            # Second method used for exponential search
            arr = [1, 2, 3, 4, 13, 15, 20]
            # The next three values used are the result of the while-loop inside `exponential search`
            @test binary_search(arr, 4, 7, 4) == "Element present at index 4"
            @test binary_search(arr, 4, 7, 10) == "Element not present in array"
        end
    end

    @testset "Searches: Linear" begin
        array = [1, 3, 4, 7, 8, 11]
        linear_search(array, 3)
        linear_search(array, 8)
        linear_search(array, 12)
    end

    @testset "Searches: Exponential" begin
        arr = [1, 2, 3, 4, 13, 15, 20]
        x = 4
        n = size(arr)[1]
        l = 1
        r = n
        @test exponential_search(arr, 1) == "Element present at index 1"
        @test exponential_search(arr, x) == "Element present at index 4"
        @test exponential_search(arr, 100) == "Element not present in array"
    end

    @testset "Searches: Interpolation" begin
        arr = [1, 2, 3, 4, 13, 15, 20]
        x = 15
        n = size(arr)[1]
        l = 1
        r = n

        interpolation_search(arr, l, r, x)
    end

    @testset "Searches: Jump" begin
        arr = [1, 2, 3, 31, 4, 13]
        x = 31
        jump = 2 # optimum is sqroot(n)
        n = size(arr)[1]

        jump_search(arr, x, jump)
    end
end

max_stars_repo_name: KohRongSoon/Julia

max_issues_repo_name: KohRongSoon/Julia

max_forks_repo_name: KohRongSoon/Julia


text:
@testset "io.jl" begin
    # Only test threading if 1.3+.
    if VERSION > v"1.2"
        @testset "threaded sampling" begin
            # Test that chains with the same seed will sample identically.
            @testset "rng" begin
                model = gdemo_default

                # multithreaded sampling with PG causes segfaults on Julia 1.5.4
                # https://github.com/TuringLang/Turing.jl/issues/1571
                samplers = @static if VERSION <= v"1.5.3" || VERSION >= v"1.6.0"
                    (
                        HMC(0.1, 7),
                        PG(10),
                        IS(),
                        MH(),
                        Gibbs(PG(3, :s), HMC(0.4, 8, :m)),
                        Gibbs(HMC(0.1, 5, :s), ESS(:m)),
                    )
                else
                    (
                        HMC(0.1, 7),
                        IS(),
                        MH(),
                        Gibbs(HMC(0.1, 5, :s), ESS(:m)),
                    )
                end
                for sampler in samplers
                    Random.seed!(5)
                    chain1 = sample(model, sampler, MCMCThreads(), 1000, 4)

                    Random.seed!(5)
                    chain2 = sample(model, sampler, MCMCThreads(), 1000, 4)

                    @test chain1.value == chain2.value
                end
            end

            # Smoke test for default sample call.
            Random.seed!(100)
            chain = sample(gdemo_default, HMC(0.1, 7), MCMCThreads(), 1000, 4)
            check_gdemo(chain)

            # run sampler: progress logging should be disabled and
            # it should return a Chains object
            sampler = Sampler(HMC(0.1, 7), gdemo_default)
            chains = sample(gdemo_default, sampler, MCMCThreads(), 1000, 4)
            @test chains isa MCMCChains.Chains
        end
    end
    @testset "chain save/resume" begin
        Random.seed!(1234)

        alg1 = HMCDA(1000, 0.65, 0.15)
        alg2 = PG(20)
        alg3 = Gibbs(PG(30, :s), HMCDA(500, 0.65, 0.05, :m))

        chn1 = sample(gdemo_default, alg1, 5000; save_state=true)
        check_gdemo(chn1)

        chn1_resumed = Turing.Inference.resume(chn1, 1000)
        check_gdemo(chn1_resumed)

        chn1_contd = sample(gdemo_default, alg1, 5000; resume_from=chn1)
        check_gdemo(chn1_contd)

        chn1_contd2 = sample(gdemo_default, alg1, 5000; resume_from=chn1, reuse_spl_n=1000)
        check_gdemo(chn1_contd2)

        chn2 = sample(gdemo_default, alg2, 1000; save_state=true)
        check_gdemo(chn2)

        chn2_contd = sample(gdemo_default, alg2, 1000; resume_from=chn2)
        check_gdemo(chn2_contd)

        chn3 = sample(gdemo_default, alg3, 1000; save_state=true)
        check_gdemo(chn3)

        chn3_contd = sample(gdemo_default, alg3, 1000; resume_from=chn3)
        check_gdemo(chn3_contd; atol=0.25)
    end
    @testset "Contexts" begin
        # Test LikelihoodContext
        @model testmodel(x) = begin
            a ~ Beta()
            lp1 = getlogp(_varinfo)
            x[1] ~ Bernoulli(a)
            global loglike = getlogp(_varinfo) - lp1
        end
        model = testmodel([1.0])
        varinfo = Turing.VarInfo(model)
        model(varinfo, Turing.SampleFromPrior(), Turing.LikelihoodContext())
        @test getlogp(varinfo) == loglike

        # Test MiniBatchContext
        @model testmodel(x) = begin
            a ~ Beta()
            x[1] ~ Bernoulli(a)
        end
        model = testmodel([1.0])
        varinfo1 = Turing.VarInfo(model)
        varinfo2 = deepcopy(varinfo1)
        model(varinfo1, Turing.SampleFromPrior(), Turing.LikelihoodContext())
        model(varinfo2, Turing.SampleFromPrior(), Turing.MiniBatchContext(Turing.LikelihoodContext(), 10))
        @test isapprox(getlogp(varinfo2) / getlogp(varinfo1), 10)
    end
    @testset "Prior" begin
        N = 5000

        # Note that all chains contain 3 values per sample: 2 variables + log probability
        Random.seed!(100)
        chains = sample(gdemo_d(), Prior(), N)
        @test chains isa MCMCChains.Chains
        @test size(chains) == (N, 3, 1)
        @test mean(chains, :s) ≈ 3 atol=0.1
        @test mean(chains, :m) ≈ 0 atol=0.1

        Random.seed!(100)
        chains = sample(gdemo_d(), Prior(), MCMCThreads(), N, 4)
        @test chains isa MCMCChains.Chains
        @test size(chains) == (N, 3, 4)
        @test mean(chains, :s) ≈ 3 atol=0.1
        @test mean(chains, :m) ≈ 0 atol=0.1

        Random.seed!(100)
        chains = sample(gdemo_d(), Prior(), N; chain_type = Vector{NamedTuple})
        @test chains isa Vector{<:NamedTuple}
        @test length(chains) == N
        @test all(length(x) == 3 for x in chains)
        @test all(haskey(x, :lp) for x in chains)
        @test mean(x[:s][1] for x in chains) ≈ 3 atol=0.1
        @test mean(x[:m][1] for x in chains) ≈ 0 atol=0.1
    end
end


text:
@testset "Overrides" begin
    g3 = SimpleWeightedGraph(PathGraph(5))
    g5 = SimpleWeightedDiGraph(4)

    for g in testgraphs(g3)
        @test @inferred(adjacency_matrix(g, Bool)) == adjacency_matrix(g, Bool; dir=:out)
        @test @inferred(adjacency_matrix(g))[3, 2] == 1
        @test adjacency_matrix(g)[2, 4] == 0
        @test adjacency_matrix(g; dir=:out) == adjacency_matrix(g; dir=:in)'
    end

    add_edge!(g5, 1, 2, 2); add_edge!(g5, 2, 3, 2); add_edge!(g5, 1, 3, 1); add_edge!(g5, 3, 4, 5)
    for g in testdigraphs(g5)
        @test @inferred(adjacency_matrix(g, Bool)) == adjacency_matrix(g, Bool; dir=:out)
        @test adjacency_matrix(g; dir=:out) == adjacency_matrix(g; dir=:in)'
        @test @inferred(pagerank(g))[3] ≈ 0.2266 atol=0.001
        @test length(@inferred(pagerank(g))) == nv(g)
        @test_throws ErrorException pagerank(g, 2)
        @test_throws ErrorException pagerank(g, 0.85, 2)
    end
end


text:
function BetaDistribution(arg0::jdouble, arg1::jdouble)
    return BetaDistribution((jdouble, jdouble), arg0, arg1)
end

function BetaDistribution(arg0::jdouble, arg1::jdouble, arg2::jdouble)
    return BetaDistribution((jdouble, jdouble, jdouble), arg0, arg1, arg2)
end

function cumulative_probability(obj::BetaDistribution, arg0::jdouble)
    return jcall(obj, "cumulativeProbability", jdouble, (jdouble,), arg0)
end

function density(obj::BetaDistribution, arg0::jdouble)
    return jcall(obj, "density", jdouble, (jdouble,), arg0)
end

function get_alpha(obj::BetaDistribution)
    return jcall(obj, "getAlpha", jdouble, ())
end

function get_beta(obj::BetaDistribution)
    return jcall(obj, "getBeta", jdouble, ())
end

function get_numerical_mean(obj::BetaDistribution)
    return jcall(obj, "getNumericalMean", jdouble, ())
end

function get_numerical_variance(obj::BetaDistribution)
    return jcall(obj, "getNumericalVariance", jdouble, ())
end

function get_support_lower_bound(obj::BetaDistribution)
    return jcall(obj, "getSupportLowerBound", jdouble, ())
end

function get_support_upper_bound(obj::BetaDistribution)
    return jcall(obj, "getSupportUpperBound", jdouble, ())
end

function is_support_connected(obj::BetaDistribution)
    return jcall(obj, "isSupportConnected", jboolean, ())
end

function log_density(obj::BetaDistribution, arg0::jdouble)
    return jcall(obj, "logDensity", jdouble, (jdouble,), arg0)
end


text:
using DFTK
using ForwardDiff
using Test
include("testcases.jl")

@testset "Force derivatives using finite differences" begin
    function compute_force(ε1, ε2)
        T = promote_type(typeof(ε1), typeof(ε2))
        pos = [[1.01, 1.02, 1.03] / 8, -ones(3) / 8 + ε1 * [1., 0, 0] + ε2 * [0, 1., 0]]
        # TODO symmetries = true gives issues for now ... debug after refactoring done.
        model = model_DFT(Matrix{T}(silicon.lattice), silicon.atoms, pos,
                          [:lda_x, :lda_c_pw]; symmetries=false)
        basis = PlaneWaveBasis(model; Ecut=5, kgrid=[2, 2, 2], kshift=[0, 0, 0])

        is_converged = DFTK.ScfConvergenceDensity(1e-10)
        scfres = self_consistent_field(basis; is_converged=is_converged)
        compute_forces_cart(scfres)[1]
    end

    F = compute_force(0.0, 0.0)
    derivative_ε1_fd = let ε1 = 1e-5
        (compute_force(ε1, 0.0) - F) / ε1
    end
    derivative_ε1 = ForwardDiff.derivative(ε1 -> compute_force(ε1, 0.0), 0.0)
    @test norm(derivative_ε1 - derivative_ε1_fd) < 1e-4

    derivative_ε2_fd = let ε2 = 1e-5
        (compute_force(0.0, ε2) - F) / ε2
    end
    derivative_ε2 = ForwardDiff.derivative(ε2 -> compute_force(0.0, ε2), 0.0)
    @test norm(derivative_ε2 - derivative_ε2_fd) < 1e-4

    @testset "Multiple partials" begin
        grad = ForwardDiff.gradient(v -> compute_force(v...)[1][1], [0.0, 0.0])
        @test abs(grad[1] - derivative_ε1[1][1]) < 1e-4
        @test abs(grad[2] - derivative_ε2[1][1]) < 1e-4

        # TODO
        # jac = ForwardDiff.jacobian(v -> compute_force(v...), [0.0, 0.0])
    end
end