Skip to content

[FEA] cuopt-java: wrap MIP user callbacks (cuOptSetMIP{Get,Set}SolutionCallback) #1204

@rgsl888prabhu

Description

@rgsl888prabhu

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:

  1. Microbenchmark a no-op upcall (empty Java callback returning immediately) under JMH. Measure round-trip cost.
  2. 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).
  3. 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:

Metadata

Metadata

Assignees

Labels

awaiting responseThis expects a response from maintainer or contributor depending on who requested in last comment.feature requestNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions