Skip to content

Commit 95aab34

Browse files
authored
Add VectorNonlinearOracle set (#2860)
1 parent d04de18 commit 95aab34

File tree

7 files changed

+422
-0
lines changed

7 files changed

+422
-0
lines changed

docs/src/manual/standard_form.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ The vector-valued set types implemented in MathOptInterface.jl are:
8282
| [`RelativeEntropyCone(d)`](@ref MathOptInterface.RelativeEntropyCone) | ``\{ (u, v, w) \in \mathbb{R}^{d} : u \ge \sum_i w_i \log (\frac{w_i}{v_i}), v_i \ge 0, w_i \ge 0 \}`` |
8383
| [`HyperRectangle(l, u)`](@ref MathOptInterface.HyperRectangle) | ``\{x \in \bar{\mathbb{R}}^d: x_i \in [l_i, u_i] \forall i=1,\ldots,d\}`` |
8484
| [`NormCone(p, d)`](@ref MathOptInterface.NormCone) | ``\{ (t,x) \in \mathbb{R}^{d} : t \ge \left(\sum\limits_i \lvert x_i \rvert^p\right)^{\frac{1}{p}} \}`` |
85+
| [`VectorNonlinearOracle`](@ref MathOptInterface.VectorNonlinearOracle)| ``\{x \in \mathbb{R}^{dimension}: l \le f(x) \le u \}`` |
8586

8687
## Matrix cones
8788

docs/src/reference/standard_form.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ ACTIVATE_ON_ONE
104104
Complements
105105
HyperRectangle
106106
Scaled
107+
VectorNonlinearOracle
107108
```
108109

109110
## Constraint programming sets

src/Test/test_basic_constraint.jl

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,31 @@ function _set(::Type{T}, ::Type{MOI.HyperRectangle}) where {T}
175175
return MOI.HyperRectangle(zeros(T, 3), ones(T, 3))
176176
end
177177

178+
function _set(::Type{T}, ::Type{MOI.VectorNonlinearOracle}) where {T}
179+
set = MOI.VectorNonlinearOracle(;
180+
dimension = 3,
181+
l = T[0, 0],
182+
u = T[1, 0],
183+
eval_f = (ret, x) -> begin
184+
ret[1] = x[2]^2
185+
ret[2] = x[3]^2 + x[4]^3 - x[1]
186+
return
187+
end,
188+
jacobian_structure = [(1, 2), (2, 1), (2, 3), (2, 4)],
189+
eval_jacobian = (ret, x) -> begin
190+
ret[1] = T(2) * x[2]
191+
ret[2] = -T(1)
192+
ret[3] = T(2) * x[3]
193+
ret[4] = T(3) * x[4]^2
194+
return
195+
end,
196+
)
197+
x, ret_f, ret_J = T[1, 2, 3, 4, 5], T[0, 0], T[0, 0, 0, 0]
198+
set.eval_f(ret_f, x)
199+
set.eval_jacobian(ret_J, x)
200+
return set
201+
end
202+
178203
function _test_function_modification(
179204
model::MOI.ModelLike,
180205
config::Config{T},
@@ -392,6 +417,7 @@ for s in [
392417
:Table,
393418
:Path,
394419
:HyperRectangle,
420+
:VectorNonlinearOracle,
395421
]
396422
S = getfield(MOI, s)
397423
functions = if S <: MOI.AbstractScalarSet

src/Test/test_nonlinear.jl

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2223,3 +2223,162 @@ function setup_test(
22232223
end
22242224

22252225
version_added(::typeof(test_nonlinear_quadratic_4)) = v"1.35.0"
2226+
2227+
function test_vector_nonlinear_oracle(
2228+
model::MOI.ModelLike,
2229+
config::Config{T},
2230+
) where {T}
2231+
@requires _supports(config, MOI.optimize!)
2232+
@requires MOI.supports_constraint(
2233+
model,
2234+
MOI.VectorOfVariables,
2235+
MOI.VectorNonlinearOracle{T},
2236+
)
2237+
set = MOI.VectorNonlinearOracle(;
2238+
dimension = 5,
2239+
l = T[0, 0],
2240+
u = T[0, 0],
2241+
eval_f = (ret, x) -> begin
2242+
@test length(ret) == 2
2243+
@test length(x) == 5
2244+
ret[1] = x[1]^2 - x[4]
2245+
ret[2] = x[2]^2 + x[3]^3 - x[5]
2246+
return
2247+
end,
2248+
jacobian_structure = [(1, 1), (2, 2), (2, 3), (1, 4), (2, 5)],
2249+
eval_jacobian = (ret, x) -> begin
2250+
@test length(ret) == 5
2251+
@test length(x) == 5
2252+
ret[1] = T(2) * x[1]
2253+
ret[2] = T(2) * x[2]
2254+
ret[3] = T(3) * x[3]^2
2255+
ret[4] = -T(1)
2256+
ret[5] = -T(1)
2257+
return
2258+
end,
2259+
hessian_lagrangian_structure = [(1, 1), (2, 2), (3, 3)],
2260+
eval_hessian_lagrangian = (ret, x, u) -> begin
2261+
@test length(ret) == 3
2262+
@test length(x) == 5
2263+
@test length(u) == 2
2264+
ret[1] = T(2) * u[1]
2265+
ret[2] = T(2) * u[2]
2266+
ret[3] = T(6) * x[3] * u[2]
2267+
return
2268+
end,
2269+
)
2270+
@test MOI.dimension(set) == 5
2271+
x = T[1, 2, 3, 4, 5]
2272+
ret = T[0, 0]
2273+
set.eval_f(ret, x)
2274+
@test ret == T[-3, 26]
2275+
ret = T[0, 0, 0, 0, 0]
2276+
set.eval_jacobian(ret, x)
2277+
@test ret == T[2, 4, 27, -1, -1]
2278+
ret = T[0, 0, 0]
2279+
set.eval_hessian_lagrangian(ret, x, T[2, 3])
2280+
@test ret == T[4, 6, 54]
2281+
x, y = MOI.add_variables(model, 3), MOI.add_variables(model, 2)
2282+
MOI.add_constraints.(model, x, MOI.EqualTo.(T(1):T(3)))
2283+
c = MOI.add_constraint(model, MOI.VectorOfVariables([x; y]), set)
2284+
MOI.optimize!(model)
2285+
x_v = MOI.get.(model, MOI.VariablePrimal(), x)
2286+
y_v = MOI.get.(model, MOI.VariablePrimal(), y)
2287+
@test (y_v, [x_v[1]^2, x_v[2]^2 + x_v[3]^3], config)
2288+
@test (MOI.get(model, MOI.ConstraintPrimal(), c), [x_v; y_v], config)
2289+
@test (MOI.get(model, MOI.ConstraintDual(), c), zeros(T, 5), config)
2290+
return
2291+
end
2292+
2293+
function setup_test(
2294+
::typeof(test_vector_nonlinear_oracle),
2295+
model::MOIU.MockOptimizer,
2296+
config::Config{T},
2297+
) where {T}
2298+
MOI.Utilities.set_mock_optimize!(
2299+
model,
2300+
mock -> MOI.Utilities.mock_optimize!(
2301+
mock,
2302+
config.optimal_status,
2303+
T[1, 2, 3, 1, 31],
2304+
(MOI.VectorOfVariables, MOI.VectorNonlinearOracle{T}) =>
2305+
[zeros(T, 5)],
2306+
),
2307+
)
2308+
model.eval_variable_constraint_dual = false
2309+
return () -> model.eval_variable_constraint_dual = true
2310+
end
2311+
2312+
version_added(::typeof(test_vector_nonlinear_oracle)) = v"1.46.0"
2313+
2314+
function test_vector_nonlinear_oracle_no_hessian(
2315+
model::MOI.ModelLike,
2316+
config::Config{T},
2317+
) where {T}
2318+
@requires _supports(config, MOI.optimize!)
2319+
@requires MOI.supports_constraint(
2320+
model,
2321+
MOI.VectorOfVariables,
2322+
MOI.VectorNonlinearOracle{T},
2323+
)
2324+
set = MOI.VectorNonlinearOracle(;
2325+
dimension = 5,
2326+
l = T[0, 0],
2327+
u = T[0, 0],
2328+
eval_f = (ret, x) -> begin
2329+
ret[1] = x[1]^2 - x[4]
2330+
ret[2] = x[2]^2 + x[3]^3 - x[5]
2331+
return
2332+
end,
2333+
jacobian_structure = [(1, 1), (2, 2), (2, 3), (1, 4), (2, 5)],
2334+
eval_jacobian = (ret, x) -> begin
2335+
ret[1] = T(2) * x[1]
2336+
ret[2] = T(2) * x[2]
2337+
ret[3] = T(3) * x[3]^2
2338+
ret[4] = -T(1)
2339+
ret[5] = -T(1)
2340+
return
2341+
end,
2342+
)
2343+
@test MOI.dimension(set) == 5
2344+
x = T[1, 2, 3, 4, 5]
2345+
ret = T[0, 0]
2346+
set.eval_f(ret, x)
2347+
@test ret == T[-3, 26]
2348+
ret = T[0, 0, 0, 0, 0]
2349+
set.eval_jacobian(ret, x)
2350+
@test ret == T[2, 4, 27, -1, -1]
2351+
@test isempty(set.hessian_lagrangian_structure)
2352+
@test set.eval_hessian_lagrangian === nothing
2353+
x, y = MOI.add_variables(model, 3), MOI.add_variables(model, 2)
2354+
MOI.add_constraints.(model, x, MOI.EqualTo.(T(1):T(3)))
2355+
c = MOI.add_constraint(model, MOI.VectorOfVariables([x; y]), set)
2356+
MOI.optimize!(model)
2357+
x_v = MOI.get.(model, MOI.VariablePrimal(), x)
2358+
y_v = MOI.get.(model, MOI.VariablePrimal(), y)
2359+
@test (y_v, [x_v[1]^2, x_v[2]^2 + x_v[3]^3], config)
2360+
@test (MOI.get(model, MOI.ConstraintPrimal(), c), [x_v; y_v], config)
2361+
@test (MOI.get(model, MOI.ConstraintDual(), c), zeros(T, 5), config)
2362+
return
2363+
end
2364+
2365+
function setup_test(
2366+
::typeof(test_vector_nonlinear_oracle_no_hessian),
2367+
model::MOIU.MockOptimizer,
2368+
config::Config{T},
2369+
) where {T}
2370+
MOI.Utilities.set_mock_optimize!(
2371+
model,
2372+
mock -> MOI.Utilities.mock_optimize!(
2373+
mock,
2374+
config.optimal_status,
2375+
T[1, 2, 3, 1, 31],
2376+
(MOI.VectorOfVariables, MOI.VectorNonlinearOracle{T}) =>
2377+
[zeros(T, 5)],
2378+
),
2379+
)
2380+
model.eval_variable_constraint_dual = false
2381+
return () -> model.eval_variable_constraint_dual = true
2382+
end
2383+
2384+
version_added(::typeof(test_vector_nonlinear_oracle_no_hessian)) = v"1.46.0"

src/Utilities/model.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,7 @@ const EqualToIndicatorZero{T} =
843843
MOI.Table,
844844
MOI.BinPacking,
845845
MOI.HyperRectangle,
846+
MOI.VectorNonlinearOracle,
846847
),
847848
(MOI.ScalarNonlinearFunction,),
848849
(MOI.ScalarAffineFunction, MOI.ScalarQuadraticFunction),

0 commit comments

Comments
 (0)