Hi, I’m working on a bilevel problem that is converted into an equivalent non-convex QCQP by applying strong duality to the lower-level problem (LP).

My code returns a (local) optimal solution with Ipopt solver (w/ ma86).
However, the same code returns infeasibility with Gurobi v9.0.2 (NonConvex=2).

This makes me wonder if the solution obtained with Ipopt is reliable.
Is there any possible reasoning for this? Any advice would be highly appreciated.

My experience has been that Ipopt is the most numerically stable non-linear solver. In this case, I would suspect there is a numerical issue in Guorbi. One useful diagnostic is to evaluate the feasibility of each constraint in the solution found by Ipopt.

@ccoffrin Thank you for your advice. Is there a smart way to check the feasibility?

The only way I know is to do something like: value.(g) - value.(d) == 0 for constraint @constraint(m, const1[t in 1:24], g[t] - d[t] == 0)
I just have too many constraints to do this manually.

Also, it is odd to me that Gurobi returns infeasibility rather than taking a longer time, as this means Gurobi fails to find any feasible point if I understand it correctly.

Also, it is odd to me that Gurobi returns infeasibility rather than taking a longer time, as this means Gurobi fails to find any feasible point if I understand it correctly.

Not really. You can use something like the following:

model = Model()
@variable(model, x >= 0)
@variable(model, y >= 0)
c = @constraint(model, x * y <= 1)
o = constraint_object(c)
value(o.func) # left-hand side
o.set.upper # right-hand side, if <=. Use .lower if >=, and .value if ==