Forum Discussion

FICO's avatar
FICO
Community Manager
2 months ago

How to make cuts added in a preIntsol callback globally valid (root node) instead of local to the current subtree?

I'm using the Xpress Optimizer Java API (com.dashoptimization, Xpress 9.4) to solve a MIP with lazy constraints that are generated dynamically. My constraints are all globally valid — they are not local to any node.

Current approach: I register a preIntsol callback (AbstractPreIntsolListener). When a candidate integer solution is found, I check it, and if it violates one of my lazy constraints I build the cut, presolve it, and add it with prob.addCut(). I've disabled dual reductions (setMIPDualReductions(0)) as required for lazy constraints.

This works correctly, but as I understand it XPRSaddcuts activates the cut at the current node and its descendants only. When the search backtracks above that node, the cut is deactivated (kept in the pool, but no longer in the active LP). Because my cuts are globally valid, this is safe, but it's inefficient: the same infeasible integer solution can be rediscovered elsewhere in the tree, re-triggering my callback to re-derive cuts I already found.

What I want: I'd like each generated cut to be treated as globally valid — effectively added at the root node — so it stays active throughout the whole branch-and-bound tree and is never re-derived.

Is there a way to add a cut from within a callback and have it applied globally (root node), rather than only to the current node's subtree?

2 Replies

  • FICO's avatar
    FICO
    Community Manager

    Dear Christian,

    Many thanks for your prompt and detailed answer!

    I will take a look at those links while waiting patiently for new implementations.

    Bests,

    Emanuele Cutore

  • FICO's avatar
    FICO
    Community Manager

    Dear Emanuele,

    Your approach is correct. Your cuts should be added at integral tree nodes (soltype==0) if the integral solution violates one of your constraints. If the infeasible solution stems from a heuristic (soltype!=0), you can only reject it, not derive a cut from it. In addition, you can hook into the optnode callback to generate violated constraints.

    There are a few examples on separating lazy constraints, including in this community: https://community.fico.com/s/question/0D54W00008P73MsSAJ/lazy-cut-callback-in-java. Also check examples around the traveling salesman problem and subtour elimination constraints, available for different APIs: https://examples.xpress.fico.com/example.pl?id=tsp_java.

    For the moment, cuts in Xpress are managed locally — it is not possible to add global cuts in the sense of an automation that keeps a cut permanently enforced at the root. We are aware of this limitation and are actively working on solutions that would address use-cases like yours.

    Best regards,

    Christian Raack