diff --git a/docs/src/guide/derivative.md b/docs/src/guide/derivative.md index ada20e37..6397f4ce 100644 --- a/docs/src/guide/derivative.md +++ b/docs/src/guide/derivative.md @@ -1,6 +1,6 @@ ```@meta DocTestFilters = [r"≥|>=", r" == | = ", r" ∈ | in ", r" for all | ∀ ", r"d|∂", - r"integral|∫", r".*scalar_parameters.jl:785"] + r"integral|∫", r".*scalar_parameters.jl:813"] ``` # [Derivative Operators](@id deriv_docs) @@ -503,7 +503,7 @@ julia> derivative_constraints(d1) julia> add_supports(t, 0.2) ┌ Warning: Support/method changes will invalidate existing derivative evaluation constraints that have been added to the InfiniteModel. Thus, these are being deleted. -└ @ InfiniteOpt ~/work/infiniteopt/InfiniteOpt.jl/src/scalar_parameters.jl:785 +└ @ InfiniteOpt ~/work/infiniteopt/InfiniteOpt.jl/src/scalar_parameters.jl:813 julia> has_derivative_constraints(d1) false diff --git a/src/array_parameters.jl b/src/array_parameters.jl index 76949282..0637a5c9 100644 --- a/src/array_parameters.jl +++ b/src/array_parameters.jl @@ -156,23 +156,46 @@ end ## Process the supports format via dispatch # Vector{<:Real} -function _process_supports( +function _process_array_supports( _error::Function, supps::Vector{<:Real}, domain, sig_digits ) + supps = round.(supps, sigdigits = sig_digits) if !supports_in_domain(reshape(supps, length(supps), 1), domain) _error("Support violates the infinite domain.") end - supps = round.(supps, sigdigits = sig_digits) return DataStructures.OrderedDict{Vector{Float64}, Set{DataType}}( supps => Set([UserDefined]) ) end +# Vector{Matrix{<:Real}} +function _process_array_supports( + _error::Function, + vect_supps::Vector{<:Matrix{<:Real}}, + domain, + sig_digits + ) + supps = first(vect_supps) + if any(arr != supps for arr in vect_supps) + _error("Cannot specify a matrix of supports for individual infinite parameters.") + elseif size(supps, 1) != length(vect_supps) + _error("Matrix of supports does not match the dimension of infinite parameters. " * + "Ensure the number of rows is equal to the number of parameters.") + end + rounded_supps = round.(supps, sigdigits = sig_digits) + if !supports_in_domain(rounded_supps, domain) + _error("Supports violate the infinite domain.") + end + return DataStructures.OrderedDict{Vector{Float64}, Set{DataType}}( + s => Set([UserDefined]) for s in eachcol(rounded_supps) + ) +end + # Vector{Vector{<:Real}} -function _process_supports( +function _process_array_supports( _error::Function, vect_supps::Vector{<:Vector{<:Real}}, domain, @@ -183,15 +206,35 @@ function _process_supports( _error("Inconsistent support dimensions.") end supps = permutedims(reduce(hcat, vect_supps)) + supps = round.(supps, sigdigits = sig_digits) if !supports_in_domain(supps, domain) _error("Supports violate the infinite domain.") end - supps = round.(supps, sigdigits = sig_digits) return DataStructures.OrderedDict{Vector{Float64}, Set{DataType}}( s => Set([UserDefined]) for s in eachcol(supps) ) end +# Vector of other collections +function _process_array_supports( + _error::Function, + vect_supps::Vector{<:Union{UnitRange{T}, StepRange{T}, StepRangeLen{T}, NTuple{N, T}, Base.Generator}}, + domain, + sig_digits + ) where {N, T <: Real} + return _process_array_supports(_error, collect.(vect_supps), domain, sig_digits) +end + +# Fallback +function _process_array_supports( + _error::Function, + vect_supps, + domain, + sig_digits + ) + error("Unrecognized support input. Please consult the docs.") +end + ## Use dispatch to make the formatting of the derivative method vector # Valid vector function _process_derivative_methods( @@ -222,7 +265,7 @@ function _build_parameters( orig_inds::Collections.ContainerIndices; num_supports::Int = 0, sig_digits::Int = DefaultSigDigits, - supports::Union{Vector{<:Real}, Vector{<:Vector{<:Real}}} = Float64[], + supports = Float64[], derivative_method::Vector = [], extra_kwargs... ) @@ -235,7 +278,7 @@ function _build_parameters( domain = round_domain(domain, sig_digits) # we have supports if !isempty(supports) - supp_dict = _process_supports(_error, supports, domain, sig_digits) + supp_dict = _process_array_supports(_error, supports, domain, sig_digits) # we want to generate supports elseif !iszero(num_supports) supps, label = generate_support_values( @@ -257,10 +300,11 @@ function _build_parameters( end """ - add_parameters(model::InfiniteModel, - params::DependentParameters, - names::Vector{String} - )::Vector{GeneralVariableRef} + add_parameters( + model::InfiniteModel, + params::DependentParameters, + names::Vector{String} + )::Vector{GeneralVariableRef} Add `params` to `model` and return an appropriate container of the dependent infinite parameter references. This is intended as an internal method for use @@ -988,8 +1032,10 @@ function significant_digits(pref::DependentParameterRef) end """ - num_supports(pref::DependentParameterRef; - [label::Type{<:AbstractSupportLabel} = PublicLabel])::Int + num_supports( + pref::DependentParameterRef; + [label::Type{<:AbstractSupportLabel} = PublicLabel] + )::Int Return the number of support points associated with a single dependent infinite parameter `pref`. Specify a subset of supports via `label` to only count the @@ -1018,8 +1064,10 @@ function num_supports( end """ - num_supports(prefs::AbstractArray{<:DependentParameterRef}; - [label::Type{<:AbstractSupportLabel} = PublicLabel])::Int + num_supports( + prefs::AbstractArray{<:DependentParameterRef}; + [label::Type{<:AbstractSupportLabel} = PublicLabel] + )::Int Return the number of support points associated with dependent infinite parameters `prefs`. Errors if not all from the same underlying object. @@ -1072,8 +1120,10 @@ function has_supports(prefs::AbstractArray{<:DependentParameterRef}) end """ - supports(pref::DependentParameterRef; - [label::Type{<:AbstractSupportLabel} = PublicLabel])::Vector{Float64} + supports( + pref::DependentParameterRef; + [label::Type{<:AbstractSupportLabel} = PublicLabel] + )::Vector{Float64} Return the support points associated with `pref`. A subset of supports can be returned via `label` to return just the supports associated with `label`. By @@ -1103,9 +1153,10 @@ function supports( end """ - supports(prefs::AbstractArray{<:DependentParameterRef}; - [label::Type{<:AbstractSupportLabel} = PublicLabel] - )::Union{Vector{<:AbstractArray{<:Real}}, Array{Float64, 2}} + supports( + prefs::AbstractArray{<:DependentParameterRef}; + [label::Type{<:AbstractSupportLabel} = PublicLabel] + )::Union{Vector{<:AbstractArray{<:Real}}, Array{Float64, 2}} Return the support points associated with `prefs`. Errors if not all of the infinite dependent parameters are from the same object. This will return a @@ -1204,10 +1255,12 @@ function _make_support_matrix( end """ - set_supports(prefs::AbstractArray{<:DependentParameterRef}, - supports::Vector{<:AbstractArray{<:Real}}; - [force::Bool = false, - label::Type{<:AbstractSupportLabel} = UserDefined])::Nothing + set_supports( + prefs::AbstractArray{<:DependentParameterRef}, + supports::Vector{<:AbstractArray{<:Real}}; + [force::Bool = false, + label::Type{<:AbstractSupportLabel} = UserDefined] + )::Nothing Specify the support points for `prefs`. Errors if the supports violate the domain of the infinite domain, if the dimensions don't match up properly, @@ -1217,10 +1270,12 @@ supports and `force = false`. Note that it is strongly preferred to use `add_supports` if possible to avoid destroying measure dependencies. ```julia - set_supports(prefs::Vector{DependentParameterRef}, - supports::Array{<:Real, 2}; - [force::Bool = false, - label::Type{<:AbstractSupportLabel} = UserDefined])::Nothing + set_supports( + prefs::Vector{DependentParameterRef}, + supports::Array{<:Real, 2}; + [force::Bool = false, + label::Type{<:AbstractSupportLabel} = UserDefined] + )::Nothing ``` Specify the supports for a vector `prefs` of dependent infinite parameters. Here rows of `supports` correspond to `prefs` and the columns correspond to the @@ -1260,6 +1315,7 @@ function set_supports( label::Type{<:AbstractSupportLabel} = UserDefined ) domain = infinite_domain(prefs) # this does a check on prefs + supports = round.(supports, sigdigits = significant_digits(first(prefs))) if has_supports(prefs) && !force error("Unable set supports for $prefs since they already have supports." * " Consider using `add_supports` or use `force = true` to " * @@ -1267,7 +1323,6 @@ function set_supports( elseif !supports_in_domain(supports, domain) error("Supports violate the domain of the infinite domain.") end - supports = round.(supports, sigdigits = significant_digits(first(prefs))) _update_parameter_supports(prefs, supports, label) return end @@ -1278,9 +1333,11 @@ function set_supports(pref::DependentParameterRef, supports; kwargs...) end """ - add_supports(prefs::AbstractArray{<:DependentParameterRef}, - supports::Vector{<:AbstractArray{<:Real}}; - [label::Type{<:AbstractSupportLabel} = UserDefined])::Nothing + add_supports( + prefs::AbstractArray{<:DependentParameterRef}, + supports::Vector{<:AbstractArray{<:Real}}; + [label::Type{<:AbstractSupportLabel} = UserDefined] + )::Nothing Add additional support points for `prefs`. Errors if the supports violate the domain of the infinite domain, if the dimensions don't match up properly, @@ -1288,9 +1345,11 @@ if `prefs` and `supports` have different indices, or not all of the `prefs` are from the same dependent infinite parameter container. ```julia - add_supports(prefs::Vector{DependentParameterRef}, - supports::Array{<:Real, 2}; - [label::Type{<:AbstractSupportLabel} = UserDefined])::Nothing + add_supports( + prefs::Vector{DependentParameterRef}, + supports::Array{<:Real, 2}; + [label::Type{<:AbstractSupportLabel} = UserDefined] + )::Nothing ``` Specify the supports for a vector `prefs` of dependent infinite parameters. Here rows of `supports` correspond to `prefs` and the columns correspond to the @@ -1335,10 +1394,10 @@ function add_supports( check::Bool = true ) domain = infinite_domain(prefs) # this does a check on prefs + supports = round.(supports, sigdigits = significant_digits(first(prefs))) if check && !supports_in_domain(supports, domain) error("Supports violate the domain of the infinite domain.") end - supports = round.(supports, sigdigits = significant_digits(first(prefs))) current_supports = _parameter_supports(first(prefs)) added_new_support = false for i in 1:size(supports, 2) @@ -1370,8 +1429,10 @@ function add_supports(pref::DependentParameterRef, supports; kwargs...) end """ - delete_supports(prefs::AbstractArray{<:DependentParameterRef}; - [label::Type{<:AbstractSupportLabel} = All])::Nothing + delete_supports( + prefs::AbstractArray{<:DependentParameterRef}; + [label::Type{<:AbstractSupportLabel} = All] + )::Nothing Delete the support points for `prefs`. Errors if any of the parameters are used by a measure or if not all belong to the same set of dependent parameters. diff --git a/src/general_variables.jl b/src/general_variables.jl index 66f92df9..8076c477 100644 --- a/src/general_variables.jl +++ b/src/general_variables.jl @@ -190,7 +190,7 @@ end Delete the concrete `AbstractDataObject` associated with `vref`. """ -function _delete_data_object(vref::DispatchVariableRef)::Nothing +function _delete_data_object(vref::DispatchVariableRef) delete!(_data_dictionary(vref), JuMP.index(vref)) return end @@ -228,7 +228,7 @@ Extend `JuMP.set_name` to set the name of `vref`. It relies on `JuMP.set_name` being defined for the underlying `DispatchVariableRef`, otherwise an `ArgumentError` is thrown. """ -function JuMP.set_name(vref::GeneralVariableRef, name::String)::Nothing +function JuMP.set_name(vref::GeneralVariableRef, name::String) return JuMP.set_name(dispatch_variable_ref(vref), name) end @@ -378,7 +378,7 @@ Extend `JuMP.delete` to delete `vref` and its dependencies. It relies on `JuMP.delete` being defined for the underlying `DispatchVariableRef`, otherwise an `ArgumentError` is thrown. """ -function JuMP.delete(model::InfiniteModel, vref::GeneralVariableRef)::Nothing +function JuMP.delete(model::InfiniteModel, vref::GeneralVariableRef) return JuMP.delete(model, dispatch_variable_ref(vref)) end @@ -391,7 +391,7 @@ their dependencies. An `ArgumentError` is thrown if `prefs` are not dependent infinite parameters. """ function JuMP.delete(model::InfiniteModel, - prefs::AbstractArray{<:GeneralVariableRef})::Nothing + prefs::AbstractArray{<:GeneralVariableRef}) return JuMP.delete(model, dispatch_variable_ref.(prefs)) end @@ -503,7 +503,7 @@ by a measure. An `ArgumentError` is thrown if `pref` is not an infinite paramete function set_infinite_domain( pref::GeneralVariableRef, domain::InfiniteScalarDomain - )::Nothing + ) return set_infinite_domain(dispatch_variable_ref(pref), domain) end @@ -521,7 +521,7 @@ parameters. function set_infinite_domain( prefs::AbstractArray{<:GeneralVariableRef}, domain::InfiniteArrayDomain - )::Nothing + ) return set_infinite_domain(dispatch_variable_ref.(prefs), domain) end @@ -542,8 +542,11 @@ function set_supports(pref, supports; kwargs...) end """ - set_supports(pref::GeneralVariableRef, supports::Union{Real, Vector{<:Real}}; - [force::Bool = false])::Nothing + set_supports( + pref::GeneralVariableRef, + supports::Union{Real, Vector{<:Real}, UnitRange{<:Real}, StepRange{<:Real}, NTuple, Base.Generator}; + [force::Bool = false] + )::Nothing Set the support points associated with a single infinite parameter `pref`. An `ArgumentError` is thrown if `pref` is not an independent @@ -551,10 +554,10 @@ infinite parameter. """ function set_supports( pref::GeneralVariableRef, - supports::Union{Real, Vector{<:Real}}; + supports; force::Bool = false, label::Type{<:AbstractSupportLabel} = UserDefined - )::Nothing + ) return set_supports(dispatch_variable_ref(pref), supports, force = force, label = label) end @@ -575,7 +578,7 @@ function set_supports( supports::Union{Array{<:Real, 2}, Vector{<:AbstractArray{<:Real}}}; label::Type{<:AbstractSupportLabel} = UserDefined, force::Bool = false - )::Nothing + ) return set_supports(dispatch_variable_ref.(prefs), supports, label = label, force = force) end @@ -587,8 +590,10 @@ function add_supports(pref, supports; kwargs...) end """ - add_supports(pref::GeneralVariableRef, - supports::Union{Real, Vector{<:Real}})::Nothing + add_supports( + pref::GeneralVariableRef, + supports::Union{Real, Vector{<:Real}, UnitRange{<:Real}, StepRange{<:Real}, NTuple, Base.Generator} + )::Nothing Add the support points `supports` to a single infinite parameter `pref`. An `ArgumentError` is thrown if `pref` is not an independent @@ -596,10 +601,10 @@ infinite parameter. """ function add_supports( pref::GeneralVariableRef, - supports::Union{Real, Vector{<:Real}}; + supports; check::Bool = true, label::Type{<:AbstractSupportLabel} = UserDefined - )::Nothing + ) return add_supports(dispatch_variable_ref(pref), supports, check = check, label = label) end @@ -619,7 +624,7 @@ function add_supports( supports::Union{Array{<:Real, 2}, Vector{<:AbstractArray{<:Real}}}; label::Type{<:AbstractSupportLabel} = UserDefined, check::Bool = true - )::Nothing + ) return add_supports(dispatch_variable_ref.(prefs), supports, label = label, check = check) end @@ -638,7 +643,7 @@ set the value of `vref`. It relies on `JuMP.set_value` being defined for the underlying `DispatchVariableRef`, otherwise an `ArgumentError` is thrown. """ -function JuMP.set_value(vref::GeneralVariableRef, value::Real)::Nothing +function JuMP.set_value(vref::GeneralVariableRef, value::Real) return JuMP.set_value(dispatch_variable_ref(vref), value) end @@ -659,7 +664,7 @@ An `ArgumentError` is thrown if `pref` is not an infinite parameter. function set_derivative_method( pref::GeneralVariableRef, method::AbstractDerivativeMethod - )::Nothing + ) return set_derivative_method(dispatch_variable_ref(pref), method) end @@ -674,7 +679,7 @@ for op = (:_set_has_generative_supports, :_set_has_internal_supports, throw(ArgumentError(str)) end # define the dispatch version - function $op(vref::GeneralVariableRef, status::Bool)::Nothing + function $op(vref::GeneralVariableRef, status::Bool) return $op(dispatch_variable_ref(vref), status) end end @@ -740,7 +745,7 @@ Set the start value function of `vref`. It relies on `set_start_value_function` being defined for the underlying `DispatchVariableRef`, otherwise an `ArgumentError` is thrown. """ -function set_start_value_function(vref::GeneralVariableRef, start)::Nothing +function set_start_value_function(vref::GeneralVariableRef, start) return set_start_value_function(dispatch_variable_ref(vref), start) end @@ -852,7 +857,7 @@ for op = (:set_lower_bound, :set_upper_bound, :set_start_value) `ArgumentError` is thrown. See the underlying docstrings for more information. """ - function JuMP.$op(vref::GeneralVariableRef, value::Real)::Nothing + function JuMP.$op(vref::GeneralVariableRef, value::Real) return JuMP.$op(dispatch_variable_ref(vref), value) end end diff --git a/src/scalar_parameters.jl b/src/scalar_parameters.jl index 57617a07..fa06fe70 100644 --- a/src/scalar_parameters.jl +++ b/src/scalar_parameters.jl @@ -154,23 +154,46 @@ end # Define the default derivative evaluation method const DefaultDerivativeMethod = FiniteDifference() -# Check that supports don't violate the domain bounds -function _check_supports_in_bounds( +# Check supports and format them +function _process_scalar_supports( _error::Function, - supports::Union{<:Real, Vector{<:Real}}, - domain::AbstractInfiniteDomain - ) - if !supports_in_domain(supports, domain) + supports::Union{T, Vector{T}, UnitRange{T}, StepRange{T}, StepRangeLen{T}}, + domain::InfiniteScalarDomain, + sig_digits::Int, + check::Bool = true + ) where {T <: Real} + supps = round.(supports, sigdigits = sig_digits) + if check && !supports_in_domain(supps, domain) _error("Supports violate the domain bounds.") end - return + return supps +end +function _process_scalar_supports( + _error::Function, + supports::Union{Base.Generator, Tuple}, + domain::InfiniteScalarDomain, + sig_digits::Int, + check::Bool = true + ) + supps = collect(supports) + return _process_scalar_supports(_error, supps, domain, sig_digits, check) +end +function _process_scalar_supports( + _error::Function, + supports, + domain::InfiniteScalarDomain, + sig_digits::Int, + check::Bool = true + ) + _error("Unsupported format `$(typeof(supports))` for `supports`. Please " * + "provide a vector, range, tuple, or generator of real numbers.") end """ build_parameter( _error::Function, domain::InfiniteScalarDomain; [num_supports::Int = 0, - supports::Union{Real, Vector{<:Real}} = Float64[], + supports::Union{Vector{<:Real}, UnitRange{<:Real}, StepRange{<:Real}} = Float64[], sig_digits::Int = DefaultSigDigits, derivative_method::AbstractDerivativeMethod = DefaultDerivativeMethod] )::IndependentParameter @@ -191,7 +214,7 @@ function build_parameter( _error::Function, domain::InfiniteScalarDomain; num_supports::Int = 0, - supports::Union{Real, Vector{<:Real}} = Float64[], + supports = Float64[], sig_digits::Int = DefaultSigDigits, derivative_method::AbstractDerivativeMethod = DefaultDerivativeMethod, extra_kwargs... @@ -201,17 +224,22 @@ function build_parameter( end domain = round_domain(domain, sig_digits) label = UserDefined - length_supports = length(supports) if !isempty(supports) - supports = round.(supports, sigdigits = sig_digits) - _check_supports_in_bounds(_error, supports, domain) - num_supports == 0 || @warn("Ignoring num_supports since supports is not empty.") + supps = _process_scalar_supports(_error, supports, domain, sig_digits) + num_supports == 0 || @warn("Ignoring `num_supports` since `supports` is not empty.") elseif num_supports != 0 - supports, label = generate_support_values(domain, num_supports = num_supports, - sig_digits = sig_digits) + supps, label = generate_support_values( + domain, + num_supports = num_supports, + sig_digits = sig_digits + ) + else + supps = supports end + length_supports = length(supps) supports_dict = DataStructures.SortedDict{Float64, Set{DataType}}( - i => Set([label]) for i in supports) + i => Set([label]) for i in supps + ) if length_supports != 0 && (length(supports_dict) != length_supports) @warn("Support points are not unique, eliminating redundant points.") end @@ -1124,8 +1152,10 @@ function significant_digits(pref::IndependentParameterRef) end """ - num_supports(pref::IndependentParameterRef; - [label::Type{<:AbstractSupportLabel} = PublicLabel])::Int + num_supports( + pref::IndependentParameterRef; + [label::Type{<:AbstractSupportLabel} = PublicLabel] + )::Int Return the number of support points associated with `pref`. By default, only the number of public supports are counted. The full amount can be determined by setting @@ -1164,8 +1194,10 @@ true has_supports(pref::IndependentParameterRef) = !isempty(_parameter_supports(pref)) """ - supports(pref::IndependentParameterRef; - [label::Type{<:AbstractSupportLabel} = PublicLabel])::Vector{Float64} + supports( + pref::IndependentParameterRef; + [label::Type{<:AbstractSupportLabel} = PublicLabel] + )::Vector{Float64} Return the support points associated with `pref`. Errors if there are no supports. Users can query just support points generated by a certain method @@ -1227,10 +1259,12 @@ function supports( end """ - set_supports(pref::IndependentParameterRef, supports::Vector{<:Real}; - [force::Bool = false, - label::Type{<:AbstractSupportLabel} = UserDefined] - )::Nothing + set_supports( + pref::IndependentParameterRef, + supports::Union{Vector{<:Real}, UnitRange{<:Real}, StepRange{<:Real}, NTuple, Base.Generator}; + [force::Bool = false, + label::Type{<:AbstractSupportLabel} = UserDefined] + )::Nothing Specify the support points for `pref`. Errors if the supports violate the bounds associated with the infinite domain. Warns if the points are not unique. If `force` @@ -1249,7 +1283,7 @@ julia> supports(t) """ function set_supports( pref::IndependentParameterRef, - supports::Vector{<:Real}; + supports; force::Bool = false, label::Type{<:AbstractSupportLabel} = UserDefined ) @@ -1259,10 +1293,11 @@ function set_supports( "overwrite the existing supports.") end domain = _parameter_domain(pref) - supports = round.(supports, sigdigits = significant_digits(pref)) - _check_supports_in_bounds(error, supports, domain) + sig_digits = significant_digits(pref) + supps = _process_scalar_supports(error, supports, domain, sig_digits) supports_dict = DataStructures.SortedDict{Float64, Set{DataType}}( - i => Set([label]) for i in supports) + i => Set([label]) for i in supps + ) if length(supports_dict) != length(supports) @warn("Support points are not unique, eliminating redundant points.") end @@ -1272,9 +1307,11 @@ function set_supports( end """ - add_supports(pref::IndependentParameterRef, - supports::Union{Real, Vector{<:Real}}; - [label::Type{<:AbstractSupportLabel} = UserDefined])::Nothing + add_supports( + pref::IndependentParameterRef, + supports::Union{Real, Vector{<:Real}, UnitRange{<:Real}, StepRange{<:Real}, NTuple, Base.Generator}; + [label::Type{<:AbstractSupportLabel} = UserDefined] + )::Nothing Add additional support points for `pref` with identifying label `label`. @@ -1300,15 +1337,16 @@ julia> supports(t) """ function add_supports( pref::IndependentParameterRef, - supports::Union{Real, Vector{<:Real}}; + supports; label::Type{<:AbstractSupportLabel} = UserDefined, - check::Bool = true) + check::Bool = true + ) domain = infinite_domain(pref) - supports = round.(supports, sigdigits = significant_digits(pref)) - check && _check_supports_in_bounds(error, supports, domain) + sig_digits = significant_digits(pref) + supps = _process_scalar_supports(error, supports, domain, sig_digits, check) supports_dict = _parameter_supports(pref) added_new_support = false - for s in supports + for s in supps if haskey(supports_dict, s) push!(supports_dict[s], label) else @@ -1330,8 +1368,10 @@ function add_supports( end """ - delete_supports(pref::IndependentParameterRef; - [label::Type{<:AbstractSupportLabel} = All])::Nothing + delete_supports( + pref::IndependentParameterRef; + [label::Type{<:AbstractSupportLabel} = All] + )::Nothing Delete the support points for `pref`. If `label != All` then delete `label` and any supports that solely depend on it. @@ -1432,8 +1472,10 @@ function JuMP.set_value(pref::FiniteParameterRef, value::Real) end """ - fill_in_supports!(pref::IndependentParameterRef; - [num_supports::Int = DefaultNumSupports])::Nothing + fill_in_supports!( + pref::IndependentParameterRef; + [num_supports::Int = DefaultNumSupports] + )::Nothing Automatically generate support points for a particular independent parameter `pref`. Generating `num_supports` for the parameter. The supports are generated uniformly @@ -1473,10 +1515,12 @@ function fill_in_supports!( end """ - generate_and_add_supports!(pref::IndependentParameterRef, - domain::AbstractInfiniteDomain, - [method::Type{<:AbstractSupportLabel}]; - [num_supports::Int = DefaultNumSupports])::Nothing + generate_and_add_supports!( + pref::IndependentParameterRef, + domain::AbstractInfiniteDomain, + [method::Type{<:AbstractSupportLabel}]; + [num_supports::Int = DefaultNumSupports] + )::Nothing Generate supports for independent parameter `pref` via [`generate_support_values`](@ref) and add them to `pref`. This is intended as an extendable internal method for diff --git a/test/array_parameters.jl b/test/array_parameters.jl index a08e30b7..a2ff50ca 100644 --- a/test/array_parameters.jl +++ b/test/array_parameters.jl @@ -87,17 +87,32 @@ end # fallback @test_throws ErrorException InfiniteOpt._make_array_domain(error, domain2, inds1) end - # test _process_supports - @testset "_process_supports" begin + # test _process_array_supports + @testset "_process_array_supports" begin # single support supps = OrderedDict([0., 0.] => Set([UserDefined])) - @test InfiniteOpt._process_supports(error, [0, 0], domain1, 2) == supps - @test_throws ErrorException InfiniteOpt._process_supports(error, [2, 2], domain1, 2) + @test InfiniteOpt._process_array_supports(error, [0, 0], domain1, 2) == supps + @test_throws ErrorException InfiniteOpt._process_array_supports(error, [2, 2], domain1, 2) # multiple supports supps = OrderedDict([0., 0.] => Set([UserDefined]), [1., 1.] => Set([UserDefined])) - @test InfiniteOpt._process_supports(error, [[0, 1], [0, 1]], domain1, 2) == supps - @test_throws ErrorException InfiniteOpt._process_supports(error, [[0, 0], [1]], domain1, 2) - @test_throws ErrorException InfiniteOpt._process_supports(error, [[0, 2], [0, 2]], domain1, 2) + @test InfiniteOpt._process_array_supports(error, [[0, 1], [0, 1]], domain1, 2) == supps + @test_throws ErrorException InfiniteOpt._process_array_supports(error, [[0, 0], [1]], domain1, 2) + @test_throws ErrorException InfiniteOpt._process_array_supports(error, [[0, 2], [0, 2]], domain1, 2) + # non-vector supports + @test InfiniteOpt._process_array_supports(error, [(0, 1), (0, 1)], domain1, 2) == supps + @test InfiniteOpt._process_array_supports(error, [0:1, 0:1], domain1, 2) == supps + @test InfiniteOpt._process_array_supports(error, [0:1:1, 0:1:1], domain1, 2) == supps + @test InfiniteOpt._process_array_supports(error, [(i for i in 0:1), (i for i in 0:1)], domain1, 2) == supps + # single matrix input + mat = [0 1; 0 1] + @test InfiniteOpt._process_array_supports(error, [mat, mat], domain1, 2) == supps + @test_throws ErrorException InfiniteOpt._process_array_supports(error, [mat, zeros(2, 2)], domain1, 2) + mat = [0 1; 0 1; 0 1] + @test_throws ErrorException InfiniteOpt._process_array_supports(error, [mat, mat], domain1, 2) + mat = ones(2, 1) * 4 + @test_throws ErrorException InfiniteOpt._process_array_supports(error, [mat, mat], domain1, 2) + # fallback + @test_throws ErrorException InfiniteOpt._process_array_supports(error, ["a", "b"], domain1, 2) end # test _process_derivative_methods @testset "_process_derivative_methods" begin @@ -212,7 +227,7 @@ end # test explicit build with some args prefs = [GeneralVariableRef(m, 3, DependentParameterIndex, i) for i in 1:2] expected = convert(JuMPC.SparseAxisArray, prefs) - @test all(isequal.(@infinite_parameter(m, c[1:2] in sdomain1, supports = 0, + @test all(isequal.(@infinite_parameter(m, c[1:2] in sdomain1, supports = 0:1, base_name = "z", container = SparseAxisArray), expected)) @test name.(prefs) == ["z[1]", "z[2]"] @@ -232,7 +247,8 @@ end # test anonymous with domain keyword prefs = [GeneralVariableRef(m, 6, DependentParameterIndex, i) for i in 1:2] @test isequal(@infinite_parameter(m, [1:2], domain = sdomain2, - derivative_method = TestMethod()), prefs) + derivative_method = TestMethod(), supports = ones(2, 1)), prefs) + @test supports(prefs) == ones(2, 1) # test anonymous with dist keyword and base_name prefs = [GeneralVariableRef(m, 7, DependentParameterIndex, i) for i in 1:2] @test isequal(@infinite_parameter(m, [1:2], diff --git a/test/scalar_parameters.jl b/test/scalar_parameters.jl index 8396be0c..f228b1ad 100644 --- a/test/scalar_parameters.jl +++ b/test/scalar_parameters.jl @@ -158,19 +158,22 @@ end # Test parameter definition methods @testset "Definition" begin # _check_supports_in_bounds - @testset "_check_supports_in_bounds" begin + @testset "_process_scalar_supports" begin domain = IntervalDomain(0, 1) - @test isa(InfiniteOpt._check_supports_in_bounds(error, 0, domain), Nothing) - @test_throws ErrorException InfiniteOpt._check_supports_in_bounds(error, - -1, domain) - @test_throws ErrorException InfiniteOpt._check_supports_in_bounds(error, - 2, domain) + @test InfiniteOpt._process_scalar_supports(error, 0, domain, 8) == 0 + @test_throws ErrorException InfiniteOpt._process_scalar_supports(error, -1, domain, 8) + @test_throws ErrorException InfiniteOpt._process_scalar_supports(error, 2, domain, 8) + @test_throws ErrorException InfiniteOpt._process_scalar_supports(error, "2", domain, 8) + @test InfiniteOpt._process_scalar_supports(error, [0.5, 1], domain, 8) == [0.5, 1] + @test InfiniteOpt._process_scalar_supports(error, 0:1, domain, 8) == [0, 1] + @test InfiniteOpt._process_scalar_supports(error, 0:0.5:1, domain, 8) == [0, 0.5, 1] + @test InfiniteOpt._process_scalar_supports(error, (0, 0.5), domain, 8) == [0.0, 0.5] + @test InfiniteOpt._process_scalar_supports(error, (i for i in (0, 1)), domain, 8) == [0, 1] + @test_throws ErrorException InfiniteOpt._process_scalar_supports(error, (0, 2), domain, 8) domain = UniDistributionDomain(Uniform()) - @test isa(InfiniteOpt._check_supports_in_bounds(error, 0, domain), Nothing) - @test_throws ErrorException InfiniteOpt._check_supports_in_bounds(error, - -1, domain) - @test_throws ErrorException InfiniteOpt._check_supports_in_bounds(error, - 2, domain) + @test InfiniteOpt._process_scalar_supports(error, 0, domain, 8) == 0 + @test_throws ErrorException InfiniteOpt._process_scalar_supports(error, -1, domain, 8) + @test_throws ErrorException InfiniteOpt._process_scalar_supports(error, 2, domain, 8) end # build_independent_parameter @testset "build_parameter (IndependentParameter)" begin @@ -182,7 +185,7 @@ end @test build_parameter(error, domain, supports = supps).domain == domain @test build_parameter(error, domain, supports = supps).supports == supps_dict @test_throws ErrorException build_parameter(error, domain, bob = 42) - warn = "Ignoring num_supports since supports is not empty." + warn = "Ignoring `num_supports` since `supports` is not empty." @test_logs (:warn, warn) build_parameter(error, domain, supports = [0, 1], num_supports = 2) repeated_supps = [1, 1] @@ -193,6 +196,7 @@ end domain = UniDistributionDomain(Normal()) @test length(build_parameter(error, domain, num_supports = 5).supports) == 5 @test build_parameter(error, domain, derivative_method = method).derivative_method == method + @test collect(keys(build_parameter(error, domain, supports = -1:0.5:1).supports)) == [-1, -0.5, 0, 0.5, 1] end # build_finite_parameter @testset "build_parameter (FiniteParameter)" begin @@ -847,7 +851,7 @@ end @testset "set_supports" begin @test_throws ArgumentError set_supports(bad, [0, 1]) @test isa(set_supports(pref_disp, [0, 1], force = true), Nothing) - @test isa(set_supports(pref, [0, 1], force = true), Nothing) + @test isa(set_supports(pref, (0, 1), force = true), Nothing) @test supports(pref) == [0., 1.] @test_throws ErrorException set_supports(pref, [2, 3]) warn = "Support points are not unique, eliminating redundant points." @@ -859,7 +863,7 @@ end @testset "add_supports" begin @test_throws ArgumentError add_supports(bad, 0.5) @test isa(add_supports(pref_disp, 0.25), Nothing) - @test isa(add_supports(pref, 0.5), Nothing) + @test isa(add_supports(pref, (i for i in [0.5])), Nothing) @test supports(pref) == [0.25, 0.5, 1.] @test isa(add_supports(pref, [0, 0.25, 1], check = false), Nothing) @test supports(pref) == [0, 0.25, 0.5, 1.]