Is your feature request related to a problem? Please describe.
The C API exposes user callback hooks for MIP solves:
cuOptSetMIPGetSolutionCallback (cpp/include/cuopt/linear_programming/cuopt_c.h:747) — invoked by the solver to deliver incumbent solutions to the user.
cuOptSetMIPSetSolutionCallback (cpp/include/cuopt/linear_programming/cuopt_c.h:765) — invoked by the solver to ask the user to inject a candidate solution.
Both are not yet wrapped by cuopt-java (PR #1192). They're listed in the post-merge work in temp/cuopt-java-RESUME.md.
Describe the solution you'd like
A Java API exposed via SolverSettings (or Problem) that lets the user register two callbacks:
@FunctionalInterface
public interface MIPGetSolutionCallback {
void onSolution(double[] primal);
}
@FunctionalInterface
public interface MIPSetSolutionCallback {
boolean provideSolution(double[] outPrimal); // returns true if a solution was written
}
settings.setMIPGetSolutionCallback(primal -> { ... });
settings.setMIPSetSolutionCallback(out -> { populate(out); return true; });
Implementation: FFM upcall stubs created with Linker.upcallStub(...) bound to a per-solve Arena. On invocation, copy the native cuopt_float_t* buffer into a Java double[], call the user lambda, and (for Set callbacks) copy back.
Describe alternatives you've considered
- Skip in v1 — current state. Acceptable, but customers coming from Gurobi/CPLEX expect callback hooks for warm-start injection and incumbent monitoring.
- JNI bridge — heavier mechanism; FFM upcalls are the right tool now.
Additional context
Benchmark first. FFM upcall overhead (Java ↔ native round-trip) is non-trivial — typically reported in the 100s of nanoseconds per call. In a tight MIP B&B loop with frequent incumbents, this could dominate. Acceptance criteria:
- Microbenchmark a no-op upcall (empty Java callback returning immediately) under JMH. Measure round-trip cost.
- Compare against a representative MIP solve's incumbent-frequency profile (likely <1 callback per second in most problems, but could be hundreds per second in degenerate cases).
- If overhead is >100 µs per invocation OR causes >5% wall-clock regression on a representative benchmark, expose the callback behind a feature flag or refactor to batch deliveries.
Related issues:
Is your feature request related to a problem? Please describe.
The C API exposes user callback hooks for MIP solves:
cuOptSetMIPGetSolutionCallback(cpp/include/cuopt/linear_programming/cuopt_c.h:747) — invoked by the solver to deliver incumbent solutions to the user.cuOptSetMIPSetSolutionCallback(cpp/include/cuopt/linear_programming/cuopt_c.h:765) — invoked by the solver to ask the user to inject a candidate solution.Both are not yet wrapped by cuopt-java (PR #1192). They're listed in the post-merge work in
temp/cuopt-java-RESUME.md.Describe the solution you'd like
A Java API exposed via
SolverSettings(orProblem) that lets the user register two callbacks:Implementation: FFM upcall stubs created with
Linker.upcallStub(...)bound to a per-solveArena. On invocation, copy the nativecuopt_float_t*buffer into a Javadouble[], call the user lambda, and (for Set callbacks) copy back.Describe alternatives you've considered
Additional context
Benchmark first. FFM upcall overhead (Java ↔ native round-trip) is non-trivial — typically reported in the 100s of nanoseconds per call. In a tight MIP B&B loop with frequent incumbents, this could dominate. Acceptance criteria:
Related issues: