User cuts and lazy constraints are similar but have some important differences.
- User cuts help tighten the relaxation of a MIP by removing fractional solutions. They are not required for the model, but they potentially help solve a MIP faster.
- Lazy constraints are required for the model, i.e., 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 to include them only when they are violated. Generally, they are used for models that contain a relatively large number of constraints, most of which 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. Adding lazy constraints will affect the set of integer feasible solutions. Note that if you add lazy constraints via a callback, you must set the parameter LazyConstraints=1. Otherwise, Gurobi might apply dual presolve reductions that are not valid for the lazy constraints.
If you set LazyConstraints=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 LazyConstraints parameter.