-
Notifications
You must be signed in to change notification settings - Fork 87
/
instantiate.jl
126 lines (113 loc) · 4.61 KB
/
instantiate.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
"""
struct OptimizerWithAttributes
optimizer_constructor
params::Vector{Pair{AbstractOptimizerAttribute,<:Any}}
end
Object grouping an optimizer constructor and a list of optimizer attributes.
Instances are created with [`instantiate`](@ref).
"""
struct OptimizerWithAttributes
# Function that takes zero arguments and returns a new optimizer.
# The type of the function could be
# * `Function`: a function, or
# * `DataType`: a type, or
# * `UnionAll`: a type with missing parameters.
optimizer_constructor::Any
params::Vector{Pair{AbstractOptimizerAttribute,Any}}
end
_to_param(param::Pair{<:AbstractOptimizerAttribute}) = param
_to_param(param::Pair{String}) = RawParameter(param.first) => param.second
function _to_param(param::Pair)
return error("Expected an optimizer attribute or a string, got `$(param.first)` which is a `$(typeof(param.first))`.")
end
"""
OptimizerWithAttributes(optimizer_constructor, params::Pair...)
Create an [`OptimizerWithAttributes`](@ref) with the parameters `params`.
"""
function OptimizerWithAttributes(
optimizer_constructor,
args::Vararg{Pair,N},
) where {N}
if !applicable(optimizer_constructor)
error(_INSTANTIATE_NOT_CALLABLE_MESSAGE)
end
params =
Pair{AbstractOptimizerAttribute,Any}[_to_param(arg) for arg in args]
return OptimizerWithAttributes(optimizer_constructor, params)
end
const _INSTANTIATE_NOT_CALLABLE_MESSAGE =
"The provided `optimizer_constructor` is invalid. It must be callable with zero " *
"arguments. For example, \"Ipopt.Optimizer\" or " *
"\"() -> ECOS.Optimizer()\". It should not be an instantiated optimizer " *
"like \"Ipopt.Optimizer()\" or \"ECOS.Optimizer()\". " *
"(Note the difference in parentheses!)"
"""
_instantiate_and_check(optimizer_constructor)
Create an instance of optimizer by calling `optimizer_constructor`.
Then check that the type returned is an empty [`AbstractOptimizer`](@ref).
"""
function _instantiate_and_check(optimizer_constructor)
if !applicable(optimizer_constructor)
error(_INSTANTIATE_NOT_CALLABLE_MESSAGE)
end
optimizer = optimizer_constructor()
if !isa(optimizer, AbstractOptimizer)
error(
"The provided `optimizer_constructor` returned an object of type " *
"$(typeof(optimizer)). Expected a " *
"MathOptInterface.AbstractOptimizer.",
)
end
if !is_empty(optimizer)
error("The provided `optimizer_constructor` returned a non-empty optimizer.")
end
return optimizer
end
"""
_instantiate_and_check(optimizer_constructor::OptimizerWithAttributes)
Create an instance of optimizer represented by [`OptimizerWithAttributes`](@ref).
Then check that the type returned is an empty [`AbstractOptimizer`](@ref).
"""
function _instantiate_and_check(optimizer_constructor::OptimizerWithAttributes)
optimizer =
_instantiate_and_check(optimizer_constructor.optimizer_constructor)
for param in optimizer_constructor.params
set(optimizer, param.first, param.second)
end
return optimizer
end
"""
instantiate(optimizer_constructor,
with_bridge_type::Union{Nothing, Type}=nothing,
with_names::Bool=false)
Creates an instance of optimizer either by calling
`optimizer_constructor.optimizer_constructor()` and setting the parameters in
`optimizer_constructor.params` if `optimizer_constructor` is a
[`OptimizerWithAttributes`](@ref) or by calling `optimizer_constructor()`
if `optimizer_constructor` is callable.
If `with_bridge_type` is not `nothing`, it enables all the bridges defined in
the MathOptInterface.Bridges submodule with coefficient type
`with_bridge_type`.
If the optimizer created by `optimizer_constructor` does not support loading the
problem incrementally or does not support names and `with_names` is `true` (see
[`Utilities.supports_default_copy_to`](@ref)) then a
[`Utilities.CachingOptimizer`](@ref) is added to store a cache of the bridged
model.
Hence set `with_names` to `true` if names might be set.
"""
function instantiate(
optimizer_constructor;
with_bridge_type::Union{Nothing,Type} = nothing,
with_names::Bool = false,
)
optimizer = _instantiate_and_check(optimizer_constructor)
if with_bridge_type === nothing
return optimizer
end
if !Utilities.supports_default_copy_to(optimizer, with_names)
universal_fallback =
Utilities.UniversalFallback(Utilities.Model{with_bridge_type}())
optimizer = Utilities.CachingOptimizer(universal_fallback, optimizer)
end
return Bridges.full_bridge_optimizer(optimizer, with_bridge_type)
end