User cuts and lazy constraints are often confused.
- User cuts help tighten a MIP by removing fractional solutions. They are not required for the model, but they can help a MIP solve faster.
- Lazy constraints are required for the model: the model would be incorrect without these constraints. For some models, it is helpful to designate some constraints as lazy when it is computationally faster just to include them when they are violated. This is typically for models that contain a relative large number of constraints, and most are trivially satisfied.
A user cut should never eliminate an integer solution that would otherwise be feasible. Thus, the model plus all possible user cuts should have exactly the same set of integer feasible solutions as the model without user cuts.
In contrast, lazy constraints are usually used to eliminate integer solutions that are otherwise feasible. So, adding lazy constraints will affect the set of integer feasible solutions. Thus, if you create lazy constraints via a callback, you must set the parameter LazyConstraint=1. Otherwise, Gurobi would potentially apply dual presolve reductions that are not valid for the lazy constraints. If you set LazyConstraint=1 without adding any lazy constraints, then the algorithmic behavior of Gurobi will change (due to implicitly disabling dual presolve reductions), but the optimal objective value should not change.
Finally, note that you can add lazy constraints directly to the model, and have Gurobi treat them as lazy by setting the Lazy attribute on these constraints. In this case, it is not necessary to set the LazyConstraint parameter.