Some additional context: in Gurobi v9 and v10, non-convex constraints other than quadratic were supported in the API, but handled internally via a piece-wise linear approximation. In v11, Gurobi added the option to handle these explicitly as non-convex constraints, as opposed to performing a piece-wise linear approximation. Note that non-convex quadratic constraints were fully supported since v9.
Gurobi’s nonconvex API supports a finite number of pre-defined functions (like power, sin/cos, exponential, logarithm, etc.). AFAIK JuMP does not support passing, e.g., the constraint y = \sqrt{x} to Gurobi because that would require a specialized API call, whereas JuMP handles nonlinear expression/constraints in a unified way.
This means that, in order to pass y = \sqrt{x} to Gurobi, you need to use the C API.
That being said, if constraints of the form \sum_{i} \sqrt{x_{i}} \leq k is what you’re after, an alternative approach is to formulate it as \sum_{i} y_{i} \leq k, y_{i}^{2} = x_{i}, y_{i} \geq 0. The first constraint is linear, the second is a non-convex quadratic, and the last is a variable bound. You can formulate all 3 in JuMP and hand it to Gurobi, without needing any C API hack.
The corresponding Julia code would be (I added bounds on x
, y
):
using JuMP, Gurobi
N = 2
model = direct_model(Gurobi.Optimizer())
@variable(model, x[i in 1:N] >= 0)
@variable(model, y[i in 1:N] >= 0)
# y == sqrt(x) <=> (y^2 == x, y >= 0)
@constraint(model, [i in 1:n], y[i] * y[i] == x[i])
@constraint(model, sum(y) <= k)
@objective(model, Min, k) # something
optimize!(model)