Evaluating constraints at fixed points (and extracting their variables) in JuMP

Hello folks,
I know this has likely been addressed in a really deep thread here somewhere, but I have been having trouble evaluating constraints in JuMP for fixed variable values. So far, I am doing the following:

# Working example
using JuMP
using MathOptInterface
const MOI = MathOptInterface
m = Model();
@variable(m, -1 <= x[1:5] <= 1); @variable(m, -5 <= y[1:3] <= 8); @variable(m, -30 <= z <= 5);
@NLconstraint(m, sum(x[i] for i=1:4) - y[1]*y[2] + z <=10)
d = JuMP.NLPEvaluator(m)
MOI.initialize(d, [:Jac])
constraint_values = zeros(1)
inp = rand(9) # the input..
MOI.eval_constraint(d, constraint_values, inp) # where it dumps result into ```constraint_values```.

But this is cumbersome, because eval_constraint requires passing an array for ALL of the variable values, even if they are not in the constraint. Furthermore, as the size of the model changes, the size of input inp does not change (it has to be reinitialized in order to do so).
I was wondering if there was a better way of doing this. In a nicer world, it might be like:

inp = Dict(subset_of_vars .=> nums)
evaluate(constraint, dict)

That being said, any method to obtain the subset of variables in a constraint would be appreciated too. I haven’t found a streamlined way to do so thus far. Thanks in advance folks!

2 Likes

Buried in ? value, there is

help?> value
search: value values setvalue getvalue set_value fix_value has_values start_value callback_value
─────────────────────────────────────────────────────────────────────────────────────────────────

# ... lots of other stuff ...

─────────────────────────────────────────────────────────────────────────────────────────────────

  value(ex::NonlinearExpression, var_value::Function)

  Evaluate ex using var_value(v) as the value for each variable v.

So:

using JuMP
model = Model()
@variables(model, begin
    -1 <= x[1:5] <= 1
    -5 <= y[1:3] <= 8
    -30 <= z <= 5
end)
ex = @NLexpression(model, sum(x[i] for i=1:4) - y[1] * y[2] + z)
@NLconstraint(model, ex <= 10)

inp = Dict(
    x[1] => 1, x[2] => 2, x[3] => 3, x[4] => 4, y[1] => 5, y[2] => 6, z => 7
)

# `get(dict, key, default)` is used to avoid specifying unused variables.
value(ex, i -> get(inp, i, 0.0))  # -13.0
3 Likes

Woohoo, that works great! As for the second issue, is there an equivalent of JuMP.all_variables(model::Model) for constraints or expressions? It would be really helpful to be able to parse out which ones are relevant.

1 Like

There’s:

list_of_constraint_types(model::Model)
all_constraints(model::Model, function_type, set_type)::Vector{<:ConstraintRef}

which can usually be used together to narrow down the constraints you’re interested in. Not sure how to extract the relevant variables from a ConstraintRef though.

1 Like

is there an equivalent of JuMP.all_variables(model::Model) for constraints or expressions

No. You can look through the .terms field of affine and quadratic expressions. But nonlinear expressions are stored in a different manner.

For constraints constructed with @constraint, you can go

model = Model()
@variable(model, x)
c = @constraint(model, 2x + 1 <= 0)
obj = constraint_object(c)
obj.func  # The function

This doesn’t work for @NLconstraint, however.

1 Like