# Lagrange multipliers of a \`VectorNonlinearOracle\` after solve

**URL:** <https://discourse.julialang.org/t/lagrange-multipliers-of-a-vectornonlinearoracle-after-solve/134236>\
**Category:** Optimization (Mathematical)\
**Tags:** jump, mathoptinterface\
**Created:** [November 30, 2025, 4:21pm UTC](https://discourse.julialang.org/t/lagrange-multipliers-of-a-vectornonlinearoracle-after-solve/134236 "2025-11-30T16:21:52Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![franckgaga](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/franckgaga/32/218241_2.png) [@franckgaga](https://discourse.julialang.org/u/franckgaga)\
**Post date:** [November 30, 2025, 4:21pm UTC](https://discourse.julialang.org/t/lagrange-multipliers-of-a-vectornonlinearoracle-after-solve/134236/1 "2025-11-30T16:21:52Z")

</div>

I have a nonlinear optimization problem that relies on [`MOI.VectorNonlinearOracle`](https://jump.dev/MathOptInterface.jl/dev/reference/standard_form/#MathOptInterface.VectorNonlinearOracle) for the constraints. I would like to compute the Hessian of the Langrangian at the optimum after solving, or, in other words, fetching the `ret` value at the optimum in the function `eval_hessian_lagrangian(ret, x, μ)`. I need the optimal Langrange multiplier `μ` for this. I think `JuMP.dual` is intended for this?

For Ipopt.jl, why does `dual` called on the `VectorNonlinearOracle` constraint returns a vector with the number of elements equal to the number of decision variable? Isn’t supposed to be the number of nonlinear constraint in the set, if it’s truly the Langrange multipliers `μ` ?

Here’s a MRE with two decision variables and one nonlinear constraint:

```julia
using JuMP, Ipopt, MathOptInterface
set = MathOptInterface.VectorNonlinearOracle(;
    dimension = 2,
    l = [-Inf],
    u = [1.0],
    eval_f = (ret, x) -> (ret[1] = x[1]^2 + x[2]^2),
    jacobian_structure = [(1, 1), (1, 2)],
    eval_jacobian = (ret, x) -> ret .= 2.0 .* x,
    hessian_lagrangian_structure = [(1, 1), (2, 2)],
    eval_hessian_lagrangian = (ret, x, u) -> ret .= 2.0 .* u[1],
)
model = Model(Ipopt.Optimizer)
set_silent(model)
@variable(model, x)
@variable(model, y)
@objective(model, Max, x + y)
@constraint(model, c, [x, y] in set)
optimize!(model)
@show value(x), value(y)
@show dual(c)

```

giving a dual vector with 2 elements instead of 1 element:

```julia-auto
(value(x), value(y)) = (0.707106783471979, 0.707106783471979)
dual(c) = [-0.9999999949684055, -0.9999999949684055]

```

---

<div class="post-metadata">

**Author:** ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)\
**Post date:** [November 30, 2025, 7:39pm UTC](https://discourse.julialang.org/t/lagrange-multipliers-of-a-vectornonlinearoracle-after-solve/134236/2 "2025-11-30T19:39:32Z")

</div>

The dual we return from `VectorNonlinearOracle` is {\mu}^\top J(x).

Our general convention has been that the dual is the same dimension as the input dimension. Our input here is a 2-element vector `[x, y]`, so \mu^\top J(x) seemed to be the must relevant “dual” to return from the MOI point of view.

I’ll open an issue to discuss this further: [The dual of VectorNonlinearOracle · Issue #2887 · jump-dev/MathOptInterface.jl · GitHub](https://github.com/jump-dev/MathOptInterface.jl/issues/2887)
